Skip Headers
Oracle® Fusion Middleware Developer's Guide for Oracle Directory Server Enterprise Edition
11g Release 1 (11.1.1.7.0)

Part Number E28970-01
Go to Documentation Home
Home
Go to Table of Contents
Contents
Go to Index
Index
Go to Feedback page
Contact Us

Go to previous page
Previous
Go to next page
Next
PDF · Mobi · ePub

3 Getting Started With Directory Server Plug-Ins

This chapter provides an introduction to creating Directory Server plug-ins. This chapter also explains how to enable the server to use plug-ins and how to generate log entries.

If you maintain plug-ins developed for a previous release of Directory Server, refer to Chapter 2, "Changes to the Plug-In API Since Directory Server 5.2" for information about what has changed.

This chapter covers the following topics:

3.1 A Hello World Plug-In

This section demonstrates a plug-in that logs a famous greeting. You can follow the process outlined in this section to understand the concepts that are covered in this chapter.

3.1.1 Find the Code

On the directory host, look in the install-path/examples/ directory. The example code that is covered in this section is hello.c.

3.1.2 Review the Plug-In

The following example logs Hello, World! at Directory Server startup.

Example 3-1 Hello, World! Plug-In (hello.c)

#include "slapi-plugin.h"

Slapi_PluginDesc desc = { 
    "Hello, World",                    /* plug-in identifier      */
    "Oracle Corporation (test)",       /* vendor name             */
    "11.1.1.3.0",                      /* plug-in revision number */
    "My first plug-in"                 /* plug-in description     */
};

/* Log a greeting at server startup if info logging is on for plug-ins */
int
hello()
{
    slapi_log_info_ex(
        SLAPI_LOG_INFO_AREA_PLUGIN,    /* Log if info logging is  */
        SLAPI_LOG_INFO_LEVEL_DEFAULT,  /* set for plug-ins.       */
        SLAPI_LOG_NO_MSGID,            /* No client at startup    */
        SLAPI_LOG_NO_CONNID,           /* No conn.  at startup    */
        SLAPI_LOG_NO_OPID,             /* No op.    at startup    */
        "hello() in My first plug-in", /* Origin of this message  */
        "Hello, World!\n"              /* Informational message   */
    );
    return 0;
}

/* Register the plug-in with the server */
#ifdef _WIN32
__declspec(dllexport)
#endif
int
hello_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 *) &desc;
    );
    rc |= slapi_pblock_set(            /* Startup function        */
        pb,
        SLAPI_PLUGIN_START_FN,
        (void *) hello
    );
    return rc;
}

To log the greeting, the plug-in includes a function to be called at Directory Server startup. The plug-in also includes an initialization function to register the plug-in description, supported API version, and startup function with Directory Server.

The startup function specifies that the message is from a plug-in, SLAPI_LOG_INFO_AREA_PLUGIN. The startup function also specifies that the message should be logged when informational logging is activated, SLAPI_LOG_INFO_LEVEL_DEFAULT. For this log message, no client connection information is available, SLAPI_LOG_NO_MSGID, SLAPI_LOG_NO_CONNID, SLAPI_LOG_NO_OPID. Directory Server calls the function at startup before any clients have connected. The function specifies where the log message originates, "hello() in My first plug-in". Finally, the function provides the famous log message.

The initialization function is named hello_init(). This function modifies the parameter block, pb, with the function slapi_pblock_set(). The function thus registers the plug-in API version supported, the plug-in description, and the functions offered to Directory Server by this plug-in. As required for all plug-in initialization functions, hello_init() returns 0 on success, -1 on failure. The function slapi_pblock_set () returns 0 if successful, -1 otherwise. Therefore, you do not need to set the return code to -1 explicitly in A Hello World Plug-In.

3.1.3 Build the Plug-In

Build the plug-in as a shared object, libtest-plugin.so or libtest-plugin.sl, or dynamic link library, testplugin.dll, depending on your platform. On Solaris SPARC systems, you do the following.

$ gmake -f Makefile

