/// <summary>
        /// RPC bind over TCP/IP, using specified endpoint and authenticate provider.
        /// </summary>
        /// <param name="serverName">NRPC server machine name.</param>
        /// <param name="endpoint">RPC endpoints, it's the port on TCP/IP.</param>
        /// <param name="securityContext">
        /// Security provider for RPC. 
        /// Set the value to null to disable authentication.
        /// </param>
        /// <param name="timeout">Timeout for bind and all future requests.</param>
        /// <exception cref="ArgumentNullException">
        /// Thrown when serverName is null.
        /// </exception>
        public void BindOverTcp(
            string serverName,
            ushort endpoint,
            ClientSecurityContext securityContext,
            TimeSpan timeout)
        {
            if (serverName == null)
            {
                throw new ArgumentNullException("serverName");
            }

            nrpcSecurityContext = securityContext as NrpcClientSecurityContext;
            if (nrpcSecurityContext != null)
            {
                context = nrpcSecurityContext.nrpc.context;
            }

            rpc.Bind(
                RpceUtility.RPC_OVER_TCPIP_PROTOCOL_SEQUENCE,
                serverName,
                endpoint.ToString(CultureInfo.InvariantCulture),
                null,
                securityContext,
                securityContext == null
                    ? RpceAuthenticationLevel.RPC_C_AUTHN_LEVEL_NONE
                    : (context.SealSecureChannel
                        ? RpceAuthenticationLevel.RPC_C_AUTHN_LEVEL_PKT_PRIVACY
                        : RpceAuthenticationLevel.RPC_C_AUTHN_LEVEL_PKT_INTEGRITY),
                timeout);

            context.PrimaryName = serverName;
            NrpcRpcAdapter nrpcRpcAdapter = rpc as NrpcRpcAdapter;
            if (nrpcRpcAdapter != null)
            {
                context.rpceTransportContext = nrpcRpcAdapter.rpceClientTransport.Context;
            }
        }
        public void APDS_KERBEROS_PAC_VALIDATION()
        {
            base.Logging();

            BaseTestSite.Log.Add(LogEntryKind.Comment, "Construct Kerberos client for testing.");
            client = new KerberosTestClient(
                this.testConfig.LocalRealm.RealmName,
                this.testConfig.LocalRealm.Admin.Username,
                this.testConfig.LocalRealm.Admin.Password,
                KerberosAccountType.User,
                testConfig.LocalRealm.KDC[0].IPAddress,
                testConfig.LocalRealm.KDC[0].Port,
                testConfig.TransportType,
                testConfig.SupportedOid);
            BaseTestSite.Log.Add(LogEntryKind.Comment, "Create and send AS request with no PA data.");
            KdcOptions options = KdcOptions.FORWARDABLE | KdcOptions.CANONICALIZE | KdcOptions.RENEWABLE;
            client.SendAsRequest(options, null);
            //Recieve preauthentication required error
            METHOD_DATA methodData;
            KerberosKrbError krbError = client.ExpectPreauthRequiredError(out methodData);
            //Create sequence of PA data
            string timeStamp = KerberosUtility.CurrentKerberosTime.Value;
            PaEncTimeStamp paEncTimeStamp = new PaEncTimeStamp(timeStamp, 0, this.client.Context.SelectedEType, this.client.Context.CName.Password, this.client.Context.CName.Salt);
            PaPacRequest paPacRequest = new PaPacRequest(true);
            Asn1SequenceOf<PA_DATA> seqOfPaData = new Asn1SequenceOf<PA_DATA>(new PA_DATA[] { paEncTimeStamp.Data, paPacRequest.Data});
            BaseTestSite.Log.Add(LogEntryKind.Comment, "Create and send AS request with PA data.");
            client.SendAsRequest(options, seqOfPaData);
            KerberosAsResponse asResponse = client.ExpectAsResponse();
            BaseTestSite.Assert.IsNotNull(asResponse.Response.ticket, "AS response should contain a TGT.");
            BaseTestSite.Log.Add(LogEntryKind.Comment, "Create and send TGS request.");
            client.SendTgsRequest(this.testConfig.LocalRealm.ClientComputer.DefaultServiceName, options);
            KerberosTgsResponse tgsResponse = client.ExpectTgsResponse();
            EncryptionKey key = testConfig.QueryKey(this.testConfig.LocalRealm.ClientComputer.DefaultServiceName, this.testConfig.LocalRealm.RealmName, this.client.Context.SelectedEType);
            tgsResponse.DecryptTicket(key);

            if (this.testConfig.IsKileImplemented)
            {
                //Get Server and KDC Signatures
                PacServerSignature pacServerSignature = null;
                PacKdcSignature pacKdcSignature = null;
                BaseTestSite.Assert.IsNotNull(tgsResponse.TicketEncPart.authorization_data, "The ticket contains Authorization data.");
                AdWin2KPac adWin2kPac = FindOneInAuthData<AdWin2KPac>(tgsResponse.TicketEncPart.authorization_data.Elements);
                BaseTestSite.Assert.IsNotNull(adWin2kPac, "The Authorization data contains AdWin2KPac.");
                foreach (var buf in adWin2kPac.Pac.PacInfoBuffers)
                {
                    if (buf is PacServerSignature)
                    {
                        pacServerSignature = buf as PacServerSignature;
                    }
                    if (buf is PacKdcSignature)
                    {
                        pacKdcSignature = buf as PacKdcSignature;
                    }
                }

                BaseTestSite.Log.Add(LogEntryKind.Comment, "Establish Secure Channel.");
                NrpcClient nrpcClient = NrpcClient.CreateNrpcClient(this.testConfig.LocalRealm.RealmName);
                ushort[] endPointList = NrpcUtility.QueryNrpcTcpEndpoint(testConfig.LocalRealm.KDC[0].FQDN);
                ushort endPoint = endPointList[0];
                MachineAccountCredential machineCredential = new MachineAccountCredential(
                    this.testConfig.LocalRealm.RealmName,
                    testConfig.LocalRealm.ClientComputer.FQDN.Split('.')[0],
                    testConfig.LocalRealm.ClientComputer.Password);

                nrpcClient.Context.NegotiateFlags = NrpcNegotiateFlags.SupportsAESAndSHA2
                    | NrpcNegotiateFlags.SupportsConcurrentRpcCalls
                    | NrpcNegotiateFlags.SupportsCrossForestTrusts
                    | NrpcNegotiateFlags.SupportsGenericPassThroughAuthentication
                    | NrpcNegotiateFlags.SupportsNetrLogonGetDomainInfo
                    | NrpcNegotiateFlags.SupportsNetrLogonSendToSam
                    | NrpcNegotiateFlags.SupportsNetrServerPasswordSet2
                    | NrpcNegotiateFlags.SupportsRC4
                    | NrpcNegotiateFlags.SupportsRefusePasswordChange
                    | NrpcNegotiateFlags.SupportsRodcPassThroughToDifferentDomains
                    | NrpcNegotiateFlags.SupportsSecureRpc
                    | NrpcNegotiateFlags.SupportsStrongKeys
                    | NrpcNegotiateFlags.SupportsTransitiveTrusts;

                NrpcClientSecurityContext securityContext = new NrpcClientSecurityContext(
                    this.testConfig.LocalRealm.RealmName,
                    testConfig.LocalRealm.KDC[0].FQDN.Split('.')[0],
                    machineCredential,
                    true,
                    nrpcClient.Context.NegotiateFlags);

                nrpcClient.BindOverTcp(testConfig.LocalRealm.KDC[0].FQDN, endPoint, securityContext, TimeSpan.FromMilliseconds(600000));

                _NETLOGON_LOGON_INFO_CLASS logonLevel = _NETLOGON_LOGON_INFO_CLASS.NetlogonGenericInformation;
                _NETLOGON_VALIDATION_INFO_CLASS validationLevel = _NETLOGON_VALIDATION_INFO_CLASS.NetlogonValidationGenericInfo2;
                _NETLOGON_VALIDATION? validationInfomation;
                byte? authoritative;
                NrpcNetrLogonSamLogonExtraFlags? extraFlags = NrpcNetrLogonSamLogonExtraFlags.None;

                BaseTestSite.Log.Add(LogEntryKind.Comment, "Create valid KERB_VERIFY_PAC_REQUEST.");
                KERB_VERIFY_PAC_REQUEST kerberosReq = ApdsUtility.CreateKerbVerifyPacRequest(pacServerSignature.NativePacSignatureData, pacKdcSignature.NativePacSignatureData);
                //Create Kerberos Validation Logon Info
                _NETLOGON_LEVEL netlogonLevel = ApdsUtility.CreatePacLogonInfo(
                    NrpcParameterControlFlags.AllowLogonWithComputerAccount,
                    this.testConfig.LocalRealm.RealmName,
                    this.testConfig.LocalRealm.Admin.Username,
                    testConfig.LocalRealm.KDC[0].FQDN.Split('.')[0],
                    kerberosReq);
                _NETLOGON_LEVEL encryptedLogonLevel = nrpcClient.EncryptNetlogonLevel(
                    (_NETLOGON_LOGON_INFO_CLASS)logonLevel,
                    netlogonLevel);
                BaseTestSite.Log.Add(LogEntryKind.Comment, "Call NetrLogonSamLogonEx for Kerberos pac validation.");
                NtStatus result = nrpcClient.NetrLogonSamLogonEx(
                    nrpcClient.Handle,
                    testConfig.LocalRealm.KDC[0].FQDN.Split('.')[0],
                    testConfig.LocalRealm.ClientComputer.FQDN.Split('.')[0],
                    logonLevel,
                    encryptedLogonLevel,
                    validationLevel,
                    out validationInfomation,
                    out authoritative,
                    ref extraFlags);
                BaseTestSite.Assert.AreEqual(NtStatus.STATUS_SUCCESS, result, "[MS-APDS]3.2.5.2 If the checksum is verified, the DC MUST return STATUS_SUCCESS.");
                BaseTestSite.Assert.IsNull(validationInfomation.Value.ValidationGeneric2[0].ValidationData, "[MS-APDS]3.2.5.2 There is no return message.");

                BaseTestSite.Log.Add(LogEntryKind.Comment, "Create invalid KERB_VERIFY_PAC_REQUEST.");
                kerberosReq = ApdsUtility.CreateKerbVerifyPacRequest(pacKdcSignature.NativePacSignatureData, pacKdcSignature.NativePacSignatureData);
                //Create Kerberos Validation Logon Info
                netlogonLevel = ApdsUtility.CreatePacLogonInfo(
                    NrpcParameterControlFlags.AllowLogonWithComputerAccount,
                    this.testConfig.LocalRealm.RealmName,
                    this.testConfig.LocalRealm.Admin.Username,
                    testConfig.LocalRealm.KDC[0].FQDN.Split('.')[0],
                    kerberosReq);
                encryptedLogonLevel = nrpcClient.EncryptNetlogonLevel(
                    (_NETLOGON_LOGON_INFO_CLASS)logonLevel,
                    netlogonLevel);
                BaseTestSite.Log.Add(LogEntryKind.Comment, "Call NetrLogonSamLogonEx for Kerberos pac validation.");
                result = nrpcClient.NetrLogonSamLogonEx(
                    nrpcClient.Handle,
                    testConfig.LocalRealm.KDC[0].FQDN.Split('.')[0],
                    testConfig.LocalRealm.ClientComputer.FQDN.Split('.')[0],
                    logonLevel,
                    encryptedLogonLevel,
                    validationLevel,
                    out validationInfomation,
                    out authoritative,
                    ref extraFlags);
                BaseTestSite.Assert.AreEqual(NtStatus.STATUS_LOGON_FAILURE, result, "[MS-APDS]3.2.5.2 If the checksum verification fails, the DC MUST return an error code, STATUS_LOGON_FAILURE (section 2.2) as the return value to the Netlogon Generic Pass-through method.");
            }
        }
        /// <summary>
        /// RPC bind over named pipe, using well-known endpoint "\PIPE\NETLOGON".
        /// </summary>
        /// <param name="serverName">NRPC server machine name.</param>
        /// <param name="transportCredential">
        /// If connect by SMB/SMB2, it's the security credential 
        /// used by under layer transport (SMB/SMB2). 
        /// If connect by TCP, this parameter is ignored.
        /// </param>
        /// <param name="securityContext">
        /// Security provider for RPC. 
        /// Set the value to null to disable authentication.
        /// </param>
        /// <param name="timeout">Timeout for bind and all future requests.</param>
        /// <exception cref="ArgumentNullException">
        /// Thrown when serverName is null.
        /// </exception>
        public void BindOverNamedPipe(
            string serverName,
            AccountCredential transportCredential,
            ClientSecurityContext securityContext,
            TimeSpan timeout)
        {
            if (serverName == null)
            {
                throw new ArgumentNullException("serverName");
            }

            nrpcSecurityContext = securityContext as NrpcClientSecurityContext;
            if (nrpcSecurityContext != null)
            {
                context = nrpcSecurityContext.nrpc.context;
            }

            rpc.Bind(
                RpceUtility.RPC_OVER_NAMED_PIPE_PROTOCOL_SEQUENCE,
                serverName,
                NrpcUtility.NETLOGON_RPC_OVER_NP_WELLKNOWN_ENDPOINT,
                transportCredential,
                securityContext,
                securityContext == null
                    ? RpceAuthenticationLevel.RPC_C_AUTHN_LEVEL_NONE
                    : (context.SealSecureChannel
                        ? RpceAuthenticationLevel.RPC_C_AUTHN_LEVEL_PKT_PRIVACY
                        : RpceAuthenticationLevel.RPC_C_AUTHN_LEVEL_PKT_INTEGRITY),
                timeout);

            context.PrimaryName = serverName;
            NrpcRpcAdapter nrpcRpcAdapter = rpc as NrpcRpcAdapter;
            if (nrpcRpcAdapter != null)
            {
                context.rpceTransportContext = nrpcRpcAdapter.rpceClientTransport.Context;
            }
        }