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.
You can use attribute encryption instead of writing an entry store and entry fetch plug-in. See Encrypting Attribute Values in Sun Java System Directory Server Enterprise Edition 6.3 Administration Guide.
This chapter covers the following topics:
This section describes when entry store and entry fetch plug-ins are called. This section also describes 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.
Unlike other types of plug-ins, entry store and entry fetch plug-in functions do not take a parameter block as an argument. Instead, the functions 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 is as follows:
int my_entrystore_fn(char ** entry, unsigned int * length);
Plug-in functions can manipulate the string as necessary. Entry store and entry fetch plug-ins return zero, 0, on success. When the function returns, Directory Server expects entry and length to contain the modified versions of the parameters.
The plug-in function examples in this chapter can be found in install-path/examples/testentry.c.
The following example shows the entry store scrambling function used in this chapter. This function is called by Directory Server before writing an entry to the database.
#include "slapi-plugin.h" #ifdef _WIN32 typedef unsigned int uint; __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; }
The following example shows the entry fetch unscrambling function used in this chapter. The function is called by the server after reading an entry from the database.
#include "slapi-plugin.h" #ifdef _WIN32 typedef unsigned int uint; __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 can be significantly more complicated.
This section shows how to register entry stored entry fetch plug-ins. It demonstrates how to write a plug-in that scrambles directory entries that are written to the directory database. It also demonstrates how to unscramble directory entries that are read from the directory database.
The examples in this chapter do not constitute a secure entry storage scheme.
The following example demonstrates how entry store and entry fetch plug-ins are registered with Directory Server.
The following example demonstrates how entry store and entry fetch plug-ins are registered with Directory Server.
#include "slapi-plugin.h" Slapi_PluginDesc entrypdesc = { "test-entry", /* plug-in identifier */ "Sun Microsystems, Inc.", /* vendor name */ "6.0", /* 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; }
You demonstrate the plug-in by showing the difference between scrambled and unscrambled data in the database. You therefore do not enable the plug-in immediately. Instead, you add an entry to a new directory suffix before scrambling. You then observe the results in the database on disk. Next, you remove the entry and enable the scrambling plug-in. Then you add the same entry again. Finally, you observe the results after the entry has been scrambled.
If you have not done so already, set up a directory instance with a suffix, dc=example,dc=com, containing data loaded from a sample LDIF file, install-path/ds6/ldif/Example.ldif.
Create a new Directory Server instance.
For example:
$ dsadm create /local/ds Choose the Directory Manager password: Confirm the Directory Manager password: $ |
Start the new Directory Server instance.
For example:
$ dsadm start /local/ds Server started: pid=4705 $ |
Create a suffix called dc=example,dc=com.
For example, with long lines folded for the printed page:
$ dsconf create-suffix -h localhost -p 1389 dc=example,dc=com Enter "cn=directory manager" password: Certificate "CN=defaultCert, CN=hostname:1636" presented by the server is not trusted. Type "Y" to accept, "y" to accept just once, "n" to refuse, "d" for more details: Y $ |
Load the sample LDIF.
For example, with long lines folded for the printed page:
$ dsconf import -h localhost -p 1389 \ /opt/SUNWdsee/ds6/ldif/Example.ldif dc=example,dc=com Enter "cn=directory manager" password: New data will override existing data of the suffix "dc=example,dc=com". Initialization will have to be performed on replicated suffixes. Do you want to continue [y/n] ? y ## Index buffering enabled with bucket size 16 ## Beginning import job... ## Processing file "/opt/SUNWdsee/ds6/ldif/Example.ldif" ## Finished scanning file "/opt/SUNWdsee/ds6/ldif/Example.ldif" (160 entries) ## Workers finished; cleaning up... ## Workers cleaned up. ## Cleaning up producer thread... ## Indexing complete. ## Starting numsubordinates attribute generation. This may take a while, please wait for further activity reports. ## Numsubordinates attribute generation complete. Flushing caches... ## Closing files... ## Import complete. Processed 160 entries in 5 seconds. (32.00 entries/sec) Task completed (slapd exit code: 0). $ |
You can use Directory Service Control Center to perform this task. For more information, see the Directory Service Control Center online help.
Here, you add an entry for Quentin Cubbins to the example suffix before registering the entry store and fetch plug-in with Directory Server. You see that Quentin’s mail address is visible in the database that holds mail address attribute values. Quentin’s entry, quentin.ldif, appears as shown in the following example.
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=bjensen,ou=People,dc=example,dc=com
Add Quentin’s entry to the directory. For example, if the entry is in quentin.ldif, add the following:
$ ldapmodify -a -h localhost -p 1389 -f quentin.ldif \ -D uid=kvaughan,ou=people,dc=example,dc=com -w bribery |
Now look for strings in the directory database file for the mail attribute values.
$ cd instance-path/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 if a user gains access to the database files. If the value was a credit card number, security would have been an issue.
Here, you add an entry for Quentin Cubbins to the example suffix after registering the entry store and fetch plug-in with Directory Server. You see that Quentin’s mail address is no longer visible in the database that holds mail address attribute values.
Before loading the plug-in, delete Quentin’s entry:
$ ldapdelete -D uid=kvaughan,ou=people,dc=example,dc=com -w bribery uid=qcubbins,ou=People,dc=example,dc=com |
Next, configure Directory Server to load the plug-in as shown in the comments at the beginning of testentry.c, and then restart the server.
With the entry store-fetch plug-in active, add Quentin’s entry back into the directory:
$ ldapmodify -a -h localhost -p 1389 -f quentin.ldif \ -D uid=kvaughan,ou=people,dc=example,dc=com -w bribery |
Now search again for strings in the directory database file for the mail attribute values.
$ cd instance-path/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 who have 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 the following example.
$ ldapsearch -h localhost -p 1389 -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, you see that entry store and entry fetch plug-ins affect only the way entries are stored, not the directory front end.