On Solaris x64 systems where you boot a 64-bit kernel, you do the following.

$ gmake -f Makefile64

Use the Makefile or Makefile64 in install-path/examples/ to compile and to link the code. This file builds and links all plug-in examples into the same library. Refer to Searching Plug-In Libraries for details when building a plug-in for use with a 64-bit Directory Server instance.

3.1.4 Plug In the Plug-In

Use the dsconf command to add information about the plug-in to the server configuration.

3.1.4.1 Updating Directory Server Configuration

Configure the server to log plug-in messages:

$ dsconf set-log-prop -h localhost -p 1389 error level:err-plugins

Configure the server to load the plug-in:

$ dsconf create-plugin -h localhost -p 1389 \
 -H lib-path -F hello_init -Y object "Hello World"
$ dsconf set-plugin-prop "Hello World" feature:"Hello, World" version:11.1.1.3.0 
 vendor:"Oracle Corporation (test)" desc:"My first plug-in"
$ dsconf enable-plugin -h localhost -p 1389 "Hello World"
Directory Server needs to be restarted for changes to take effect

Here, lib-path must correspond to the absolute path to the plug-in library, such as /local/myplugins/examples/libtest-plugin.so. Directory Server requires an absolute path, not a relative path. Before setting lib-path on a 64-bit system, read Searching Plug-In Libraries.

Note:

Plug-ins delivered with Directory Server have signatures, which are stored as ds-pluginSignature attribute values. Plug-ins also have digests, which are stored as ds-pluginDigest attribute values. The values allow you to differentiate plug-ins that are delivered with Directory Server from custom plug-ins.

3.1.4.2 Restarting Directory Server

After changing the Directory Server configuration, you must restart Directory Server for the server to register the plug-in. Use the dsadm command.

For example, to restart a server instance in /local/ds/, type the following:

$ dsadm restart /local/ds
Waiting for server to stop...
Server stopped
Server started: pid=4362

3.1.4.3 Checking the Log

After Directory Server has started, search the error log, instance-path/logs/errors, for Hello, World! You should find an entry similar to the following line, which is wrapped for the printed page:

[02/Jan/2006:16:56:07 +0100] - INFORMATION - 
 hello() in My first plug-in - conn=-1 op=-1 msgId=-1 -  Hello, World!

At this point, reset the log level to the default to avoid logging unnecessary messages:

$ dsconf set-log-prop -h localhost -p 1389 error level:default

3.2 Writing Directory Server Plug-Ins

This section focuses on the basics of coding a Directory Server plug-in. This section covers the key tasks. These tasks include specifying the header file, writing an initialization function, setting parameter block values, and registering plug-in functions.

3.2.1 Include the slapi-plugin.h Header File

The plug-in API is defined in install-path/include/slapi-plugin.h. Observe that the header file includes ldap.h, the entry point for the standard and extended LDAP C APIs, and ldap_msg.h, the list of error message identifiers used by Directory Server.

In general, interfaces that Directory Server exposes are specified in install-path/include/. For details about specific features of the API, refer to Plug-In API Reference.

To use the API, include slapi-plugin.h in the declaration section of your plug-in source:

#include "slapi-plugin.h"

As a rule, use appropriate macros in your Makefile or project file to tell the linker to look for header files in install-path/include/.

3.2.2 Write Your Plug-In Functions

Directory Server calls plug-in functions in the context of a Directory Server operation, for example when a bind, add, search, modify, or delete is performed. Do not export these functions. The functions become available in the appropriate scope when registered with Directory Server at startup. This guide covers how to write such functions.

A plug-in function prototype looks like the prototype of any other locally used function. Many plug-in functions are passed a parameter block.

int prebind_auth(Slapi_PBlock * pb); /* External authentication. */

You can also use additional helper functions that are not registered with Directory Server. This guide does not cover additional helper functions, but some of the sample plug-ins delivered with the product include such functions.

3.2.3 Use Appropriate Return Codes

