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 "mail=neil.rieck@bell.ca" 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");
}