async Task <ThinClientConnection> DcConnectEx(WideTunnel wt, ThinClientConnectOptions connectOptions, CancellationToken cancel, bool checkPort, bool firstConnection, Func <ThinClientAuthRequest, CancellationToken, Task <ThinClientAuthResponse> > authCallback, Func <ThinClientOtpRequest, CancellationToken, Task <ThinClientOtpResponse> > otpCallback, Func <ThinClientInspectRequest, CancellationToken, Task <ThinClientInspectResponse> > inspectCallback) { string otpTicket = ""; string inspectTicket = ""; WtcSocket? sock = null; PipeStream?st = null; if (checkPort == false && connectOptions.DebugGuacMode == false) { throw new CoresLibException("checkPort == false && connectOptions.DebugGuacMode == false"); } try { sock = await wt.WideClientConnectAsync(connectOptions.Pcid, connectOptions.ClientOptions, false, cancel); st = sock.GetStream(true); st.ReadTimeout = st.WriteTimeout = Consts.ThinClient.ProtocolCommTimeoutMsecs; // バージョンを送信 Pack p = new Pack(); p.AddInt("ClientVer", Consts.ThinClient.DummyClientVer); p.AddInt("ClientBuild", Consts.ThinClient.DummyClientBuild); p.AddBool("CheckPort", checkPort); p.AddBool("FirstConnection", firstConnection); p.AddBool("HasURDP2Client", true); p.AddBool("SupportOtp", true); p.AddBool("SupportOtpEnforcement", true); p.AddBool("SupportInspect", true); p.AddBool("SupportServerAllowedMacListErr", true); p.AddIp("ClientLocalIP", connectOptions.ClientIpAddress); p.AddUniStr("UserName", "HTML5 WebClient"); p.AddUniStr("ComputerName", "HTML5 WebClient"); p.AddBool("SupportWatermark", true); p.AddBool("GuacdMode", connectOptions.DebugGuacMode == false); GuaDnFlags flags = GuaDnFlags.None; if (connectOptions.GuaPreference?.EnableAlwaysWebp ?? false) { flags |= GuaDnFlags.AlwaysWebp; } p.AddInt("GuacdFlags", (uint)flags); await st._SendPackAsync(p, cancel); // 認証パラメータを受信 p = await st._RecvPackAsync(cancel); var err = p.GetErrorFromPack(); err.ThrowIfError(p); var authType = (ThinAuthType)p["AuthType"].SIntValueSafeNum; var svcType = (ThinSvcType)p["ServiceType"].SIntValueSafeNum; var svcPort = (int)p["ServicePort"].SIntValueSafeNum; var caps = (ThinServerCaps)p["DsCaps"].SIntValueSafeNum; var rand = p["Rand"].DataValueNonNull; var machineKey = p["MachineKey"].DataValueNonNull; var isShareDisabled = p["IsShareDisabled"].BoolValue; var useAdvancedSecurity = p["UseAdvancedSecurity"].BoolValue; var isOtpEnabled = p["IsOtpEnabled"].BoolValue; var runInspect = p["RunInspect"].BoolValue; var lifeTime = p["Lifetime"].SInt64Value; var lifeTimeMsg = p["LifeTimeMsg"].UniStrValueNonNull; var waterMarkStr1 = p["WatermarkStr1"].UniStrValueNonNull; var waterMarkStr2 = p["WatermarkStr2"].UniStrValueNonNull; var idleTimeout = p["IdleTimeout"].SIntValueSafeNum; var isLimitedFirewallMandated = p["IsLimitedFirewallMandated"].BoolValue; if (isLimitedFirewallMandated) { // 完全閉域化 FW が強制されているが HTML5 版ではサポートされていない throw new VpnException(VpnError.ERR_DESK_GOVFW_HTML5_NO_SUPPORT); } if (isOtpEnabled) { // OTP 認証 ThinClientOtpRequest otpReq = new ThinClientOtpRequest(); var otpRes = await otpCallback(otpReq, cancel); p = new Pack(); p.AddStr("Otp", otpRes.Otp._NonNull()); await st._SendPackAsync(p, cancel); // 結果を受信 p = await st._RecvPackAsync(cancel); p.ThrowIfError(); // OTP チケットを保存 otpTicket = p["OtpTicket"].StrValueNonNull; } if (runInspect) { // 検疫および MAC アドレス認証 ThinClientInspectRequest inspectReq = new ThinClientInspectRequest(); var inspectRes = await inspectCallback(inspectReq, cancel); p = new Pack(); p.AddBool("AntiVirusOk", inspectRes.AntiVirusOk); p.AddBool("WindowsUpdateOk", inspectRes.WindowsUpdateOk); p.AddStr("MacAddressList", inspectRes.MacAddressList._NonNull()); p.AddStr("Ticket", inspectRes.Ticket._NonNull()); await st._SendPackAsync(p, cancel); // 結果を受信 p = await st._RecvPackAsync(cancel); p.ThrowIfError(); // OTP チケットを保存 inspectTicket = p["InspectionTicket"].StrValueNonNull; } // ユーザー認証 p = new Pack(); if (useAdvancedSecurity == false) { // 古いユーザー認証 if (authType == ThinAuthType.None) { // 匿名認証 ThinClientAuthRequest authReq = new ThinClientAuthRequest { AuthType = ThinAuthType.None, }; var authRes = await authCallback(authReq, cancel); } else if (authType == ThinAuthType.Password) { // パスワード認証 ThinClientAuthRequest authReq = new ThinClientAuthRequest { AuthType = ThinAuthType.Password, }; var authRes = await authCallback(authReq, cancel); var passwordHash = Secure.HashSHA1(authRes.Password._GetBytes_UTF8()); p.AddData("SecurePassword", Secure.SoftEther_SecurePassword(passwordHash, rand)); } else { // そのような認証方法はサポートしていない throw new VpnException(VpnError.ERR_AUTHTYPE_NOT_SUPPORTED); } } else { // 高度なユーザー認証 ThinClientAuthRequest authReq = new ThinClientAuthRequest { AuthType = ThinAuthType.Advanced, }; var authRes = await authCallback(authReq, cancel); p.AddInt("authtype", 2); // CLIENT_AUTHTYPE_PLAIN_PASSWORD p.AddStr("username", authRes.Username); p.AddStr("plain_password", authRes.Password); } await st._SendPackAsync(p, cancel); // 結果を受信 p = await st._RecvPackAsync(cancel); err = p.GetErrorFromPack(); err.ThrowIfError(p); st.ReadTimeout = st.WriteTimeout = Timeout.Infinite; var misc = new ThinClientMiscParams(lifeTime, lifeTimeMsg, idleTimeout, isShareDisabled, caps.Bit(ThinServerCaps.AudioInSupported)); return(new ThinClientConnection(sock, st, svcType, svcPort, isShareDisabled, caps, runInspect, otpTicket, inspectTicket, waterMarkStr1, waterMarkStr2, misc)); } catch { await st._DisposeSafeAsync(); await sock._DisposeSafeAsync(); throw; } }