LDAP sample program

The sample program is designed for someone who is familiar with LDAP and probably already uses it. It is intended to show how WebSphere MQ applications can use an LDAP directory.

Building the sample program

This program has been built and tested only on Windows using TCP/IP. As well as the general considerations mentioned in Preparing C programs the following points must be observed:

Configuring the directory

Before the sample program can be run, an LDAP Directory Server must be configured with sample data. The file MQuser.ldif contains some sample data in LDIF (LDAP Data Interchange Format). You can edit this file to suit your needs. It contains data for a fictitious company called MQuser that has a Transport Department comprising three offices. Each of these offices has a machine that runs a WebSphere MQ server.

As a minimum you must edit the three lines that contain the host names of the machines running the WebSphere MQ servers - these are lines 18, 27, and 36:

host: LondonHost
  ...
host: SydneyHost
  ...
host: WashingtonHost

You must change "LondonHost", "SydneyHost", and "WashingtonHost" to the names of three of your machines which run WebSphere MQ servers. You may also change the channel and queue names if you wish (the sample uses names of the system defaults). You may also wish to increase or decrease the number of offices in the sample data.

Configuring the IBM eNetwork LDAP server

Refer to the eNetwork LDAP Directory Administrator's Guide for information about installing the directory. In the chapter "Installing and Configuring Server", work through the sections "Installing Server" and "Basic Server Configuration". If necessary, read through the chapter "Administrator Interface" to familiarize yourself with how the interface works.

In the chapter "Configuring - How Do I", follow the instructions for starting up the administrator, then work through the section "Configure Database" and create a default database. Skip the section "Configure replica" and using the section "Work with Suffixes", add a suffix "o=MQuser".

Before adding any entries to the database, you must extend the directory schema by adding some attribute definitions and an objectclass definition. This is described in the eNetwork LDAP Directory Administrator's Guide in the chapter "Reference Information" under the section "Directory Schema". Two sample files are included to help you with this. The file "mq.at.conf" includes the attribute definitions which you must add to the file "/etc/slapd.at.conf". Do this by including the sample file by editing slapd.at.conf and adding a line:

include <pathname>/mq.at.conf

Alternatively you can edit the file slapd.at.conf and add the contents of the sample file directly to it, that is, add the lines:

# MQ attribute definitions
attribute mqChannel           ces   mqChannel        1000   normal
attribute mqQueueManager      ces   mqQueueManager   1000   normal
attribute mqQueue             ces   mqQueue          1000   normal
attribute mqPort              cis   mqPort           64     normal

Similarly for the objectclass definition, you can either include the sample file by editing "etc/slapd.oc.conf" and add the line:

include <pathname>/mq.oc.conf

or you can add the contents of the sample file directly to slapd.oc.conf, that is, add the lines:

# MQ object classdefinition
objectclass mqApplication
      requires
              objectClass,
              cn,
              host,
              mqChannel,
              mqQueue
      allows
              mqQueueManager,
              mqPort,
              description,
              l,
              ou,
              seeAlso

You can now start the directory server (Administration, Server, Startup) and add the sample entries to it. To add the sample entries, go to the Administration, Add Entries page of the administrator, type in the full pathname of the sample file "MQuser.ldif" and click the Submit button.

The directory server is now running and loaded with data suitable for running the sample program.

Configuring the Netscape directory server

Using the Netscape Server Administration page, click on "Create New Netscape Directory Server". You should now be presented with a form containing configuration information. Change the Directory Suffix to "o=MQuser" and add a password for the Unrestricted User. You may also, if you wish, change any other information to suit your installation. Click on the OK button, and the directory should be created successfully. Click on "Return to Server Administration" and start the directory server. Click on the directory name to start the Directory Server Administration server for the new directory.

Before adding any entries to the database, you must extend the directory schema by adding some attribute definitions and an objectclass definition. Click on the "Schema" tab of the Directory Server page. You are now presented with a form that allows you to add new attributes. Add the following attributes (the Attribute OID can be left blank for all of them):

Attribute Name              Syntax
--------------              ------
mqChannel                   Case Exact String
mqQueueManager              Case Exact String
mqQueue                     Case Exact String
mqPort                      Integer

Add a new objectClass by clicking "Create ObjectClass" in the side panel. Enter "mqApplication" as the ObjectClass Name, select "applicationProcess" as the parent ObjectClass and leave the ObjectClass OID blank. Now add some attributes to the objectClass. Select "host", "mqChannel", and "mqQueue" as Required Attributes, and select "mqQueueManager" and "mqPort" as Allowed attributes. Press the "Create New ObjectClass" button to create the objectClass.

To add the sample data, click on the "Database Management" tab and select "Add Entries" from the side panel. You must enter the pathname of the sample data file <pathname>\MQuser.ldif, enter the password, and click on the OK button.

The sample program runs as an unauthorized user, and by default the Netscape Directory does not allow unauthorized users to search the directory. You must change this by clicking the "Access Control" tab. Enter the password for the Unrestricted User and click the OK button to load in the access control entries for the directory. These should currently be empty. Press the "New ACI" button to create a new access control entry. In the entry box which appears, click on the word "Deny" (which is underlined) and in the resultant dialog box, change it to "Allow". Add a name, for example, "MQuser-access", and click on "choose a suffix" to select "o=MQuser". Enter "o=MQuser" as the target, enter the password for the Unrestricted User, and click on the "Submit" button.

The directory server is now running and loaded with data suitable for running the sample program.

Running the sample program

You should now have an LDAP Directory Server running and populated with the sample data. The data specifies three host machines all of which should be running WebSphere MQ servers. You should ensure that the default queue manager is running on each machine (unless you changed the sample data to specify a different queue manager).

