Understanding the Schema

The schema is the collection of class and attribute definitions in Active Directory. Active Directory has over 140 predefined types of classes and over 850 attributes. These classes and attributes define what data can be stored in the directory. In the following sections, I'll describe the base concepts of the schema and then provide a more detailed discussion of classes, attributes, and syntaxes.

Object Classes

The Active Directory schema contains objects that define each class that can be stored within the directory. Each class determines the rules to use when creating new objects of that class and the available attributes. For example, the Active Directory person class specifies that objects created using this class must have a cn (Common-Name) attribute and can optionally include a sn (Surname) and telephoneNumber attribute.

An Active Directory class also sets the rules for naming and containership. For example, every object has a naming attribute that is used to create its relative distinguished name (RDN). The naming attribute for new objects of the organizationalUnit class is the ou (Organizational-Unit-Name) attribute instead of the often-used cn attribute. Also, since any object can potentially be a container, you might expect the container to specify which classes of objects it can contain, but actually, the object class specifies what containers it's allowed to exist in. For example, contact class objects can exist only in domainDNS and organizationalUnit containers.

A class also sets the default security for new objects of the class. A default security descriptor is contained in the class and is copied to each object based on that class. I'll discuss security in more detail later in the chapter in the section "Security."

The terms class and object are overused in computer programming, so to make clear their usage in the context of Active Directory, remember that a class in Active Directory, sometimes called an object class, is a template that defines the type of object and what information is contained within it. An object is an instance of a class.

Object Attributes

The Active Directory schema also contains objects that define each attribute that can be stored within the directory. The definition of an attribute includes specifications for the name of the attribute, the type of data stored, and the range of values it can have. The definition also indicates whether attributes are mandatory or optional for a given object class. In Active Directory, attributes are defined only once and are available globally. This is different from COM objects, for which attributes (called properties in COM) are defined as part of the object.

An attribute can be defined and stored in the schema and used with one, many, or no classes. The class definition determines whether a particular attribute is available to objects of that class. Of course, you cannot create an instance of an attribute. It can exist only as part of its corresponding object.

Syntaxes

The type of value that an attribute can contain is defined by a syntax. Active Directory defines 26 syntaxes (although fewer are actually available). Examples of syntaxes are Integer for storing whole number values, and Unicode String for storing Unicode strings. A syntax serves two functions within Active Directory. First, it provides for validation to ensure data written to an attribute is the correct type, and second, a syntax provides matching rules that define how Active Directory compares values when searching. For example, the CaseIgnoreString syntax can be matched to a string containing uppercase and lowercase characters; however, the CaseExactString syntax requires that comparisons take the case of the characters into account.

Although syntaxes are part of the Active Directory schema, unlike classes and attributes, you cannot create new syntaxes or modify existing ones. Later in the chapter, I'll show how to use the IADsSyntax interface to discover information about a syntax and describe syntaxes in more detail.

While Active Directory supports many syntaxes, internally it ignores some of them. One such example is the PrintableString syntax, which should only contain printable characters and not include control code characters such as Tab (0x09). Care should be taken to design applications to set the desired syntax and validate the correctness of the data.

Object Identifiers

Each class, attribute, and syntax defined by Active Directory contains a unique number that is used to identify it and prevent naming conflicts. These unique numbers are known as object identifiers (OIDs). Their purpose is similar to globally unique identifiers (GUIDs), but whereas GUIDs are mathematically generated, the International Telecommunications Union (ITU) manages OIDs. Some examples of OIDs found in Active Directory are listed in Table 9-1.

OID Defined For

1.2.840.113556.1.2.256

streetAddress attribute

1.2.840.113556.1.5.9

user class

2.5.5.9

Integer syntax

Table 9-1 Example object identifiers.

OIDs are segmented using branches, with each period separating a branch. In the preceding table, notice how both the streetAddress attribute and user class have 1.2.840.113556.1 in common. This is the Active Directory branch of the Microsoft tree. Table 9-2 shows what the numbers signify for the user class.

OID Branch Branch Description

1

International Standards Organization (ISO)

2

ISO members

840

American National Standards Institute (ANSI) branch for organizations in the United States

113556

Microsoft

1

Active Directory

5

Classes

9

user class

