示例#1
0
        public void DistinguishedName_AddParent_Null()
        {
            var dn = new DistinguishedName("CN=Users");

            dn.AddParent((DistinguishedName)null);
            dn.AddParent((DistinguishedNameComponent)null);
            Assert.AreEqual("CN=Users", dn.ToString());
        }
        public void DistinguishedName_AddParent()
        {
            var dn = new DistinguishedName("CN=Users");

            dn.AddParent(new DistinguishedName("DC=adatum,DC=com"));
            Assert.AreEqual("CN=Users,DC=adatum,DC=com", dn.ToString());
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="dnTag"></param>
        /// <returns></returns>
        /// <exception cref="DirectoryObjectNotFoundException"></exception>
        public DistinguishedName Resolve(int dnTag)
        {
            if (dnTag < ADConstants.RootDNTag)
            {
                throw new ArgumentOutOfRangeException("dnTag");
            }
            if (dnTag == ADConstants.RootDNTag)
            {
                // TODO: or null?
                return(new DistinguishedName());
            }
            // TODO: Move to constructor?
            var dntColId     = schema.FindColumnId(CommonDirectoryAttributes.DNTag);
            var pdntColId    = schema.FindColumnId(CommonDirectoryAttributes.ParentDNTag);
            var rdnColId     = schema.FindColumnId(CommonDirectoryAttributes.RDN);
            var rdnTypeColId = schema.FindColumnId(CommonDirectoryAttributes.RDNType);

            DistinguishedName dn = new DistinguishedName();

            cursor.CurrentIndex = schema.FindIndexName(CommonDirectoryAttributes.DNTag);
            int currentDNTag = dnTag;

            do
            {
                bool found = cursor.GotoKey(Key.Compose(currentDNTag));
                if (!found)
                {
                    throw new DirectoryObjectNotFoundException(dnTag);
                }
                string name    = cursor.RetrieveColumnAsString(rdnColId);
                int    rdnType = cursor.RetrieveColumnAsInt(rdnTypeColId).Value;
                string rdnAtt  = schema.FindAttribute(rdnType).Name.ToUpper();
                dn.AddParent(rdnAtt, name);
                currentDNTag = cursor.RetrieveColumnAsDNTag(pdntColId).Value;
            } while (currentDNTag != ADConstants.RootDNTag);

            // TODO: Parent DN Caching
            return(dn);
        }
示例#4
0
        /// <summary>
        /// Recursively resolves a DN Tag to a full distinguished name.
        /// </summary>
        /// <param name="dnTag">Distinguished name tag</param>
        /// <returns>Resolved DN</returns>
        /// <exception cref="DirectoryObjectNotFoundException" />
        public DistinguishedName Resolve(int dnTag)
        {
            // Check the DN cache first
            DistinguishedName dnFromCache = this.TryResolveFromCache(dnTag);

            if (dnFromCache != null)
            {
                // We just return the DN from cache.
                return(dnFromCache);
            }

            if (dnTag < ADConstants.RootDNTag)
            {
                // Minimum DN Tag is 2.
                throw new ArgumentOutOfRangeException("dnTag");
            }

            // Cache column IDs
            var dntColId     = schema.FindColumnId(CommonDirectoryAttributes.DNTag);
            var pdntColId    = schema.FindColumnId(CommonDirectoryAttributes.ParentDNTag);
            var rdnColId     = schema.FindColumnId(CommonDirectoryAttributes.RDN);
            var rdnTypeColId = schema.FindColumnId(CommonDirectoryAttributes.RDNType);

            // Set index to the Distinguished Name Tag (~primary key)
            cursor.CurrentIndex = schema.FindIndexName(CommonDirectoryAttributes.DNTag);

            // We will build the DN from leaf to root
            DistinguishedName result = new DistinguishedName();
            int currentDNTag         = dnTag;

            while (currentDNTag != ADConstants.RootDNTag)
            {
                // Move cursor to the current object
                bool found = cursor.GotoKey(Key.Compose(currentDNTag));
                if (!found)
                {
                    throw new DirectoryObjectNotFoundException(dnTag);
                }

                // Retrieve the current object's RDN, e.g. CN=Administrator
                string name       = cursor.RetrieveColumnAsString(rdnColId);
                int    rdnType    = cursor.RetrieveColumnAsInt(rdnTypeColId).Value;
                string rdnAtt     = schema.FindAttribute(rdnType).Name.ToUpper();
                var    currentRDN = new DistinguishedNameComponent(rdnAtt, name);

                // Concat the current RDN with the child RDN in result
                result.AddParent(currentRDN);

                // Identify the current object's parent
                int parentDNTag = cursor.RetrieveColumnAsDNTag(pdntColId).Value;

                // Check the DN cache
                DistinguishedName parentDN = this.TryResolveFromCache(parentDNTag);
                if (parentDN != null)
                {
                    // We have found the parent object in DN cache.
                    result.AddParent(parentDN);

                    // Add the current object to cache if the parent is DC or root.
                    bool shoulCache = parentDN.Components.Count == 0 ||
                                      String.Equals(parentDN.Components[0].Name, CommonDirectoryAttributes.DomainComponent, StringComparison.OrdinalIgnoreCase);
                    if (shoulCache)
                    {
                        var currentDN = new DistinguishedName(currentRDN);
                        currentDN.AddParent(parentDN);
                        this.dnCache.Add(currentDNTag, currentDN);
                    }

                    // We can stop the recursion as we have resolved the entire DN using cache.
                    break;
                }

                // Move upwards to the object's parent as we have not found it in the DN cache.
                currentDNTag = parentDNTag;
            }

            return(result);
        }
示例#5
0
        public DomainController(DirectoryContext context)
        {
            // TODO: Split to different methods.

            // Open the hiddentable
            this.systemTableCursor = context.OpenSystemTable();

            // Go to the first and only record in the hiddentable:
            this.systemTableCursor.MoveToFirst();

            // Load attributes from the hiddentable:
            this.NTDSSettingsDNT = this.systemTableCursor.RetrieveColumnAsInt(ntdsSettingsCol).Value;

            if (this.systemTableCursor.TableDefinition.Columns.Contains(osVersionMajorCol))
            {
                // Some databases like the initial adamntds.dit or ntds.dit on Windows Server 2003 do not contain the OS Version
                this.OSVersionMinor = this.systemTableCursor.RetrieveColumnAsUInt(osVersionMinorCol);
                this.OSVersionMajor = this.systemTableCursor.RetrieveColumnAsUInt(osVersionMajorCol);
            }

            if (this.systemTableCursor.TableDefinition.Columns.Contains(epochCol))
            {
                // This is a new feature since Windows Server 2008
                this.epochCache = this.systemTableCursor.RetrieveColumnAsInt(epochCol);
            }

            if (this.systemTableCursor.TableDefinition.Columns.Contains(usnAtIfmCol))
            {
                this.UsnAtIfm = this.systemTableCursor.RetrieveColumnAsLong(usnAtIfmCol);
            }

            // Load and cache the backup expiration time
            this.backupExpirationCache = this.systemTableCursor.RetrieveColumnAsGeneralizedTime(backupExpirationCol);

            this.BackupUsn = this.systemTableCursor.RetrieveColumnAsLong(backupUsnCol);
            this.State     = (DatabaseState)this.systemTableCursor.RetrieveColumnAsInt(stateCol).Value;
            byte[] binaryFlags   = this.systemTableCursor.RetrieveColumnAsByteArray(flagsCol);
            var    databaseFlags = new DatabaseFlags(binaryFlags);

            this.IsADAM = databaseFlags.ADAMDatabase;
            // TODO: Export other database flags, not just IsADAM.
            // TODO: Load database health
            this.highestUSNCache = this.systemTableCursor.RetrieveColumnAsLong(highestCommitedUsnCol).Value;

            // Now we can load the Invocation ID and other information from the datatable:
            using (var dataTableCursor = context.OpenDataTable())
            {
                // Goto NTDS Settings object:
                DirectorySchema schema = context.Schema;
                dataTableCursor.CurrentIndex = schema.FindIndexName(CommonDirectoryAttributes.DNTag);
                bool ntdsFound = dataTableCursor.GotoKey(Key.Compose(this.NTDSSettingsDNT));

                // Load data from the NTDS Settings object
                this.InvocationId = dataTableCursor.RetrieveColumnAsGuid(schema.FindColumnId(CommonDirectoryAttributes.InvocationId)).Value;
                this.DsaGuid      = dataTableCursor.RetrieveColumnAsGuid(schema.FindColumnId(CommonDirectoryAttributes.ObjectGUID)).Value;
                this.Options      = dataTableCursor.RetrieveColumnAsDomainControllerOptions(schema.FindColumnId(CommonDirectoryAttributes.Options));
                string ntdsName = dataTableCursor.RetrieveColumnAsString(schema.FindColumnId(CommonDirectoryAttributes.CommonName));

                // Retrieve Configuration Naming Context
                this.ConfigurationNamingContextDNT = dataTableCursor.RetrieveColumnAsDNTag(schema.FindColumnId(CommonDirectoryAttributes.NamingContextDNTag)).Value;
                this.ConfigurationNamingContext    = context.DistinguishedNameResolver.Resolve(this.ConfigurationNamingContextDNT);

                // Retrieve Schema Naming Context
                this.SchemaNamingContextDNT = dataTableCursor.RetrieveColumnAsDNTag(schema.FindColumnId(CommonDirectoryAttributes.SchemaLocation)).Value;
                this.SchemaNamingContext    = context.DistinguishedNameResolver.Resolve(this.SchemaNamingContextDNT);

                // Goto DC object (parent of NTDS):
                bool dcFound = dataTableCursor.GotoParentObject(schema);

                // Load data from the DC object

                // Load DC name:
                string dcName = dataTableCursor.RetrieveColumnAsString(schema.FindColumnId(CommonDirectoryAttributes.CommonName));

                // DC name is null in the initial database, so use NTDS Settings object's CN instead
                this.Name = dcName ?? ntdsName;

                // Load DNS Host Name
                this.DNSHostName = dataTableCursor.RetrieveColumnAsString(schema.FindColumnId(CommonDirectoryAttributes.DNSHostName));

                // Load server reference to domain partition:
                int dcDNTag = dataTableCursor.RetrieveColumnAsDNTag(schema.FindColumnId(CommonDirectoryAttributes.DNTag)).Value;
                this.ServerReferenceDNT = context.LinkResolver.GetLinkedDNTag(dcDNTag, CommonDirectoryAttributes.ServerReference);

                // Goto Servers object (parent of DC):
                bool serversFound = dataTableCursor.GotoParentObject(schema);
                // Goto Site object (parent of servers):
                bool siteFound = dataTableCursor.GotoParentObject(schema);
                // Load data from the Site object
                if (siteFound)
                {
                    this.SiteName = dataTableCursor.RetrieveColumnAsString(schema.FindColumnId(CommonDirectoryAttributes.CommonName));
                }

                // Load partitions (linked multivalue attribute)
                // TODO: Does not return PAS partitions on RODCs
                IEnumerable <int> partitionDNTags = context.LinkResolver.GetLinkedDNTags(this.NTDSSettingsDNT, CommonDirectoryAttributes.MasterNamingContexts);
                this.WritablePartitions = context.DistinguishedNameResolver.Resolve(partitionDNTags).Select(dn => dn.ToString()).ToArray();

                // Load domain (linked multivalue attribute)
                // TODO: Test this against a GC and RODC:
                this.DomainNamingContextDNT = context.LinkResolver.GetLinkedDNTag(this.NTDSSettingsDNT, CommonDirectoryAttributes.DomainNamingContexts);
                if (this.DomainNamingContextDNT.HasValue)
                {
                    // Move cursor to domain:
                    bool domainObjectFound = dataTableCursor.GotoKey(Key.Compose(this.DomainNamingContextDNT.Value));

                    // Load domain SID
                    this.DomainSid = dataTableCursor.RetrieveColumnAsSid(schema.FindColumnId(CommonDirectoryAttributes.ObjectSid));

                    // Load domain naming context:
                    this.DomainNamingContext = context.DistinguishedNameResolver.Resolve(this.DomainNamingContextDNT.Value);

                    // Load the domain functional level
                    this.DomainMode = dataTableCursor.RetrieveColumnAsFunctionalLevel(schema.FindColumnId(CommonDirectoryAttributes.FunctionalLevel));
                }

                // Goto server object in domain partition
                if (this.ServerReferenceDNT.HasValue)
                {
                    bool serverFound = dataTableCursor.GotoKey(Key.Compose(this.ServerReferenceDNT.Value));
                    this.OSName          = dataTableCursor.RetrieveColumnAsString(schema.FindColumnId(CommonDirectoryAttributes.OperatingSystemName));
                    this.ServerReference = context.DistinguishedNameResolver.Resolve(this.ServerReferenceDNT.Value);
                }

                // Construct crossRefContainer DN (CN=Partitions,CN=Configuration,...)
                var crossRefContainer = new DistinguishedName(CrossRefContainerRDN);
                crossRefContainer.AddParent(this.ConfigurationNamingContext);

                // Goto crossRefContainer
                var  crossRefContainerDNT   = context.DistinguishedNameResolver.Resolve(crossRefContainer);
                bool crossRefContainerFound = dataTableCursor.GotoKey(Key.Compose(crossRefContainerDNT));

                // Read the forest functional level from the crossRefContainer object we just located
                this.ForestMode = dataTableCursor.RetrieveColumnAsFunctionalLevel(schema.FindColumnId(CommonDirectoryAttributes.FunctionalLevel));
            }
        }