In general, return 0 from your plug-in functions when they complete successfully. For some functions that search for matches, 0 means a successful match, and -1 means that no match is found. For preoperation functions, 0 means that Directory Server should continue processing the operation. When you want the server to stop processing the operation after your preoperation function completes, return a positive value such as 1.

When plug-in functions do not complete successfully, send a result to the client if appropriate, log an error message, and return a non-zero value, such as the LDAP result code from install-path/include/ldap-standard.h, for example.

3.2.4 Write an Initialization Function

All plug-ins must include an initialization function. The initialization function registers the plug-in version compatibility, the plug-in description, the plug-in functions, and any other data required by the plug-in. The initialization function takes a pointer to a Slapi_PBlock structure as a parameter. Refer to A Hello World Plug-In.

The initialization function returns 0 if everything registers successfully. The initialization function returns -1 if registration fails for any configuration information or function. A return code of -1 from a plug-in initialization function prevents the server from starting.

Directory Server can call the initialization function more than once during startup.

3.2.5 Set Configuration Information Through the Parameter Block

Directory Server passes a parameter block pointer to the plug-in initialization function. This parameter block holds configuration information. The parameter block can hold other data from Directory Server. The parameter block is the structure into which you add configuration information and pointers to plug-in functions using calls to slapi_pblock_set().

Tip:

To read parameter values, use slapi_pblock_get(). To write parameter values, use slapi_pblock_set(). Using other functions can cause the server to crash.

3.2.5.1 Specifying Compatibility

You specify compatibility with the plug-in API version as defined in slapi-plugin.h, which is described in Plug-In API Reference. If you are creating a new plug-in, for example, use SLAPI_PLUGIN_CURRENT_VERSION or SLAPI_PLUGIN_VERSION_03. For example, to specify that a plug-in supports the current version, version 3, of the plug-in API, use the following:

slapi_pblock_set(pb,SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_03);

Here, pb is the parameter block pointer passed to the initialization function. SLAPI_PLUGIN_VERSION signifies that you are setting plug-in API version compatibility in the parameter block.

3.2.5.2 Specifying the Plug-In Description

Specify the plug-in description in a Slapi_PluginDesc structure, as specified in slapi-plugin.h and described in Plug-In API Reference. Call slapi_pblock_set() to register the description:

slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION,(void *) &desc);

Here, desc is a Slapi_PluginDesc structure that contains the plug-in description. See A Hello World Plug-In.

3.2.6 Set Pointers to Functions Through the Parameter Block

Register plug-in functions according to what operation Directory Server performs. Also register plug-in functions according to when the operation is performed. Directory Server typically calls plug-in functions before, during, or after a standard operation.

Macros that specify when Directory Server should call plug-ins have the form SLAPI_PLUGIN_*_FN. As the sample plug-ins demonstrate, the macro used to register a plug-in function depends entirely on what the function is supposed to do. For example, to register a plug-in function foo() to be called at Directory Server startup, do the following:

slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN, (void *) foo);

Here, pb is the parameter block pointer passed to the initialization function. SLAPI_PLUGIN_START_FN signifies that Directory Server calls foo() at startup. Note that foo() returns 0 on success.

3.2.7 Locate Examples

Sample plug-ins are located in install-path/examples/.

3.3 Building Directory Server Plug-Ins

This section explains how to build plug-in binaries. This section deals with compilation requirements and with linking requirements for Directory Server plug-ins.

3.3.1 Include the Header File for the Plug-In API

The compiler needs to be able to locate the header files such as slapi-plugin.h. Find header files in install-path/include/.

3.3.2 Link the Plug-In as a Shared Object or Dynamic Link Library

Link plug-ins so the plug-in library is reentrant and portable and can be shared. The following example shows one way of building a plug-in library. The example works with the compiler that is used with a 64-bit Directory Server running on Solaris platforms.

Example 3-2 64-bit: Makefile for a Solaris Sample Plug-In Library

