Sun ONE logo     Previous      Contents      Index      Next     
Sun ONE Directory Server 5.2 Plug-In API Programming Guide



Chapter 8   Writing Entry Store and Entry Fetch Plug-Ins

This chapter covers how to write plug-ins that modify how Directory Server operates when writing entries to and reading entries from the directory database.

This chapter includes the following sections:

Calling Entry Store and Entry Fetch Plug-Ins

This section describes when entry store and entry fetch plug-ins are called and how entries are expected to be handled by the plug-in.

The server calls entry store plug-in functions before writing data to a directory database. It calls entry fetch plug-in functions after reading data from the directory database. Entry store and entry fetch plug-ins may therefore typically be used to encrypt and decrypt directory entries, or to perform auditing work.

An LDIF String, Not a Parameter Block

Unlike other types of plug-ins, entry store and entry fetch plug-in functions do not take a parameter block as an argument. Instead, they take two parameters, the LDIF string representation of an entry and the length of the string. Directory Server uses the modified LDIF string after the plug-in returns successfully. An example prototype for an entry store plug-in function:

int my_entrystore_fn(char ** entry, unsigned int * length);

Plug-in functions may manipulate the string as necessary. Entry store and entry fetch plug-ins return 0 on success. When the function returns, Directory Server expects entry and length to contain the modified versions of the parameters.

On Windows Platforms

Export the plug-in function itself with __declspec(dllexport) and include it in the appropriate .def file.

Writing a Plug-In to Encrypt Entries

This section demonstrates how to write a plug-in that scrambles directory entries written to the directory database and de-scrambles directory entries read from the directory database.



Caution

The example does not constitute a secure entry storage scheme.



Code Example 8-1 demonstrates how entry store and entry fetch plug-ins are registered with Directory Server.



Code Example 8-1    Registering Entry Store and Entry Fetch Plug-Ins (testentry.c) 

#include "slapi-plugin.h"

Slapi_PluginDesc entrypdesc = {
"test-entry", /* plug-in identifier */
"Sun Microsystems, Inc.", /* vendor name */
"5.2", /* plug-in revision number */
"Sample entry store/fetch plug-in" /* plug-in description */
};

int
testentry_init(Slapi_PBlock *pb)
{
int rc = 0; /* 0 means success */
rc |= slapi_pblock_set( /* Plug-in API version */
pb,
SLAPI_PLUGIN_VERSION,
SLAPI_PLUGIN_CURRENT_VERSION
);
rc |= slapi_pblock_set( /* Plug-in description */
pb,
SLAPI_PLUGIN_DESCRIPTION,
(void *) &entrypdesc
);
rc |= slapi_pblock_set( /* Entry store function */
pb,
SLAPI_PLUGIN_ENTRY_STORE_FUNC,
(void *) testentry_scramble
);
rc |= slapi_pblock_set( /* Entry fetch function */
pb,
SLAPI_PLUGIN_ENTRY_FETCH_FUNC,
(void *) testentry_unscramble
);
return rc;
}


Finding the Examples

This chapter refers to the plug-in function examples in ServerRoot/plugins/slapd/slapi/examples/testentry.c.

Code Example 8-2 shows the entry store scrambling function used in this chapter, and called by Directory Server before writing an entry to the database.



Code Example 8-2    Entry Fetch Scrambler (testentry.c) 

#include "slapi-plugin.h"

#ifdef _WIN32
typedef unsigned int uint;
#endif

#ifdef _WIN32
__declspec(dllexport)
#endif
int
testentry_scramble(char ** entry, uint * len)
{
uint i;

/* Scramble using bitwise exclusive-or on each character. */
for (i = 0; i < *len - 1; i++) { (*entry)[i] ^= 0xaa; }

slapi_log_info_ex(
SLAPI_LOG_INFO_AREA_PLUGIN,
SLAPI_LOG_INFO_LEVEL_DEFAULT,
SLAPI_LOG_NO_MSGID,
SLAPI_LOG_NO_CONNID,
SLAPI_LOG_NO_OPID,
"testentry_scramble in test-entry plug-in",
"Entry data scrambled.\n"
);

return 0;
}


Code Example 8-3 shows the entry fetch de-scrambling function used in this chapter, and called by the server after reading an entry from the database.



Code Example 8-3    Entry Fetch De-Scrambler (testentry.c) 

#include "slapi-plugin.h"

#ifdef _WIN32
typedef unsigned int uint;
#endif

#ifdef _WIN32
__declspec(dllexport)
#endif
int
testentry_unscramble(char ** entry, uint * len)
{
uint i;

/* Return now if the entry is not scrambled. */
if (!strncmp(*entry, "dn:", 3)) { return 0; }

/* Unscramble using bitwise exclusive-or on each character. */
for (i = 0; i < *len - 1; i++) { (*entry)[i] ^= 0xaa; }

slapi_log_info_ex(
SLAPI_LOG_INFO_AREA_PLUGIN,
SLAPI_LOG_INFO_LEVEL_DEFAULT,
SLAPI_LOG_NO_MSGID,
SLAPI_LOG_NO_CONNID,
SLAPI_LOG_NO_OPID,
"testentry_unscramble in test-entry plug-in",
"Entry data unscrambled.\n"
);

return 0;
}


