OpenVMS Source Code Demos

LDAP_EXAMPLE_HACK

//=====================================================================================================================
// Title  : LDAP_EXAMPLE_HACK.C
// Author : Neil Rieck
// Created: 2007-06-22
// OS     : OpenVMS-8.2 (or higher)
// Build  : cc   LDAP_EXAMPLE_HACK.c
//	    link LDAP_EXAMPLE_HACK
// Notes  : this program was derived from "sys$examples:ldap_example.c" published by Compaq in 2000
//        : this version is meant to work with LDAP server "bhxcvx.qc.bell.ca" which does not require authentication
//=====================================================================================================================
// Create a foreign DCL command (depending upon location) like so:
//	ldapdemo1 := $DISK$USER1:[CODE.DVLP._C_DEMO]ldap_example_hack
//
// Try running this app like so:
//	ldapdemo1 bhxcvx.qc.bell.ca "o=BELL, c=CA" "bellPEIN=N026180" cn mail
//	ldapdemo1 bhxcvx.qc.bell.ca         "c=CA" "telephonenumber=7057223259" cn
//	ldapdemo1 bhxcvx.qc.bell.ca         "c=CA" "telephonenumber=7057223259"
//	ldapdemo1 bhxcvx.qc.bell.ca "o=BELL, c=CA" "telephonenumber=7057220860" cn mail bellPEIN employeenumber
//
//	ldapdemo1 bhxcvx.qc.bell.ca "o=BELL, c=CA" "bellPEIN=N123119" cn mail	! returns only NAME + MAIL
//	ldapdemo1 bhxcvx.qc.bell.ca "o=BELL, c=CA" "bellPEIN=N123119" cn	! returns only NAME
//	ldapdemo1 bhxcvx.qc.bell.ca "o=BELL, c=CA" "bellPEIN=N123119" mail	! returns only MAIL
//	ldapdemo1 bhxcvx.qc.bell.ca "o=BELL, c=CA" "bellPEIN=N123119"		! returns everything
// ====================================================================================================================
/*
 *
 * 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;
	}

	printf("LDAP environment initialized.\n");

	/*
	* 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;
	}
	printf("Successfully applied LDAP options via ldap_set_option...\n");

	/*
	* Execute a simple bind, using credentials supplied by CGI
	*/
	//	stat = ldap_simple_bind_s(ld,NULL,NULL);
	stat = ldap_simple_bind_s(ld,"ou=ICSIS,ou=Applications,o=BELL,c=CA", "icsis2007");
	if (stat != LDAP_SUCCESS)
	{
		report_error("simple_bind",stat,ld);
		goto finished;
	}

	printf("Logged into server %s.\n", argv[1]);

	/*
	* Issue a synchronous search request; this call will not return
	* until the server has responded.
	*/
	printf("Searching for %s starting from base: %s\n", argv[3], argv[2]);
	stat = ldap_search_s(	ld,                  /* ld */
				argv[2],             /* base, eg: c=CA */
				LDAP_SCOPE_SUBTREE,  /* scope */
				argv[3],             /* filter eg: bellPEIN=N026180 */
				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));
			// Look for company name in dn
			// dn looks like this: employeenumber=78226,ou=EXPERTECH,ou=PEOPLE,o=EXTERNAL,C=ca
			// 		or   : employeeNumber=2026180,ou=BELL CANADA,ou=PEOPLE,o=BELL,c=CA
			char scratch[255];			//allocate some space to scribble in
			char  *start, *end;			//and some pointers to use
			strcpy(scratch, dn);			//copy the distinguished name into modifiable space
			start = strstr(scratch, ",ou=");	//locate the beginning of the company name.
			if (start != NULL)			//Did we find it?
			{
				start += 4;			//move pointer to beginning of company name.
				end = strstr(start, ",");	//find the end of the company name
				*end = '\0';			//put a null after the end
				printf("\nCompany name: %s.\n", start);	//brag that we found the company name.
			}
			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;
					//don't modify values, eg by values++, as ldap_value_free needs to see the original value
					while (values[i] != NULL)	//print out all values for this attribute
					{
						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");

}