OpenVMS Source Code Demos

LDAP_EXAMPLE_HACK_AUTHENTICATED

//=====================================================================================================================
// Title  : LDAP_EXAMPLE_HACK_AUTHENTICATED.C
// Author : Neil Rieck
// Created: 2007-06-22
// OS     : OpenVMS-8.2 (or higher)
// Build  : cc   LDAP_EXAMPLE_HACK_AUTHENTICATED.c
//          link LDAP_EXAMPLE_HACK_AUTHENTICATED
// Notes  : 1) derived from "ldap_example_hack.c"
//             which was derived from from "sys$examples:ldap_example.c" published by Compaq in 2000
//        : 2) this version is meant to work with LDAP server "entdirhb000.intranet.bell.ca" which DOES require
//        :    authentication. The server and login parameters are picked up from OpenVMS logical names.
//====================================================================================================================
// $show log icsis$ldap*
//
//  (LNM$SYSTEM_TABLE)
//
//  "ICSIS$LDAP" = "ENABLE"
//  "ICSIS$LDAP_BASE" = "c=CA"
//  "ICSIS$LDAP_LOGLEVEL" = "NONE"
//  "ICSIS$LDAP_PASSWORD" = "ICSIS909291"
//  "ICSIS$LDAP_SERVER1" = "entdirhb000.intranet.bell.ca"
//  "ICSIS$LDAP_SERVER2" = "entdirhb100.intranet.bell.ca"
//  "ICSIS$LDAP_SERVER3" = "entdirhb300.intranet.bell.ca"
//  "ICSIS$LDAP_USER" = "ou=ICSIS,ou=Applications,o=BELL,c=CA"
//=====================================================================================================================
// Create a foreign DCL command (depending upon location) like so:
//	ldapdemo2 := $DISK$USER1:[CODE.DVLP._C_DEMO]ldap_example_hack_authenticated
//
// Try running this app like this:
//	ldapdemo2 "bellPEIN=N026180"           cn mail
//	ldapdemo2 "telephonenumber=7057223259" cn
//	ldapdemo2 "telephonenumber=7057220860" cn mail bellPEIN employeenumber
//
//      ldapdemo2 "bellPEIN=N123119" cn mail   ! returns only NAME + MAIL
//      ldapdemo2 "bellPEIN=N123119" cn        ! returns only NAME
//      ldapdemo2 "bellPEIN=N123119" mail      ! returns only MAIL
//      ldapdemo2 "bellPEIN=N123119"           ! returns everything <<<---***
//
//	ldapdemo2 "[email protected]"      bellorgcode
//=====================================================================================================================

/*
 *
 * 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>
#include <time.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;
	char node[3][45];
	char * user;
	char * pw;
	char * base = "c=CA";
//	node = getenv("ICSIS$LDAP_SERVER1");
	for (i=1; i<4; i++)			// ICSIS$LDAP_SERVER0 -> ICSIS$LDAP_SERVER3
	{
		sprintf(node[i-1], "ICSIS$LDAP_SERVER%d", i);
		sprintf(node[i-1], "%s", getenv(node[i-1]));
	}

	user = getenv("ICSIS$LDAP_USER");	// username (from logical name)
	pw = getenv("ICSIS$LDAP_PASSWORD");	// password (from logical name)
	printf("base: %s\n", base);
	for (i=0;i<3;i++)			// read 3 params
		printf("node[%d]: %s\n", i, node[i]);
	printf("username: %s\n", user);
	printf("password: %s\n", pw);
	/*
	* 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         ldap_opt;
	/*
	* 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 < 2)
	{
//		printf("Usage : %s  [filter] <attributes>\n",argv[0]);
		printf("Usage : %s  <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 - 2);
	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+2]);
			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.
	*/
	i = 0;
loopit:
	if (i > 3)
		goto finished;
	printf("Initializing ldap library with ldap_init(node[i], LDAP_PORT); (ldap_init(\"%s\", %d);\n", node[i] , LDAP_PORT);
	ld = ldap_init(node[i], 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
	*/
	printf("Setting option to LDAP_VERSION3)\n");
	ldap_opt = LDAP_VERSION3;
	stat = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &ldap_opt);
	if (stat != LDAP_SUCCESS)
	{
		report_error("ldap_set_option",stat,ld);
		goto finished;
	}
	printf("Setting default 3 second timeout...\n");
	ldap_opt = 3;	//3 second rule?
	stat = ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &ldap_opt);
	if (stat != LDAP_SUCCESS)
	{
		report_error("ldap_set_option",stat,ld);
		goto finished;
	}
	// If we get here, all is ok.
	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);
	printf("Executing: ldap_simple_bind_s(ld,\"%s\", \"%s\");\n", user, pw);
	stat = ldap_simple_bind_s(ld, user, pw);
	if (stat != LDAP_SUCCESS)
	{
		report_error("simple_bind",stat,ld);
		i++;
		goto loopit;
//		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[1], base);
	struct timeval timeout;
	timeout.tv_sec = 2;
	timeout.tv_usec = 0;
	stat = ldap_search_st(	ld,                  /* ld */
				base,             /* base, eg: c=CA */
				LDAP_SCOPE_SUBTREE,  /* scope */
				argv[1],             /* filter eg: bellPEIN=N026180 */
				attrs_array,         /* attrs */
				0,                   /* attrsonly */
				&timeout,		/* time to wait before timeout		*/
				&result);		/* res */


	printf("Returned from ldap_search_st(...) call.\n");
	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");

}