12. Appendix A: Writing a slapd Backend

Slapd has a front end that handles connection management, access control, and protocol interpretation, and a number of backends that handle database operations. The two pieces communicate through a well-defined API. This section documents that API for programmers who want to write their own database backend, and describes the steps necessary to integrate a new backend with slapd.

Here's a quick overview of the steps you should follow to create a new backend for slapd.

1. Choose a name for your backend (we'll call it foo) and create a new directory in the slapd source area (servers/slapd/) called back-foo. This directory will contain the backend routines you are about to write. You should also create a Make-template file in this directory. See the other Make-template files in the various back-*/ directories for examples.

2. Write backend routines for each function you want your backend to provide. See the next section for details on how to do this and the API your routines should export. You should prefix your backend routines with "foo_" to ensure uniqueness. Your backend will undoubtedly want to call some of the utility routines described in section A.2.

3. Edit the file servers/slapd/backend.c to add declarations for the backend routines you wrote in step 2, and to initialize a backend structure. Take a look at the existing definitions in that file for other backends.

12.1 The slapd Backend API

The slapd backend API (SLAPI) consists of twelve calls. Nine of the calls correspond to the nine LDAP protocol operations bind, unbind, search, compare, modify, modify RDN, add, delete, and abandon. The other three calls are to initialize the backend, shut down the backend, and handle backend-specific configuration. Each call is described in detail below. The first nine routines are passed the same first three parameters:
Backend *be /* info about this backend */
Connection *conn /* info about this connection */
Operation *op /* info about this operation */
The other parameters depend on the call itself.

12.1.1 Bind

The SLAPI bind routine is defined as follows.
foo_bind(
Backend *be,
Connection *conn,
Operation *op,
char *dn,
int method,
struct berval *cred
)
The first three parameters are as defined above. The remaining parameters are
dn
The distinguished name to bind as.
method
The authentication method to use. It should be one of the ldap.h constants
LDAP_AUTH_SIMPLE
LDAP_AUTH_KRBV41
LDAP_ATH_KRBV42
cred
The credentials for the bind (either a password or Kerberos credentials).
The bind routine should return a value of 0 if the bind is successful, nonzero otherwise. This is important, as a return of 0 will cause the front end to consider the connection authenticated, and it will base subsequent access control decisions assuming the DN supplied is authentic.

Things to note:

* If the length of the credentials supplied for simple authentication is zero, a NULL bind is being requested. This should succeed.

* If a client sends a NULL dn, a NULL bind is also requested. This situation is handled by the front end, so you will never see it.

12.1.2 Unbind

The SLAPI unbind routine is defined as follows.
foo_unbind(
Backend *be,
Connection *conn,
Operation *op
)
The only three parameters are the common parameters defined above. The connection will be dropped by the front end. The unbind backend routine is provided so the backend can do any clean-up of local information it has pertaining to the connection.

12.1.3 Compare

The SLAPI compare function is defined as follows.
foo_compare(
Backend *be,
Connection *conn,
Operation *op,
char *dn,
Ava *ava
)
The first three parameters are the common ones described above. The other parameters are
dn
The distinguished name of the entry on which to perform the compare.
ava
The attribute value assertion to test against the entry.
The AVA structure is defined as follows.
typedef struct ava {
char *ava_type;
struct berval ava_value;
} Ava;
The type to compare is given in the ava_type field, and the value to compare is given in the ava_value field.

12.1.4 Search

The SLAPI search routine is defined as follows.
foo_search(
Backend *be,
Connection *conn,
Operation *op,
char *base,
int scope,
int sizelimit,
int timelimit,
Filter *filter,
char *filterstr,
char **attrs,
int attrsonly
)
The first three parameters are the common ones described above. The rest of the parameters are
base
The DN of the base object at which to start the search.
scope
The scope of the search. One of the ldap.h constants
LDAP_SCOPE_BASEOBJECT
LDAP_SCOPE_ONELEVEL
LDAP_SCOPE_SUBTREE
sizelimit
A client-supplied limit on the number of entries to return. A value of zero implies no limit.
timelimit
A client-supplied limit on the number of seconds to spend on the search. A value of zero implies no limit.
filter
A data structure representing the search filter. A backend would normally use either this parameter or the filterstr parameter, not both. See below for a description of this structure.
filterstr
A string representation of the search filter. A backend would normally use either this parameter or the filter parameter, not both. The format of this string is as defined in RFC 1588.
attrs
An array of char *'s indicating the attributes to return from the search. A NULL value for attrs implies all attributes.
attrsonly
A Boolean parameter indicating whether only attribute types should be returned (non-zero) or if attribute types and values should be returned (zero).
The Filter structure is used to represent an LDAP search filter. The search filter is described in ASN.1 as the following.
Filter ::= CHOICE {
and [0] SET OF Filter,
or [1] SET OF Filter,
not [2] Filter,
equalityMatch [3] AttributeValueAssertion,
substrings [4] SubstringFilter,
greaterOrEqual [5] AttributeValueAssertion,
lessOrEqual [6] AttributeValueAssertion,
present [7] AttributeType,
approxMatch [8] AttributeValueAssertion
}
The C language Filter structure definition used to represent this via the filter parameter is defined as follows in the slap.h header file.
typedef struct filter {
unsigned long f_choice; /* from ldap.h */
union {
char *f_un_type /* present */
Ava f_un_ava; /* eq,approx,le,ge */
struct filter *f_un_complex;/* and,or,not */
struct sub { /* substrings */
char *f_un_sub_type;
char *f_un_sub_initial;
char **f_un_sub_any;
char *f_un_sub_final;
} f_un_sub;
} f_un;
#define f_type f_un.f_un_type
#define f_ava f_un.f_un_ava
#define f_avtype f_un.f_un_ava.ava_type
#define f_avvalue f_un.f_un_ava.ava_value
#define f_and f_un.f_un_complex
#define f_or f_un.f_un_complex
#define f_not f_un.f_un_complex
#define f_list f_un.f_un_complex
#define f_sub f_un.f_un_sub
#define f_sub_type f_un.f_un_sub.f_un_sub_type
#define f_sub_initial f_un.f_un_sub.f_un_sub_initial
#define f_sub_any f_un.f_un_sub.f_un_sub_any
#define f_sub_final f_un.f_un_sub.f_un_sub_final
struct filter *f_next; /* in and/or chain */
} Filter;
The f_choice field will have one of the following values, defined in the ldap.h header file.
LDAP_FILTER_AND
LDAP_FILTER_OR
LDAP_FILTR_NOT
LDAP_FILTER_EQUALITY
LDAP_FILTER_SUBSTRINGS
LDAP_FILTER_GE
LDAP_FILTER_LE
LDAP_FILTER_PRESENT
LDAP_FILTER_APPROX

12.1.5 Modify

The SLAPI modify function is defined as follows.
foo_modify(
Backend *be,
Connection *conn,
Operation *op,
char *dn,
LDAPMod *mods
)
The first three parameters are the common ones described above. The other parameters are
dn
The distinguished name of the entry to modify.
mods
The list of modifications to make to the entry.
The LDAPMod structure is defined as follows in the ldap.h header file.
typedef struct ldapmod {
int mod_op;
char *mod_type;
union {
char **modv_strvals;
struct berval **modv_bvals;
} mod_vals;
#define mod_values mod_vals.modv_strvals
#define mod_bvalues mod_vals.modv_bvals
struct ldapmod *mod_next;
} LDAPMod;
The mod_op field identifies the type of modification and will have one of the following values, defined in the ldap.h header file.
LDAP_MOD_ADD
LDAP_MOD_DELETE
LDAP_MOD_RELACE
Note that the mod_bvalues form of representing values is always used, but that the mod_op field is not ORed with LDAP_MOD_BVALUES, as LDAP clients must do to use the mod_bvalues field.

12.1.6 Modify RDN

The SLAPI modify RDN function is defined as follows.
foo_modifyrdn(
Backend *be,
Connection *conn,
Operation *op,
char *dn,
char *newrdn,
int deleteoldrdn
)
The first three parameters are the common ones described above. The other parameters are
dn
The distinguished name of the entry whose name is to be changed.
newrdn
The new RDN to give the entry.
deleteoldrdn
A Boolean flag indicating whether the old RDN is to be deleted from the entry (non-zero) or kept as a non-distinguished attribute value in the entry (zero).

12.1.7 Add

The SLAPI add function is defined as follows.
foo_add(
Backend *be,
Connection *conn,
Operation *op,
Entry *e
)
The first three parameters are the common ones described above. The additional parameter is
e
A pointer to an Entry structure specifying the entry to add.
The Entry structure is defined in the slap.h header file as follows.
typedef struct entry {
char *e_dn;
Attribute *e_attrs;
/* other things you should not mess with */
} Entry;
The e_dn field contains the DN of the entry.

The e_attrs field is a linked list of the entry's attributes. Each element of this list has the following definition, as given in slap.h.

typedef struct attr {
char *a_type;
struct berval **a_vals;
int a_syntax;
struct attr *a_next;
} Attribute;
The a_syntax field identifies the syntax of the attribute and will have one of the following values, defined in slap.h.
SYNTAX_CIS /* case insensitive string */
SYNTAX_CES /* case sensitive string */
SYNTAX_BIN /* binary data */
SYNTAX_TEL /* telephone number string */
SYNTAX_DN /* dn string */
The syntax values may be additive in some cases. For example, an attribute of type telephoneNumber will have syntax (SYNTAX_CIS | SYNTAX_TEL).

12.1.8 Delete

The SLAPI delete function is defined as follows.
foo_delete(
Backend *be,
Connection *conn,
Operation *op,
char *dn
)
The first three parameters are the common ones described above. The additional parameter is
dn
The distinguished name of the entry to delete.

12.1.9 Abandon

The SLAPI abandon function is defined as follows.
foo_abandon(
Backend *be,
Connection *conn,
Operation *op,
int id
)
The first three parameters are the common ones defined above. The additional parameters is
id
the message identifier of the request to be abandoned.
In addition, the front end will set the o_abandoned flag in the operation's Operation structure. Backends may check this flag periodically to see if the operation has been abandoned.

12.1.10 Initialization

When a new backend instance is encountered in the slapd configuration file, the corresponding SLAPI initialization routine is called. It is defined as follows.
foo_init(
Backend *be
)
The sole parameter is
be
The backend-specific data structure.
The be parameter is used to hold backend-specific information. It is as defined in the beginning of this section in the slap.h header file. If your backend needs to keep any information specific to a backend instance, it should put it in the be_private field of the be parameter.

12.1.11 Configuration

When a configuration option unknown to the front end is encountered in a database definition in the slapd configuration file, it is parsed and passed to a backend-specific configuration routine for processing. The SLAPI backend-specific configuration routine is defined as follows.
foo_config(
Backend *be,
int lineno,
int argc,
char **argv
)
The parameters are
be
The backend-specific data structure defined above.
lineno
The current line number in the configuration file. This is useful if an error message has to be printed.
argc
The number of arguments from the configuration file line.
argv
The list of arguments from the configuration file line.

12.1.12 Close

When slapd exits normally, it calls a close routine provided by each backend database, allowing the backends to clean up and shut down properly. The SLAPI close routine is defined as follows.
foo_close(
Backend *be
)
The sole parameter is
be
The backend-specific data described above.

12.2 Utility Routines Your Backend May Want to Call

There are several utility routines provided for dealing with various data types, sending results and errors to clients, etc., that your backend will likely want to call. Some of the more common and useful routines are described here.

12.2.1 Sending Search Entries

The send_search_entry() routine is used to encode a search result entry and send it back to the client. It is defined as follows.
send_search_entry(
Backend *be,
Connection *conn,
Operation *op,
Entry *e,
char **attrs,
int attrsonly
)
The first three parameters are the common ones passed to the backend routines. The entry to send back is given in e. An array of attribute types to include from the entry (subject to access control) is given in attrs. The attrsonly parameter determines whether attributes only or attributes and values should be sent back.

12.2.2 Sending a Result

An LDAPResult is sent to the client by calling the send_ldap_result() routine, defined as follows.
send_ldap_result(
Connection *conn,
Operation *op,
int err,
char *matched,
char *text
)
The first two parameters are two of the three common parameters passed to the backend. The err parameter is the LDAP error code to pass back. It should be one of the codes defined ldap.h. The matched parameter should only be non-NULL if err is set to LDAP_NO_SUCH_OBJECT. In this case, matched gives the DN prefix of the request that was resolved successfully. The final parameter, text, is an arbitrary string sent back to the client. It is meant to contain a helpful error message.

12.2.3 Testing a Filter Against an Entry

Often, your backend may need to test an entry to see if it satisfies a given search filter. The test_filter() routine is provided for this purpose.
test_filter(
Backend *be,
Connection *conn,
Operation *op,
Entry *e,
Filter *filter
)
The first three parameters are the common ones. The e parameter is the entry to match against the filter, given in the filter parameter. test_filter() returns zero if the entry matches the filter, non-zero otherwise.

12.2.4 Creating an Entry

Two routines are provided to convert between the LDIF text entry format and the internal representation. They are
str2entry(
char *s
)
where s is the string containing the LDIF entry; and
char *
entry2str(
Entry *e,
int *len,
int printid
)
where len will contain the length of the string returned, and printid indicates whether the entry ID should be printed in the LDIF format. The string returned should be considered a pointer to static storage that is overwritten on each call.
[View Next Section] [View Previous Section] [Return to Table of Contents]

Send comments about this page to: ldap-support@umich.edu