/// <summary> /// This takes the given SecBuffers, which are used by SSPI method DecryptMessage. /// </summary> /// <param name="securityBuffers">SecBuffer.Encrypted data will be filled in SecBuffers.</param> /// <returns>If successful, returns true, otherwise false.</returns> /// <exception cref="ArgumentNullException">Thrown when securityBuffers is null. </exception> /// <exception cref="ArgumentException">Thrown when length of securityBuffers is zero or /// securityBuffers have null element.</exception> public override bool Decrypt(params SecurityBuffer[] securityBuffers) { if (securityBuffers == null) { throw new ArgumentNullException("securityBuffers"); } if (securityBuffers.Length == 0) { throw new ArgumentException("Length of securityBuffer cannot be zero.", "securityBuffers"); } for (int i = 0; i < securityBuffers.Length; i++) { if (securityBuffers[i] == null) { throw new ArgumentException("securityBuffers have null element", "securityBuffers"); } } return(NrpcUtility.ValidateNetlogonSignatureToken( ((clientSessionInfo.NegotiateFlags & NrpcNegotiateFlags.SupportsAESAndSHA2) != 0), ref sequenceNumber, SessionKey, true, true, securityBuffers)); }
/// <summary> /// Calculates session key based on negotiation flags /// </summary> private void ComputeSessionKey() { if (SharedSecret == null) { throw new InvalidOperationException("Not able to calculate session key, SharedSecret is null"); } if (ClientChallenge == null) { throw new InvalidOperationException("Not able to calculate session key, ClientChallenge is null"); } if (ServerChallenge == null) { throw new InvalidOperationException("Not able to calculate session key, ServerChallenge is null"); } if ((NegotiateFlags & NrpcNegotiateFlags.SupportsAESAndSHA2) != 0) { SessionKey = NrpcUtility.ComputeSessionKey(NrpcComputeSessionKeyAlgorithm.HMACSHA256, SharedSecret, ClientChallenge, ServerChallenge); } else if ((NegotiateFlags & NrpcNegotiateFlags.SupportsStrongKeys) != 0) { SessionKey = NrpcUtility.ComputeSessionKey(NrpcComputeSessionKeyAlgorithm.MD5, SharedSecret, ClientChallenge, ServerChallenge); } else { SessionKey = NrpcUtility.ComputeSessionKey(NrpcComputeSessionKeyAlgorithm.DES, SharedSecret, ClientChallenge, ServerChallenge); } }
/// <summary> /// Construct Kerberos PAC pass-through logon information /// </summary> /// <param name="parameterControl"> /// A set of bit flags that contain information pertaining to the logon validation processing. /// </param> /// <param name="domainName">domain name</param> /// <param name="userName">user name</param> /// <param name="serverName">NetBIOS name of server </param> /// <param name="kerbVerifyPacRequest">KERB_VERIFY_PAC_REQUEST packet</param> /// <returns>Kerberos PAC netlogon information structure </returns> public static _NETLOGON_LEVEL CreatePacLogonInfo( NrpcParameterControlFlags parameterControl, string domainName, string userName, string serverName, KERB_VERIFY_PAC_REQUEST kerbVerifyPacRequest) { _NETLOGON_LEVEL netLogonLevel = new _NETLOGON_LEVEL(); byte[] logonData = TypeMarshal.ToBytes <KERB_VERIFY_PAC_REQUEST>(kerbVerifyPacRequest); //Identity: A NETLOGON_LOGON_IDENTITY_INFO structure, as specified in section MS-NRPC 2.2.1.4.15, //that contains information about the logon identity. _NETLOGON_LOGON_IDENTITY_INFO identityInfo = NrpcUtility.CreateNetlogonIdentityInfo( parameterControl, domainName, userName, serverName); netLogonLevel.LogonGeneric = new _NETLOGON_GENERIC_INFO[1]; netLogonLevel.LogonGeneric[0].Identity = identityInfo; netLogonLevel.LogonGeneric[0].PackageName = DtypUtility.ToRpcUnicodeString(KERBEROS_PACKAGENAME); netLogonLevel.LogonGeneric[0].LogonData = logonData; netLogonLevel.LogonGeneric[0].DataLength = (uint)logonData.Length; return(netLogonLevel); }
/// <summary> /// Validates the client authenticator /// </summary> /// <param name="clientAuthenticator">the client authenticator</param> private void ValidateNetlogonAuthenticator(_NETLOGON_AUTHENTICATOR?clientAuthenticator) { if (SessionKey == null || StoredCredential == null) { throw new InvalidOperationException("Unable to validate client authenticator"); } if (!clientAuthenticator.HasValue) { return; } NrpcComputeNetlogonCredentialAlgorithm algorithm; if ((NegotiateFlags & NrpcNegotiateFlags.SupportsAESAndSHA2) != 0) { algorithm = NrpcComputeNetlogonCredentialAlgorithm.AES128; } else { algorithm = NrpcComputeNetlogonCredentialAlgorithm.DESECB; } byte[] serverStoredCredential = StoredCredential; if (!NrpcUtility.ValidateClientNetlogonAuthenticator( clientAuthenticator.Value, algorithm, ref serverStoredCredential, SessionKey)) { throw new InvalidOperationException("Client authenticator isn't correct"); } StoredCredential = serverStoredCredential; }
/// <summary> /// Call to this method establishes a secure channel between protocol client and /// protocol server and generates a session key, ehich is used for encryption of /// request packets and decryption of response packets. /// </summary> private void EstablishSecureChannel() { nrpcClient = NrpcClient.CreateNrpcClient(sutDomainName); ushort[] endPointList = NrpcUtility.QueryNrpcTcpEndpoint(serverName); ushort endPoint = endPointList[0]; MachineAccountCredential machineCredential = new MachineAccountCredential( sutDomainName, clientComputerName, clientComputerPassword); 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( sutDomainName, sutComputerName, machineCredential, true, nrpcClient.Context.NegotiateFlags); nrpcClient.BindOverTcp(serverName, endPoint, securityContext, timeout); }
/// <summary> /// Create DPSP logon information structure /// </summary> /// <param name="parameterControl"> /// A set of bit flags that contain information pertaining to the logon validation processing. /// </param> /// <param name="digestValidationReq">DIGEST_VALIDATION_REQ structure</param> /// <returns>Dpsp netlogon information structure</returns> public static _NETLOGON_LEVEL CreateDpspLogonInfo( NrpcParameterControlFlags parameterControl, DIGEST_VALIDATION_REQ digestValidationReq) { if (digestValidationReq.Payload == null) { throw new ArgumentException( "invalid digestValidationReq parameter: the payload field is null", "digestValidationReq"); } _NETLOGON_LEVEL netLogonLevel = new _NETLOGON_LEVEL(); DIGEST_VALIDATION_REQ_Payload payload = DIGEST_VALIDATION_REQ_Payload.Parse(digestValidationReq.Payload); byte[] logonData = TypeMarshal.ToBytes <DIGEST_VALIDATION_REQ>(digestValidationReq); //Identity: A NETLOGON_LOGON_IDENTITY_INFO structure, as specified in section MS-NRPC 2.2.1.4.15, //that contains information about the logon identity. _NETLOGON_LOGON_IDENTITY_INFO identityInfo = NrpcUtility.CreateNetlogonIdentityInfo( parameterControl, payload.Domain, payload.Username, payload.ServerName); netLogonLevel.LogonGeneric = new _NETLOGON_GENERIC_INFO[1]; netLogonLevel.LogonGeneric[0].Identity = identityInfo; netLogonLevel.LogonGeneric[0].PackageName = DtypUtility.ToRpcUnicodeString(DIGEST_PACKAGENAME); netLogonLevel.LogonGeneric[0].LogonData = logonData; netLogonLevel.LogonGeneric[0].DataLength = (uint)logonData.Length; return(netLogonLevel); }
/// <summary> /// Initialize method is not used for NRPC SSPI.<para/> /// NRPC SSPI will negotiate security context in its own RPC call. /// </summary> /// <param name="inToken"> /// A token returned from server SSPI; /// if it's set to null, indicates to initialize a new client token. /// </param> /// <exception cref="SspiException"> /// Thrown when server returned token is invalid. /// </exception> public override void Initialize(byte[] inToken) { if (inToken == null) { //Initialize a new token. if (nrpc.Context.SessionKey == null) { //Negotiate a session key. NrpcNegotiateFlags clientCapabilities = nrpc.Context.NegotiateFlags; ushort[] nrpcTcpEndpoints = NrpcUtility.QueryNrpcTcpEndpoint(nrpc.Context.PrimaryName); if (nrpcTcpEndpoints == null || nrpcTcpEndpoints.Length == 0) { throw new InvalidOperationException("Server doesn't support NRPC protocol."); } nrpc.BindOverTcp( nrpc.Context.PrimaryName, nrpcTcpEndpoints[0], null, timeout); nrpc.NetrServerReqChallenge(credential.MachineName); nrpc.NetrServerAuthenticate3( credential.AccountName, this.secureChannelType, ref clientCapabilities, credential.Password); } NL_AUTH_MESSAGE nlAuthMessage = nrpc.CreateNlAuthMessage(); this.token = ArrayUtility.ConcatenateArrays( BitConverter.GetBytes((uint)nlAuthMessage.MessageType), BitConverter.GetBytes((uint)nlAuthMessage.Flags), nlAuthMessage.Buffer); this.needContinueProcessing = true; } else { this.token = null; this.needContinueProcessing = false; NL_AUTH_MESSAGE nlAuthMessage = new NL_AUTH_MESSAGE(); int offset = 0; nlAuthMessage.MessageType = (MessageType_Values)BitConverter.ToInt32(inToken, offset); offset += sizeof(int); // cannot call: Marshal.SizeOf(nlAuthMessage.MessageType); nlAuthMessage.Flags = (NL_AUTH_MESSAGE_Flags_Value)BitConverter.ToUInt32(inToken, offset); offset += sizeof(NL_AUTH_MESSAGE_Flags_Value); nlAuthMessage.Buffer = ArrayUtility.SubArray(inToken, offset, inToken.Length - offset); if (!nrpc.ValidateNlAuthMessage(nlAuthMessage)) { //validate server returned token failed. throw new SspiException("Server returned token is invalid."); } } }
/// <summary> /// Validates the client credential. /// </summary> /// <param name="sessionKey">the session key negotiated</param> /// <param name="negotiateFlags">the negotiation flags</param> /// <param name="clientChallenge">client challenge received</param> /// <param name="clientCredentialReceived">the client credential received</param> private void ValidateClientCredential(byte[] sessionKey, uint negotiateFlags, byte[] clientChallenge, _NETLOGON_CREDENTIAL?clientCredentialReceived) { if (clientCredentialReceived == null || clientCredentialReceived.Value.data == null) { throw new InvalidOperationException("Client Credential doesn't match"); } byte[] clientCredentialComputed = NrpcUtility.ComputeNetlogonCredential(sessionKey, negotiateFlags, clientChallenge); bool compareResult = ArrayUtility.CompareArrays <byte>(clientCredentialReceived.Value.data, clientCredentialComputed); if (!compareResult) { throw new InvalidOperationException("Client Credential doesn't match"); } StoredCredential = clientCredentialComputed; }
/// <summary> /// Construct Nlmp pass-through interactive logon information structure /// from client NTLM authenticate response message /// </summary> /// <param name="parameterControl">A set of bit flags /// that contain information pertaining to the logon validation processing. /// </param> /// <param name="domainName">domain name</param> /// <param name="userName">user name</param> /// <param name="password">password</param> /// <param name="serverName">NetBIOS name of server </param> /// <returns>nlmp interactive logon information structure</returns> public static _NETLOGON_LEVEL CreateNlmpInteractiveLogonInfo( NrpcParameterControlFlags parameterControl, string domainName, string userName, string password, string serverName ) { _NETLOGON_LEVEL netLogonLevel = new _NETLOGON_LEVEL(); //LmOwfPassword: LM_OWF_PASSWORD structure, as specified in section 2.2.1.1.3, //that contains the LMOWFv1 of a password. //LMOWFv1 is specified in NTLM v1 Authentication in [MS-NLMP] section 3.3.1. byte[] lmOwf = NlmpUtility.LmOWF(NlmpVersion.v1, domainName, userName, password); //NtOwfPassword: An NT_OWF_PASSWORD structure, as specified in section 2.2.1.1.4, //that contains the NTOWFv1 of a password. //NTOWFv1 is specified in NTLM v1 Authentication in [MS-NLMP] section 3.3.1. byte[] ntOwf = NlmpUtility.NtOWF(NlmpVersion.v1, domainName, userName, password); //Identity: A NETLOGON_LOGON_IDENTITY_INFO structure, as specified in section MS-NRPC 2.2.1.4.15, //that contains information about the logon identity. _NETLOGON_LOGON_IDENTITY_INFO identityInfo = NrpcUtility.CreateNetlogonIdentityInfo( parameterControl, domainName, userName, serverName); netLogonLevel.LogonInteractive = new _NETLOGON_INTERACTIVE_INFO[1]; netLogonLevel.LogonInteractive[0].Identity = identityInfo; netLogonLevel.LogonInteractive[0].LmOwfPassword = new _LM_OWF_PASSWORD(); netLogonLevel.LogonInteractive[0].LmOwfPassword.data = NrpcUtility.CreateCypherBlocks(lmOwf); netLogonLevel.LogonInteractive[0].NtOwfPassword = new _NT_OWF_PASSWORD(); netLogonLevel.LogonInteractive[0].NtOwfPassword.data = NrpcUtility.CreateCypherBlocks(ntOwf); return(netLogonLevel); }
/// <summary> /// Receives and processes remote requests to establish secure channels /// </summary> /// <param name="threadParameter">A dictionary whose key is the machine name and the /// value is the machine password</param> internal static void EstablishSecureChannel(object threadParameter) { Dictionary <string, string> machineNameToPasswordDictionary = threadParameter as Dictionary <string, string>; if (serverForSecureChannel == null) { serverForSecureChannel = new NrpcServer(null); serverForSecureChannel.StartTcp(tcpPort); //todo: support ipv6 serverForSecureChannel.StartNamedPipe(NrpcUtility.NETLOGON_RPC_OVER_NP_WELLKNOWN_ENDPOINT, null, IPAddress.Any); } TimeSpan defaultTimeSpan = new TimeSpan(0, 0, 0, 0, DefaultTimeout); NrpcServerSessionContext sessionContext; while (!isStopped) { NrpcRequestStub request = serverForSecureChannel.ExpectRpcCall <NrpcRequestStub>(defaultTimeSpan, out sessionContext); switch (request.Opnum) { case NrpcMethodOpnums.NetrServerReqChallenge: NrpcNetrServerReqChallengeRequest nrpcNetrServerReqChallengeRequest = request as NrpcNetrServerReqChallengeRequest; NrpcNetrServerReqChallengeResponse nrpcNetrServerReqChallengeResponse; if (!machineNameToPasswordDictionary.ContainsKey(sessionContext.ClientComputerName)) { nrpcNetrServerReqChallengeResponse = serverForSecureChannel.CreateNetrServerReqChallengeResponse(sessionContext, NrpcUtility.GenerateNonce(8), ""); nrpcNetrServerReqChallengeResponse.Status = NtStatus.STATUS_ACCESS_DENIED; } else { nrpcNetrServerReqChallengeResponse = serverForSecureChannel.CreateNetrServerReqChallengeResponse(sessionContext, NrpcUtility.GenerateNonce(8), machineNameToPasswordDictionary[sessionContext.ClientComputerName]); } serverForSecureChannel.SendRpcCallResponse( sessionContext, nrpcNetrServerReqChallengeResponse); break; case NrpcMethodOpnums.NetrServerAuthenticate: NrpcNetrServerAuthenticateRequest nrpcNetrServerAuthenticateRequest = request as NrpcNetrServerAuthenticateRequest; NrpcNetrServerAuthenticateResponse nrpcNetrServerAuthenticateResponse = serverForSecureChannel.CreateNetrServerAuthenticateResponse(sessionContext); serverForSecureChannel.SendRpcCallResponse( sessionContext, nrpcNetrServerAuthenticateResponse); break; case NrpcMethodOpnums.NetrServerAuthenticate2: NrpcNetrServerAuthenticate2Request nrpcNetrServerAuthenticate2Request = request as NrpcNetrServerAuthenticate2Request; NrpcNetrServerAuthenticate2Response nrpcNetrServerAuthenticate2Response = serverForSecureChannel.CreateNetrServerAuthenticate2Response(sessionContext, (uint)sessionContext.NegotiateFlags); serverForSecureChannel.SendRpcCallResponse( sessionContext, nrpcNetrServerAuthenticate2Response); break; case NrpcMethodOpnums.NetrServerAuthenticate3: NrpcNetrServerAuthenticate3Request nrpcNetrServerAuthenticate3Request = request as NrpcNetrServerAuthenticate3Request; NrpcNetrServerAuthenticate3Response nrpcNetrServerAuthenticate3Response = serverForSecureChannel.CreateNetrServerAuthenticate3Response(sessionContext, (uint)sessionContext.NegotiateFlags, 100); serverForSecureChannel.SendRpcCallResponse( sessionContext, nrpcNetrServerAuthenticate3Response); break; default: //bypass other requests break; } } serverForSecureChannel.StopTcp(tcpPort); serverForSecureChannel.StopNamedPipe(NrpcUtility.NETLOGON_RPC_OVER_NP_WELLKNOWN_ENDPOINT); serverForSecureChannel.Dispose(); serverForSecureChannel = null; }
/// <summary> /// Send Digest request message to DC, and validate the credentials. /// </summary> /// <param name="isValidationSuccess">Indicates whether the validation from server will be success.</param> /// <param name="digestType">Indicates the DigestType field of the request.</param> /// <param name="algType">Indicates the AlgType field of the request.</param> /// <param name="ignoredFields">It indicates the fields that should be ignored by DC in DIGEST_VALIDATION_REQ.</param> /// <returns>Indicates the result status of DC response.</returns> public Status GenerateDigestRequest( Boolean isValidationSuccess, AccountInformation accountInfo, DigestType_Values digestType, AlgType_Values algType, IgnoredFields ignoredFields) { DIGEST_VALIDATION_REQ digestReq; _NETLOGON_LOGON_INFO_CLASS logonLevel = _NETLOGON_LOGON_INFO_CLASS.NetlogonGenericInformation; _NETLOGON_VALIDATION_INFO_CLASS validationLevel = _NETLOGON_VALIDATION_INFO_CLASS.NetlogonValidationGenericInfo2; //Compute the password GenerateCurrentCredentials(accountInfo); //Get Digest Request GetDigestRequest(digestType, algType, ignoredFields, out digestReq); //Create digest validation logon info _NETLOGON_LEVEL netlogonLevel = ApdsUtility.CreateDpspLogonInfo( NrpcParameterControlFlags.AllowLogonWithComputerAccount, digestReq); //Create Secure Channel EstablishSecureChannel(); //Client calls EncryptNetlogonLevel _NETLOGON_LEVEL encryptedLogonLevel = nrpcClient.EncryptNetlogonLevel( (_NETLOGON_LOGON_INFO_CLASS)logonLevel, netlogonLevel); //Client calls NetrLogonSamLogonEx _NETLOGON_VALIDATION?validationInfomation; byte?authoritative; NrpcNetrLogonSamLogonExtraFlags?extraFlags = NrpcNetrLogonSamLogonExtraFlags.None; result = nrpcClient.NetrLogonSamLogonEx( nrpcClient.Handle, sutComputerName, clientComputerName, logonLevel, encryptedLogonLevel, validationLevel, out validationInfomation, out authoritative, ref extraFlags); // Whether this method use pass-through mechanism or not. bool isPassThroughMethod = false; // //The Digest validation protocol SHOULD use the generic pass-through mechanism. //For generic pass-through, the LogonLevel is 4(NetlogonGenericInformation) as defined in [MS-NRPC] section 3.2.4.1. //So when the LogonLevel is 4, we can say that NRPC pass-through authentication method is used. // if ((int)logonLevel == 4) { isPassThroughMethod = true; } // //Verify MS-APDS requirment:MS-APDS_R5 // Site.CaptureRequirementIfIsTrue( isPassThroughMethod, 5, @"For domain support, authentication protocols MUST use an NRPC pass-through authentication ([MS-NRPC] section 3.2) method with parameters determined by the authentication protocol being used[to return the response structures to member server]."); // //Verify MS-APDS requirment:MS-APDS_R15 // Site.CaptureRequirementIfAreEqual <int>( 5, (int)validationLevel, 15, @"Digest response messages MUST be encoded as opaque blobs and transported by the generic pass-through capability of Netlogon."); // //Configured in PTFConfig file,default SHOULD to true and MAY to false. // string isR169Implemented = "true"; // //Check OS version // if (isWindows) { // //Verify MS-APDS requirment:MS-APDS_R100169 // Site.CaptureRequirementIfAreEqual <int>( 5, (int)validationLevel, 100169, @"In Windows, the Digest validation protocol uses the generic pass-through mechanism."); if (null == isR169Implemented) { Site.Properties.Add("R169Implemented", Boolean.TrueString); isR169Implemented = Boolean.TrueString; } } if (null != isR169Implemented) { bool implSigns = Boolean.Parse(isR169Implemented); bool isSatisfied = ((int)_NETLOGON_VALIDATION_INFO_CLASS.NetlogonValidationGenericInfo2 == 5); // //Verify MS-APDS requirment:MS-APDS_R169 // Site.CaptureRequirementIfAreEqual <Boolean>( implSigns, isSatisfied, 169, string.Format(@"The Digest validation protocol SHOULD use the generic pass-through mechanism. This requirement is {0} implemented.", implSigns ? "" : "not")); } byte[] buf; bool isDigestResStructure = true; DIGEST_VALIDATION_RESP digestValidationResponse = new DIGEST_VALIDATION_RESP(); // Judge whether the digest response is exist, validationData is response point. // if validationData equals 0, no response return from NRPC. if (validationInfomation.Value.ValidationGeneric2 == null) { isDigestResStructure = false; } else { // decrypt validation info buf = NrpcUtility.DecryptBuffer( (nrpcClient.Context.NegotiateFlags & NrpcNegotiateFlags.SupportsAESAndSHA2) == NrpcNegotiateFlags.SupportsAESAndSHA2, nrpcClient.Context.SessionKey, validationInfomation.Value.ValidationGeneric2[0].ValidationData); _NETLOGON_VALIDATION decryptValidationInfo = new _NETLOGON_VALIDATION(); decryptValidationInfo.ValidationGeneric2 = new _NETLOGON_VALIDATION_GENERIC_INFO2[1]; decryptValidationInfo.ValidationGeneric2[0].ValidationData = buf; digestValidationResponse = ApdsUtility.ConvertDataToDigestValidationResponse(decryptValidationInfo); VerifyMessageSyntaxDigestValidCredential(digestValidationResponse, validationLevel, (uint)buf.Length); } if (result != NtStatus.STATUS_SUCCESS) { // //Verify MS-APDS requirment:MS-APDS_R292 // Site.CaptureRequirementIfIsFalse( isDigestResStructure, 292, "[If unsuccessful]It[DC] MUST NOT send back the DIGEST_VALIDATION_RESP message."); VerifyMessageSyntxDigestInvalidResp((uint)result, digestValidationResponse.AuthDataSize); } return((Status)result); }
/// <summary> /// Construct Nlmp pass-through network logon information structure /// from client NTLM authenticate response message /// </summary> /// <param name="parameterControl"> /// A set of bit flags that contain information pertaining to the logon validation processing. /// </param> /// <param name="nlmpAuthenticatePacket"> /// nlmp authenticate response packet sent from client machine /// </param> /// <param name="lmChallenge"> /// nlmp challenge sent from server to client /// </param> /// <returns> /// Nlmp pass-through network logon information /// </returns> /// <exception cref="ArgumentNullException"> /// Thrown when nlmpAuthenticatePacket or lmChallenge is null. /// </exception> /// <exception cref="ArgumentException"> /// Thrown when the length of lmChallenge is not equal to 8 bytes /// </exception> public static _NETLOGON_LEVEL CreateNlmpNetworkLogonInfo( NrpcParameterControlFlags parameterControl, NlmpAuthenticatePacket nlmpAuthenticatePacket, byte[] lmChallenge ) { if (nlmpAuthenticatePacket == null) { throw new ArgumentNullException("nlmpAuthenticatePacket"); } if (lmChallenge == null) { throw new ArgumentNullException("lmChallenge"); } // ServerChallenge (8 bytes): A 64-bit value that contains the NTLM challenge. // The challenge is a 64-bit nonce. The processing of the // ServerChallenge is specified in sections 3.1.5 and 3.2.5. if (lmChallenge.Length != NLMP_SERVER_CHALLENGE_LENGTH) { throw new ArgumentException( "the length of lmChallenge should be 8 bytes", "lmChallenge"); } string domainName; string userName; string logonWorkStation; _NETLOGON_LEVEL netLogonLevel = new _NETLOGON_LEVEL(); if (nlmpAuthenticatePacket.Payload.DomainName != null) { domainName = Encoding.Unicode.GetString(nlmpAuthenticatePacket.Payload.DomainName); } else { throw new ArgumentException( "DomainName field should not be null", "nlmpAuthenticatePacket"); } if (nlmpAuthenticatePacket.Payload.UserName != null) { userName = Encoding.Unicode.GetString(nlmpAuthenticatePacket.Payload.UserName); } else { throw new ArgumentException( "UserName field should not be null", "nlmpAuthenticatePacket"); } if (nlmpAuthenticatePacket.Payload.Workstation != null) { logonWorkStation = Encoding.Unicode.GetString(nlmpAuthenticatePacket.Payload.Workstation); } else { throw new ArgumentException( "WorkStation field should not be null", "nlmpAuthenticatePacket"); } //Identity: A NETLOGON_LOGON_IDENTITY_INFO structure, as specified in section MS-NRPC 2.2.1.4.15, //that contains information about the logon identity. _NETLOGON_LOGON_IDENTITY_INFO identityInfo = NrpcUtility.CreateNetlogonIdentityInfo( parameterControl, domainName, userName, logonWorkStation); netLogonLevel.LogonNetwork = new _NETLOGON_NETWORK_INFO[1]; netLogonLevel.LogonNetwork[0].Identity = identityInfo; netLogonLevel.LogonNetwork[0].LmChallenge = new LM_CHALLENGE(); netLogonLevel.LogonNetwork[0].LmChallenge.data = lmChallenge; netLogonLevel.LogonNetwork[0].LmChallengeResponse = NrpcUtility.CreateString(nlmpAuthenticatePacket.Payload.LmChallengeResponse); netLogonLevel.LogonNetwork[0].NtChallengeResponse = NrpcUtility.CreateString(nlmpAuthenticatePacket.Payload.NtChallengeResponse); return(netLogonLevel); }