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



Chapter 11   Writing Password Storage Scheme Plug-Ins

This chapter covers how to write plug-ins that let you modify how Directory Server stores password attribute values.

This chapter includes the following sections:

Calling Password Storage Scheme Plug-Ins

This section describes the circumstances in which Directory Server calls password storage scheme plug-ins and how password values are expected to be handled by the plug-ins.

Two Types

Two types of password storage scheme plug-ins work with Directory Server, pwdstoragescheme and reverpwdstoragescheme. The former is one-way, in that once the server encodes and stores a password, the password is not decoded. The pwdstoragescheme type therefore includes plug-in functions only for encoding passwords to be stored and for comparing incoming passwords with encoded, stored passwords. The latter is reversible, in that the plug-in allows Directory Server both to encode and to decode passwords. The reverpwdstoragescheme type therefore includes encode, compare, and decode plug-in functions.



Note

This chapter covers the one-way type pwdstoragescheme plug-ins.



Pre-Installed Schemes

Existing schemes delivered with Directory Server are provided as password storage scheme plug-ins. Search cn=config for entries whose DN contains cn=Password Storage Schemes. The default password storage scheme uses the Salted Secure Hashing Algorithm (SSHA).

You can change the password storage scheme used to encode user passwords. Refer to the Sun ONE Directory Server Administration Guide for instructions.

Affects Password Attribute Values

Password storage scheme plug-in functions act on password (userPassword) attribute values. Directory Server registers password storage scheme plug-ins at startup. After startup, any registered, enabled password storage scheme plug-in can then be used to encode password values, and to compare incoming passwords to the encoded values. Which plug-in Directory Server invokes depends on the password storage scheme used for the entry in question.

Invoked for Add and Modify Requests

Add and modify requests can imply that Directory Server encode an input password, and then store it in the directory. First, Directory Server determines the storage scheme for the password value. Next, it invokes the plug-in encode function for the appropriate scheme. The encode function returns the encoded password to Directory Server.

Invoked for Bind Requests

Bind requests imply that Directory Server compares an input password value to a stored password value. As for add and modify requests, Directory Server determines the storage scheme for the password value. Next, it invokes the plug-in compare function for the appropriate scheme. The compare scheme returns an int that communicates to Directory Server whether the two passwords match as described in "Comparing a Password".

Part of a Password Policy

Password storage scheme plug-ins typically do no more than encode passwords and compare input passwords with stored, encoded passwords. In other words, they represent only a part of a comprehensive password policy. Refer to the Sun ONE Directory Server Deployment Guide for suggestions on designing secure directory services.

Writing a Password Storage Scheme Plug-In

This section demonstrates how to write a plug-in that encodes passwords and allows Directory Server to compare stored passwords with passwords provided by a client application.



Caution

The example does not constitute a secure password storage scheme.



The source for the example plug-in referenced in this section is ServerRoot/plugins/slapd/slapi/examples/testpwdstore.c. For encoding and comparing, the plug-in performs an exclusive or with 42 on each character of the password.

Encoding a Password

When Directory Server calls a password storage scheme plug-in encode function, it passes that function an input password char * and expects an encoded password char * in return. The prototype for our example encode function, xorenc(), is:

static char * xorenc(char * pwd);

Allocate space for the encoded password using slapi_ch_malloc() rather than regular malloc(). Directory Server can then terminate with an "out of memory" message if allocation fails. Free memory using slapi_ch_free().

By convention, we prefix the encoded password with the common name, of the password storage scheme, enclosed in braces, { and }. In other words, our example plug-in has cn: XOR.

Our name is declared in the example:

static char * name = "XOR"; /* Storage scheme name */

We return encoded strings prefixed with {XOR}, and register that name with Directory Server.



Code Example 11-1    Encoding a userPassword Value (testpwdstore.c) 

#include "slapi-plugin.h"

static char * name ="XOR"; /* Storage scheme name */

#define PREFIX_START '{'
#define PREFIX_END '}'

static char *
xorenc(char * pwd)
{
char * tmp = NULL; /* Used for encoding */
char * head = NULL; /* Encoded password */
char * cipher = NULL; /* Prefix, then pwd */
int i, len;

/* Allocate space to build the encoded password */
len = strlen(pwd);
tmp = slapi_ch_malloc(len + 1);
if (tmp == NULL) return NULL;

memset(tmp, '\0', len + 1);
head = tmp;

/* Encode. This example is not secure by any means. */
for (i = 0; i < len; i++, pwd++, tmp++) *tmp = *pwd ^ 42;

/* Add the prefix to the cipher */
if (tmp != NULL) {
cipher = slapi_ch_malloc(3 + strlen(name) + strlen(head));
if (cipher != NULL) {
sprintf(cipher,"%c%s%c%s",PREFIX_START,name,PREFIX_END,head);
}
}
slapi_ch_free((void **) &head);

return (cipher); /* Server frees cipher */
}