Table 9-2 OID branches for the user class.

So why is the Integer syntax OID (2.5.5.9) so different? Because it's part of the X.500 standards published by the ITU and maintained by the ISO. The top-level branch, 2, is maintained jointly by the ITU and ISO; the first 5 is the branch reserved for X.500 directory services, and the second 5 is for X.500 syntaxes. The 9 is reserved for the Integer syntax.

Unless you are extending the schema, you generally don't have to deal with OIDs. If you're curious, you can find more information in the LDAP RFCs; see Chapter 3 for a list.

Microsoft makes available a branch of OIDs for extensions. I'll describe these and other details about OIDs in the section "Obtaining an Object Identifier" later in the chapter.

Schema Structure

The schema itself is located within Active Directory in a container, known as the Schema container, that stores objects that define classes and attributes. Since the data definitions are contained within the directory, you can use the same methods to manipulate and extend the schema as you would with any other part of the directory.

The Schema container stores instances of the classSchema and attribute-Schema classes. Instances of the classSchema class exist for each class supported by Active Directory. Similarly, instances of the attributeSchema class exist for each supported attribute. This can be confusing from a terminology standpoint. An attribute object is an object in the Schema container that defines a particular attribute. In addition to the attributeSchema and classSchema objects, the Schema container also contains a single instance of a subSchema object that I'll discuss later in this chapter in the section "Abstract Schema."

Recall from the overview of Active Directory architecture in Chapter 2 that Active Directory is partitioned to reduce replication issues. These partitions consist of the domain partition, configuration partition, and schema partition. Each domain has a domain partition, but all the domains in an enterprise forest share a common configuration and schema partition. Each domain controller in the forest has a replica of the configuration and schema partitions. The schema has its own partition so that it can be referenced and replicated on a different schedule than the configuration partition.

Schema objects are stored in the Schema container. Its distinguished name (DN) has the following form:

CN=Schema,CN=Configuration,DC=forest name,DC=forest root

The values for forest name and forest root are the domain components for the enterprise Active Directory forest. For example, in the Copper Software business empire, the distinguished name of the Schema container would be:

CN=Schema,CN=Configuration,DC=coppersoftware,DC=com

Looking at the distinguished name for the Schema container, you can see that the Schema container is within the Configuration container. However, if you enumerate the configuration partition, you will not find a Schema container because the Schema container is a part of the schema partition.

Figure 9-1 shows the relationship between the Configuration and Schema containers and the configuration and schema partitions.

Figure 9-1 Relationship between containers and partitions.

