<!--

Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.

The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.

See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.

-->
<chapter id="csdk-server-info"><title>Getting Server Information With &DirectorySDKForC;
</title>
<indexterm>
<primary>C SDK</primary>
<secondary>getting server information</secondary>
</indexterm><highlights>
<para>This chapter explains how to access and modify information about your
LDAP server over the LDAP protocol.</para>
<itemizedlist>
<para>This chapter covers the following topics:</para>
<listitem><para><olink targetptr="bdahu">Reading DSEs With Directory SDK for
C</olink></para></listitem>
<listitem><para><olink targetptr="bdahw">Determining LDAP v3 Support With
Directory SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="bdahx">Getting Schema Information With Directory
SDK for C</olink></para></listitem>
</itemizedlist>
</highlights>
<sect1 id="bdahu"><title>Reading DSEs With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>getting server information</secondary>
<tertiary>DSE</tertiary>
</indexterm>
<para>A DSA-specific entry, <firstterm>DSE</firstterm>, contains information
specific to the server. In a directory tree, the root of the tree is the root
DSE. The root DSE is not part of any naming context. For example, the root
DSE is superior to <literal>dc=example,dc=com</literal> in the directory tree.</para>
<para>The root DSE is specified as part of LDAP v3. Note that LDAP v2 servers
do not necessarily have a root DSE.</para>
<itemizedlist>
<para>The root DSE can contain the following information:</para>
<listitem><para>The naming contexts of this server such as, <literal>dc=example,dc=com
</literal></para></listitem>
<listitem><para>URLs of alternate servers to contact if this server is unavailable
</para></listitem>
<listitem><para>The versions of LDAP supported by this server, version 2 or
version 3</para></listitem>
<listitem><para>The LDAP v3 controls supported by the server</para><para>See <olink targetptr="csdk-controls">Chapter&nbsp;16, LDAP Controls With Directory SDK
for C</olink> for details.</para></listitem>
<listitem><para>The SASL mechanisms supported by the server</para><para>See <olink targetptr="csdk-sasl">Chapter&nbsp;17, SASL Authentication With Directory
SDK for C</olink> for details.</para></listitem>
<listitem><para>The LDAP v3 extended operations supported by the server</para>
<para>See <olink targetptr="csdk-extop">Chapter&nbsp;18, Extended Operations
With Directory SDK for C</olink> for details.</para></listitem>
</itemizedlist>
<para>The following lists root DSE attributes and explains the meaning of
their values.</para>
<table frame="topbot" pgwide="1" id="server-root-dse-info"><title>Root DSE
Attributes and Descriptions of Their Values</title>
<tgroup cols="2"><colspec colnum="1" colwidth="21.64*"><colspec colnum="2"
colwidth="78.36*">
<thead>
<row>
<entry>
<para>Attribute Name</para></entry>
<entry>
<para>Description of Values</para></entry>
</row>
</thead>
<tbody>
<row>
<entry>
<para><literal>namingContexts</literal></para></entry>
<entry>
<para>The naming contexts supported by this server, such <literal>dc=example,dc=com
</literal>.</para></entry>
</row>
<row>
<entry>
<para><literal>altServer</literal></para></entry>
<entry>
<para>LDAP URLs that identify other servers to contact if this server is unavailable.
</para></entry>
</row>
<row>
<entry>
<para><literal>supportedExtension</literal></para></entry>
<entry>
<para>The object identifiers (OIDs) of the LDAP v3 extended operations supported
by this server.</para>
<para>If this attribute is not in the root DSE, the server does not support
any extended operations.</para></entry>
</row>
<row>
<entry>
<para><literal>supportedControl</literal></para></entry>
<entry>
<para>The OIDs of the LDAP v3 controls supported by this server.</para>
<para>If this attribute is not in the root DSE, the server does not support
any LDAP v3 controls.</para></entry>
</row>
<row>
<entry>
<para><literal>supportedSASLMechanisms</literal></para></entry>
<entry>
<para>The names of the SASL mechanisms supported by the server.</para>
<para>If this attribute is not in the root DSE, the server does not support
any SASL mechanisms.</para></entry>
</row>
<row>
<entry>
<para><literal>supportedLDAPVersion</literal></para></entry>
<entry>
<para>The value of this attribute is the version of LDAP supported by this
server, such as <literal>2</literal> or <literal>3</literal>.</para></entry>
</row>
</tbody>
</tgroup>
</table>
<task id="bdahv"><title>To Get the Root DSE</title>
<procedure>
<step><para>Initialize an LDAP session by calling the <function>ldap_init</function> or <function>
prldap_init</function> function.</para></step>
<step><para>Turn off automatic referral handling by calling the <function>ldap_set_option
</function> function and setting the <literal>LDAP_OPT_REFERRALS</literal> option
to <literal>LDAP_OPT_OFF</literal>.</para></step>
<step><para>Search the directory with the following criteria:</para>
<substeps>
<step><para>Set the search scope to a <literal>base</literal> search.</para>
</step>
<step><para>Specify an empty string for the base DN.</para></step>
<step><para>Use the search filter <literal>(objectclass=*)</literal>.</para>
</step></substeps>
</step>
<step><para>Check the results of the search.</para><para>If the server returns
a result code, such as <errorcode>LDAP_OPERATIONS_ERROR</errorcode>, <errorcode>LDAP_PROTOCOL_ERROR
</errorcode>, <errorcode>LDAP_REFERRAL</errorcode>, or <errorcode>LDAP_NO_SUCH_OBJECT
</errorcode>, the LDAP server probably does not support LDAP v3.</para><para>The
following example gets the root DSE for a server and prints the values of
the root DSE attributes. The function assumes that you are passing in a valid
connection handle, an <structname>LDAP</structname> structure, you have created
by calling <function>ldap_init</function> or <function>prldap_init</function>.
The function returns <literal>0</literal> if successful or <literal>1</literal> if
an error occurred.</para></step>
</procedure>
<example id="server-dse-attr-example">
<title>Getting the Root DSE and Printing its Attribute Values</title>
<programlisting>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, &amp;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, &amp;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 );
}</programlisting>
</example>
</task>
</sect1>
<sect1 id="bdahw"><title>Determining LDAP v3 Support With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>getting server information</secondary>
<tertiary>LDAP v3 support</tertiary>
</indexterm>
<para>You can determine what version an LDAP server supports by getting the <literal>
supportedLDAPVersion</literal> attribute from the root DSE. This attribute
could contain the value <literal>2</literal> or <literal>3</literal>.</para>
<para>You do not need to authenticate or bind before searching the directory.
Unlike LDAP v2, LDAP v3 states that clients do not need to bind to the server
before performing LDAP operations.</para>
<para>The following example connects to an LDAP server. The example code then
determines whether the server supports LDAP v3.</para>
<example id="server-ldapv3-support-example"><title>Determining the Supported
LDAP Version</title>
<programlisting>/* 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. Use prldap_init() for IPv6. */
  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, &amp;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  &amp;&amp;
      ( a = ldap_first_attribute( ld, e, &amp;ber )) != NULL  &amp;&amp;
      (vals = ldap_get_values( ld, e, a)) != NULL ) {
    for ( i = 0; vals[i] != NULL; i++ ) {
      if ( !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 );
}
...</programlisting>
</example>
</sect1>
<sect1 id="bdahx"><title>Getting Schema Information With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>getting server information</secondary>
<tertiary>schema</tertiary>
</indexterm>
<para>In LDAP v3, an entry can specify the schema that defines the object
classes, attributes, and matching rules used by the directory. This entry
is called the <literal>subschema</literal> entry. To find the DN of the <literal>
subschema</literal> entry, get the <literal>subschemaSubentry</literal> operational
attribute from the root DSE or any entry.</para>
<itemizedlist>
<para>The <literal>subschema</literal> entry can have the following attributes:</para>
<listitem><para><literal>objectClasses</literal> specifies the object class
definitions in the schema. Each value of this attribute is an object class
that is known to the server.</para></listitem>
<listitem><para><literal>attributeTypes</literal> specifies the attribute
type definitions in the schema. Each value of this attribute is an attribute
type that is known to the server.</para></listitem>
<listitem><para><literal>matchingRules</literal> specifies the matching rule
definitions in the schema. Each value of this attribute is a matching rule
that is known to the server.</para></listitem>
<listitem><para><literal>matchingRuleUse</literal> specifies the use of a
matching rule in the schema. This rule specifies the attributes that can be
used with this extensible matching rule. Each value of this attribute is a
matching rule use description.</para></listitem>
</itemizedlist>
<para>For information about the format of the attribute values, see <ulink
url="http://www.ietf.org/rfc/rfc4517.txt" type="text_url"><?Pub Caret>RFC
4517</ulink>, <citetitle>Lightweight Directory Access Protocol (v3): Attribute
Syntax Definitions</citetitle>.</para></sect1>
</chapter>
