/// <summary>
        ///  The NetrServerPasswordSet2 method Supported in windows_2000_server,
        ///  windows_xp, windows_server_2003, windows_vista, windows_server_2008,
        ///  windows_7, and windows_server_7. allows the client
        ///  to set a new clear text password for an account used
        ///  by the domain controller (as specified in section )
        ///  for setting up the secure channel from the client. A
        ///  domain member uses this function to periodically change
        ///  its machine account password. A PDC uses this function
        ///  to periodically change the trust password for all directly
        ///  trusted domains. By default, the period is 30 days
        ///  in windows_2000_server, windows_xp, windows_server_2003,
        ///  windows_vista, windows_server_2008, windows_7, and
        ///  windows_server_7. Opnum: 30 
        /// </summary>
        /// <param name="PrimaryName">
        ///  The custom RPC binding handle, as specified in section
        ///  .
        /// </param>
        /// <param name="AccountName">
        ///  The null-terminated Unicode string that contains the
        ///  name of the account whose password is being changed. In
        ///  windows, all machine account names are the name of
        ///  the machine with a $ (dollar sign) appended.
        /// </param>
        /// <param name="SecureChannelType">
        ///  An enumerated value that describes the secure channel
        ///  to be used for authentication, as specified in section
        ///  .
        /// </param>
        /// <param name="ComputerName">
        ///  The null-terminated Unicode string that contains the
        ///  NetBIOS name of the computer making the request.
        /// </param>
        /// <param name="Authenticator">
        ///  A pointer to a NETLOGON_AUTHENTICATOR structure, as
        ///  specified in section , that contains the encrypted
        ///  logon credential and a time stamp.
        /// </param>
        /// <param name="ReturnAuthenticator">
        ///  A pointer to a NETLOGON_AUTHENTICATOR structure, as
        ///  specified in section , that contains the server return
        ///  authenticator.
        /// </param>
        /// <param name="ClearNewPassword">
        ///  A pointer to an NL_TRUST_PASSWORD structure, as specified
        ///  in section , that contains the new password encrypted
        ///  as specified in Calling NetrServerPasswordSet2.
        /// </param>
        public NtStatus NetrServerPasswordSet2(
            string PrimaryName,
            string AccountName,
            _NETLOGON_SECURE_CHANNEL_TYPE SecureChannelType,
            string ComputerName,
            _NETLOGON_AUTHENTICATOR? Authenticator,
            out _NETLOGON_AUTHENTICATOR? ReturnAuthenticator,
            _NL_TRUST_PASSWORD? ClearNewPassword)
        {
            const ushort opnum = 30;

            byte[] requestStub;
            byte[] responseStub;
            Int3264[] paramList;
            int retVal;

            SafeIntPtr pPrimaryName = Marshal.StringToHGlobalUni(PrimaryName);
            SafeIntPtr pAccountName = Marshal.StringToHGlobalUni(AccountName);
            SafeIntPtr pComputerName = Marshal.StringToHGlobalUni(ComputerName);
            SafeIntPtr pAuthenticator = TypeMarshal.ToIntPtr(Authenticator);
            SafeIntPtr pClearNewPassword = TypeMarshal.ToIntPtr(ClearNewPassword);

            paramList = new Int3264[] {
                pPrimaryName,
                pAccountName,
                (uint)SecureChannelType,
                pComputerName,
                pAuthenticator,
                IntPtr.Zero,
                pClearNewPassword,
                0 // retVal
            };

            requestStub = RpceStubEncoder.ToBytes(
                     RpceStubHelper.GetPlatform(),
                    NrpcRpcStubFormatString.TypeFormatString,
                    new RpceStubExprEval[] { new RpceStubExprEval(logon__NETLOGON_DELTA_USERExprEval_0000) },
                    NrpcRpcStubFormatString.ProcFormatString,
                    NrpcRpcStubFormatString.ProcFormatStringOffsetTable[opnum],
                    true,
                    paramList);

            rpceClientTransport.Call(opnum, requestStub, rpceTimeout, out responseStub);

            using (RpceInt3264Collection outParamList = RpceStubDecoder.ToParamList(
                     RpceStubHelper.GetPlatform(),
                    NrpcRpcStubFormatString.TypeFormatString,
                    new RpceStubExprEval[] { new RpceStubExprEval(logon__NETLOGON_DELTA_USERExprEval_0000) },
                    NrpcRpcStubFormatString.ProcFormatString,
                    NrpcRpcStubFormatString.ProcFormatStringOffsetTable[opnum],
                    true,
                    responseStub,
                    paramList))
            {
                IntPtr pReturnAuthenticator = outParamList[5];
                ReturnAuthenticator = TypeMarshal.ToNullableStruct<_NETLOGON_AUTHENTICATOR>(pReturnAuthenticator);

                retVal = outParamList[7].ToInt32();
            }

            pPrimaryName.Dispose();
            pAccountName.Dispose();
            pComputerName.Dispose();
            pAuthenticator.Dispose();
            pClearNewPassword.Dispose();

            return (NtStatus)retVal;
        }
        /// <summary>
        /// Encrypt a NL_TRUST_PASSWORD structure.
        /// </summary>
        /// <param name="nlTrustPassword">
        /// A NL_TRUST_PASSWORD structure which contains data to be encrypted.
        /// </param>
        /// <returns>Encrypted NL_TRUST_PASSWORD.</returns>
        /// <exception cref="ArgumentException">
        /// Thrown when nlTrustPassword is invalid.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// Thrown when the method is called before establishing a NRPC secure channel. 
        /// Thrown when neither AES nor RC4 is negotiated.
        /// </exception>
        public _NL_TRUST_PASSWORD EncryptNlTrustPassword(_NL_TRUST_PASSWORD nlTrustPassword)
        {
            if (nlTrustPassword.Buffer == null)
            {
                throw new ArgumentException("nlTrustPassword is invalid.", "nlTrustPassword");
            }
            ValidateSecureChannelExists();

            //Encrypt the ClearNewPassword parameter using the RC4 algorithm
            //and the session key established as the encryption key.
            using (SafeIntPtr ptr = TypeMarshal.ToIntPtr(nlTrustPassword))
            {
                byte[] buf = new byte[
                    nlTrustPassword.Buffer.Length * sizeof(ushort)
                    + Marshal.SizeOf(nlTrustPassword.Length)];
                Marshal.Copy(ptr, buf, 0, buf.Length);
                buf = NrpcUtility.EncryptBuffer(IsAesOrRc4Negotiated(), context.SessionKey, buf);
                Marshal.Copy(buf, 0, ptr, buf.Length);
                return TypeMarshal.ToStruct<_NL_TRUST_PASSWORD>(ptr);
            }
        }
        /// <summary>
        ///  The NetrServerPasswordSet2 method Supported in windows_2000_server,
        ///  windows_xp, windows_server_2003, windows_vista, windows_server_2008,
        ///  windows_7, and windows_server_7. allows the client
        ///  to set a new clear text password for an account used
        ///  by the domain controller 
        ///  for setting up the secure channel from the client. A
        ///  domain member uses this function to periodically change
        ///  its machine account password. A PDC uses this function
        ///  to periodically change the trust password for all directly
        ///  trusted domains. By default, the period is 30 days
        ///  in windows_2000_server, windows_xp, windows_server_2003,
        ///  windows_vista, windows_server_2008, windows_7, and
        ///  windows_server_7. Opnum: 30 
        /// </summary>
        /// <param name="primaryName">
        ///  The custom RPC binding handle.
        /// </param>
        /// <param name="accountName">
        ///  The null-terminated Unicode string that contains the
        ///  name of the account whose password is being changed. In
        ///  windows, all machine account names are the name of
        ///  the machine with a $ (dollar sign) appended.
        /// </param>
        /// <param name="secureChannelType">
        ///  An enumerated value that describes the secure channel
        ///  to be used for authentication.
        /// </param>
        /// <param name="computerName">
        ///  The null-terminated Unicode string that contains the
        ///  NetBIOS name of the computer making the request.
        /// </param>
        /// <param name="authenticator">
        ///  A pointer to a NETLOGON_AUTHENTICATOR structure, 
        ///  that contains the encrypted
        ///  logon credential and a time stamp.
        /// </param>
        /// <param name="returnAuthenticator">
        ///  A pointer to a NETLOGON_AUTHENTICATOR structure, 
        ///  that contains the server return
        ///  authenticator.
        /// </param>
        /// <param name="clearNewPassword">
        ///  A pointer to an NL_TRUST_PASSWORD structure, 
        ///  that contains the new password encrypted
        ///  as specified in Calling NetrServerPasswordSet2.
        /// </param>
        /// <returns>
        /// The method returns 0x00000000 on success; 
        /// otherwise, it returns a nonzero error code.
        /// </returns>
        public NtStatus NetrServerPasswordSet2(
            string primaryName,
            string accountName,
            _NETLOGON_SECURE_CHANNEL_TYPE secureChannelType,
            string computerName,
            _NETLOGON_AUTHENTICATOR? authenticator,
            out _NETLOGON_AUTHENTICATOR? returnAuthenticator,
            _NL_TRUST_PASSWORD? clearNewPassword)
        {
            NtStatus status = rpc.NetrServerPasswordSet2(
                primaryName,
                accountName,
                secureChannelType,
                computerName,
                authenticator,
                out returnAuthenticator,
                clearNewPassword);

            context.ConnectionStatus = status;
            return status;
        }
        /// <summary>
        /// Create an instance of NL_TRUST_PASSWORD structure. 
        /// The data is not encrypted, the caller should call 
        /// EncryptNlTrustPassword to encrypt it.
        /// </summary>
        /// <param name="password">The clear text password.
        /// </param>
        /// <param name="isInterdomainAccount">
        /// If the password is for an interdomain account, 
        /// the TrustPasswordVersion in context will be added to 
        /// NL_TRUST_PASSWORD structure and updated accordingly.
        /// For any other type of account, TrustPasswordVersion is not used.
        /// </param>
        /// <returns>Created but not-yet-encrypted NL_TRUST_PASSWORD structure.</returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown when password is null.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// Thrown when password length exceeds the limit.
        /// </exception>
        public _NL_TRUST_PASSWORD CreateNlTrustPassword(
            string password,
            bool isInterdomainAccount)
        {
            if (password == null)
            {
                throw new ArgumentNullException("password");
            }

            _NL_TRUST_PASSWORD nlTrustPassword = new _NL_TRUST_PASSWORD();

            //The ClearNewPassword parameter is constructed as follows,
            //assuming a WCHAR-represented password of length X bytes.
            byte[] passwordBuffer = Encoding.Unicode.GetBytes(password);
            int X = passwordBuffer.Length;

            if (X > 512)
            {
                throw new ArgumentException("password length exceeds the limit.", "password");
            }

            byte[] buffer;

            if (isInterdomainAccount)
            {
                //If the password is for an interdomain account:

                //An NL_PASSWORD_VERSION structure, as specified in section 2.2.1.3.8,
                //is prepared. The PasswordVersionNumber field of the structure is set to
                //the value of the TrustPasswordVersion variable corresponding to
                //the password being set. The first trust password generated has
                //TrustPasswordVersion equal to one. Each time a new trust password
                //is generated, its TrustPasswordVersion is computed by adding one
                //to the value of TrustPasswordVersion of the previous password.
                //The NL_PASSWORD_VERSION structure is copied into ClearNewPassword.Buffer
                //starting at byte offset (512 - X - size of (NL_PASSWORD_VERSION)).
                _NL_PASSWORD_VERSION nlPasswordVersion = new _NL_PASSWORD_VERSION();
                nlPasswordVersion.ReservedField = ReservedField_Values.V1;
                nlPasswordVersion.PasswordVersionNumber = context.TrustPasswordVersion;
                nlPasswordVersion.PasswordVersionPresent = PasswordVersionPresent_Values.V1;
                byte[] nlPasswordVersionBuf = TypeMarshal.ToBytes(nlPasswordVersion);

                if ((X + nlPasswordVersionBuf.Length) > 512)
                {
                    throw new ArgumentException("password length exceeds the limit.", "password");
                }

                //The password is copied into the Buffer field of ClearNewPassword,
                //which is treated as an array of bytes, starting at byte offset (512 - X).
                //The first (512 - X) - size of (NL_PASSWORD_VERSION) bytes of
                //ClearNewPassword.Buffer are filled with randomly generated data.
                buffer = ArrayUtility.ConcatenateArrays(
                    NrpcUtility.GenerateNonce(512 - X - nlPasswordVersionBuf.Length),
                    nlPasswordVersionBuf,
                    passwordBuffer);

                context.TrustPasswordVersion += 1;
            }
            else
            {
                //If the password is not for an interdomain account:
                buffer = ArrayUtility.ConcatenateArrays(
                    NrpcUtility.GenerateNonce(512 - X),
                    passwordBuffer);
            }

            nlTrustPassword.Buffer = new ushort[256];
            Buffer.BlockCopy(buffer, 0, nlTrustPassword.Buffer, 0, 512);

            //ClearNewPassword.Length is set to X.
            nlTrustPassword.Length = (uint)X;

            return nlTrustPassword;
        }