Mozilla LDAP C SDK Programmer's Guide

Chapter 7 - Using Filter Configuration Files

This chapter explains how to use API functions to work with filter configuration files. Filter configuration files can help simplify the process of selecting the appropriate search filter for a search request.

The chapter contains the following sections:

Understanding Filter Configuration Files

Suppose that you are writing a client that allows users to search the directory. You might want to use different search filters tailored for specific types of search criteria. For example, suppose the user wants to search for this:
bjensen@example.com

You might want to use this search filter:
(mail=bjensen@example.com)

Similarly, suppose the search term entered by the user contains numbers, like this:
555-1212

In this case, you might want to use this search filter:
(telephoneNumber=555-1212)

Rather than write code to find and select the appropriate filter (based on the user's search criteria), you can include the filters in a filter configuration file.

A filter configuration file contains a list of filters that you can load and use in your searches.

Understanding the Configuration File Syntax

A filter configuration file has the following format:

tag
 pattern1  delimiters  filter1-1 desc1-1 [scope]
 filter1-2  desc1-2              [scope]
 pattern2  delimiters  filter2-1 desc2-1 [scope]
...

This format is explained below:

For example, the following section of a filter configuration file specifies a filter for telephone numbers and two filters for email addresses. The telephone number filter is used if the search criteria contains one or more numbers. The email filters are used if the search criteria contains an "at" sign (@).

"people"
 "^[0-9][0-9-]*$"     "
 "(telephoneNumber=*%v))"  "phone number ends with"
 "@"  " " "(mail=%v)"  "email address is"
 "(mail=%v*)"         "email address starts with"

You should specify the filters in the order that you want them to be used. For example, if you want to apply the (mail=%v) filter before the (mail=%v*) filter, make sure that the filters appear in that order.

Understanding Filter Parameters

Within a filter, you can use the following parameters:

Loading a Filter Configuration File

To load a filter configuration file, call the ldap_init_getfilter() function.

You can also read the filter configuration file from a buffer in memory by calling the ldap_init_getfilter_buf() function.

Both functions return a pointer to an LDAPFiltDesc structure, which contains information about the filter. If an error occurs, both functions return NULL.

Retrieving Filters

After loading a filter configuration file into memory, you can retrieve filters based on the search criteria. For example, if the search criteria is an e-mail address (bjensen@example.com), you can have your client automatically search for this value in the mail attribute of person entries.

To retrieve the first filter that matches the search criteria, call the ldap_getfirstfilter() function.

To get the next filter that matches the search criteria, call the ldap_getnextfilter() function.

Both functions return a pointer to an LDAPFiltInfo structure, which contains information about the filter.

The following section of code uses a filter configuration file containing the following filters:

"people"
 "^[0-9][0-9-]*$"    "
 "(telephoneNumber=*%v))"  "phone number ends with"
 "@"  " " "(mail=%v)"  "email address is"
 "(mail=%v*)"         "email address starts with"

This section of code retrieves filters that match the search criteria.

Code Example 7-1 - Retrieving configuration filters

#include <stdio.h>
#include <ldap.h>
...
LDAP     *ld;
LDAPMessage  *result, *e;
BerElement  *ber;
char     *a, *dn;
char     **vals;
int i;
LDAPFiltDesc *ldfp;
LDAPFiltInfo *ldfi;
char buf[ 80 ]; /* contains the search criteria */
int found;
...
/* Load the filter configuration file into an LDAPFiltDesc structure. */
if ( ( ldfp = ldap_init_getfilter( "myfilters.conf" ) ) == NULL ) {
 perror( "Cannot open filter configuration file" );
}

/* Select a filter to use when searching for the value in buf.
Use filters under the "people" tag in the filter configuration file. */
found = 0;
for ( ldfi = ldap_getfirstfilter( ldfp, "people", buf ); ldfi != NULL; 
 ldfi = ldap_getnextfilter( ldfp ) ) {

 /* Use the selected filter to search the directory. */
 if ( ldap_search_s( ld, "dc=example,dc=com", ldfi->lfi_scope, 
  ldfi->lfi_filter, NULL, 0, &result ) != LDAP_SUCCESS ) {
  ldap_perror( ld, "ldap_search_s" );
  return( 1 );
 } else {

  /* Once a filter gets results back, stop iterating through 
  the different filters. */ 
  if ( ( found = ldap_count_entries( ld, result ) > 0 ) ) {
   break;
  } else { 
   ldap_msgfree( result );
  }
 }
}

if ( found == 0 ) {
 printf( "No matching entries found.\n" );
} else {
 printf( "Found %d match%s where %s \"%s\"\n\n", found, 
  found == 1 ? "" : "es", ldfi->lfi_desc, buf );
}

ldap_msgfree( result );
ldap_getfilter_free( ldfp );
...

Suppose that the search criteria is bjensen@example.com and the client application finds one matching entry. In this case, the application prints the following output:
Found 1 match where email address is bjensen@example.com

Adding Filter Prefixes and Suffixes

If you need to apply a filter to all searches, you can add a filter prefix and suffix to all filters (rather than add the criteria to all filters). For example, if your client searches only for person entries, you can add the following filter prefix to restrict the search:
(&(objectClass=person)

Note that this filter now requires a suffix ")" to balance the number of parentheses. This prefix is automatically added to any filter retrieved through the ldap_getfirstfilter() and ldap_getnextfilter() functions. (See "Retrieving Filters" for details.) For example, suppose you use this filter in a filter configuration file:
(cn=Babs Jensen)

If you retrieve this filter through the ldap_getfirstfilter() or ldap_getnextfilter() function, you get the following filter:
(&(objectClass=person)(cn=Babs Jensen))

To add a prefix and suffix automatically to all filters retrieved from the filter configuration file, call the ldap_set_filter_additions() function.

The following section of code loads the filter configuration file named myfilters.conf into memory and adds the prefix (&(objectClass=person) and the suffix ")" to each filter retrieved:

Code Example 7-2 - Adding prefixes and suffixes

...
LDAPFiltDesc *lfdp;
char *filter_file = "myfilters.conf"; 
char *prefix = "(&(objectClass=person)";
char *suffix = ")";
...
lfdp = ldap_init_getfilter( filter_file );
ldap_setfilteraffixes( lfdp, prefix, suffix );
...

Freeing Filters from Memory

When you complete your search, you should free the LDAPFiltDesc structure from memory. To free the LDAPFiltDesc structure, call the ldap_getfilter_free() function.

The following section of code frees the LDAPFiltDesc structure from memory after all searches are completed.

Code Example 7-3 - Freeing filters from memory

...
LDAPFiltDesc *lfdp;
char *filter_file = "myfilters.conf";
...
/* Read the filter configuration file into an LDAPFiltDesc structure. */
lfdp = ldap_init_getfilter( filter_file );
...
/* Retrieve filters and perform searches. */
...
/* Free the configuration file (the LDAPFiltDesc structure). */
ldap_getfilter_free( lfdp );
...

Creating Filters Programmatically

You can build your own filters by calling the ldap_create_filter() function.

The following section of code builds the filter (mail=bjensen@example.com).

Code Example 7-4 - Creating filters

char *pattern = "(%a=%v);
char *attr = "mail";
char *value = "bjensen@example.com";
...
ldap_create_filter( buf, LDAP_FILT_MAXSIZ, pattern, NULL, NULL, attr, 
  value, NULL );
...