Netscape Directory Server 6.2 User Manual

Page 1
Plug-In Programmer’s Guide
Netscape Directory Server
Version 6.2
December 2003
Page 2
Netscape Communications Corporation ("Netscape") and its licensors retain all ownership rig hts to the software prog rams offered by Netscape (referred to herein as "Software") and related documentation. Use of the Software and related documentation is governed by the license agreement for the Software and applicable copyright law.
THIS DOCUMENTATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN NO EVENT SHALL NETSCAPE BE LIABLE FOR INDIRECT, SPECIAL, INCIDENTAL , OR CON SEQ UENTIAL DAMAGES OF ANY KIND ARISING FRO M ANY ERRO R IN THI S DOCUMENTATION, INCLUDING WITHOUT LIMITATION ANY LOSS OR INTERRUPTION OF BUSINESS, PROFITS, USE, OR DATA.
The downloading, exporting, or reexporting of Netscape software or any underlying information or technology must be in full compliance with all United States and other applicable laws and regulations. Any provision of Netscape sof tware or documentatio n to the U.S. government is with restricted rights as described in the license agreement for that Software.
Netscape and the Netscape N logo are registered trademarks of Netscape Communications Corporation in the United States and other countries. Other Netscape logos, product names, and service names are also trademarks of Netscape Communications Corporation, which may be registe red in some countries. Other product and brand names are the exclusive property of their respective owners.
The Software and documentation are copyright © 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002, 2003 Netscape Communications Corporation. All rights reserved.
================================================================================================================================
Portions of the Software copyright © 1995 PEER Networks, Inc. All rights reserved.
================================================================================================================================
The Software contains the Taligent International Classes from Taligent, Inc. and IBM Corp.
================================================================================================================================
Portions of the Software copyright ©1992-1998 Regents of the University of Michigan. All rights reserved.
================================================================================================================================
The Software contains encryption software from RSA Security Inc. Copyright © 1994 RSA Data Security, Inc. All rights reserved. This product contains software derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm.
================================================================================================================================
This product incorporates International Components for Unicode (ICU) libraries, ICU is an open source development project sponsored, s uppor ted, and used by IBM.
================================================================================================================================
The source code to the Standard Version of Perl can be obtained from CPAN sites, including http://www.perl.com/.
================================================================================================================================
This product incorporates compression code by the Info-ZIP group. There are no extra charges or costs due to the use of this code, and the original compression sources are freely available from http://www.infozip.com/ on the Internet.
================================================================================================================================
This product includes software developed by the Apache Software Foundation (http://www.apache.org/).
================================================================================================================================
Portions of the Software copyright © 1989 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms of such U.C. Regents software, with or without modification, are permitted provided that the
following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. All advertising materials mentioning features or use of this software must display the following acknowledgment: This product includes software developed by the University of California, Berkeley and its contributors.
4. Neither the name of the University nor the names of its contributors may be used to endorse or pro mote pro ducts derived fro m this soft ware without specific prior written permission.
THIS SOFTWARE IS PR OVID ED BY THE RE GENTS A ND CON TRIBU TORS "A S IS" AND A NY EXPRE SS OR IMPL IED WA RRANTIES , I NCLUDIN G, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONS EQ UENT IAL D AMA GES ( INC LUD ING, BUT NOT LIMI TED TO, PROC UREMEN T OF S UBSTI TUTE GO ODS OR S ERVI CES; LOSS OF USE, DATA, OR PROFIT S; OR BU SINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================================================================================================
Portions of the Software copyright (C) 1987, 1988 Student Information Processing Board of the Massachusetts Institute of Technology. Permission to use, copy, modify, and distribute such M.I.T. software and its documentation f or any purpose and without fee is hereby granted, provided
that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the names of M.I.T. and the M.I.T. S.I.P.B. not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. M.I.T. and the M.I.T. S.I.P.B. make no representations about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty.
Page 3
Contents
Preface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
What You Should Already Know . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
Using Directory Server Plug-In APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
Document Conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
Where to Find Directory Server Information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
Part 1 Introduction to Directory Server Plug-Ins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
Chapter 1 An Overview of Directory Server Plug-Ins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
What Are Directory Server Plug-Ins? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
How Directory Server Plug-Ins Work . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
Calling Directory Server Plug-In Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
The Directory Server Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
Types of Directory Server Plug-Ins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
Chapter 2 Writing and Compiling Plug-Ins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
Writing a Plug-In Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
Including the API Header File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
Passing Data with Parameter Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
Working with Parameter Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
Getting Data from the Parameter Block . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
Setting Data in the Parameter Block . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
Calling Front-End Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
Plug-in Return Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
Writing Plug-in Initialization Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
Initialization Functions for Windows Platforms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
Specifying Directory Server Compatibility . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
Specifying Information About the Plug-In . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
3
Page 4
Registering Your Plug-In Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
Returning a Value to the Directory Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
Example of an Initialization Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
Compiling a Directory Server Plug-In . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
Chapter 3 Configuring Plug-Ins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
Creating a Plug-In Configuration File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
Plug-In Dependencies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
Specific Plug-in Dependencies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
Plug-In Type Dependencies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Specifying the Order of Plug-In Directives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Summary of Plug-In Directives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Loading the Plug-In Configuration File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
Passing Extra Arguments to Plug-Ins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
Setting the Log Level of the Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
Chapter 4 A Quick Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
An Example Pre-Operation Plug-In . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
Writing the Plug-In Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
Compiling the Plug-In Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
Registering the Plug-In Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
Running the Plug-In Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
Part 2 Basic Plug-In Programming Techniques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
Chapter 5 Front-End API Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
Logging Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
Adding Notes to Access Log Entries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
Sending Data to the Client . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
Determining if an Operation Was Abandoned . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
Working with Entries, Attributes, and Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
Creating a New Entry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
Converting Between Entries and Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
Getting and Setting the DN of an Entry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
Verifying Compliance with the Schema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
Getting the Attributes and Values of an Entry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
Iterating Through the Attributes in an Entry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
Finding a Specific Attribute in an Entry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
Adding and Removing Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
Working with DNs and RDNs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
Determining if a DN is the Root DN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
4 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 5
Working with DN Suffixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
Server Suffixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
Getting the Parent DN of a DN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
Normalizing a DN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
Working with Search Filters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
Determining if an Entry Matches a Filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
Getting the Filter Type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
Getting the Search Criteria . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
Converting a String to a Filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
Creating Complex Filters by Combining Filters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
Checking Passwords . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
Chapter 6 Writing Pre/Post-Operation Plug-Ins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
How Pre/Post-Operation Plug-Ins Work . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
Types Pre-Operation and Post-Operation Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
Types of Pre-Operation Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
Types of Post-Operation Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
Registering Pre/Post-Operation Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
Chapter 7 Defining Functions for LDAP Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
Specifying Start and Close Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
Processing an LDAP Bind Operation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
Defining Functions for the Bind Operation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
Getting and Setting Parameters for the Bind Operation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
Processing an LDAP Unbind Operation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
Processing an LDAP Search Operation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
Getting the List of Candidates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
Iterating Through Candidates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
Processing an LDAP Compare Operation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
Processing an LDAP Add Operation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
Processing an LDAP Modify Operation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
Processing an LDAP Modify RDN Operation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
Processing an LDAP Delete Operation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
Processing an LDAP Abandon Operation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
Chapter 8 Defining Functions for Authentication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
Understanding Authentication Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
How the Directory Server Identifies Clients . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
How the Authentication Process Works . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
Writing Your Own Authentication Plug-in . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
Writing a Pre-Operation Bind Plug-in . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
Defining Your Authentication Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
5
Page 6
Getting and Checking the Bind Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
Getting the Entry and Checking the Credentials . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
What to Do If Authentication Fails . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
What to Do If Authentication Succeeds . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
Registering the SASL Mechanism . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
Example of a Pre-Operation Bind Plug-In . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
Example of a Pre-Operation Bind Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
Example of an Initialization Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
Registering the Plug-In . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
Using SASL with an LDAP Client . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
Part 3 Advanced Programming Techniques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
Chapter 9 Writing Entry Store/Fetch Plug-Ins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
How Entry Store/Fetch Plug-Ins Work . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
Writing Entry Store/Fetch Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
Registering Entry Store/Fetch Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
Chapter 10 Writing Extended Operation Plug-Ins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
How Extended Operation Plug-Ins Work . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
Writing Extended Operation Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
Registering Extended Operation Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
Specifying Start and Close Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
Chapter 11 Writing Matching Rule Plug-Ins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
Understanding Matching Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
Extensible Match Filters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
Extensible Match Filters in the Directory Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
Understanding Matching Rule Plug-Ins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
Functions Defined in Matching Rule Plug-Ins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
How Matching Rules Are Identified . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
How the Server Associates Plug-Ins with OIDs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
Finding a Plug-In for Indexing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
Finding a Plug-In for Searching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
How the Server Uses Parameter Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
Indexing Based on Matching Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
How the Server Sets Up the Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
How the Server Updates the Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
Writing the Indexer Factory Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
Getting and Setting Parameters in Indexer Factory Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
Writing the Indexer Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
6 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 7
Getting and Setting Parameters in Indexer Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
Handling Extensible Match Filters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
How the Server Handles the Filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
Query Operators in Matching Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
Writing a Filter Factory Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
Getting and Setting Parameters in Filter Factory Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
Writing a Filter Index Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
Getting and Setting Parameters in Filter Index Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
Writing a Filter Matching Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
Handling Sorting by Matching Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
Writing a Destructor Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
Writing an Initialization Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
Registering Matching Rule Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
Specifying Start and Close Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146
Chapter 12 Using the Custom Distribution Logic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
About Distributing Flat Namespaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
Creating a Distribution Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
Adding the Distribution Function to Your Directory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150
Adding Multiple Databases to a Single Suffix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
Using the Console . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
From the Command-Line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
Adding Distribution Logic to a Suffix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152
Using the Console . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152
From the Command-Line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152
Using the Distribution Logic Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
Custom Distribution Checklist . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
Chapter 13 Using Data Interoperability Plug-Ins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
Installing Directory Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
Understanding Deployment Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
Installing Two Instances of Directory Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
Enabling the DIOP Feature in Directory Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161
Using the DIOP Feature . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
Sample DIOP Plug-In . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164
Debugging the Plug-In . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
Plug-In API Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
Preserving the Default Behavior of the Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
Bypassing Access Control Checks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
7
Page 8
Part 4 Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169
Chapter 14 Data Type and Structure Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
Summary of Data Types and Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
Chapter 15 Function Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
Distribution Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216
Functions for Access Control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218
Functions for Internal Operations and Plug-In Callback . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224
Functions for Setting Internal Operation Flags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232
Functions for Handling Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243
Functions for Managing Backend Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262
Functions for Dealing with Controls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281
Functions for Syntax Plug-In . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288
Functions for Managing Memory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291
Functions for Managing DNs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 298
Functions for Managing Entries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307
Functions Related to Entry Flags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 345
Functions for Dealing with Filters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 348
Functions Specific to Extended Operation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 367
Functions Specific to Bind Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 368
Functions for Thread-Safe LDAP Connections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 369
Functions for Logging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 372
Functions for Handling Matching Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 375
Functions for LDAPMod Manipulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 383
Functions for Monitoring Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 419
Functions for Managing Parameter Block . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 421
Functions for Handling Passwords . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 425
Functions for Managing RDN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 428
Functions for Managing Roles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 450
Functions for Managing DNs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 451
Functions for Sending Entries and Results to the Client . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 476
Functions Related to UTF-8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 481
Functions for Handling Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 494
Functions for Handling Valueset . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 514
Functions Specific to Virtual Attribute Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 524
Functions for Managing Locks and Synchronization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 532
Functions for Managing Computed Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 537
Functions for Manipulating Bits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 540
Functions for Registering Object Extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 545
Functions Related to Data Interoperability . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 548
Functions for Registering Additional Plug-Ins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 552
8 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 9
Chapter 16 Parameter Block Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 555
Parameters for Registering Plug-In Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 556
Pre-Operation/Data Validation Plug-Ins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 556
Post-Operation/Data Notification Plug-Ins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 558
Matching Rule Plug-Ins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 559
Entry Plug-Ins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 560
Parameters Accessible to All Plug-Ins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 560
Information About the Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 561
Information About the Connection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 563
Information About the Operation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 565
Information About Extended Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 566
Information About the Transaction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 566
Information About Access Control Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 567
Notes in the Access Log . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 567
Information About the Plug-In . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 568
Types of Plug-Ins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 568
Version Information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 569
Information About Command-Line Arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 570
Information About Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 570
Attribute Names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 570
Attribute Flags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 571
Attribute Comparisons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 571
Information About Targets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 572
Parameters for the Bind Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 572
Parameters for the Search Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 573
Parameters Passed to the Search Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 573
Parameters for Executing the Search . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 574
Parameters for the Search Results . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 575
Parameters that Return Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 575
Parameters that Convert Strings to Entries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 576
Parameters for the Add Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 577
Parameters for the Compare Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 578
Parameters for the Delete Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 578
Parameters for the Modify Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 579
Parameters for the Modify RDN Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 579
Parameters for the Abandon Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 580
Parameters for the Matching Rule Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 581
Query Operators in Extensible Match Filters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 582
Parameters for LDBM Backend Pre- and Post-Operation Functions . . . . . . . . . . . . . . . . . . . . . . . . . . 583
Pre-Operation Plug-Ins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 583
Post-Operation Plug-Ins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 584
Parameters for the Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 584
Information About the Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 584
9
Page 10
Information About Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 585
Information About Backend State Change . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 586
Parameters for LDAP Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 586
Parameters for LDAP Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 586
Parameters for LDAP Control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 587
Parameters for Generating LDIF Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 588
Parameters for Error Logging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 589
Parameters for Filters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 590
Parameters for Comparison Filters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 591
Parameters for Filter Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 591
Parameters for Password Storage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 592
Password Storage Plug-Ins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 592
Parameters for Password Storage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 592
Parameters for Resource Limits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 593
Parameter for Binder-Based Resource Limits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 593
Status Codes for Resource Limits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 593
Parameters for the Virtual Attribute Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 593
Glossary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 597
Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 601
10 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 11
Preface
This book describes how to write server plug-ins in order to customize and extend the capabilities of the Netscape Directory Server (D irectory S e rver).
• What You Should Already Know
• Using Directory Server Plug-In APIs
• Document Conventions
• Where to Find Directory Server Information
What You Should Already Know
This book assumes you have this basic backgrou nd:
• A general understanding of the Internet and the World Wide Web (WWW).
• A general understanding of the Lightweight Directory Access Protocol (LDAP) and the Directory Server. This book does not duplicate basic information on server administration or LDAP concepts. For such information, refer to the documents listed in “Where to Find Directory Server Information,” on page 14.
• Programming experience in C or C++.
Using Directory Server Plug-In APIs
Note the following:
• When you install Directory S erver, the plug-in related files are placed in this directory:
<server_root>/plugins/slapd/slapi/
11
Page 12
Using Directory Server Plug-In APIs
• The main header file is located here:
<server_root>/plugins/slapd/slapi/include/slapi-plugin.h
• The location and syntax for the plug-in directives have changed. In t he Directory Server 4.x release, the of the your
<server_root>/slapd-<instance_id>/config directory. For guidelines,
refer to the Readme file located here:
<server_root>/plugins/slapd/slapi/examples/
• Database plug-ins are not supported in this version of Directory Server. Be sure to use the pre-operation, post-operation, and/or extended operation API to register plug-in functions. Note that some code examples in this book are yet to be updated to reflect this change.
• To comply with Internet Protocol version 6, Directory Server plug-ins can now use the to allow plug-ins to recognize the IP address of the LDAP client and server. These new parameters use the Netscape Portable Runtime (NSPR) structure for storing the IP addresses. Because of this, the NSPR files are shipped with Directory Server.
plugin directives were in the database section
slapd.ldbm.conf file. In this release of Directory Server, you must add
plugin directives to the dse.ldif file, which is located in the
SLAPI_CONN_CLIENTEDADDR and SLAPI_CONNSERVERADDR parameters
PRNetADDr
The NSPR API allows compliant applications to use system facilities such as threads, thread synchronization, I/O, interval timing, atom ic operations, and several other low-level services in a platform-i ndependent manner.
• Several functions have been deprecated in this release of the Directory Server Plug-in API. The deprecated functions are still supported for backward compatibility. They are, however, not documented in this release. The table below lists the deprecated functions and the func tions you should use in their place. If you need additional information on functions that have been deprecated, check this file:
<server_root>/plugins/slapd/slapi/include/slapi-plugin-compat4.h
Table 0-1 Deprecated Functions and Their Suggested Replacements
Deprecated Function Suggested Replacement Function
The following functions th at deal with bervals ar e deprecated and their use is not recommended. For each deprecated functi on, you will fin d in slapi-plugin.h a correspo nding fun ction with a _sv extens ion that uses Slapi_Values instead of bervals. The new functions are more efficient than the old ones.
slapi_entry_attr_merge() slapi_entry_attr_merge_sv() slapi_entry_add_values() slapi_entry_add_values_sv() slapi_entry_delete_values() slapi_entry_delete_values_sv()
12 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 13
Document Conventions
Table 0-1 Deprecated Functions and Their Suggested Replacements (Continued)
Deprecated Function Suggested Replacement Function
slapi_entry_attr_replace() slapi_entry_attr_replace_sv() slapi_attr_get_values() slapi_attr_value_find() slapi_attr_get_oid() slapi_attr_get_oid_copy() slapi_pw_find() slapi_pw_find_sv() slapi_call_syntax_values2keys() slapi_call_syntax_values2keys_sv() slapi_call_syntax_assertion2keys_ava() slapi_call_syntax_assertion2keys_ava_sv() slapi_call_syntax_assertion2keys_sub() slapi_call_syntax_assertion2keys_sub_sv() slapi_entry_attr_hasvalue() slapi_entry_attr_has_syntax_value() The following inter nal-operat ion ca lls ar e deprec ated. The new in te rnal o peration function s tha t are defined
in slapi-plugin.h take a Slapi_PBlock for extensibility and support the new plug-in configuration capabilities.
slapi_search_internal_callback() slapi_search_internal_callback_pb() slapi_search_internal() slapi_search_internal_pb() slapi_modify_internal() slapi_modify_internal_pb() slapi_add_internal() slapi_add_internal_pb() slapi_delete_internal() slapi_delete_internal_pb() slapi_modrdn_internal() slapi_modrdn_internal_pb() The following three functions are not multi-thread safe; they return a pointer to unprotected data. Use the
new functions in slapi-plugin.h that end in _copy() instead. slapi_get_supported_controls() slapi_get_supported_controls_copy() slapi_get_supported_extended_ops() slapi_get_supported_extended_ops_copy() slapi_get_supported_saslmechanism() slapi_get_supported_saslmechanisms_copy()
Document Conventions
The Directory Server runs on Windows NT and a number of different UNIX platforms; the information here applies to all versions. File and directory paths are given in Unix format (with forward slashes separating directory names). For Windows versions, the directory paths are the same, except that you use backslashes instead of s lashes to separate directorie s.
This book uses Uniform Resource Locators (URLs) of the form
Preface 13
Page 14
Where to Find Directory Server Information
http://<server>.<domain>/<path>/<file>.html
In these URLs, <server> represents the name of the server on which you run your application (such as name (such as server, and
<file>.html represents an individual filename.
research1 or www), <domain> represents your Internet domain
example.com), <path> represents the directory structure on the
If your server has Secure Sockets Layer (SSL) enabled, you would use instead of
http in the URL.
This book uses the following font conventions:
The monospace font is used for sample code and code listings, API and
• language eleme nts (such as function names and class names), filenames, pathnames, directory names, HTML tags, and any text that must be typed on the screen.
• Italic type is used for book titles, emphasis, and placeholders, and words used in the literal sense.
• Variables are enclosed in angle brackets.
• Boldface type is used for glossary terms.
Where to Find Directory Server Information
This book explains how to write your own server plug-ins to customize the Directory Server. You can write plug-ins that validate data before the data is stored in the directory, that notify users when data has changed, or that replace the standard database in the Directory Server with your own database.
https
The document set for Directory Server also contains the following guides:
• Netscape Directory Server Inst a llation Guide. Contains procedures for installing your Directory Server as well as procedures for migrating from a previous installation of Directory Server.
• Netscape Directo ry Ser ver Deplo yme nt Guid e. Contains procedures for the day-to-day maintenance of your directory service. Includes information on configuring server-side plug-ins.
• Netscape Dire ctory Server Administrator’s Guide. Contains procedures for the day-to-day maintenance of your directory service. Includes information on configuring server-side plug-ins.
14 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 15
Where to Find Directory Server Information
• Netscape Directory Server Configuration, Command, and File Reference. Contains information about using the command-line scripts shipped with Directory Server.
• Netscape Directory Server Schema Reference. Contains information about the Directory Se rver schema.
For a list of documentation installed with Directory Server, open the
<server_root>/manual/en/slapd/index.htm file, where <server_root> is th e
directory in which you installed Directory Server. For the latest information about Directory Server, including current release notes,
complete product documentation, technical notes, and deployment information, check this site:
http://enterprise.netscape.com/docs
For a list of LDAP standards-related documen ts, check this site:
http://www.mozilla.org/directory/standards.html
Preface 15
Page 16
Where to Find Directory Server Information
16 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 17
Introduction to Directory Server
Chapter 1, “An Overview of Directory Server Plug-Ins”
Chapter 2, “Writing and Compiling Plug-Ins”
Part 1
Plug-Ins
Chapter 3, “Configuring Plug-Ins”
Chapter 4, “A Quick Example”
17
Page 18
18 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 19
Chapter 1
An Overview of Directory Server
Plug-Ins
This chapter introduces you to Netscape Directory Server (Directory Server) plug-ins and discusses the different types of plug-ins that you can write. The chapter covers the following topics:
• What Are Directory Server Plug-Ins?
• How Directory Server Plug-Ins Work
• Types of Directory Server Plug-Ins
If you have already written a plug-in for Directory Server, refer to the section “Using Directory Server Plug-In APIs” on page 11 for information on migrating your plug-in to the latest version of the Directory Server.
What Are Directory Server Plug-Ins?
If you want to extend the capabilities of the Directory Server, you can write your own Directory Server plug-in. A server plug-in is a shared object or library (or on the Windows NT platform, a dynamic link library) that contains custom functions that you write.
By writing your own plug-in functions, you can extend the functionality of the Directory Server. For example, here are some of the things you can do with Directory Se rver plug-ins:
• You can design an action that the Directory Server performs before the server processes an LDAP action. For example, you can write a custom function to validate data before the server performs an LDAP operation on the data.
19
Page 20
How Directory Server Plug-Ins Work
• You can design an action that the Directory Server performs after the server successfully completes an LDAP operation. For example, you can send mail to a client after an LDAP operation is successfully completed.
• You can define extended operations, as defined in the the LDAP v3 protocol.
• You can provide alternate matching rules when comparing certain attribute values.
How Directory Server Plug-Ins Work
When properly configured, the Directory Server will load your plug-in on startup. Once loaded, the Directory Server will resolve calls made to your plug-in functions as it processes the LDAP requests cont ained in your applications.
Internally, the Directory Server has hook s that allow you to register your own functions to be called when specific events occur. For example, the Directory Server has hooks to call a registered plug-in in the following situa tions:
• Before preforming an LDAP operation (for example, before an entry is added to the directory)
• When adding, modifying, remo ving, renaming, or searching for entries in the database
• After performing an LDAP operation (for example, after an entry is added to the directory)
• Before writing an entry to the database
• After reading an entry from the database
• When processing an extended operation
• When indexing an attribute
• When filtering search result candidates ba sed on an attribute
When you register your plug-in functions, you specify the function type and the plug-in type. Together, these specifications indicate when the function is called. For more information on this topic, refer to the section “Types of Directory Server Plug-Ins” on page 24.
20 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 21
How Directory Server Plug-Ins Work
Calling Directory Server Plug-In Functions
At specific LDAP events, the Directory Server calls all plug-in functions that are registered for that event. For example, before performing an LDAP add operation (an add event), the server calls all plug-in functions registered as pre-operation add functions. When the add operation is completed, the server will call all registered post-operation add functions.
In most plug-in function calls, the server passes a parameter block to the function. The parameter block contains data relevant to the operation. In most Director y Server plug-in functions you write, you access a nd mo dify the data in the param eter block.
For example, when the Directory Server receives an LDAP add request, the server does the following:
1. Parses the request and retrieves the new DN and the entry to be added.
2. Places pointers to the DN and the entry in the parameter block.
3. Calls any registered pre-o p eration add functions, passing the parameter block
to these functions.
4. Calls the registered database add function (which is responsible for adding the
entry to the directory database), and passes to it the parameter block.
5. Calls any registered post-operation add functions, passing the parameter block
to these functions.
If you are writing a function that is invoked before an LDAP operation is performed, you can prevent the operation from being performed. For exam ple, you can write a function that validates data before a new entry is added to the directory. If the data is not valid, you can prevent the LDAP add operation from occurring and return an error message to the LDAP client.
In some situations, you can also set the data that is used by the server to perform an operation. For example, in a pre-operation add function, you can change an entry before it is added to the directory.
The Directory Server Architecture
Internally, the Directory Server consists of two ma jor subsections: The front-end and the back -end.
Chapter 1 An Overview of Directory Server Plug-Ins 21
Page 22
How Directory Server Plug-Ins Work
The front-end receives LDAP requests from clients and processes those requests. When processing requests, the front-end calls functions in the back-end to read and write data. The front-end then sends the results back to the client.
The back-end reads and writes data to the database containing the directory entries. The back-end abstracts the database from the front-end. The data stored in a back-end is identified by the suffixes that the back-end supports. For example, a back-end that supports the “o=example.com” suff ix contains directory entries that end with that suffix.
Figure 1-1 illustrates the Directory Server architecture.
22 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 23
Figure 1-1 Directory Server Architecture
How Directory Server Plug-Ins Work
Chapter 1 An Overview of Directory Server Plug-Ins 23
Page 24
Types of Directory Server Plug-Ins
Types of Directory Server Plug-Ins
You can write the following types of plug-ins for the Directory Server:
• Pre-operation/data validatio n. The server calls a pre-operation/data validation plug -in function before p erforming an LD AP operation.
The main purpose of this type of plug-in is to validat e data befo re the data is added to the directory or before it is used in an operat ion.
• Post-operation/data notificati on. The server calls a post-operation/data notification plug-in function after performing an LDAP operati on.
The main purpose of this type of plug-in is to invoke a function after a particular operation is executed. For example, you can write a plug-in that sends email to users if their entries are modified.
• Entry storage and entry f etch. The server calls an entry storage plug-in functi on right before writing data to the database back-end. The server calls entry fetch plug-in functions after retrieving an entry from the database back-end.
For example, you can create an entry storage plug-in that encrypts an entry before it is saved to the database and an entry fetch plug-in that decrypts an entry after it is read from the database.
• Extended operation. The server calls an extended operation plug-in function when the client requests an operation by OID. Extended operations are defined in LDAP v3 and are described in more detail in Chapter 10 , “Writing Extended Operation Plug- I ns.”
• Syntax. The server calls a syntax plug-in function when getting a list of possible candidates for a search. The server also calls these functions when adding or deleting values from certain attribute indexes.
Syntax plug-in functions can d efine the comparison operations used in searches. For example, you could use a syntax plug-in function to define how the “equals” comparison works for case-insensitive strings.
• Matching rule. The server calls matching rule plug-in functions when the client sends a search request with an extensible matching search filter. You can also write matching rule plug-in functions that the server calls when indexing attributes for the back-end database.
Figure 1-2 illustrates how some of these different plug-in types fit into the Directory Server architecture.
24 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 25
Types of Directory Server Plug-Ins
Figure 1-2 Architecture of the Directory Server and Server Plug-Ins
Chapter 1 An Overview of Directory Server Plug-Ins 25
Page 26
Types of Directory Server Plug-Ins
26 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 27
Chapter 2
Writing and Compiling Plug-Ins
This chapter provides an introduction on how to write and compile Netscape Directory Server (Directory Server) plug-ins. Chapter 3, “Configuring Plug-Ins,” describes how to load your plug-in int o the Directory Server configuration once it is successfully compiled. This chapter covers the following topics:
• Writing a Plug-In Function
• Writing Plug-in Init ialization Functions
• Compiling a Directory Server Pl ug-In If you have already written a plug-in for the Directory Server, refer to the
section “Using Directory Server Plug-In APIs” on page 11 for information on migrating your plug-in to the latest versi on of the Directory Server.
Writing a Plug-In Function
To write a Directory Server plug-in, you must do the follo wing in your plug-in code:
• Include the API header file
• Set the function parameters using the parameter block
• Call the front-end
• Specify the function return value For additional information o n writing specific plug-in types, refer to the follow ing
chapters:
• Chapter 6, “Writing Pre/Post-Operation Plug-Ins”
• Chapter 9, “Writing Entry Store/Fetch Plug-Ins ”
27
Page 28
Writing a Plug-In Function
• Chapter 10, “Writing Extended Operation Plu g-Ins”
Including the API Header File
The interface to the Directory Server plug-in API is located in the slapi-plugin.h header file. You must include this header file in the plug-ins you write. The following line of code shows an example of including this header file:
#include "slapi-plugin.h"
When you install the Directory Server, slapi-plugin.h g et s installed into the following directory:
<server_root>/plugins/slapd/slapi/include
Passing Data with Parameter Blocks
Often, plug-in functions make use of a parameter block, Slapi_PBlock, for passing information to and from the Directory Server. The following plug-in function types pass a parameter block as a fu nction argume nt:
• Pre-operation plug-in functions
• Post-operat ion plug-in functions
• Matching rule functions for indexing
• Factory functions for matching rule index functions
• Factory functions for matching rule filter functions
When invoking these types of plug-in functions, you pass to the Directory Server a single argument of type values needed to complete the function request. Your plug-in function should have a prototype similar to the following:
int myFunction( Slapi_PBlock pb );
In this prototype, pb is the parameter block that contains the parameters pertaining to the operation or function.
For example, the parameter block for an add operatio n will contain the target DN and the entry to be added; the parameter block for a bind operation will contain the DN of the user, the authentication method, and the user’s credentials.
Slapi_PBlock. This argument contains the parameter
28 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 29
Writing a Plug-In Function
Working with Parameter Blocks
In the functions you write, you set values in the parameter block that pertain to the operation you are p e rforming. You can a lso get data from the parameter block which you can use within your functions. This process is described in the next section, “Getting Data from the Parameter Block , ” on page 29.
You can also set values in the parameter block during the processing of your plug-in functions. The Directory Se rver ca n then use the new data values to complete an operation which it might be processin g. For d e tails on this, see “Setting Data in the Parameter Block,” on pag e 30.
Some of the data that you can retrieve from the parameter block includes entries, attributes, search filters, and distinguished names (DNs). Once you retrieve a piece of data, you can manipulate it using the front-end API functions. For example, you can use front-end API functions to verify that an entry complies with the schema or you can split up a search filter into it s ind ividual components. For details, see the section “Calling Front-End Functions,” on page 31.
Getting Data from the Parameter Block
When the Directory Server calls your plug-in function, it passes any relevant data to your function in a parameter block. The parameter block is defined as a
Slapi_PBlock data type. To access the data in a parameter block, call the slapi_pblock_get() function.
NOTE Often,
When you call your own functions to modify the value retrieved by
slapi_pblock_get(), you are modifying the actual data in the
parameter block, not a copy of the data.
In the following example, the the base DN for the LDAP search operation. It then normalizes the DN, converts all characters to lowercase, and writes the converted DN to the error log. Note that the actual DN (not a copy of it) is normalized and converted to lowercase.
Code Example 2-1 Getting Data From the Parameter Block
#include <slapi-plugin.h> ... int searchdn_preop_search( Slapi_PBlock *pb ) {
char *dn;
slapi_pblock_get() returns a pointer to the actual data.
searchdn_preop_search() function gets the DN of
Chapter 2 Writing and Compiling Plug-Ins 29
Page 30
Writing a Plug-In Function
Code Example 2-1 Gett ing Data From the Pa rameter Block (Continued)
/* Indicate the point when the plug-in starts executing */ slapi_log_error( SLAPI_LOG_PLUGIN, "searchdn_preop_search",
"*** PREOPERATION SEARCH PLUGIN ***\n");
/* Get the base DN of the search from the parameter block. */ slapi_pblock_get( pb, SLAPI_SEARCH_TARGET, &dn );
/* Normalize the DN (the actual DN, not a copy of it)
and convert it to lowercase */
slapi_dn_normalize_case( dn ); /* Log the normalized DN */
slapi_log_error( SLAPI_LOG_PLUGIN, "searchdn_preop_search",
"Normalized DN: %s\n", dn );
return( 0 );
}
In this code example, SLAPI_SEARCH_TARGET identifies the parameter in the parameter block that contains the base DN of the search. For a complete listing of the parameter block IDs, see Chapter 16, “Parameter Block Reference.”
Setting Data in the Parameter Block
To modify the value of a parameter in the parameter block, call the function
slapi_pblock_set(). For example, you call can slapi_pblock_set() to change
the value of the plug-in.
In the following example, the
SLAPI_PRIVATE
Code Example 2-2 Setting Values in the Parameter Block
#include <slapi-plugin.h> ... int ldif_back_init( Slapi_PBlock *pb ) {
LDIF *db; /* context of the database */ ...
/* Allocate space for the database context, which contains
information about the database and a pointer to the list of entries. */
if ( slapi_pblock_set( pb, SLAPI_PRIVATE, (void *) db ) == -1 )
{
slapi_log_error( SLAPI_LOG_PLUGIN, "ldif_back_init",
SLAPI_PRIVATE parameter, which stores private data for the
ldif_back_init() function sets the value of the
parameter to the context of the database.
30 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 31
Code Example 2-2 Setting Values in the Parameter Block (Continued)
"Unable to store database information\n" );
} ... }
Notice that this example uses the function slapi_new_condvar() to notify the user if an error occurred.
Writing a Plug-In Function
In this code example,
SLAPI_PRIVATE identifies the parameter in the parameter
block that contains private data for use in the database functions. For a complete listing of the parameter block IDs, see Chapter 16, “Parameter Block Reference.”
Calling Front-End Functions
The types of data that you can get from a parameter block i nclude entries, attributes, distinguished names, and search filters. If you want to manipulate these data items, you can call the associated front-end API functions provided with the Directory Server. For example, using the the front-end API functions, you can:
• Write messages to the error log
• Get the attributes of an entry
• Get or set the DN of an entry
• Add or delete the values of an attribute
• Determine the OID of an attribute
• Determine the type of a search filter For more information on the front-end A PI, see Chapter 5, “Front-End API
Functions” and Chapter 15, “Function Reference.”
Plug-in Return Values
If your plug-in function is successful, it should return 0 to the front-end. If it is not successful, it should return a non-zero value and you should call the front-end API function problem (“Logging Messages ” on page 58 details this process).
slapi_new_condvar() to log an error message to describe the
Chapter 2 Writing and Compiling Plug-Ins 31
Page 32
Writing Plug-in Initialization Functions
In some cases, you may need to send an LDAP result back to the client. For example, if you are writing a pre-operation bind function and an error occurs during the processing of the function, the function should return a non-zero value, log an error message, and send the appropriate LDAP result code back to the client. For information on the appropriate result code to return to the client, refer to the chapter that documents the type of plug-in you ar e writing.
Writing Plug-in Initialization Functions
Before the Directory Server can call your plug-in function, the function be must properly initialized. To do this, you m ust write an initialization function for your server plug-in. The initialization function should do the following:
1. Specify the plug-in compatibility version.
2. Register each of your plug-in functions.
3. Return a valu e to the Directory Server.
Your initialization function should have a prototype simi lar to the following:
int my_init_function( Slapi_PBlock pb );
Notice that in the initialization function, the Directory Server passes a single argument of t y pe
Slapi_PBlock.
Initialization Functions for Windows Platforms
If you are writing an initialization function for a plug-in that runs on Windows NT or Windows 2000, make sure to export the initialization function. For example:
__declspec(dllexport) int my_init_function(Slapi_PBlock pb);
On top of exporting the initializa tion function, you must also specify the name of the initialization funct ion in a
In addition to the initialization function, you might need to export other functions contained in your plug-in. In particular, you will need to export a ny functions that are not specifically registered by your initialization functions, such as the entry store and entry fetch plug-in functions that are described in Chapter 9. Registering plug-in functions is described in det ail in the next section, “Registering Your Plug-In Functions.”
.def file.
32 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 33
Writing Plug-in Initialization Functions
NOTE You do not need to export all plug-in functions. Specifically, you do
not need to export any plug-in function that is specified in the parameter block.
Specifying Directory Server Compatibility
You need to specify the compatibility version of your plug-in so that the Directory Server can determine whether or not it supports the plug-in.
To specify the plug-in compatibility version, call the functio n an d set the
SLAPI_PLUGIN_VERSION parameter to the version number
slapi_pblock_set()
associated with the plug-in. For example:
slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, \
SLAPI_PLUGIN_VERSION_03);
• Plug-in version 1 (SLAPI_PLUGIN_VERSION_01) is compatible with versions 3.x and 4.x of the Directory Server.
• Plug-in version 2 (
SLAPI_PLUGIN_VERSION_02) is compatible with version 4.x
of the Directory Server.
• Plug-in version 3 (
SLAPI_PLUGIN_VERSION_03) is compat ible with ve rsio ns 6.1
and later of the Directory Server.
Specifying Information About the Plug-In
You specify information about your plug-in, such as a description of the plug-in, with the see “Slapi_PluginDesc,” on page 207.
It is advised that you include a plug-in description since the Netscape Console displays this information as part of the server configuration information.
Slapi_PluginDesc structure. For details on this data structure,
To specify plug-in information, call the
SLAPI_PLUGIN_DESCRIPTION parameter to this structure. For example:
Code Example 2-3 Specifying Plug-In Info rm at ion
/* Specify information about the plug-in */ Slapi_PluginDesc mypdesc = { "test-plugin", "example.com",
"0.5", "sample pre-operation plugin" };
...
slapi_pblock_set() function and set the
Chapter 2 Writing and Compiling Plug-Ins 33
Page 34
Writing Plug-in Initialization Functions
Code Example 2-3 Specifying Plug-In Information (Continued)
/* Set this information in the parameter block */ slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
(void *)&mypdesc );
In this example code specifies the following plug-in information:
• The unique identifier for the server plug-in is
• The vendor of the server plug-in is
• The version of the server plug-in is
example.com.
0.5.
test-plugin.
Note that this version is intended to be used for your tracking purposes only; it is not the same as the server compatibility version number specified by the
SLAPI_PLUGIN_VERSION parameter (see “Specifying Directory Server
Compatibility” on page 33 for details on this parameter). As you make changes to your plug-in code, you can track the version distributed using the number contained in the
Slapi_PluginDesc structure.
• The description of the server plug-in is contained in the data structure value
sample pre-operation plug-in.
Registering Your Plug-In Functi ons
Whether you register your plug-in through the initialization function depends upon the type of function you are registering.
For some plug-in types, you do not need to register the plu g-in function from within the initialization function. For example, you register entry store and entry fetch plug-ins by specifying the function names in the
dse.ldif file.
plugin directive in the
For other plug-in types, such as pre-operation plug-ins and post-operation plug-ins, the Directory Server gets the pointer to your function from a parameter in the initializatio n function parameter block. In these cases, you use the
slapi_pblock_set() function to specify the name of your plug-in function.
The full list parameters that you can use to register your plug-in functions are listed in “Parameters for Registering Plug-In Functions” on page 556.
34 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 35
Writing Plug-in Initialization Functions
For example, if you want to register searchdn_preop_search() as a pre-operation search function, include the follo wing code in your initialization f unction:
slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_SEARCH_FN, \
(void *) searchdn_preop_search )
SLAPI_PLUGIN_PRE_SEARCH_FN
is the parameter that specifies the pre-operation
plug-in functi on for the LDAP search operation.
NOTE If you do not register your plug-in functions, the Directory Server
will not call your plug-in functions. Make sure to register your plug-in functions.
You can register more than one plug-in function in your initialization function; you do not need to write an initialization function for each plug-in func tion that you need to register. You should, however, define a different initialization function for each type of plug-in that you are registering.
Returning a Value to the Directory Server
If the initialization function is successful, it should return 0. If an error occurs, it should return exit.
-1. If the initialization funct ion returns -1, the Directory Server will
Example of an Initialization Function
The following is an example of an initialization function that registers the pre-operation plug-in function function returns, the server will call search operation is executed.
Code Example 2-4 An Example Initialization Function
#include "slapi-plugin.h" ... #ifdef _WIN32 __declspec(dllexport) #endif
searchdn_preop_init( Slapi_PBlock *pb ) {
/* Specify the version of the plug-in (set this to "01")*/
searchdn_preop_search(). After the initialization
searchdn_preop_search() before each LDAP
Chapter 2 Writing and Compiling Plug-Ins 35
Page 36
Compiling a Directory Server Plug-In
Code Example 2-4 An Example Initialization Function (Continued)
if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
SLAPI_PLUGIN_VERSION_01 ) != 0 ||
/* Set up the server to call searchdn_preop_search()
before each LDAP search operation. */
slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_SEARCH_FN,
(void *) searchdn_preop_search ) !=0 ) {
/* If a problem occurs, log an error message, return -1.*/
slapi_log_error(SLAPI_LOG_PLUGIN,"searchdn_preop_init",
"Error registering function.\n" ); return( -1 ); }
/* If the plug-in was successfully registered, log a
message and return 0. */ slapi_log_error( SLAPI_LOG_PLUGIN, "searchdn_preop_init",
"Plug-in successfully registered.\n" );
return( 0 );
}
Compiling a Directory Server Plug-In
Keep in mind the following tips when com piling your server plug-in:
• You need to compile and link your code as a shared object or library on UNIX or as a dynamic link library (DLL) on Windows pl atforms. For e xample, on Solaris, specify command.
Some compilers require that you provide special flags when compiling code to be used in a shared object or DLL. For example, on Solaris, you must specify the
-Kpic or -KPIC flag, which specifies that you want to generate
position-independent code. Consult the documentation for your platform compiler and linker for details.
• Make sure that the is in your include path. Use for Windows NT and Windows 2000 plug-ins.
• On Windows platforms, link to the located in this directory:
ld -G <objects> -o <shared_object> as your link
<server_root>/plugins/slapd/slapi/include directory
<server_root>\plugins\slapd\slapi\include
libslapd.lib import library, which is
<server_root>\plugins\slapd\slapi\lib
36 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 37
Compiling a Directory Server Plug-In
• If you want, you can compile all plug-in functions in a single library. Although you can include different types of plug-in functions in the same library, you need to write separate initialization functions for each type of plug-in function. Refer to the chapter “Configuring Plug-Ins” on page 39 for details on how to specify each initialization functi on in a directive for a specific type of plug-in.
The following code shows a sample Makefile for Solaris. The example assumes that the source files are located in the following directory:
<server_root>/plugins/slapd/slapi/examples
The server plug-in API header files are located in the relative path ../include.
Code Example 2-5 Example Solaris Makefile
# SOLARIS Makefile for Directory Server plug-in examples # CC = cc LD = ld INCLUDE_FLAGS = -I../include CFLAGS = $(INCLUDE_FLAGS) -D_REENTRANT -KPIC LDFLAGS = -G OBJS = testsaslbind.o testextendedop.o testpreop.o testpostop.o
testentry.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
Chapter 2 Writing and Compiling Plug-Ins 37
Page 38
Compiling a Directory Server Plug-In
38 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 39
Chapter 3
Configuring Plug-Ins
After you compile your server plug-in, you need to configure the Netscape Directory Server (Directory Server) so that it properl y loa d s your plug-in. The following sections in this chapter show how this is done:
• Creating a Plug-In Configuration File
• Loading the Plug-In Configurati on File
• Passing Extra Argume nts to Plug-Ins
• Setting the Log Level of the Server
Creating a Plug-In Config u ra tio n File
To add your plug-in to the Directory Server configuration, you need to create an LDIF representation of your plug-in entry, add the plug-in entry to the Directory Server configuration, and reload the server configuration. Thi s section illustrates how to create your plug-in entry. The section “Loading the Plug-In Configuration File,” on page 44 explains how to add the plug-in entry to the Directory Server configuration and reload the server configuration.
The plug-in configuration file must be an LDIF file written in ASCII format. Code Example 3-1 shows the contents of an example plug-in configuration file. Note that line numbers have been added for ease of reference; do not number the lines in your own LDIF file.
Code Example 3-1 An Example Plug-In Configuration File
1. dn: cn=Example Plug-in,cn=plugins,cn=config
2. objectclass: top
3. objectclass: nsSlapdPlugin
4. objectclass: extensibleObject
39
Page 40
Creating a Plug-In Configuration File
Code Example 3-1 An Example Plug-In Configuration File (Continued)
5. cn: Example Plug-in
6. nsslapd-pluginpath: C:/ds60/lib/test-plugin.dll
7. nsslapd-plugininitfunc: searchdn_preop_init
8. nsslapd-plugintype: preoperation
9. nsslapd-pluginenabled: on
10. nsslapd-pluginid: Example Pre-operation Plug-in
11. nsslapd-pluginversion: 1.0
12. nsslapd-pluginvendor: Example Corporation
13. nsslapd-plugindescription: This plug-in does ...
This example plug-in configuration file defines an example plug-in as follows:
• Line 1 sets the DN of the plug-in, which identi fi es the plug-in:
dn: cn=Example Plug-in,cn=plugins,cn=config
Here, the common name of the plug-in is set to Example Plug-in. The rest of the DN entry ( that contains the configuration settings for plug-ins.
cn=plugins,cn=config) places the entry in the database tree
• Lines 2-4 declare the object classes of the plug-in.
• Line 5 sets the common name of the plug-in to
Example Plug-in.
• Line 6 defines the absolute path to the library that implements the plug-in:
nsslapd-pluginpath: C:/ds60/lib/test-plugin.dll
In this example, the plug-in is a Windows NT DLL, located in the directory
C:/ds60/lib.
• Line 7 identifies the initialization function that the server calls to register the plug-in. In this example, the initialization is set to
searchdn_preop_init. For
information on implementing initialization functions, see “Writing Plug-in Initialization Fun c tions,” on page 32.
• Line 8 sets the type of plug-in. In this case, it is a pre-operation plug-in. For a complete list of the types of plug-in you can declare, refer to the “Summary of Plug-In Directives” on page 42.
• Line 9 specifies whether or not the plug-in is active by default. The
nsslapd-pluginenabled attribute can have a value of either on or off. The
following line specifies that the plug- in is active by default:
nsslapd-pluginenabled: on
40 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 41
Creating a Plug-In Configuration File
You can also use the Directory Server Console to activate or deactivate the plug-in once the plug-in is loaded.
• Line 10 uses the
nsslapd-pluginid attribute to set the name of the plug-in.
The name that you specify here will show up in the Directory Server Console. In this example, the plug-in identification is set to
Plug-in
.
Example Pre-operation
• Line 11 sets the version number of the plug-in. This version number will also show up in the Directory Server Console, and is used to track the vers ion of the distributed plug-in; it does not indicate the Directory Server compatibility, as is defined by the plug-in version number described in “Specifying Directory Server Compatibility,” on page 33.
• Line 12 identifies the vendor/author of the plug-in. In the following line, the vendor is set to “Example Corporation”:
nsslapd-pluginvendor: Example Corporation
• Finally, Line 13 sets the description of the plug-in. The description you set will be the plug-in description that is visible through the Directory Server Console.
Plug-In Dependencies
You can specify that your plug-in is dependent on one or more different plug-ins. If you do specify any plug-in dependencies, thos e pl ug- ins that you specify must properly start before your associ ated plu g -i n wil l start.
There are two attributes that you can use in the plug-in configuration file to specify the dependencies of your plug-in:
• nsslapd-plugin-depends-on-name
• nsslapd-plugin-depends-on-type
Each of these attributes can take multiple values, meaning that your plug-in depends on one or more other plug-ins.
Specific Plug-in Dependencies
If you specify the nsslapd-plugin-depends-on-name attribute in your plug-in configuration file, set its value to the names of one or more plug-ins. For example, in your plug-in configurati on file, you could specify the following:
nsslapd-plugin-depends-on-name: my_pluginA nsslapd-plugin-depends-on-name: vendor_pluginB
Chapter 3 Configuring Plug-Ins 41
Page 42
Creating a Plug-In Configuration File
In this example, the plug-in depends on two specifically named plug-ins:
my_pluginA and vendor_plugin. This configuration line indicates that before your
plug-in can be loaded, the two specifically named plug-ins must be loaded. If either of these two plug-ins fail to load, the Directory Server will exit with a
Plug-In Type Dependencies
If you specify the nsslapd-plugin-depends-on-type attribute in your plug-in configuration file, set its value to one or more plug-in types. For example, in your plug-in configuration file, you could specify the following:
nsslapd-plugin-depends-on-type: syntax
This configuration line indicates that your plug-in depends on any plug-in of type
syntax. If there is a configured plug-in of type syntax, it must be successfully
loaded before your plug-in can be loaded, otherwise the Directory Server will exit with a
Note that if you specify a plug-in type dependency, the Directory Server will search for any and all plug-ins of the type( s) specif ied. If none are found, processing will continue without errors. However, the Directory Server must load all plug-ins of the type(s) specified before it can load your plug-in. For a complete list of the supported plug-in types, refer to the “Summ ary of Plug-In Directives,” on page 42.
-1 error code.
-1 error code.
Specifying the Order of Plug-In Directives
You cannot in general rely on plug-ins being called in a certain order. For example, you cannot rely on a particular pre-operation plug-in to be called before another. You should ensure that your plug-in is written in such a way as to make it independent of the order in which it will be called.
If you must use ordering, you can make use of alphabetical order. The server loads the plug-ins in alphabetical order—that is, the loading order is determined by standard ASCII ordering o f the cn
=plugins,cn=config in the dse.ldif file. Because this feature may be
deprecated in a future version of the product, it is recommended that yo u write your plug-in to not rely on any specific loading order.
cn value of the plug-in entry, which appears under
Summary of Plug-In Directives
The following table summarizes the different types of plug-ins that you can specify in the plug-in configuration file.
42 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 43
Creating a Plug-In Configuration File
Table 3-1 Directives for Specifying Different Plug-In Types
Directive Description
entryfetch Declares an entry fetch plug-in, which is called by the server after retrieving an
entry from the default back-end database. Example of use: If you encrypt data with an entry store plug-in function before
saving the data to the database, you can define an entry fetch function that decrypts data after reading it from the database.
entrystore Declares an entry store plug-in, which is called by the server before saving an
entry to the default back-end database. (If you are writing your own database plug-in, you do not need to use this plug-in.)
Example of use: You can define an entry store function to encrypt data before saving the data to th e data base.
extendedop Declares an extended operation plug-in, which is called by the server when
receiving a request for an extended operation from a client.
matchingRule Declares a matching rule plug-in, which is called by the server when receives a
search request with an extensible matching search filter from a client. This type of plug-in is also called by th e se rver when indexing attribut es for t he
back-end database.
postoperation Declares a post-operation/data notification plug-in, which is called by the
server after performing an LDAP operation. Example of use: You can define a data notificatio n function to send notificati on
to the adminis trator if certa in data has changed.
preoperation Declares a pre-operation/data validation plug-in, which is called by the server
before perfo rming an LDAP op eration. Example of use: You can define a data validati on function to check new entri es
before they are added to the directory.
syntax Declares a syntax plug-in, which is called by the server when getting a list of
possible candidates for a search, when determining how to compare values in searches, and when adding or deleting values from certain attribute indexes.
Example of use: You can define a function that specifies how the “equals” comparison works for case-insensitive strings.
Chapter 3 Configuring Plug-Ins 43
Page 44
Loading the Plug-In Configuration File
Table 3-1 Directives for Specifying Different Plug-In Types (Continued)
Directive Description
object Declares an object plug-in. Object plug-ins can install
SLAPI_PLUGIN_START_FN, SLAPI_PLUGIN_CLOSE_FN, and SLAPI_PLUGIN_POSTSTART_FN functions. They can also use the slapi_register_plugin() call to register any kind of plug-in they like.
Object plug-ins are typically used to simplify configuration of a group of related plug-ins (one entry under cn=config instead of many).
Example of use: You can use this type when your plug-in doesn’t fit in any of the other types listed in this table. For example, if your plug-in does more than one thing, then you should use this directive. This type of plug-in will typically register the types of operations it wants to handle using the internal API.
pwdstoragescheme This directive will be supported in the future .
Loading the Plug-In Co nfig u ra tio n File
After you have written the plug-in config uration file, you must load it into the
dse.ldif file, which is located in the <server_root>/slapd-<instance_id>/config directory. You can do this either
by using an LDAP utility, such as
ldapmodify, or by editing the file directly. If you
choose to edit the file directly, be sure to shut down the Directory Server first. The following line shows an example of an LDAP command that loads the plug-in
defined in the configuration fi le
ldapmodify -h my_host -p 389 -a -D "cn= Directory Manager" \
-w adminadmin -f example-plugin.ldif
example-plugin.ldif:
Once the plug-in configuration is loaded, you must shut down the Directory Server and then restart it before you can make calls to your plug-in. There are various ways to shut down and restart the Directory Server; for example, you can:
• Use the Directory Server Console
• Use the UNIX scripts
stop-slapd and start-slapd
• Use the Windows NT Services applet, wh ic h c an be found in the Contr ol Panel
44 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 45
Passing Extra Arguments to Plug-Ins
In the Directory Server 4.x version, you could specify addition al arguments at the end of the
plugin preoperation /usr/lib/myplugin.so my_init_fn \
arg1 arg2
From the initialization function and the plug-in functions, you can get these arguments by getting the follow ing parameters from the parameter block:
•
SLAPI_PLUGIN_ARGC is an int that specifies the number of additional
arguments in the directive.
SLAPI_PLUGIN_ARGV is an array of char* that specifies each additional
• argument in the directive.
However, in Directory Server version 6.1 onwards, plug-ins must not start up in the
init function. They must start up in the start functi on. The preferred method
of communicating plug-in specific configuration is through custom attribute-value pairs in the plug-in entry (in the
plugin directive. For example:
dse.ldif file). Two examples are shown below:
Passing Extra Arguments to Plug-Ins
Example 1:
dn: cn=Test ExtendedOp,cn=plugins,cn=config objectClass: top objectClass: nsSlapdPlugin objectClass: extensibleObject cn: Test ExtendedOp nsslapd-pluginPath: /usr/netscape/servers/plugins/slapd/slapi/
examples/libtest-plugin.so
nsslapd-pluginInitfunc: testexop_init nsslapd-pluginType: extendedop nsslapd-pluginEnabled: on nsslapd-plugin-depends-on-type: database nsslapd-pluginId: test-extendedop
nsslapd-pluginarg0: 1.2.3.4
Example 2:
dn: cn=Internationalization Plugin,cn=plugins,cn=config objectClass: top objectClass: nsSlapdPlugin objectClass: extensibleObject cn: Internationalization Plugin nsslapd-pluginPath: d:/netscape/servers/lib/liblcoll.dll nsslapd-pluginInitfunc: orderingRule_init nsslapd-pluginType: matchingRule nsslapd-pluginEnabled: on
Chapter 3 Configuring Plug-Ins 45
Page 46
Setting the Log Level of the Server
nsslapd-pluginarg0: d:/netsca pe/ serve rs/s lapd-host/config/slapd-collation s.c onf
nsslapd-pluginId: orderingrule nsslapd-pluginVersion: 6.0 nsslapd-pluginVendor: Netscape Communications Corporation nsslapd-pluginDescription: internationalized ordering rule plugin
This method allows for more descriptive configuration, which is easier to maintain. To find the plug-in entry DN, retrieve
SLAPI_TARGET_DN from the pblock passed
to your start function. Once the DN is known, the normal plug-in API functions for entry retrieval and manipulation can be used for configuration retrieval.
For additional information, check the code sa mples provided here:
<server_root>/plugins/slapd/slapi/examples
Setting the Log Leve l of the Serv er
If your functions call the slapi_new_condvar() function to write messag es to the error log, you need to make sure that the Directory Server is configured to log messages with the severity level you’ve specified. The available severity levels are fully documented in the Reference section on page534.
For example, suppose you call this function in your plug-in:
slapi_log_error( SLAPI_LOG_PLUGIN, "searchdn_preop_init",
"Plug-in successfully registered.\n" );
You need to make sure that the Directory Server is configured to log messages with the severity level
SLAPI_LOG_PLUGIN. In the Directory Server 4.x, this corresponds
to the log level of “plugin”.
46 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 47
Chapter 4
A Quick Example
This chapter provides an example of a pre-operation Netscape Directory Server (Directory Server) server plug-in that you can compile and run. Along with the source code to the example, the chapter provides a Solaris Makefile that you can use to build the plug-in.
You may not understand some of the func tionality contained in the example program; however, all the concepts contained in the example code are explained in detail in chapters that follow.
An Example Pre-Operation Plug-In
The example shows how to create a pre-operation plug-in for the LDAP search operation. In other words, the Directory Server will proc ess the registered plug-in functions before it processes each LDAP search operation. The example contains two primary functions:
•The
•The
These functions illustrate the data in the parameter block tha t is available to your function. You can get and manipulate the parameter block data by calling various front-end API functions .
test_preop_search() function logs information about the search,
including the base DN of the search, the search scope, and the type of filter used.
test_preop_init() function is the initialization function that registers
test_preop_search() as a SLAPI_PLUGIN_PRE_SEARCH_FN pre-operation
plug-in functi on for LDAP search op erations.
47
Page 48
An Example Pre-Operation Plug-In
Writing the Plug-In Example
The following example code includes the sample pre-operation search function and the sample initializat ion function.
Code Example 4-1 Sample Pre-Operation Search and Initialization Functions
#include <stdio.h> #include <string.h> #include "slapi-plugin.h"
/* function prototypes */ int test_preop_init( Slapi_PBlock *pb ); int test_preop_search( Slapi_PBlock *pb );
/* Description of the plug-in */ Slapi_PluginDesc srchpdesc = { "test-search", "example.com", "0.5",
"sample pre-operation search plugin" };
/* Initialization function This function registers your plug-in function as a pre-operation search function in the Directory Server. You need to specify this initialization function in the server configuration file so that the server calls this initialization function on startup. */ #ifdef _WIN32 __declspec(dllexport) #endif int test_preop_init( Slapi_PBlock *pb ) {
/* Specify the version of the plug-in ("01" in this release ) */ if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
SLAPI_PLUGIN_VERSION_01 ) != 0 || /* Specify the description of the plug-in */ slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
(void *)&srchpdesc ) != 0 ||
/* Set test_preop_search() as the function to call before
executing LDAP search operations. */
slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_SEARCH_FN,
(void *) test_preop_search ) !=0 ) { /* Log an error message and return -1 if a problem occurred */ slapi_log_error( SLAPI_LOG_PLUGIN, "test_preop_init",
"Error registering the plug-in.\n" ); return( -1 );
} /* If successful, log a message and return 0 */ slapi_log_error( SLAPI_LOG_PLUGIN, "test_preop_init",
"Plug-in successfully registered.\n" );
return( 0 );
} /* Pre-operation plug-in function for LDAP search operations
This function is called by the server before processing an LDAP search operation. The function gets data about the search request
48 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 49
An Example Pre-Operation Plug-In
Code Example 4-1 Sample Pre-Operation Search and Initialization Functions (Continued)
from the parameter block and prints the data to the error log. */ int test_preop_search( Slapi_PBlock *pb ) {
char *base, *filter_str, *attr_type, *substr_init, *substr_final; char **substr_any; int scope, deref, filter_type, i; Slapi_Filter *filter; struct berval *bval; /* Log a message to indicate when the plug-in function starts */ slapi_log_error( SLAPI_LOG_PLUGIN, "test_preop_search",
"*** PREOPERATION SEARCH PLUGIN ***\n"); /* Get and log the base DN of the search criteria */ if ( slapi_pblock_get( pb, SLAPI_SEARCH_TARGET, &base ) == 0 )
slapi_log_error( SLAPI_LOG_PLUGIN, "SLAPI_SEARCH_TARGET",
"%s\n", base ); /* Get and log the search scope */ if ( slapi_pblock_get( pb, SLAPI_SEARCH_SCOPE, &scope ) == 0 ) {
switch( scope ) { case LDAP_SCOPE_BASE:
slapi_log_error( SLAPI_LOG_PLUGIN, "SLAPI_SEARCH_SCOPE",
"LDAP_SCOPE_BASE\n" );
break;
case LDAP_SCOPE_ONELEVEL:
slapi_log_error( SLAPI_LOG_PLUGIN, "SLAPI_SEARCH_SCOPE",
"LDAP_SCOPE_ONELEVEL\n" );
break;
case LDAP_SCOPE_SUBTREE:
slapi_log_error( SLAPI_LOG_PLUGIN, "SLAPI_SEARCH_SCOPE",
"LDAP_SCOPE_SUBTREE\n" );
break;
default:
slapi_log_error( SLAPI_LOG_PLUGIN, "SLAPI_SEARCH_SCOPE",
"unknown value specified: %d\n", scope );
break;
} } /* Get and log the alias dereferencing setting */ if ( slapi_pblock_get( pb, SLAPI_SEARCH_DEREF, &deref ) == 0 ) {
switch( deref ) {
case LDAP_DEREF_NEVER:
slapi_log_error( SLAPI_LOG_PLUGIN, "SLAPI_SEARCH_DEREF",
"LDAP_DEREF_NEVER\n" );
break;
case LDAP_DEREF_SEARCHING:
slapi_log_error( SLAPI_LOG_PLUGIN, "SLAPI_SEARCH_DEREF",
"LDAP_DEREF_SEARCHING\n" );
break;
case LDAP_DEREF_FINDING:
slapi_log_error( SLAPI_LOG_PLUGIN, "SLAPI_SEARCH_DEREF",
"LDAP_DEREF_FINDING\n" );
break;
case LDAP_DEREF_ALWAYS:
slapi_log_error( SLAPI_LOG_PLUGIN, "SLAPI_SEARCH_DEREF",
"LDAP_DEREF_ALWAYS\n" );
Chapter 4 A Quick Example 49
Page 50
An Example Pre-Operation Plug-In
Code Example 4-1 Sample Pre-Operation Search and Initialization Functions (Continued)
break;
default:
slapi_log_error( SLAPI_LOG_PLUGIN, "SLAPI_SEARCH_DEREF",
"unknown value specified: %d\n", deref );
break;
} } /* Get and log the search filter information */ if ( slapi_pblock_get(pb,SLAPI_SEARCH_FILTER, &filter)==0 ) {
/* Get and log the filter type */
filter_type = slapi_filter_get_choice( filter );
switch( filter_type ) {
case LDAP_FILTER_AND:
case LDAP_FILTER_OR:
case LDAP_FILTER_NOT:
slapi_log_error( SLAPI_LOG_PLUGIN, "SLAPI_SEARCH_FILTER",
"Complex search filter. See value of
SLAPI_SEARCH_STRFILTER.\n" );
break;
case LDAP_FILTER_EQUALITY:
slapi_log_error( SLAPI_LOG_PLUGIN, "SLAPI_SEARCH_FILTER",
"LDAP_FILTER_EQUALITY\n" );
break;
case LDAP_FILTER_GE:
slapi_log_error( SLAPI_LOG_PLUGIN, "SLAPI_SEARCH_FILTER",
"LDAP_FILTER_GE\n" );
break;
case LDAP_FILTER_LE:
slapi_log_error( SLAPI_LOG_PLUGIN, "SLAPI_SEARCH_FILTER",
"LDAP_FILTER_LE\n" );
break;
case LDAP_FILTER_APPROX:
slapi_log_error( SLAPI_LOG_PLUGIN, "SLAPI_SEARCH_FILTER",
"LDAP_FILTER_APPROX\n" );
break;
case LDAP_FILTER_SUBSTRINGS:
slapi_log_error( SLAPI_LOG_PLUGIN, "SLAPI_SEARCH_FILTER",
"LDAP_FILTER_SUBSTRINGS\n" );
/* For substring filters, get and log the attribute type and
the substrings in the filter */ slapi_filter_get_subfilt( filter, &attr_type, &substr_init,
&substr_any, &substr_final );
if ( attr_type != NULL )
slapi_log_error( SLAPI_LOG_PLUGIN, "\tAttribute type",
"%s\n", attr_type );
if ( substr_init != NULL )
slapi_log_error( SLAPI_LOG_PLUGIN, "\tInitial substring",
"%s\n", substr_init );
if ( substr_any != NULL ) {
for ( i = 0; substr_any[i] != NULL; i++ ) {
slapi_log_error( SLAPI_LOG_PLUGIN, "\tSubstring",
"# %d: %s\n", i, substr_any[i] );
} } if ( substr_final != NULL )
50 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 51
An Example Pre-Operation Plug-In
Code Example 4-1 Sample Pre-Operation Search and Initialization Functions (Continued)
slapi_log_error( SLAPI_LOG_PLUGIN, "\tFinal substring",
"%s\n", substr_final );
break;
case LDAP_FILTER_PRESENT:
slapi_log_error( SLAPI_LOG_PLUGIN, "SLAPI_SEARCH_FILTER",
"LDAP_FILTER_PRESENT\n" ); /* For presence filters, get and log the attribute type */ slapi_filter_get_type( filter, &attr_type ); if ( attr_type != NULL )
slapi_log_error( SLAPI_LOG_PLUGIN, "\tSearch for presence of attr",
"%s\n", attr_type );
break;
case LDAP_FILTER_EXTENDED:
slapi_log_error( SLAPI_LOG_PLUGIN, "SLAPI_SEARCH_FILTER",
"LDAP_FILTER_EXTENDED\n" ); break;
default:
slapi_log_error( SLAPI_LOG_PLUGIN, "SLAPI_SEARCH_FILTER", "Unknown filter type:
slapi_filter_get_choice returned %d\n", filter_type ); break;
} } /* For comparison filters, get and log the attribute type */ if ( filter_type == LDAP_FILTER_EQUALITY || LDAP_FILTER_GE ||
LDAP_FILTER_LE || LDAP_FILTER_APPROX ) { slapi_filter_get_ava( filter, &attr_type, &bval ); if ( ( attr_type != NULL ) && ( bval->bv_val != NULL ) ) {
slapi_log_error( SLAPI_LOG_PLUGIN, "\tAttribute type",
"%s\n", attr_type );
slapi_log_error( SLAPI_LOG_PLUGIN, "\tAttribute value",
"%s\n", bval->bv_val );
}
} /* Get and log the string representation of the filter */ if ( slapi_pblock_get(pb, SLAPI_SEARCH_STRFILTER, &filter_str) == 0 )
slapi_log_error( SLAPI_LOG_PLUGIN, "SLAPI_SEARCH_STRFILTER",
"%s\n", filter_str );
slapi_log_error( SLAPI_LOG_PLUGIN, "test_preop_search",
"*** DONE ***\n\n" );
return( 0 );
}
Compiling the Plug-In Example
On Solaris, you can use the following Makefile to compile the example. (This sample Makefile assume s that the source code is stored in you are compiling a plug-in named
srchxmpl.c and that
srchxmpl.so.)
Chapter 4 A Quick Example 51
Page 52
An Example Pre-Operation Plug-In
Code Example 4-2 Example Solaris Makefile
# SOLARIS Makefile for Directory Server plug-in examples # CC = cc LD = ld INCLUDE_FLAGS = -I../include CFLAGS = $(INCLUDE_FLAGS) -D_REENTRANT -KPIC LDFLAGS = -G OBJS = srchxmpl.o all: srchxmpl.so srchxmpl.so: $(OBJS)
$(LD) $(LDFLAGS) -o $@ $(OBJS)
.c.o:
$(CC) $(CFLAGS) -c $<
clean:
-rm -f $(OBJS) srchxmpl.so
On Windows platforms, make sure to link to the libslapd.lib import library (located under the
<server_root>\plugins\slapd\slapi\lib directory).
Registering the Plug-In Example
To register this example plug-in, you should d o th e following:
1. Create an LDIF confi gura tion file in an ASCII text editor; see “Creating a
Plug-In Configuration File,” on page 39.
2. Load the plug -i n configuration file; see “Loading the Plug-In Configuration
File,” on page 44.
3. Shut down the Directory Server.
4. Restart the Directo ry Server.
When you restart the Directory Server, it will read the entries in the file, which contain the entry for you new plug- in. If all is done correctly, your plug-in will now be loaded. (You may want to check the plug-ins list in the Directory Server Console.)
dse.ldif
52 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 53
An Example Pre-Operation Plug-In
Running the Plug-In Example
After compiling the plug-in and registering it with the Directory Server, you’re ready to make calls that are processed by the plug-in functions.
The first step is to restart the Directory Server and check the error log to see that the plug-in is properly registered. You should see the follo wing line in the error log:
Error log messsage here!
Verify that the Plugins log level is selected. (The sample source code logs messages to the error log with the Plugins severity level.)
If the plug-in is properly registered, you can then perform a few searches against the directory. The pre-operation search plug-in function should write data about each search to the error log.
Chapter 4 A Quick Example 53
Page 54
An Example Pre-Operation Plug-In
54 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 55
Basic Plug-In Programming
Chapter 5, “Front-End API Functions
Chapter 6, “Writing Pre/Post-Operation Plug-Ins”
Part 2
Techniques
Chapter 7, “Defining Functions for LDAP Operations”
Chapter 8, “Defining Functions for Authentication”
55
Page 56
56 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 57
Chapter 5
Front-End API Functions
The Netscape Directory Server (Directory Server) provides some general-purpose, front-end API functions that allow you to work wit h the en tries in the Directory Server. This chapter explains how to use the front-end API functions to accomplish various tasks; you can call these functions in your plug-in to interact with the client (for example, send results or result codes), log messages, and work with entries, attributes, and filters. While all of the functions described here must be used in conjunction with other API functions, understanding how these functions work will help you under stand how to program other plug-in API fu nc tions.
This chapter contains the following sections:
•Logging Messages
• Adding Notes to Access Log Entries
• Sending Data to the Client
• Determining if an Operation Was Abandoned
• Working with Entries, Attributes, and Values
•Working with DNs and RDNs
• Working with Search Filters
•Checking Passwords The front-end functions are declared in the
slapi-plugin.h header file.
57
Page 58
Logging Messages
Logging Messages
To write an error message to the error log, call th e slapi_new_condvar() function. For example, the following the error log:
slapi_log_error( SLAPI_LOG_PLUGIN, "searchdn_preop_search",
"*** PREOPERATION SEARCH PLUGIN ***\n");
This call will create the following message in the error log:
[01/Oct/1997:02:24:18 -0700] searchdn_preop_search \
- *** PREOPERATION SEARCH PLUGIN ***
Make sure that the Directory Server is configured to log messages that have the severity that you specify (for example, see “Setting the Log Level of the Server” on page 46.
slapi_log_error() function call writes a message in
SLAPI_LOG_PLUGIN). For more information,
Adding Notes to Access Log Entries
When the back-end database processes a search operation, it attempts to use indexes to narrow down the list of candidates matching the search criteria. If the back-end is unable to use indexes, it appends the following string to the access log entry for the search:
notes="U"
This note indicates that an unindexed search was performed. If you are writing your own back-end database search function, you ca n append
this note to access log entries by setting the the flag to be appended to access log entries. Currently, only value that you can set for this parameter. In future releases, additional flags will be defined. You will be able to use bitwise OR combinations of flags to specify different combinations of notes.
The server appends these notes and writes out the access log entries whenever sending a result or search entry back to the client.
SLAPI_OP_NOTE_UNINDEXED. This parameter identifies any notes that need
SLAPI_OPERATION_NOTES parameter to
SLAPI_OP_NOTE_UNINDEXED is the
58 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 59
Sending Data to the Client
Sometimes you might need to communicate various information directly back to the client. For example, you might want to do this in the following situations:
• If you need to send a result code back to the client (for example, to report an error or a successful result to an LDAP operation), call the
slapi_send_ldap_result() function.
• If you are fulfilling a search request and need to send matching entries back to the client, call the
• If you need to refer the LDAP request to a different LDAP server, call the
slapi_str2filter() function.
slapi_send_ldap_search_entry() function for each entry.
Sending Data to the Client
For example, the following statement sends an
LDAP_SUCCESS status code back to
the client.
slapi_send_ldap_result( pb, LDAP_SUCCESS, NULL, \
"The operation was processed successfully.\n", 0, NULL );
NOTE
It is important that you send only one result per operation back to the client.
Determining if an Operation Was Abandoned
At any point in time, the client can choose to abandon an LDAP operation. When writing database functions, keep in mind that you should periodically check to see if the operation has been abandoned.
To determine if an operation has been abandoned, call For example:
if ( slapi_op_abandoned( pb ) ) {
slapi_log_error( SLAPI_LOG_PLUGIN, "my_function",
"The operation was abandoned.\n" );
return 1;
}
slapi_op_abandoned().
Chapter 5 Front-End API Functions 59
Page 60
Working with Entries, Attributes, and Values
Working with Entries, Attributes, and Values
This section discusses how to create new entries in the di re ctory and how to convert them to LDIF and back.
In certain situations, you will need to pass directory entries between the front-end and the client. For example, it you create a custom add function, the front-end passes to your function an entry in the parameter block. When you perform a search operation, you return each matching search entry to the client.
When working with entries, you use the
Slapi_Entry datatype to get attribute
value pairs. The front-end routines listed in Table 5-1 are designed to help you manipulate entries passed in parameter blocks. These functions are described in more detail in the sections that follow the table.
Table 5-1 Front-End Functions for Manipulating Entries and Attributes
Front-end function Description
slapi_entry_alloc() Allocate memory for a new entry slapi_entry_dup() Copy an entry slapi_entry_free() Free an unused entry from memory slapi_filter_free()
slapi_str2entry() slapi_entry_get_dn()
slapi_entry_set_dn() slapi_entry_schema_check() Verify that an entry complies with the schema slapi_entry_first_attr()
slapi_entry_next_attr() slapi_entry_attr_find() Find the values for a specified attribute
Convert an entry to an LDIF str ing representation and vice versa
Get or set the DN for an entry
Get the attributes of an entry
slapi_entry_attr_merge_sv() Merge an attribute and its values into an
slapi_entry_add_values_sv() Add values to an attribute in an entry slapi_entry_delete_values_sv() Delete values from an attribute in an entry
60 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
entry
Page 61
Working with Entries, Attributes, and Values
Creating a New Entry
In some situations, you might need to create a new entry. There are two basic ways to do this:
• By allocating memory for a new entry To allocate memory for a new entry, call the
This function returns a pointer to a new entry of the opaque datatype
Slapi_Entry
. Once you create a new entry, you should call other front-end
slapi_entry_alloc() function.
routines to set the DN and attributes of the entry.
• By copying an existing entry To make a copy of an existing entry, call the
function returns a pointer to a new entry of the datat ype
slapi_entry_dup() routine. This
Slapi_Entry that
contains the copied data.
When you are finished using the entry, you should free it from memory by calling
slapi_entry_free() function.
the
Converting Between Entries and Strings
Entries can be stored in LDIF files. When stored in the se files, entr ies are converted into a string representation. The following format is the LDIF string representation for a directory entry:
dn:[:] <dn>\n [<attr>:[:] <value>\n] [<attr>:[:] <value>\n] [<space><continuedvalue>\n]* ...
If you want to continue the specificat ion of a value on additional lines (in other words, if the value wraps around to another line), use a single space (the ASCII 32 character) at the beginning of subsequent lines. For example:
dn: cn=Jane Doe
inski, ou=Accoun ting, o=ex ample.com
Refer to the Netscape Directory Server Administrator’s Guide for details on DN syntax.
Chapter 5 Front-End API Functions 61
Page 62
Working with Entries, Attributes, and Values
If a double-colon is used after a data type, it signifies that the value after the double-colon is encoded as a base-64 string. Data is sometimes encoded as a base-64 string. For example, it might be encoded this way if the value contains a non-printing character or newli ne.
To get the LDIF string representation of an entry (and vice versa), call the following functions:
• To convert an entry from the datatype representation, call the
slapi_filter_free() function.
Slapi_Entry to its LDIF string
This function returns the LDIF string representation of the entry or NULL if an error occurs. When you no longer need to use the string, you should free it from memory by calling the
slapi_ch_free() function.
• To convert an LDIF string representation back to an entry of the da tatype
Slapi_Entry
This function returns an entry of the datatype
, call the slapi_str2entry() function.
Slapi_Entry. If an error
occurred during the conversion process, the function returns NULL instead. When you are done working with the entry, y ou should call the
slapi_entry_free() function.
NOTE Calling
slapi_str2entry() modifies the value of the string
argument passed into the function (not a copy). If you s till want to use the string representation of the entry, make a copy of the string before calling this function.
Getting and Setting the DN of an Entry
You can call the following two front-end routines to get and set the DN for an entry:
• To get the DN for an entry, call the
• To set the DN for an entry, call the
Verifying Compliance with the Schema
Before you add or modify an entry in the database, you may want to verify that the new or changed entry still complies with the database schema.
62 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
slapi_entry_get_dn() function.
slapi_entry_set_dn() function.
Page 63
Working with Entries, Attributes, and Values
To see if an entry complies with the schema, call the
slapi_entry_schema_check() function.
Getting the Attribut es and Values of an Entry
There are two basic ways to obtain the attributes and values of an entry:
• You can iterate through the attributes of the entry, testing each one to see if it is the needed attribute.
• You can use the specific attribute.
Once you find the attribute you are looking for, use return the value of that attribute.
slapi_entry_attr_find() function to see if an entry has a
slapi_attr_value_find() to
Iterating Through the Attributes in an Entry
To iterate through the attributes associated with an entry, call the
slapi_entry_first_attr() function to get the first attribute of the entry. This
function returns a pointer to the first attribute in the entry. With a pointer to the attribute, you can test to see if it is the attribute you are interested in.
To retrieve the subsequent attributes in the entry, call passing to it the pointer to the current attribute in the function. Like pointer to the current attribute.
Once you find the attribute you need, you can retrieve its value using
slapi_attr_value_find().
slapi_entry_first_attr(), slapi_entry_next_attr() returns a
slapi_entry_next_attr(), cookie parameter of the
Finding a Specific Attr i bu te in an Entr y
To see if an entry contains a specific attribute, call slapi_entry_attr_find(). This function return 0 if the entry contains the attribute, -1 if it does not .
Adding and Removing Values
You can also call front-end routines to add or remove attributes and values in an entry. The front-end provides the following functionality:
• To add new values to an entry, call the function .
slapi_entry_add_values_sv()
Chapter 5 Front-End API Functions 63
Page 64
Working with DNs and RDNs
• To remove values from an entry, call slapi_entry_delete_values_sv().
• In certain situations, you may want to add an attribute and its values to an entry while not replacing any attribute values that already exist. To do this, call
slapi_entry_attr_merge_sv() function.
the
Working with DNs and RDNs
In certain situations, the front-end passes DNs to the back-end through the parameter block. For example, when calling the add function, the parameter block includes a parameter that specifies the DN of the new entry to be added.
If you need to manipulate DNs within parameter blocks, you can call the following front-end routines:
Table 5-2 Front-End Functions for Manipulating DNs
Function Description
slapi_dn_isroot() Determines if a DN is the root DN (the DN of the
privileged superuser)
slapi_dn_parent() slapi_dn_beparent()
slapi_dn_issuffix() Determines if a DN is the child of another DN slapi_dn_isbesuffix() Determines if a DN is a suffix served by one of
slapi_dn_normalize() Normalizes a DN slapi_dn_ignore_case() Converts all ch aracters in a DN to lowercase slapi_dn_normalize_case() Normalizes a DN and converts all characters to
Gets a copy of the parent DN
the server’s back-ends
lowercase
Determining if a DN is the Root DN
To determine if a DN is the root DN, call slapi_dn_isroot(). This function returns DN is not the root DN.
1 if the specified DN is the root DN of the local database. It returns 0 if the
64 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 65
Working with DNs and RDNs
Working with DN Suffixes
A suffix of a DN identifies a subtree in the directory tree where the DN is located. For example, consider the following DN:
cn=Babs Jensen, ou=Product Development, o=Example Corporation, c=US
In this case, one of the suffixes is:
o=Example Corporation, c=US
This suffix indicates that the Babs Jensen entry is located in the Example
Corporation
subtree in the directory tree.
To determine if a value is a suffix for a DN, call determine if a DN is one of the suffixes served by the back-end, call the
slapi_dn_isbesuffix() function.
slapi_dn_issuffix(). To
Server Suffixes
The suffix directive in the server configuration file specifies which DNs are served by a particular back-end. For example, suppose the suf f ix d irective is configured to the following:
suffix “o=Example Corporation, c=US”
Here, all entries within the “o=Example Corporation, c=US” subtree are served by this back-end.
Getting the Parent DN of a DN
To get a copy of the parent DN for a DN, call the slapi_dn_parent() function or the
slapi_dn_beparent() function.
These functions return the parent DN of
slapi_dn_beparent() will return NULL.
dn. If dn is a suffix served by the back-end,
When you are done working with the parent DN, you should free it from memory by calling
Normalizing a DN
If you need to compare DNs (for example, if you are searching your database for a particular DN), you should normalize the DNs that you are comparing to ensure that they are properly compared.
free().
Chapter 5 Front-End API Functions 65
Page 66
Working with Search Filters
You can use the following front-end function to normalize and convert the case of a DN:
•Use
•Use
•Use
slapi_dn_normalize() normalize a DN. slapi_dn_ignore_case() to convert all characters in a DN to lowercase. slapi_dn_normalize_case() to both normalize the DN and convert all
characters in the DN to lowercase.
NOTE These functions operate on the actual DN specified in the
argument, not a copy of the DN. If you want to modify a copy of the DN, call
slapi_ch_strdup() to make a copy of the DN.
Working with Search Filters
When a client requests an LDAP search operation, the front-end passes the search filter to the back-end as part of the parameter block. (The filter is passed through the
SLAPI_SEARCH_FILTER parameter. A string representation of the filter is also
available in the To manipulate search filters, call the following f ront-end routines:
SLAPI_SEARCH_STRFILTER parameter.)
Table 5-3 Front-End Functions for Manipulating Filters
Function Description
slapi_filter_test() Determine if an entry matches a filter’s criteria slapi_filter_get_choice() Get the filter type slapi_filter_get_ava() Get the attribute type and value used for
comparison in an attribute-value assertion filter (only applicable to the followin g searches:
LDAP_FILTER_EQUALITY, LDAP_FILTER_GE, LDAP_FILTER_LE, and LDAP_FILTER_APPROX)
slapi_filter_get_type() Get the type of attribute that the fil ter is
searching for (only applicable to
LDAP_FILTER_PRESENT searches)
slapi_filter_get_subfilt() Get the substring pattern used for the filter
(applicable only to LDAP_FILTER_SUBSTRING searches)
66 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 67
Working with Search Filters
Table 5-3 Front-End Functions for Manipulating Filters (Continued)
Function Description
slapi_str2filter() Convert a string representation of a filter to a
filter of the datatype Slapi_Filter
slapi_filter_join() Construct a ne w LDAP_FILTER_AND,
LDAP_FILTER_OR, or LDAP_FILTER_NOT
filter from other filters
slapi_filter_list_first(), slapi_filter_list_next()
slapi_filter_free() Free a filter from memory
Get the components of a filter (only applicable to LDAP_FILTER_AND, LDAP_FILTER_OR, and LDAP_FILTER_NOT searches)
Determining if an Entry Matches a Filter
After retrieving a filter from the SLAPI_SEARCH_FILTER parameter of the param eter block, you can call the
slapi_filter_test() function to determine if
entries in your database match the filter.
Getting the Filter Typ e
To determine the type of filter you are using, call slapi_filter_get_choice(). This function returns the filter type, which can be any one of the following values:
Table 5-4 Types of Filters
Filter Type Description
LDAP_FILTER_AND The search should find entries matching all filters that
LDAP_FILTER_OR The search should find entries matching any filter
LDAP_FILTER_NOT The search should find entries not matching the
LDAP_FILTER_EQUALITY The search should find entries that contain a value
LDAP_FILTER_SUBSTRINGS The search should find entries that contain a value
are specified in this complex filter.
specified in this complex filter.
specified filter.
equal to the specified attribute value.
matching the specified substrings.
Chapter 5 Front-End API Functions 67
Page 68
Working with Search Filters
Table 5-4 Types of Filters (Continued)
Filter Type Description
LDAP_FILTER_GE The search should find entries that contain a value
LDAP_FILTER_LE The search should find entries that contain a value less
LDAP_FILTER_PRESENT The search should find entries that contain the
LDAP_FILTER_APPROX The search should find entries that contain a value
Getting the Search Criteria
To get the search criteria specified by a search filter, call one of the following functions:
greater than or equal to the specified attribute value.
than or equal to the specified attribute value.
specified attribute.
approximately matching the specified attribute value.
• If the filter type is
LDAP_FILTER_LE
value used in the filter by calling
• If the filter type is the filter is searching for by calling the
• If the filter type is that the filter searches for by calling
• To get the components of a complex filter of th e type
LDAP_FILTER_OR
and
slapi_filter_list_next() functions.
LDAP_FILTER_EQUALITY, LDAP_FILTER_GE,
, or LDAP_FILTER_APPROX, you can get the attribute and
slapi_filter_get_ava().
LDAP_FILTER_PRESENT, you can get the attribute type that
slapi_filter_get_type() function.
LDAP_FILTER_SUBSTRINGS, you can get the attribute type
slapi_filter_get_subfilt().
LDAP_FILTER_AND,
, or LDAP_FILTER_NOT, call the slapi_filter_list_first()
Both of these functions will return either a filter compo nen t of the complex filter or a NULL value, according to the following:
❍ If slapi_list_first() returns a NULL, the complex filter is not of the
type
LDAP_FILTER_AND, LDAP_FILTER_OR, or LDAP_FILTER_NOT.
❍ If slapi_list_next() returns a NULL, the component returned by the
call is the last component in the complex filter.
NOTE You do not need to free the values returned by the
slapi_filter_get_ava(), slapi_filter_get_type(), and slapi_filter_get_subfilt() functions.
68 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 69
Checking Passwords
Converting a String to a Filter
A search filter can be represented by either the datatype Slapi_Filter or as a string. In a parameter block for a search operation, of the datatype
Slapi_Filter and SLAPI_SEARCH_STRFILTER is the string
representation of that filter. In general, it is easier to specify a filter as a string than it is to construct a filter from the type
Slapi_Filter.
SLAPI_SEARCH_FILTER is a filter
To convert the string representation of a filter into a filter of the datatype
Slapi_Filter
, call the slapi_str2filter() function.
When you are done working with the filter, yo u should free it by calling the
slapi_filter_free() function.
Creating Complex Filters by Combining Filters
You can use AND, OR and NOT to combine different filters to create a complex filter. To do this, call the
The
slapi_filter_join() function returns the complex filter you’ve created.
When you are done using the complex filter, you should free it by calling
slapi_filter_free().
Filters of the type (
ftype) is LDAP_FILTER_NOT, you must pass a NULL value for the second filter
when calling
LDAP_FILTER_NOT can have only one component. If the filter type
slapi_filter_join().
Checking Passwords
slapi_filter_join() function.
When Directory Server 4.x stores the password for an entry in the userpassword attribute, it encodes the password using the scheme sp ecifie d i n the directive of the configuration file. The scheme can be cleartext).
By default, Directory Server 6.x uses the credentials for an entry. The server encodes the password using the scheme specified in the attributes of the be any of the following:
•
CLEAR (means no encryp tion and can be defi ned using the clear-password-storage-scheme plug-in)
passwdhash
crypt or sha or “ “ (for
userpassword attribute to store the
nsslapd-rootpwstoragescheme or passwordStorageScheme
cn=config entry contained in the dse.ldif file. The scheme can
Chapter 5 Front-End API Functions 69
Page 70
Checking Passwords
• CRYPT (means Unix crypt algorithm and ca n be d efine d using the
crypt-password-storage-scheme plug-in) SHA (means Secure Hashing Algorithm and can be defined using the
•
sha
-password-storage-scheme plug-in)
•
SSHA (means Salted Secure Hashing Algorith m and can be defined using the ssha-password-storage-scheme plug-in)
To determine if a given password is one of the values of the attribute, call
slapi_pw_find_sv(). This function determines which password
userpassword
scheme was used to store the password and uses the appropriate comparison function to compare a given value against the encrypted values of the
userpassword attribute.
70 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 71
Chapter 6
Writing Pre/Post-Operation Plug-Ins
This chapter explains how to write functions that the Netscape Directory S e rver (Directory Server) calls before and after executing an LDAP operation. These functions are called pre-operation and post-operation plug-in functions.
• How Pre/Post-Operation Plug-Ins Wo rk
• Types Pre-Operation and Post-Operation Functions
• Registering Pre/Post-Operation Functions
How Pre/Post-Operation Plug-Ins Work
The Directory Server can perform the following LDAP operations: Bind, Unbind, Search, Modify, Add, Delete, Modify RDN, Compare, and Abandon.
NOTE The Directory Server can also perform extended operations as
defined in the LDAP v3 protocol. For information on implementing plug-in functions to execute extended operations, see Chapter 10, “Writing Extended Operation Plu g -I ns ”.
You can configure the Directory Server to call your custom plug-in functions before and after executing any of these LDAP operations.
For example, you can write a pre-operation function that validates an entry before the server performs an LDAP add operation. An example of a post-operation plug-in function would be one that sends a notification to a user after their entry has been modified by an LDAP modify operation.
71
Page 72
How Pre/Post-Operation Plug-Ins Work
You can also set up the Directory Server to call your own plug-in functions before and after:
• Sending an LDAP entry back to the client
• Sending an LDAP result code back to the client
• Sending an LDAP referral back to the client
Figure 6-1 illustrates how the Directory Server front-end calls pre-operation and post-operation functions before and after executing an LDAP operation.
When processing a request, the Directory Server will call all registered pre-operation functions before it calls the back-end to service the request. All pre-operation functions must return before the front-end calls the associated back-end function.
Figure 6-1 Calling Pre-Operation and Post-Operation Plug-In Functions
72 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 73
Types Pre-Operation and Post-Operation Functions
Types Pre-Operation and Post-Op eration Functions
As is the case with other server plug-in functions, pre-operation func tions and post-operation functions are specified in a parameter block that you can set on server startup. Each function corresponds to an ID in the parameter block. In your initialization function, you can call the the name of your function that correspond s to the pre-operation or post-operation function. For more information on the parameter block, see “Getting Data from the Parameter Block” on page 29.
Types of Pre-Operation Functions
Table 6-1 lists the Directory Server pre-operation functions and the purpose of each function.
slapi_pblock_set() function to specify
Table 6-1 Functions Called Before the Directory Server Executes an Operation
ID in Parameter Block Description
SLAPI_PLUGIN_PRE_BIND_FN Specifies the function called before the Directory Server
executes an LDAP bind operation. For information on writing this type of function, see “Processing an LDAP Bind Operation” on page 78.
SLAPI_PLUGIN_PRE_UNBIND_FN Specifies the function called before the Directory Server
executes an LDAP unbind operation. For information on writing this type of function, see “Processing an LDAP Unbind Operation” on page 79.
SLAPI_PLUGIN_PRE_SEARCH_FN Specifies the function called before the Directory Server
executes an LDAP search operation. For information on writing this type of function, see “Processing an LDAP Search Operation” on page 80.
SLAPI_PLUGIN_PRE_COMPARE_FN Specifies the function called before the Directory Server
executes an LDAP compare operation. For information on writing this type of function, see “Processing an LDAP Compare Operation” on page 84.
SLAPI_PLUGIN_PRE_ADD_FN Specifies the function called before the Directory Server
executes an LDAP add operation. For information on writing this type of function, see “Processing an LDAP Add Operation” on page 84.
Chapter 6 Writing Pre/Post-Operation Plug-Ins 73
Page 74
Types Pre-Operation and Post-Operation Functions
Table 6-1 Functions Called Before the Directory Server Executes an Operation (Continued)
ID in Parameter Block Description
SLAPI_PLUGIN_PRE_MODIFY_FN Specifies the function called before the Directory Server
executes an LDAP modify operation. For information on writing this type of func tion, see “P rocessing an LDAP Modify Operation” on page 86.
SLAPI_PLUGIN_PRE_MODRDN_FN Specifies the function called before the Directory Server
executes an LDAP modify RDN oper ation. Fo r inform ation o n writing this type of func tion, see “P rocessing an LDAP Modify RDN Operation” on page 87.
SLAPI_PLUGIN_PRE_DELETE_FN Specifies the function called before the Directory Server
executes an LDAP delete operation. For information on writing this type of function, see “Processing an LDAP Delete Operation” on page 89.
SLAPI_PLUGIN_PRE_ABANDON_FN Specifies the function called before the Directory Server
executes an LDAP abandon operation. For information on writing this type of function, see “Processing an LDAP Abandon Operation” on page 89.
SLAPI_PLUGIN_PRE_ENTRY_FN Specifies the function called before the Directory Server sends
an entry back to the client (for example, when you call slapi_send_ldap_search_entry(), the pre-operation entry function is called before the entry is sent back to the client).
SLAPI_PLUGIN_PRE_REFERRAL_FN Specifies the function called before the Directory Server
sends a referral back to the client (for example, when you call slapi_str2filter(), the pre-operation referral function is called before the referral is sent back to the client).
SLAPI_PLUGIN_PRE_RESULT_FN Specifies the function called before the Directory Server
sends a result code back to the client (for example, when you call slapi_send_ldap_result(), the pre-operation result function is called before the result code is sent back to the client).
Types of Post-Operation Functions
Table 6-2 lists the Directory Server post-operation functions and the purpose of each function.
74 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 75
Types Pre-Operation and Post-Operation Functions
Table 6-2 Functions Called After the Directory Server Executes an Operation
ID in Parameter Block Description
SLAPI_PLUGIN_POST_BIND_FN Specifies the function called after the Directory Server
executes an LDAP bind operation. For information on writing this type of function, see “Processing an LDAP Bind Operation” on page 78.
SLAPI_PLUGIN_POST_UNBIND_FN Specifies the function called after the Directory Server
executes an LDAP unbind operation. For information on writing this type of function, see “Processing an LDAP Unbind Operation” on page 79.
SLAPI_PLUGIN_POST_SEARCH_FN Specifies the function called after the Directory Server
executes an LDAP search operation. For information on writing this type of function, see “Processing an LDAP Search Operati on ” on page 80.
SLAPI_PLUGIN_POST_COMPARE_FN Specifies the function called after the Directory Server
executes an LDAP compare operation. For information on writing this type of function, see “Processing an LDAP Compare Operation” on page 84.
SLAPI_PLUGIN_POST_ADD_FN Specifies the function called after the Directory Server
executes an LDAP add o peration. For in formation on writing this type of function, see “Processing an LDAP Add Operation” on page 84.
SLAPI_PLUGIN_POST_MODIFY_FN Specifies the function called after the Directory Server
executes an LDAP modify operation. For information on writing this type of function, see “Processing an LDAP Modify Operation” on page 86.
SLAPI_PLUGIN_POST_MODRDN_FN Specifies the function called after the Directory Server
executes an LDAP modify RDN operation. For information on writing this type of function, see “Processing an LDAP Modify RDN Operation” on page 87.
SLAPI_PLUGIN_POST_DELETE_FN Specifies the function called after the Directory Server
executes an LDAP delete operation. For information on writing this type of function, see “Processing an LDAP Delete Operation” on page 89.
SLAPI_PLUGIN_POST_ABANDON_FN Specifies the function called after the Directory Server
executes an LDAP abandon operation. For information on writing this type of function, see “Processing an LDAP Abandon Operation” on page 89.
Chapter 6 Writing Pre/Post-Operation Plug-Ins 75
Page 76
Registering Pre/Post-Operation Functions
Table 6-2 Functions Called After the Directory Server Executes an Operation (Continued)
ID in Parameter Block Description
SLAPI_PLUGIN_POST_ENTRY_FN Specifies the function called after the Directory Server
sends an entry back to the client (for example, when you call slapi_send_ldap_search_entry(), the post-operati on entry functi on is called after the entry is sent back to the client).
SLAPI_PLUGIN_POST_REFERRAL_FN Specifies the function called after the Directory Server
sends a referral back to the client (for example, when you call slapi_str2filter(), the pre-operation referral function is called after the referral is sent back to the client).
SLAPI_PLUGIN_POST_RESULT_FN Specifies the function called after the Directory Server
sends a result code back to the client (for example, when you call slapi_send_ldap_result(), the pre-operation result function is called after the result code is sent back to the client).
Registering Pre/Post-Operation Functions
To register your pre-operation and post-operation plug-in functions, you need to write an initialization func tion and then configure the server to load your plug-in. For details, follow the procedures outlined in “Writing Plug-i n Initialization Functions” on page 32 and “Configuring Plug-Ins” on page 39.
76 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 77
Chapter 7
Defining Functions for LDAP
Operations
This chapter explains how to write pre-operation and po st- operation functions for specific LDAP operations. In general, the functions outlined here use a parameter block to pass information between the plug-in and the Netscape Directory Server (Directory Server). Because of this, these plug-in functions will pass a single argument, a parameter block defined by the data type information on this, see “Passing Data with Parameter Blocks” on page 28.
Slapi_PBlock. For more
This chapter outlines how to define plug-in functions to do the following:
• Specifying Start and Close Functions
• Processing an LDAP Bind Operation
• Processing an LDAP Unbind Opera tion
• Processing an LDAP Search Operation
• Processing an LDAP Compare Operation
• Processing an LDAP Add Operation
• Processing an LDAP Modify Operation
• Processing an LDAP Modify RDN Operation
• Processing an LDAP Dele te Operation
• Processing an LDAP Abandon Operation
77
Page 78
Specifying Start and Close Functions
Specifying Start and Close Functions
For each pre-operation and post-operation plug-in, you can specify the name of a function to be called after the server starts and before the server is shut down.
Use the following parameters to specify these functions:
SLAPI_PLUGIN_START_FN Specifies the function called after the Directory Server
starts up.
SLAPI_PLUGIN_CLOSE_FN Specifies the function called before the Directory Server
shuts down.
If you register multiple plug-ins with different start and close functions, the functions are called in the order that the plug-ins are registered (in other words, in the order that the
plugin directives appear in the server configuration file).
Processing an LDAP Bind Operation
When the Directory Server receives an LDAP bind request from a client, the front-end determines the DN that the client is attempting to bind as and the authentication method being used. The front-end also gets the credentials used for authentication, an d (if SASL is used for authe nticat ion), t he SASL mechan ism used.
Defining Functions for the Bind Operation
In the parameter block, the following parameters specify plug-in functions that are called in the process of executing a bind operation:
•The
•The
You register your plug-in function s by calling parameters in your initializa tion function. (For details, see “Registering Your Plug-In Functions” on page 34.)
SLAPI_PLUGIN_PRE_BIND_FN parameter specifies the pre-operation bind
function.
SLAPI_PLUGIN_POST_BIND_FN parameter specifies the post-operation bind
function.
slapi_pblock_set() to set these
78 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 79
Processing an LDAP Unbind Operation
Your pre-operation and post-operation bind functions should return 0 if successful. If the pre-operation function returns a non-zero value, the post-operation bind function is never cal led.
For information on defining a func tion that handles authentication, see Chapter 8, “Defining Functions for Authentication.”
Getting and Setting Parameters for the Bind Operation
The front-end makes this inform ation available to pre-operation and post-operation plug-in functions in the form of parameters in a parameter block.
Parameter ID Data Type Description
SLAPI_BIND_TARGET char * DN of the entry to bin d as. SLAPI_BIND_METHOD int Authentication method used, for example,
LDAP_AUTH_SIMPLE or LDAP_AUTH_SASL.
SLAPI_BIND_CREDENTIALS struct
berval *
SLAPI_BIND_RET_SASLCREDS struct
berval *
SLAPI_BIND_SASLMECHANISM char * SASL mechanism used, for example,
Note that i f the
SLAPI_BIND_SASLMECHANISM parameter is empty, simple
Credentials from the bind request.
Credentials that you want sent back to the client. Set this before calling
slapi_send_ldap_result().
LDAP_SASL_EXTERNAL.
authentication was used and simple credentials were provided.
Processing an LDAP Unbind Oper ation
When the Directory Server receives an LDAP unbind request from a client, the front-end calls the unbind function for each back-end. No operation-specific parameters are placed in the parameter block that is passed to the unbind function.
In the parameter block, the following parameters specify plug-in functions that are called in the process of executing an unbind operation:
Chapter 7 Defining Functions for LDAP Operations 79
Page 80
Processing an LDAP Search Operation
•The SLAPI_PLUGIN_PRE_UNBIND_FN parameter specifies the pre-operation unbind function.
•The
SLAPI_PLUGIN_POST_UNBIND_FN parameter specifies the post-operation
unbind function.
You set these parameters to the names of your functio ns by calling
slapi_pblock_set().
Your plug-in functions should return 0 if successful. If the pre-operation function returns a non-zero value, the post-operation unbind function is never called.
Processing an LDAP Search Operation
The server processes an LDAP search operation in two stages:
• First, the server gets a list of candidate entries, using an index (if applicable). For example, for a search filter that finds entries where “
checks the index for the “ start with “
a”, and generates a list of matching entries.
mail” attribute (if the index exists), finds the keys that
If no applicable index exists, all entries are considered to be candid a tes. To get the list of candidates, the server calls the backend search function. For
details, see “Getting the List of Candidates” on page 81.
mail=a*”, the server
• Next, the server iterates through each candidate in the list and determines if the candidate matches the search criteria.
If an entry matches the criteria, the server sends the entry to the client. To check each candidate, the server calls the backend “next candidate”
function for each candidate in the list. For details, see “Iterating Through Candidates” on page 82.
The rest of this section explains these stages in more detail.
80 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 81
Processing an LDAP Search Operation
Getting the List of Candidates
When the Directory Server receives an LDAP search request, the front-end gets information about the search (such as the scope and base DN). The front-end normalizes the base DN (by calling the determines if the base DN identifies a DSA-specific entry (DSE). If so, the front-end handles the search request directly and does not pass it to the backend search function.
If the base DN is not a DSE, the front-end finds the back-end that services the suffix specified in the base DN. The front-end then pas ses the search criteria to the search function for that back-end.
The front-end makes this inform ation available to pre-operation and post-operation plug-in functions in the form of parameters in a parameter block.
Parameter ID Data Type Description
SLAPI_SEARCH_TARGET char * DN of the base entry in the search
slapi_dn_normalize() function) and
operation (the starting point of the search).
SLAPI_SEARCH_SCOPE int The scope of the search. The
scope can be one of the following values:
• LDAP_SCOPE_BASE
• LDAP_SCOPE_ONELEVEL
• LDAP_SCOPE_SUBTREE
SLAPI_SEARCH_DEREF int Method for handling aliases in a
search. This method can be one of the following values:
• LDAP_DEREF_NEVER
• LDAP_DEREF_SEARCHING
• LDAP_DEREF_FINDING
• LDAP_DEREF_ALWAYS
SLAPI_SEARCH_SIZELIMIT int Maximum number of entries to
return in the search resul ts.
SLAPI_SEARCH_TIMELIMIT int Maximum amount of time (in
seconds) allowed for the sea rch operation.
Chapter 7 Defining Functions for LDAP Operations 81
Page 82
Processing an LDAP Search Operation
Parameter ID Data Type Description
SLAPI_SEARCH_FILTER Slapi_Filter * Slapi_Filter struct (an
SLAPI_SEARCH_STRFILTER char * String representation of the filter
SLAPI_SEARCH_ATTRS char ** Array of attribute types to be
SLAPI_SEARCH_ATTRSONLY int Specifies whether the search
opaque data structure) representing the filter to be used in the search.
to be used in the search.
returned in the search results.
results return attribute types only or attribute types and values. ( 0 means return both at tr ib u tes an d values; 1 means return attribute types only)
Your search function should return 0 if successful. Call the slapi_pblock_set() function to assign the set of search results to the
SLAPI_SEARCH_RESULT_SET
parameter in the parameter block. The front-end then uses this function in conjunction with the “next entry” function
(see “Iterating Through Candidates” on page 82) to iterate through the result set. The front-end sends each re sult back to the client and continues updates the
SLAPI_NENTRIES parameter with the current number of entries sent back to the
client. If a result is actually a referral, the front-end sends the referral back to the client
and updates the
SLAPI_SEARCH_REFERRALS parameter with the list of referral
URLs. Finally, after sending the last entry to the client, the front-end sends an LDAP
result message specifying the number of entries found.
Iterating Through Cand idates
In addition to the parameters specified in “Processing an LDAP Search Operation” on page 80, the “nex t entry” funct ion has access to the f ollow ing par ameter s (whic h are set by the front-end and the back-end during the course of executing a search operation):
82 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 83
Processing an LDAP Search Operation
Parameter ID Data Type Description
SLAPI_SEARCH_RESULT_SET void * Set of search results. SLAPI_SEARCH_RESULT_ENTRY void * Entry returned from iterating
through the results set. This “next entry” function actua lly sets this paramet er.
SLAPI_SEARCH_RESULT_ENTRY_EXT void * (Netscape Directory Server 4.x)
Reserved for future use. The context identifying the last
result sent in the results set. This “next entry” function actually sets this parameter.
SLAPI_NENTRIES int Number of search results found SLAPI_SEARCH_REFERRALS struct
berval **
Array of the URLs to other LDAP servers that the current server is referring the client to
The “next entry” function should get the next result specified in the set of results in the parameter as the value of the
SLAPI_SEARCH_RESULT_SET. The function should set this next entry
SLAPI_SEARCH_RESULT_ENTRY parameter in the parameter
block, and the “next entry” function should return 0 if successful. The “next entry” function should set the
SLAPI_SEARCH_RESULT_ENTRY parameter
to NULL and return -1 if one of the following situations occurs :
• The operation is abandoned (you can check this by calling the
slapi_op_abandoned() function)
• The time limit has been exceeded
• The maximum number of entries has been exceeded If no more entries exist in the set of results, the “next entry” function should set the
SLAPI_SEARCH_RESULT_ENTRY parameter to NULL and return 0.
Chapter 7 Defining Functions for LDAP Operations 83
Page 84
Processing an LDAP Compare Operation
Processing an LDAP Compare Operation
When the Directory Server receives an LDAP compare request from a client, the front-end gets the DN of the entry being compared and the attribute and value being used in the comparison.
The front-end makes this information available to pre-operation and post-operation plug-in functions in the form of parameters in a parameter block.
Parameter ID Data Type Description
SLAPI_COMPARE_TARGET char * DN of the entry to be compared. SLAPI_COMPARE_TYPE char * Attribute type to use in the comparison. SLAPI_COMPARE_VALUE struct
berval *
The compare function should call
LDAP_COMPARE_TRUE if the specified value is equal to the value of the entry’s
attribute or
LDAP_COMPARE_FALSE if the values are not equal.
slapi_send_ldap_result() to send
Attribute value to use in the comparison
If successful, the compare function should return 0. If an erro r occurs (f or exam ple, if the specified attribute doesn’t exist), the compare fun ct ion should call
slapi_send_ldap_result() to send an LDAP error code and should return 1.
Processing an LDAP Add Operation
When the Directory Server receives an LDAP add request from a client, the front-end normalizes the DN of the new entry. The front-end makes this information available to pre-operation and post-operation plug-in functions in the form of parameters in a parameter block.
Parameter ID Data Type Description
SLAPI_ADD_TARGET char * DN of the entry to be added. SLAPI_ADD_ENTRY Slapi_Entry * The entry to be added (specified as the
84 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
opaque Slapi_Entry datatype).
Page 85
Processing an LDAP Add Operation
The add function should check the following:
• If the operation has been abandoned, the function should return -1. (You do not need to call
slapi_send_ldap_result() to send an LDAP error code to
the client. According to the LDAP protocol, the client does not expect a server response after an operation is abandoned.)
• If the entry already exists in the database, the function should call
slapi_send_ldap_result() to send an LDAP error code LDAP_ALREADY_EXISTS and should return -1.
• If the parent entry (or the closest matching entry) is a referral entry (an entry with the object class “ref”) and no manageDSAIT control is included with the request, the function should call
slapi_str2filter() to send a referral and
return -1. To determine if a manageDSAIT control is present, call
to get the value of the
SLAPI_MANAGEDSAIT parameter. If the value is 1, the
slapi_pblock_get()
control is included in the request. If 0, the control is not included in the request.
• If the parent entry does not exist, the function should call
slapi_send_ldap_result() to send an LDAP error code LDAP_NO_SUCH_OBJECT and return -1.
• If the entry is not schema-compliant (call determine this), the function should call the LDAP error code
LDAP_OBJECT_CLASS_VIOLATION and should return -1.
slapi_entry_schema_check() to
slapi_send_ldap_result() to send
• If the requestor does not have permission to add the entry (call
slapi_access_allowed() to determine this), the function should call slapi_send_ldap_result() to send the LDAP error code LDAP_INSUFFICIENT_ACCESS and should return -1.
You should also verify that the ACI syntax for the entry is correct (call
slapi_acl_check_mods() to determine this).
If the add function is successful, the function should call
slapi_send_ldap_result() to send an LDAP_SUCCESS code back to the client
and should return 0.
Chapter 7 Defining Functions for LDAP Operations 85
Page 86
Processing an LDAP Modify Operation
Processing an LDAP Modify Operation
When the Directory Server receives an LDAP modify request from a client, the front-end gets the DN of the entry to be modified and the modifications to be made. The front-end makes this information available to pre-operation and post-operation plug-in functions in the form of parameters in a parameter block.
Parameter ID Data Type Description
SLAPI_MODIFY_TARGET char * DN of the entry to be modified. SLAPI_MODIFY_MODS LDAPMod ** A NULL-terminated array of LDAPMod
structures, which represent the modifications to be performed on the entry.
The modify function should check the following:
• If the operation has been abandoned, the function should return -1. (You do not need to call slapi_send_ldap_result() to send an LDAP error code to the client. According to the LDAP protocol, the client does not expect a server response after an operation is abandoned.)
• If the entry is a referral entry (an entry with the object class “ref”) and no manageDSAIT control is included with the request, the function should call
slapi_str2filter() to send a referral and return -1.
To determine if a manageDSAIT control is present, call to get the value of the
SLAPI_MANAGEDSAIT parameter. If the value is 1, the
slapi_pblock_get()
control is included in the request. If 0, the control is not included in the request.
• If the entry does not exist, check the following:
❍ If the closest matching entry is a referral entry and if no manageDSAIT
control is included in the request, the function should call
slapi_send_ldap_referral() to send a referral and return -1.
❍ Oth e rwise, the function should call slapi_send_ldap_result() to send
an LDAP error code
• If the entry is not schema-compliant (call determine this), the function should call the LDAP error code
LDAP_NO_SUCH_OBJECT and return -1.
slapi_entry_schema_check() to
slapi_send_ldap_result() to send
LDAP_OBJECT_CLASS_VIOLATION and should return -1.
86 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 87
Processing an LDAP Modify RDN Operation
• If the RDN of the entry contains attribute values th at are not part of th e entry (for example, if the RDN is “uid=bje nsen” but the entry has no uid value or has a different uid value), the function should call send the LDAP error code
LDAP_NOT_ALLOWED_ON_RDN and should return
slapi_send_ldap_result() to
-1.
• If the requestor does not have permission to modify the entry (call
slapi_access_allowed() to determine this), the function should call slapi_send_ldap_result() to send the LDAP error code LDAP_INSUFFICIENT_ACCESS and should return -1.
You should also verify that the ACI syntax for the entry is correct (call
slapi_acl_check_mods() to determine this).
If the modify function is successful, the function should call
slapi_send_ldap_result() to send an LDAP_SUCCESS code back to the client
and should return 0.
Processing an LDAP Modify RDN Operation
When the Directory Server receives an LDAP modify RDN request from a client, the front-end gets the original DN of the entry, the new RDN, and (if the entry is moving to a different location in the directory tree) the DN of the new parent of the entry.
The front-end makes this inform ation available to pre-operation and post-operation plug-in functions in the form of parameters in a parameter block.
Parameter ID Data Type Description
SLAPI_MODRDN_TARGET char * DN of the entry that you want to
rename.
SLAPI_MODRDN_NEWRDN char * New RDN to assign to the en try. SLAPI_MODRDN_DELOLDRDN int Specifies whether or not you want to
delete the old RDN. (0 means don’t delete the old RDN; 1 means delete the old RDN)
SLAPI_MODRDN_NEWSUPERIOR char * DN of the new parent of the entry, if
the entry is being moved to a new location in the directory tree.
Chapter 7 Defining Functions for LDAP Operations 87
Page 88
Processing an LDAP Modify RDN Operation
The modify RDN function should check the following:
• If the operation has been abandoned, the function should return -1. (You do not need to call the client. According to the LDAP protocol, the client does not expect a server response after an operation is abandoned.)
• If the entry is a referral entry (an entry with the object class “ref”) and no manageDSAIT control is included with the request, the function should call
slapi_str2filter() to send a referral and return -1.
slapi_send_ldap_result() to send an LDAP error code to
To determine if a manageDSAIT control is present, call to get the value of the
SLAPI_MANAGEDSAIT parameter. If the value is 1, the
slapi_pblock_get()
control is included in the request. If 0, the control is not included in the request.
• If the entry does not exist, check the following:
❍ If the closest matching entry is a referral entry and if no manageDSAIT
control is included in the request, the function should call
slapi_send_ldap_referral() to send a referral and return -1.
❍ Oth e rwise, the function should call slapi_send_ldap_result() to send
an LDAP error code
• If the entry is not schema-compliant (call determine this), the function should call the LDAP error code
LDAP_NO_SUCH_OBJECT and return -1.
slapi_entry_schema_check() to
slapi_send_ldap_result() to send
LDAP_OBJECT_CLASS_VIOLATION and should return -1.
• If the RDN of the entry contains attribute values that are not part of the entry (for example, if the RDN is “uid=bje nsen” but the entry has no uid value or has a different uid value), the function should call send the LDAP error code
LDAP_NOT_ALLOWED_ON_RDN and should return
slapi_send_ldap_result() to
-1.
• If the requestor does not have permission to modify the entry (call
slapi_access_allowed() to determine this), the function should call slapi_send_ldap_result() to send the LDAP error code LDAP_INSUFFICIENT_ACCESS and should return -1.
You should also verify that the ACI syntax for the entry is correct (call
slapi_acl_check_mods() to determine this).
If the modify RDN function is succes sf ul, the function should call
slapi_send_ldap_result() to send an LDAP_SUCCESS code back to the client
and should return 0.
88 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 89
Processing an LDAP Delete Operation
Processing an LDAP Delete Operation
When the Directory Server receives an LDAP delete request from a client, the front-end gets the DN of the entry to be removed from the directory. The front-end makes this information ava ilable to pre-operation and post-operation plug-in functions in the form of parameters in a parameter block .
Parameter ID Data Type Description
SLAPI_DELETE_TARGET char * DN of the entry to delete.
If the delete function is successful, it should return 0.
Processing an LDAP Abandon Operation
When the Directory Server receives an LDAP abandon request from a client, the front-end gets the message ID of the operation that should be abandoned. The front-end makes this information available to pre-operation and post-operation plug-in functions in the form of parameters in a parameter block.
Parameter ID Data Type Description
SLAPI_ABANDON_MSGID unsigned long Message ID of the operation to
abandon.
Chapter 7 Defining Functions for LDAP Operations 89
Page 90
Processing an LDAP Abandon Operation
90 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 91
Chapter 8
Defining Functions for Authentication
This chapter explains how to write a plug-in function to bypass or replace the standard function for authentication with your own f unction.
Information on authentication with the Netscape Directory Server (Directory Server) is organized in the following sections:
• Understanding Authentication Me thods
• How the Directory Server Identifies Clients
• How the Authentication Process Works
• Writing Your Own Authentication Plug-in
• Writing a Pre-Operation Bind Plug-in
• Using SASL with an LDAP Client
Understanding Authentication Methods
Authentication methods for LDAP is described in RFC 2829, which you can find at this location:
Two methods that you can use to authenticate clients are simple authentication and SASL authentication:
• Simple authentication is de scribed in RFC 2251, which you can find at this location:
Simple authentication provides minimal facilities for authentication. In the simple authentication method, clients send a DN and password to the server for authentication. The server compares the password sent by the client against the password stored in the client’s directory entry.
http://www.ietf.org/rfc/rfc2829.txt
http://www.ietf.org/rfc/rfc2251.txt
91
Page 92
How the Directory Server Identifies Clients
• Simple Authentication and Security Layer (SASL) is described in RFC 2222, which you can find a t this location:
http://www.ietf.org/rfc/rfc2222.txt
SASL provides the means to use mechanisms other than simple authentication and SSL to authenticate to the Directory Server.
How the Directory Server Identifies Clients
The server keeps track of the identity of the LDAP client through the
SLAPI_CONN_DN and SLAPI_CONN_AUTHTYPE parameters.
During an LDAP bind operation, the server authenticates the user and puts the DN and authenticated method in the parameters.
When an authenticated client requests the server to perform an LDAP operation, the server checks the DN in the client has the appropriate access rights.
SLAPI_CONN_DN and SLAPI_CONN_AUTHTYPE
SLAPI_CONN_DN parameter to determine if the
How the Authentication Process Works
When the Directory Server receives an LDAP bind request from a client, it processes the request in the following steps:
1. The server parses the LDAP bind request and retrieves the following
information:
❍ The D N that the client is attempting to authenticate as ❍ The met ho d of authentication used ❍ Any credentials (such as a password) included in the request
If the method of authentication is server also retrieves the name of the SASL mechanism used from the LDAP bind request.
2. The server normalizes the DN retrieved from the request. (See the
slapi_dn_normalize() function for more information on normalized DNs.)
3. The server retrieves any LDAP v3 controls included with the LDAP bind
request.
LDAP_AUTH_SASL (SASL authentication), the
92 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 93
How the Authentication Process Works
4. If the method of auth entica tion is LDAP_AUTH_SASL (SASL authentication), the
server determines whether or not the SASL mechanism (specified in the request) is supported.
If the SASL mechanism is not supported by the server, the server sends an
LDAP_AUTH_METHOD_NOT_SUPPORTED
result code back to the cli ent and ends the
processing of the bind request.
5. If the method of auth entica tion is LDAP_AUTH_SIMPLE (simple authentication),
the server checks if the DN is an empty string or if there are no credentials. If the DN is an empty string, if the DN is not specified, or if no credentials are
specified, the server assumes that the client is binding anonymously and sends an
LDAP_SUCCESS result code back to the client.
The DN and authentication method for the connection (which are used to determine access rights for all operations performed through the connection) are left as NULL and
6. If the DN specified in the request is not served by this Directory Server (for
example, if the DN is root of the server is
SLAPD_AUTH_NONE, respectively.
“uid=moxcross, o=netscape.com” and the directory
“o=example.com”), the server sends one of the following
two results back to the client and ends the processing of the bind request:
❍ If the server is configured with a default referral (an LDAP URL
identifying an LDAP server that handles referrals), the server sends an
LDAP_REFERRAL
result code back to the client (LDAP_PARTIAL_RESULTS if
the client only supports the LDAP v2 protocol).
❍ If the server is not configured with a default referral, the server sends an
LDAP_NO_SUCH_OBJECT
result code back to the client.
7. The server puts the information from the bind request into the parameter
block:
❍ SLAPI_BIND_TARGET is set to the DN that the client is authenticating as. ❍ SLAPI_BIND_METHOD is set to the auth entica tion method (for example,
LDAP_AUTH_SIMPLE or LDAP_AUTH_SASL).
❍ SLAPI_BIND_CREDENTIALS is set to the credentials (for example, the
password) included in the request.
❍ SLAPI_BIND_SASLMECHANISM (if the authentication m ethod is
LDAP_AUTH_SASL
) is set to the name of the SASL mechanism that the client
is using for authentication.
8. If the DN is the root DN or the update DN (the DN of the master entity
responsible for replicating the directory), the server authenticates the client.
Chapter 8 Defining Functions for Authentication 93
Page 94
How the Authentication Process Works
❍ If the credentials are correct, the server sets the SLAPI_CONN_DN
parameter to the DN and the SLAPI_CONN_AUTHTYPE parameter to
LDAP_AUTH_SIMPLE
to the client and ends the processing of the bind request.
❍ If the credentials are incorrect, the server sends an
LDAP_INVALID_CREDENTIALS
processing of the bind request.
9. The server calls any pre-operation bind plug-in functions. If the function
returns a non-zero value, the server ends the processing of the bind request. If you are writing your own plug-in fun c tion to handle authentication, you
should return a non-zero value so that the server does not attempt to co ntinue processing the bind request.
10. The server calls the backend bind function. The bind function returns one of
the following values:
❍ If the function returns a non-zero value (SLAPI_BIND_FAIL_OR_ANONYMOUS
in Netscape Directory Server 4.x), the server ends the processing of the bind request. The bind function is responsible for sending the appropriate result code back to the client before returning a non-zero value.
. The server sends an LDAP_SUCCESS result code back
result code back to the client and ends the
❍ If the function returns 0 (SLAPI_BIND_SUCCESS in Netscape Directory
Server 4.x), the server continues processing the bind request. The server sends the
LDAP_SUCCESS result code back to the client. (The bind function
does not do this.)
11. If the backend bind function succeeds, the server sets the SLAPI_CONN_DN
parameter to the DN and the SLAPI_CONN_AUTHTYPE parameter to the authentication method.
12. The server sends an LDAP_SUCCESS result code back to the client and ends the
processing of the bind request. If the client’s password is going to expire, the server includes a “password
expiring” control (with the OID 2.16.840.1.113730.3.4.5) with the result sent to the client. If the client is logging in for the first time and needs to change the password, the server includes a “password expired” control (with the OID
2.16.840.1.113730.3.4.4) with the result sent to the client.
94 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 95
Writing Your Own Authentication Plug-in
Writing Your Own Authenti cation Plug-in
A situation may arise in which you may want to write and implement your own function for authentication; that is, replace the standard m e an s of authentication with your own function. You can write a pre-operation bind plug-in function (a function that the server calls before processing an LDAP bind request) that performs the authentication and bypasses the default bind function al ity. For details, see the next section, “Writing a Pre-Operation Bind Plug-in” on page 95.
Writing a Pre-Operation Bind Plug-in
You can define your own pre-operation bind plug-in fu nc tion to authentica te LDAP clients. The server will call your function during the authentication process (in Step 9). Your function should return a non-zero value to bypass the default backend bind function and the post-operation bind functions.
Note that this means that Step 10 through Step 12 are skipped. Your pre-operation plug-in function is responsible for sending the result code to the client and for setting the DN and authentication method for the conn ection.
Figure 8-1 summarizes the process of using a pre-operation bind plug-in function to authenticate LDAP clients to the Directory Server.
Chapter 8 Defining Functions for Authentication 95
Page 96
Writing a Pre-Operation Bind Plug-in
Figure 8-1 Using a Pre-Operation Bind Plug-In Function to Handle Authentication
Figure 8-2 illustrates the steps that your pre-operation bind plug-in function must take to authenticate LDAP clients to the Directory Server.
96 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 97
Writing a Pre-Operation Bind Plug-in
Figure 8-2 How Your Pre-Operation Bind Plug-In Function Can Authenticate LDAP
Clients
Defining Your Authentication Function
The following sections cover guidelin es that you can follow when defining your authentication function:
• Getting and Checking the Bind Parameters
• Getting the Entry and Checking the Credentials
• What to Do If Authentication Fail s
• What to Do If Authentication Succeeds
NOTE Be sure to check this source file for an example of a pre-operation
plug-in function that handles authentication:
<server_root>/plugins/slapd/slapi/examples/testbind.c
Getting and Checking the Bind Parameters
Call the slapi_pblock_get() function to get the values of the following parameters:
SLAPI_BIND_TARGET (a string value specifying the DN that the client is
• attempting to authenticate as)
•
SLAPI_BIND_METHOD (an integer value specifying the authentication method,
such as
LDAP_AUTH_SIMPLE or LDAP_AUTH_SASL)
Chapter 8 Defining Functions for Authentication 97
Page 98
Writing a Pre-Operation Bind Plug-in
• SLAPI_BIND_CREDENTIALS (a berval structure containing the credentials sent by the client)
If you plan to support authentication th rough SASL mechanisms, you should also get the value of the specifying the name of the SASL mechanism to use for authentication).
Make sure to check the following:
• Determine if the client is requesting to bind as an anonymous user. If the
SLAPI_BIND_CREDENTIALS parameter is empty or NULL, the client is
attempting to bind anonymously. Call
back to the client.
SLAPI_BIND_SASLMECHANISM parameter (a string value
SLAPI_BIND_METHOD parameter is LDAP_AUTH_SIMPLE and the
slapi_send_ldap_result() to send the LDAP result code LDAP_SUCCESS
•If the
SLAPI_BIND_METHOD parameter specifies a method that you do not
recognize or support, call
LDAP_STRONG_AUTH_NOT_SUPPORTED result code back to the client.
slapi_send_ldap_result() to send an
In both cases, return a non-zero value to prevent the server from calling the default backend function for authentication.
Getting the Entry and Checking the Credentials
Get the entry for the DN specified by the SLAPI_BIND_TARGET parameter and compare the credentials in the known credentials for that entry.
By default, Directory Server 4.x uses the credentials for an entry. The server encodes the password using the scheme specified in the scheme can be
passwdhash directive of the slapd.conf configuration file. The
crypt or sha or “ “ (for cleartext).
By default, Directory Server 6.x uses the credentials for an entry. The server encodes the password using the scheme specified in the attributes of the
nsslapd-rootpwstoragescheme or passwordStorageScheme
cn=config entry contained in the dse.ldif file. The scheme can
be any of the following:
SLAPI_BIND_CREDENTIALS parameter against the
userpassword attribute to store the
userpassword attribute to store the
CLEAR (means no encryp tion and can be defi ned using the
•
clear-password-storage-scheme plug-in)
•
CRYPT (means Unix crypt algorithm and can be define d using the crypt-password-storage-scheme plug-in)
98 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Page 99
Writing a Pre-Operation Bind Plug-in
• SHA (means Secure Hashing Algorithm and can be defined using the
sha
-password-storage-scheme plug-in)
SSHA (means Salted Secure Hashing Algorith m and can be defined using the
•
ssha-password-storage-scheme plug-in)
If you need to compare the client’s credentials against the value of the
userpassword attribute, you can call the slapi_pw_find_sv() function. This
function determines whi c h password scheme was used to store the password and uses the appropriate comparison function to compare a given value against the encrypted value of the
userpassword attribute.
What to Do If Authentication Fails
If authentication fails, send one of the following result codes back to the client:
• If no entry matches the DN specified by the client, send an
LDAP_NO_SUCH_OBJECT result code back to the client.
When calling the back to the client, specify the closest matching DN as th e
slapi_send_ldap_result() function to send the result code
matched argument.
• If the client fails to provide the necessary cre dentials or if cred entials cannot be found in the entry, send an
LDAP_INAPPROPRIATE_AUTH result code back to the
client.
• If the credentials specified by the client do not match the credentials found in the entry, send an
• If a general error occurs, send an
LDAP_INVALID_CREDENTIALS result code back to the client.
LDAP_OPERATIONS_ERROR result code back to
the client.
Your function should also return a non-zero value (
SLAPI_BIND_FAIL_OR_ANONYMOUS in Netscape Directory Server 4.x).
You do not need to set any values for the
SLAPI_CONN_AUTHTYPE
and
LDAP_AUTH_NONE, which indicate that the client has bound anonymously.
parameter. By default, these parameters are set to NULL
SLAPI_CONN_DN parameter and the
What to Do If Authentication Succeeds
If the authentication is successful, your authentica tion function should do the following:
• Call and the method.
slapi_pblock_set() to set the values of the SLAPI_CONN_DN parameter
SLAPI_CONN_AUTHTYPE parameter to the DN and authentication
Chapter 8 Defining Functions for Authentication 99
Page 100
Writing a Pre-Operation Bind Plug-in
This sets the DN and authentication method for the connection to the clien t. (The server uses this DN and method in subsequent operations when checking access rights.)
You can set
❍ SLAPD_AUTH_NONE represents no authentication. (The client is binding
SLAPI_CONN_AUTHTYPE to one of the following values:
anonymously.)
❍ SLAPD_AUTH_SIMPLE represents the simple authentication method. ❍ SLAPD_AUTH_SSL represents authentication through SSL. ❍ SLAPD_AUTH_SASL represents SASL authentication.
Note that these values differ from the values in the parameter. The values listed above are string values defined in the
slapi-plugin.h
parameter (such as values defined in the
header file, whereas the values of the SLAPI_BIND_METHOD
LDAP_AUTH_SIMPLE and LDAP_AUTH_SASL) are integer
ldap.h header file.
SLAPI_BIND_METHOD
• If you want to, specify the credentials that you want sent back to the client. If the value of the
you want to return a set of credentials to the client, call to set the
SLAPI_BIND_RET_SASLCREDS parameter to the credentials.
SLAPI_BIND_METHOD parameter is LDAP_AUTH_SASL and
slapi_pblock_set()
• Send the result of the authentication process back to the client.
slapi_send_ldap_result() to send an LDAP_SUCCESS return code to
Call the client.
Make sure that your function returns a non-zero value to bypass the default backend bind function and any post-operation plug-in functions.
Registering the SASL Mechanism
If you are using SASL as the authentication method, you need to register the SASL mechanisms t hat you plan to use.
In your initialization function (see “Writing Plug-in Initialization Functions” on page 32), call the of the SASL mechanism. For example:
slapi_register_supported_saslmechanism( "babsmechanism" );
100 Netscape Directory Server Plug-In Programmer’s Guide • December 2003
Functions for Syntax Plug-In function and specify the name
Loading...