The exact location of the Schema container can be obtained by looking at the schemaNamingContext property of the RootDSE object. The schemaNamingContext property contains the distinguished name for the Schema container. Listing 9-1, from the SchemaBrowser sample on the companion CD, shows how to obtain the location of the Schema container:

 Public Function BindToSchemaPartition() As IADs
    ` Retrieve the RootDSE object from the nearest server
    Dim adsRootDSE As IADs
    Set adsRootDSE = GetObject("LDAP://RootDSE")
    ` Form an ADsPath string to the schema container
    Dim strSchemaADsPath As String
    strSchemaADsPath = _ 
        "LDAP://" & adsRootDSE.Get("schemaNamingContext")
    
    ` Get the root domain object
    Set BindToSchemaPartition = GetObject(strSchemaADsPath)
    
End Function

Listing 9-1 A function from the SchemaBrowser sample showing how to obtain the location of the Schema container.

Listing 9-2, from the ExtendSchema sample on the companion CD, shows the C++ version of obtaining the Schema container location.

 //----------------------------------------------------------------
// Function:     RetrieveSchemaPartition
// Description:  Retrieve the schema partition on any DC
//
// In:           IADs**   Empty IADs interface pointer
// Out:          IADs**   Bound to schema partition
// Returns:      HRESULT  COM/ADSI Error code
//
// Notes:        Caller must Release() interface when finished
//----------------------------------------------------------------
HRESULT RetrieveSchemaPartition( IADs **padsSchema )
{
    HRESULT hResult;
    // Bind to the RootDSE
    IADs *padsRootDSE = NULL;
    hResult = ADsGetObject( L"LDAP://rootDSE",
                            IID_IADs,
                            (void**) &padsRootDSE );     if( SUCCEEDED( hResult ) )
        {
        // Get the schema partition DN (AKA naming context)
        _variant_t varSchemaNC;
        hResult = padsRootDSE->Get( L"schemaNamingContext",
            &varSchemaNC );
        if( SUCCEEDED( hResult ) )
        {
            // Create ADsPath to the schema partition
            _bstr_t strSchemaPath = _bstr_t( "LDAP://" ) +
                _bstr_t(varSchemaNC);
            // Bind to the schema container, return IADs interface
            hResult = ADsGetObject( strSchemaPath,
                                    IID_IADs,
                                    (void**) padsSchema );
            }
        }
    // Free the RootDSE object
    if ( padsRootDSE )
        padsRootDSE->Release ();
    // Return the result code
    return hResult;
}

Listing 9-2 A function from the ExtendSchema sample showing how to obtain the location of the Schema container.

Abstract Schema

The LDAP recommendations do not specify exactly how a directory must implement its schema; they require only that information about the schema be available to applications in a prescribed format. Active Directory has an alternative representation of the schema in a subSchema object. This object is named the Aggregate object and is known as the abstract schema. The Aggregate object is contained in the Schema container, and in this single object, all the classes and attributes are made available. The reason for this alternative representation is to allow any client application to discover schema information independently of the implementation details. A client application uses the subSchemaSubEntry attribute of the RootDSE object to discover the distinguished name of the subSchema object.

The attributes of the subSchema class are listed in Table 9-3. Note that each and every class and attribute defined in the schema is contained in two multivalued attributes of the Aggregate object. Storing nearly 900 attribute values in a single attribute is remarkable.

subSchema Attribute Description

attributeTypes

Each value contains information about an attribute defined in the schema, including the OID, name, and syntax of the attribute.

objectClasses

Each value contains information about a class defined in the schema, including the OID, name, and mandatory and optional attributes of the class.

extendedAttributeInfo

Each value contains extended information about an attribute defined in the schema, including the OID, name, GUID, and security information.

extendedClassInfo

Each value contains extended information about a class defined in the schema, including the OID, name, and GUID.

dITContentRules

This attribute is not required by RFC 2252, and its implementation by Active Directory is incomplete and undocumented.

modifyTimeStamp

A single-valued attribute that indicates the last time the schema was modified.

Table 9-3 Attributes of the subSchema class.

There is no need to work directly with the Aggregate object because ADSI exposes it as the abstract schema container. This special container is how ADSI allows easy access to the subSchema information. You can bind to the abstract schema using the following special ADsPath:

 LDAP://schema 

ADSI returns an IADsContainer interface. Each item in the virtual schema container is an attribute, class, or syntax defined by the schema. Accordingly, ADSI provides the IADsProperty, IADsClass, and IADsSyntax interfaces to allow access to the information provided.

Listing 9-3, from the SchemaBrowser sample on the companion CD, shows how to enumerate the objects of the abstract schema. For brevity, functions such as event handling that are unrelated to the schema have been omitted. See the sample on the companion CD for a complete listing.

 ` ADsClassList.frm - Main form for Schema Browser
` Shows binding to abstract schema
`
Option Explicit
Public Sub ListClasses(lstListBox As ListBox)
    `
    ` Enumerate all the classes in the schema container
    `
    Dim adsAbstractSchema As IADsContainer
    Set adsAbstractSchema = GetObject("LDAP://schema")
    
    ` Enumerate the classes of the schema
    adsAbstractSchema.Filter = Array("Class")
    
    Dim adsClass As IADsClass
    For Each adsClass In adsAbstractSchema
    
        ` Add the class name to the list box
        lstListBox.AddItem adsClass.Name
    Next adsClass
End Sub
Public Function BindToSchemaPartition() As IADs
    ` Retrieve the RootDSE object from the nearest server
    Dim adsRootDSE As IADs
    Set adsRootDSE = GetObject("LDAP://RootDSE")
    ` Form an ADsPath string to the schema container
    Dim strSchemaADsPath As String
    strSchemaADsPath = _
        "LDAP://" & adsRootDSE.Get("schemaNamingContext")     ` Get the root domain object
    Set BindToSchemaPartition = GetObject(strSchemaADsPath)
    
