Question

Background
I am having trouble error handling the ldap_initialize function in C.

After reading through numerous documents (most which are just flat out copies of the man pages), I have found a number of ways (which are possibly misleading or wrong) to error handle this function.

Here is the code that I am having trouble with:

//--------------------------------------
// declarations
//--------------------------------------
int status = 0;
int optionHandlingStatus = 0;
char * ldapErrorString = NULL;
char serverAddress[PLS_STRING_ARRAY_SIZE];

//--------------------------------------
// prepare the server's address
//--------------------------------------
sprintf(
    serverAddress,
    "ldap://%s:%s",
    settings->serverAddress,
    settings->serverPort
);
//writeDebugLog("LDAP server address set to [%s].", serverAddress);

//--------------------------------------
// connect to the server
//--------------------------------------
status = ldap_initialize(&ldapServerConnection, serverAddress);
optionHandlingStatus = ldap_get_option(ldapServerConnection, LDAP_OPT_RESULT_CODE, &status);
if (status != LDAP_SUCCESS || errno != LDAP_SUCCESS) { //the specs are strange
    if (status && errno) {
        writeDebugLog("CONNECTION Fail!.");
        writeSyslog("CONNECTION Fail!.");
    }
    ldapErrorString = ldap_err2string(status);
    writeDebugLog("Connection to server failed with [%s].", ldapErrorString);
    writeSyslog(
        "LDAP server initalization error. Check [%s] server's status.",
        serverAddress
    );
    return(NULL);
}  

Problem
The documents say that ldap_initialize should either:
1. return a NULL pointer in the case of a connection error (if I use ldap_init)
2. return an error status that can be fetched using ldap_get_option

However, neither of these methods are reliable. I have done thorough testing of the function that I created to start the connection to my LDAP server. There are times ldap_init returns with a valid pointer to an LDAP object, ldap_initialize returns the with the error code LDAP success (when using ldap_get_option), and ldap_get_option returns successfully when parsing error codes.

I have found that if I check C's errno variable I can fairly accurately get the connection status of the ldap_initialize function as it seems to be setting an errno when it fails (errno == 2) => "No such file or directory".

When I specify random unused ports in my program, this is usually accurate. However, I went to test my program more thoroughly with a program named pamtester and it was unable to authenticate the users that I had specified. The error that was set was "No such file or directory" immediately after my call to ldap_initialize.

I set C's (errno = 0) by force after ldap_initialize and I was able to authenticate users against my LDAP database successfully.

Questions
1. What is the correct way to error handle the ldap_initialize function?
2. Should I be using a different function to initialize my LDAP connection?
3. If error status is actually handled by C's errno flag and not by ldap_get_options why do all of the man pages and examples state otherwise?

Was it helpful?

Solution

Only check errno if ldap_initilize returned something different then LDAP_SUCCESS. Also do this immedialty after ldap_initilize returned, otherweise errno might have been spoiled.

The code shall look like this:

int status = ldap_initialize(&ldapServerConnection, serverAddress);
if (status != LDAP_SUCCESS)
{
  /* int errno_save = errno; */
  perror("ldap_initialize() failed"); /* This call shows the error message related to errno. */
  /* If on a GNU system also the following will do: */
  /* fprintf(stderr, ""ldap_initialize() failed with #%d: '%s'\n", errno_save, strerror(errno_save)); */

  writeDebugLog("CONNECTION Fail!.");
  writeSyslog("CONNECTION Fail!.");

  ldapErrorString = ldap_err2string(status);
  writeDebugLog("Connection to server failed with [%s].", ldapErrorString);
  writeSyslog(
    "LDAP server initalization error. Check [%s] server's status.",
    serverAddress
  );
  return(NULL);
}

Update:

Using the ldap_init*() functions does not try to establish a connection, so any invalid address data will not be detected as such. To actually test the connection use ldap_open(), but ldsp_init().

From man ldap_open:

ldap_init() acts just like ldap_open(), but does not open a connection to the LDAP server. The actual connection open will occur when the first operation is attempted.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top