OpenVMS Source Code Demos

ldap_example.c

/* -*- C -*-
 *
 * Copyright 2000 Compaq Computer Corporation
 *
 * COMPAQ Registered in U.S. Patent and Trademark Office.
 *
 * Consistent with FAR 12.211 and 12.212, Commercial Computer Software,
 * Computer Software Documentation, and Technical Data for Commercial Items
 * are licensed to the U.S. Government under vendor's standard commercial
 * license.
 *
 * This software is subject to change without notice and is provided "AS IS"
 * WITHOUT WARRANTY OF ANY KIND. THE ENTIRE RISK ARISING OUT OF THE USE OF
 * THIS SOFTWARE REMAINS WITH RECIPIENT. IN NO EVENT SHALL COMPAQ BE LIABLE
 * FOR ANY DIRECT, CONSEQUENTIAL, INCIDENTAL, SPECIAL, PUNITIVE OR OTHER
 * DAMAGES WHATSOEVER (INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF
 * BUSINESS PROFITS, BUSINESS INTERRUPTION OR LOSS OF BUSINESS INFORMATION),
 * EVEN IF COMPAQ HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.  THE
 * FOREGOING SHALL APPLY REGARDLESS OF THE NEGLIGENCE OR OTHER FAULT OF
 * EITHER PARTY AND REGARDLESS OF WHETHER SUCH LIABILITY SOUNDS IN CONTRACT,
 * NEGLIGENCE, TORT, OR ANY OTHER THEORY OF LEGAL LIABILITY, AND
 * NOTWITHSTANDING ANY FAILURE OF ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
 *
 * The limited warranties for Compaq products are exclusively set forth in
 * the documentation accompanying such products. Nothing herein should be
 * construed as constituting a further or additional warranty.
 *
 *
 */

/*
 * Compaq revision history
 *
 * Rev    Author         Date         Comments
 * ---    ------         ----         --------
 * 001    Nick Hudson    08-Sep-2000  Initial version
 */

/*
 * This program demonstrates the use of the OpenVMS LDAP API from a client
 * application.
 *
 * The program may be compiled using either C or C++.
 *
 * The program may be compiled with either 32 or 64 bit pointers (providing
 * that the compiler supports it).
 *
 * To build this program use:
 * $ cc ldap_example
 * $ link ldap_example
 *
 * The program expects to run as a foreign command.  To define the foreign
 * command use the following syntax:
 *
 * $ ldap_example := $disk1:[mydir]ldap_example.exe ! define foreign command
 *
 * The program expects the following arguments:
 *
 *   server         The node which is providing LDAP access to a directory
 *
 *   base           The base object in the directory for the search operation
 *
 *   filter         The search filter to be used
 *
 *   attributes     An optional list of one or more attributes to be returned
 *                  for each matching record.  If no attributes are specified,
 *                  then all user attributes will be returned.
 *
 * An example of a search command would be:
 *
 * $ ldap_example server "o=acme, c=us" "(sn=s*)" cn sn
 *
 * Given the parameters above, the program will attempt to make contact
 * with an LDAP server on node "server", and request a search for all
 * records below the object "o=acme, c=us" that match the filter "sn=s*".
 * For each matching record, the attributes "cn" and "sn" will be displayed.
 */

#include <ldap.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/*
 * Generic routine to display an error message and return any
 * supplementary information from the LDAP handle
 */
void report_error(const char *operation, int result, LDAP *ld)
{
  int    stat;
  char   *errmsgp = NULL;

  printf("%s returned error %d (\"%s\")\n",operation,
         result, ldap_err2string(result));


  stat = ldap_get_option(ld,LDAP_OPT_ERROR_STRING,&errmsgp);

  if ((stat == -1) || (strlen(errmsgp) == 0)) {
    printf("No supplementary error text available\n");
  }
  else {
    printf("Error text : \"%s\"\n",errmsgp);
  }

  if (errmsgp != NULL) {
    ldap_memfree(errmsgp);
    errmsgp = NULL;
  }


}