You should also start the WebSphere MQ listener program on each machine; the sample uses TCP/IP with the default WebSphere MQ port number, so you can start the listener with the command:

runmqlsr -t tcp

To test the sample, you might also wish to run a program to read the messages arriving at each WebSphere MQ server, for example you could use the "amqstrg" sample program:

amqstrg SYSTEM.DEFAULT.LOCAL.QUEUE

The sample program uses three environment variables, one required and two optional. The required variable is LDAP_BASEDN, which specifies the base Distinguished Name for the directory search. To work with the sample data, you should set this to "ou=Transport, o=MQuser", for example at a command prompt on Windows systems type:

set LDAP_BASEDN=ou=Transport, o=MQuser

The optional variables are LDAP_HOST and LDAP_VERSION. The LDAP_HOST variable specifies the name of the host where the LDAP server is running, it defaults to the local host if it is not specified. The LDAP_VERSION variable specifies the version of the LDAP protocol to be used, and can be either 2 or 3. Most LDAP servers now support version 3 of the protocol; they all support the older version 2. This sample works equally well with either version of the protocol, and if it is not specified it defaults to version 2.

You can now run the sample by typing the program name followed by the name of the WebSphere MQ application you wish to send messages to, in the case of the sample data the application names are "London", "Sydney", and "Washington". For example, to send messages to the London application:

amqsldpc London

If the program fails to connect to the WebSphere MQ server, an appropriate error message will appear. If it connects successfully you can start typing messages, each line you type (terminated by <return> or <enter>) is sent as a separate message, an empty line ends the program.

Program design

The program has two distinct parts: the first part uses the environment variables and command line value to query an LDAP directory server; the second part establishes the WebSphere MQ connection using the information returned from the directory and sends the messages.

The LDAP calls used in the first part of the program differ slightly depending on whether LDAP version 2 or 3 is being used, and they are described in detail by the documentation which comes with the LDAP client libraries. This section gives a brief description.

The first part of the program checks that it has been called correctly and reads the environment variables. It then establishes a connection with the LDAP directory server at the specified host:

if (ldapVersion == LDAP_VERSION3)
{
  if ((ld = ldap_init(ldapHost, LDAP_PORT)) == NULL)
     ...
}
else
{
  if ((ld = ldap_open(ldapHost, LDAP_PORT)) == NULL )
     ...
}

When a connection has been established, the program sets some options on the server with the "ldap_set_option" call, and then authenticates itself to the server by binding to it:

if (ldapVersion == LDAP_VERSION3)
{
  if (ldap_simple_bind_s(ld, bindDN, password) != LDAP_SUCCESS)
     ...
}
else
{
  if (ldap_bind_s(ld, bindDN, password, LDAP_AUTH_SIMPLE) !=
      LDAP_SUCCESS)
     ...
}

In the sample program "bindDN" and "password" are set to NULL, which means that the program authenticates itself as an anonymous user, that is, it does not have any special access rights and can access only information which is publicly available. In practice most organizations would restrict access to the information they store in directories so that only authorized users can access it.

The first parameter to the bind call "ld" is a handle which is used to identify this particular LDAP session throughout the rest of the program. After authenticating, the program searches the directory for entries which match the application name:

rc = ldap_search_s(ld,                 /* LDAP Handle             */
                  baseDN,              /* base distinguished name */
                  LDAP_SCOPE_ONELEVEL, /* one-level search        */
                  filterPattern,       /* filter search pattern   */
                  attrs,               /* attributes required     */
                  FALSE,               /* NOT attributes only     */
                  &ldapResult);        /* search result           */

This is a simple synchronous call to the server which returns the results directly. There are other types of search which are more appropriate for complex queries or when a large number of results is expected. The first parameter to the search is the handle "ld" which identifies the session. The second parameter is the base distinguished name, which specifies where in the directory the search is to begin, and the third parameter is the scope of the search, that is, which entries relative to the starting point are searched. These two parameters together define which entries in the directory are searched. The next parameter, "filterPattern" specifies what we are searching for. The "attrs" parameter lists the attributes which we want to get back from the object when we have found it. The next attribute says whether we want just the attributes or their values as well, setting this to FALSE means that we want the attribute values. The final parameter is used to return the result.

The result could contain many directory entries, each with the specified attributes and their values. We have to extract the values we want from the result. In this sample program we only expect one entry to be found, so we only look at the first entry in the result:

ldapEntry = ldap_first_entry(ld, ldapResult);

This call returns a handle which represents the first entry, and we set up a for loop to extract all the attributes from the entry:

for (attribute = ldap_first_attribute(ld, ldapEntry, &ber);
     attribute != NULL;
     attribute = ldap_next_attribute(ld, ldapEntry, ber ))
{

For each of these attributes, we extract the values associated with it. Again we only expect one value per attribute, so we only use the first value; we determine which attribute we have and store the value in the appropriate program variable:

values = ldap_get_values(ld, ldapEntry, attribute);
if (values != NULL && values[0] != NULL)
{
  if (stricmp(attribute, MQ_HOST_ATTR) == 0)
  {
    mqHost = strdup(values[0]);
    ...

Finally we tidy up by freeing memory (ldap_value_free, ldap_memfree, ldap_msgfree) and close the session by "unbinding" from the server:

ldap_unbind(ld);

We check that we have found all the WebSphere MQ values we need from the directory, and if so we call sendMessages() to connect to the WebSphere MQ server and send the WebSphere MQ messages.

The second part of the sample program is the sendMessages() routine which contains all of the WebSphere MQ calls. This is modelled on the amqsput0 sample program, the differences being that the parameters to the program have been extended and MQCONNX is used instead of the MQCONN call.



© IBM Corporation 1993, 2002. All Rights Reserved