Mozilla LDAP C SDK Programmer's Guide
Chapter 11 - Getting Server Information
This chapter explains how to access and modify information about your LDAP server over the LDAP protocol.
The chapter includes the following sections:
- Understanding DSEs
- Getting the Root DSE
- Determining if the Server Supports LDAPv3
- Getting Schema Information
Understanding DSEs
A DSE is a DSA-specific entry in the directory. (A DSA is a directory system agent, which is an X.500 term for a directory server.) A DSE contains information specific to the server.
In a directory tree, the root of the tree is the
root DSE. It is not part of any
naming context. For example, it is above
"dc=example,dc=com
" in the directory tree.
(Note that the root DSE is specified as part of the LDAPv3 protocol. LDAPv2 servers do not necessarily have a root DSE.)
The root DSE can contain the following information:
-
The naming contexts of this server (for
example, "
dc=example,dc=com
"). - URLs of alternate servers to contact if this server is unavailable.
- The LDAPv3 extended operations supported by this server (see Chapter 15 - Working with Extended Operations" for details).
- The LDAPv3 controls supported by this server (see Chapter 14 - Working with LDAP Controls" for details).
- The SASL mechanisms supported by this server (see Chapter 13 - Using SASL Authentication" for details).
- The versions of the LDAP protocol supported by this server (for example, 2 and 3).
- Additional server-specific information.
Getting the Root DSE
The root DSE for an LDAP server specifies information about the server. The following table lists the types of information available in different attributes of the root DSE.
Table 11-1 - Information available in the root DSE
Attribute Name | Description of Values |
---|---|
namingContexts |
The values of this attribute are the naming
contexts supported by this server (for example,
"dc=example,dc=com ").
|
altServer |
The values of this attribute are LDAP URLs that identify other servers that can be contacted if this server is unavailable. |
supportedExtension |
The values of this attribute are the object identifiers (OIDs) of the LDAPv3 extended operations supported by this server. If this attribute is not in the root DSE, the server does not support any extended operations. |
supportedControl |
The values of this attribute are the object identifiers (OIDs) of the LDAPv3 controls supported by this server. If this attribute is not in the root DSE, the server does not support any LDAPv3 controls. |
supportedSASLMechanisms |
The values of this attribute are the names of the SASL mechanisms supported by the server. If this attribute is not in the root DSE, the server does not support any SASL mechanisms. |
supportedLDAPVersion |
The values of this attribute are the versions of the LDAP protocol supported by this server (for example, 2 and 3). |
To get the root DSE for an LDAP server, do the following:
-
Initialize an LDAP session by calling the
ldap_init()
function. -
Turn off automatic referral handling by calling the
ldap_set_option()
function and setting theLDAP_OPT_REFERRALS
option toLDAP_OPT_OFF
. -
Search the directory using the following criteria:
- Set the search scope to a base search.
- Specify an empty string for the base DN.
- Use the search filter
(objectclass=*)
.
-
Check the results of the search.
If the server returns a result code such as
LDAP_OPERATIONS_ERROR
,LDAP_PROTOCOL_ERROR
,LDAP_REFERRAL
, orLDAP_NO_SUCH_OBJECT
result code, the LDAP server probably does not support LDAPv3.
The following function gets the root DSE for a server and prints
out its attributes. The function assumes that you are passing in a
valid connection handle (LDAP
structure) that you have created by calling
ldap_init()
. The function
returns 0 if successful or 1
if an error occurred.
Code Example 11-1 - Getting the root DSE attribute values
int printdse( LDAP *ld ) { int rc, i; char *matched_msg = NULL, *error_msg = NULL; LDAPMessage *result, *e; BerElement *ber; char *a; char **vals; char *attrs[3]; /* Verify that the connection handle is valid. */ if ( ld == NULL ) { fprintf( stderr, "Invalid connection handle.\n" ); return( 1 ); } /* Set automatic referral processing off. */ if ( ldap_set_option( ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF ) != 0 ) { rc = ldap_get_lderrno( ld, NULL, NULL ); fprintf( stderr, "ldap_set_option: %s\n", ldap_err2string( rc ) ); return( 1 ); } /* Search for the root DSE. */ attrs[0] = "supportedControl"; attrs[1] = "supportedExtension"; attrs[2] = NULL; rc = ldap_search_ext_s( ld, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, 0, NULL, NULL, NULL, 0, &result ); /* Check the search results. */ switch( rc ) { /* If successful, the root DSE was found. */ case LDAP_SUCCESS: break; /* If the root DSE was not found, the server does not comply with the LDAPv3 protocol. */ case LDAP_PARTIAL_RESULTS: case LDAP_NO_SUCH_OBJECT: case LDAP_OPERATIONS_ERROR: case LDAP_PROTOCOL_ERROR: printf( "LDAP server returned result code %d (%s).\n" "This server does not support the LDAPv3 protocol.\n", rc, ldap_err2string( rc ) ); return( 1 ); /* If any other value is returned, an error must have occurred. */ default: fprintf( stderr, "ldap_search_ext_s: %s\n", ldap_err2string( rc ) ); return( 1 ); } /* Since only one entry should have matched, get that entry. */ e = ldap_first_entry( ld, result ); if ( e == NULL ) { fprintf( stderr, "ldap_search_ext_s: Unable to get root DSE.\n"); ldap_memfree( result ); return( 1 ); } /* Iterate through each attribute in the entry. */ for ( a = ldap_first_attribute( ld, e, &ber ); a != NULL; a = ldap_next_attribute( ld, e, ber ) ) { /* Print each value of the attribute. */ if ((vals = ldap_get_values( ld, e, a)) != NULL ) { for ( i = 0; vals[i] != NULL; i++ ) { printf( "%s: %s\n", a, vals[i] ); } /* Free memory allocated by ldap_get_values(). */ ldap_value_free( vals ); } /* Free memory allocated by ldap_first_attribute(). */ ldap_memfree( a ); } /* Free memory allocated by ldap_first_attribute(). */ if ( ber != NULL ) { ber_free( ber, 0 ); } printf( "\n" ); /* Free memory allocated by ldap_search_ext_s(). */ ldap_msgfree( result ); ldap_unbind( ld ); return( 0 ); }
Determining If the Server Supports LDAPv3
You can determine what version an LDAP server
supports by getting the supportedLDAPVersion
attribute
from the root DSE. This attribute
should contain the value 3. (It may also contain other values, such
as 2, so you may want to check through the values of this attribute.)
Note that you do not need to authenticate or bind (see "Binding and Authenticating to an LDAP Server" for details) before searching the directory. Unlike the LDAPv2protocol, the LDAPv3 protocol states that clients do not need to bind to the server before performing LDAP operations.
The following function connects to an LDAP server and determines whether or not that server supports the LDAPv3 protocol.
Code Example 11-2 - Determining the supported LDAP version
/* Function for determining if the LDAP server supports LDAPv3. This function returns 1 if the server supports LDAPv3 or 0 if the server does not support LDAPv3. */ int check_version( char *hostname, int portnum ) { LDAP *ld; int i, rc, v3supported = 0; LDAPMessage *result, *e; BerElement *ber; LDAPControl **serverctrls = NULL, **clntctrls = NULL; char *a, *dn; char **vals; char *attrs[2]; char *filter = "(objectClass=*)"; /* Check arguments */ if ( !hostname || !hostname[0] || !portnum ) { printf( "Error: hostname or port number not specified\n" ); return( -1 ); } /* Get a handle to an LDAP connection. */ if ( (ld = ldap_init( hostname, portnum )) == NULL ) { perror( "ldap_init" ); return( -1 ); } /* Set automatic referral processing off. */ if (ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF) != LDAP_SUCCESS) { ldap_perror( ld, "ldap_set_option" ); return( -1 ); } /* Search for the root DSE and get the supportedLDAPVersion attribute. */ attrs[0] = "supportedLDAPVersion"; attrs[1] = NULL; rc = ldap_search_ext_s( ld, "", LDAP_SCOPE_BASE, filter, attrs, 0, serverctrls, clntctrls, NULL, 0, &result ); /* Check the search results. */ switch( rc ) { /* If successful, the root DSE was found. */ case LDAP_SUCCESS: break; /* If the root DSE was not found, the server does not comply with the LDAPv3 protocol. */ case LDAP_PARTIAL_RESULTS: case LDAP_NO_SUCH_OBJECT: case LDAP_OPERATIONS_ERROR: case LDAP_PROTOCOL_ERROR: ldap_perror( ld, "ldap_search_ext_s" ); return( 0 ); break; /* If an different result code is returned, an error may have occurred (for example, the server may be down. */ default: ldap_perror( ld, "ldap_search_ext_s" ); return( -1 ); break; } /* Get the values of the supportedLDAPVersion attribute in the entry. */ if (( e = ldap_first_entry( ld, result )) != NULL && ( a = ldap_first_attribute( ld, e, &ber )) != NULL && (vals = ldap_get_values( ld, e, a)) != NULL ) { for ( i = 0; vals[i] != NULL; i++ ) { if ( 0 == strcmp( "3", vals[i] ) ) { v3supported = 1; break; } } /* Free any memory allocated. */ ldap_value_free( vals ); ldap_memfree( a ); if ( ber != NULL ) { ber_free( ber, 0 ); } } /* Free memory allocated by ldap_search_ext_s(). */ ldap_msgfree( result ); /* Free the ld structure. */ ldap_unbind_s( ld ); /* Return a value indicating whether or not LDAPv3 is supported. */ return( v3supported ); } ...
Getting Schema Information
In the LDAPv3 protocol, an entry can specify the schema that defines the object classes, attributes, and matching rules used by the directory. This entry is called the subschema entry.
To find the DN of the subschema entry, get the
subschemaSubentry
operational attribute from the root
DSE or from any entry. (See "Specifying
the Attributes to Retrieve" for details.)
The subschema entry itself can have the following attributes:
-
objectClasses
specifies the object class definitions in the schema. Each value of this attribute is an object class that is known to the server. -
attributeTypes
specifies the attribute type definitions in the schema. Each value of this attribute is an attribute type that is known to the server. -
matchingRules
specifies the matching rule definitions in the schema. Each value of this attribute is a matching rule that is known to the server. -
matchingRuleUse
specifies the use of a matching rule in the schema (this specifies the attributes that can be used with this extensible matching rule). Each value of this attribute is a matching rule use description.
For the format of the attribute values, reference LDAPv3: Attribute Syntax Definitions, RFC 2252. For more information, see Where to Find Additional Information.