void main(int argc, char *argv[])
{
  int         stat;
  int         i;
  int         num_entries;
  char        **attrs_array = NULL;
  int         attribute_count;

  /*
   * For servers which don't support version 3 of the protocol, edit
   * the line below to use LDAP_VERSION2.  Both of these constants
   * are defined inside LDAP.H
   */
  int         protocol = LDAP_VERSION3;

  /*
   * The following pointers may be allocated by the LDAP API, and
   * should be free'd using an appropriate mechanism
   */
  LDAP        *ld = NULL;
  LDAPMessage *result = NULL;
  LDAPMessage *one_entry = NULL;
  char        *dn = NULL;
  char        *attr_name = NULL;
  char        **values = NULL;
  BerElement  *ber = NULL;

  if (argc < 4) {
    printf("Usage : %s [server] [base] [filter] <attributes>\n",argv[0]);
    goto finished;
  }

  /*
   * If the user requested any particular attributes, then build up
   * an array to pass to the search routine.  If no attributes are
   * specified, then "attrs_array" will be NULL, and the server should
   * return all user attributes for each matching entry
   */
  attribute_count = (argc - 4);
  if (attribute_count != 0) {
    i = 0;

    /*
     * Allocate enough room for a pointer to each attribute, plus
     * a NULL terminating pointer.
     */
    attrs_array = (char **)calloc((attribute_count + 1),sizeof(char *));
    while (i < attribute_count) {
      attrs_array[i] = strdup(argv[i+4]);
      i++;
    }
  }


  /*
   * Establish a context with the library specifying an LDAP server name
   * and using the default LDAP port number.
   * No connection is made with the server at this stage, so a failure here
   * would indicate a problem with the library, rather than a network or
   * server related issue.
   */
  ld = ldap_init(argv[1], LDAP_PORT);
  if (ld == NULL) {
    printf("ldap_init failed\n");
    goto finished;
  }


  /*
   * Having been provided with a LDAP context, it is possible now to
   * specify options for this session
   */
  stat = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &protocol);
  if (stat != LDAP_SUCCESS) {
    report_error("ldap_set_option",stat,ld);
    goto finished;
  }


  /*
   * Execute a simple bind, without specifying any authorization
   * information, i.e. an anonymous bind
   */
  stat = ldap_simple_bind_s(ld,NULL,NULL);
  if (stat != LDAP_SUCCESS) {
    report_error("simple_bind",stat,ld);
    goto finished;
  }


  /*
   * Issue a synchronous search request; this call will not return
   * until the server has responded.
   */
  stat = ldap_search_s(ld,                  /* ld */
                       argv[2],             /* base */
                       LDAP_SCOPE_SUBTREE,  /* scope */
                       argv[3],             /* filter */
                       attrs_array,         /* attrs */
                       0,                   /* attrsonly */
                       &result);            /* res */


  if (stat != LDAP_SUCCESS) {
    report_error("ldap_search_s",stat,ld);
    goto finished;
  }

  num_entries = ldap_count_entries(ld,result);

  if (num_entries == 0) {
    printf("No matching entries found\n");
    goto finished;
  }

  printf("Number of entries returned : %d\n",num_entries);

  /*
   * Now look at the results that came back
   */
  one_entry = ldap_first_entry(ld,result);

  while (one_entry != NULL) {

    /*
     * The distinguished name of this entry
     */
    dn = ldap_get_dn(ld,one_entry);

    if (dn != NULL) {
      printf("\ndn = %s\n",ldap_get_dn(ld,one_entry));
      ldap_memfree(dn);
      dn = NULL;

      /*
       * Step through each attribute
       */
      attr_name = ldap_first_attribute(ld,one_entry,&ber);
      if (attr_name == NULL) {
        printf("<No attributes returned>\n");
      }

      /*
       * Extract the values for each attribute returned.  This program
       * assumes that such values will be "printable" value strings.  For
       * non-printable (binary) data, ldap_get_values_len() should
       * be used.
       */
      while (attr_name != NULL) {
        values = ldap_get_values(ld,one_entry,attr_name);
        if (values == NULL) {
          printf("<no values returned>\n");
        }
        else {
          i = 0;
          while (values[i] != NULL) {
            printf("%s : %s\n",attr_name,values[i]);
            i++;
          }
        }

        ldap_memfree(attr_name);
        attr_name = NULL;

        ldap_value_free(values);
        values = NULL;


        attr_name = ldap_next_attribute(ld,one_entry,ber);
      }

      /*
       * The BerElement pointer is no longer needed and so can be
       * released.  Since this pointer was just being used as an
       * iterator and doesn't point to any memory that the program
       * has allocated itself, use zero as the second parameter to
       * ber_free().
       */
      if (ber != NULL) {
        ber_free(ber, 0);
        ber = NULL;
      }

    }
    else {
      report_error("ldap_get_dn",0,ld);
    }

    one_entry = ldap_next_entry(ld,one_entry);
  }

  /*
   * All exit paths should come through here, where free up any data
   * structures that the library has allocated using the appropriate
   * functions.
   * It is a good habit to set pointers to NULL after releasing them,
   * although in the cases below it isn't strictly necessary.
   */
finished:

  /*
   * "dn" may have been allocated by ldap_get_dn()
   */
  if (dn != NULL) {
    ldap_memfree(dn);
    dn = NULL;
  }

  /*
   * "attr_name" may have been allocated by ldap_first_attribute() or
   * ldap_next_attribute()
   */
  if (attr_name != NULL) {
    ldap_memfree(attr_name);
    attr_name = NULL;
  }

  /*
   * "values" may have been allocated by ldap_get_values()
   */
  if (values != NULL) {
    ldap_value_free(values);
    values = NULL;
  }

  /*
   * "ber" may have been allocated by ldap_first_attribute() or
   * ldap_next_attribute()
   * Since this pointer was just being used as an iterator and
   * doesn't point to any memory that the program has allocated
   * itself, use zero as the second parameter to ber_free()
   */
  if (ber != NULL) {
    ber_free(ber, 0);
    ber = NULL;
  }

  /*
   * "one_entry" may have been allocated by ldap_first_entry() or
   * ldap_next_entry()
   */
  if (one_entry != NULL) {
    ldap_msgfree(one_entry);
    one_entry = NULL;
  }

  /*
   * "result" may have been allocated by ldap_search_s()
   */
  if (result != NULL) {
    ldap_msgfree(result);
    result = NULL;
  }

  /*
   * "ld" was returned from ldap_init()
   */
  if (ld != NULL) {
    ldap_unbind(ld);
    ld = NULL;
  }

  /*
   * "attrs_array" was allocated by this program
   */
  if (attrs_array != NULL) {
    i = 0;
    while (attrs_array[i] != NULL) {
      free(attrs_array[i]);
      attrs_array[i] = NULL;
      i++;
    }
    free(attrs_array);
    attrs_array = NULL;
  }

  printf("\nProgram terminating\n");

}

Back to Home
Neil Rieck
Waterloo, Ontario, Canada.