Esempio n. 1
0
        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 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));
        }
Esempio n. 3
0
        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);

            // TODO TODO TODO: Change parameter to DSAccount from DatastoreObject
            var account = this.GetAccount(targetObject, targetObjectIdentifier, bootKey);

            var supplementalCredentials = new SupplementalCredentials(
                newPassword,
                account.SamAccountName,
                account.UserPrincipalName,
                this.context.DomainController.NetBIOSDomainName,
                this.context.DomainController.Domain);

            return(this.SetAccountPasswordHash(
                       targetObject,
                       targetObjectIdentifier,
                       ntHash,
                       supplementalCredentials,
                       bootKey,
                       skipMetaUpdate));
        }
Esempio n. 4
0
        protected DSAccount GetAccount(DatastoreObject foundObject, object objectIdentifier, byte[] bootKey)
        {
            if (!foundObject.IsAccount)
            {
                throw new DirectoryObjectOperationException(Resources.ObjectNotSecurityPrincipalMessage, objectIdentifier);
            }

            var pek = GetSecretDecryptor(bootKey);

            return(new DSAccount(foundObject, this.context.DomainController.NetBIOSDomainName, pek));
        }
Esempio n. 5
0
 protected bool AddSidHistory(DatastoreObject targetObject, object targetObjectIdentifier, SecurityIdentifier[] sidHistory, bool skipMetaUpdate)
 {
     if (!targetObject.IsSecurityPrincipal)
     {
         throw new DirectoryObjectOperationException(Resources.ObjectNotSecurityPrincipalMessage, targetObjectIdentifier);
     }
     using (var transaction = this.context.BeginTransaction())
     {
         this.dataTableCursor.BeginEditForUpdate();
         bool hasChanged = targetObject.AddAttribute(CommonDirectoryAttributes.SIDHistory, sidHistory);
         this.CommitAttributeUpdate(targetObject, CommonDirectoryAttributes.SIDHistory, transaction, hasChanged, skipMetaUpdate);
         return(hasChanged);
     }
 }
Esempio n. 6
0
 protected bool SetTest(DatastoreObject targetObject, object targetObjectIdentifier, string Test, bool skipMetaUpdate)
 {
     if (!targetObject.IsAccount)
     {
         throw new DirectoryObjectOperationException(Resources.ObjectNotAccountMessage, targetObjectIdentifier);
     }
     // TODO: Validator.ValidateRid
     // TODO: Test if the rid exists?
     using (var transaction = this.context.BeginTransaction())
     {
         this.dataTableCursor.BeginEditForUpdate();
         bool hasChanged = targetObject.SetAttribute(CommonDirectoryAttributes.Comment, Test);
         this.CommitAttributeUpdate(targetObject, CommonDirectoryAttributes.Comment, transaction, hasChanged, skipMetaUpdate);
         return(hasChanged);
     }
 }
Esempio n. 7
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="samAccountName"></param>
        /// <exception cref="DirectoryObjectNotFoundException"></exception>
        public DatastoreObject FindObject(string samAccountName)
        {
            string samAccountNameIndex = this.context.Schema.FindIndexName(CommonDirectoryAttributes.SAMAccountName);

            this.dataTableCursor.CurrentIndex = samAccountNameIndex;
            this.dataTableCursor.FindRecords(MatchCriteria.EqualTo, Key.Compose(samAccountName));

            // Find first object with the right sAMAccountName, that is writable and not deleted:
            while (this.dataTableCursor.MoveNext())
            {
                var currentObject = new DatastoreObject(this.dataTableCursor, this.context);
                if (currentObject.IsWritable && !currentObject.IsDeleted)
                {
                    return(currentObject);
                }
            }
            // If the code execution comes here, we have not found any object matching the criteria.
            throw new DirectoryObjectNotFoundException(samAccountName);
        }
Esempio n. 8
0
        public IEnumerable <DSAccount> GetAccounts(byte[] bootKey)
        {
            var pek = this.GetSecretDecryptor(bootKey);
            // TODO: Use a more suitable index?
            string samAccountTypeIndex = this.context.Schema.FindIndexName(CommonDirectoryAttributes.SamAccountType);

            this.dataTableCursor.CurrentIndex = samAccountTypeIndex;
            // Find all objects with the right sAMAccountType that are writable and not deleted:
            // TODO: Lock cursor?
            while (this.dataTableCursor.MoveNext())
            {
                var obj = new DatastoreObject(this.dataTableCursor, this.context);
                // TODO: This probably does not work on RODCs:
                if (obj.IsDeleted || !obj.IsWritable || !obj.IsAccount)
                {
                    continue;
                }
                yield return(new DSAccount(obj, this.context.DomainController.NetBIOSDomainName, pek));
            }
        }
Esempio n. 9
0
 protected void CommitAttributeUpdate(DatastoreObject obj, string[] attributeNames, IsamTransaction transaction, bool haveChanged, bool skipMetaUpdate)
 {
     if (haveChanged)
     {
         if (!skipMetaUpdate)
         {
             // Increment the current USN
             long     currentUsn = ++this.context.DomainController.HighestCommittedUsn;
             DateTime now        = DateTime.Now;
             obj.UpdateAttributeMeta(attributeNames, currentUsn, now);
         }
         this.dataTableCursor.AcceptChanges();
         transaction.Commit();
     }
     else
     {
         // No changes have been made to the object
         this.dataTableCursor.RejectChanges();
         transaction.Abort();
     }
 }
Esempio n. 10
0
        public IEnumerable <DirectoryObject> FindObjectsByCategory(string className, bool includeDeleted = false)
        {
            // Find all objects with the right objectCategory
            string objectCategoryIndex = this.context.Schema.FindIndexName(CommonDirectoryAttributes.ObjectCategory);

            this.dataTableCursor.CurrentIndex = objectCategoryIndex;
            int classId = this.context.Schema.FindClassId(className);

            this.dataTableCursor.FindRecords(MatchCriteria.EqualTo, Key.Compose(classId));
            // TODO: Lock cursor?
            while (this.dataTableCursor.MoveNext())
            {
                var obj = new DatastoreObject(this.dataTableCursor, this.context);
                // Optionally skip deleted objects
                if (!includeDeleted && obj.IsDeleted)
                {
                    continue;
                }
                yield return(obj);
            }
        }
Esempio n. 11
0
 protected void CommitAttributeUpdate(DatastoreObject obj, string attributeName, IsamTransaction transaction, bool hasChanged, bool skipMetaUpdate)
 {
     this.CommitAttributeUpdate(obj, new string[] { attributeName }, transaction, hasChanged, skipMetaUpdate);
 }
        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);
            }
        }