INCLUDE_FLAGS = -I../include
CFLAGS = $(INCLUDE_FLAGS) -D_REENTRANT -KPIC -xarch=v9 -DUSE_64
LDFLAGS = -G
DIR64 = 64

OBJS = dns.o entries.o hello.o internal.o testpwdstore.o \
 testsaslbind.o testextendedop.o testpreop.o testpostop.o \
 testentry.o testbind.o testgetip.o

all: MKDIR64 $(DIR64)/libtest-plugin.so

MKDIR64:
    @if [ ! -d $(DIR64) ]; then mkdir $(DIR64); fi

$(DIR64)/libtest-plugin.so: $(OBJS)
    $(LD) $(LDFLAGS) -o $@ $(OBJS)

.c.o:
    $(CC) $(CFLAGS) -c $<

clean:
    -rm -f $(OBJS) libtest-plugin.so $(DIR64)/libtest-plugin.so

The CFLAGS -xarch=v9 and -DUSE_64 specify that the compiler builds the library for use with a 64-bit server. Notice also that the 64-bit library is placed in a directory that is named 64/. This extra directory is required for 64-bit plug-ins. A 64-bit server adds the name of the extra directory to the path name when searching for the library. Refer to Searching Plug-In Libraries for further information.

The following example shows a 32-bit equivalent of the Makefile.

Example 3-3 32-bit: Makefile for a Solaris Sample Plug-In Library

INCLUDE_FLAGS = -I../include
CFLAGS = $(INCLUDE_FLAGS) -D_REENTRANT -KPIC
LDFLAGS = -G

OBJS = dns.o entries.o hello.o internal.o testpwdstore.o \
 testsaslbind.o testextendedop.o testpreop.o testpostop.o \
 testentry.o testbind.o testgetip.o

all: libtest-plugin.so

libtest-plugin.so: $(OBJS)
    $(LD) $(LDFLAGS) -o $@ $(OBJS)

.c.o:
    $(CC) $(CFLAGS) -c $<

clean:
    -rm -f $(OBJS) libtest-plugin.so

Notice that both 32-bit versions and 64-bit versions of the plug-in library can coexist on the same host.

3.3.3 Locate the Example Build Rules

Build rules are in install-path/examples/. The rules are also in install-path/examples/Makefile64. Refer to these files for the recommended setup for compiling and linking on your platform.

3.4 Plugging Libraries Into Directory Server

This section covers server plug-in configuration. This section also explains how plug-ins are loaded. When plug-ins are properly loaded, Directory Server can initialize and register the plug-ins correctly. Dependencies between Directory Server plug-ins are also discussed.

3.4.1 Specify Plug-In Configuration Settings

Plug-in configuration settings specify information that Directory Server requires. The server uses the information to load a plug-in at startup, to identify the plug-in, and to pass parameters to the plug-in at load time.

You access configuration settings through the dsconf command, using the subcommands create-plugin, set-plugin-prop, and enable-plugin.

The dsconf create-plugin command forces you to set required plug-in configuration settings. The settings include the name, plug-in initialization function, path to the library that contains the plug-in, and plug-in type.

The dsconf set-plugin-prop command allows you to set optional configuration settings.

The dsconf enable-plugin command allows you to turn the plug-in on or off. When you change this setting, you must restart the server.

The following table identifies the configuration settings and indicates whether the settings are required, set with dsconf create-plugin, or optional, set with dsconf set-plugin-prop.

Table 3-1 Plug-In Configuration Settings

Setting Description Required or Optional

Plug-in name

Common name for the plug-in, corresponding to the name registered by the plug-in

Required

Initialization function (-F)

Name of the initialization function that is called during Directory Server startup as the name appears in the plug-in code

Required

Library path (-H)

Full path to the library that contains the plug-in, not including 64-bit directory for 64-bit plug-in libraries

Refer to Searching Plug-In Libraries for details.

Required

Plug-in type (-Y)

Plug-in type that defines the types of functions the plug-in implements

Refer to Understanding Plug-In Types and Dependencies for details.

Required

argument