End Function
Private Sub Form_Load()
    ` Clear the list box and text box
    txtSchemaPath.Text = vbNull
    lstClasses.Clear
    ` Get the schema location, and display it
    Dim adsSchema As IADs
    Set adsSchema = BindToSchemaPartition()
    txtSchemaPath.Text = adsSchema.ADsPath
    ` Display each class in the list box
    Call ListClasses(lstClasses)
End Sub

Listing 9-3 Code from the SchemaBrowser sample showing how to enumerate objects of the abstract schema.

The main window of the SchemaBrowser sample is shown in Figure 9-2. I'll expand on this sample and discuss the IADsClass and IADsProperty interfaces later in the chapter.

Figure 9-2 The main window of the SchemaBrowser sample showing the path to the Schema container and the classes contained within it.

Tools for Exploring the Schema

A good way to browse and learn about the schema is to use the Active Directory Schema snap-in for the Microsoft Management Console (MMC). This snap-in, introduced in Chapter 2, provides a tree-based view of the schema and allows you to view all available classes and attributes. Figure 9-3 shows an example of the Active Directory Schema snap-in.

Figure 9-3 Active Directory Schema snap-in showing the attributes available in the computer class.

Since the schema is a technical and sensitive portion of Active Directory, the Schema snap-in is not among the list of Administrative Tools displayed in Control Panel. To start the Active Directory Schema snap-in, type schmmgmt.msc in the Run dialog box.

Although the actual schema is a single container, the Active Directory Schema snap-in displays two folders, one for classes and another for attributes. When a class is selected, the right pane displays a list of attributes available for that class. Double-click or press ALT+Enter to access the Properties dialog box for a selected class in the Classes folder or a selected attribute in the Attributes folder. Figure 9-4 shows the Properties dialog box for the computer class.

Figure 9-4 The Properties dialog box in the Active Directory Schema snap-in for the computer class.


The Base Directory Information Tree

The actual database that holds directory data is known as the directory information tree (DIT). The definition for the default entries that ship with Active Directory is sometimes referred to as the base DIT. The base DIT is an empty directory that contains only the schema objects and other entries, such as the default containers and display specifiers.

This initial content of Active Directory is specified in text form in the file %SystemRoot%\system32\schema.ini. This file is processed by Microsoft Windows 2000 when a server is promoted to a domain controller and a new directory is created. The entries in the Schema.ini file become the base DIT for the new Active Directory. Interestingly enough, the schema objects are not part of this file, but all other default entries in a new Active Directory are. A portion of the Schema.ini file is shown here.

 ;!---------------------------------------
;! The tree under the root of the domain.
;!---------------------------------------
[DEFAULTROOTDOMAIN]
objectClass = DomainDNS
objectCategory = Domain-DNS NTSecurityDescriptor=O:DAG:DAD:(A;;RP;;;WD)
(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ED)
(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;ED)
(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;ED)
(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;BA)
(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;BA)
(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;BA)
(A;;RPLCLORC;;;AU)(A;;RPWPCRLCLOCCRCWDWOSW;;;DA)
(A;CI;RPWPCRLCLOCCRCWDWOSDSW;;;BA)(A;;RPWPCRLCLOCCDCRCWDWOSDDTSW;;;SY)
(A;CI;RPWPCRLCLOCCDCRCWDWOSDDTSW;;;EA)(A;CI;LC;;;RU)
(OA;CIIO;RP;037088f8-0ae1-11d2-b422-00a0c968f939;bf967aba-0de6-11d0-a285-00aa003049e2;RU)
(OA;CIIO;RP;59ba2f42-79a2-11d0-9020-00c04fc2d3cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)
(OA;CIIO;RP;bc0ac240-79a9-11d0-9020-00c04fc2d4cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)
(OA;CIIO;RP;4c164200-20c0-11d0-a768-00aa006e0529;bf967aba-0de6-11d0-a285-00aa003049e2;RU)
(OA;CIIO;RP;5f202010-79a5-11d0-9020-00c04fc2d4cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)
(OA;CIIO;RPLCLORC;;bf967a9c-0de6-11d0-a285-00aa003049e2;RU)
(A;;RC;;;RU)
(OA;CIIO;RPLCLORC;;bf967aba-0de6-11d0-a285-00aa003049e2;RU)S:
(AU;CISAFA;WDWOSDDTWPCRCCDCSW;;;WD)
auditingPolicy=\x0001
nTMixedDomain=1
;Its a NC ROOT
instanceType=5
;Its the PDC, set FSMO role owner
fSMORoleOwner=$REGISTRY=Machine DN Name
wellKnownObjects=$EMBEDDED:32:a9d1ca15768811d1aded00c04fd8d5cd:
cn=Users,<Root Domain
wellKnownObjects=$EMBEDDED:32:aa312825768811d1aded00c04fd8d5cd:
cn=Computers,<Root Domain
wellKnownObjects=$EMBEDDED:32:a361b2ffffd211d1aa4b00c04fd7d83a:
ou=Domain Controllers,<Root Domain
wellKnownObjects=$EMBEDDED:32:ab1d30f3768811d1aded00c04fd8d5cd:
cn=System,<Root Domain
wellKnownObjects=$EMBEDDED:32:ab8153b7768811d1aded00c04fd8d5cd:
cn=LostAndFound,<Root Domain
wellKnownObjects=$EMBEDDED:32:2fbac1870ade11d297c400c04fd8d5cd:
cn=Infrastructure,<Root Domain
wellKnownObjects=$EMBEDDED:32:18e2ea80684f11d2b9aa00c04f79f805:
cn=Deleted Objects,<Root Domain
gPLink=$REGISTRY=GPODomainLink
mS-DS-MachineAccountQuota=10
isCriticalSystemObject=True;systemFlags=FLAG_CONFIG_DISALLOW_RENAME        |
;             FLAG_CONFIG_DISALLOW_MOVE         |
;             FLAG_DISALLOW_DELETE
systemFlags=0x8C000000

;        every domain needs these in the root
CHILD= LostAndFound
CHILD= Deleted Objects
CHILD= Users
CHILD= Computers
CHILD= System
CHILD= Domain Controllers
CHILD= Infrastructure
CHILD= ForeignSecurityPrincipals
...
[Users]
nTSecurityDescriptor=O:DAG:DAD:(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)
(A;;RPWPCRCCDCLCLORCWOWDSW;;;DA)
(OA;;CCDC;bf967aba-0de6-11d0-a285-00aa003049e2;;AO)
(OA;;CCDC;bf967a9c-0de6-11d0-a285-00aa003049e2;;AO)
(OA;;CCDC;bf967aa8-0de6-11d0-a285-00aa003049e2;;PO)(A;;RPLCLORC;;;AU)
objectClass =Container
ObjectCategory =Container
description=Default container for upgraded user accounts
ShowInAdvancedViewOnly=False
isCriticalSystemObject=True
;systemFlags=FLAG_CONFIG_DISALLOW_RENAME        |
;             FLAG_CONFIG_DISALLOW_MOVE         |
;             FLAG_DISALLOW_DELETE
systemFlags=0x8C000000

[Computers]
nTSecurityDescriptor=O:DAG:DAD:(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)
(A;;RPWPCRCCDCLCLORCWOWDSW;;;DA)
(OA;;CCDC;bf967a86-0de6-11d0-a285-00aa003049e2;;AO)
(OA;;CCDC;bf967aba-0de6-11d0-a285-00aa003049e2;;AO)
(OA;;CCDC;bf967a9c-0de6-11d0-a285-00aa003049e2;;AO)
(OA;;CCDC;bf967aa8-0de6-11d0-a285-00aa003049e2;;PO)(A;;RPLCLORC;;;AU)
objectClass =Container
ObjectCategory =Container
description=Default container for upgraded computer accounts  
ShowInAdvancedViewOnly=False
isCriticalSystemObject=True
;systemFlags=FLAG_CONFIG_DISALLOW_RENAME        |
;             FLAG_CONFIG_DISALLOW_MOVE         |
;             FLAG_DISALLOW_DELETE
systemFlags=0x8C000000



MicrosoftR WindowsR 2000 Active DirectoryT Programming
MicrosoftR WindowsR 2000 Active DirectoryT Programming
ISBN: N/A
EAN: N/A
Year: 2001
Pages: 108

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net