protected bool SetAccountPassword(DatastoreObject targetObject, object targetObjectIdentifier, SecureString newPassword, byte[] bootKey, bool skipMetaUpdate) { // Validate input Validator.AssertNotNull(newPassword, "newPassword"); // Calculate NT hash byte[] ntHash = NTHash.ComputeHash(newPassword); // We need to read sAMAccountName and userPrincipalName to be able to generate the supplementalCredentials. string samAccountName; targetObject.ReadAttribute(CommonDirectoryAttributes.SAMAccountName, out samAccountName); string userPrincipalName; targetObject.ReadAttribute(CommonDirectoryAttributes.UserPrincipalName, out userPrincipalName); var supplementalCredentials = new SupplementalCredentials( newPassword, samAccountName, userPrincipalName, this.context.DomainController.NetBIOSDomainName, this.context.DomainController.DomainName); return(this.SetAccountPasswordHash( targetObject, targetObjectIdentifier, ntHash, supplementalCredentials, bootKey, skipMetaUpdate)); }
protected bool SetAccountStatus(DatastoreObject targetObject, object targetObjectIdentifier, bool enabled, bool skipMetaUpdate) { using (var transaction = this.context.BeginTransaction()) { // Read the current value first. We do not want to touch any other flags. int?numericUac; targetObject.ReadAttribute(CommonDirectoryAttributes.UserAccountControl, out numericUac); if (!numericUac.HasValue) { // This object does not have the userAccountControl attribute, so it probably is not an account. throw new DirectoryObjectOperationException(Resources.ObjectNotAccountMessage, targetObjectIdentifier); } var uac = (UserAccountControl)numericUac.Value; if (enabled) { // Clear the ADS_UF_ACCOUNTDISABLE flag uac &= ~UserAccountControl.Disabled; } else { // Set the ADS_UF_ACCOUNTDISABLE flag uac |= UserAccountControl.Disabled; } this.dataTableCursor.BeginEditForUpdate(); bool hasChanged = targetObject.SetAttribute <int>(CommonDirectoryAttributes.UserAccountControl, (int?)uac); this.CommitAttributeUpdate(targetObject, CommonDirectoryAttributes.UserAccountControl, transaction, hasChanged, skipMetaUpdate); return(hasChanged); } }
protected bool SetAccountPasswordHash(DatastoreObject targetObject, object targetObjectIdentifier, byte[] newNtHash, SupplementalCredentials newSupplementalCredentials, byte[] bootKey, bool skipMetaUpdate) { // Validate input Validator.AssertLength(newNtHash, NTHash.HashSize, "newNtHash"); Validator.AssertNotNull(bootKey, "bootKey"); if (!targetObject.IsAccount) { throw new DirectoryObjectOperationException(Resources.ObjectNotSecurityPrincipalMessage, targetObjectIdentifier); } if (newSupplementalCredentials == null) { // Create empty supplemental credentials structure, beca newSupplementalCredentials = new SupplementalCredentials(); } // Load the password encryption key var pek = this.GetSecretDecryptor(bootKey); // Calculate LM hash // Note that AD uses a random value in LM hash history since 2003. byte[] lmHash = new byte[LMHash.HashSize]; new Random().NextBytes(lmHash); // Write the data using (var transaction = this.context.BeginTransaction()) { // Load account RID as it is used in the key derivation process SecurityIdentifier sid; targetObject.ReadAttribute(CommonDirectoryAttributes.ObjectSid, out sid); int rid = sid.GetRid(); // Start a database transaction this.dataTableCursor.BeginEditForUpdate(); // Encrypt and set NT hash byte[] encryptedNtHash = pek.EncryptHash(newNtHash, rid); targetObject.SetAttribute(CommonDirectoryAttributes.NTHash, encryptedNtHash); // Clear the LM hash (Default behavior since 2003) byte[] clear = null; targetObject.SetAttribute(CommonDirectoryAttributes.LMHash, clear); // Encrypt and set NT hash history byte[] encryptedNtHashHistory = pek.EncryptHashHistory(new byte[][] { newNtHash }, rid); targetObject.SetAttribute(CommonDirectoryAttributes.NTHashHistory, encryptedNtHashHistory); // Encrypt and set LM hash history. byte[] encryptedLmHashHistory = pek.EncryptHashHistory(new byte[][] { lmHash }, rid); targetObject.SetAttribute(CommonDirectoryAttributes.LMHashHistory, encryptedLmHashHistory); // Encrypt and set Supplemental Credentials byte[] encryptedSupplementalCredentials = pek.EncryptSecret(newSupplementalCredentials.ToByteArray()); targetObject.SetAttribute(CommonDirectoryAttributes.SupplementalCredentials, encryptedSupplementalCredentials); // Set the pwdLastSet attribute if (!skipMetaUpdate) { targetObject.SetAttribute(CommonDirectoryAttributes.PasswordLastSet, DateTime.Now); } // As supplementalCredentials contains salted values, we will always presume that the values of password attributes have changed. bool passwordHasChanged = true; string[] passwordAttributes = { CommonDirectoryAttributes.NTHash, CommonDirectoryAttributes.NTHashHistory, CommonDirectoryAttributes.LMHash, CommonDirectoryAttributes.LMHashHistory, CommonDirectoryAttributes.SupplementalCredentials, CommonDirectoryAttributes.PasswordLastSet }; this.CommitAttributeUpdate(targetObject, passwordAttributes, transaction, passwordHasChanged, skipMetaUpdate); return(passwordHasChanged); } }