A parameter passed to the plug-in at Directory Server startup such as suffix=dc=example,dc=com

Refer to Retrieving Arguments Passed to Plug-Ins

.

Optional

depends-on-named

One or more plug-in dependencies on plug-in names (RDN) such as State Change Plugin or Multimaster Replication Plugin

Refer to Understanding Plug-In Types and Dependencies for details.

Optional

depends-on-type

One or more plug-in dependencies on plug-in types such as preoperation or database

Refer to Understanding Plug-In Types and Dependencies for details.

Optional

desc

One-line description as specified in the spd_description field of the plug-in Slapi_PluginDesc structure

Optional

feature

Identifier as specified in the spd_id field of the plug-in Slapi_PluginDesc structure

Optional

vendor

Vendor name as specified in the spd_vendor field of the plug-in Slapi_PluginDesc structure

Optional

version

Version number as specified in the spd_version field of the plug-in Slapi_PluginDesc structure

Optional


3.4.1.1 Understanding Plug-In Types and Dependencies

The plug-in type tells Directory Server which type of plug-in functions can be registered by a plug-in. A plug-in type corresponds to the principal type of operation that the plug-in performs. Refer to How Plug-Ins Interact With the Server and Example Uses for explanations of plug-in types. Plug-In API Reference describes plug-in types and lists type property settings that correspond to the type identifiers specified in slapi-plugin.h.

Determining the plug-in type is clear-cut when you know what the plug-in must do. For example, if you write a plug-in to handle authentication of a request before Directory Server processes the bind for that request, the type is preoperation. In other words, the plug-in does something to the request prior to the bind operation. Such a plug-in therefore registers at least a pre-bind plug-in function to process the request prior to the bind. If, on the other hand, you write a plug-in to encode passwords, and also compare incoming passwords with encoded passwords, the type is pwdstoragescheme. Such a plug-in registers at least password encoding, and also compares functions. In both cases, plug-in type follows plug-in function.

Plug-in dependencies tell Directory Server that a plug-in requires one or more other plug-ins in order to function properly. Directory Server resolves dependencies as the server loads the plug-ins. Therefore, Directory Server fails to register a plug-in if a plug-in that the plug-in depends on cannot be registered.

Specify plug-in dependencies by name, using depends-on-named, or by type, using depends-on-type. Here, plug-in name refers to the plug-in relative distinguished name (RDN) from the configuration entry. Plug-in type is a type identifier from the list of types in Chapter 17, "Parameter Block Reference". Both depends-on-named and nsslapddepends-on-type can take multiple values.

A plug-in configuration entry can specify either kind or both kinds of dependencies. Use the configuration entry to identify dependencies on specific plug-ins by name. Identify dependencies on a type of plug-in by type. If a dependency identifies a plug-in by name, Directory Server only registers the plug-in after the server registers the named plug-in. If a dependency identifies a plug-in by type, Directory Server only registers the plug-in after the server registers all plug-ins of the specified type.

Do not confuse plug-in registration dependencies with a mechanism to specify the order in which Directory Server calls plug-ins.

3.4.1.2 Ordering Plug-In Calls

Directory Server allows you to define the order in which plug-ins are called. This mechanism is independent of the mechanism that defines plug-in load dependencies.

This mechanism uses a set of attributes on the entry with DN cn=plugins,cn=monitor. Plug-in call ordering is defined for each type of plug-in on attributes whose values are comma-separated lists of plug-in names. Each attribute type name starts with plugin-list- and identifies a point in the server request processing where plug-ins can be called. In the comma-separated list of plug-ins, the first plug-in in the list is called first, the second is called second, and so forth.

For example, six postoperation plug-ins are called after a modify operation. The plugin-list-postoperation-modify attribute on cn=plugins,cn=monitor shows the order in which these six plug-ins are called by the server.

plugin-list-postoperation-modify:
 Class of Service,
 Legacy replication postoperation plugin,
 Multimaster replication postoperation plugin,
 Retrocl postoperation plugin,
 Roles Plugin,
 State Change Plugin