Notice the symmetry between the two functions. The scrambling mask, 0xaa or 10101010 in binary, makes the transformation simple to understand but not secure. A secure encryption mechanism may be significantly more complicated.

Trying It Out

We demonstrate the plug-in by showing the difference between scrambled and unscrambled data in the database itself. We therefore do not enable the plug-in immediately, but instead add an entry to a new directory suffix before scrambling and observe the results in the database on disk. Then we remove the entry, enable the scrambling plug-in, add the same entry again, and finally observe the results after the entry has been scrambled.

Setting Up an Example Suffix

If you have not done so already, prepare some data by creating a directory suffix, dc=example,dc=com, whose users we load from an LDIF file, ServerRoot/slapd-serverID/ldif/Example-Plugin.ldif. Refer to "Setting Up an Example Suffix" for instructions.

Looking for Strings in the Database Before Scrambling

Here, we add an entry for Quentin Cubbins to our example suffix before registering the entry store-fetch plug-in with Directory Server. We see that Quentin's mail address is visible in the database holding mail address attribute values. Quentin's entry, quentin.ldif, appears as shown in Code Example 8-4.



Code Example 8-4    LDIF Representation of Quentin's Entry 

dn: uid=qcubbins,ou=People,dc=example,dc=com
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
uid: qcubbins
givenName: Quentin
sn: Cubbins
cn: Quentin Cubbins
mail: qcubbins@example.com
userPassword: qcubbins
secretary: uid=bcubbins,ou=People,dc=example,dc=com


Add Quentin's entry to the directory. For example, if the entry is in quentin.ldif:

$ ldapmodify -a -p port -D "cn=directory manager" -w password -f quentin.ldif

Now look for strings in the directory database file for the mail attribute values.



Code Example 8-5    Attribute Values in a Database File Before Scrambling 

$ cd ServerRoot/slapd-serverID/db/example/
$ strings example_mail.db3 | grep example.com
=qcubbins@example.com
=agodiva@example.com
=hfuddnud@example.com
=pblinn@example.com
=scooper@example.com
=bcubbins@example.com
=yyorgens@example.com


Notice that Quentin's mail address is clearly visible to a user who manages to gain access to the database files. If this were not a mail address, but instead a credit card number, we could have a possible security issue.

Looking for Strings in the Database After Scrambling

Here, we add an entry for Quentin Cubbins to our example suffix after registering the entry store-fetch plug-in with Directory Server. We see that Quentin's mail address is no longer visible in the database holding mail address attribute values.

Before loading the plug-in, delete Quentin's entry. For example:

$ ldapdelete -p port -D "cn=directory manager" -w password \
"uid=qcubbins,ou=People,dc=example,dc=com"

Next, load the plug-in configuration entry into the directory, and then restart the server. To load the configuration entry, first save it to a file, testentry.ldif. Code Example 8-6 shows the configuration entry.



Code Example 8-6    Configuration Entry (testentry.c) 

dn: cn=Test entry,cn=plugins,cn=config
objectClass: top
objectClass: nsSlapdPlugin
objectClass: extensibleObject
cn: Test entry
nsslapd-pluginPath: ServerRoot/plugins/slapd/slapi/examples/LibName
nsslapd-pluginInitfunc: testentry_init
nsslapd-pluginType: ldbmentryfetchstore
nsslapd-pluginEnabled: on
nsslapd-plugin-depends-on-type: database
nsslapd-pluginId: test-entry
nsslapd-pluginVersion: 5.2
nsslapd-pluginVendor: Sun Microsystems, Inc.
nsslapd-pluginDescription: Sample entry store/fetch plug-in


After editing ServerRoot to correspond to your system and saving testentry.ldif, modify the directory configuration to include the entry:

$ ldapmodify -a -p port -D "cn=directory manager" -w password \
-f testentry.ldif

Restart Directory Server for the modification to take effect. For example:

$ ServerRoot/slapd-serverID/start-slapd

With the entry store-fetch plug-in active, add Quentin's entry back into the directory:

$ ldapmodify -a -p port -D "cn=directory manager" -w password \
-f quentin.ldif

Now search again for strings in the directory database file for the mail attribute values.



Code Example 8-7    Attribute Values in a Database File After Scrambling 

$ cd ServerRoot/slapd-serverID/db/example/
$ strings example_mail.db3 | grep example.com
=agodiva@example.com
=hfuddnud@example.com
=pblinn@example.com
=scooper@example.com
=bcubbins@example.com
=yyorgens@example.com


Notice that Quentin's mail address value is now not visible in the directory database. Directory users having appropriate access rights (anonymous in this simple example case) can still view the attribute during a search. The attribute and its value are emphasized in Code Example 8-8.



Code Example 8-8    De-Scrambled Search Results 

$ ldapsearch -L -p port -b "dc=example,dc=com" "(uid=qcubbins)"
dn: uid=qcubbins,ou=People,dc=example,dc=com
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
uid: qcubbins
givenName: Quentin
sn: Cubbins
cn: Quentin Cubbins
mail: qcubbins@example.com
secretary: uid=bcubbins,ou=People,dc=example,dc=com


In this way, we see that entry fetch-store plug-ins affect only the way entries are stored, and not the directory frontend.


Previous      Contents      Index      Next     
Copyright 2003 Sun Microsystems, Inc. All rights reserved.