Notice we free only memory allocated for temporary use. Directory Server frees memory for the char * returned, not the plug-in. For details on slapi_ch_malloc() and slapi_ch_free(), refer to the Sun ONE Directory Server Plug-In API Reference.

Comparing a Password

When Directory Server calls a password storage scheme plug-in compare function, it passes that function an input password char * and a stored, encoded password char * from the directory. The compare function returns 0 if the input password matches the password from the directory. It returns 1 otherwise. The prototype for our example compare function, xorcmp(), is therefore:

static int xorcmp(char * userpwd, char * dbpwd);

Here, userpwd is the input password and dbpwd is the password from the directory. The compare function must encode the input password to compare the result to the password from the directory.



Code Example 11-2    Comparing a userPassword Value (testpwdstore.c) 

#include "slapi-plugin.h"

static int
xorcmp(char * userpwd, char * dbpwd)
{
/* Check the correspondence of the two char by char */
int i, len = strlen(userpwd);
for (i = 0; i < len; i++) {
if ((userpwd[i] ^ 42) != dbpwd[i])
return 1; /* Different passwords */
}
return 0; /* Identical passwords */
}


Notice Directory Server strips the prefix from the password before passing it to the compare function. In other words, we need not account for {XOR} in this case.

Not all encoding algorithms have such a trivial compare function.

Registering the Plug-In

You must register four password storage scheme specific items with Directory Server: the storage scheme name (used for the prefix), the encode function, the compare function, and the decode function.

Notice we provide no decoding function. In this case, Directory Server never decodes user passwords once they are stored.



Code Example 11-3    Registering a Password Storage Scheme Plug-In (testpwdstore.c) 

#include "slapi-plugin.h"

static char * name ="XOR"; /* Storage scheme name */

static Slapi_PluginDesc desc = {
"xor-password-storage-scheme", /* Plug-in identifier */
"Sun Microsystems, Inc.", /* Vendor name */
"5.2", /* Revision number */
"Exclusive-or example (XOR)" /* Plug-in description */
};

#ifdef _WIN32
__declspec(dllexport)
#endif
int
xor_init(Slapi_PBlock * pb)
{
int rc = 0; /* 0 means success */
rc |= slapi_pblock_set( /* Plug-in API version */
pb,
SLAPI_PLUGIN_VERSION,
(void *) SLAPI_PLUGIN_CURRENT_VERSION
);
rc |= slapi_pblock_set( /* Plug-in description */
pb,
SLAPI_PLUGIN_DESCRIPTION,
(void *) &desc
);
rc |= slapi_pblock_set( /* Storage scheme name */
pb,
SLAPI_PLUGIN_PWD_STORAGE_SCHEME_NAME,
(void *) name
);
rc |= slapi_pblock_set( /* Encode password */
pb,
SLAPI_PLUGIN_PWD_STORAGE_SCHEME_ENC_FN,
(void *) xorenc
);
rc |= slapi_pblock_set( /* Compare password */
pb,
SLAPI_PLUGIN_PWD_STORAGE_SCHEME_CMP_FN,
(void *) xorcmp
);
rc |= slapi_pblock_set( /* Never decode pwd */
pb,
SLAPI_PLUGIN_PWD_STORAGE_SCHEME_DEC_FN,
NULL
);
return rc;
}


Creating a Configuration Entry

Build the plug-in if you have not done so already.

The configuration entry for the plug-in resembles other entries under cn=config whose DN contains cn=Password Storage Schemes. Create an LDIF file similar to that of Code Example 11-4.



Code Example 11-4    Configuration Entry (testpwdstore.c) 

dn: cn=XOR,cn=Password Storage Schemes,cn=plugins,cn=config
objectclass: top
objectclass: nsSlapdPlugin
cn: XOR
nsslapd-pluginPath: <ServerRoot>/plugins/slapd/slapi/examples/<LibName>
nsslapd-pluginInitFunc: xor_init
nsslapd-pluginType: pwdstoragescheme
nsslapd-pluginEnabled: on
nsslapd-pluginId: xor-password-storage-scheme
nsslapd-pluginVersion: 5.2
nsslapd-pluginVendor: Sun Microsystems, Inc.
nsslapd-pluginDescription: Exclusive-or example (XOR)


Notice nsslapd-pluginEnabled must be set to on. Otherwise, no one can use the password storage scheme. Setting nsslapd-pluginEnabled to on does not suffice, however, for the plug-in to be used. In addition to enabling the plug-in, you must configure Directory Server to use the password storage scheme it provides.

Add the entry to the directory configuration. For example:

$ ldapmodify -a -p port -D "cn=Directory Manager" -w password -f file.ldif

Here, file.ldif contains the plug-in configuration entry.