You can also retrieve these attributes by performing a search on the entry with DN cn=plugins,cn=monitor.

To change the order in which plug-ins are called, you must not modify the value of the attribute type starting with plugin-list-. Instead, you must modify the value of a corresponding attribute type starting with plugin-order-, and having the same ending as the plugin-list- attribute. Also you must store the attribute type starting with plugin-order- in the entry with DN cn=plugins,cn=config.

The full list of plug-in call ordering attribute types is as follows:

  • plugin-order-bepostoperation-add

  • plugin-order-bepostoperation-delete

  • plugin-order-bepostoperation-modify

  • plugin-order-bepostoperation-modrdn

  • plugin-order-beprecommit-add

  • plugin-order-beprecommit-delete

  • plugin-order-beprecommit-modify

  • plugin-order-beprecommit-modrdn

  • plugin-order-bepreoperation-add

  • plugin-order-bepreoperation-delete

  • plugin-order-bepreoperation-modify

  • plugin-order-bepreoperation-modrdn

  • plugin-order-internalpostoperation-add

  • plugin-order-internalpostoperation-delete

  • plugin-order-internalpostoperation-modify

  • plugin-order-internalpostoperation-modrdn

  • plugin-order-internalpreoperation-add

  • plugin-order-internalpreoperation-delete

  • plugin-order-internalpreoperation-modify

  • plugin-order-internalpreoperation-modrdn

  • plugin-order-postoperation-abandon

  • plugin-order-postoperation-add

  • plugin-order-postoperation-bind

  • plugin-order-postoperation-compare

  • plugin-order-postoperation-delete

  • plugin-order-postoperation-entry

  • plugin-order-postoperation-modify

  • plugin-order-postoperation-modrdn

  • plugin-order-postoperation-referral

  • plugin-order-postoperation-result

  • plugin-order-postoperation-search

  • plugin-order-postoperation-unbind

  • plugin-order-preoperation-abandon

  • plugin-order-preoperation-add

  • plugin-order-preoperation-attr-encode-result

  • plugin-order-preoperation-bind

  • plugin-order-preoperation-compare

  • plugin-order-preoperation-delete

  • plugin-order-preoperation-entry

  • plugin-order-preoperation-finish-entry-encode-result

  • plugin-order-preoperation-modify

  • plugin-order-preoperation-modrdn

  • plugin-order-preoperation-referral

  • plugin-order-preoperation-result

  • plugin-order-preoperation-search

  • plugin-order-preoperation-unbind

  • plugin-order-pwdpolicy-bind-fail

  • plugin-order-pwdpolicy-bind-success

For example, if you want to change the order in which postoperation plug-ins are called after a modify, first read plugin-list-postoperation-modify. Next set plugin-order-postoperation-modify, copying plug-in names from the value of plugin-list-postoperation-modify. Then restart Directory Server. Plug-in names are not case—sensitive, but white spaces are taken into account. Unrecognized names are ignored.

With a single asterisk, *, as an item in the comma-separated list, you let Directory Server define the call order for plug-ins you do not identify explicitly.

If you have two postoperation modify plug-ins, the first, Call Me First, and the second, Call Me Last, you could set plugin-list-postoperation-modify as follows:

plugin-order-postoperation-modify: Call Me First,*,Call Me Last

The plug-in name that you specify must be identical to the name argument that is passed to the slapi_register_plugin function. There must also be no white space between the comma delimiter and the adjacent plug-in names, and no white space at the end of the names list.

Plug-ins can remain that you do not explicitly identify by name or implicitly identify using *. Directory Server calls such plug-ins before calling the plug-ins that you listed.

3.4.1.3 Retrieving Arguments Passed to Plug-Ins

Your plug-in can retrieve parameters specified in the configuration settings property argument, which is multivalued. Directory Server makes the argument available to the plug-in through the parameter block passed to the plug-in initialization function.

If you include parameters in the configuration settings, the following apply:

  • SLAPI_PLUGIN_ARGC specifies the number of parameters

  • SLAPI_PLUGIN_ARGV contains the parameters

The following example uses slapi_pblock_get() to retrieve the arguments from install-path/examples/testextendedop.c.

Example 3-4 Plug-In Using Arguments (testextendedop.c)

#include "slapi-plugin.h"

Slapi_PluginDesc expdesc = {
    "test-extendedop",                 /* plug-in identifier       */
    "Oracle Corporation (test)",       /* vendor name              */
    "11.1.1.3.0",                      /* plug-in revision number  */
    "Sample extended operation plug-in"/* plug-in description      */
};

/* Register the plug-in with the server.                           */
#ifdef _WIN32
__declspec(dllexport)
#endif
int
testexop_init(Slapi_PBlock * pb)
{
    char ** argv;                      /* Args from configuration  */
    int     argc;                      /* entry for plug-in.       */
    char ** oid_list;                  /* OIDs supported           */
    int     rc = 0;                    /* 0 means success          */
    int     i;

    /* Get the arguments from the configuration entry.             */
    rc |= slapi_pblock_get(pb, SLAPI_PLUGIN_ARGV, &argv);
    rc |= slapi_pblock_get(pb, SLAPI_PLUGIN_ARGC, &argc);
    if (rc != 0) {
        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,
            "testexop_init in test-extendedop plug-in",
            "Could not get plug-in arguments.\n"
        );
        return (rc);
    }

    /* Extended operation plug-ins may handle a range of OIDs. */
    oid_list = (char **)slapi_ch_malloc((argc + 1) * sizeof(char *));
    for (i = 0; i < argc; ++i) {
        oid_list[i] = slapi_ch_strdup(argv[i]);
        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,
            "testexop_init in test-extendedop plug-in",
            "Registering plug-in for extended operation %s.\n",
            oid_list[i]
        );
    }
    oid_list[argc] = NULL;
    
    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 *) &expdesc
    );
    rc |= slapi_pblock_set(            /* Extended op. handler     */
        pb,
        SLAPI_PLUGIN_EXT_OP_FN,
        (void *) test_extendedop
    );
    rc |= slapi_pblock_set(            /* List of OIDs handled     */
        pb,
        SLAPI_PLUGIN_EXT_OP_OIDLIST,
        oid_list
    );
    return (rc);
}

You can specify multiple arguments by using multiple properties in the command line. The dsconf command causes the server to provide the arguments to the plug-in in the order you specify on the command line. When you change the list of arguments by using the dsconf command, the new arguments replace the existing arguments. The arguments are not appended to the list.

3.4.1.4 Searching Plug-In Libraries

Directory Server searches for plug-in libraries with the library path that you specify with the -H option to the dsconf create-plugin command.

  • 64-bit servers search for 64-bit libraries by adding a directory name to the end of the path name.

    For example, if you specify -H /local/myplugins/mylib.so, a 64-bit Directory Server running on Solaris platforms searches for a 64-bit plug-in library that is named as follows:

    /local/myplugins/64/mylib.so
    
  • A 32-bit Directory Server searches for 32-bit plug-in libraries with the exact path specified. A 32-bit Directory Server using the same configuration entry would search for the plug-in library named:

    /local/myplugins/mylib.so
    

Directory Server fails to start when the server cannot find a plug-in library specified in the configuration entry.

3.4.2 Modify the Directory Server Configuration

With Directory Server running, add your plug-in configuration settings with the dsconf command. Enable the plug-in with the dsconf enable-plugin name command.

If everything works as expected, Directory Server adds a plug-in configuration entry to the Directory Server configuration, which is stored in instance-path/config/dse.ldif. Do not modify the configuration file directly.

3.4.3 Restart Directory Server

Directory Server does not load plug-ins dynamically. Instead, you must restart the server. Directory Server then registers your plug-in at startup.

Set logging so Directory Server logs plug-in informational messages with the dsconf set-log-prop error level:err-plugins command. After setting the log level appropriately, restart the server to ensure that it loads the new plug-ins that you configured:

$ dsadm restart instance-path

You can adjust log levels while the server is running.

3.5 Logging Plug-In Messages

This sectioon shows how to do the following:

3.5.1 Log Three Levels of Message Severity

The plug-in API provides log functions for logging fatal error messages, warnings, and information. Error messages and warnings are always logged. Informational logging is turned off by default. You can adjust log levels while Directory Server is running.

Tip:

Directory Server, as Directory Server waits for the system to write every log message to disk, slowing the server down.

Use logging when you need logging. Turn logging off when you do not need to use it.

Refer to Chapter 15, "Directory ServerFunction Reference, Part I" for details about each of the logging functions.

3.5.1.1 Fatal Error Messages

For fatal errors, use slapi_log_error_ex(). In many cases, you might return -1 after you log the message to indicate to Directory Server that a serious problem has occurred.

Example 3-5 Logging a Fatal Error Message

#include "slapi-plugin.h"
#include "example-com-error-ids.h" /* example.com unique
                                      error IDs file       */
int
foobar(Slapi_PBlock * pb)
{
    char * error_cause;
    int    apocalypse = 1;         /* Expect the worst.    */

    /* ... */

    if (apocalypse) {              /* Server to crash soon */
        slapi_log_error_ex(
            EXCOM_SERVER_MORIBUND, /* Unique error ID      */
            SLAPI_LOG_NO_MSGID,
            SLAPI_LOG_NO_CONNID,
            SLAPI_LOG_NO_OPID,
            "example.com: foobar in baz plug-in",
            "cannot write to file system: %s\n",
            error_cause
        );
        return -1;
    }
    return 0;
}

In this example, foobar() logs an error as Directory Server is about to crash.

Tip:

If the plug-ins are internationalized, use macros, not literal strings, for the last two arguments to slapi_log_*_ex() functions.

3.5.1.2 Warning Messages

For serious situations that require attention and in which messages should always be logged, use slapi_log_warning_ex().

In the following example, foobar() logs a warning because the disk is nearly full.

Example 3-6 Logging a Warning Message

#include "slapi-plugin.h"
#include "example-com-warning-ids.h" /* example.com unique
                                        warning IDs file  */
int
foobar()
{
    int disk_use_percentage;

    /* ... */

    if (disk_use_percentage>= 95) {
        slapi_log_warning_ex(
            EXCOM_DISK_FULL_WARN,    /* unique warning ID */
            SLAPI_LOG_NO_MSGID,
            SLAPI_LOG_NO_CONNID,
            SLAPI_LOG_NO_OPID,
            "example.com: foobar in baz plug-in",
            "disk %.0f%% full, find more space\n",
            disk_use_percentage
        );
    }
    return 0;
}

3.5.1.3 Informational Messages

For informational or debug messages, use slapi_log_info_ex(). This function can be set for default logging, which means that the message is not logged when logging is turned off for plug-ins. Informational logging can also be set to occur only when heavy logging is used. Thus, the message is logged when plug-in logging is both turned on and set to log all informational messages.

Refer to Review the Plug-In for an example of how to log an informational message from a plug-in.

3.5.2 Set the Appropriate Log Level in the Directory Server Configuration

Log levels can be set for plug-in informational messages, as well as for a number of other Directory Server subsystems. You can set the log level through Directory Service Control Center. You can also set the log level from the command line by using the dsconf set-log-prop command.

When you set dsconf set-log-prop error level:err-plugins, the server turns on plug-in informational logging.

3.5.3 Find Messages in the Log

The log file for errors, warnings, and informational messages is instance-path/logs/errors. All messages go to the same log so you can easily determine the order in which events occurred.

As shown in this example, messages consist of a timestamp, followed by an identifier, followed by the other information in the log message. Note that this log message is broken for the printed page.

[02/Jan/2006:16:54:57 +0100] - INFORMATION - 
 start_tls - conn=-1 op=-1 msgId=-1 - 
 Start TLS extended operation request confirmed.

Use the identifiers to filter what you do not need.