Restart Directory Server so it loads the plug-in at startup:

$ ServerRoot/slapd-serverID/restart-slapd

At this point, the XOR password storage scheme plug-in should be enabled for Directory Server, and visible in the server configuration.

Trying It Out

This section demonstrates the example plug-in for this chapter. Plug the XOR password storage scheme into Directory Server if you have not done so already.

Perform a Quick Test

Before we do anything involved, quickly check that Directory Server manages to call the plug-in encode function as expected. To perform this quick test, we use the pwdhash tool. The pwdhash tool can be used to have Directory Server encode a password, then display the result.



Code Example 11-5    Testing the Password Storage Scheme 

$ cd ServerRoot/bin/slapd/server
$ ./pwdhash -D ServerRoot/slapd-serverID -s XOR password
{XOR}ZKYY]EXN


Do not be concerned with the exact value of the resulting encoded password. The output should, however, start with {XOR}.

As Directory Server calls the encode function dynamically, we can fix the plug-in library, then try pwdhash again without touching Directory Server. That is, if this quick test does not work for you, now is a good time to fix the example.

Add Example Users with Clear Text Passwords

In order to experiment with user passwords, we need some users with passwords. Here, we create a directory suffix, dc=example,dc=com, whose users we load from an LDIF file, ServerRoot/slapd-serverID/ldif/Example-Plugin.ldif. The example user passwords appear in clear text in Example-Plugin.ldif.

Perform the following steps to load the example into the directory.

  1. Open the Directory Server Console.
  2. Use the console to create a new root suffix, dc=example,dc=com.
  3. Hint Configuration tab page. Select Data node. Object > New Root Suffix.

  4. Set the password storage scheme to No encryption (CLEAR).
  5. Hint Use the Password encryption drop-down list.

  6. Log in as cn=Directory Manager.
  7. Hint Console > Log in as New User...

  8. Import entries from ServerRoot/slapd-serverID/ldif/Example-Plugin.ldif.
  9. Hint Console > Import Databases...

Once the Example-Plugin.ldif entries have been imported, check that the user passwords appear in clear text. The console does not show passwords in clear text, so we use ldapsearch on the command line.



Code Example 11-6    Sample User Entry 

$ ldapsearch -L -p port -D "cn=directory manager" -w password \
-b dc=example,dc=com uid=yyorgens
dn: uid=yyorgens,ou=People,dc=example,dc=com
mail: yyorgens@example.com
uid: yyorgens
secretary: uid=bcubbins,ou=People,dc=example,dc=com
givenName: Yolanda
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
sn: Yorgenson
cn: Yolanda Yorgenson
userPassword: yyorgens


Notice that Yolanda Yorgensons's password is yyorgens.

Encode a Password with the XOR Scheme

Here we use the XOR scheme to encode a new password for Yolanda Yorgenson.

  1. As Directory Manager, set the password storage scheme for the suffix to Exclusive-or example (XOR).
  2. Hint Use the Password encryption drop-down list.

  3. Change Yolanda's password to foobar12.
  4. Hint Directory tab page. Select example/People. Double-click yyorgens.

  5. View Yolanda's newly encoded password.


  6. Code Example 11-7    User Entry after Password Change 

    $ ldapsearch -L -p port -D "cn=directory manager" -w password \
    -b dc=example,dc=com uid=yyorgens
    dn: uid=yyorgens,ou=People,dc=example,dc=com
    mail: yyorgens@example.com
    uid: yyorgens
    secretary: uid=bcubbins,ou=People,dc=example,dc=com
    givenName: Yolanda
    objectClass: top
    objectClass: person
    objectClass: organizationalPerson
    objectClass: inetOrgPerson
    sn: Yorgenson
    cn: Yolanda Yorgenson
    userPassword: {XOR}ZKYY]EXN


Notice that Yolanda Yorgenson's password is XOR encoded.

Compare an XOR-Encoded Password

Yolanda has the right to search other entries under dc=example,dc=com. Here we search for Bartholomew Cubbins's entry as yyorgens.



Code Example 11-8    Binding with the New Password 

$ ldapsearch -L -p port -b dc=example,dc=com \
-D "uid=yyorgens,ou=People,dc=example,dc=com" -w foobar12 \
uid=bcubbins
dn: uid=bcubbins,ou=People,dc=example,dc=com
mail: bcubbins@example.com
uid: bcubbins
facsimileTelephoneNumber: +1 234 567 8910
givenName: Bartholomew
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
sn: Cubbins
cn: Bartholomew Cubbins
userPassword: bcubbins


We know Directory Server uses a plug-in to check Yolanda's password during the bind. In this case, Directory Server must have used the XOR plug-in, because we saw that Yolanda's password was XOR encoded. If the whole process appears to work, we can conclude that our compare function works, too.


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