]> git.sur5r.net Git - openldap/commitdiff
Remove or #ifdef experimental features
authorKurt Zeilenga <kurt@openldap.org>
Mon, 18 Feb 2002 20:16:53 +0000 (20:16 +0000)
committerKurt Zeilenga <kurt@openldap.org>
Mon, 18 Feb 2002 20:16:53 +0000 (20:16 +0000)
include/ldap.h
servers/slapd/at.c [new file with mode: 0644]
servers/slapd/schema_init.c [new file with mode: 0644]
servers/slapd/schema_prep.c [new file with mode: 0644]
servers/slapd/slap.h
tests/data/slapd-schema.conf [new file with mode: 0644]

index 1eab5bda62322dce07c67affdfe65f8db84eaa2c..d64a0eb38624546548c7654a7d5e9fc5c6c7a607 100644 (file)
@@ -1,4 +1,15 @@
+/* $OpenLDAP$ */
 /*
+ * Copyright 1998-2002 The OpenLDAP Foundation, Redwood City, California, USA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.  A copy of this license is available at
+ * http://www.OpenLDAP.org/license.html or in file LICENSE in the
+ * top-level directory of the distribution.
+ */
+/* Portions
  * Copyright (c) 1990 Regents of the University of Michigan.
  * All rights reserved.
  *
 #ifndef _LDAP_H
 #define _LDAP_H
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
+/* pull in lber */
+#include <lber.h>
 
-#ifdef WINSOCK
-#include "msdos.h"
-#include <winsock.h>
-#endif
+/* include version and API feature defines */
+#include <ldap_features.h>
 
-#if !defined( NEEDPROTOS ) && defined(__STDC__)
-#define NEEDPROTOS     1
-#endif
+LDAP_BEGIN_DECL
 
-#define LDAP_PORT      389
 #define LDAP_VERSION1  1
 #define LDAP_VERSION2  2
-#define LDAP_VERSION   LDAP_VERSION2
+#define LDAP_VERSION3  3
+
+#define LDAP_VERSION_MIN       LDAP_VERSION2
+#define        LDAP_VERSION            LDAP_VERSION2
+#define LDAP_VERSION_MAX       LDAP_VERSION3
 
-#define COMPAT20
-#define COMPAT30
-#if defined(COMPAT20) || defined(COMPAT30)
-#define COMPAT
+/*
+ * We'll use 2000+draft revision for our API version number
+ * As such, the number will be above the old RFC but below
+ * whatever number does finally get assigned
+ */
+#define LDAP_API_VERSION       2004
+#define LDAP_VENDOR_NAME       "OpenLDAP"
+
+/* OpenLDAP API Features */
+#define LDAP_API_FEATURE_X_OPENLDAP LDAP_VENDOR_VERSION
+
+#if defined( LDAP_API_FEATURE_X_OPENLDAP_REENTRANT ) || \
+       ( defined( LDAP_THREAD_SAFE ) && \
+               defined( LDAP_API_FEATURE_X_OPENLDAP_THREAD_SAFE ) )
+       /* -lldap may or may not be thread safe */
+       /* -lldap_r, if available, is always thread safe */
+#      define  LDAP_API_FEATURE_THREAD_SAFE 1
+#endif
+#if defined( LDAP_THREAD_SAFE ) && \
+       defined( LDAP_API_FEATURE_X_OPENLDAP_THREAD_SAFE )
+/* #define LDAP_API_FEATURE_SESSION_SAFE       1       */
+/* #define LDAP_API_OPERATION_SESSION_SAFE     1       */
 #endif
 
-#define LDAP_MAX_ATTR_LEN      100
+#define LDAP_PORT              389             /* ldap:///             default LDAP port */
+#define LDAPS_PORT             636             /* ldaps:///    default LDAP over TLS port */
 
-/* debugging stuff */
-#ifdef LDAP_DEBUG
-extern int     ldap_debug;
-#ifdef LDAP_SYSLOG
-extern int     ldap_syslog;
-extern int     ldap_syslog_level;
-#endif
-#define LDAP_DEBUG_TRACE       0x001
-#define LDAP_DEBUG_PACKETS     0x002
-#define LDAP_DEBUG_ARGS                0x004
-#define LDAP_DEBUG_CONNS       0x008
-#define LDAP_DEBUG_BER         0x010
-#define LDAP_DEBUG_FILTER      0x020
-#define LDAP_DEBUG_CONFIG      0x040
-#define LDAP_DEBUG_ACL         0x080
-#define LDAP_DEBUG_STATS       0x100
-#define LDAP_DEBUG_STATS2      0x200
-#define LDAP_DEBUG_SHELL       0x400
-#define LDAP_DEBUG_PARSE       0x800
-#define LDAP_DEBUG_ANY         0xffff
-
-#ifdef LDAP_SYSLOG
-#define Debug( level, fmt, arg1, arg2, arg3 )  \
-       { \
-               if ( ldap_debug & level ) \
-                       fprintf( stderr, fmt, arg1, arg2, arg3 ); \
-               if ( ldap_syslog & level ) \
-                       syslog( ldap_syslog_level, fmt, arg1, arg2, arg3 ); \
-       }
-#else /* LDAP_SYSLOG */
-#ifndef WINSOCK
-#define Debug( level, fmt, arg1, arg2, arg3 ) \
-               if ( ldap_debug & level ) \
-                       fprintf( stderr, fmt, arg1, arg2, arg3 );
-#else /* !WINSOCK */
-extern void Debug( int level, char* fmt, ... );
-#endif /* !WINSOCK */
-#endif /* LDAP_SYSLOG */
-#else /* LDAP_DEBUG */
-#define Debug( level, fmt, arg1, arg2, arg3 )
-#endif /* LDAP_DEBUG */
-
-/* 
+#define LDAP_ROOT_DSE                          ""
+#define LDAP_NO_ATTRS                          "1.1"
+#define LDAP_ALL_USER_ATTRIBUTES       "*"
+#define LDAP_ALL_OPERATIONAL_ATTRIBUTES        "+" /* OpenLDAP extension */
+
+/*
+ * LDAP_OPTions defined by draft-ldapext-ldap-c-api-02
+ * 0x0000 - 0x0fff reserved for api options
+ * 0x1000 - 0x3fff reserved for api extended options
+ * 0x4000 - 0x7fff reserved for private and experimental options
+ */
+#define LDAP_OPT_API_INFO                      0x0000
+#define LDAP_OPT_DESC                          0x0001 /* deprecated */
+#define LDAP_OPT_DEREF                         0x0002
+#define LDAP_OPT_SIZELIMIT                     0x0003
+#define LDAP_OPT_TIMELIMIT                     0x0004
+/* 0x05 - 0x07 not defined by current draft */
+#define LDAP_OPT_REFERRALS                     0x0008
+#define LDAP_OPT_RESTART                       0x0009
+/* 0x0a - 0x10 not defined by current draft */
+#define LDAP_OPT_PROTOCOL_VERSION      0x0011
+#define LDAP_OPT_SERVER_CONTROLS       0x0012
+#define LDAP_OPT_CLIENT_CONTROLS       0x0013
+/* 0x14 not defined by current draft */
+#define LDAP_OPT_API_FEATURE_INFO      0x0015
+
+/* 0x16 - 0x2f not defined by current draft */
+#define LDAP_OPT_HOST_NAME                     0x0030
+#define        LDAP_OPT_ERROR_NUMBER           0x0031
+#define LDAP_OPT_ERROR_STRING          0x0032
+#define LDAP_OPT_MATCHED_DN                    0x0033
+
+/* 0x34 - 0x0fff not defined by current draft */
+
+#define LDAP_OPT_PRIVATE_EXTENSION_BASE 0x4000  /* to 0x7FFF inclusive */
+
+/* private and experimental options */
+/* OpenLDAP specific options */
+#define LDAP_OPT_DEBUG_LEVEL           0x5001  /* debug level */
+#define LDAP_OPT_TIMEOUT                       0x5002  /* default timeout */
+#define LDAP_OPT_REFHOPLIMIT           0x5003  /* ref hop limit */
+#define LDAP_OPT_NETWORK_TIMEOUT        0x5005  /* socket level timeout */
+#define LDAP_OPT_URI                           0x5006
+
+/* OpenLDAP TLS options */
+#define LDAP_OPT_X_TLS                         0x6000
+#define LDAP_OPT_X_TLS_CTX                     0x6001  /* SSL CTX */
+#define LDAP_OPT_X_TLS_CACERTFILE      0x6002
+#define LDAP_OPT_X_TLS_CACERTDIR       0x6003
+#define LDAP_OPT_X_TLS_CERTFILE                0x6004
+#define LDAP_OPT_X_TLS_KEYFILE         0x6005
+#define LDAP_OPT_X_TLS_REQUIRE_CERT    0x6006
+/* #define LDAP_OPT_X_TLS_PROTOCOL             0x6007 */
+#define LDAP_OPT_X_TLS_CIPHER_SUITE    0x6008
+#define LDAP_OPT_X_TLS_RANDOM_FILE     0x6009
+
+#define LDAP_OPT_X_TLS_NEVER           0
+#define LDAP_OPT_X_TLS_HARD            1
+#define LDAP_OPT_X_TLS_DEMAND          2
+#define LDAP_OPT_X_TLS_ALLOW           3
+#define LDAP_OPT_X_TLS_TRY             4
+
+/* OpenLDAP SASL options */
+#define LDAP_OPT_X_SASL_MECH                   0x6100
+#define LDAP_OPT_X_SASL_REALM                  0x6101
+#define LDAP_OPT_X_SASL_AUTHCID                        0x6102
+#define LDAP_OPT_X_SASL_AUTHZID                        0x6103
+#define LDAP_OPT_X_SASL_SSF                            0x6104 /* read-only */
+#define LDAP_OPT_X_SASL_SSF_EXTERNAL   0x6105 /* write-only */
+#define LDAP_OPT_X_SASL_SECPROPS               0x6106 /* write-only */
+#define LDAP_OPT_X_SASL_SSF_MIN                        0x6107
+#define LDAP_OPT_X_SASL_SSF_MAX                        0x6108
+#define        LDAP_OPT_X_SASL_MAXBUFSIZE              0x6109
+
+
+/* on/off values */
+#define LDAP_OPT_ON            ((void *) 1)
+#define LDAP_OPT_OFF   ((void *) 0)
+
+/*
+ * ldap_get_option() and ldap_set_option() return values.
+ * As later versions may return other values indicating
+ * failure, current applications should only compare returned
+ * value against LDAP_OPT_SUCCESS.
+ */
+#define LDAP_OPT_SUCCESS       0
+#define        LDAP_OPT_ERROR          (-1)
+
+#define LDAP_API_INFO_VERSION  (1)
+typedef struct ldapapiinfo {
+       int             ldapai_info_version;            /* version of LDAPAPIInfo (1) */
+       int             ldapai_api_version;                     /* revision of API supported */
+       int             ldapai_protocol_version;        /* highest LDAP version supported */
+       char    **ldapai_extensions;            /* names of API extensions */
+       char    *ldapai_vendor_name;            /* name of supplier */
+       int             ldapai_vendor_version;          /* supplier-specific version * 100 */
+} LDAPAPIInfo;
+
+#define LDAP_FEATURE_INFO_VERSION (1) /* version of api feature structure */
+typedef struct ldap_apifeature_info {
+       int             ldapaif_info_version; /* version of this struct (1) */
+       char*   ldapaif_name;    /* matches LDAP_API_FEATURE_... less the prefix */
+       int             ldapaif_version; /* matches the value LDAP_API_FEATURE_... */
+} LDAPAPIFeatureInfo;
+
+typedef struct ldapcontrol {
+       char *                  ldctl_oid;
+       struct berval   ldctl_value;
+       char                    ldctl_iscritical;
+} LDAPControl;
+
+/* LDAP Controls */
+
+#define LDAP_CONTROL_MANAGEDSAIT       "2.16.840.1.113730.3.4.2"
+
+#define LDAP_CONTROL_SORTREQUEST    "1.2.840.113556.1.4.473"
+#define LDAP_CONTROL_SORTRESPONSE      "1.2.840.113556.1.4.474"
+#define LDAP_CONTROL_VLVREQUEST        "2.16.840.1.113730.3.4.9"
+#define LDAP_CONTROL_VLVRESPONSE    "2.16.840.1.113730.3.4.10"
+
+/* LDAP Unsolicited Notifications */
+#define        LDAP_NOTICE_OF_DISCONNECTION    "1.3.6.1.4.1.1466.20036"
+#define LDAP_NOTICE_DISCONNECT LDAP_NOTICE_OF_DISCONNECTION
+
+/* LDAP Extended Operations */
+#define LDAP_EXOP_START_TLS    "1.3.6.1.4.1.1466.20037"
+
+#define LDAP_EXOP_MODIFY_PASSWD        "1.3.6.1.4.1.4203.1.11.1"
+#define LDAP_TAG_EXOP_MODIFY_PASSWD_ID ((ber_tag_t) 0x80U)
+#define LDAP_TAG_EXOP_MODIFY_PASSWD_OLD        ((ber_tag_t) 0x81U)
+#define LDAP_TAG_EXOP_MODIFY_PASSWD_NEW        ((ber_tag_t) 0x82U)
+#define LDAP_TAG_EXOP_MODIFY_PASSWD_GEN        ((ber_tag_t) 0x80U)
+
+#define LDAP_EXOP_X_WHO_AM_I   "1.3.6.1.4.1.4203.1.11.3"
+
+/*
  * specific LDAP instantiations of BER types we know about
  */
 
+/* Overview of LBER tag construction
+ *
+ *     Bits
+ *     ______
+ *     8 7 | CLASS
+ *     0 0 = UNIVERSAL
+ *     0 1 = APPLICATION
+ *     1 0 = CONTEXT-SPECIFIC
+ *     1 1 = PRIVATE
+ *             _____
+ *             | 6 | DATA-TYPE
+ *               0 = PRIMITIVE
+ *               1 = CONSTRUCTED
+ *                     ___________
+ *                     | 5 ... 1 | TAG-NUMBER
+ */
+
 /* general stuff */
-#define LDAP_TAG_MESSAGE       0x30L   /* tag is 16 + constructed bit */
-#define OLD_LDAP_TAG_MESSAGE   0x10L   /* forgot the constructed bit  */
-#define LDAP_TAG_MSGID         0x02L
+#define LDAP_TAG_MESSAGE       ((ber_tag_t) 0x30U)     /* constructed + 16 */
+#define LDAP_TAG_MSGID         ((ber_tag_t) 0x02U)     /* integer */
+#define LDAP_TAG_LDAPDN                ((ber_tag_t) 0x04U)     /* octet string */
+#define LDAP_TAG_LDAPCRED      ((ber_tag_t) 0x04U)     /* octet string */
+#define LDAP_TAG_CONTROLS      ((ber_tag_t) 0xa0U)     /* context specific + constructed + 0 */
+#define LDAP_TAG_REFERRAL      ((ber_tag_t) 0xa3U)     /* context specific + constructed + 3 */
+
+#define LDAP_TAG_NEWSUPERIOR   ((ber_tag_t) 0x80U)     /* context-specific + primitive + 0 */
+
+#define LDAP_TAG_EXOP_REQ_OID   ((ber_tag_t) 0x80U)    /* context specific + primitive */
+#define LDAP_TAG_EXOP_REQ_VALUE ((ber_tag_t) 0x81U)    /* context specific + primitive */
+#define LDAP_TAG_EXOP_RES_OID   ((ber_tag_t) 0x8aU)    /* context specific + primitive */
+#define LDAP_TAG_EXOP_RES_VALUE ((ber_tag_t) 0x8bU)    /* context specific + primitive */
+
+#define LDAP_TAG_SASL_RES_CREDS        ((ber_tag_t) 0x87U)     /* context specific + primitive */
+
 
 /* possible operations a client can invoke */
-#define LDAP_REQ_BIND                  0x60L   /* application + constructed */
-#define LDAP_REQ_UNBIND                        0x42L   /* application + primitive   */
-#define LDAP_REQ_SEARCH                        0x63L   /* application + constructed */
-#define LDAP_REQ_MODIFY                        0x66L   /* application + constructed */
-#define LDAP_REQ_ADD                   0x68L   /* application + constructed */
-#define LDAP_REQ_DELETE                        0x4aL   /* application + primitive   */
-#define LDAP_REQ_MODRDN                        0x6cL   /* application + constructed */
-#define LDAP_REQ_COMPARE               0x6eL   /* application + constructed */
-#define LDAP_REQ_ABANDON               0x50L   /* application + primitive   */
-
-/* version 3.0 compatibility stuff */
-#define LDAP_REQ_UNBIND_30             0x62L
-#define LDAP_REQ_DELETE_30             0x6aL
-#define LDAP_REQ_ABANDON_30            0x70L
-
-/* 
- * old broken stuff for backwards compatibility - forgot application tag
- * and constructed/primitive bit
- */
-#define OLD_LDAP_REQ_BIND              0x00L
-#define OLD_LDAP_REQ_UNBIND            0x02L
-#define OLD_LDAP_REQ_SEARCH            0x03L
-#define OLD_LDAP_REQ_MODIFY            0x06L
-#define OLD_LDAP_REQ_ADD               0x08L
-#define OLD_LDAP_REQ_DELETE            0x0aL
-#define OLD_LDAP_REQ_MODRDN            0x0cL
-#define OLD_LDAP_REQ_COMPARE           0x0eL
-#define OLD_LDAP_REQ_ABANDON           0x10L
+#define LDAP_REQ_BIND                  ((ber_tag_t) 0x60U)     /* application + constructed */
+#define LDAP_REQ_UNBIND                        ((ber_tag_t) 0x42U)     /* application + primitive   */
+#define LDAP_REQ_SEARCH                        ((ber_tag_t) 0x63U)     /* application + constructed */
+#define LDAP_REQ_MODIFY                        ((ber_tag_t) 0x66U)     /* application + constructed */
+#define LDAP_REQ_ADD                   ((ber_tag_t) 0x68U)     /* application + constructed */
+#define LDAP_REQ_DELETE                        ((ber_tag_t) 0x4aU)     /* application + primitive   */
+#define LDAP_REQ_MODDN                 ((ber_tag_t) 0x6cU)     /* application + constructed */
+#define LDAP_REQ_MODRDN                        LDAP_REQ_MODDN
+#define LDAP_REQ_RENAME                        LDAP_REQ_MODDN
+#define LDAP_REQ_COMPARE               ((ber_tag_t) 0x6eU)     /* application + constructed */
+#define LDAP_REQ_ABANDON               ((ber_tag_t) 0x50U)     /* application + primitive   */
+#define LDAP_REQ_EXTENDED              ((ber_tag_t) 0x77U)     /* application + constructed */
 
 /* possible result types a server can return */
-#define LDAP_RES_BIND                  0x61L   /* application + constructed */
-#define LDAP_RES_SEARCH_ENTRY          0x64L   /* application + constructed */
-#define LDAP_RES_SEARCH_RESULT         0x65L   /* application + constructed */
-#define LDAP_RES_MODIFY                        0x67L   /* application + constructed */
-#define LDAP_RES_ADD                   0x69L   /* application + constructed */
-#define LDAP_RES_DELETE                        0x6bL   /* application + constructed */
-#define LDAP_RES_MODRDN                        0x6dL   /* application + constructed */
-#define LDAP_RES_COMPARE               0x6fL   /* application + constructed */
-#define LDAP_RES_ANY                   (-1L)
-
-/* old broken stuff for backwards compatibility */
-#define OLD_LDAP_RES_BIND              0x01L
-#define OLD_LDAP_RES_SEARCH_ENTRY      0x04L
-#define OLD_LDAP_RES_SEARCH_RESULT     0x05L
-#define OLD_LDAP_RES_MODIFY            0x07L
-#define OLD_LDAP_RES_ADD               0x09L
-#define OLD_LDAP_RES_DELETE            0x0bL
-#define OLD_LDAP_RES_MODRDN            0x0dL
-#define OLD_LDAP_RES_COMPARE           0x0fL
+#define LDAP_RES_BIND                  ((ber_tag_t) 0x61U)     /* application + constructed */
+#define LDAP_RES_SEARCH_ENTRY          ((ber_tag_t) 0x64U)     /* application + constructed */
+#define LDAP_RES_SEARCH_REFERENCE      ((ber_tag_t) 0x73U)     /* V3: application + constructed */
+#define LDAP_RES_SEARCH_RESULT         ((ber_tag_t) 0x65U)     /* application + constructed */
+#define LDAP_RES_MODIFY                        ((ber_tag_t) 0x67U)     /* application + constructed */
+#define LDAP_RES_ADD                   ((ber_tag_t) 0x69U)     /* application + constructed */
+#define LDAP_RES_DELETE                        ((ber_tag_t) 0x6bU)     /* application + constructed */
+#define LDAP_RES_MODDN                 ((ber_tag_t) 0x6dU)     /* application + constructed */
+#define LDAP_RES_MODRDN                        LDAP_RES_MODDN  /* application + constructed */
+#define LDAP_RES_RENAME                        LDAP_RES_MODDN  /* application + constructed */
+#define LDAP_RES_COMPARE               ((ber_tag_t) 0x6fU)     /* application + constructed */
+#define LDAP_RES_EXTENDED              ((ber_tag_t) 0x78U)     /* V3: application + constructed */
+#define LDAP_RES_EXTENDED_PARTIAL      ((ber_tag_t) 0x79U)     /* V3+: application + constructed */
+
+#define LDAP_RES_ANY                   (-1)
+#define LDAP_RES_UNSOLICITED   (0)
+
+
+/* sasl methods */
+#define LDAP_SASL_SIMPLE               ((char*)0)
+#define LDAP_SASL_NULL                 ("")
+
 
 /* authentication methods available */
-#define LDAP_AUTH_NONE         0x00L   /* no authentication              */
-#define LDAP_AUTH_SIMPLE       0x80L   /* context specific + primitive   */
-#define LDAP_AUTH_KRBV4                0xffL   /* means do both of the following */
-#define LDAP_AUTH_KRBV41       0x81L   /* context specific + primitive   */
-#define LDAP_AUTH_KRBV42       0x82L   /* context specific + primitive   */
-
-/* 3.0 compatibility auth methods */
-#define LDAP_AUTH_SIMPLE_30    0xa0L   /* context specific + constructed */
-#define LDAP_AUTH_KRBV41_30    0xa1L   /* context specific + constructed */
-#define LDAP_AUTH_KRBV42_30    0xa2L   /* context specific + constructed */
-
-/* old broken stuff */
-#define OLD_LDAP_AUTH_SIMPLE   0x00L
-#define OLD_LDAP_AUTH_KRBV4    0x01L
-#define OLD_LDAP_AUTH_KRBV42   0x02L
+#define LDAP_AUTH_NONE         ((ber_tag_t) 0x00U)     /* no authentication              */
+#define LDAP_AUTH_SIMPLE       ((ber_tag_t) 0x80U)     /* context specific + primitive   */
+#define LDAP_AUTH_SASL         ((ber_tag_t) 0xa3U)     /* context specific + constructed */
+#define LDAP_AUTH_KRBV4                ((ber_tag_t) 0xffU)     /* means do both of the following */
+#define LDAP_AUTH_KRBV41       ((ber_tag_t) 0x81U)     /* context specific + primitive   */
+#define LDAP_AUTH_KRBV42       ((ber_tag_t) 0x82U)     /* context specific + primitive   */
+
 
 /* filter types */
-#define LDAP_FILTER_AND                0xa0L   /* context specific + constructed */
-#define LDAP_FILTER_OR         0xa1L   /* context specific + constructed */
-#define LDAP_FILTER_NOT                0xa2L   /* context specific + constructed */
-#define LDAP_FILTER_EQUALITY   0xa3L   /* context specific + constructed */
-#define LDAP_FILTER_SUBSTRINGS 0xa4L   /* context specific + constructed */
-#define LDAP_FILTER_GE         0xa5L   /* context specific + constructed */
-#define LDAP_FILTER_LE         0xa6L   /* context specific + constructed */
-#define LDAP_FILTER_PRESENT    0x87L   /* context specific + primitive   */
-#define LDAP_FILTER_APPROX     0xa8L   /* context specific + constructed */
-
-/* 3.0 compatibility filter types */
-#define LDAP_FILTER_PRESENT_30 0xa7L   /* context specific + constructed */
-
-/* old broken stuff */
-#define OLD_LDAP_FILTER_AND            0x00L
-#define OLD_LDAP_FILTER_OR             0x01L
-#define OLD_LDAP_FILTER_NOT            0x02L
-#define OLD_LDAP_FILTER_EQUALITY       0x03L
-#define OLD_LDAP_FILTER_SUBSTRINGS     0x04L
-#define OLD_LDAP_FILTER_GE             0x05L
-#define OLD_LDAP_FILTER_LE             0x06L
-#define OLD_LDAP_FILTER_PRESENT                0x07L
-#define OLD_LDAP_FILTER_APPROX         0x08L
+#define LDAP_FILTER_AND                ((ber_tag_t) 0xa0U)     /* context specific + constructed */
+#define LDAP_FILTER_OR         ((ber_tag_t) 0xa1U)     /* context specific + constructed */
+#define LDAP_FILTER_NOT                ((ber_tag_t) 0xa2U)     /* context specific + constructed */
+#define LDAP_FILTER_EQUALITY   ((ber_tag_t) 0xa3U)     /* context specific + constructed */
+#define LDAP_FILTER_SUBSTRINGS ((ber_tag_t) 0xa4U)     /* context specific + constructed */
+#define LDAP_FILTER_GE         ((ber_tag_t) 0xa5U)     /* context specific + constructed */
+#define LDAP_FILTER_LE         ((ber_tag_t) 0xa6U)     /* context specific + constructed */
+#define LDAP_FILTER_PRESENT    ((ber_tag_t) 0x87U)     /* context specific + primitive   */
+#define LDAP_FILTER_APPROX     ((ber_tag_t) 0xa8U)     /* context specific + constructed */
+#define LDAP_FILTER_EXT                ((ber_tag_t) 0xa9U)     /* context specific + constructed */
+
+/* extended filter component types */
+#define LDAP_FILTER_EXT_OID    ((ber_tag_t) 0x81U)     /* context specific */
+#define LDAP_FILTER_EXT_TYPE   ((ber_tag_t) 0x82U)     /* context specific */
+#define LDAP_FILTER_EXT_VALUE  ((ber_tag_t) 0x83U)     /* context specific */
+#define LDAP_FILTER_EXT_DNATTRS        ((ber_tag_t) 0x84U)     /* context specific */
 
 /* substring filter component types */
-#define LDAP_SUBSTRING_INITIAL 0x80L   /* context specific */
-#define LDAP_SUBSTRING_ANY     0x81L   /* context specific */
-#define LDAP_SUBSTRING_FINAL   0x82L   /* context specific */
-
-/* 3.0 compatibility substring filter component types */
-#define LDAP_SUBSTRING_INITIAL_30      0xa0L   /* context specific */
-#define LDAP_SUBSTRING_ANY_30          0xa1L   /* context specific */
-#define LDAP_SUBSTRING_FINAL_30                0xa2L   /* context specific */
-
-/* old broken stuff */
-#define OLD_LDAP_SUBSTRING_INITIAL     0x00L
-#define OLD_LDAP_SUBSTRING_ANY         0x01L
-#define OLD_LDAP_SUBSTRING_FINAL       0x02L
+#define LDAP_SUBSTRING_INITIAL ((ber_tag_t) 0x80U)     /* context specific */
+#define LDAP_SUBSTRING_ANY     ((ber_tag_t) 0x81U)     /* context specific */
+#define LDAP_SUBSTRING_FINAL   ((ber_tag_t) 0x82U)     /* context specific */
 
 /* search scopes */
-#define LDAP_SCOPE_BASE                0x00
-#define LDAP_SCOPE_ONELEVEL    0x01
-#define LDAP_SCOPE_SUBTREE     0x02
+#define LDAP_SCOPE_DEFAULT     ((ber_int_t) -1)
+#define LDAP_SCOPE_BASE                ((ber_int_t) 0x0000)
+#define LDAP_SCOPE_ONELEVEL    ((ber_int_t) 0x0001)
+#define LDAP_SCOPE_SUBTREE     ((ber_int_t) 0x0002)
 
-/* for modifications */
-typedef struct ldapmod {
-       int             mod_op;
-#define LDAP_MOD_ADD           0x00
-#define LDAP_MOD_DELETE                0x01
-#define LDAP_MOD_REPLACE       0x02
-#define LDAP_MOD_BVALUES       0x80
-       char            *mod_type;
-       union {
-               char            **modv_strvals;
-               struct berval   **modv_bvals;
-       } mod_vals;
-#define mod_values     mod_vals.modv_strvals
-#define mod_bvalues    mod_vals.modv_bvals
-       struct ldapmod  *mod_next;
-} LDAPMod;
+/* substring filter component types */
+#define LDAP_SUBSTRING_INITIAL ((ber_tag_t) 0x80U)     /* context specific */
+#define LDAP_SUBSTRING_ANY     ((ber_tag_t) 0x81U)     /* context specific */
+#define LDAP_SUBSTRING_FINAL   ((ber_tag_t) 0x82U)     /* context specific */
 
-/* 
+/*
  * possible error codes we can return
  */
 
+#define LDAP_RANGE(n,x,y)      (((x) <= (n)) && ((n) <= (y)))
+
 #define LDAP_SUCCESS                   0x00
 #define LDAP_OPERATIONS_ERROR          0x01
 #define LDAP_PROTOCOL_ERROR            0x02
@@ -232,9 +335,18 @@ typedef struct ldapmod {
 #define LDAP_SIZELIMIT_EXCEEDED                0x04
 #define LDAP_COMPARE_FALSE             0x05
 #define LDAP_COMPARE_TRUE              0x06
-#define LDAP_STRONG_AUTH_NOT_SUPPORTED 0x07
+#define LDAP_AUTH_METHOD_NOT_SUPPORTED 0x07
+#define LDAP_STRONG_AUTH_NOT_SUPPORTED LDAP_AUTH_METHOD_NOT_SUPPORTED
 #define LDAP_STRONG_AUTH_REQUIRED      0x08
-#define LDAP_PARTIAL_RESULTS           0x09
+#define LDAP_PARTIAL_RESULTS           0x09    /* LDAPv2+ (not LDAPv3) */
+
+#define        LDAP_REFERRAL                           0x0a /* LDAPv3 */
+#define LDAP_ADMINLIMIT_EXCEEDED       0x0b /* LDAPv3 */
+#define        LDAP_UNAVAILABLE_CRITICAL_EXTENSION     0x0c /* LDAPv3 */
+#define LDAP_CONFIDENTIALITY_REQUIRED  0x0d /* LDAPv3 */
+#define        LDAP_SASL_BIND_IN_PROGRESS      0x0e /* LDAPv3 */
+
+#define LDAP_ATTR_ERROR(n)     LDAP_RANGE((n),0x10,0x15) /* 16-21 */
 
 #define LDAP_NO_SUCH_ATTRIBUTE         0x10
 #define LDAP_UNDEFINED_TYPE            0x11
@@ -243,31 +355,45 @@ typedef struct ldapmod {
 #define LDAP_TYPE_OR_VALUE_EXISTS      0x14
 #define LDAP_INVALID_SYNTAX            0x15
 
+#define LDAP_NAME_ERROR(n)     LDAP_RANGE((n),0x20,0x24) /* 32-34,36 */
+
 #define LDAP_NO_SUCH_OBJECT            0x20
 #define LDAP_ALIAS_PROBLEM             0x21
 #define LDAP_INVALID_DN_SYNTAX         0x22
-#define LDAP_IS_LEAF                   0x23
+#define LDAP_IS_LEAF                   0x23 /* not LDAPv3 */
 #define LDAP_ALIAS_DEREF_PROBLEM       0x24
 
-#define NAME_ERROR(n)  ((n & 0xf0) == 0x20)
+#define LDAP_SECURITY_ERROR(n) LDAP_RANGE((n),0x30,0x32) /* 48-50 */
 
 #define LDAP_INAPPROPRIATE_AUTH                0x30
 #define LDAP_INVALID_CREDENTIALS       0x31
 #define LDAP_INSUFFICIENT_ACCESS       0x32
+
+#define LDAP_SERVICE_ERROR(n)  LDAP_RANGE((n),0x33,0x36) /* 51-54 */
+
 #define LDAP_BUSY                      0x33
 #define LDAP_UNAVAILABLE               0x34
 #define LDAP_UNWILLING_TO_PERFORM      0x35
 #define LDAP_LOOP_DETECT               0x36
 
+#define LDAP_UPDATE_ERROR(n)   LDAP_RANGE((n),0x40,0x47) /* 64-69,71 */
+
 #define LDAP_NAMING_VIOLATION          0x40
 #define LDAP_OBJECT_CLASS_VIOLATION    0x41
 #define LDAP_NOT_ALLOWED_ON_NONLEAF    0x42
 #define LDAP_NOT_ALLOWED_ON_RDN                0x43
 #define LDAP_ALREADY_EXISTS            0x44
 #define LDAP_NO_OBJECT_CLASS_MODS      0x45
-#define LDAP_RESULTS_TOO_LARGE         0x46
+#define LDAP_RESULTS_TOO_LARGE         0x46 /* CLDAP */
+#define LDAP_AFFECTS_MULTIPLE_DSAS     0x47 /* LDAPv3 */
 
 #define LDAP_OTHER                     0x50
+
+#define LDAP_API_ERROR(n)              LDAP_RANGE((n),0x51,0x61) /* 81-97 */
+#define LDAP_API_RESULT(n)             (((n) == LDAP_SUCCESS) || \
+                                                                       LDAP_RANGE((n),0x51,0x61)) /* 0,81-97 */
+
+/* reserved for APIs */
 #define LDAP_SERVER_DOWN               0x51
 #define LDAP_LOCAL_ERROR               0x52
 #define LDAP_ENCODING_ERROR            0x53
@@ -279,9 +405,14 @@ typedef struct ldapmod {
 #define LDAP_PARAM_ERROR               0x59
 #define LDAP_NO_MEMORY                 0x5a
 
-
-/* default limit on nesting of referrals */
-#define LDAP_DEFAULT_REFHOPLIMIT       5
+/* used but not reserved for APIs */
+#define LDAP_CONNECT_ERROR                             0x5b    /* draft-ietf-ldap-c-api-xx */
+#define LDAP_NOT_SUPPORTED                             0x5c    /* draft-ietf-ldap-c-api-xx */
+#define LDAP_CONTROL_NOT_FOUND                 0x5d    /* draft-ietf-ldap-c-api-xx */
+#define LDAP_NO_RESULTS_RETURNED               0x5e    /* draft-ietf-ldap-c-api-xx */
+#define LDAP_MORE_RESULTS_TO_RETURN            0x5f    /* draft-ietf-ldap-c-api-xx */
+#define LDAP_CLIENT_LOOP                               0x60    /* draft-ietf-ldap-c-api-xx */
+#define LDAP_REFERRAL_LIMIT_EXCEEDED   0x61    /* draft-ietf-ldap-c-api-xx */
 
 /*
  * This structure represents both ldap messages and ldap responses.
@@ -289,89 +420,29 @@ typedef struct ldapmod {
  * where a response has multiple messages.
  */
 
-typedef struct ldapmsg {
-       int             lm_msgid;       /* the message id */
-       int             lm_msgtype;     /* the message type */
-       BerElement      *lm_ber;        /* the ber encoded message contents */
-       struct ldapmsg  *lm_chain;      /* for search - next msg in the resp */
-       struct ldapmsg  *lm_next;       /* next response */
-       unsigned long   lm_time;        /* used to maintain cache */
-} LDAPMessage;
-#define NULLMSG        ((LDAPMessage *) NULL)
-
-
-#ifdef LDAP_REFERRALS
-/*
- * structure for tracking LDAP server host, ports, DNs, etc.
- */
-typedef struct ldap_server {
-       char                    *lsrv_host;
-       char                    *lsrv_dn;       /* if NULL, use default */
-       int                     lsrv_port;
-       struct ldap_server      *lsrv_next;
-} LDAPServer;
-
-
-/*
- * structure for representing an LDAP server connection
- */
-typedef struct ldap_conn {
-       Sockbuf                 *lconn_sb;
-       int                     lconn_refcnt;
-       unsigned long           lconn_lastused; /* time */
-       int                     lconn_status;
-#define LDAP_CONNST_NEEDSOCKET         1
-#define LDAP_CONNST_CONNECTING         2
-#define LDAP_CONNST_CONNECTED          3
-       LDAPServer              *lconn_server;
-       char                    *lconn_krbinstance;
-       struct ldap_conn        *lconn_next;
-} LDAPConn;
-
-
-/*
- * structure used to track outstanding requests
- */
-typedef struct ldapreq {
-       int             lr_msgid;       /* the message id */
-       int             lr_status;      /* status of request */
-#define LDAP_REQST_INPROGRESS  1
-#define LDAP_REQST_CHASINGREFS 2
-#define LDAP_REQST_NOTCONNECTED        3
-#define LDAP_REQST_WRITING     4
-       int             lr_outrefcnt;   /* count of outstanding referrals */
-       int             lr_origid;      /* original request's message id */
-       int             lr_parentcnt;   /* count of parent requests */
-       int             lr_res_msgtype; /* result message type */
-       int             lr_res_errno;   /* result LDAP errno */
-       char            *lr_res_error;  /* result error string */
-       char            *lr_res_matched;/* result matched DN string */
-       BerElement      *lr_ber;        /* ber encoded request contents */
-       LDAPConn        *lr_conn;       /* connection used to send request */
-       struct ldapreq  *lr_parent;     /* request that spawned this referral */
-       struct ldapreq  *lr_refnext;    /* next referral spawned */
-       struct ldapreq  *lr_prev;       /* previous request */
-       struct ldapreq  *lr_next;       /* next request */
-} LDAPRequest;
-#endif /* LDAP_REFERRALS */
-
-
-/*
- * structure for client cache
- */
-#define LDAP_CACHE_BUCKETS     31      /* cache hash table size */
-typedef struct ldapcache {
-       LDAPMessage     *lc_buckets[LDAP_CACHE_BUCKETS];/* hash table */
-       LDAPMessage     *lc_requests;                   /* unfulfilled reqs */
-       long            lc_timeout;                     /* request timeout */
-       long            lc_maxmem;                      /* memory to use */
-       long            lc_memused;                     /* memory in use */
-       int             lc_enabled;                     /* enabled? */
-       unsigned long   lc_options;                     /* options */
-#define LDAP_CACHE_OPT_CACHENOERRS     0x00000001
-#define LDAP_CACHE_OPT_CACHEALLERRS    0x00000002
-}  LDAPCache;
-#define NULLLDCACHE ((LDAPCache *)NULL)
+typedef struct ldapmsg LDAPMessage;
+
+/* for modifications */
+typedef struct ldapmod {
+       int             mod_op;
+
+#define LDAP_MOD_ADD           ((ber_int_t) 0x0000)
+#define LDAP_MOD_DELETE                ((ber_int_t) 0x0001)
+#define LDAP_MOD_REPLACE       ((ber_int_t) 0x0002)
+#define LDAP_MOD_BVALUES       ((ber_int_t) 0x0080)
+/* IMPORTANT: do not use code 0x1000 (or above),
+ * it is used internally by the backends!
+ * (see ldap/servers/slapd/slap.h)
+ */
+
+       char            *mod_type;
+       union mod_vals_u {
+               char            **modv_strvals;
+               struct berval   **modv_bvals;
+       } mod_vals;
+#define mod_values     mod_vals.modv_strvals
+#define mod_bvalues    mod_vals.modv_bvals
+} LDAPMod;
 
 /*
  * structures for ldap getfilter routines
@@ -380,8 +451,8 @@ typedef struct ldapcache {
 typedef struct ldap_filt_info {
        char                    *lfi_filter;
        char                    *lfi_desc;
-       int                     lfi_scope;      /* LDAP_SCOPE_BASE, etc */
-       int                     lfi_isexact;    /* exact match filter? */
+       int                     lfi_scope;
+       int                     lfi_isexact;
        struct ldap_filt_info   *lfi_next;
 } LDAPFiltInfo;
 
@@ -410,183 +481,1138 @@ typedef struct ldap_filt_desc {
 
 
 /*
- * structure representing an ldap connection
+ * structure representing an ldap session which can
+ * encompass connections to multiple servers (in the
+ * face of referrals).
  */
+typedef struct ldap LDAP;
 
-typedef struct ldap {
-       Sockbuf         ld_sb;          /* socket descriptor & buffer */
-       char            *ld_host;
-       int             ld_version;
-       char            ld_lberoptions;
-       int             ld_deref;
-#define LDAP_DEREF_NEVER       0
-#define LDAP_DEREF_SEARCHING   1
-#define LDAP_DEREF_FINDING     2
-#define LDAP_DEREF_ALWAYS      3
+#define LDAP_DEREF_NEVER       0x00
+#define LDAP_DEREF_SEARCHING   0x01
+#define LDAP_DEREF_FINDING     0x02
+#define LDAP_DEREF_ALWAYS      0x03
 
-       int             ld_timelimit;
-       int             ld_sizelimit;
 #define LDAP_NO_LIMIT          0
 
-       LDAPFiltDesc    *ld_filtd;      /* from getfilter for ufn searches */
-       char            *ld_ufnprefix;  /* for incomplete ufn's */
+/* how many messages to retrieve results for */
+#define LDAP_MSG_ONE           0x00
+#define LDAP_MSG_ALL           0x01
+#define LDAP_MSG_RECEIVED      0x02
 
-       int             ld_errno;
-       char            *ld_error;
-       char            *ld_matched;
-       int             ld_msgid;
+/*
+ * types for ldap URL handling
+ */
+typedef struct ldap_url_desc {
+       struct ldap_url_desc *lud_next;
+       char    *lud_scheme;
+       char    *lud_host;
+       int             lud_port;
+       char    *lud_dn;
+       char    **lud_attrs;
+       int             lud_scope;
+       char    *lud_filter;
+       char    **lud_exts;
+       int             lud_crit_exts;
+} LDAPURLDesc;
 
-       /* do not mess with these */
-#ifdef LDAP_REFERRALS
-       LDAPRequest     *ld_requests;   /* list of outstanding requests */
-#else /* LDAP_REFERRALS */
-       LDAPMessage     *ld_requests;   /* list of outstanding requests */
-#endif /* LDAP_REFERRALS */
-       LDAPMessage     *ld_responses;  /* list of outstanding responses */
-       int             *ld_abandoned;  /* array of abandoned requests */
-       char            ld_attrbuffer[LDAP_MAX_ATTR_LEN];
-       LDAPCache       *ld_cache;      /* non-null if cache is initialized */
-       char            *ld_cldapdn;    /* DN used in connectionless search */
+#define LDAP_URL_SUCCESS               0x00    /* Success */
+#define LDAP_URL_ERR_MEM               0x01    /* can't allocate memory space */
+#define LDAP_URL_ERR_PARAM             0x02    /* parameter is bad */
 
-       /* it is OK to change these next four values directly */
-       int             ld_cldaptries;  /* connectionless search retry count */
-       int             ld_cldaptimeout;/* time between retries */
-       int             ld_refhoplimit; /* limit on referral nesting */
-       unsigned long   ld_options;     /* boolean options */
-#ifdef LDAP_DNS
-#define LDAP_OPT_DNS           0x00000001      /* use DN & DNS */
-#endif /* LDAP_DNS */
-#ifdef LDAP_REFERRALS
-#define LDAP_OPT_REFERRALS     0x00000002      /* chase referrals */
-#endif /* LDAP_REFERRALS */
-#define LDAP_OPT_RESTART       0x00000004      /* restart if EINTR occurs */
+#define LDAP_URL_ERR_BADSCHEME 0x03    /* URL doesn't begin with "ldap[si]://" */
+#define LDAP_URL_ERR_BADENCLOSURE 0x04 /* URL is missing trailing ">" */
+#define LDAP_URL_ERR_BADURL            0x05    /* URL is bad */
+#define LDAP_URL_ERR_BADHOST   0x06    /* host port is bad */
+#define LDAP_URL_ERR_BADATTRS  0x07    /* bad (or missing) attributes */
+#define LDAP_URL_ERR_BADSCOPE  0x08    /* scope string is invalid (or missing) */
+#define LDAP_URL_ERR_BADFILTER 0x09    /* bad or missing filter */
+#define LDAP_URL_ERR_BADEXTS   0x0a    /* bad or missing extensions */
 
-       /* do not mess with the rest though */
-       char            *ld_defhost;    /* full name of default server */
-       int             ld_defport;     /* port of default server */
-       BERTranslateProc ld_lber_encode_translate_proc;
-       BERTranslateProc ld_lber_decode_translate_proc;
-#ifdef LDAP_REFERRALS
-       LDAPConn        *ld_defconn;    /* default connection */
-       LDAPConn        *ld_conns;      /* list of server connections */
-       void            *ld_selectinfo; /* platform specifics for select */
-       int             (*ld_rebindproc)( struct ldap *ld, char **dnp,
-                               char **passwdp, int *authmethodp, int freeit );
-                               /* routine to get info needed for re-bind */
-#endif /* LDAP_REFERRALS */
-} LDAP;
+/*
+ * The API draft spec says we should declare (or cause to be declared)
+ * 'struct timeval'.   We don't.  See IETF LDAPext discussions.
+ */
+struct timeval;
 
+/*
+ * in options.c:
+ */
+LDAP_F( int )
+ldap_get_option LDAP_P((
+       LDAP *ld,
+       int option,
+       void *outvalue));
+
+LDAP_F( int )
+ldap_set_option LDAP_P((
+       LDAP *ld,
+       int option,
+       LDAP_CONST void *invalue));
+
+/* V3 REBIND Function Callback Prototype */
+typedef int (LDAP_REBIND_PROC) LDAP_P((
+       LDAP *ld, LDAP_CONST char *url,
+       ber_tag_t request, ber_int_t msgid,
+       void *params ));
+
+LDAP_F( int )
+ldap_set_rebind_proc LDAP_P((
+       LDAP *ld,
+       LDAP_REBIND_PROC *rebind_proc,
+       void *params ));
 
 /*
- * structure for ldap friendly mapping routines
+ * in controls.c:
  */
+LDAP_F( int )
+ldap_create_control LDAP_P((
+       LDAP_CONST char *requestOID,
+       BerElement *ber,
+       int iscritical,
+       LDAPControl **ctrlp ));
 
-typedef struct friendly {
-       char    *f_unfriendly;
-       char    *f_friendly;
-} FriendlyMap;
+LDAP_F( void )
+ldap_control_free LDAP_P((
+       LDAPControl *ctrl ));
 
+LDAP_F( void )
+ldap_controls_free LDAP_P((
+       LDAPControl **ctrls ));
 
 /*
- * handy macro to check whether LDAP struct is set up for CLDAP or not
+ * in dnssrv.c:
  */
-#define LDAP_IS_CLDAP( ld )    ( ld->ld_sb.sb_naddr > 0 )
+LDAP_F( int )
+ldap_domain2dn LDAP_P((
+       LDAP_CONST char* domain,
+       char** dn ));
 
+LDAP_F( int )
+ldap_dn2domain LDAP_P((
+       LDAP_CONST char* dn,
+       char** domain ));
+
+LDAP_F( int )
+ldap_domain2hostlist LDAP_P((
+       LDAP_CONST char *domain,
+       char** hostlist ));
 
 /*
- * types for ldap URL handling
+ * in extended.c:
  */
-typedef struct ldap_url_desc {
-    char       *lud_host;
-    int                lud_port;
-    char       *lud_dn;
-    char       **lud_attrs;
-    int                lud_scope;
-    char       *lud_filter;
-    char       *lud_string;    /* for internal use only */
-} LDAPURLDesc;
-#define NULLLDAPURLDESC        ((LDAPURLDesc *)NULL)
-
-#define LDAP_URL_ERR_NOTLDAP   1       /* URL doesn't begin with "ldap://" */
-#define LDAP_URL_ERR_NODN      2       /* URL has no DN (required) */
-#define LDAP_URL_ERR_BADSCOPE  3       /* URL scope string is invalid */
-#define LDAP_URL_ERR_MEM       4       /* can't allocate memory space */
-
-
-#ifndef NEEDPROTOS
-extern LDAP *ldap_open();
-extern LDAP *ldap_init();
-#ifdef STR_TRANSLATION
-extern void ldap_set_string_translators();
-#ifdef LDAP_CHARSET_8859
-extern int ldap_t61_to_8859();
-extern int ldap_8859_to_t61();
-#endif /* LDAP_CHARSET_8859 */
-#endif /* STR_TRANSLATION */
-extern LDAPMessage *ldap_first_entry();
-extern LDAPMessage *ldap_next_entry();
-extern char *ldap_get_dn();
-extern char *ldap_dn2ufn();
-extern char **ldap_explode_dn();
-extern char *ldap_first_attribute();
-extern char *ldap_next_attribute();
-extern char **ldap_get_values();
-extern struct berval **ldap_get_values_len();
-extern void ldap_value_free();
-extern void ldap_value_free_len();
-extern int ldap_count_values();
-extern int ldap_count_values_len();
-extern char *ldap_err2string();
-extern void ldap_getfilter_free();
-extern LDAPFiltDesc *ldap_init_getfilter();
-extern LDAPFiltDesc *ldap_init_getfilter_buf();
-extern LDAPFiltInfo *ldap_getfirstfilter();
-extern LDAPFiltInfo *ldap_getnextfilter();
-extern void ldap_setfilteraffixes();
-extern void ldap_build_filter();
-extern void ldap_flush_cache();
-extern void ldap_set_cache_options();
-extern void ldap_uncache_entry();
-extern void ldap_uncache_request();
-extern char *ldap_friendly_name();
-extern void ldap_free_friendlymap();
-extern LDAP *cldap_open();
-extern void cldap_setretryinfo();
-extern void cldap_close();
-extern LDAPFiltDesc *ldap_ufn_setfilter();
-extern int ldap_ufn_timeout();
-extern int ldap_sort_entries();
-extern int ldap_sort_values();
-extern int ldap_sort_strcasecmp();
-void ldap_free_urldesc();
-void ldap_set_rebind_proc();
-void ldap_enable_translation();
-
-
-#if defined(ultrix) || defined(VMS) || defined( nextstep )
-extern char *strdup();
-#endif
+LDAP_F( int )
+ldap_extended_operation LDAP_P((
+       LDAP                    *ld,
+       LDAP_CONST char *reqoid,
+       struct berval   *reqdata,
+       LDAPControl             **serverctrls,
+       LDAPControl             **clientctrls,
+       int                             *msgidp ));
+
+LDAP_F( int )
+ldap_extended_operation_s LDAP_P((
+       LDAP                    *ld,
+       LDAP_CONST char *reqoid,
+       struct berval   *reqdata,
+       LDAPControl             **serverctrls,
+       LDAPControl             **clientctrls,
+       char                    **retoidp,
+       struct berval   **retdatap ));
+
+LDAP_F( int )
+ldap_parse_extended_result LDAP_P((
+       LDAP                    *ld,
+       LDAPMessage             *res,
+       char                    **retoidp,
+       struct berval   **retdatap,
+       int                             freeit ));
+
+LDAP_F( int )
+ldap_parse_extended_partial LDAP_P((
+       LDAP                    *ld,
+       LDAPMessage             *res,
+       char                    **retoidp,
+       struct berval   **retdatap,
+       LDAPControl             ***serverctrls,
+       int                             freeit ));
 
-#else /* NEEDPROTOS */
-#if !defined(MACOS) && !defined(DOS) && !defined(_WIN32) && !defined(WINSOCK)
-#include <sys/time.h>
-#endif
-#if defined(WINSOCK)
-#include "proto-ld.h"
-#else
-#include "proto-ldap.h"
-#endif
+/*
+ * in abandon.c:
+ */
+LDAP_F( int )
+ldap_abandon_ext LDAP_P((
+       LDAP                    *ld,
+       int                             msgid,
+       LDAPControl             **serverctrls,
+       LDAPControl             **clientctrls ));
 
-#ifdef VMS
-extern char *strdup( const char *s );
-#endif
-#if defined(ultrix) || defined( nextstep )
-extern char *strdup();
-#endif
+LDAP_F( int )
+ldap_abandon LDAP_P((  /* deprecated */
+       LDAP *ld,
+       int msgid ));
 
-#endif /* NEEDPROTOS */
 
-#ifdef __cplusplus
-}
-#endif
+/*
+ * in add.c:
+ */
+LDAP_F( int )
+ldap_add_ext LDAP_P((
+       LDAP                    *ld,
+       LDAP_CONST char *dn,
+       LDAPMod                 **attrs,
+       LDAPControl             **serverctrls,
+       LDAPControl             **clientctrls,
+       int                     *msgidp ));
+
+LDAP_F( int )
+ldap_add_ext_s LDAP_P((
+       LDAP                    *ld,
+       LDAP_CONST char *dn,
+       LDAPMod                 **attrs,
+       LDAPControl             **serverctrls,
+       LDAPControl             **clientctrls ));
+
+LDAP_F( int )
+ldap_add LDAP_P((      /* deprecated */
+       LDAP *ld,
+       LDAP_CONST char *dn,
+       LDAPMod **attrs ));
+
+LDAP_F( int )
+ldap_add_s LDAP_P((    /* deprecated */
+       LDAP *ld,
+       LDAP_CONST char *dn,
+       LDAPMod **attrs ));
+
+
+/*
+ * in sasl.c:
+ */
+LDAP_F( int )
+ldap_sasl_bind LDAP_P((
+       LDAP                    *ld,
+       LDAP_CONST char *dn,
+       LDAP_CONST char *mechanism,
+       struct berval   *cred,
+       LDAPControl             **serverctrls,
+       LDAPControl             **clientctrls,
+       int                             *msgidp ));
+
+/* Interaction flags (should be passed about in a control)
+ *  Automatic (default): use defaults, prompt otherwise
+ *  Interactive: prompt always
+ *  Quiet: never prompt
+ */
+#define LDAP_SASL_AUTOMATIC            0U
+#define LDAP_SASL_INTERACTIVE  1U
+#define LDAP_SASL_QUIET                        2U
+
+/*
+ * V3 SASL Interaction Function Callback Prototype
+ *     when using Cyrus SASL, interact is pointer to sasl_interact_t
+ *  should likely passed in a control (and provided controls)
+ */
+typedef int (LDAP_SASL_INTERACT_PROC) LDAP_P((
+       LDAP *ld, unsigned flags, void* defaults, void *interact ));
+
+LDAP_F( int )
+ldap_sasl_interactive_bind_s LDAP_P((
+       LDAP *ld,
+       LDAP_CONST char *dn, /* usually NULL */
+       LDAP_CONST char *saslMechanism,
+       LDAPControl **serverControls,
+       LDAPControl **clientControls,
+
+       /* should be client controls */
+       unsigned flags,
+       LDAP_SASL_INTERACT_PROC *proc,
+       void *defaults ));
+
+LDAP_F( int )
+ldap_sasl_bind_s LDAP_P((
+       LDAP                    *ld,
+       LDAP_CONST char *dn,
+       LDAP_CONST char *mechanism,
+       struct berval   *cred,
+       LDAPControl             **serverctrls,
+       LDAPControl             **clientctrls,
+       struct berval   **servercredp ));
+
+LDAP_F( int )
+ldap_parse_sasl_bind_result LDAP_P((
+       LDAP                    *ld,
+       LDAPMessage             *res,
+       struct berval   **servercredp,
+       int                             freeit ));
+
+/*
+ * in bind.c:
+ *     (deprecated)
+ */
+LDAP_F( int )
+ldap_bind LDAP_P((     /* deprecated */
+       LDAP *ld,
+       LDAP_CONST char *who,
+       LDAP_CONST char *passwd,
+       int authmethod ));
+
+LDAP_F( int )
+ldap_bind_s LDAP_P((   /* deprecated */
+       LDAP *ld,
+       LDAP_CONST char *who,
+       LDAP_CONST char *cred,
+       int authmethod ));
+
+/*
+ * in sbind.c:
+ */
+LDAP_F( int )
+ldap_simple_bind LDAP_P((
+       LDAP *ld,
+       LDAP_CONST char *who,
+       LDAP_CONST char *passwd ));
+
+LDAP_F( int )
+ldap_simple_bind_s LDAP_P((
+       LDAP *ld,
+       LDAP_CONST char *who,
+       LDAP_CONST char *passwd ));
+
+
+/*
+ * in kbind.c:
+ *     (deprecated)
+ */
+LDAP_F( int )
+ldap_kerberos_bind_s LDAP_P((  /* deprecated */
+       LDAP *ld,
+       LDAP_CONST char *who ));
+
+LDAP_F( int )
+ldap_kerberos_bind1 LDAP_P((   /* deprecated */
+       LDAP *ld,
+       LDAP_CONST char *who ));
+
+LDAP_F( int )
+ldap_kerberos_bind1_s LDAP_P(( /* deprecated */
+       LDAP *ld,
+       LDAP_CONST char *who ));
+
+LDAP_F( int )
+ldap_kerberos_bind2 LDAP_P((   /* deprecated */
+       LDAP *ld,
+       LDAP_CONST char *who ));
+
+LDAP_F( int )
+ldap_kerberos_bind2_s LDAP_P(( /* deprecated */
+       LDAP *ld,
+       LDAP_CONST char *who ));
+
+/*
+ * in cache.c
+ * (deprecated)
+ */
+LDAP_F( int )
+ldap_enable_cache LDAP_P(( LDAP *ld, long timeout, ber_len_t maxmem ));
+
+LDAP_F( void )
+ldap_disable_cache LDAP_P(( LDAP *ld ));
+
+LDAP_F( void )
+ldap_set_cache_options LDAP_P(( LDAP *ld, unsigned long opts ));
+
+LDAP_F( void )
+ldap_destroy_cache LDAP_P(( LDAP *ld ));
+
+LDAP_F( void )
+ldap_flush_cache LDAP_P(( LDAP *ld ));
+
+LDAP_F( void )
+ldap_uncache_entry LDAP_P(( LDAP *ld, LDAP_CONST char *dn ));
+
+LDAP_F( void )
+ldap_uncache_request LDAP_P(( LDAP *ld, int msgid ));
+
+
+/*
+ * in compare.c:
+ */
+LDAP_F( int )
+ldap_compare_ext LDAP_P((
+       LDAP                    *ld,
+       LDAP_CONST char *dn,
+       LDAP_CONST char *attr,
+       struct berval   *bvalue,
+       LDAPControl             **serverctrls,
+       LDAPControl             **clientctrls,
+       int                     *msgidp ));
+
+LDAP_F( int )
+ldap_compare_ext_s LDAP_P((
+       LDAP                    *ld,
+       LDAP_CONST char *dn,
+       LDAP_CONST char *attr,
+       struct berval   *bvalue,
+       LDAPControl             **serverctrls,
+       LDAPControl             **clientctrls ));
+
+LDAP_F( int )
+ldap_compare LDAP_P((  /* deprecated */
+       LDAP *ld,
+       LDAP_CONST char *dn,
+       LDAP_CONST char *attr,
+       LDAP_CONST char *value ));
+
+LDAP_F( int )
+ldap_compare_s LDAP_P((        /* deprecated */
+       LDAP *ld,
+       LDAP_CONST char *dn,
+       LDAP_CONST char *attr,
+       LDAP_CONST char *value ));
+
+
+/*
+ * in delete.c:
+ */
+LDAP_F( int )
+ldap_delete_ext LDAP_P((
+       LDAP                    *ld,
+       LDAP_CONST char *dn,
+       LDAPControl             **serverctrls,
+       LDAPControl             **clientctrls,
+       int                     *msgidp ));
+
+LDAP_F( int )
+ldap_delete_ext_s LDAP_P((
+       LDAP                    *ld,
+       LDAP_CONST char *dn,
+       LDAPControl             **serverctrls,
+       LDAPControl             **clientctrls ));
+
+LDAP_F( int )
+ldap_delete LDAP_P((   /* deprecated */
+       LDAP *ld,
+       LDAP_CONST char *dn ));
+
+LDAP_F( int )
+ldap_delete_s LDAP_P(( /* deprecated */
+       LDAP *ld,
+       LDAP_CONST char *dn ));
+
+
+/*
+ * in error.c:
+ */
+LDAP_F( int )
+ldap_parse_result LDAP_P((
+       LDAP                    *ld,
+       LDAPMessage             *res,
+       int                             *errcodep,
+       char                    **matcheddnp,
+       char                    **errmsgp,
+       char                    ***referralsp,
+       LDAPControl             ***serverctrls,
+       int                             freeit ));
+
+LDAP_F( char * )
+ldap_err2string LDAP_P((
+       int err ));
+
+LDAP_F( int )
+ldap_result2error LDAP_P((     /* deprecated */
+       LDAP *ld,
+       LDAPMessage *r,
+       int freeit ));
+
+LDAP_F( void )
+ldap_perror LDAP_P((   /* deprecated */
+       LDAP *ld,
+       LDAP_CONST char *s ));
+
+
+/*
+ * in modify.c:
+ */
+LDAP_F( int )
+ldap_modify_ext LDAP_P((
+       LDAP                    *ld,
+       LDAP_CONST char *dn,
+       LDAPMod                 **mods,
+       LDAPControl             **serverctrls,
+       LDAPControl             **clientctrls,
+       int                     *msgidp ));
+
+LDAP_F( int )
+ldap_modify_ext_s LDAP_P((
+       LDAP                    *ld,
+       LDAP_CONST char *dn,
+       LDAPMod                 **mods,
+       LDAPControl             **serverctrls,
+       LDAPControl             **clientctrls ));
+
+LDAP_F( int )
+ldap_modify LDAP_P((   /* deprecated */
+       LDAP *ld,
+       LDAP_CONST char *dn,
+       LDAPMod **mods ));
+
+LDAP_F( int )
+ldap_modify_s LDAP_P(( /* deprecated */
+       LDAP *ld,
+       LDAP_CONST char *dn,
+       LDAPMod **mods ));
+
+
+/*
+ * in modrdn.c:
+ */
+LDAP_F( int )
+ldap_rename LDAP_P((
+       LDAP *ld,
+       LDAP_CONST char *dn,
+       LDAP_CONST char *newrdn,
+       LDAP_CONST char *newSuperior,
+       int deleteoldrdn,
+       LDAPControl **sctrls,
+       LDAPControl **cctrls,
+       int *msgidp ));
+
+LDAP_F( int )
+ldap_rename_s LDAP_P((
+       LDAP *ld,
+       LDAP_CONST char *dn,
+       LDAP_CONST char *newrdn,
+       LDAP_CONST char *newSuperior,
+       int deleteoldrdn,
+       LDAPControl **sctrls,
+       LDAPControl **cctrls ));
+
+LDAP_F( int )
+ldap_rename2 LDAP_P((  /* deprecated */
+       LDAP *ld,
+       LDAP_CONST char *dn,
+       LDAP_CONST char *newrdn,
+       LDAP_CONST char *newSuperior,
+       int deleteoldrdn ));
+
+LDAP_F( int )
+ldap_rename2_s LDAP_P((        /* deprecated */
+       LDAP *ld,
+       LDAP_CONST char *dn,
+       LDAP_CONST char *newrdn,
+       LDAP_CONST char *newSuperior,
+       int deleteoldrdn ));
+
+LDAP_F( int )
+ldap_modrdn LDAP_P((   /* deprecated */
+       LDAP *ld,
+       LDAP_CONST char *dn,
+       LDAP_CONST char *newrdn ));
+
+LDAP_F( int )
+ldap_modrdn_s LDAP_P(( /* deprecated */
+       LDAP *ld,
+       LDAP_CONST char *dn,
+       LDAP_CONST char *newrdn ));
+
+LDAP_F( int )
+ldap_modrdn2 LDAP_P((  /* deprecated */
+       LDAP *ld,
+       LDAP_CONST char *dn,
+       LDAP_CONST char *newrdn,
+       int deleteoldrdn ));
+
+LDAP_F( int )
+ldap_modrdn2_s LDAP_P((        /* deprecated */
+       LDAP *ld,
+       LDAP_CONST char *dn,
+       LDAP_CONST char *newrdn,
+       int deleteoldrdn));
+
+
+/*
+ * in open.c:
+ */
+LDAP_F( LDAP * )
+ldap_init LDAP_P((
+       LDAP_CONST char *host,
+       int port ));
+
+LDAP_F( LDAP * )
+ldap_open LDAP_P((     /* deprecated */
+       LDAP_CONST char *host,
+       int port ));
+
+LDAP_F( int )
+ldap_create LDAP_P((
+       LDAP **ldp ));
+
+LDAP_F( int )
+ldap_initialize LDAP_P((
+       LDAP **ldp,
+       LDAP_CONST char *url ));
+
+LDAP_F( int )
+ldap_start_tls_s LDAP_P((
+       LDAP *ld,
+       LDAPControl **serverctrls,
+       LDAPControl **clientctrls ));
+
+/*
+ * in messages.c:
+ */
+LDAP_F( LDAPMessage * )
+ldap_first_message LDAP_P((
+       LDAP *ld,
+       LDAPMessage *chain ));
+
+LDAP_F( LDAPMessage * )
+ldap_next_message LDAP_P((
+       LDAP *ld,
+       LDAPMessage *msg ));
+
+LDAP_F( int )
+ldap_count_messages LDAP_P((
+       LDAP *ld,
+       LDAPMessage *chain ));
+
+
+/*
+ * in references.c:
+ */
+LDAP_F( LDAPMessage * )
+ldap_first_reference LDAP_P((
+       LDAP *ld,
+       LDAPMessage *chain ));
+
+LDAP_F( LDAPMessage * )
+ldap_next_reference LDAP_P((
+       LDAP *ld,
+       LDAPMessage *ref ));
+
+LDAP_F( int )
+ldap_count_references LDAP_P((
+       LDAP *ld,
+       LDAPMessage *chain ));
+
+LDAP_F( int )
+ldap_parse_reference LDAP_P((
+       LDAP                    *ld,
+       LDAPMessage             *ref,
+       char                    ***referralsp,
+       LDAPControl             ***serverctrls,
+       int                             freeit));
+
+
+/*
+ * in getentry.c:
+ */
+LDAP_F( LDAPMessage * )
+ldap_first_entry LDAP_P((
+       LDAP *ld,
+       LDAPMessage *chain ));
+
+LDAP_F( LDAPMessage * )
+ldap_next_entry LDAP_P((
+       LDAP *ld,
+       LDAPMessage *entry ));
+
+LDAP_F( int )
+ldap_count_entries LDAP_P((
+       LDAP *ld,
+       LDAPMessage *chain ));
+
+LDAP_F( int )
+ldap_get_entry_controls LDAP_P((
+       LDAP                    *ld,
+       LDAPMessage             *entry,
+       LDAPControl             ***serverctrls));
+
+
+/*
+ * in addentry.c
+ */
+LDAP_F( LDAPMessage * )
+ldap_delete_result_entry LDAP_P((
+       LDAPMessage **list,
+       LDAPMessage *e ));
+
+LDAP_F( void )
+ldap_add_result_entry LDAP_P((
+       LDAPMessage **list,
+       LDAPMessage *e ));
+
+
+/*
+ * in getdn.c
+ */
+LDAP_F( char * )
+ldap_get_dn LDAP_P((
+       LDAP *ld,
+       LDAPMessage *entry ));
+
+typedef struct ldap_ava {
+       struct berval la_attr;
+       struct berval la_value;
+       unsigned la_flags;
+#define LDAP_AVA_STRING                0x0000U
+#define LDAP_AVA_BINARY                0x0001U
+#define LDAP_AVA_NONPRINTABLE  0x0002U
+
+       void *la_private;
+} LDAPAVA;
+
+typedef LDAPAVA** LDAPRDN;
+typedef LDAPRDN** LDAPDN;
+
+/* DN formats */
+#define LDAP_DN_FORMAT_LDAP            0x0000U
+#define LDAP_DN_FORMAT_LDAPV3          0x0010U
+#define LDAP_DN_FORMAT_LDAPV2          0x0020U
+#define LDAP_DN_FORMAT_DCE             0x0030U
+#define LDAP_DN_FORMAT_UFN             0x0040U /* dn2str only */
+#define LDAP_DN_FORMAT_AD_CANONICAL    0x0050U /* dn2str only */
+#define LDAP_DN_FORMAT_LBER            0x00F0U /* for testing only */
+#define LDAP_DN_FORMAT_MASK            0x00F0U
+
+/* DN flags */
+#define LDAP_DN_PRETTY                 0x0100U
+#define LDAP_DN_SKIP                   0x0200U
+#define LDAP_DN_P_NOLEADTRAILSPACES    0x1000U
+#define LDAP_DN_P_NOSPACEAFTERRDN      0x2000U
+#define LDAP_DN_PEDANTIC               0xF000U
+
+LDAP_F( void )
+ldap_avafree LDAP_P(( LDAPAVA *ava ));
+LDAP_F( void )
+ldap_rdnfree LDAP_P(( LDAPRDN *rdn ));
+LDAP_F( void )
+ldap_dnfree LDAP_P(( LDAPDN *dn ));
+
+LDAP_F( int )
+ldap_bv2dn LDAP_P(( 
+       struct berval *bv, 
+       LDAPDN **dn, 
+       unsigned flags ));
+
+LDAP_F( int )
+ldap_str2dn LDAP_P((
+       LDAP_CONST char *str,
+       LDAPDN **dn,
+       unsigned flags ));
+
+LDAP_F( int )
+ldap_dn2bv LDAP_P((
+       LDAPDN *dn,
+       struct berval *bv,
+       unsigned flags ));
+
+LDAP_F( int )
+ldap_dn2str LDAP_P((
+       LDAPDN *dn,
+       char **str,
+       unsigned flags ));
+
+LDAP_F( int )
+ldap_bv2rdn LDAP_P((
+       struct berval *bv,
+       LDAPRDN **rdn,
+       char **next,
+       unsigned flags ));
+
+LDAP_F( int )
+ldap_str2rdn LDAP_P((
+       LDAP_CONST char *str,
+       LDAPRDN **rdn,
+       char **next,
+       unsigned flags ));
+
+LDAP_F( int )
+ldap_rdn2bv LDAP_P((
+       LDAPRDN *rdn,
+       struct berval *bv,
+       unsigned flags ));
+
+LDAP_F( int )
+ldap_rdn2str LDAP_P((
+       LDAPRDN *rdn,
+       char **str,
+       unsigned flags ));
+
+LDAP_F( int )
+ldap_dn_normalize LDAP_P((
+       LDAP_CONST char *in, unsigned iflags,
+       char **out, unsigned oflags ));
+
+LDAP_F( char * )
+ldap_dn2ufn LDAP_P(( /* deprecated */
+       LDAP_CONST char *dn ));
+
+LDAP_F( char ** )
+ldap_explode_dn LDAP_P(( /* deprecated */
+       LDAP_CONST char *dn,
+       int notypes ));
+
+LDAP_F( char ** )
+ldap_explode_rdn LDAP_P(( /* deprecated */
+       LDAP_CONST char *rdn,
+       int notypes ));
+
+LDAP_F( char * )
+ldap_dn2dcedn LDAP_P(( LDAP_CONST char *dn )); /* deprecated */
+
+LDAP_F( char * )
+ldap_dcedn2dn LDAP_P(( LDAP_CONST char *dce ));        /* deprecated */
+
+LDAP_F( char * )
+ldap_dn2ad_canonical LDAP_P(( LDAP_CONST char *dn ));  /* deprecated */
+
+/*
+ * in getattr.c
+ */
+LDAP_F( char * )
+ldap_first_attribute LDAP_P((
+       LDAP *ld,
+       LDAPMessage *entry,
+       BerElement **ber ));
+
+LDAP_F( char * )
+ldap_next_attribute LDAP_P((
+       LDAP *ld,
+       LDAPMessage *entry,
+       BerElement *ber ));
+
+
+/*
+ * in getvalues.c
+ */
+LDAP_F( struct berval ** )
+ldap_get_values_len LDAP_P((
+       LDAP *ld,
+       LDAPMessage *entry,
+       LDAP_CONST char *target ));
+
+LDAP_F( int )
+ldap_count_values_len LDAP_P((
+       struct berval **vals ));
+
+LDAP_F( void )
+ldap_value_free_len LDAP_P((
+       struct berval **vals ));
+
+LDAP_F( char ** )
+ldap_get_values LDAP_P((       /* deprecated */
+       LDAP *ld,
+       LDAPMessage *entry,
+       LDAP_CONST char *target ));
+
+LDAP_F( int )
+ldap_count_values LDAP_P((     /* deprecated */
+       char **vals ));
+
+LDAP_F( void )
+ldap_value_free LDAP_P((       /* deprecated */
+       char **vals ));
+
+/*
+ * in result.c:
+ */
+LDAP_F( int )
+ldap_result LDAP_P((
+       LDAP *ld,
+       int msgid,
+       int all,
+       struct timeval *timeout,
+       LDAPMessage **result ));
+
+LDAP_F( int )
+ldap_msgtype LDAP_P((
+       LDAPMessage *lm ));
+
+LDAP_F( int )
+ldap_msgid   LDAP_P((
+       LDAPMessage *lm ));
+
+LDAP_F( int )
+ldap_msgfree LDAP_P((
+       LDAPMessage *lm ));
+
+LDAP_F( int )
+ldap_msgdelete LDAP_P((
+       LDAP *ld,
+       int msgid ));
+
+
+/*
+ * in search.c:
+ */
+LDAP_F( int )
+ldap_search_ext LDAP_P((
+       LDAP                    *ld,
+       LDAP_CONST char *base,
+       int                             scope,
+       LDAP_CONST char *filter,
+       char                    **attrs,
+       int                             attrsonly,
+       LDAPControl             **serverctrls,
+       LDAPControl             **clientctrls,
+       struct timeval  *timeout,
+       int                             sizelimit,
+       int                             *msgidp ));
+
+LDAP_F( int )
+ldap_search_ext_s LDAP_P((
+       LDAP                    *ld,
+       LDAP_CONST char *base,
+       int                             scope,
+       LDAP_CONST char *filter,
+       char                    **attrs,
+       int                             attrsonly,
+       LDAPControl             **serverctrls,
+       LDAPControl             **clientctrls,
+       struct timeval  *timeout,
+       int                             sizelimit,
+       LDAPMessage             **res ));
+
+LDAP_F( int )
+ldap_search LDAP_P((   /* deprecated */
+       LDAP *ld,
+       LDAP_CONST char *base,
+       int scope,
+       LDAP_CONST char *filter,
+       char **attrs,
+       int attrsonly ));
+
+LDAP_F( int )
+ldap_search_s LDAP_P(( /* deprecated */
+       LDAP *ld,
+       LDAP_CONST char *base,
+       int scope,
+       LDAP_CONST char *filter,
+       char **attrs,
+       int attrsonly,
+       LDAPMessage **res ));
+
+LDAP_F( int )
+ldap_search_st LDAP_P((        /* deprecated */
+       LDAP *ld,
+       LDAP_CONST char *base,
+       int scope,
+       LDAP_CONST char *filter,
+    char **attrs,
+       int attrsonly,
+       struct timeval *timeout,
+       LDAPMessage **res ));
+
+/*
+ * in unbind.c
+ */
+LDAP_F( int )
+ldap_unbind LDAP_P(( /* deprecated */
+       LDAP *ld ));
+
+LDAP_F( int )
+ldap_unbind_s LDAP_P(( /* deprecated */
+       LDAP *ld ));
+
+LDAP_F( int )
+ldap_unbind_ext LDAP_P((
+       LDAP                    *ld,
+       LDAPControl             **serverctrls,
+       LDAPControl             **clientctrls));
+
+LDAP_F( int )
+ldap_unbind_ext_s LDAP_P((
+       LDAP                    *ld,
+       LDAPControl             **serverctrls,
+       LDAPControl             **clientctrls));
+
+/*
+ * in getfilter.c
+ *     (deprecated)
+ */
+LDAP_F( LDAPFiltDesc * )
+ldap_init_getfilter LDAP_P(( /* deprecated */
+       LDAP_CONST char *fname ));
+
+LDAP_F( LDAPFiltInfo * )
+ldap_getfirstfilter LDAP_P(( /* deprecated */
+       LDAPFiltDesc *lfdp,
+       /* LDAP_CONST */ char *tagpat,
+       /* LDAP_CONST */ char *value ));
+
+LDAP_F( LDAPFiltInfo * )
+ldap_getnextfilter LDAP_P(( /* deprecated */
+       LDAPFiltDesc *lfdp ));
+
+
+/*
+ * in free.c
+ */
+
+LDAP_F( void * )
+ldap_memalloc LDAP_P((
+       ber_len_t s ));
+
+LDAP_F( void * )
+ldap_memrealloc LDAP_P((
+       void* p,
+       ber_len_t s ));
+
+LDAP_F( void * )
+ldap_memcalloc LDAP_P((
+       ber_len_t n,
+       ber_len_t s ));
+
+LDAP_F( void )
+ldap_memfree LDAP_P((
+       void* p ));
+
+LDAP_F( void )
+ldap_memvfree LDAP_P((
+       void** v ));
+
+LDAP_F( char * )
+ldap_strdup LDAP_P((
+       LDAP_CONST char * ));
+
+LDAP_F( void )
+ldap_getfilter_free LDAP_P((
+       LDAPFiltDesc *lfdp ));
+
+LDAP_F( void )
+ldap_mods_free LDAP_P((
+       LDAPMod **mods,
+       int freemods ));
+
+
+/*
+ * in sort.c
+ *     (deprecated)
+ */
+typedef int (LDAP_SORT_AD_CMP_PROC) LDAP_P(( /* deprecated */
+       LDAP_CONST char *left,
+       LDAP_CONST char *right ));
+
+typedef int (LDAP_SORT_AV_CMP_PROC) LDAP_P(( /* deprecated */
+       LDAP_CONST void *left,
+       LDAP_CONST void *right ));
+
+LDAP_F( int )  /* deprecated */
+ldap_sort_entries LDAP_P(( LDAP *ld,
+       LDAPMessage **chain,
+       LDAP_CONST char *attr,
+       LDAP_SORT_AD_CMP_PROC *cmp ));
+
+LDAP_F( int )  /* deprecated */
+ldap_sort_values LDAP_P((
+       LDAP *ld,
+       char **vals,
+       LDAP_SORT_AV_CMP_PROC *cmp ));
+
+LDAP_F( int ) /* deprecated */
+ldap_sort_strcasecmp LDAP_P((
+       LDAP_CONST void *a,
+       LDAP_CONST void *b ));
+
+
+/*
+ * in url.c
+ */
+LDAP_F( int )
+ldap_is_ldap_url LDAP_P((
+       LDAP_CONST char *url ));
+
+LDAP_F( int )
+ldap_is_ldaps_url LDAP_P((
+       LDAP_CONST char *url ));
+
+LDAP_F( int )
+ldap_is_ldapi_url LDAP_P((
+       LDAP_CONST char *url ));
+
+LDAP_F( int )
+ldap_url_parse LDAP_P((
+       LDAP_CONST char *url,
+       LDAPURLDesc **ludpp ));
+
+LDAP_F( char * )
+ldap_url_desc2str LDAP_P((
+       LDAPURLDesc *ludp ));
+
+LDAP_F( void )
+ldap_free_urldesc LDAP_P((
+       LDAPURLDesc *ludp ));
+
+/*
+ * in sortctrl.c
+ */
+/*
+ * structure for a sort-key
+ */
+typedef struct ldapsortkey {
+       char *  attributeType;
+       char *  orderingRule;
+       int     reverseOrder;
+} LDAPSortKey;
+
+LDAP_F( int )
+ldap_create_sort_keylist LDAP_P((
+       LDAPSortKey ***sortKeyList,
+       char        *keyString ));
+
+LDAP_F( void )
+ldap_free_sort_keylist LDAP_P((
+       LDAPSortKey **sortkeylist ));
+
+LDAP_F( int )
+ldap_create_sort_control LDAP_P((
+       LDAP *ld,
+       LDAPSortKey **keyList,
+       int ctl_iscritical,
+       LDAPControl **ctrlp ));
+
+LDAP_F( int )
+ldap_parse_sort_control LDAP_P((
+       LDAP           *ld,
+       LDAPControl    **ctrlp,
+       unsigned long  *result,
+       char           **attribute ));
+
+
+/*
+ * in vlvctrl.c
+ */
+
+/*
+ * structure for virtul list.
+ */
+typedef struct ldapvlvinfo {
+       int             ldvlv_version;
+    unsigned long   ldvlv_before_count;
+    unsigned long   ldvlv_after_count;
+    unsigned long   ldvlv_offset;
+    unsigned long   ldvlv_count;
+    struct berval  *ldvlv_attrvalue;
+    struct berval  *ldvlv_context;
+    void           *ldvlv_extradata;
+} LDAPVLVInfo;
+
+LDAP_F( int )
+ldap_create_vlv_control LDAP_P((
+       LDAP *ld,
+       LDAPVLVInfo *ldvlistp,
+       LDAPControl **ctrlp ));
+
+LDAP_F( int )
+ldap_parse_vlv_control LDAP_P((
+       LDAP          *ld,
+       LDAPControl   **ctrls,
+       unsigned long *target_posp,
+       unsigned long *list_countp,
+       struct berval **contextp,
+       int           *errcodep ));
+
+
+LDAP_END_DECL
 #endif /* _LDAP_H */
diff --git a/servers/slapd/at.c b/servers/slapd/at.c
new file mode 100644 (file)
index 0000000..9101500
--- /dev/null
@@ -0,0 +1,479 @@
+/* $OpenLDAP$ */
+/*
+ * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ */
+/* at.c - routines for dealing with attribute types */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/ctype.h>
+#include <ac/errno.h>
+#include <ac/socket.h>
+#include <ac/string.h>
+#include <ac/time.h>
+
+#include "ldap_pvt.h"
+#include "slap.h"
+
+
+int is_at_syntax(
+       AttributeType *at,
+       const char *oid )
+{
+       for( ; at != NULL; at = at->sat_sup ) {
+               if( at->sat_syntax_oid ) {
+                       return ( strcmp( at->sat_syntax_oid, oid ) == 0 );
+               }
+       }
+
+       return 0;
+}
+
+int is_at_subtype(
+       AttributeType *sub,
+       AttributeType *sup )
+{
+       for( ; sub != NULL; sub = sub->sat_sup ) {
+               if( sub == sup ) return 1;
+       }
+
+       return 0;
+}
+
+struct aindexrec {
+       struct berval   air_name;
+       AttributeType   *air_at;
+};
+
+static Avlnode *attr_index = NULL;
+static AttributeType *attr_list = NULL;
+
+static int
+attr_index_cmp(
+    struct aindexrec   *air1,
+    struct aindexrec   *air2
+)
+{
+       int i = air1->air_name.bv_len - air2->air_name.bv_len;
+       if (i)
+               return i;
+       return (strcasecmp( air1->air_name.bv_val, air2->air_name.bv_val ));
+}
+
+static int
+attr_index_name_cmp(
+    struct berval      *type,
+    struct aindexrec   *air
+)
+{
+       int i = type->bv_len - air->air_name.bv_len;
+       if (i)
+               return i;
+       return (strncasecmp( type->bv_val, air->air_name.bv_val,
+               type->bv_len ));
+}
+
+AttributeType *
+at_find(
+    const char         *name
+)
+{
+       struct berval bv;
+
+       bv.bv_val = (char *)name;
+       bv.bv_len = strlen( name );
+
+       return at_bvfind( &bv );
+}
+
+AttributeType *
+at_bvfind(
+    struct berval      *name
+)
+{
+       struct aindexrec *air;
+
+       air = (struct aindexrec *) avl_find( attr_index, name,
+            (AVL_CMP) attr_index_name_cmp );
+
+       return air != NULL ? air->air_at : NULL;
+}
+
+int
+at_append_to_list(
+    AttributeType      *sat,
+    AttributeType      ***listp
+)
+{
+       AttributeType   **list;
+       AttributeType   **list1;
+       int             size;
+
+       list = *listp;
+       if ( !list ) {
+               size = 2;
+               list = ch_calloc(size, sizeof(AttributeType *));
+               if ( !list ) {
+                       return -1;
+               }
+       } else {
+               size = 0;
+               list1 = *listp;
+               while ( *list1 ) {
+                       size++;
+                       list1++;
+               }
+               size += 2;
+               list1 = ch_realloc(list, size*sizeof(AttributeType *));
+               if ( !list1 ) {
+                       return -1;
+               }
+               list = list1;
+       }
+       list[size-2] = sat;
+       list[size-1] = NULL;
+       *listp = list;
+       return 0;
+}
+
+int
+at_delete_from_list(
+    int                        pos,
+    AttributeType      ***listp
+)
+{
+       AttributeType   **list;
+       AttributeType   **list1;
+       int             i;
+       int             j;
+
+       if ( pos < 0 ) {
+               return -2;
+       }
+       list = *listp;
+       for ( i=0; list[i]; i++ )
+               ;
+       if ( pos >= i ) {
+               return -2;
+       }
+       for ( i=pos, j=pos+1; list[j]; i++, j++ ) {
+               list[i] = list[j];
+       }
+       list[i] = NULL;
+       /* Tell the runtime this can be shrinked */
+       list1 = ch_realloc(list, (i+1)*sizeof(AttributeType **));
+       if ( !list1 ) {
+               return -1;
+       }
+       *listp = list1;
+       return 0;
+}
+
+int
+at_find_in_list(
+    AttributeType      *sat,
+    AttributeType      **list
+)
+{
+       int     i;
+
+       if ( !list ) {
+               return -1;
+       }
+       for ( i=0; list[i]; i++ ) {
+               if ( sat == list[i] ) {
+                       return i;
+               }
+       }
+       return -1;
+}
+
+void
+at_destroy( void )
+{
+       AttributeType *a, *n;
+       avl_free(attr_index, ldap_memfree);
+
+       for (a=attr_list; a; a=n) {
+               n = a->sat_next;
+               if (a->sat_subtypes) ldap_memfree(a->sat_subtypes);
+               ad_destroy(a->sat_ad);
+               ldap_pvt_thread_mutex_destroy(&a->sat_ad_mutex);
+               ldap_attributetype_free((LDAPAttributeType *)a);
+       }
+       if ( slap_schema.si_at_undefined )
+               ad_destroy(slap_schema.si_at_undefined->sat_ad);
+}
+
+static int
+at_insert(
+    AttributeType      *sat,
+    const char         **err
+)
+{
+       AttributeType           **atp;
+       struct aindexrec        *air;
+       char                    **names;
+
+       atp = &attr_list;
+       while ( *atp != NULL ) {
+               atp = &(*atp)->sat_next;
+       }
+       *atp = sat;
+
+       if ( sat->sat_oid ) {
+               air = (struct aindexrec *)
+                       ch_calloc( 1, sizeof(struct aindexrec) );
+               air->air_name.bv_val = sat->sat_oid;
+               air->air_name.bv_len = strlen(sat->sat_oid);
+               air->air_at = sat;
+               if ( avl_insert( &attr_index, (caddr_t) air,
+                                (AVL_CMP) attr_index_cmp,
+                                (AVL_DUP) avl_dup_error ) ) {
+                       *err = sat->sat_oid;
+                       ldap_memfree(air);
+                       return SLAP_SCHERR_DUP_ATTR;
+               }
+               /* FIX: temporal consistency check */
+               at_bvfind(&air->air_name);
+       }
+
+       if ( (names = sat->sat_names) ) {
+               while ( *names ) {
+                       air = (struct aindexrec *)
+                               ch_calloc( 1, sizeof(struct aindexrec) );
+                       air->air_name.bv_val = *names;
+                       air->air_name.bv_len = strlen(*names);
+                       air->air_at = sat;
+                       if ( avl_insert( &attr_index, (caddr_t) air,
+                                        (AVL_CMP) attr_index_cmp,
+                                        (AVL_DUP) avl_dup_error ) ) {
+                               *err = *names;
+                               ldap_memfree(air);
+                               return SLAP_SCHERR_DUP_ATTR;
+                       }
+                       /* FIX: temporal consistency check */
+                       at_bvfind(&air->air_name);
+                       names++;
+               }
+       }
+
+       return 0;
+}
+
+int
+at_add(
+    LDAPAttributeType  *at,
+    const char         **err
+)
+{
+       AttributeType   *sat;
+       MatchingRule    *mr;
+       Syntax          *syn;
+       int             code;
+       char    *cname;
+       char    *oid;
+
+       if ( !OID_LEADCHAR( at->at_oid[0] )) {
+               /* Expand OID macros */
+               oid = oidm_find( at->at_oid );
+               if ( !oid ) {
+                       *err = at->at_oid;
+                       return SLAP_SCHERR_OIDM;
+               }
+               if ( oid != at->at_oid ) {
+                       ldap_memfree( at->at_oid );
+                       at->at_oid = oid;
+               }
+       }
+
+       if ( at->at_syntax_oid && !OID_LEADCHAR( at->at_syntax_oid[0] )) {
+               /* Expand OID macros */
+               oid = oidm_find( at->at_syntax_oid );
+               if ( !oid ) {
+                       *err = at->at_syntax_oid;
+                       return SLAP_SCHERR_OIDM;
+               }
+               if ( oid != at->at_syntax_oid ) {
+                       ldap_memfree( at->at_syntax_oid );
+                       at->at_syntax_oid = oid;
+               }
+
+       }
+
+       if ( at->at_names && at->at_names[0] ) {
+               int i;
+
+               for( i=0; at->at_names[i]; i++ ) {
+                       if( !slap_valid_descr( at->at_names[i] ) ) {
+                               *err = at->at_names[i];
+                               return SLAP_SCHERR_BAD_DESCR;
+                       }
+               }
+
+               cname = at->at_names[0];
+
+       } else if ( at->at_oid ) {
+               cname = at->at_oid;
+
+       } else {
+               *err = "";
+               return SLAP_SCHERR_ATTR_INCOMPLETE;
+       }
+
+       *err = cname;
+
+       if ( !at->at_usage && at->at_no_user_mod ) {
+               /* user attribute must be modifable */
+               return SLAP_SCHERR_ATTR_BAD_USAGE;
+       }
+
+       if ( at->at_collective ) {
+               if( at->at_usage ) {
+                       /* collective attributes cannot be operational */
+                       return SLAP_SCHERR_ATTR_BAD_USAGE;
+               }
+
+               if( at->at_single_value ) {
+                       /* collective attributes cannot be single-valued */
+                       return SLAP_SCHERR_ATTR_BAD_USAGE;
+               }
+
+               /* collective attributes not supported */
+               return SLAP_SCHERR_NOT_SUPPORTED;
+       }
+
+       sat = (AttributeType *) ch_calloc( 1, sizeof(AttributeType) );
+       AC_MEMCPY( &sat->sat_atype, at, sizeof(LDAPAttributeType));
+
+       sat->sat_cname.bv_val = cname;
+       sat->sat_cname.bv_len = strlen( cname );
+       ldap_pvt_thread_mutex_init(&sat->sat_ad_mutex);
+
+       if ( at->at_sup_oid ) {
+               AttributeType *supsat = at_find(at->at_sup_oid);
+
+               if ( (supsat == NULL ) ) {
+                       *err = at->at_sup_oid;
+                       return SLAP_SCHERR_ATTR_NOT_FOUND;
+               }
+
+               sat->sat_sup = supsat;
+
+               if ( at_append_to_list(sat, &supsat->sat_subtypes) ) {
+                       return SLAP_SCHERR_OUTOFMEM;
+               }
+
+               if ( sat->sat_usage != supsat->sat_usage ) {
+                       /* subtypes must have same usage as their SUP */
+                       return SLAP_SCHERR_ATTR_BAD_USAGE;
+               }
+       }
+
+       /*
+        * Inherit definitions from superiors.  We only check the
+        * direct superior since that one has already inherited from
+        * its own superiorss
+        */
+       if ( sat->sat_sup ) {
+               sat->sat_syntax = sat->sat_sup->sat_syntax;
+               sat->sat_equality = sat->sat_sup->sat_equality;
+               sat->sat_approx = sat->sat_sup->sat_approx;
+               sat->sat_ordering = sat->sat_sup->sat_ordering;
+               sat->sat_substr = sat->sat_sup->sat_substr;
+       }
+
+       if ( at->at_syntax_oid ) {
+               if ( (syn = syn_find(sat->sat_syntax_oid)) ) {
+                       sat->sat_syntax = syn;
+               } else {
+                       *err = sat->sat_syntax_oid;
+                       return SLAP_SCHERR_SYN_NOT_FOUND;
+               }
+
+
+       } else if ( sat->sat_syntax == NULL ) {
+               return SLAP_SCHERR_ATTR_INCOMPLETE;
+       }
+
+       if ( sat->sat_equality_oid ) {
+               if ( (mr = mr_find(sat->sat_equality_oid)) ) {
+                       sat->sat_equality = mr;
+                       sat->sat_approx = mr->smr_associated;
+               } else {
+                       *err = sat->sat_equality_oid;
+                       return SLAP_SCHERR_MR_NOT_FOUND;
+               }
+
+       }
+
+       if ( sat->sat_ordering_oid ) {
+               if ( (mr = mr_find(sat->sat_ordering_oid)) ) {
+                       sat->sat_ordering = mr;
+               } else {
+                       *err = sat->sat_ordering_oid;
+                       return SLAP_SCHERR_MR_NOT_FOUND;
+               }
+       }
+
+       if ( sat->sat_substr_oid ) {
+               if ( (mr = mr_find(sat->sat_substr_oid)) ) {
+                       sat->sat_substr = mr;
+               } else {
+                       *err = sat->sat_substr_oid;
+                       return SLAP_SCHERR_MR_NOT_FOUND;
+               }
+       }
+
+       code = at_insert(sat,err);
+       return code;
+}
+
+#ifdef LDAP_DEBUG
+static int
+at_index_printnode( struct aindexrec *air )
+{
+
+       printf("%s = %s\n",
+               air->air_name.bv_val,
+               ldap_attributetype2str(&air->air_at->sat_atype) );
+       return( 0 );
+}
+
+static void
+at_index_print( void )
+{
+       printf("Printing attribute type index:\n");
+       (void) avl_apply( attr_index, (AVL_APPLY) at_index_printnode,
+               0, -1, AVL_INORDER );
+}
+#endif
+
+#if defined( SLAPD_SCHEMA_DN )
+int
+at_schema_info( Entry *e )
+{
+       struct berval   vals[2];
+       AttributeType   *at;
+
+       AttributeDescription *ad_attributeTypes = slap_schema.si_ad_attributeTypes;
+
+       vals[1].bv_val = NULL;
+
+       for ( at = attr_list; at; at = at->sat_next ) {
+               if ( ldap_attributetype2bv( &at->sat_atype, vals ) == NULL ) {
+                       return -1;
+               }
+#if 0
+               Debug( LDAP_DEBUG_TRACE, "Merging at [%ld] %s\n",
+                      (long) vals[0].bv_len, vals[0].bv_val, 0 );
+#endif
+               attr_merge( e, ad_attributeTypes, vals );
+               ldap_memfree( vals[0].bv_val );
+       }
+       return 0;
+}
+#endif
diff --git a/servers/slapd/schema_init.c b/servers/slapd/schema_init.c
new file mode 100644 (file)
index 0000000..d8d8249
--- /dev/null
@@ -0,0 +1,4683 @@
+/* schema_init.c - init builtin schema */
+/* $OpenLDAP$ */
+/*
+ * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <limits.h>
+
+#include <ac/ctype.h>
+#include <ac/errno.h>
+#include <ac/string.h>
+#include <ac/socket.h>
+
+#include "slap.h"
+#include "ldap_pvt.h"
+#include "lber_pvt.h"
+
+#include "ldap_utf8.h"
+
+#include "lutil_hash.h"
+#define HASH_BYTES                             LUTIL_HASH_BYTES
+#define HASH_CONTEXT                   lutil_HASH_CTX
+#define HASH_Init(c)                   lutil_HASHInit(c)
+#define HASH_Update(c,buf,len) lutil_HASHUpdate(c,buf,len)
+#define HASH_Final(d,c)                        lutil_HASHFinal(d,c)
+
+/* recycled validatation routines */
+#define berValidate                                            blobValidate
+
+/* unimplemented pretters */
+#define integerPretty                                  NULL
+
+/* recycled matching routines */
+#define bitStringMatch                                 octetStringMatch
+#define numericStringMatch                             caseIgnoreIA5Match
+#define objectIdentifierMatch                  caseIgnoreIA5Match
+#define telephoneNumberMatch                   caseIgnoreIA5Match
+#define telephoneNumberSubstringsMatch caseIgnoreIA5SubstringsMatch
+#define generalizedTimeMatch                   caseIgnoreIA5Match
+#define generalizedTimeOrderingMatch   caseIgnoreIA5Match
+#define uniqueMemberMatch                              dnMatch
+
+/* approx matching rules */
+#define directoryStringApproxMatchOID  "1.3.6.1.4.1.4203.666.4.4"
+#define directoryStringApproxMatch     approxMatch
+#define directoryStringApproxIndexer   approxIndexer
+#define directoryStringApproxFilter    approxFilter
+#define IA5StringApproxMatchOID                        "1.3.6.1.4.1.4203.666.4.5"
+#define IA5StringApproxMatch                   approxMatch
+#define IA5StringApproxIndexer                 approxIndexer
+#define IA5StringApproxFilter                  approxFilter
+
+/* orderring matching rules */
+#define caseIgnoreOrderingMatch                        caseIgnoreMatch
+#define caseExactOrderingMatch                 caseExactMatch
+
+/* unimplemented matching routines */
+#define caseIgnoreListMatch                            NULL
+#define caseIgnoreListSubstringsMatch  NULL
+#define protocolInformationMatch               NULL
+#define integerFirstComponentMatch             NULL
+
+#ifdef SLAPD_ACI_ENABLED
+#define OpenLDAPaciMatch                               NULL
+#endif
+#ifdef SLAPD_AUTHPASSWD
+#define authPasswordMatch                              NULL
+#endif
+
+/* recycled indexing/filtering routines */
+#define dnIndexer                              caseExactIgnoreIndexer
+#define dnFilter                               caseExactIgnoreFilter
+#define bitStringFilter                        octetStringFilter
+#define bitStringIndexer               octetStringIndexer
+
+#define telephoneNumberIndexer                 caseIgnoreIA5Indexer
+#define telephoneNumberFilter                  caseIgnoreIA5Filter
+#define telephoneNumberSubstringsIndexer       caseIgnoreIA5SubstringsIndexer
+#define telephoneNumberSubstringsFilter                caseIgnoreIA5SubstringsFilter
+
+/* must match OIDs below */
+#define caseExactMatchOID                      "2.5.13.5"
+#define caseExactSubstringsMatchOID            "2.5.13.7"
+
+static char *bvcasechr( struct berval *bv, int c, ber_len_t *len )
+{
+       ber_len_t i;
+       int lower = TOLOWER( c );
+       int upper = TOUPPER( c );
+
+       if( c == 0 ) return NULL;
+       
+       for( i=0; i < bv->bv_len; i++ ) {
+               if( upper == bv->bv_val[i] || lower == bv->bv_val[i] ) {
+                       *len = i;
+                       return &bv->bv_val[i];
+               }
+       }
+
+       return NULL;
+}
+
+static int
+octetStringMatch(
+       int *matchp,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *value,
+       void *assertedValue )
+{
+       int match = value->bv_len - ((struct berval *) assertedValue)->bv_len;
+
+       if( match == 0 ) {
+               match = memcmp( value->bv_val,
+                       ((struct berval *) assertedValue)->bv_val,
+                       value->bv_len );
+       }
+
+       *matchp = match;
+       return LDAP_SUCCESS;
+}
+
+/* Index generation function */
+static int octetStringIndexer(
+       slap_mask_t use,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *prefix,
+       BerVarray values,
+       BerVarray *keysp )
+{
+       int i;
+       size_t slen, mlen;
+       BerVarray keys;
+       HASH_CONTEXT   HASHcontext;
+       unsigned char   HASHdigest[HASH_BYTES];
+       struct berval digest;
+       digest.bv_val = HASHdigest;
+       digest.bv_len = sizeof(HASHdigest);
+
+       for( i=0; values[i].bv_val != NULL; i++ ) {
+               /* just count them */
+       }
+
+       /* we should have at least one value at this point */
+       assert( i > 0 );
+
+       keys = ch_malloc( sizeof( struct berval ) * (i+1) );
+
+       slen = syntax->ssyn_oidlen;
+       mlen = mr->smr_oidlen;
+
+       for( i=0; values[i].bv_val != NULL; i++ ) {
+               HASH_Init( &HASHcontext );
+               if( prefix != NULL && prefix->bv_len > 0 ) {
+                       HASH_Update( &HASHcontext,
+                               prefix->bv_val, prefix->bv_len );
+               }
+               HASH_Update( &HASHcontext,
+                       syntax->ssyn_oid, slen );
+               HASH_Update( &HASHcontext,
+                       mr->smr_oid, mlen );
+               HASH_Update( &HASHcontext,
+                       values[i].bv_val, values[i].bv_len );
+               HASH_Final( HASHdigest, &HASHcontext );
+
+               ber_dupbv( &keys[i], &digest );
+       }
+
+       keys[i].bv_val = NULL;
+
+       *keysp = keys;
+
+       return LDAP_SUCCESS;
+}
+
+/* Index generation function */
+static int octetStringFilter(
+       slap_mask_t use,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *prefix,
+       void * assertValue,
+       BerVarray *keysp )
+{
+       size_t slen, mlen;
+       BerVarray keys;
+       HASH_CONTEXT   HASHcontext;
+       unsigned char   HASHdigest[HASH_BYTES];
+       struct berval *value = (struct berval *) assertValue;
+       struct berval digest;
+       digest.bv_val = HASHdigest;
+       digest.bv_len = sizeof(HASHdigest);
+
+       slen = syntax->ssyn_oidlen;
+       mlen = mr->smr_oidlen;
+
+       keys = ch_malloc( sizeof( struct berval ) * 2 );
+
+       HASH_Init( &HASHcontext );
+       if( prefix != NULL && prefix->bv_len > 0 ) {
+               HASH_Update( &HASHcontext,
+                       prefix->bv_val, prefix->bv_len );
+       }
+       HASH_Update( &HASHcontext,
+               syntax->ssyn_oid, slen );
+       HASH_Update( &HASHcontext,
+               mr->smr_oid, mlen );
+       HASH_Update( &HASHcontext,
+               value->bv_val, value->bv_len );
+       HASH_Final( HASHdigest, &HASHcontext );
+
+       ber_dupbv( keys, &digest );
+       keys[1].bv_val = NULL;
+
+       *keysp = keys;
+
+       return LDAP_SUCCESS;
+}
+
+static int
+nameUIDValidate(
+       Syntax *syntax,
+       struct berval *in )
+{
+       int rc;
+       struct berval dn;
+
+       if( in->bv_len == 0 ) return LDAP_SUCCESS;
+
+       ber_dupbv( &dn, in );
+       if( !dn.bv_val ) return LDAP_OTHER;
+
+       if( dn.bv_val[dn.bv_len-1] == 'B'
+               && dn.bv_val[dn.bv_len-2] == '\'' )
+       {
+               /* assume presence of optional UID */
+               ber_len_t i;
+
+               for(i=dn.bv_len-3; i>1; i--) {
+                       if( dn.bv_val[i] != '0' &&      dn.bv_val[i] != '1' ) {
+                               break;
+                       }
+               }
+               if( dn.bv_val[i] != '\'' ||
+                   dn.bv_val[i-1] != '#' ) {
+                       ber_memfree( dn.bv_val );
+                       return LDAP_INVALID_SYNTAX;
+               }
+
+               /* trim the UID to allow use of dnValidate */
+               dn.bv_val[i-1] = '\0';
+               dn.bv_len = i-1;
+       }
+
+       rc = dnValidate( NULL, &dn );
+
+       ber_memfree( &dn );
+       return rc;
+}
+
+static int
+nameUIDNormalize(
+       Syntax *syntax,
+       struct berval *val,
+       struct berval *normalized )
+{
+       struct berval out;
+       int rc;
+
+       ber_dupbv( &out, val );
+       if( out.bv_len != 0 ) {
+               ber_len_t dnlen;
+               char *uid = NULL;
+               ber_len_t uidlen = 0;
+
+               if( out.bv_val[out.bv_len-1] == '\'' ) {
+                       /* assume presence of optional UID */
+                       uid = strrchr( out.bv_val, '#' );
+
+                       if( uid == NULL ) {
+                               free( out.bv_val );
+                               return LDAP_INVALID_SYNTAX;
+                       }
+
+                       uidlen = out.bv_len - (uid - out.bv_val);
+                       /* temporarily trim the UID */
+                       *uid = '\0';
+                       out.bv_len -= uidlen;
+               }
+
+#ifdef USE_DN_NORMALIZE
+               rc = dnNormalize2( NULL, &out, normalized );
+#else
+               rc = dnPretty2( NULL, &out, normalized );
+#endif
+
+               if( rc != LDAP_SUCCESS ) {
+                       free( out.bv_val );
+                       return LDAP_INVALID_SYNTAX;
+               }
+
+               dnlen = normalized->bv_len;
+
+               if( uidlen ) {
+                       struct berval b2;
+                       b2.bv_val = ch_malloc(dnlen + uidlen + 1);
+                       AC_MEMCPY( b2.bv_val, normalized->bv_val, dnlen );
+
+                       /* restore the separator */
+                       *uid = '#';
+                       /* shift the UID */
+                       AC_MEMCPY( normalized->bv_val+dnlen, uid, uidlen );
+                       b2.bv_len = dnlen + uidlen;
+                       normalized->bv_val[dnlen+uidlen] = '\0';
+                       free(normalized->bv_val);
+                       *normalized = b2;
+               }
+               free( out.bv_val );
+       }
+
+       return LDAP_SUCCESS;
+}
+
+static int
+inValidate(
+       Syntax *syntax,
+       struct berval *in )
+{
+       /* any value allowed */
+       return LDAP_OTHER;
+}
+
+static int
+blobValidate(
+       Syntax *syntax,
+       struct berval *in )
+{
+       /* any value allowed */
+       return LDAP_SUCCESS;
+}
+
+static int
+bitStringValidate(
+       Syntax *syntax,
+       struct berval *in )
+{
+       ber_len_t i;
+
+       /* very unforgiving validation, requires no normalization
+        * before simplistic matching
+        */
+       if( in->bv_len < 3 ) {
+               return LDAP_INVALID_SYNTAX;
+       }
+
+       /*
+        * rfc 2252 section 6.3 Bit String
+        * bitstring = "'" *binary-digit "'"
+        * binary-digit = "0" / "1"
+        * example: '0101111101'B
+        */
+       
+       if( in->bv_val[0] != '\'' ||
+               in->bv_val[in->bv_len-2] != '\'' ||
+               in->bv_val[in->bv_len-1] != 'B' )
+       {
+               return LDAP_INVALID_SYNTAX;
+       }
+
+       for( i=in->bv_len-3; i>0; i-- ) {
+               if( in->bv_val[i] != '0' && in->bv_val[i] != '1' ) {
+                       return LDAP_INVALID_SYNTAX;
+               }
+       }
+
+       return LDAP_SUCCESS;
+}
+
+static int
+bitStringNormalize(
+       Syntax *syntax,
+       struct berval *val,
+       struct berval *normalized )
+{
+       /*
+        * A normalized bitString is has no extaneous (leading) zero bits.
+        * That is, '00010'B is normalized to '10'B
+        * However, as a special case, '0'B requires no normalization.
+        */
+       char *p;
+
+       /* start at the first bit */
+       p = &val->bv_val[1];
+
+       /* Find the first non-zero bit */
+       while ( *p == '0' ) p++;
+
+       if( *p == '\'' ) {
+               /* no non-zero bits */
+               ber_str2bv( "\'0\'B", sizeof("\'0\'B") - 1, 1, normalized );
+               goto done;
+       }
+
+       normalized->bv_val = ch_malloc( val->bv_len + 1 );
+
+       normalized->bv_val[0] = '\'';
+       normalized->bv_len = 1;
+
+       for( ; *p != '\0'; p++ ) {
+               normalized->bv_val[normalized->bv_len++] = *p;
+       }
+
+       normalized->bv_val[normalized->bv_len] = '\0';
+
+done:
+       return LDAP_SUCCESS;
+}
+
+/*
+ * Handling boolean syntax and matching is quite rigid.
+ * A more flexible approach would be to allow a variety
+ * of strings to be normalized and prettied into TRUE
+ * and FALSE.
+ */
+static int
+booleanValidate(
+       Syntax *syntax,
+       struct berval *in )
+{
+       /* very unforgiving validation, requires no normalization
+        * before simplistic matching
+        */
+
+       if( in->bv_len == 4 ) {
+               if( !memcmp( in->bv_val, "TRUE", 4 ) ) {
+                       return LDAP_SUCCESS;
+               }
+       } else if( in->bv_len == 5 ) {
+               if( !memcmp( in->bv_val, "FALSE", 5 ) ) {
+                       return LDAP_SUCCESS;
+               }
+       }
+
+       return LDAP_INVALID_SYNTAX;
+}
+
+static int
+booleanMatch(
+       int *matchp,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *value,
+       void *assertedValue )
+{
+       /* simplistic matching allowed by rigid validation */
+       struct berval *asserted = (struct berval *) assertedValue;
+       *matchp = value->bv_len != asserted->bv_len;
+       return LDAP_SUCCESS;
+}
+
+static int
+UTF8StringValidate(
+       Syntax *syntax,
+       struct berval *in )
+{
+       ber_len_t count;
+       int len;
+       unsigned char *u = in->bv_val;
+
+       if( !in->bv_len ) return LDAP_INVALID_SYNTAX;
+
+       for( count = in->bv_len; count > 0; count-=len, u+=len ) {
+               /* get the length indicated by the first byte */
+               len = LDAP_UTF8_CHARLEN2( u, len );
+
+               /* very basic checks */
+               switch( len ) {
+                       case 6:
+                               if( (u[5] & 0xC0) != 0x80 ) {
+                                       return LDAP_INVALID_SYNTAX;
+                               }
+                       case 5:
+                               if( (u[4] & 0xC0) != 0x80 ) {
+                                       return LDAP_INVALID_SYNTAX;
+                               }
+                       case 4:
+                               if( (u[3] & 0xC0) != 0x80 ) {
+                                       return LDAP_INVALID_SYNTAX;
+                               }
+                       case 3:
+                               if( (u[2] & 0xC0 )!= 0x80 ) {
+                                       return LDAP_INVALID_SYNTAX;
+                               }
+                       case 2:
+                               if( (u[1] & 0xC0) != 0x80 ) {
+                                       return LDAP_INVALID_SYNTAX;
+                               }
+                       case 1:
+                               /* CHARLEN already validated it */
+                               break;
+                       default:
+                               return LDAP_INVALID_SYNTAX;
+               }
+
+               /* make sure len corresponds with the offset
+                       to the next character */
+               if( LDAP_UTF8_OFFSET( u ) != len ) return LDAP_INVALID_SYNTAX;
+       }
+
+       if( count != 0 ) return LDAP_INVALID_SYNTAX;
+
+       return LDAP_SUCCESS;
+}
+
+static int
+UTF8StringNormalize(
+       Syntax *syntax,
+       struct berval *val,
+       struct berval *normalized )
+{
+       char *p, *q, *s, *e;
+       int len = 0;
+
+       p = val->bv_val;
+
+       /* Ignore initial whitespace */
+       /* All space is ASCII. All ASCII is 1 byte */
+       for ( ; p < val->bv_val + val->bv_len && ASCII_SPACE( p[ 0 ] ); p++ );
+
+       ber_mem2bv( p, val->bv_len - (p - val->bv_val), 1, normalized );
+       e = normalized->bv_val + val->bv_len - (p - val->bv_val);
+
+       assert( normalized->bv_val );
+
+       p = q = normalized->bv_val;
+       s = NULL;
+
+       while ( p < e ) {
+               q += len;
+               if ( ASCII_SPACE( *p ) ) {
+                       s = q - len;
+                       len = 1;
+                       *q = *p++;
+
+                       /* Ignore the extra whitespace */
+                       while ( ASCII_SPACE( *p ) ) {
+                               p++;
+                       }
+               } else {
+                       len = LDAP_UTF8_COPY(q,p);
+                       s=NULL;
+                       p+=len;
+               }
+       }
+
+       assert( normalized->bv_val < p );
+       assert( q+len <= p );
+
+       /* cannot start with a space */
+       assert( !ASCII_SPACE(normalized->bv_val[0]) );
+
+       /*
+        * If the string ended in space, backup the pointer one
+        * position.  One is enough because the above loop collapsed
+        * all whitespace to a single space.
+        */
+
+       if ( s != NULL ) {
+               len = q - s;
+               q = s;
+       }
+
+       /* cannot end with a space */
+       assert( !ASCII_SPACE( *q ) );
+
+       q += len;
+
+       /* null terminate */
+       *q = '\0';
+
+       normalized->bv_len = q - normalized->bv_val;
+
+       return LDAP_SUCCESS;
+}
+
+/* Returns Unicode canonically normalized copy of a substring assertion
+ * Skipping attribute description */
+static SubstringsAssertion *
+UTF8SubstringsassertionNormalize(
+       SubstringsAssertion *sa,
+       unsigned casefold )
+{
+       SubstringsAssertion *nsa;
+       int i;
+
+       nsa = (SubstringsAssertion *)ch_calloc( 1, sizeof(SubstringsAssertion) );
+       if( nsa == NULL ) {
+               return NULL;
+       }
+
+       if( sa->sa_initial.bv_val != NULL ) {
+               UTF8bvnormalize( &sa->sa_initial, &nsa->sa_initial, casefold );
+               if( nsa->sa_initial.bv_val == NULL ) {
+                       goto err;
+               }
+       }
+
+       if( sa->sa_any != NULL ) {
+               for( i=0; sa->sa_any[i].bv_val != NULL; i++ ) {
+                       /* empty */
+               }
+               nsa->sa_any = (struct berval *)ch_malloc( (i + 1) * sizeof(struct berval) );
+               for( i=0; sa->sa_any[i].bv_val != NULL; i++ ) {
+                       UTF8bvnormalize( &sa->sa_any[i], &nsa->sa_any[i], 
+                                       casefold );
+                       if( nsa->sa_any[i].bv_val == NULL ) {
+                               goto err;
+                       }
+               }
+               nsa->sa_any[i].bv_val = NULL;
+       }
+
+       if( sa->sa_final.bv_val != NULL ) {
+               UTF8bvnormalize( &sa->sa_final, &nsa->sa_final, casefold );
+               if( nsa->sa_final.bv_val == NULL ) {
+                       goto err;
+               }
+       }
+
+       return nsa;
+
+err:
+       if ( nsa->sa_final.bv_val ) free( nsa->sa_final.bv_val );
+       if ( nsa->sa_any )ber_bvarray_free( nsa->sa_any );
+       if ( nsa->sa_initial.bv_val ) free( nsa->sa_initial.bv_val );
+       ch_free( nsa );
+       return NULL;
+}
+
+/* Strip characters with the 8th bit set */
+static char *
+strip8bitChars(
+       char *in )      
+{
+       char *p = in, *q;
+  
+       if( in == NULL ) {
+               return NULL;
+       }
+       while( *p ) {
+               if( *p & 0x80 ) {
+                       q = p;
+                       while( *++q & 0x80 ) {
+                               /* empty */
+                       }
+                       p = AC_MEMCPY(p, q, strlen(q) + 1);
+               } else {
+                       p++;
+               }
+       }
+       return in;
+}
+
+#ifndef SLAPD_APPROX_OLDSINGLESTRING
+
+#if defined(SLAPD_APPROX_INITIALS)
+#define SLAPD_APPROX_DELIMITER "._ "
+#define SLAPD_APPROX_WORDLEN 2
+#else
+#define SLAPD_APPROX_DELIMITER " "
+#define SLAPD_APPROX_WORDLEN 1
+#endif
+
+static int
+approxMatch(
+       int *matchp,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *value,
+       void *assertedValue )
+{
+       char *val, *nval, *assertv, **values, **words, *c;
+       int i, count, len, nextchunk=0, nextavail=0;
+       size_t avlen;
+
+       /* Yes, this is necessary */
+       nval = UTF8normalize( value, LDAP_UTF8_NOCASEFOLD );
+       if( nval == NULL ) {
+               *matchp = 1;
+               return LDAP_SUCCESS;
+       }
+       strip8bitChars( nval );
+
+       /* Yes, this is necessary */
+       assertv = UTF8normalize( ((struct berval *)assertedValue),
+               LDAP_UTF8_NOCASEFOLD );
+       if( assertv == NULL ) {
+               ch_free( nval );
+               *matchp = 1;
+               return LDAP_SUCCESS;
+       }
+       strip8bitChars( assertv );
+       avlen = strlen( assertv );
+
+       /* Isolate how many words there are */
+       for( c=nval,count=1; *c; c++ ) {
+               c = strpbrk( c, SLAPD_APPROX_DELIMITER );
+               if ( c == NULL ) break;
+               *c = '\0';
+               count++;
+       }
+
+       /* Get a phonetic copy of each word */
+       words = (char **)ch_malloc( count * sizeof(char *) );
+       values = (char **)ch_malloc( count * sizeof(char *) );
+       for( c=nval,i=0;  i<count;  i++,c+=strlen(c)+1 ) {
+               words[i] = c;
+               values[i] = phonetic(c);
+       }
+
+       /* Work through the asserted value's words, to see if at least some
+          of the words are there, in the same order. */
+       len = 0;
+       while ( (size_t) nextchunk < avlen ) {
+               len = strcspn( assertv + nextchunk, SLAPD_APPROX_DELIMITER);
+               if( len == 0 ) {
+                       nextchunk++;
+                       continue;
+               }
+#if defined(SLAPD_APPROX_INITIALS)
+               else if( len == 1 ) {
+                       /* Single letter words need to at least match one word's initial */
+                       for( i=nextavail; i<count; i++ )
+                               if( !strncasecmp( assertv+nextchunk, words[i], 1 )) {
+                                       nextavail=i+1;
+                                       break;
+                               }
+               }
+#endif
+               else {
+                       /* Isolate the next word in the asserted value and phonetic it */
+                       assertv[nextchunk+len] = '\0';
+                       val = phonetic( assertv + nextchunk );
+
+                       /* See if this phonetic chunk is in the remaining words of *value */
+                       for( i=nextavail; i<count; i++ ){
+                               if( !strcmp( val, values[i] ) ){
+                                       nextavail = i+1;
+                                       break;
+                               }
+                       }
+                       ch_free( val );
+               }
+
+               /* This chunk in the asserted value was NOT within the *value. */
+               if( i >= count ) {
+                       nextavail=-1;
+                       break;
+               }
+
+               /* Go on to the next word in the asserted value */
+               nextchunk += len+1;
+       }
+
+       /* If some of the words were seen, call it a match */
+       if( nextavail > 0 ) {
+               *matchp = 0;
+       }
+       else {
+               *matchp = 1;
+       }
+
+       /* Cleanup allocs */
+       free( assertv );
+       for( i=0; i<count; i++ ) {
+               ch_free( values[i] );
+       }
+       ch_free( values );
+       ch_free( words );
+       ch_free( nval );
+
+       return LDAP_SUCCESS;
+}
+
+static int 
+approxIndexer(
+       slap_mask_t use,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *prefix,
+       BerVarray values,
+       BerVarray *keysp )
+{
+       char *val, *c;
+       int i,j, len, wordcount, keycount=0;
+       struct berval *newkeys;
+       BerVarray keys=NULL;
+
+       for( j=0; values[j].bv_val != NULL; j++ ) {
+               /* Yes, this is necessary */
+               val = UTF8normalize( &values[j], LDAP_UTF8_NOCASEFOLD );
+               strip8bitChars( val );
+
+               /* Isolate how many words there are. There will be a key for each */
+               for( wordcount=0,c=val;  *c;  c++) {
+                       len = strcspn(c, SLAPD_APPROX_DELIMITER);
+                       if( len >= SLAPD_APPROX_WORDLEN ) wordcount++;
+                       c+= len;
+                       if (*c == '\0') break;
+                       *c = '\0';
+               }
+
+               /* Allocate/increase storage to account for new keys */
+               newkeys = (struct berval *)ch_malloc( (keycount + wordcount + 1) 
+                       * sizeof(struct berval) );
+               AC_MEMCPY( newkeys, keys, keycount * sizeof(struct berval) );
+               if( keys ) ch_free( keys );
+               keys = newkeys;
+
+               /* Get a phonetic copy of each word */
+               for( c=val,i=0;  i<wordcount;  c+=len+1  ) {
+                       len = strlen( c );
+                       if( len < SLAPD_APPROX_WORDLEN ) continue;
+                       ber_str2bv( phonetic( c ), 0, 0, &keys[keycount] );
+                       keycount++;
+                       i++;
+               }
+
+               free( val );
+       }
+       keys[keycount].bv_val = NULL;
+       *keysp = keys;
+
+       return LDAP_SUCCESS;
+}
+
+static int 
+approxFilter(
+       slap_mask_t use,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *prefix,
+       void * assertValue,
+       BerVarray *keysp )
+{
+       char *val, *c;
+       int i, count, len;
+       BerVarray keys;
+
+       /* Yes, this is necessary */
+       val = UTF8normalize( ((struct berval *)assertValue),
+               LDAP_UTF8_NOCASEFOLD );
+       if( val == NULL ) {
+               keys = (struct berval *)ch_malloc( sizeof(struct berval) );
+               keys[0].bv_val = NULL;
+               *keysp = keys;
+               return LDAP_SUCCESS;
+       }
+       strip8bitChars( val );
+
+       /* Isolate how many words there are. There will be a key for each */
+       for( count=0,c=val;  *c;  c++) {
+               len = strcspn(c, SLAPD_APPROX_DELIMITER);
+               if( len >= SLAPD_APPROX_WORDLEN ) count++;
+               c+= len;
+               if (*c == '\0') break;
+               *c = '\0';
+       }
+
+       /* Allocate storage for new keys */
+       keys = (struct berval *)ch_malloc( (count + 1) * sizeof(struct berval) );
+
+       /* Get a phonetic copy of each word */
+       for( c=val,i=0;  i<count; c+=len+1 ) {
+               len = strlen(c);
+               if( len < SLAPD_APPROX_WORDLEN ) continue;
+               ber_str2bv( phonetic( c ), 0, 0, &keys[i] );
+               i++;
+       }
+
+       free( val );
+
+       keys[count].bv_val = NULL;
+       *keysp = keys;
+
+       return LDAP_SUCCESS;
+}
+
+
+#else
+/* No other form of Approximate Matching is defined */
+
+static int
+approxMatch(
+       int *matchp,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *value,
+       void *assertedValue )
+{
+       char *vapprox, *avapprox;
+       char *s, *t;
+
+       /* Yes, this is necessary */
+       s = UTF8normalize( value, UTF8_NOCASEFOLD );
+       if( s == NULL ) {
+               *matchp = 1;
+               return LDAP_SUCCESS;
+       }
+
+       /* Yes, this is necessary */
+       t = UTF8normalize( ((struct berval *)assertedValue),
+                          UTF8_NOCASEFOLD );
+       if( t == NULL ) {
+               free( s );
+               *matchp = -1;
+               return LDAP_SUCCESS;
+       }
+
+       vapprox = phonetic( strip8bitChars( s ) );
+       avapprox = phonetic( strip8bitChars( t ) );
+
+       free( s );
+       free( t );
+
+       *matchp = strcmp( vapprox, avapprox );
+
+       ch_free( vapprox );
+       ch_free( avapprox );
+
+       return LDAP_SUCCESS;
+}
+
+static int 
+approxIndexer(
+       slap_mask_t use,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *prefix,
+       BerVarray values,
+       BerVarray *keysp )
+{
+       int i;
+       BerVarray *keys;
+       char *s;
+
+       for( i=0; values[i].bv_val != NULL; i++ ) {
+               /* empty - just count them */
+       }
+
+       /* we should have at least one value at this point */
+       assert( i > 0 );
+
+       keys = (struct berval *)ch_malloc( sizeof( struct berval ) * (i+1) );
+
+       /* Copy each value and run it through phonetic() */
+       for( i=0; values[i].bv_val != NULL; i++ ) {
+               /* Yes, this is necessary */
+               s = UTF8normalize( &values[i], UTF8_NOCASEFOLD );
+
+               /* strip 8-bit chars and run through phonetic() */
+               ber_str2bv( phonetic( strip8bitChars( s ) ), 0, 0, &keys[i] );
+               free( s );
+       }
+       keys[i].bv_val = NULL;
+
+       *keysp = keys;
+       return LDAP_SUCCESS;
+}
+
+
+static int 
+approxFilter(
+       slap_mask_t use,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *prefix,
+       void * assertValue,
+       BerVarray *keysp )
+{
+       BerVarray keys;
+       char *s;
+
+       keys = (struct berval *)ch_malloc( sizeof( struct berval * ) * 2 );
+
+       /* Yes, this is necessary */
+       s = UTF8normalize( ((struct berval *)assertValue),
+                            UTF8_NOCASEFOLD );
+       if( s == NULL ) {
+               keys[0] = NULL;
+       } else {
+               /* strip 8-bit chars and run through phonetic() */
+               keys[0] = ber_bvstr( phonetic( strip8bitChars( s ) ) );
+               free( s );
+               keys[1] = NULL;
+       }
+
+       *keysp = keys;
+       return LDAP_SUCCESS;
+}
+#endif
+
+
+static int
+caseExactMatch(
+       int *matchp,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *value,
+       void *assertedValue )
+{
+       *matchp = UTF8normcmp( value->bv_val,
+               ((struct berval *) assertedValue)->bv_val,
+               LDAP_UTF8_NOCASEFOLD );
+       return LDAP_SUCCESS;
+}
+
+static int
+caseExactIgnoreSubstringsMatch(
+       int *matchp,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *value,
+       void *assertedValue )
+{
+       int match = 0;
+       SubstringsAssertion *sub = NULL;
+       struct berval left = { 0, NULL };
+       int i;
+       ber_len_t inlen=0;
+       char *nav = NULL;
+       unsigned casefold;
+
+       casefold = strcmp( mr->smr_oid, caseExactSubstringsMatchOID )
+               ? LDAP_UTF8_CASEFOLD : LDAP_UTF8_NOCASEFOLD;
+
+       if ( UTF8bvnormalize( value, &left, casefold ) == NULL ) {
+               match = 1;
+               goto done;
+       }
+       nav = left.bv_val;
+
+       sub = UTF8SubstringsassertionNormalize( assertedValue, casefold );
+       if( sub == NULL ) {
+               match = -1;
+               goto done;
+       }
+
+       /* Add up asserted input length */
+       if( sub->sa_initial.bv_val ) {
+               inlen += sub->sa_initial.bv_len;
+       }
+       if( sub->sa_any ) {
+               for(i=0; sub->sa_any[i].bv_val != NULL; i++) {
+                       inlen += sub->sa_any[i].bv_len;
+               }
+       }
+       if( sub->sa_final.bv_val ) {
+               inlen += sub->sa_final.bv_len;
+       }
+
+       if( sub->sa_initial.bv_val ) {
+               if( inlen > left.bv_len ) {
+                       match = 1;
+                       goto done;
+               }
+
+               match = memcmp( sub->sa_initial.bv_val, left.bv_val,
+                       sub->sa_initial.bv_len );
+
+               if( match != 0 ) {
+                       goto done;
+               }
+
+               left.bv_val += sub->sa_initial.bv_len;
+               left.bv_len -= sub->sa_initial.bv_len;
+               inlen -= sub->sa_initial.bv_len;
+       }
+
+       if( sub->sa_final.bv_val ) {
+               if( inlen > left.bv_len ) {
+                       match = 1;
+                       goto done;
+               }
+
+               match = memcmp( sub->sa_final.bv_val,
+                       &left.bv_val[left.bv_len - sub->sa_final.bv_len],
+                       sub->sa_final.bv_len );
+
+               if( match != 0 ) {
+                       goto done;
+               }
+
+               left.bv_len -= sub->sa_final.bv_len;
+               inlen -= sub->sa_final.bv_len;
+       }
+
+       if( sub->sa_any ) {
+               for(i=0; sub->sa_any[i].bv_val; i++) {
+                       ber_len_t idx;
+                       char *p;
+
+retry:
+                       if( inlen > left.bv_len ) {
+                               /* not enough length */
+                               match = 1;
+                               goto done;
+                       }
+
+                       if( sub->sa_any[i].bv_len == 0 ) {
+                               continue;
+                       }
+
+                       p = ber_bvchr( &left, *sub->sa_any[i].bv_val );
+                       if ( p == NULL ) {
+                               match = 1;
+                               goto done;
+                       }
+
+                       idx = p - left.bv_val;
+
+                       if( idx >= left.bv_len ) {
+                               /* this shouldn't happen */
+                               free( nav );
+                               if ( sub->sa_final.bv_val )
+                                       ch_free( sub->sa_final.bv_val );
+                               if ( sub->sa_any )
+                                       ber_bvarray_free( sub->sa_any );
+                               if ( sub->sa_initial.bv_val )
+                                       ch_free( sub->sa_initial.bv_val );
+                               ch_free( sub );
+                               return LDAP_OTHER;
+                       }
+
+                       left.bv_val = p;
+                       left.bv_len -= idx;
+
+                       if( sub->sa_any[i].bv_len > left.bv_len ) {
+                               /* not enough left */
+                               match = 1;
+                               goto done;
+                       }
+
+                       match = memcmp( left.bv_val,
+                               sub->sa_any[i].bv_val,
+                               sub->sa_any[i].bv_len );
+
+                       if( match != 0 ) {
+                               left.bv_val++;
+                               left.bv_len--;
+                               goto retry;
+                       }
+
+                       left.bv_val += sub->sa_any[i].bv_len;
+                       left.bv_len -= sub->sa_any[i].bv_len;
+                       inlen -= sub->sa_any[i].bv_len;
+               }
+       }
+
+done:
+       free( nav );
+       if( sub != NULL ) {
+               if ( sub->sa_final.bv_val ) free( sub->sa_final.bv_val );
+               if ( sub->sa_any ) ber_bvarray_free( sub->sa_any );
+               if ( sub->sa_initial.bv_val ) free( sub->sa_initial.bv_val );
+               ch_free( sub );
+       }
+       *matchp = match;
+       return LDAP_SUCCESS;
+}
+
+/* Index generation function */
+static int caseExactIgnoreIndexer(
+       slap_mask_t use,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *prefix,
+       BerVarray values,
+       BerVarray *keysp )
+{
+       int i;
+       unsigned casefold;
+       size_t slen, mlen;
+       BerVarray keys;
+       HASH_CONTEXT   HASHcontext;
+       unsigned char   HASHdigest[HASH_BYTES];
+       struct berval digest;
+       digest.bv_val = HASHdigest;
+       digest.bv_len = sizeof(HASHdigest);
+
+       for( i=0; values[i].bv_val != NULL; i++ ) {
+               /* empty - just count them */
+       }
+
+       /* we should have at least one value at this point */
+       assert( i > 0 );
+
+       keys = ch_malloc( sizeof( struct berval ) * (i+1) );
+
+       slen = syntax->ssyn_oidlen;
+       mlen = mr->smr_oidlen;
+
+       casefold = strcmp( mr->smr_oid, caseExactMatchOID )
+               ? LDAP_UTF8_CASEFOLD : LDAP_UTF8_NOCASEFOLD;
+
+       for( i=0; values[i].bv_val != NULL; i++ ) {
+               struct berval value;
+               ber_str2bv( UTF8normalize( &values[i], casefold ), 0, 0,
+                       &value );
+
+               HASH_Init( &HASHcontext );
+               if( prefix != NULL && prefix->bv_len > 0 ) {
+                       HASH_Update( &HASHcontext,
+                               prefix->bv_val, prefix->bv_len );
+               }
+               HASH_Update( &HASHcontext,
+                       syntax->ssyn_oid, slen );
+               HASH_Update( &HASHcontext,
+                       mr->smr_oid, mlen );
+               HASH_Update( &HASHcontext,
+                       value.bv_val, value.bv_len );
+               HASH_Final( HASHdigest, &HASHcontext );
+
+               free( value.bv_val );
+
+               ber_dupbv( &keys[i], &digest );
+       }
+
+       keys[i].bv_val = NULL;
+       *keysp = keys;
+       return LDAP_SUCCESS;
+}
+
+/* Index generation function */
+static int caseExactIgnoreFilter(
+       slap_mask_t use,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *prefix,
+       void * assertValue,
+       BerVarray *keysp )
+{
+       unsigned casefold;
+       size_t slen, mlen;
+       BerVarray keys;
+       HASH_CONTEXT   HASHcontext;
+       unsigned char   HASHdigest[HASH_BYTES];
+       struct berval value;
+       struct berval digest;
+       digest.bv_val = HASHdigest;
+       digest.bv_len = sizeof(HASHdigest);
+
+       slen = syntax->ssyn_oidlen;
+       mlen = mr->smr_oidlen;
+
+       casefold = strcmp( mr->smr_oid, caseExactMatchOID )
+               ? LDAP_UTF8_CASEFOLD : LDAP_UTF8_NOCASEFOLD;
+
+       ber_str2bv( UTF8normalize( ((struct berval *) assertValue), casefold ),
+               0, 0, &value );
+       /* This usually happens if filter contains bad UTF8 */
+       if( value.bv_val == NULL ) {
+               keys = ch_malloc( sizeof( struct berval ) );
+               keys[0].bv_val = NULL;
+               return LDAP_SUCCESS;
+       }
+
+       keys = ch_malloc( sizeof( struct berval ) * 2 );
+
+       HASH_Init( &HASHcontext );
+       if( prefix != NULL && prefix->bv_len > 0 ) {
+               HASH_Update( &HASHcontext,
+                       prefix->bv_val, prefix->bv_len );
+       }
+       HASH_Update( &HASHcontext,
+               syntax->ssyn_oid, slen );
+       HASH_Update( &HASHcontext,
+               mr->smr_oid, mlen );
+       HASH_Update( &HASHcontext,
+               value.bv_val, value.bv_len );
+       HASH_Final( HASHdigest, &HASHcontext );
+
+       ber_dupbv( keys, &digest );
+       keys[1].bv_val = NULL;
+
+       free( value.bv_val );
+
+       *keysp = keys;
+       return LDAP_SUCCESS;
+}
+
+/* Substrings Index generation function */
+static int caseExactIgnoreSubstringsIndexer(
+       slap_mask_t use,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *prefix,
+       BerVarray values,
+       BerVarray *keysp )
+{
+       unsigned casefold;
+       ber_len_t i, nkeys;
+       size_t slen, mlen;
+       BerVarray keys;
+       BerVarray nvalues;
+
+       HASH_CONTEXT   HASHcontext;
+       unsigned char   HASHdigest[HASH_BYTES];
+       struct berval digest;
+       digest.bv_val = HASHdigest;
+       digest.bv_len = sizeof(HASHdigest);
+
+       nkeys=0;
+
+       for( i=0; values[i].bv_val != NULL; i++ ) {
+               /* empty - just count them */
+       }
+
+       /* we should have at least one value at this point */
+       assert( i > 0 );
+
+       casefold = strcmp( mr->smr_oid, caseExactSubstringsMatchOID )
+               ? LDAP_UTF8_CASEFOLD : LDAP_UTF8_NOCASEFOLD;
+
+       nvalues = ch_malloc( sizeof( struct berval ) * (i+1) );
+       for( i=0; values[i].bv_val != NULL; i++ ) {
+               ber_str2bv( UTF8normalize( &values[i], casefold ),
+                       0, 0, &nvalues[i] );
+       }
+       nvalues[i].bv_val = NULL;
+       values = nvalues;
+
+       for( i=0; values[i].bv_val != NULL; i++ ) {
+               /* count number of indices to generate */
+               if( values[i].bv_len < SLAP_INDEX_SUBSTR_MINLEN ) {
+                       continue;
+               }
+
+               if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
+                       if( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
+                               nkeys += SLAP_INDEX_SUBSTR_MAXLEN -
+                                       ( SLAP_INDEX_SUBSTR_MINLEN - 1);
+                       } else {
+                               nkeys += values[i].bv_len - ( SLAP_INDEX_SUBSTR_MINLEN - 1 );
+                       }
+               }
+
+               if( flags & SLAP_INDEX_SUBSTR_ANY ) {
+                       if( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
+                               nkeys += values[i].bv_len - ( SLAP_INDEX_SUBSTR_MAXLEN - 1 );
+                       }
+               }
+
+               if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
+                       if( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
+                               nkeys += SLAP_INDEX_SUBSTR_MAXLEN -
+                                       ( SLAP_INDEX_SUBSTR_MINLEN - 1);
+                       } else {
+                               nkeys += values[i].bv_len - ( SLAP_INDEX_SUBSTR_MINLEN - 1 );
+                       }
+               }
+       }
+
+       if( nkeys == 0 ) {
+               /* no keys to generate */
+               *keysp = NULL;
+               ber_bvarray_free( nvalues );
+               return LDAP_SUCCESS;
+       }
+
+       keys = ch_malloc( sizeof( struct berval ) * (nkeys+1) );
+
+       slen = syntax->ssyn_oidlen;
+       mlen = mr->smr_oidlen;
+
+       nkeys=0;
+       for( i=0; values[i].bv_val != NULL; i++ ) {
+               ber_len_t j,max;
+
+               if( values[i].bv_len < SLAP_INDEX_SUBSTR_MINLEN ) continue;
+
+               if( ( flags & SLAP_INDEX_SUBSTR_ANY ) &&
+                       ( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) )
+               {
+                       char pre = SLAP_INDEX_SUBSTR_PREFIX;
+                       max = values[i].bv_len - ( SLAP_INDEX_SUBSTR_MAXLEN - 1);
+
+                       for( j=0; j<max; j++ ) {
+                               HASH_Init( &HASHcontext );
+                               if( prefix != NULL && prefix->bv_len > 0 ) {
+                                       HASH_Update( &HASHcontext,
+                                               prefix->bv_val, prefix->bv_len );
+                               }
+
+                               HASH_Update( &HASHcontext,
+                                       &pre, sizeof( pre ) );
+                               HASH_Update( &HASHcontext,
+                                       syntax->ssyn_oid, slen );
+                               HASH_Update( &HASHcontext,
+                                       mr->smr_oid, mlen );
+                               HASH_Update( &HASHcontext,
+                                       &values[i].bv_val[j],
+                                       SLAP_INDEX_SUBSTR_MAXLEN );
+                               HASH_Final( HASHdigest, &HASHcontext );
+
+                               ber_dupbv( &keys[nkeys++], &digest );
+                       }
+               }
+
+               max = SLAP_INDEX_SUBSTR_MAXLEN < values[i].bv_len
+                       ? SLAP_INDEX_SUBSTR_MAXLEN : values[i].bv_len;
+
+               for( j=SLAP_INDEX_SUBSTR_MINLEN; j<=max; j++ ) {
+                       char pre;
+
+                       if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
+                               pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
+                               HASH_Init( &HASHcontext );
+                               if( prefix != NULL && prefix->bv_len > 0 ) {
+                                       HASH_Update( &HASHcontext,
+                                               prefix->bv_val, prefix->bv_len );
+                               }
+                               HASH_Update( &HASHcontext,
+                                       &pre, sizeof( pre ) );
+                               HASH_Update( &HASHcontext,
+                                       syntax->ssyn_oid, slen );
+                               HASH_Update( &HASHcontext,
+                                       mr->smr_oid, mlen );
+                               HASH_Update( &HASHcontext,
+                                       values[i].bv_val, j );
+                               HASH_Final( HASHdigest, &HASHcontext );
+
+                               ber_dupbv( &keys[nkeys++], &digest );
+                       }
+
+                       if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
+                               pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
+                               HASH_Init( &HASHcontext );
+                               if( prefix != NULL && prefix->bv_len > 0 ) {
+                                       HASH_Update( &HASHcontext,
+                                               prefix->bv_val, prefix->bv_len );
+                               }
+                               HASH_Update( &HASHcontext,
+                                       &pre, sizeof( pre ) );
+                               HASH_Update( &HASHcontext,
+                                       syntax->ssyn_oid, slen );
+                               HASH_Update( &HASHcontext,
+                                       mr->smr_oid, mlen );
+                               HASH_Update( &HASHcontext,
+                                       &values[i].bv_val[values[i].bv_len-j], j );
+                               HASH_Final( HASHdigest, &HASHcontext );
+
+                               ber_dupbv( &keys[nkeys++], &digest );
+                       }
+
+               }
+
+       }
+
+       if( nkeys > 0 ) {
+               keys[nkeys].bv_val = NULL;
+               *keysp = keys;
+       } else {
+               ch_free( keys );
+               *keysp = NULL;
+       }
+
+       ber_bvarray_free( nvalues );
+
+       return LDAP_SUCCESS;
+}
+
+static int caseExactIgnoreSubstringsFilter(
+       slap_mask_t use,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *prefix,
+       void * assertValue,
+       BerVarray *keysp )
+{
+       SubstringsAssertion *sa;
+       char pre;
+       unsigned casefold;
+       ber_len_t nkeys = 0;
+       size_t slen, mlen, klen;
+       BerVarray keys;
+       HASH_CONTEXT   HASHcontext;
+       unsigned char   HASHdigest[HASH_BYTES];
+       struct berval *value;
+       struct berval digest;
+
+       casefold = strcmp( mr->smr_oid, caseExactSubstringsMatchOID )
+               ? LDAP_UTF8_CASEFOLD : LDAP_UTF8_NOCASEFOLD;
+
+       sa = UTF8SubstringsassertionNormalize( assertValue, casefold );
+       if( sa == NULL ) {
+               *keysp = NULL;
+               return LDAP_SUCCESS;
+       }
+
+       if( flags & SLAP_INDEX_SUBSTR_INITIAL && sa->sa_initial.bv_val != NULL &&
+               sa->sa_initial.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
+       {
+               nkeys++;
+       }
+
+       if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
+               ber_len_t i;
+               for( i=0; sa->sa_any[i].bv_val != NULL; i++ ) {
+                       if( sa->sa_any[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
+                               /* don't bother accounting for stepping */
+                               nkeys += sa->sa_any[i].bv_len -
+                                       ( SLAP_INDEX_SUBSTR_MAXLEN - 1 );
+                       }
+               }
+       }
+
+       if( flags & SLAP_INDEX_SUBSTR_FINAL && sa->sa_final.bv_val != NULL &&
+               sa->sa_final.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
+       {
+               nkeys++;
+       }
+
+       if( nkeys == 0 ) {
+               if ( sa->sa_final.bv_val ) free( sa->sa_final.bv_val );
+               if ( sa->sa_any ) ber_bvarray_free( sa->sa_any );
+               if ( sa->sa_initial.bv_val ) free( sa->sa_initial.bv_val );
+               ch_free( sa );
+               *keysp = NULL;
+               return LDAP_SUCCESS;
+       }
+
+       digest.bv_val = HASHdigest;
+       digest.bv_len = sizeof(HASHdigest);
+
+       slen = syntax->ssyn_oidlen;
+       mlen = mr->smr_oidlen;
+
+       keys = ch_malloc( sizeof( struct berval ) * (nkeys+1) );
+       nkeys = 0;
+
+       if( flags & SLAP_INDEX_SUBSTR_INITIAL && sa->sa_initial.bv_val != NULL &&
+               sa->sa_initial.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
+       {
+               pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
+               value = &sa->sa_initial;
+
+               klen = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len
+                       ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len;
+
+               HASH_Init( &HASHcontext );
+               if( prefix != NULL && prefix->bv_len > 0 ) {
+                       HASH_Update( &HASHcontext,
+                               prefix->bv_val, prefix->bv_len );
+               }
+               HASH_Update( &HASHcontext,
+                       &pre, sizeof( pre ) );
+               HASH_Update( &HASHcontext,
+                       syntax->ssyn_oid, slen );
+               HASH_Update( &HASHcontext,
+                       mr->smr_oid, mlen );
+               HASH_Update( &HASHcontext,
+                       value->bv_val, klen );
+               HASH_Final( HASHdigest, &HASHcontext );
+
+               ber_dupbv( &keys[nkeys++], &digest );
+       }
+
+       if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
+               ber_len_t i, j;
+               pre = SLAP_INDEX_SUBSTR_PREFIX;
+               klen = SLAP_INDEX_SUBSTR_MAXLEN;
+
+               for( i=0; sa->sa_any[i].bv_val != NULL; i++ ) {
+                       if( sa->sa_any[i].bv_len < SLAP_INDEX_SUBSTR_MAXLEN ) {
+                               continue;
+                       }
+
+                       value = &sa->sa_any[i];
+
+                       for(j=0;
+                               j <= value->bv_len - SLAP_INDEX_SUBSTR_MAXLEN;
+                               j += SLAP_INDEX_SUBSTR_STEP )
+                       {
+                               HASH_Init( &HASHcontext );
+                               if( prefix != NULL && prefix->bv_len > 0 ) {
+                                       HASH_Update( &HASHcontext,
+                                               prefix->bv_val, prefix->bv_len );
+                               }
+                               HASH_Update( &HASHcontext,
+                                       &pre, sizeof( pre ) );
+                               HASH_Update( &HASHcontext,
+                                       syntax->ssyn_oid, slen );
+                               HASH_Update( &HASHcontext,
+                                       mr->smr_oid, mlen );
+                               HASH_Update( &HASHcontext,
+                                       &value->bv_val[j], klen ); 
+                               HASH_Final( HASHdigest, &HASHcontext );
+
+                               ber_dupbv( &keys[nkeys++], &digest );
+                       }
+
+               }
+       }
+
+       if( flags & SLAP_INDEX_SUBSTR_FINAL && sa->sa_final.bv_val != NULL &&
+               sa->sa_final.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
+       {
+               pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
+               value = &sa->sa_final;
+
+               klen = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len
+                       ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len;
+
+               HASH_Init( &HASHcontext );
+               if( prefix != NULL && prefix->bv_len > 0 ) {
+                       HASH_Update( &HASHcontext,
+                               prefix->bv_val, prefix->bv_len );
+               }
+               HASH_Update( &HASHcontext,
+                       &pre, sizeof( pre ) );
+               HASH_Update( &HASHcontext,
+                       syntax->ssyn_oid, slen );
+               HASH_Update( &HASHcontext,
+                       mr->smr_oid, mlen );
+               HASH_Update( &HASHcontext,
+                       &value->bv_val[value->bv_len-klen], klen );
+               HASH_Final( HASHdigest, &HASHcontext );
+
+               ber_dupbv( &keys[nkeys++], &digest );
+       }
+
+       if( nkeys > 0 ) {
+               keys[nkeys].bv_val = NULL;
+               *keysp = keys;
+       } else {
+               ch_free( keys );
+               *keysp = NULL;
+       }
+       if ( sa->sa_final.bv_val ) free( sa->sa_final.bv_val );
+       if ( sa->sa_any ) ber_bvarray_free( sa->sa_any );
+       if ( sa->sa_initial.bv_val ) free( sa->sa_initial.bv_val );
+       ch_free( sa );
+
+       return LDAP_SUCCESS;
+}
+
+static int
+caseIgnoreMatch(
+       int *matchp,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *value,
+       void *assertedValue )
+{
+       *matchp = UTF8normcmp( value->bv_val,
+               ((struct berval *) assertedValue)->bv_val,
+               LDAP_UTF8_CASEFOLD );
+       return LDAP_SUCCESS;
+}
+       
+static int
+oidValidate(
+       Syntax *syntax,
+       struct berval *val )
+{
+       ber_len_t i;
+
+       if( val->bv_len == 0 ) {
+               /* disallow empty strings */
+               return LDAP_INVALID_SYNTAX;
+       }
+
+       if( OID_LEADCHAR(val->bv_val[0]) ) {
+               int dot = 0;
+               for(i=1; i < val->bv_len; i++) {
+                       if( OID_SEPARATOR( val->bv_val[i] ) ) {
+                               if( dot++ ) return 1;
+                       } else if ( OID_CHAR( val->bv_val[i] ) ) {
+                               dot = 0;
+                       } else {
+                               return LDAP_INVALID_SYNTAX;
+                       }
+               }
+
+               return !dot ? LDAP_SUCCESS : LDAP_INVALID_SYNTAX;
+
+       } else if( DESC_LEADCHAR(val->bv_val[0]) ) {
+               for(i=1; i < val->bv_len; i++) {
+                       if( !DESC_CHAR(val->bv_val[i] ) ) {
+                               return LDAP_INVALID_SYNTAX;
+                       }
+               }
+
+               return LDAP_SUCCESS;
+       }
+       
+       return LDAP_INVALID_SYNTAX;
+}
+
+static int
+integerMatch(
+       int *matchp,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *value,
+       void *assertedValue )
+{
+       char *v, *av;
+       int vsign=0, avsign=0;
+       struct berval *asserted;
+       ber_len_t vlen, avlen;
+
+
+       /* Start off pessimistic */
+       *matchp = 1;
+
+       /* Skip past leading spaces/zeros, and get the sign of the *value number */
+       v = value->bv_val;
+       vlen = value->bv_len;
+       while( vlen ) {
+               if( ASCII_SPACE(*v) || ( *v == '0' )) {
+                       /* empty -- skip spaces */
+               }
+               else if ( *v == '+' ) {
+                       vsign = 1;
+               }
+               else if ( *v == '-' ) {
+                       vsign = -1;
+               }
+               else if ( ASCII_DIGIT(*v) ) {
+                       if ( vsign == 0 ) vsign = 1;
+                       vsign *= 2;
+                       break;
+               }
+               v++;
+               vlen--;
+       }
+
+       /* Skip past leading spaces/zeros, and get the sign of the *assertedValue
+          number */
+       asserted = (struct berval *) assertedValue;
+       av = asserted->bv_val;
+       avlen = asserted->bv_len;
+       while( avlen ) {
+               if( ASCII_SPACE(*av) || ( *av == '0' )) {
+                       /* empty -- skip spaces */
+               }
+               else if ( *av == '+' ) {
+                       avsign = 1;
+               }
+               else if ( *av == '-' ) {
+                       avsign = -1;
+               }
+               else if ( ASCII_DIGIT(*av) ) {
+                       if ( avsign == 0 ) avsign = 1;
+                       avsign *= 2;
+                       break;
+               }
+               av++;
+               avlen--;
+       }
+
+       /* The two ?sign vars are now one of :
+          -2  negative non-zero number
+          -1  -0   \
+           0   0   collapse these three to 0
+          +1  +0   /
+          +2  positive non-zero number
+       */
+       if ( abs( vsign ) == 1 ) vsign = 0;
+       if ( abs( avsign ) == 1 ) avsign = 0;
+
+       if( vsign != avsign ) return LDAP_SUCCESS;
+
+       /* Check the significant digits */
+       while( vlen && avlen ) {
+               if( *v != *av ) break;
+               v++;
+               vlen--;
+               av++;
+               avlen--;
+       }
+
+       /* If all digits compared equal, the numbers are equal */
+       if(( vlen == 0 ) && ( avlen == 0 )) {
+               *matchp = 0;
+       }
+       return LDAP_SUCCESS;
+}
+       
+static int
+integerValidate(
+       Syntax *syntax,
+       struct berval *val )
+{
+       ber_len_t i;
+
+       if( !val->bv_len ) return LDAP_INVALID_SYNTAX;
+
+       if(( val->bv_val[0] == '+' ) || ( val->bv_val[0] == '-' )) {
+               if( val->bv_len < 2 ) return LDAP_INVALID_SYNTAX;
+       } else if( !ASCII_DIGIT(val->bv_val[0]) ) {
+               return LDAP_INVALID_SYNTAX;
+       }
+
+       for( i=1; i < val->bv_len; i++ ) {
+               if( !ASCII_DIGIT(val->bv_val[i]) ) return LDAP_INVALID_SYNTAX;
+       }
+
+       return LDAP_SUCCESS;
+}
+
+static int
+integerNormalize(
+       Syntax *syntax,
+       struct berval *val,
+       struct berval *normalized )
+{
+       char *p;
+       int negative=0;
+       ber_len_t len;
+
+
+       p = val->bv_val;
+       len = val->bv_len;
+
+       /* Ignore leading spaces */
+       while ( len && ( *p == ' ' )) {
+               p++;
+               len--;
+       }
+
+       /* save sign */
+       if( len ) {
+               negative = ( *p == '-' );
+               if(( *p == '-' ) || ( *p == '+' )) {
+                       p++;
+                       len--;
+               }
+       }
+
+       /* Ignore leading zeros */
+       while ( len && ( *p == '0' )) {
+               p++;
+               len--;
+       }
+
+       /* If there are no non-zero digits left, the number is zero, otherwise
+          allocate space for the number and copy it into the buffer */
+       if( len == 0 ) {
+               normalized->bv_val = ch_strdup("0");
+               normalized->bv_len = 1;
+       }
+       else {
+               normalized->bv_len = len+negative;
+               normalized->bv_val = ch_malloc( normalized->bv_len );
+               if( negative ) {
+                       normalized->bv_val[0] = '-';
+               }
+               AC_MEMCPY( normalized->bv_val + negative, p, len );
+       }
+
+       return LDAP_SUCCESS;
+}
+
+/* Index generation function */
+static int integerIndexer(
+       slap_mask_t use,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *prefix,
+       BerVarray values,
+       BerVarray *keysp )
+{
+       int i;
+       BerVarray keys;
+
+       /* we should have at least one value at this point */
+       assert( values != NULL && values[0].bv_val != NULL );
+
+       for( i=0; values[i].bv_val != NULL; i++ ) {
+               /* empty -- just count them */
+       }
+
+       keys = ch_malloc( sizeof( struct berval ) * (i+1) );
+
+       for( i=0; values[i].bv_val != NULL; i++ ) {
+               integerNormalize( syntax, &values[i], &keys[i] );
+       }
+
+       keys[i].bv_val = NULL;
+       *keysp = keys;
+       return LDAP_SUCCESS;
+}
+
+/* Index generation function */
+static int integerFilter(
+       slap_mask_t use,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *prefix,
+       void * assertValue,
+       BerVarray *keysp )
+{
+       BerVarray keys;
+
+       keys = ch_malloc( sizeof( struct berval ) * 2 );
+       integerNormalize( syntax, assertValue, &keys[0] );
+       keys[1].bv_val = NULL;
+       *keysp = keys;
+
+       return LDAP_SUCCESS;
+}
+
+
+static int
+countryStringValidate(
+       Syntax *syntax,
+       struct berval *val )
+{
+       if( val->bv_len != 2 ) return LDAP_INVALID_SYNTAX;
+
+       if( !SLAP_PRINTABLE(val->bv_val[0]) ) {
+               return LDAP_INVALID_SYNTAX;
+       }
+       if( !SLAP_PRINTABLE(val->bv_val[1]) ) {
+               return LDAP_INVALID_SYNTAX;
+       }
+
+       return LDAP_SUCCESS;
+}
+
+static int
+printableStringValidate(
+       Syntax *syntax,
+       struct berval *val )
+{
+       ber_len_t i;
+
+       for(i=0; i < val->bv_len; i++) {
+               if( !SLAP_PRINTABLE(val->bv_val[i]) ) {
+                       return LDAP_INVALID_SYNTAX;
+               }
+       }
+
+       return LDAP_SUCCESS;
+}
+
+static int
+printablesStringValidate(
+       Syntax *syntax,
+       struct berval *val )
+{
+       ber_len_t i;
+
+       for(i=0; i < val->bv_len; i++) {
+               if( !SLAP_PRINTABLES(val->bv_val[i]) ) {
+                       return LDAP_INVALID_SYNTAX;
+               }
+       }
+
+       return LDAP_SUCCESS;
+}
+
+static int
+IA5StringValidate(
+       Syntax *syntax,
+       struct berval *val )
+{
+       ber_len_t i;
+
+       for(i=0; i < val->bv_len; i++) {
+               if( !LDAP_ASCII(val->bv_val[i]) ) {
+                       return LDAP_INVALID_SYNTAX;
+               }
+       }
+
+       return LDAP_SUCCESS;
+}
+
+static int
+IA5StringNormalize(
+       Syntax *syntax,
+       struct berval *val,
+       struct berval *normalized )
+{
+       char *p, *q;
+
+       p = val->bv_val;
+
+       /* Ignore initial whitespace */
+       while ( ASCII_SPACE( *p ) ) {
+               p++;
+       }
+
+       normalized->bv_val = ch_strdup( p );
+       p = q = normalized->bv_val;
+
+       while ( *p ) {
+               if ( ASCII_SPACE( *p ) ) {
+                       *q++ = *p++;
+
+                       /* Ignore the extra whitespace */
+                       while ( ASCII_SPACE( *p ) ) {
+                               p++;
+                       }
+               } else {
+                       *q++ = *p++;
+               }
+       }
+
+       assert( normalized->bv_val <= p );
+       assert( q <= p );
+
+       /*
+        * If the string ended in space, backup the pointer one
+        * position.  One is enough because the above loop collapsed
+        * all whitespace to a single space.
+        */
+
+       if ( ASCII_SPACE( q[-1] ) ) {
+               --q;
+       }
+
+       /* null terminate */
+       *q = '\0';
+
+       normalized->bv_len = q - normalized->bv_val;
+
+       return LDAP_SUCCESS;
+}
+
+static int
+caseExactIA5Match(
+       int *matchp,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *value,
+       void *assertedValue )
+{
+       int match = value->bv_len - ((struct berval *) assertedValue)->bv_len;
+
+       if( match == 0 ) {
+               match = strncmp( value->bv_val,
+                       ((struct berval *) assertedValue)->bv_val,
+                       value->bv_len );
+       }
+
+       *matchp = match;
+       return LDAP_SUCCESS;
+}
+
+static int
+caseExactIA5SubstringsMatch(
+       int *matchp,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *value,
+       void *assertedValue )
+{
+       int match = 0;
+       SubstringsAssertion *sub = assertedValue;
+       struct berval left = *value;
+       int i;
+       ber_len_t inlen=0;
+
+       /* Add up asserted input length */
+       if( sub->sa_initial.bv_val ) {
+               inlen += sub->sa_initial.bv_len;
+       }
+       if( sub->sa_any ) {
+               for(i=0; sub->sa_any[i].bv_val != NULL; i++) {
+                       inlen += sub->sa_any[i].bv_len;
+               }
+       }
+       if( sub->sa_final.bv_val ) {
+               inlen += sub->sa_final.bv_len;
+       }
+
+       if( sub->sa_initial.bv_val ) {
+               if( inlen > left.bv_len ) {
+                       match = 1;
+                       goto done;
+               }
+
+               match = strncmp( sub->sa_initial.bv_val, left.bv_val,
+                       sub->sa_initial.bv_len );
+
+               if( match != 0 ) {
+                       goto done;
+               }
+
+               left.bv_val += sub->sa_initial.bv_len;
+               left.bv_len -= sub->sa_initial.bv_len;
+               inlen -= sub->sa_initial.bv_len;
+       }
+
+       if( sub->sa_final.bv_val ) {
+               if( inlen > left.bv_len ) {
+                       match = 1;
+                       goto done;
+               }
+
+               match = strncmp( sub->sa_final.bv_val,
+                       &left.bv_val[left.bv_len - sub->sa_final.bv_len],
+                       sub->sa_final.bv_len );
+
+               if( match != 0 ) {
+                       goto done;
+               }
+
+               left.bv_len -= sub->sa_final.bv_len;
+               inlen -= sub->sa_final.bv_len;
+       }
+
+       if( sub->sa_any ) {
+               for(i=0; sub->sa_any[i].bv_val; i++) {
+                       ber_len_t idx;
+                       char *p;
+
+retry:
+                       if( inlen > left.bv_len ) {
+                               /* not enough length */
+                               match = 1;
+                               goto done;
+                       }
+
+                       if( sub->sa_any[i].bv_len == 0 ) {
+                               continue;
+                       }
+
+                       p = strchr( left.bv_val, *sub->sa_any[i].bv_val );
+
+                       if( p == NULL ) {
+                               match = 1;
+                               goto done;
+                       }
+
+                       idx = p - left.bv_val;
+
+                       if( idx >= left.bv_len ) {
+                               /* this shouldn't happen */
+                               return LDAP_OTHER;
+                       }
+
+                       left.bv_val = p;
+                       left.bv_len -= idx;
+
+                       if( sub->sa_any[i].bv_len > left.bv_len ) {
+                               /* not enough left */
+                               match = 1;
+                               goto done;
+                       }
+
+                       match = strncmp( left.bv_val,
+                               sub->sa_any[i].bv_val,
+                               sub->sa_any[i].bv_len );
+
+                       if( match != 0 ) {
+                               left.bv_val++;
+                               left.bv_len--;
+                               goto retry;
+                       }
+
+                       left.bv_val += sub->sa_any[i].bv_len;
+                       left.bv_len -= sub->sa_any[i].bv_len;
+                       inlen -= sub->sa_any[i].bv_len;
+               }
+       }
+
+done:
+       *matchp = match;
+       return LDAP_SUCCESS;
+}
+
+/* Index generation function */
+static int caseExactIA5Indexer(
+       slap_mask_t use,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *prefix,
+       BerVarray values,
+       BerVarray *keysp )
+{
+       int i;
+       size_t slen, mlen;
+       BerVarray keys;
+       HASH_CONTEXT   HASHcontext;
+       unsigned char   HASHdigest[HASH_BYTES];
+       struct berval digest;
+       digest.bv_val = HASHdigest;
+       digest.bv_len = sizeof(HASHdigest);
+
+       for( i=0; values[i].bv_val != NULL; i++ ) {
+               /* empty - just count them */
+       }
+
+       /* we should have at least one value at this point */
+       assert( i > 0 );
+
+       keys = ch_malloc( sizeof( struct berval ) * (i+1) );
+
+       slen = syntax->ssyn_oidlen;
+       mlen = mr->smr_oidlen;
+
+       for( i=0; values[i].bv_val != NULL; i++ ) {
+               struct berval *value = &values[i];
+
+               HASH_Init( &HASHcontext );
+               if( prefix != NULL && prefix->bv_len > 0 ) {
+                       HASH_Update( &HASHcontext,
+                               prefix->bv_val, prefix->bv_len );
+               }
+               HASH_Update( &HASHcontext,
+                       syntax->ssyn_oid, slen );
+               HASH_Update( &HASHcontext,
+                       mr->smr_oid, mlen );
+               HASH_Update( &HASHcontext,
+                       value->bv_val, value->bv_len );
+               HASH_Final( HASHdigest, &HASHcontext );
+
+               ber_dupbv( &keys[i], &digest );
+       }
+
+       keys[i].bv_val = NULL;
+       *keysp = keys;
+       return LDAP_SUCCESS;
+}
+
+/* Index generation function */
+static int caseExactIA5Filter(
+       slap_mask_t use,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *prefix,
+       void * assertValue,
+       BerVarray *keysp )
+{
+       size_t slen, mlen;
+       BerVarray keys;
+       HASH_CONTEXT   HASHcontext;
+       unsigned char   HASHdigest[HASH_BYTES];
+       struct berval *value;
+       struct berval digest;
+       digest.bv_val = HASHdigest;
+       digest.bv_len = sizeof(HASHdigest);
+
+       slen = syntax->ssyn_oidlen;
+       mlen = mr->smr_oidlen;
+
+       value = (struct berval *) assertValue;
+
+       keys = ch_malloc( sizeof( struct berval ) * 2 );
+
+       HASH_Init( &HASHcontext );
+       if( prefix != NULL && prefix->bv_len > 0 ) {
+               HASH_Update( &HASHcontext,
+                       prefix->bv_val, prefix->bv_len );
+       }
+       HASH_Update( &HASHcontext,
+               syntax->ssyn_oid, slen );
+       HASH_Update( &HASHcontext,
+               mr->smr_oid, mlen );
+       HASH_Update( &HASHcontext,
+               value->bv_val, value->bv_len );
+       HASH_Final( HASHdigest, &HASHcontext );
+
+       ber_dupbv( &keys[0], &digest );
+       keys[1].bv_val = NULL;
+
+       *keysp = keys;
+       return LDAP_SUCCESS;
+}
+
+/* Substrings Index generation function */
+static int caseExactIA5SubstringsIndexer(
+       slap_mask_t use,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *prefix,
+       BerVarray values,
+       BerVarray *keysp )
+{
+       ber_len_t i, nkeys;
+       size_t slen, mlen;
+       BerVarray keys;
+       HASH_CONTEXT   HASHcontext;
+       unsigned char   HASHdigest[HASH_BYTES];
+       struct berval digest;
+       digest.bv_val = HASHdigest;
+       digest.bv_len = sizeof(HASHdigest);
+
+       /* we should have at least one value at this point */
+       assert( values != NULL && values[0].bv_val != NULL );
+
+       nkeys=0;
+       for( i=0; values[i].bv_val != NULL; i++ ) {
+               /* count number of indices to generate */
+               if( values[i].bv_len < SLAP_INDEX_SUBSTR_MINLEN ) {
+                       continue;
+               }
+
+               if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
+                       if( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
+                               nkeys += SLAP_INDEX_SUBSTR_MAXLEN -
+                                       ( SLAP_INDEX_SUBSTR_MINLEN - 1);
+                       } else {
+                               nkeys += values[i].bv_len - ( SLAP_INDEX_SUBSTR_MINLEN - 1 );
+                       }
+               }
+
+               if( flags & SLAP_INDEX_SUBSTR_ANY ) {
+                       if( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
+                               nkeys += values[i].bv_len - ( SLAP_INDEX_SUBSTR_MAXLEN - 1 );
+                       }
+               }
+
+               if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
+                       if( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
+                               nkeys += SLAP_INDEX_SUBSTR_MAXLEN -
+                                       ( SLAP_INDEX_SUBSTR_MINLEN - 1);
+                       } else {
+                               nkeys += values[i].bv_len - ( SLAP_INDEX_SUBSTR_MINLEN - 1 );
+                       }
+               }
+       }
+
+       if( nkeys == 0 ) {
+               /* no keys to generate */
+               *keysp = NULL;
+               return LDAP_SUCCESS;
+       }
+
+       keys = ch_malloc( sizeof( struct berval ) * (nkeys+1) );
+
+       slen = syntax->ssyn_oidlen;
+       mlen = mr->smr_oidlen;
+
+       nkeys=0;
+       for( i=0; values[i].bv_val != NULL; i++ ) {
+               ber_len_t j,max;
+               struct berval *value;
+
+               value = &values[i];
+               if( value->bv_len < SLAP_INDEX_SUBSTR_MINLEN ) continue;
+
+               if( ( flags & SLAP_INDEX_SUBSTR_ANY ) &&
+                       ( value->bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) )
+               {
+                       char pre = SLAP_INDEX_SUBSTR_PREFIX;
+                       max = value->bv_len - ( SLAP_INDEX_SUBSTR_MAXLEN - 1);
+
+                       for( j=0; j<max; j++ ) {
+                               HASH_Init( &HASHcontext );
+                               if( prefix != NULL && prefix->bv_len > 0 ) {
+                                       HASH_Update( &HASHcontext,
+                                               prefix->bv_val, prefix->bv_len );
+                               }
+
+                               HASH_Update( &HASHcontext,
+                                       &pre, sizeof( pre ) );
+                               HASH_Update( &HASHcontext,
+                                       syntax->ssyn_oid, slen );
+                               HASH_Update( &HASHcontext,
+                                       mr->smr_oid, mlen );
+                               HASH_Update( &HASHcontext,
+                                       &value->bv_val[j],
+                                       SLAP_INDEX_SUBSTR_MAXLEN );
+                               HASH_Final( HASHdigest, &HASHcontext );
+
+                               ber_dupbv( &keys[nkeys++], &digest );
+                       }
+               }
+
+               max = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len
+                       ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len;
+
+               for( j=SLAP_INDEX_SUBSTR_MINLEN; j<=max; j++ ) {
+                       char pre;
+
+                       if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
+                               pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
+                               HASH_Init( &HASHcontext );
+                               if( prefix != NULL && prefix->bv_len > 0 ) {
+                                       HASH_Update( &HASHcontext,
+                                               prefix->bv_val, prefix->bv_len );
+                               }
+                               HASH_Update( &HASHcontext,
+                                       &pre, sizeof( pre ) );
+                               HASH_Update( &HASHcontext,
+                                       syntax->ssyn_oid, slen );
+                               HASH_Update( &HASHcontext,
+                                       mr->smr_oid, mlen );
+                               HASH_Update( &HASHcontext,
+                                       value->bv_val, j );
+                               HASH_Final( HASHdigest, &HASHcontext );
+
+                               ber_dupbv( &keys[nkeys++], &digest );
+                       }
+
+                       if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
+                               pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
+                               HASH_Init( &HASHcontext );
+                               if( prefix != NULL && prefix->bv_len > 0 ) {
+                                       HASH_Update( &HASHcontext,
+                                               prefix->bv_val, prefix->bv_len );
+                               }
+                               HASH_Update( &HASHcontext,
+                                       &pre, sizeof( pre ) );
+                               HASH_Update( &HASHcontext,
+                                       syntax->ssyn_oid, slen );
+                               HASH_Update( &HASHcontext,
+                                       mr->smr_oid, mlen );
+                               HASH_Update( &HASHcontext,
+                                       &value->bv_val[value->bv_len-j], j );
+                               HASH_Final( HASHdigest, &HASHcontext );
+
+                               ber_dupbv( &keys[nkeys++], &digest );
+                       }
+
+               }
+       }
+
+       if( nkeys > 0 ) {
+               keys[nkeys].bv_val = NULL;
+               *keysp = keys;
+       } else {
+               ch_free( keys );
+               *keysp = NULL;
+       }
+
+       return LDAP_SUCCESS;
+}
+
+static int caseExactIA5SubstringsFilter(
+       slap_mask_t use,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *prefix,
+       void * assertValue,
+       BerVarray *keysp )
+{
+       SubstringsAssertion *sa = assertValue;
+       char pre;
+       ber_len_t nkeys = 0;
+       size_t slen, mlen, klen;
+       BerVarray keys;
+       HASH_CONTEXT   HASHcontext;
+       unsigned char   HASHdigest[HASH_BYTES];
+       struct berval *value;
+       struct berval digest;
+
+       if( flags & SLAP_INDEX_SUBSTR_INITIAL && sa->sa_initial.bv_val != NULL &&
+               sa->sa_initial.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
+       {
+               nkeys++;
+       }
+
+       if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
+               ber_len_t i;
+               for( i=0; sa->sa_any[i].bv_val != NULL; i++ ) {
+                       if( sa->sa_any[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
+                               /* don't bother accounting for stepping */
+                               nkeys += sa->sa_any[i].bv_len -
+                                       ( SLAP_INDEX_SUBSTR_MAXLEN - 1 );
+                       }
+               }
+       }
+
+       if( flags & SLAP_INDEX_SUBSTR_FINAL && sa->sa_final.bv_val != NULL &&
+               sa->sa_final.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
+       {
+               nkeys++;
+       }
+
+       if( nkeys == 0 ) {
+               *keysp = NULL;
+               return LDAP_SUCCESS;
+       }
+
+       digest.bv_val = HASHdigest;
+       digest.bv_len = sizeof(HASHdigest);
+
+       slen = syntax->ssyn_oidlen;
+       mlen = mr->smr_oidlen;
+
+       keys = ch_malloc( sizeof( struct berval ) * (nkeys+1) );
+       nkeys = 0;
+
+       if( flags & SLAP_INDEX_SUBSTR_INITIAL && sa->sa_initial.bv_val != NULL &&
+               sa->sa_initial.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
+       {
+               pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
+               value = &sa->sa_initial;
+
+               klen = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len
+                       ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len;
+
+               HASH_Init( &HASHcontext );
+               if( prefix != NULL && prefix->bv_len > 0 ) {
+                       HASH_Update( &HASHcontext,
+                               prefix->bv_val, prefix->bv_len );
+               }
+               HASH_Update( &HASHcontext,
+                       &pre, sizeof( pre ) );
+               HASH_Update( &HASHcontext,
+                       syntax->ssyn_oid, slen );
+               HASH_Update( &HASHcontext,
+                       mr->smr_oid, mlen );
+               HASH_Update( &HASHcontext,
+                       value->bv_val, klen );
+               HASH_Final( HASHdigest, &HASHcontext );
+
+               ber_dupbv( &keys[nkeys++], &digest );
+       }
+
+       if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
+               ber_len_t i, j;
+               pre = SLAP_INDEX_SUBSTR_PREFIX;
+               klen = SLAP_INDEX_SUBSTR_MAXLEN;
+
+               for( i=0; sa->sa_any[i].bv_val != NULL; i++ ) {
+                       if( sa->sa_any[i].bv_len < SLAP_INDEX_SUBSTR_MAXLEN ) {
+                               continue;
+                       }
+
+                       value = &sa->sa_any[i];
+
+                       for(j=0;
+                               j <= value->bv_len - SLAP_INDEX_SUBSTR_MAXLEN;
+                               j += SLAP_INDEX_SUBSTR_STEP )
+                       {
+                               HASH_Init( &HASHcontext );
+                               if( prefix != NULL && prefix->bv_len > 0 ) {
+                                       HASH_Update( &HASHcontext,
+                                               prefix->bv_val, prefix->bv_len );
+                               }
+                               HASH_Update( &HASHcontext,
+                                       &pre, sizeof( pre ) );
+                               HASH_Update( &HASHcontext,
+                                       syntax->ssyn_oid, slen );
+                               HASH_Update( &HASHcontext,
+                                       mr->smr_oid, mlen );
+                               HASH_Update( &HASHcontext,
+                                       &value->bv_val[j], klen ); 
+                               HASH_Final( HASHdigest, &HASHcontext );
+
+                               ber_dupbv( &keys[nkeys++], &digest );
+                       }
+               }
+       }
+
+       if( flags & SLAP_INDEX_SUBSTR_FINAL && sa->sa_final.bv_val != NULL &&
+               sa->sa_final.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
+       {
+               pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
+               value = &sa->sa_final;
+
+               klen = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len
+                       ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len;
+
+               HASH_Init( &HASHcontext );
+               if( prefix != NULL && prefix->bv_len > 0 ) {
+                       HASH_Update( &HASHcontext,
+                               prefix->bv_val, prefix->bv_len );
+               }
+               HASH_Update( &HASHcontext,
+                       &pre, sizeof( pre ) );
+               HASH_Update( &HASHcontext,
+                       syntax->ssyn_oid, slen );
+               HASH_Update( &HASHcontext,
+                       mr->smr_oid, mlen );
+               HASH_Update( &HASHcontext,
+                       &value->bv_val[value->bv_len-klen], klen );
+               HASH_Final( HASHdigest, &HASHcontext );
+
+               ber_dupbv( &keys[nkeys++], &digest );
+       }
+
+       if( nkeys > 0 ) {
+               keys[nkeys].bv_val = NULL;
+               *keysp = keys;
+       } else {
+               ch_free( keys );
+               *keysp = NULL;
+       }
+
+       return LDAP_SUCCESS;
+}
+       
+static int
+caseIgnoreIA5Match(
+       int *matchp,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *value,
+       void *assertedValue )
+{
+       int match = value->bv_len - ((struct berval *) assertedValue)->bv_len;
+
+       if( match == 0 && value->bv_len ) {
+               match = strncasecmp( value->bv_val,
+                       ((struct berval *) assertedValue)->bv_val,
+                       value->bv_len );
+       }
+
+       *matchp = match;
+       return LDAP_SUCCESS;
+}
+
+static int
+caseIgnoreIA5SubstringsMatch(
+       int *matchp,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *value,
+       void *assertedValue )
+{
+       int match = 0;
+       SubstringsAssertion *sub = assertedValue;
+       struct berval left = *value;
+       int i;
+       ber_len_t inlen=0;
+
+       /* Add up asserted input length */
+       if( sub->sa_initial.bv_val ) {
+               inlen += sub->sa_initial.bv_len;
+       }
+       if( sub->sa_any ) {
+               for(i=0; sub->sa_any[i].bv_val != NULL; i++) {
+                       inlen += sub->sa_any[i].bv_len;
+               }
+       }
+       if( sub->sa_final.bv_val ) {
+               inlen += sub->sa_final.bv_len;
+       }
+
+       if( sub->sa_initial.bv_val ) {
+               if( inlen > left.bv_len ) {
+                       match = 1;
+                       goto done;
+               }
+
+               match = strncasecmp( sub->sa_initial.bv_val, left.bv_val,
+                       sub->sa_initial.bv_len );
+
+               if( match != 0 ) {
+                       goto done;
+               }
+
+               left.bv_val += sub->sa_initial.bv_len;
+               left.bv_len -= sub->sa_initial.bv_len;
+               inlen -= sub->sa_initial.bv_len;
+       }
+
+       if( sub->sa_final.bv_val ) {
+               if( inlen > left.bv_len ) {
+                       match = 1;
+                       goto done;
+               }
+
+               match = strncasecmp( sub->sa_final.bv_val,
+                       &left.bv_val[left.bv_len - sub->sa_final.bv_len],
+                       sub->sa_final.bv_len );
+
+               if( match != 0 ) {
+                       goto done;
+               }
+
+               left.bv_len -= sub->sa_final.bv_len;
+               inlen -= sub->sa_final.bv_len;
+       }
+
+       if( sub->sa_any ) {
+               for(i=0; sub->sa_any[i].bv_val; i++) {
+                       ber_len_t idx;
+                       char *p;
+
+retry:
+                       if( inlen > left.bv_len ) {
+                               /* not enough length */
+                               match = 1;
+                               goto done;
+                       }
+
+                       if( sub->sa_any[i].bv_len == 0 ) {
+                               continue;
+                       }
+
+                       p = bvcasechr( &left, *sub->sa_any[i].bv_val, &idx );
+
+                       if( p == NULL ) {
+                               match = 1;
+                               goto done;
+                       }
+
+                       assert( idx < left.bv_len );
+                       if( idx >= left.bv_len ) {
+                               /* this shouldn't happen */
+                               return LDAP_OTHER;
+                       }
+
+                       left.bv_val = p;
+                       left.bv_len -= idx;
+
+                       if( sub->sa_any[i].bv_len > left.bv_len ) {
+                               /* not enough left */
+                               match = 1;
+                               goto done;
+                       }
+
+                       match = strncasecmp( left.bv_val,
+                               sub->sa_any[i].bv_val,
+                               sub->sa_any[i].bv_len );
+
+                       if( match != 0 ) {
+                               left.bv_val++;
+                               left.bv_len--;
+
+                               goto retry;
+                       }
+
+                       left.bv_val += sub->sa_any[i].bv_len;
+                       left.bv_len -= sub->sa_any[i].bv_len;
+                       inlen -= sub->sa_any[i].bv_len;
+               }
+       }
+
+done:
+       *matchp = match;
+       return LDAP_SUCCESS;
+}
+
+/* Index generation function */
+static int caseIgnoreIA5Indexer(
+       slap_mask_t use,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *prefix,
+       BerVarray values,
+       BerVarray *keysp )
+{
+       int i;
+       size_t slen, mlen;
+       BerVarray keys;
+       HASH_CONTEXT   HASHcontext;
+       unsigned char   HASHdigest[HASH_BYTES];
+       struct berval digest;
+       digest.bv_val = HASHdigest;
+       digest.bv_len = sizeof(HASHdigest);
+
+       /* we should have at least one value at this point */
+       assert( values != NULL && values[0].bv_val != NULL );
+
+       for( i=0; values[i].bv_val != NULL; i++ ) {
+               /* just count them */
+       }
+
+       keys = ch_malloc( sizeof( struct berval ) * (i+1) );
+
+       slen = syntax->ssyn_oidlen;
+       mlen = mr->smr_oidlen;
+
+       for( i=0; values[i].bv_val != NULL; i++ ) {
+               struct berval value;
+               ber_dupbv( &value, &values[i] );
+               ldap_pvt_str2upper( value.bv_val );
+
+               HASH_Init( &HASHcontext );
+               if( prefix != NULL && prefix->bv_len > 0 ) {
+                       HASH_Update( &HASHcontext,
+                               prefix->bv_val, prefix->bv_len );
+               }
+               HASH_Update( &HASHcontext,
+                       syntax->ssyn_oid, slen );
+               HASH_Update( &HASHcontext,
+                       mr->smr_oid, mlen );
+               HASH_Update( &HASHcontext,
+                       value.bv_val, value.bv_len );
+               HASH_Final( HASHdigest, &HASHcontext );
+
+               free( value.bv_val );
+
+               ber_dupbv( &keys[i], &digest );
+       }
+
+       keys[i].bv_val = NULL;
+       *keysp = keys;
+       return LDAP_SUCCESS;
+}
+
+/* Index generation function */
+static int caseIgnoreIA5Filter(
+       slap_mask_t use,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *prefix,
+       void * assertValue,
+       BerVarray *keysp )
+{
+       size_t slen, mlen;
+       BerVarray keys;
+       HASH_CONTEXT   HASHcontext;
+       unsigned char   HASHdigest[HASH_BYTES];
+       struct berval value;
+       struct berval digest;
+       digest.bv_val = HASHdigest;
+       digest.bv_len = sizeof(HASHdigest);
+
+       slen = syntax->ssyn_oidlen;
+       mlen = mr->smr_oidlen;
+
+       ber_dupbv( &value, (struct berval *) assertValue );
+       ldap_pvt_str2upper( value.bv_val );
+
+       keys = ch_malloc( sizeof( struct berval ) * 2 );
+
+       HASH_Init( &HASHcontext );
+       if( prefix != NULL && prefix->bv_len > 0 ) {
+               HASH_Update( &HASHcontext,
+                       prefix->bv_val, prefix->bv_len );
+       }
+       HASH_Update( &HASHcontext,
+               syntax->ssyn_oid, slen );
+       HASH_Update( &HASHcontext,
+               mr->smr_oid, mlen );
+       HASH_Update( &HASHcontext,
+               value.bv_val, value.bv_len );
+       HASH_Final( HASHdigest, &HASHcontext );
+
+       ber_dupbv( &keys[0], &digest );
+       keys[1].bv_val = NULL;
+
+       free( value.bv_val );
+
+       *keysp = keys;
+
+       return LDAP_SUCCESS;
+}
+
+/* Substrings Index generation function */
+static int caseIgnoreIA5SubstringsIndexer(
+       slap_mask_t use,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *prefix,
+       BerVarray values,
+       BerVarray *keysp )
+{
+       ber_len_t i, nkeys;
+       size_t slen, mlen;
+       BerVarray keys;
+       HASH_CONTEXT   HASHcontext;
+       unsigned char   HASHdigest[HASH_BYTES];
+       struct berval digest;
+       digest.bv_val = HASHdigest;
+       digest.bv_len = sizeof(HASHdigest);
+
+       /* we should have at least one value at this point */
+       assert( values != NULL && values[0].bv_val != NULL );
+
+       nkeys=0;
+       for( i=0; values[i].bv_val != NULL; i++ ) {
+               /* count number of indices to generate */
+               if( values[i].bv_len < SLAP_INDEX_SUBSTR_MINLEN ) {
+                       continue;
+               }
+
+               if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
+                       if( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
+                               nkeys += SLAP_INDEX_SUBSTR_MAXLEN -
+                                       ( SLAP_INDEX_SUBSTR_MINLEN - 1);
+                       } else {
+                               nkeys += values[i].bv_len - ( SLAP_INDEX_SUBSTR_MINLEN - 1 );
+                       }
+               }
+
+               if( flags & SLAP_INDEX_SUBSTR_ANY ) {
+                       if( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
+                               nkeys += values[i].bv_len - ( SLAP_INDEX_SUBSTR_MAXLEN - 1 );
+                       }
+               }
+
+               if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
+                       if( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
+                               nkeys += SLAP_INDEX_SUBSTR_MAXLEN -
+                                       ( SLAP_INDEX_SUBSTR_MINLEN - 1);
+                       } else {
+                               nkeys += values[i].bv_len - ( SLAP_INDEX_SUBSTR_MINLEN - 1 );
+                       }
+               }
+       }
+
+       if( nkeys == 0 ) {
+               /* no keys to generate */
+               *keysp = NULL;
+               return LDAP_SUCCESS;
+       }
+
+       keys = ch_malloc( sizeof( struct berval ) * (nkeys+1) );
+
+       slen = syntax->ssyn_oidlen;
+       mlen = mr->smr_oidlen;
+
+       nkeys=0;
+       for( i=0; values[i].bv_val != NULL; i++ ) {
+               int j,max;
+               struct berval value;
+
+               if( values[i].bv_len < SLAP_INDEX_SUBSTR_MINLEN ) continue;
+
+               ber_dupbv( &value, &values[i] );
+               ldap_pvt_str2upper( value.bv_val );
+
+               if( ( flags & SLAP_INDEX_SUBSTR_ANY ) &&
+                       ( value.bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) )
+               {
+                       char pre = SLAP_INDEX_SUBSTR_PREFIX;
+                       max = value.bv_len - ( SLAP_INDEX_SUBSTR_MAXLEN - 1);
+
+                       for( j=0; j<max; j++ ) {
+                               HASH_Init( &HASHcontext );
+                               if( prefix != NULL && prefix->bv_len > 0 ) {
+                                       HASH_Update( &HASHcontext,
+                                               prefix->bv_val, prefix->bv_len );
+                               }
+
+                               HASH_Update( &HASHcontext,
+                                       &pre, sizeof( pre ) );
+                               HASH_Update( &HASHcontext,
+                                       syntax->ssyn_oid, slen );
+                               HASH_Update( &HASHcontext,
+                                       mr->smr_oid, mlen );
+                               HASH_Update( &HASHcontext,
+                                       &value.bv_val[j],
+                                       SLAP_INDEX_SUBSTR_MAXLEN );
+                               HASH_Final( HASHdigest, &HASHcontext );
+
+                               ber_dupbv( &keys[nkeys++], &digest );
+                       }
+               }
+
+               max = SLAP_INDEX_SUBSTR_MAXLEN < value.bv_len
+                       ? SLAP_INDEX_SUBSTR_MAXLEN : value.bv_len;
+
+               for( j=SLAP_INDEX_SUBSTR_MINLEN; j<=max; j++ ) {
+                       char pre;
+
+                       if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
+                               pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
+                               HASH_Init( &HASHcontext );
+                               if( prefix != NULL && prefix->bv_len > 0 ) {
+                                       HASH_Update( &HASHcontext,
+                                               prefix->bv_val, prefix->bv_len );
+                               }
+                               HASH_Update( &HASHcontext,
+                                       &pre, sizeof( pre ) );
+                               HASH_Update( &HASHcontext,
+                                       syntax->ssyn_oid, slen );
+                               HASH_Update( &HASHcontext,
+                                       mr->smr_oid, mlen );
+                               HASH_Update( &HASHcontext,
+                                       value.bv_val, j );
+                               HASH_Final( HASHdigest, &HASHcontext );
+
+                               ber_dupbv( &keys[nkeys++], &digest );
+                       }
+
+                       if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
+                               pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
+                               HASH_Init( &HASHcontext );
+                               if( prefix != NULL && prefix->bv_len > 0 ) {
+                                       HASH_Update( &HASHcontext,
+                                               prefix->bv_val, prefix->bv_len );
+                               }
+                               HASH_Update( &HASHcontext,
+                                       &pre, sizeof( pre ) );
+                               HASH_Update( &HASHcontext,
+                                       syntax->ssyn_oid, slen );
+                               HASH_Update( &HASHcontext,
+                                       mr->smr_oid, mlen );
+                               HASH_Update( &HASHcontext,
+                                       &value.bv_val[value.bv_len-j], j );
+                               HASH_Final( HASHdigest, &HASHcontext );
+
+                               ber_dupbv( &keys[nkeys++], &digest );
+                       }
+
+               }
+
+               free( value.bv_val );
+       }
+
+       if( nkeys > 0 ) {
+               keys[nkeys].bv_val = NULL;
+               *keysp = keys;
+       } else {
+               ch_free( keys );
+               *keysp = NULL;
+       }
+
+       return LDAP_SUCCESS;
+}
+
+static int caseIgnoreIA5SubstringsFilter(
+       slap_mask_t use,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *prefix,
+       void * assertValue,
+       BerVarray *keysp )
+{
+       SubstringsAssertion *sa = assertValue;
+       char pre;
+       ber_len_t nkeys = 0;
+       size_t slen, mlen, klen;
+       BerVarray keys;
+       HASH_CONTEXT   HASHcontext;
+       unsigned char   HASHdigest[HASH_BYTES];
+       struct berval value;
+       struct berval digest;
+
+       if((flags & SLAP_INDEX_SUBSTR_INITIAL) && sa->sa_initial.bv_val != NULL &&
+               sa->sa_initial.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
+       {
+               nkeys++;
+       }
+
+       if((flags & SLAP_INDEX_SUBSTR_ANY) && sa->sa_any != NULL ) {
+               ber_len_t i;
+               for( i=0; sa->sa_any[i].bv_val != NULL; i++ ) {
+                       if( sa->sa_any[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
+                               /* don't bother accounting for stepping */
+                               nkeys += sa->sa_any[i].bv_len -
+                                       ( SLAP_INDEX_SUBSTR_MAXLEN - 1 );
+                       }
+               }
+       }
+
+       if((flags & SLAP_INDEX_SUBSTR_FINAL) && sa->sa_final.bv_val != NULL &&
+               sa->sa_final.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
+       {
+               nkeys++;
+       }
+
+       if( nkeys == 0 ) {
+               *keysp = NULL;
+               return LDAP_SUCCESS;
+       }
+
+       digest.bv_val = HASHdigest;
+       digest.bv_len = sizeof(HASHdigest);
+
+       slen = syntax->ssyn_oidlen;
+       mlen = mr->smr_oidlen;
+
+       keys = ch_malloc( sizeof( struct berval ) * (nkeys+1) );
+       nkeys = 0;
+
+       if((flags & SLAP_INDEX_SUBSTR_INITIAL) && sa->sa_initial.bv_val != NULL &&
+               sa->sa_initial.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
+       {
+               pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
+               ber_dupbv( &value, &sa->sa_initial );
+               ldap_pvt_str2upper( value.bv_val );
+
+               klen = SLAP_INDEX_SUBSTR_MAXLEN < value.bv_len
+                       ? SLAP_INDEX_SUBSTR_MAXLEN : value.bv_len;
+
+               HASH_Init( &HASHcontext );
+               if( prefix != NULL && prefix->bv_len > 0 ) {
+                       HASH_Update( &HASHcontext,
+                               prefix->bv_val, prefix->bv_len );
+               }
+               HASH_Update( &HASHcontext,
+                       &pre, sizeof( pre ) );
+               HASH_Update( &HASHcontext,
+                       syntax->ssyn_oid, slen );
+               HASH_Update( &HASHcontext,
+                       mr->smr_oid, mlen );
+               HASH_Update( &HASHcontext,
+                       value.bv_val, klen );
+               HASH_Final( HASHdigest, &HASHcontext );
+
+               free( value.bv_val );
+               ber_dupbv( &keys[nkeys++], &digest );
+       }
+
+       if((flags & SLAP_INDEX_SUBSTR_ANY) && sa->sa_any != NULL ) {
+               ber_len_t i, j;
+               pre = SLAP_INDEX_SUBSTR_PREFIX;
+               klen = SLAP_INDEX_SUBSTR_MAXLEN;
+
+               for( i=0; sa->sa_any[i].bv_val != NULL; i++ ) {
+                       if( sa->sa_any[i].bv_len < SLAP_INDEX_SUBSTR_MAXLEN ) {
+                               continue;
+                       }
+
+                       ber_dupbv( &value, &sa->sa_any[i] );
+                       ldap_pvt_str2upper( value.bv_val );
+
+                       for(j=0;
+                               j <= value.bv_len - SLAP_INDEX_SUBSTR_MAXLEN;
+                               j += SLAP_INDEX_SUBSTR_STEP )
+                       {
+                               HASH_Init( &HASHcontext );
+                               if( prefix != NULL && prefix->bv_len > 0 ) {
+                                       HASH_Update( &HASHcontext,
+                                               prefix->bv_val, prefix->bv_len );
+                               }
+                               HASH_Update( &HASHcontext,
+                                       &pre, sizeof( pre ) );
+                               HASH_Update( &HASHcontext,
+                                       syntax->ssyn_oid, slen );
+                               HASH_Update( &HASHcontext,
+                                       mr->smr_oid, mlen );
+                               HASH_Update( &HASHcontext,
+                                       &value.bv_val[j], klen );
+                               HASH_Final( HASHdigest, &HASHcontext );
+
+                               ber_dupbv( &keys[nkeys++], &digest );
+                       }
+
+                       free( value.bv_val );
+               }
+       }
+
+       if((flags & SLAP_INDEX_SUBSTR_FINAL) && sa->sa_final.bv_val != NULL &&
+               sa->sa_final.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
+       {
+               pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
+               ber_dupbv( &value, &sa->sa_final );
+               ldap_pvt_str2upper( value.bv_val );
+
+               klen = SLAP_INDEX_SUBSTR_MAXLEN < value.bv_len
+                       ? SLAP_INDEX_SUBSTR_MAXLEN : value.bv_len;
+
+               HASH_Init( &HASHcontext );
+               if( prefix != NULL && prefix->bv_len > 0 ) {
+                       HASH_Update( &HASHcontext,
+                               prefix->bv_val, prefix->bv_len );
+               }
+               HASH_Update( &HASHcontext,
+                       &pre, sizeof( pre ) );
+               HASH_Update( &HASHcontext,
+                       syntax->ssyn_oid, slen );
+               HASH_Update( &HASHcontext,
+                       mr->smr_oid, mlen );
+               HASH_Update( &HASHcontext,
+                       &value.bv_val[value.bv_len-klen], klen );
+               HASH_Final( HASHdigest, &HASHcontext );
+
+               free( value.bv_val );
+               ber_dupbv( &keys[nkeys++], &digest );
+       }
+
+       if( nkeys > 0 ) {
+               keys[nkeys].bv_val = NULL;
+               *keysp = keys;
+       } else {
+               ch_free( keys );
+               *keysp = NULL;
+       }
+
+       return LDAP_SUCCESS;
+}
+       
+static int
+numericStringValidate(
+       Syntax *syntax,
+       struct berval *in )
+{
+       ber_len_t i;
+
+       for(i=0; i < in->bv_len; i++) {
+               if( !SLAP_NUMERIC(in->bv_val[i]) ) {
+                       return LDAP_INVALID_SYNTAX;
+               }
+       }
+
+       return LDAP_SUCCESS;
+}
+
+static int
+numericStringNormalize(
+       Syntax *syntax,
+       struct berval *val,
+       struct berval *normalized )
+{
+       /* removal all spaces */
+       char *p, *q;
+
+       normalized->bv_val = ch_malloc( val->bv_len + 1 );
+
+       p = val->bv_val;
+       q = normalized->bv_val;
+
+       while ( *p ) {
+               if ( ASCII_SPACE( *p ) ) {
+                       /* Ignore whitespace */
+                       p++;
+               } else {
+                       *q++ = *p++;
+               }
+       }
+
+       /* we should have copied no more then is in val */
+       assert( (q - normalized->bv_val) <= (p - val->bv_val) );
+
+       /* null terminate */
+       *q = '\0';
+
+       normalized->bv_len = q - normalized->bv_val;
+
+       return LDAP_SUCCESS;
+}
+
+static int
+objectIdentifierFirstComponentMatch(
+       int *matchp,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *value,
+       void *assertedValue )
+{
+       int rc = LDAP_SUCCESS;
+       int match;
+       struct berval *asserted = (struct berval *) assertedValue;
+       ber_len_t i;
+       struct berval oid;
+
+       if( value->bv_len == 0 || value->bv_val[0] != '(' /*')'*/ ) {
+               return LDAP_INVALID_SYNTAX;
+       }
+
+       /* trim leading white space */
+       for( i=1; ASCII_SPACE(value->bv_val[i]) && i < value->bv_len; i++ ) {
+               /* empty */
+       }
+
+       /* grab next word */
+       oid.bv_val = &value->bv_val[i];
+       oid.bv_len = value->bv_len - i;
+       for( i=1; ASCII_SPACE(value->bv_val[i]) && i < oid.bv_len; i++ ) {
+               /* empty */
+       }
+       oid.bv_len = i;
+
+       /* insert attributeTypes, objectclass check here */
+       if( OID_LEADCHAR(asserted->bv_val[0]) ) {
+               rc = objectIdentifierMatch( &match, flags, syntax, mr, &oid, asserted );
+
+       } else {
+               if ( !strcmp( syntax->ssyn_oid, SLAP_SYNTAX_MATCHINGRULES_OID ) ) {
+                       MatchingRule *asserted_mr = mr_bvfind( asserted );
+                       MatchingRule *stored_mr = mr_bvfind( &oid );
+
+                       if( asserted_mr == NULL ) {
+                               rc = SLAPD_COMPARE_UNDEFINED;
+                       } else {
+                               match = asserted_mr != stored_mr;
+                       }
+
+               } else if ( !strcmp( syntax->ssyn_oid,
+                       SLAP_SYNTAX_ATTRIBUTETYPES_OID ) )
+               {
+                       AttributeType *asserted_at = at_bvfind( asserted );
+                       AttributeType *stored_at = at_bvfind( &oid );
+
+                       if( asserted_at == NULL ) {
+                               rc = SLAPD_COMPARE_UNDEFINED;
+                       } else {
+                               match = asserted_at != stored_at;
+                       }
+
+               } else if ( !strcmp( syntax->ssyn_oid,
+                       SLAP_SYNTAX_OBJECTCLASSES_OID ) )
+               {
+                       ObjectClass *asserted_oc = oc_bvfind( asserted );
+                       ObjectClass *stored_oc = oc_bvfind( &oid );
+
+                       if( asserted_oc == NULL ) {
+                               rc = SLAPD_COMPARE_UNDEFINED;
+                       } else {
+                               match = asserted_oc != stored_oc;
+                       }
+               }
+       }
+
+#ifdef NEW_LOGGING
+       LDAP_LOG(( "schema", LDAP_LEVEL_ENTRY,
+                  "objectIdentifierFirstComponentMatch: %d\n    %s\n    %s\n",
+                  match, value->bv_val, asserted->bv_val ));
+#else
+       Debug( LDAP_DEBUG_ARGS, "objectIdentifierFirstComponentMatch "
+               "%d\n\t\"%s\"\n\t\"%s\"\n",
+               match, value->bv_val, asserted->bv_val );
+#endif
+
+
+       if( rc == LDAP_SUCCESS ) *matchp = match;
+       return rc;
+}
+
+static int
+integerBitAndMatch(
+       int *matchp,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *value,
+       void *assertedValue )
+{
+       long lValue, lAssertedValue;
+
+       /* safe to assume integers are NUL terminated? */
+       lValue = strtoul(value->bv_val, NULL, 10);
+       if(( lValue == LONG_MIN || lValue == LONG_MAX) && errno == ERANGE )
+               return LDAP_CONSTRAINT_VIOLATION;
+
+       lAssertedValue = strtol(((struct berval *)assertedValue)->bv_val, NULL, 10);
+       if(( lAssertedValue == LONG_MIN || lAssertedValue == LONG_MAX) && errno == ERANGE )
+               return LDAP_CONSTRAINT_VIOLATION;
+
+       *matchp = (lValue & lAssertedValue);
+       return LDAP_SUCCESS;
+}
+
+static int
+integerBitOrMatch(
+       int *matchp,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *value,
+       void *assertedValue )
+{
+       long lValue, lAssertedValue;
+
+       /* safe to assume integers are NUL terminated? */
+       lValue = strtoul(value->bv_val, NULL, 10);
+       if(( lValue == LONG_MIN || lValue == LONG_MAX) && errno == ERANGE )
+               return LDAP_CONSTRAINT_VIOLATION;
+
+       lAssertedValue = strtol(((struct berval *)assertedValue)->bv_val, NULL, 10);
+       if(( lAssertedValue == LONG_MIN || lAssertedValue == LONG_MAX) && errno == ERANGE )
+               return LDAP_CONSTRAINT_VIOLATION;
+
+       *matchp = (lValue | lAssertedValue);
+       return LDAP_SUCCESS;
+}
+
+#ifdef HAVE_TLS
+#include <openssl/x509.h>
+#include <openssl/err.h>
+char digit[] = "0123456789";
+
+/*
+ * Next function returns a string representation of a ASN1_INTEGER.
+ * It works for unlimited lengths.
+ */
+
+static struct berval *
+asn1_integer2str(ASN1_INTEGER *a)
+{
+       char buf[256];
+       char *p;
+  
+       /* We work backwards, make it fill from the end of buf */
+       p = buf + sizeof(buf) - 1;
+       *p = '\0';
+
+       if ( a == NULL || a->length == 0 ) {
+               *--p = '0';
+       } else {
+               int i;
+               int n = a->length;
+               int base = 0;
+               unsigned int *copy;
+
+               /* We want to preserve the original */
+               copy = ch_malloc(n*sizeof(unsigned int));
+               for (i = 0; i<n; i++) {
+                       copy[i] = a->data[i];
+               }
+
+               /* 
+                * base indicates the index of the most significant
+                * byte that might be nonzero.  When it goes off the
+                * end, we now there is nothing left to do.
+                */
+               while (base < n) {
+                       unsigned int carry;
+
+                       carry = 0;
+                       for (i = base; i<n; i++ ) {
+                               copy[i] += carry*256;
+                               carry = copy[i] % 10;
+                               copy[i] /= 10;
+                       }
+                       if (p <= buf+1) {
+                               /*
+                                * Way too large, we need to leave
+                                * room for sign if negative
+                                */
+                               free(copy);
+                               return NULL;
+                       }
+                       *--p = digit[carry];
+                       if (copy[base] == 0)
+                               base++;
+               }
+               free(copy);
+       }
+
+       if ( a->type == V_ASN1_NEG_INTEGER ) {
+               *--p = '-';
+       }
+
+       return ber_bvstrdup(p);
+}
+
+/* Get a DN in RFC2253 format from a X509_NAME internal struct */
+static struct berval *
+dn_openssl2ldap(X509_NAME *name)
+{
+       char issuer_dn[1024];
+       BIO *bio;
+
+       bio = BIO_new(BIO_s_mem());
+       if ( !bio ) {
+#ifdef NEW_LOGGING
+               LDAP_LOG(( "schema", LDAP_LEVEL_ENTRY,
+                          "dn_openssl2ldap: error creating BIO_s_mem: %s\n",
+                          ERR_error_string(ERR_get_error(),NULL)));
+#else
+               Debug( LDAP_DEBUG_ARGS, "dn_openssl2ldap: "
+                      "error creating BIO: %s\n",
+                      ERR_error_string(ERR_get_error(),NULL), NULL, NULL );
+#endif
+               return NULL;
+       }
+       X509_NAME_print_ex(bio, name, 0, XN_FLAG_RFC2253);
+
+       BIO_gets(bio, issuer_dn, 1024);
+
+       BIO_free(bio);
+       return ber_bvstrdup(issuer_dn);
+}
+
+/*
+ * Given a certificate in DER format, extract the corresponding
+ * assertion value for certificateExactMatch
+ */
+static int
+certificateExactConvert(
+       struct berval * in,
+       struct berval * out )
+{
+       X509 *xcert;
+       unsigned char *p = in->bv_val;
+       struct berval *serial;
+       struct berval *issuer_dn;
+       struct berval *bv_tmp;
+
+       xcert = d2i_X509(NULL, &p, in->bv_len);
+       if ( !xcert ) {
+#ifdef NEW_LOGGING
+               LDAP_LOG(( "schema", LDAP_LEVEL_ENTRY,
+                          "certificateExactConvert: error parsing cert: %s\n",
+                          ERR_error_string(ERR_get_error(),NULL)));
+#else
+               Debug( LDAP_DEBUG_ARGS, "certificateExactConvert: "
+                      "error parsing cert: %s\n",
+                      ERR_error_string(ERR_get_error(),NULL), NULL, NULL );
+#endif
+               return LDAP_INVALID_SYNTAX;
+       }
+
+       serial = asn1_integer2str(xcert->cert_info->serialNumber);
+       if ( !serial ) {
+               X509_free(xcert);
+               return LDAP_INVALID_SYNTAX;
+       }
+       issuer_dn = dn_openssl2ldap(X509_get_issuer_name(xcert));
+       if ( !issuer_dn ) {
+               X509_free(xcert);
+               ber_bvfree(serial);
+               return LDAP_INVALID_SYNTAX;
+       }
+       /* Actually, dn_openssl2ldap returns in a normalized format, but
+          it is different from our normalized format */
+       bv_tmp = issuer_dn;
+       if ( dnNormalize(NULL, bv_tmp, &issuer_dn) != LDAP_SUCCESS ) {
+               X509_free(xcert);
+               ber_bvfree(serial);
+               ber_bvfree(bv_tmp);
+               return LDAP_INVALID_SYNTAX;
+       }
+       ber_bvfree(bv_tmp);
+
+       X509_free(xcert);
+
+       out->bv_len = serial->bv_len + issuer_dn->bv_len + sizeof(" $ ");
+       out->bv_val = ch_malloc(out->bv_len);
+       p = out->bv_val;
+       AC_MEMCPY(p, serial->bv_val, serial->bv_len);
+       p += serial->bv_len;
+       AC_MEMCPY(p, " $ ", sizeof(" $ ")-1);
+       p += 3;
+       AC_MEMCPY(p, issuer_dn->bv_val, issuer_dn->bv_len);
+       p += issuer_dn->bv_len;
+       *p++ = '\0';
+
+#ifdef NEW_LOGGING
+       LDAP_LOG(( "schema", LDAP_LEVEL_ENTRY,
+                  "certificateExactConvert: \n %s\n",
+                  out->bv_val));
+#else
+       Debug( LDAP_DEBUG_ARGS, "certificateExactConvert "
+               "\n\t\"%s\"\n",
+               out->bv_val, NULL, NULL );
+#endif
+
+       ber_bvfree(serial);
+       ber_bvfree(issuer_dn);
+
+       return LDAP_SUCCESS;
+}
+
+static int
+serial_and_issuer_parse(
+       struct berval *assertion,
+       struct berval **serial,
+       struct berval **issuer_dn
+)
+{
+       char *begin;
+       char *end;
+       char *p;
+       struct berval bv;
+
+       begin = assertion->bv_val;
+       end = assertion->bv_val+assertion->bv_len-1;
+       for (p=begin; p<=end && *p != '$'; p++)
+               ;
+       if ( p > end )
+               return LDAP_INVALID_SYNTAX;
+
+       /* p now points at the $ sign, now use begin and end to delimit the
+          serial number */
+       while (ASCII_SPACE(*begin))
+               begin++;
+       end = p-1;
+       while (ASCII_SPACE(*end))
+               end--;
+
+       bv.bv_len = end-begin+1;
+       bv.bv_val = begin;
+       *serial = ber_dupbv(NULL, &bv);
+
+       /* now extract the issuer, remember p was at the dollar sign */
+       begin = p+1;
+       end = assertion->bv_val+assertion->bv_len-1;
+       while (ASCII_SPACE(*begin))
+               begin++;
+       /* should we trim spaces at the end too? is it safe always? */
+
+       bv.bv_len = end-begin+1;
+       bv.bv_val = begin;
+       dnNormalize( NULL, &bv, issuer_dn );
+
+       return LDAP_SUCCESS;
+}
+
+static int
+certificateExactMatch(
+       int *matchp,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *value,
+       void *assertedValue )
+{
+       X509 *xcert;
+       unsigned char *p = value->bv_val;
+       struct berval *serial;
+       struct berval *issuer_dn;
+       struct berval *asserted_serial;
+       struct berval *asserted_issuer_dn;
+       int ret;
+
+       xcert = d2i_X509(NULL, &p, value->bv_len);
+       if ( !xcert ) {
+#ifdef NEW_LOGGING
+               LDAP_LOG(( "schema", LDAP_LEVEL_ENTRY,
+                          "certificateExactMatch: error parsing cert: %s\n",
+                          ERR_error_string(ERR_get_error(),NULL)));
+#else
+               Debug( LDAP_DEBUG_ARGS, "certificateExactMatch: "
+                      "error parsing cert: %s\n",
+                      ERR_error_string(ERR_get_error(),NULL), NULL, NULL );
+#endif
+               return LDAP_INVALID_SYNTAX;
+       }
+
+       serial = asn1_integer2str(xcert->cert_info->serialNumber);
+       issuer_dn = dn_openssl2ldap(X509_get_issuer_name(xcert));
+
+       X509_free(xcert);
+
+       serial_and_issuer_parse(assertedValue,
+                               &asserted_serial,
+                               &asserted_issuer_dn);
+
+       ret = integerMatch(
+               matchp,
+               flags,
+               slap_schema.si_syn_integer,
+               slap_schema.si_mr_integerMatch,
+               serial,
+               asserted_serial);
+       if ( ret == LDAP_SUCCESS ) {
+               if ( *matchp == 0 ) {
+                       /* We need to normalize everything for dnMatch */
+                       ret = dnMatch(
+                               matchp,
+                               flags,
+                               slap_schema.si_syn_distinguishedName,
+                               slap_schema.si_mr_distinguishedNameMatch,
+                               issuer_dn,
+                               asserted_issuer_dn);
+               }
+       }
+
+#ifdef NEW_LOGGING
+       LDAP_LOG(( "schema", LDAP_LEVEL_ENTRY,
+                  "certificateExactMatch: %d\n  %s $ %s\n       %s $   %s\n",
+                  *matchp, serial->bv_val, issuer_dn->bv_val,
+                  asserted->serial->bv_val, asserted_issuer_dn->bv_val));
+#else
+       Debug( LDAP_DEBUG_ARGS, "certificateExactMatch "
+               "%d\n\t\"%s $ %s\"\n",
+               *matchp, serial->bv_val, issuer_dn->bv_val );
+       Debug( LDAP_DEBUG_ARGS, "\t\"%s $ %s\"\n",
+               asserted_serial->bv_val, asserted_issuer_dn->bv_val,
+               NULL );
+#endif
+
+       ber_bvfree(serial);
+       ber_bvfree(issuer_dn);
+       ber_bvfree(asserted_serial);
+       ber_bvfree(asserted_issuer_dn);
+
+       return ret;
+}
+
+/* 
+ * Index generation function
+ * We just index the serials, in most scenarios the issuer DN is one of
+ * a very small set of values.
+ */
+static int certificateExactIndexer(
+       slap_mask_t use,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *prefix,
+       BerVarray values,
+       BerVarray *keysp )
+{
+       int i;
+       BerVarray keys;
+       X509 *xcert;
+       unsigned char *p;
+       struct berval * serial;
+
+       /* we should have at least one value at this point */
+       assert( values != NULL && values[0].bv_val != NULL );
+
+       for( i=0; values[i].bv_val != NULL; i++ ) {
+               /* empty -- just count them */
+       }
+
+       keys = ch_malloc( sizeof( struct berval ) * (i+1) );
+
+       for( i=0; values[i].bv_val != NULL; i++ ) {
+               p = values[i].bv_val;
+               xcert = d2i_X509(NULL, &p, values[i].bv_len);
+               if ( !xcert ) {
+#ifdef NEW_LOGGING
+                       LDAP_LOG(( "schema", LDAP_LEVEL_ENTRY,
+                           "certificateExactIndexer: error parsing cert: %s\n",
+                               ERR_error_string(ERR_get_error(),NULL)));
+#else
+                       Debug( LDAP_DEBUG_ARGS, "certificateExactIndexer: "
+                              "error parsing cert: %s\n",
+                              ERR_error_string(ERR_get_error(),NULL),
+                              NULL, NULL );
+#endif
+                       /* Do we leak keys on error? */
+                       return LDAP_INVALID_SYNTAX;
+               }
+
+               serial = asn1_integer2str(xcert->cert_info->serialNumber);
+               X509_free(xcert);
+               integerNormalize( slap_schema.si_syn_integer,
+                                 serial,
+                                 &keys[i] );
+               ber_bvfree(serial);
+#ifdef NEW_LOGGING
+               LDAP_LOG(( "schema", LDAP_LEVEL_ENTRY,
+                          "certificateExactIndexer: returning: %s\n",
+                          keys[i].bv_val));
+#else
+               Debug( LDAP_DEBUG_ARGS, "certificateExactIndexer: "
+                      "returning: %s\n",
+                      keys[i].bv_val,
+                      NULL, NULL );
+#endif
+       }
+
+       keys[i].bv_val = NULL;
+       *keysp = keys;
+       return LDAP_SUCCESS;
+}
+
+/* Index generation function */
+/* We think this is always called with a value in matching rule syntax */
+static int certificateExactFilter(
+       slap_mask_t use,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *prefix,
+       void * assertValue,
+       BerVarray *keysp )
+{
+       BerVarray keys;
+       struct berval *asserted_serial;
+       struct berval *asserted_issuer_dn;
+
+       serial_and_issuer_parse(assertValue,
+                               &asserted_serial,
+                               &asserted_issuer_dn);
+
+       keys = ch_malloc( sizeof( struct berval ) * 2 );
+       integerNormalize( syntax, asserted_serial, &keys[0] );
+       keys[1].bv_val = NULL;
+       *keysp = keys;
+
+       ber_bvfree(asserted_serial);
+       ber_bvfree(asserted_issuer_dn);
+       return LDAP_SUCCESS;
+}
+#endif
+
+static int
+check_time_syntax (struct berval *val,
+       int start,
+       int *parts)
+{
+       static int ceiling[9] = { 99, 99, 11, 30, 23, 59, 59, 12, 59 };
+       static int mdays[2][12] = {
+               /* non-leap years */
+               { 30, 27, 30, 29, 30, 29, 30, 30, 29, 30, 29, 30 },
+               /* leap years */
+               { 30, 28, 30, 29, 30, 29, 30, 30, 29, 30, 29, 30 }
+       };
+       char *p, *e;
+       int part, c, tzoffset, leapyear = 0 ;
+
+       if( val->bv_len == 0 ) {
+               return LDAP_INVALID_SYNTAX;
+       }
+
+       p = (char *)val->bv_val;
+       e = p + val->bv_len;
+
+       /* Ignore initial whitespace */
+       while ( ( p < e ) && ASCII_SPACE( *p ) ) {
+               p++;
+       }
+
+       if (e - p < 13 - (2 * start)) {
+               return LDAP_INVALID_SYNTAX;
+       }
+
+       for (part = 0; part < 9; part++) {
+               parts[part] = 0;
+       }
+
+       for (part = start; part < 7; part++) {
+               c = *p;
+               if ((part == 6) && (c == 'Z' || c == '+' || c == '-')) {
+                       part++;
+                       break;
+               }
+               p++;
+               c -= '0';
+               if (p == e) {
+                       return LDAP_INVALID_SYNTAX;
+               }
+               if (c < 0 || c > 9) {
+                       return LDAP_INVALID_SYNTAX;
+               }
+               parts[part] = c;
+
+               c = *p++ - '0';
+               if (p == e) {
+                       return LDAP_INVALID_SYNTAX;
+               }
+               if (c < 0 || c > 9) {
+                       return LDAP_INVALID_SYNTAX;
+               }
+               parts[part] *= 10;
+               parts[part] += c;
+
+               if (part == 2 || part == 3) {
+                       parts[part]--;
+               }
+               if (parts[part] < 0) {
+                       return LDAP_INVALID_SYNTAX;
+               }
+               if (parts[part] > ceiling[part]) {
+                       return LDAP_INVALID_SYNTAX;
+               }
+       }
+
+       /* leapyear check for the Gregorian calendar (year>1581) */
+       if (((parts[1] % 4 == 0) && (parts[1] != 0)) ||
+               ((parts[0] % 4 == 0) && (parts[1] == 0)))
+       {
+               leapyear = 1;
+       }
+
+       if (parts[3] > mdays[leapyear][parts[2]]) {
+               return LDAP_INVALID_SYNTAX;
+       }
+       
+       c = *p++;
+       if (c == 'Z') {
+               tzoffset = 0; /* UTC */
+       } else if (c != '+' && c != '-') {
+               return LDAP_INVALID_SYNTAX;
+       } else {
+               if (c == '-') {
+                       tzoffset = -1;
+               } else /* c == '+' */ {
+                       tzoffset = 1;
+               }
+
+               if (p > e - 4) {
+                       return LDAP_INVALID_SYNTAX;
+               }
+
+               for (part = 7; part < 9; part++) {
+                       c = *p++ - '0';
+                       if (c < 0 || c > 9) {
+                               return LDAP_INVALID_SYNTAX;
+                       }
+                       parts[part] = c;
+
+                       c = *p++ - '0';
+                       if (c < 0 || c > 9) {
+                               return LDAP_INVALID_SYNTAX;
+                       }
+                       parts[part] *= 10;
+                       parts[part] += c;
+                       if (parts[part] < 0 || parts[part] > ceiling[part]) {
+                               return LDAP_INVALID_SYNTAX;
+                       }
+               }
+       }
+
+       /* Ignore trailing whitespace */
+       while ( ( p < e ) && ASCII_SPACE( *p ) ) {
+               p++;
+       }
+       if (p != e) {
+               return LDAP_INVALID_SYNTAX;
+       }
+
+       switch ( tzoffset ) {
+       case -1: /* negativ offset to UTC, ie west of Greenwich  */
+               parts[4] += parts[7];
+               parts[5] += parts[8];
+               for (part = 6; --part > 0; ) { /* offset is just hhmm, no seconds */
+                       if (part != 3) {
+                               c = ceiling[part];
+                       } else {
+                               c = mdays[leapyear][parts[2]];
+                       }
+                       if (parts[part] > c) {
+                               parts[part] -= c + 1;
+                               parts[part - 1]++;
+                       }
+               }
+               break;
+       case 1: /* positive offset to UTC, ie east of Greenwich */
+               parts[4] -= parts[7];
+               parts[5] -= parts[8];
+               for (part = 6; --part > 0; ) {
+                       if (part != 3) {
+                               c = ceiling[part];
+                       } else {
+                               /* first arg to % needs to be non negativ */
+                               c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
+                       }
+                       if (parts[part] < 0) {
+                               parts[part] += c + 1;
+                               parts[part - 1]--;
+                       }
+               }
+               break;
+       case 0: /* already UTC */
+               break;
+       }
+
+       return LDAP_SUCCESS;
+}
+
+static int
+utcTimeNormalize(
+       Syntax *syntax,
+       struct berval *val,
+       struct berval *normalized )
+{
+       int parts[9], rc;
+
+       rc = check_time_syntax(val, 1, parts);
+       if (rc != LDAP_SUCCESS) {
+               return rc;
+       }
+
+       normalized->bv_val = ch_malloc( 14 );
+       if ( normalized->bv_val == NULL ) {
+               return LBER_ERROR_MEMORY;
+       }
+
+       sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02dZ",
+               parts[1], parts[2] + 1, parts[3] + 1,
+               parts[4], parts[5], parts[6] );
+       normalized->bv_len = 13;
+
+       return LDAP_SUCCESS;
+}
+
+static int
+utcTimeValidate(
+       Syntax *syntax,
+       struct berval *in )
+{
+       int parts[9];
+
+       return check_time_syntax(in, 1, parts);
+}
+
+static int
+generalizedTimeValidate(
+       Syntax *syntax,
+       struct berval *in )
+{
+       int parts[9];
+
+       return check_time_syntax(in, 0, parts);
+}
+
+static int
+generalizedTimeNormalize(
+       Syntax *syntax,
+       struct berval *val,
+       struct berval *normalized )
+{
+       int parts[9], rc;
+
+       rc = check_time_syntax(val, 0, parts);
+       if (rc != LDAP_SUCCESS) {
+               return rc;
+       }
+
+       normalized->bv_val = ch_malloc( 16 );
+       if ( normalized->bv_val == NULL ) {
+               return LBER_ERROR_MEMORY;
+       }
+
+       sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02dZ",
+               parts[0], parts[1], parts[2] + 1, parts[3] + 1,
+               parts[4], parts[5], parts[6] );
+       normalized->bv_len = 15;
+
+       return LDAP_SUCCESS;
+}
+
+static int
+nisNetgroupTripleValidate(
+       Syntax *syntax,
+       struct berval *val )
+{
+       char *p, *e;
+       int commas = 0;
+
+       if ( val->bv_len == 0 ) {
+               return LDAP_INVALID_SYNTAX;
+       }
+
+       p = (char *)val->bv_val;
+       e = p + val->bv_len;
+
+       if ( *p != '(' /*')'*/ ) {
+               return LDAP_INVALID_SYNTAX;
+       }
+
+       for ( p++; ( p < e ) && ( *p != /*'('*/ ')' ); p++ ) {
+               if ( *p == ',' ) {
+                       commas++;
+                       if ( commas > 2 ) {
+                               return LDAP_INVALID_SYNTAX;
+                       }
+
+               } else if ( !ATTR_CHAR( *p ) ) {
+                       return LDAP_INVALID_SYNTAX;
+               }
+       }
+
+       if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
+               return LDAP_INVALID_SYNTAX;
+       }
+
+       p++;
+
+       if (p != e) {
+               return LDAP_INVALID_SYNTAX;
+       }
+
+       return LDAP_SUCCESS;
+}
+
+static int
+bootParameterValidate(
+       Syntax *syntax,
+       struct berval *val )
+{
+       char *p, *e;
+
+       if ( val->bv_len == 0 ) {
+               return LDAP_INVALID_SYNTAX;
+       }
+
+       p = (char *)val->bv_val;
+       e = p + val->bv_len;
+
+       /* key */
+       for (; ( p < e ) && ( *p != '=' ); p++ ) {
+               if ( !ATTR_CHAR( *p ) ) {
+                       return LDAP_INVALID_SYNTAX;
+               }
+       }
+
+       if ( *p != '=' ) {
+               return LDAP_INVALID_SYNTAX;
+       }
+
+       /* server */
+       for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
+               if ( !ATTR_CHAR( *p ) ) {
+                       return LDAP_INVALID_SYNTAX;
+               }
+       }
+
+       if ( *p != ':' ) {
+               return LDAP_INVALID_SYNTAX;
+       }
+
+       /* path */
+       for ( p++; p < e; p++ ) {
+               if ( !ATTR_CHAR( *p ) ) {
+                       return LDAP_INVALID_SYNTAX;
+               }
+       }
+
+       return LDAP_SUCCESS;
+}
+
+static struct syntax_defs_rec {
+       char *sd_desc;
+#define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
+#define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
+       int sd_flags;
+       slap_syntax_validate_func *sd_validate;
+       slap_syntax_transform_func *sd_normalize;
+       slap_syntax_transform_func *sd_pretty;
+#ifdef SLAPD_BINARY_CONVERSION
+       slap_syntax_transform_func *sd_ber2str;
+       slap_syntax_transform_func *sd_str2ber;
+#endif
+} syntax_defs[] = {
+       {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' "
+               X_BINARY X_NOT_H_R ")",
+               SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
+               0, NULL, NULL, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
+               0, NULL, NULL, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' "
+               X_NOT_H_R ")",
+               SLAP_SYNTAX_BLOB, blobValidate, NULL, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' "
+               X_NOT_H_R ")",
+               SLAP_SYNTAX_BER, berValidate, NULL, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
+               0, bitStringValidate, bitStringNormalize, NULL },
+       {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
+               0, booleanValidate, NULL, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
+               X_BINARY X_NOT_H_R ")",
+               SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
+               X_BINARY X_NOT_H_R ")",
+               SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
+               X_BINARY X_NOT_H_R ")",
+               SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
+               0, countryStringValidate, IA5StringNormalize, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
+               0, dnValidate, dnNormalize2, dnPretty2},
+       {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
+               0, NULL, NULL, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
+               0, NULL, NULL, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
+               0, UTF8StringValidate, UTF8StringNormalize, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
+               0, NULL, NULL, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
+               0, NULL, NULL, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
+               0, NULL, NULL, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
+               0, NULL, NULL, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
+               0, NULL, NULL, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
+               0, printablesStringValidate, IA5StringNormalize, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
+               SLAP_SYNTAX_BLOB, NULL, NULL, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
+               0, generalizedTimeValidate, generalizedTimeNormalize, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
+               0, NULL, NULL, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
+               0, IA5StringValidate, IA5StringNormalize, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
+               0, integerValidate, integerNormalize, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
+               SLAP_SYNTAX_BLOB, blobValidate, NULL, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
+               0, NULL, NULL, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
+               0, NULL, NULL, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
+               0, NULL, NULL, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
+               0, NULL, NULL, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
+               0, NULL, NULL, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
+               0, nameUIDValidate, nameUIDNormalize, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
+               0, NULL, NULL, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
+               0, numericStringValidate, numericStringNormalize, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
+               0, NULL, NULL, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
+               0, oidValidate, NULL, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
+               0, IA5StringValidate, IA5StringNormalize, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
+               0, blobValidate, NULL, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
+               0, UTF8StringValidate, UTF8StringNormalize, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
+               0, NULL, NULL, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
+               0, NULL, NULL, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
+               0, printableStringValidate, IA5StringNormalize, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' "
+               X_BINARY X_NOT_H_R ")",
+               SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
+               X_BINARY X_NOT_H_R ")",
+               SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
+               0, printableStringValidate, IA5StringNormalize, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
+               0, NULL, NULL, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
+               0, printablesStringValidate, IA5StringNormalize, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
+               0, utcTimeValidate, utcTimeNormalize, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
+               0, NULL, NULL, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
+               0, NULL, NULL, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
+               0, NULL, NULL, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
+               0, NULL, NULL, NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
+               0, NULL, NULL, NULL},
+
+       /* RFC 2307 NIS Syntaxes */
+       {"( 1.3.6.1.1.1.0.0  DESC 'RFC2307 NIS Netgroup Triple' )",
+               0, nisNetgroupTripleValidate, NULL, NULL},
+       {"( 1.3.6.1.1.1.0.1  DESC 'RFC2307 Boot Parameter' )",
+               0, bootParameterValidate, NULL, NULL},
+
+#ifdef HAVE_TLS
+       /* From PKIX */
+       /* These OIDs are not published yet, but will be in the next
+        * I-D for PKIX LDAPv3 schema as have been advanced by David
+        * Chadwick in private mail.
+        */
+       {"( 1.2.826.0.1.3344810.7.1 DESC 'Serial Number and Issuer' )",
+               0, NULL, NULL, NULL},
+#endif
+
+       /* OpenLDAP Experimental Syntaxes */
+#ifdef SLAPD_ACI_ENABLED
+       {"( 1.3.6.1.4.1.4203.666.2.1 DESC 'OpenLDAP Experimental ACI' )",
+               SLAP_SYNTAX_HIDE,
+               UTF8StringValidate /* THIS WILL CHANGE FOR NEW ACI SYNTAX */,
+               NULL, NULL},
+#endif
+
+#ifdef SLAPD_AUTHPASSWD
+       /* needs updating */
+       {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
+               SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
+#endif
+
+       /* OpenLDAP Void Syntax */
+       {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
+               SLAP_SYNTAX_HIDE, inValidate, NULL, NULL},
+       {NULL, 0, NULL, NULL, NULL}
+};
+
+/*
+ * Other matching rules in X.520 that we do not use (yet):
+ *
+ * 2.5.13.9            numericStringOrderingMatch
+ * 2.5.13.15   integerOrderingMatch
+ * 2.5.13.18   octetStringOrderingMatch
+ * 2.5.13.19   octetStringSubstringsMatch
+ * 2.5.13.25   uTCTimeMatch
+ * 2.5.13.26   uTCTimeOrderingMatch
+ * 2.5.13.31   directoryStringFirstComponentMatch
+ * 2.5.13.32   wordMatch
+ * 2.5.13.33   keywordMatch
+ * 2.5.13.35   certificateMatch
+ * 2.5.13.36   certificatePairExactMatch
+ * 2.5.13.37   certificatePairMatch
+ * 2.5.13.38   certificateListExactMatch
+ * 2.5.13.39   certificateListMatch
+ * 2.5.13.40   algorithmIdentifierMatch
+ * 2.5.13.41   storedPrefixMatch
+ * 2.5.13.42   attributeCertificateMatch
+ * 2.5.13.43   readerAndKeyIDMatch
+ * 2.5.13.44   attributeIntegrityMatch
+ */
+static struct mrule_defs_rec {
+       char *                                          mrd_desc;
+       slap_mask_t                                     mrd_usage;
+       slap_mr_convert_func *          mrd_convert;
+       slap_mr_normalize_func *        mrd_normalize;
+       slap_mr_match_func *            mrd_match;
+       slap_mr_indexer_func *          mrd_indexer;
+       slap_mr_filter_func *           mrd_filter;
+
+       char *                                          mrd_associated;
+} mrule_defs[] = {
+       /*
+        * EQUALITY matching rules must be listed after associated APPROX
+        * matching rules.  So, we list all APPROX matching rules first.
+        */
+       {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
+               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
+               SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT,
+               NULL, NULL,
+               directoryStringApproxMatch,
+               directoryStringApproxIndexer, 
+               directoryStringApproxFilter,
+               NULL},
+
+       {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
+               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
+               SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT,
+               NULL, NULL,
+               IA5StringApproxMatch,
+               IA5StringApproxIndexer, 
+               IA5StringApproxFilter,
+               NULL},
+
+       /*
+        * Other matching rules
+        */
+       
+       {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
+               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
+               SLAP_MR_EQUALITY | SLAP_MR_EXT,
+               NULL, NULL,
+               objectIdentifierMatch, caseIgnoreIA5Indexer, caseIgnoreIA5Filter,
+               NULL},
+
+       {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
+               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
+               SLAP_MR_EQUALITY | SLAP_MR_EXT,
+               NULL, NULL,
+               dnMatch, dnIndexer, dnFilter,
+               NULL},
+
+       {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
+               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
+               SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_DN_FOLD,
+               NULL, NULL,
+               caseIgnoreMatch, caseExactIgnoreIndexer, caseExactIgnoreFilter,
+               directoryStringApproxMatchOID },
+
+       {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
+               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
+               SLAP_MR_ORDERING,
+               NULL, NULL,
+               caseIgnoreOrderingMatch, NULL, NULL,
+               NULL},
+
+       {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
+               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
+               SLAP_MR_SUBSTR | SLAP_MR_EXT,
+               NULL, NULL,
+               caseExactIgnoreSubstringsMatch,
+               caseExactIgnoreSubstringsIndexer,
+               caseExactIgnoreSubstringsFilter,
+               NULL},
+
+       {"( 2.5.13.5 NAME 'caseExactMatch' "
+               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
+               SLAP_MR_EQUALITY | SLAP_MR_EXT,
+               NULL, NULL,
+               caseExactMatch, caseExactIgnoreIndexer, caseExactIgnoreFilter,
+               directoryStringApproxMatchOID },
+
+       {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
+               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
+               SLAP_MR_ORDERING,
+               NULL, NULL,
+               caseExactOrderingMatch, NULL, NULL,
+               NULL},
+
+       {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
+               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
+               SLAP_MR_SUBSTR | SLAP_MR_EXT,
+               NULL, NULL,
+               caseExactIgnoreSubstringsMatch,
+               caseExactIgnoreSubstringsIndexer,
+               caseExactIgnoreSubstringsFilter,
+               NULL},
+
+       {"( 2.5.13.8 NAME 'numericStringMatch' "
+               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
+               SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_DN_FOLD,
+               NULL, NULL,
+               caseIgnoreIA5Match,
+               caseIgnoreIA5Indexer,
+               caseIgnoreIA5Filter,
+               NULL},
+
+       {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
+               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
+               SLAP_MR_SUBSTR | SLAP_MR_EXT,
+               NULL, NULL,
+               caseIgnoreIA5SubstringsMatch,
+               caseIgnoreIA5SubstringsIndexer,
+               caseIgnoreIA5SubstringsFilter,
+               NULL},
+
+       {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
+               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )",
+               SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_DN_FOLD,
+               NULL, NULL,
+               caseIgnoreListMatch, NULL, NULL,
+               NULL},
+
+       {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
+               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
+               SLAP_MR_SUBSTR | SLAP_MR_EXT,
+               NULL, NULL,
+               caseIgnoreListSubstringsMatch, NULL, NULL,
+               NULL},
+
+       {"( 2.5.13.13 NAME 'booleanMatch' "
+               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
+               SLAP_MR_EQUALITY | SLAP_MR_EXT,
+               NULL, NULL,
+               booleanMatch, NULL, NULL,
+               NULL},
+
+       {"( 2.5.13.14 NAME 'integerMatch' "
+               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
+               SLAP_MR_EQUALITY | SLAP_MR_EXT,
+               NULL, NULL,
+               integerMatch, integerIndexer, integerFilter,
+               NULL},
+
+       {"( 2.5.13.16 NAME 'bitStringMatch' "
+               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
+               SLAP_MR_EQUALITY | SLAP_MR_EXT,
+               NULL, NULL,
+               bitStringMatch, bitStringIndexer, bitStringFilter,
+               NULL},
+
+       {"( 2.5.13.17 NAME 'octetStringMatch' "
+               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
+               SLAP_MR_EQUALITY | SLAP_MR_EXT,
+               NULL, NULL,
+               octetStringMatch, octetStringIndexer, octetStringFilter,
+               NULL},
+
+       {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
+               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
+               SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_DN_FOLD,
+               NULL, NULL,
+               telephoneNumberMatch,
+               telephoneNumberIndexer,
+               telephoneNumberFilter,
+               NULL},
+
+       {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
+               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
+               SLAP_MR_SUBSTR | SLAP_MR_EXT,
+               NULL, NULL,
+               telephoneNumberSubstringsMatch,
+               telephoneNumberSubstringsIndexer,
+               telephoneNumberSubstringsFilter,
+               NULL},
+
+       {"( 2.5.13.22 NAME 'presentationAddressMatch' "
+               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
+               SLAP_MR_EQUALITY | SLAP_MR_EXT,
+               NULL, NULL,
+               NULL, NULL, NULL,
+               NULL},
+
+       {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
+               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )",
+               SLAP_MR_EQUALITY | SLAP_MR_EXT,
+               NULL, NULL,
+               uniqueMemberMatch, NULL, NULL,
+               NULL},
+
+       {"( 2.5.13.24 NAME 'protocolInformationMatch' "
+               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
+               SLAP_MR_EQUALITY | SLAP_MR_EXT,
+               NULL, NULL,
+               protocolInformationMatch, NULL, NULL,
+               NULL},
+
+       {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
+               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
+               SLAP_MR_EQUALITY | SLAP_MR_EXT,
+               NULL, NULL,
+               generalizedTimeMatch, NULL, NULL,
+               NULL},
+
+       {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
+               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
+               SLAP_MR_ORDERING,
+               NULL, NULL,
+               generalizedTimeOrderingMatch, NULL, NULL,
+               NULL},
+
+       {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
+               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
+               SLAP_MR_EQUALITY | SLAP_MR_EXT,
+               NULL, NULL,
+               integerFirstComponentMatch, NULL, NULL,
+               NULL},
+
+       {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
+               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
+               SLAP_MR_EQUALITY | SLAP_MR_EXT,
+               NULL, NULL,
+               objectIdentifierFirstComponentMatch, NULL, NULL,
+               NULL},
+
+#ifdef HAVE_TLS
+       {"( 2.5.13.34 NAME 'certificateExactMatch' "
+               "SYNTAX 1.2.826.0.1.3344810.7.1 )",
+               SLAP_MR_EQUALITY | SLAP_MR_EXT,
+               certificateExactConvert, NULL,
+               certificateExactMatch,
+               certificateExactIndexer, certificateExactFilter,
+               NULL},
+#endif
+
+       {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
+               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
+               SLAP_MR_EQUALITY | SLAP_MR_EXT,
+               NULL, NULL,
+               caseExactIA5Match, caseExactIA5Indexer, caseExactIA5Filter,
+               IA5StringApproxMatchOID },
+
+       {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
+               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
+               SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_DN_FOLD,
+               NULL, NULL,
+               caseIgnoreIA5Match, caseIgnoreIA5Indexer, caseIgnoreIA5Filter,
+               IA5StringApproxMatchOID },
+
+       {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
+               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
+               SLAP_MR_SUBSTR,
+               NULL, NULL,
+               caseIgnoreIA5SubstringsMatch,
+               caseIgnoreIA5SubstringsIndexer,
+               caseIgnoreIA5SubstringsFilter,
+               NULL},
+
+       {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
+               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
+               SLAP_MR_SUBSTR,
+               NULL, NULL,
+               caseExactIA5SubstringsMatch,
+               caseExactIA5SubstringsIndexer,
+               caseExactIA5SubstringsFilter,
+               NULL},
+
+#ifdef SLAPD_AUTHPASSWD
+       /* needs updating */
+       {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
+               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
+               SLAP_MR_EQUALITY,
+               NULL, NULL,
+               authPasswordMatch, NULL, NULL,
+               NULL},
+#endif
+
+#ifdef SLAPD_ACI_ENABLED
+       {"( 1.3.6.1.4.1.4203.666.4.2 NAME 'OpenLDAPaciMatch' "
+               "SYNTAX 1.3.6.1.4.1.4203.666.2.1 )",
+               SLAP_MR_EQUALITY,
+               NULL, NULL,
+               OpenLDAPaciMatch, NULL, NULL,
+               NULL},
+#endif
+
+       {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
+               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
+               SLAP_MR_EXT,
+               NULL, NULL,
+               integerBitAndMatch, NULL, NULL,
+               NULL},
+
+       {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
+               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
+               SLAP_MR_EXT,
+               NULL, NULL,
+               integerBitOrMatch, NULL, NULL,
+               NULL},
+
+       {NULL, SLAP_MR_NONE, NULL, NULL, NULL, NULL}
+};
+
+int
+slap_schema_init( void )
+{
+       int             res;
+       int             i;
+
+       /* we should only be called once (from main) */
+       assert( schema_init_done == 0 );
+
+       for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
+               res = register_syntax( syntax_defs[i].sd_desc,
+                       syntax_defs[i].sd_flags,
+                       syntax_defs[i].sd_validate,
+                       syntax_defs[i].sd_normalize,
+                       syntax_defs[i].sd_pretty
+#ifdef SLAPD_BINARY_CONVERSION
+                       ,
+                       syntax_defs[i].sd_ber2str,
+                       syntax_defs[i].sd_str2ber
+#endif
+               );
+
+               if ( res ) {
+                       fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
+                                syntax_defs[i].sd_desc );
+                       return LDAP_OTHER;
+               }
+       }
+
+       for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
+               if( mrule_defs[i].mrd_usage == SLAP_MR_NONE ) {
+                       fprintf( stderr,
+                               "slap_schema_init: Ingoring unusable matching rule %s\n",
+                                mrule_defs[i].mrd_desc );
+                       continue;
+               }
+
+               res = register_matching_rule(
+                       mrule_defs[i].mrd_desc,
+                       mrule_defs[i].mrd_usage,
+                       mrule_defs[i].mrd_convert,
+                       mrule_defs[i].mrd_normalize,
+                       mrule_defs[i].mrd_match,
+                       mrule_defs[i].mrd_indexer,
+                       mrule_defs[i].mrd_filter,
+                       mrule_defs[i].mrd_associated );
+
+               if ( res ) {
+                       fprintf( stderr,
+                               "slap_schema_init: Error registering matching rule %s\n",
+                                mrule_defs[i].mrd_desc );
+                       return LDAP_OTHER;
+               }
+       }
+
+       res = slap_schema_load();
+       schema_init_done = 1;
+       return res;
+}
+
+void
+schema_destroy( void )
+{
+       oidm_destroy();
+       oc_destroy();
+       at_destroy();
+       mr_destroy();
+       syn_destroy();
+}
diff --git a/servers/slapd/schema_prep.c b/servers/slapd/schema_prep.c
new file mode 100644 (file)
index 0000000..1626244
--- /dev/null
@@ -0,0 +1,981 @@
+/* schema_init.c - init builtin schema */
+/* $OpenLDAP$ */
+/*
+ * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/ctype.h>
+#include <ac/string.h>
+#include <ac/socket.h>
+
+#include "slap.h"
+#include "ldap_pvt.h"
+#include "ldap_pvt_uc.h"
+
+int schema_init_done = 0;
+
+struct slap_internal_schema slap_schema;
+
+static int
+objectClassMatch(
+       int *matchp,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *value,
+       void *assertedValue )
+{
+       struct berval *a = (struct berval *) assertedValue;
+       ObjectClass *oc = oc_bvfind( value );
+       ObjectClass *asserted = oc_bvfind( a );
+
+#if 1
+#ifdef NEW_LOGGING
+       LDAP_LOG(( "schema", LDAP_LEVEL_ENTRY,
+                  "> objectClassMatch(%s, %s)\n",
+                  value->bv_val, a->bv_val ));
+#else
+       Debug( LDAP_DEBUG_TRACE, "> objectClassMatch(%s,%s)\n",
+               value->bv_val, a->bv_val, 0 );
+#endif
+#endif
+
+       if( asserted == NULL ) {
+               if( OID_LEADCHAR( *a->bv_val ) ) {
+                       /* OID form, return FALSE */
+                       *matchp = 1;
+                       return LDAP_SUCCESS;
+               }
+
+               /* desc form, return undefined */
+               return SLAPD_COMPARE_UNDEFINED;
+       }
+
+       if ( oc == NULL ) {
+               /* unrecognized stored value */
+               return SLAPD_COMPARE_UNDEFINED;
+       }
+
+       if( SLAP_IS_MR_VALUE_SYNTAX_MATCH( flags ) ) {
+               *matchp = ( asserted != oc );
+       } else {
+               *matchp = !is_object_subclass( asserted, oc );
+       }
+
+#if 1
+#ifdef NEW_LOGGING
+       LDAP_LOG(( "schema", LDAP_LEVEL_ENTRY,
+                  "< objectClassMatch(%s, %s) = %d\n",
+                  value->bv_val, a->bv_val, *matchp ));
+#else
+       Debug( LDAP_DEBUG_TRACE, "< objectClassMatch(%s,%s) = %d\n",
+               value->bv_val, a->bv_val, *matchp );
+#endif
+#endif
+
+       return LDAP_SUCCESS;
+}
+
+#if 1
+#define structuralObjectClassMatch objectClassMatch
+#else
+static int
+structuralObjectClassMatch(
+       int *matchp,
+       slap_mask_t flags,
+       Syntax *syntax,
+       MatchingRule *mr,
+       struct berval *value,
+       void *assertedValue )
+{
+       struct berval *a = (struct berval *) assertedValue;
+       ObjectClass *oc = oc_bvfind( value );
+       ObjectClass *asserted = oc_bvfind( a );
+
+#if 1
+#ifdef NEW_LOGGING
+       LDAP_LOG(( "schema", LDAP_LEVEL_ENTRY,
+                  "> structuralObjectClassMatch(%s, %s)\n",
+                  value->bv_val, a->bv_val ));
+#else
+       Debug( LDAP_DEBUG_TRACE, "> structuralObjectClassMatch(%s,%s)\n",
+               value->bv_val, a->bv_val, 0 );
+#endif
+#endif
+
+       if( asserted == NULL ) {
+               if( OID_LEADCHAR( *a->bv_val ) ) {
+                       /* OID form, return FALSE */
+                       *matchp = 1;
+                       return LDAP_SUCCESS;
+               }
+
+               /* desc form, return undefined */
+               return SLAPD_COMPARE_UNDEFINED;
+       }
+
+       if ( oc == NULL ) {
+               /* unrecognized stored value */
+               return SLAPD_COMPARE_UNDEFINED;
+       }
+
+       *matchp = ( asserted != oc );
+
+#if 1
+#ifdef NEW_LOGGING
+       LDAP_LOG(( "schema", LDAP_LEVEL_ENTRY,
+                  "< structuralObjectClassMatch( %s, %s ) = %d\n",
+                  value->bv_val, a->bv_val, *matchp ));
+#else
+       Debug( LDAP_DEBUG_TRACE, "< structuralObjectClassMatch(%s,%s) = %d\n",
+               value->bv_val, a->bv_val, *matchp );
+#endif
+#endif
+
+       return LDAP_SUCCESS;
+}
+#endif
+
+static ObjectClassSchemaCheckFN rootDseObjectClass;
+static ObjectClassSchemaCheckFN aliasObjectClass;
+static ObjectClassSchemaCheckFN referralObjectClass;
+static ObjectClassSchemaCheckFN subentryObjectClass;
+static ObjectClassSchemaCheckFN dynamicObjectClass;
+
+static struct slap_schema_oc_map {
+       char *ssom_name;
+       char *ssom_defn;
+       ObjectClassSchemaCheckFN *ssom_check;
+       slap_mask_t ssom_flags;
+       size_t ssom_offset;
+} oc_map[] = {
+       { "top", "( 2.5.6.0 NAME 'top' "
+                       "DESC 'top of the superclass chain' "
+                       "ABSTRACT MUST objectClass )",
+               0, 0, offsetof(struct slap_internal_schema, si_oc_top) },
+       { "extensibleObject", "( 1.3.6.1.4.1.1466.101.120.111 "
+                       "NAME 'extensibleObject' "
+                       "DESC 'RFC2252: extensible object' "
+                       "SUP top AUXILIARY )",
+               0, 0, offsetof(struct slap_internal_schema, si_oc_extensibleObject) },
+       { "alias", "( 2.5.6.1 NAME 'alias' "
+                       "DESC 'RFC2256: an alias' "
+                       "SUP top STRUCTURAL "
+                       "MUST aliasedObjectName )",
+               aliasObjectClass, SLAP_OC_ALIAS,
+               offsetof(struct slap_internal_schema, si_oc_alias) },
+       { "referral", "( 2.16.840.1.113730.3.2.6 NAME 'referral' "
+                       "DESC 'namedref: named subordinate referral' "
+                       "SUP top STRUCTURAL MUST ref )",
+               referralObjectClass, SLAP_OC_REFERRAL,
+               offsetof(struct slap_internal_schema, si_oc_referral) },
+       { "LDAProotDSE", "( 1.3.6.1.4.1.4203.1.4.1 "
+                       "NAME ( 'OpenLDAProotDSE' 'LDAProotDSE' ) "
+                       "DESC 'OpenLDAP Root DSE object' "
+                       "SUP top STRUCTURAL MAY cn )",
+               rootDseObjectClass, 0,
+               offsetof(struct slap_internal_schema, si_oc_rootdse) },
+       { "subentry", "( 2.5.20.0 NAME 'subentry' "
+                       "SUP top STRUCTURAL "
+                       "MUST ( cn $ subtreeSpecification ) )",
+               subentryObjectClass, SLAP_OC_SUBENTRY,
+               offsetof(struct slap_internal_schema, si_oc_subentry) },
+       { "subschema", "( 2.5.20.1 NAME 'subschema' "
+               "DESC 'RFC2252: controlling subschema (sub)entry' "
+               "AUXILIARY "
+               "MAY ( dITStructureRules $ nameForms $ ditContentRules $ "
+                       "objectClasses $ attributeTypes $ matchingRules $ "
+                       "matchingRuleUse ) )",
+               subentryObjectClass, 0,
+               offsetof(struct slap_internal_schema, si_oc_subschema) },
+       { "monitor", "( 1.3.6.1.4.1.4203.666.3.2 NAME 'monitor' "
+               "DESC 'OpenLDAP system monitoring' "
+               "STRUCTURAL "
+               "MUST cn )",
+               0, 0, offsetof(struct slap_internal_schema, si_oc_monitor) },
+       { NULL, NULL, NULL, 0, 0 }
+};
+
+static AttributeTypeSchemaCheckFN rootDseAttribute;
+static AttributeTypeSchemaCheckFN aliasAttribute;
+static AttributeTypeSchemaCheckFN referralAttribute;
+static AttributeTypeSchemaCheckFN subentryAttribute;
+static AttributeTypeSchemaCheckFN administrativeRoleAttribute;
+static AttributeTypeSchemaCheckFN dynamicAttribute;
+
+static struct slap_schema_ad_map {
+       char *ssam_name;
+       char *ssam_defn;
+       AttributeTypeSchemaCheckFN *ssam_check;
+       slap_mask_t ssam_flags;
+       slap_mr_match_func *ssam_match;
+       slap_mr_indexer_func *ssam_indexer;
+       slap_mr_filter_func *ssam_filter;
+       size_t ssam_offset;
+} ad_map[] = {
+       { "objectClass", "( 2.5.4.0 NAME 'objectClass' "
+                       "DESC 'RFC2256: object classes of the entity' "
+                       "EQUALITY objectIdentifierMatch "
+                       "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
+               NULL, 0, objectClassMatch, NULL, NULL,
+               offsetof(struct slap_internal_schema, si_ad_objectClass) },
+
+       /* user entry operational attributes */
+       { "structuralObjectClass", "( 2.5.21.9 NAME 'structuralObjectClass' "
+                       "DESC 'X.500(93): structural object class of entry' "
+                       "EQUALITY objectIdentifierMatch "
+                       "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 "
+                       "NO-USER-MODIFICATION SINGLE-VALUE USAGE directoryOperation )",
+               NULL, 0, structuralObjectClassMatch, NULL, NULL,
+               offsetof(struct slap_internal_schema, si_ad_structuralObjectClass) },
+       { "createTimestamp", "( 2.5.18.1 NAME 'createTimestamp' "
+                       "DESC 'RFC2252: time which object was created' "
+                       "EQUALITY generalizedTimeMatch "
+                       "ORDERING generalizedTimeOrderingMatch "
+                       "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
+                       "SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )",
+               NULL, 0, NULL, NULL, NULL,
+               offsetof(struct slap_internal_schema, si_ad_createTimestamp) },
+       { "modifyTimestamp", "( 2.5.18.2 NAME 'modifyTimestamp' "
+                       "DESC 'RFC2252: time which object was last modified' "
+                       "EQUALITY generalizedTimeMatch "
+                       "ORDERING generalizedTimeOrderingMatch "
+                       "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
+                       "SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )",
+               NULL, 0, NULL, NULL, NULL,
+               offsetof(struct slap_internal_schema, si_ad_modifyTimestamp) },
+       { "creatorsName", "( 2.5.18.3 NAME 'creatorsName' "
+                       "DESC 'RFC2252: name of creator' "
+                       "EQUALITY distinguishedNameMatch "
+                       "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 "
+                       "SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )",
+               NULL, 0, NULL, NULL, NULL,
+               offsetof(struct slap_internal_schema, si_ad_creatorsName) },
+       { "modifiersName", "( 2.5.18.4 NAME 'modifiersName' "
+                       "DESC 'RFC2252: name of last modifier' "
+                       "EQUALITY distinguishedNameMatch "
+                       "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 "
+                       "SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )",
+               NULL, 0, NULL, NULL, NULL,
+               offsetof(struct slap_internal_schema, si_ad_modifiersName) },
+       { "hasSubordinates", "( 2.5.18.9 NAME 'hasSubordinates' "
+                       "DESC 'X.501: entry has children' "
+                       "EQUALITY booleanMatch "
+                       "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 "
+                       "SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )",
+               NULL, 0, NULL, NULL, NULL,
+               offsetof(struct slap_internal_schema, si_ad_hasSubordinates) },
+       { "subschemaSubentry", "( 2.5.18.10 NAME 'subschemaSubentry' "
+                       "DESC 'RFC2252: name of controlling subschema entry' "
+                       "EQUALITY distinguishedNameMatch "
+                       "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 NO-USER-MODIFICATION "
+                       "SINGLE-VALUE USAGE directoryOperation )",
+               NULL, 0, NULL, NULL, NULL,
+               offsetof(struct slap_internal_schema, si_ad_subschemaSubentry) },
+
+       /* root DSE attributes */
+       { "altServer", "( 1.3.6.1.4.1.1466.101.120.6 NAME 'altServer' "
+                       "DESC 'RFC2252: alternative servers' "
+                       "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 USAGE dSAOperation )",
+               rootDseAttribute, 0, NULL, NULL, NULL,
+               offsetof(struct slap_internal_schema, si_ad_altServer) },
+       { "namingContexts", "( 1.3.6.1.4.1.1466.101.120.5 "
+                       "NAME 'namingContexts' "
+                       "DESC 'RFC2252: naming contexts' "
+                       "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 USAGE dSAOperation )",
+               rootDseAttribute, 0, NULL, NULL, NULL,
+               offsetof(struct slap_internal_schema, si_ad_namingContexts) },
+       { "supportedControl", "( 1.3.6.1.4.1.1466.101.120.13 "
+                       "NAME 'supportedControl' "
+                  "DESC 'RFC2252: supported controls' "
+                  "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 USAGE dSAOperation )",
+               rootDseAttribute, 0, NULL, NULL, NULL,
+               offsetof(struct slap_internal_schema, si_ad_supportedControl) },
+       { "supportedExtension", "( 1.3.6.1.4.1.1466.101.120.7 "
+                       "NAME 'supportedExtension' "
+                       "DESC 'RFC2252: supported extended operations' "
+                       "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 USAGE dSAOperation )",
+               rootDseAttribute, 0, NULL, NULL, NULL,
+               offsetof(struct slap_internal_schema, si_ad_supportedExtension) },
+       { "supportedLDAPVersion", "( 1.3.6.1.4.1.1466.101.120.15 "
+                       "NAME 'supportedLDAPVersion' "
+                       "DESC 'RFC2252: supported LDAP versions' "
+                       "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 USAGE dSAOperation )",
+               rootDseAttribute, 0, NULL, NULL, NULL,
+               offsetof(struct slap_internal_schema, si_ad_supportedLDAPVersion) },
+       { "supportedSASLMechanisms", "( 1.3.6.1.4.1.1466.101.120.14 "
+                       "NAME 'supportedSASLMechanisms' "
+                       "DESC 'RFC2252: supported SASL mechanisms'"
+                       "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 USAGE dSAOperation )",
+               rootDseAttribute, 0, NULL, NULL, NULL,
+               offsetof(struct slap_internal_schema, si_ad_supportedSASLMechanisms) },
+       { "supportedFeatures", "( 1.3.6.1.4.1.4203.1.3.5 "
+                       "NAME 'supportedFeatures' "
+                       "DESC 'features supported by the server' "
+                       "EQUALITY objectIdentifierMatch "
+                       "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 "
+                       "USAGE dSAOperation )",
+               rootDseAttribute, 0, NULL, NULL, NULL,
+               offsetof(struct slap_internal_schema, si_ad_supportedFeatures) },
+       { "vendorName", "( 1.3.6.1.1.4 NAME 'vendorName' "
+                       "DESC 'RFC3045: name of implementation vendor' "
+                       "EQUALITY 1.3.6.1.4.1.1466.109.114.1 "
+                       "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 "
+                       "SINGLE-VALUE NO-USER-MODIFICATION "
+                       "USAGE dSAOperation )",
+               rootDseAttribute, 0, NULL, NULL, NULL,
+               offsetof(struct slap_internal_schema, si_ad_vendorName) },
+       { "vendorVersion", "( 1.3.6.1.1.5 NAME 'vendorVersion' "
+                       "DESC 'RFC3045: version of implementation' "
+                       "EQUALITY 1.3.6.1.4.1.1466.109.114.1 "
+                       "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 "
+                       "SINGLE-VALUE NO-USER-MODIFICATION "
+                       "USAGE dSAOperation )",
+               rootDseAttribute, 0, NULL, NULL, NULL,
+               offsetof(struct slap_internal_schema, si_ad_vendorVersion) },
+
+       /* subentry attributes */
+       { "administrativeRole", "( 2.5.18.5 NAME 'administrativeRole' "
+                       "EQUALITY objectIdentifierMatch "
+                       "USAGE directoryOperation "
+                       "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
+               administrativeRoleAttribute, 0, NULL, NULL, NULL,
+               offsetof(struct slap_internal_schema, si_ad_administrativeRole) },
+       { "subtreeSpecification", "( 2.5.18.6 NAME 'subtreeSpecification' "
+                       "SINGLE-VALUE "
+                       "USAGE directoryOperation "
+                       "SYNTAX 1.3.6.1.4.1.1466.115.121.1.45 )",
+               subentryAttribute, 0, NULL, NULL, NULL,
+               offsetof(struct slap_internal_schema, si_ad_subtreeSpecification) },
+
+       /* subschema subentry attributes */
+       { "ditStructureRules", "( 2.5.21.1 NAME 'dITStructureRules' "
+                       "DESC 'RFC2252: DIT structure rules' "
+                       "EQUALITY integerFirstComponentMatch "
+                       "SYNTAX 1.3.6.1.4.1.1466.115.121.1.17 "
+                       "USAGE directoryOperation ) ",
+               subentryAttribute, 0, NULL, NULL, NULL,
+               offsetof(struct slap_internal_schema, si_ad_ditStructureRules) },
+       { "ditContentRules", "( 2.5.21.2 NAME 'dITContentRules' "
+                       "DESC 'RFC2252: DIT content rules' "
+                       "EQUALITY objectIdentifierFirstComponentMatch "
+                       "SYNTAX 1.3.6.1.4.1.1466.115.121.1.16 USAGE directoryOperation )",
+               subentryAttribute, 0, NULL, NULL, NULL,
+               offsetof(struct slap_internal_schema, si_ad_ditContentRules) },
+       { "matchingRules", "( 2.5.21.4 NAME 'matchingRules' "
+                       "DESC 'RFC2252: matching rules' "
+                       "EQUALITY objectIdentifierFirstComponentMatch "
+                       "SYNTAX 1.3.6.1.4.1.1466.115.121.1.30 USAGE directoryOperation )",
+               subentryAttribute, 0, NULL, NULL, NULL,
+               offsetof(struct slap_internal_schema, si_ad_matchingRules) },
+       { "attributeTypes", "( 2.5.21.5 NAME 'attributeTypes' "
+                       "DESC 'RFC2252: attribute types' "
+                       "EQUALITY objectIdentifierFirstComponentMatch "
+                       "SYNTAX 1.3.6.1.4.1.1466.115.121.1.3 USAGE directoryOperation )",
+               subentryAttribute, 0, NULL, NULL, NULL,
+               offsetof(struct slap_internal_schema, si_ad_attributeTypes) },
+       { "objectClasses", "( 2.5.21.6 NAME 'objectClasses' "
+                       "DESC 'RFC2252: object classes' "
+                       "EQUALITY objectIdentifierFirstComponentMatch "
+                       "SYNTAX 1.3.6.1.4.1.1466.115.121.1.37 USAGE directoryOperation )",
+               subentryAttribute, 0, NULL, NULL, NULL,
+               offsetof(struct slap_internal_schema, si_ad_objectClasses) },
+       { "nameForms", "( 2.5.21.7 NAME 'nameForms' "
+                       "DESC 'RFC2252: name forms ' "
+                       "EQUALITY objectIdentifierFirstComponentMatch "
+                       "SYNTAX 1.3.6.1.4.1.1466.115.121.1.35 USAGE directoryOperation )",
+               subentryAttribute, 0, NULL, NULL, NULL,
+               offsetof(struct slap_internal_schema, si_ad_nameForms) },
+       { "matchingRuleUse", "( 2.5.21.8 NAME 'matchingRuleUse' "
+                       "DESC 'RFC2252: matching rule uses' "
+                       "EQUALITY objectIdentifierFirstComponentMatch "
+                       "SYNTAX 1.3.6.1.4.1.1466.115.121.1.31 USAGE directoryOperation )",
+               subentryAttribute, 0, NULL, NULL, NULL,
+               offsetof(struct slap_internal_schema, si_ad_matchingRuleUse) },
+
+       { "ldapSyntaxes", "( 1.3.6.1.4.1.1466.101.120.16 NAME 'ldapSyntaxes' "
+                       "DESC 'RFC2252: LDAP syntaxes' "
+                       "EQUALITY objectIdentifierFirstComponentMatch "
+                       "SYNTAX 1.3.6.1.4.1.1466.115.121.1.54 USAGE directoryOperation )",
+               subentryAttribute, 0, NULL, NULL, NULL,
+               offsetof(struct slap_internal_schema, si_ad_ldapSyntaxes) },
+
+       /* knowledge information */
+       { "aliasedObjectName", "( 2.5.4.1 "
+                       "NAME ( 'aliasedObjectName' 'aliasedEntryName' ) "
+                       "DESC 'RFC2256: name of aliased object' "
+                       "EQUALITY distinguishedNameMatch "
+                       "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE )",
+               aliasAttribute, 0, NULL, NULL, NULL,
+               offsetof(struct slap_internal_schema, si_ad_aliasedObjectName) },
+       { "ref", "( 2.16.840.1.113730.3.1.34 NAME 'ref' "
+                       "DESC 'namedref: subordinate referral URL' "
+                       "EQUALITY caseExactMatch "
+                       "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 "
+                       "USAGE distributedOperation )",
+               referralAttribute, 0, NULL, NULL, NULL,
+               offsetof(struct slap_internal_schema, si_ad_ref) },
+
+       /* access control internals */
+       { "entry", "( 1.3.6.1.4.1.4203.1.3.1 "
+                       "NAME 'entry' "
+                       "DESC 'OpenLDAP ACL entry pseudo-attribute' "
+                       "SYNTAX 1.3.6.1.4.1.4203.1.1.1 "
+                       "SINGLE-VALUE NO-USER-MODIFICATION USAGE dSAOperation )",
+               NULL, 0, NULL, NULL, NULL,
+               offsetof(struct slap_internal_schema, si_ad_entry) },
+       { "children", "( 1.3.6.1.4.1.4203.1.3.2 "
+                       "NAME 'children' "
+                       "DESC 'OpenLDAP ACL children pseudo-attribute' "
+                       "SYNTAX 1.3.6.1.4.1.4203.1.1.1 "
+                       "SINGLE-VALUE NO-USER-MODIFICATION USAGE dSAOperation )",
+               NULL, 0, NULL, NULL, NULL,
+               offsetof(struct slap_internal_schema, si_ad_children) },
+
+#ifdef SLAPD_ACI_ENABLED
+       { "OpenLDAPaci", "( 1.3.6.1.4.1.4203.666.1.5 "
+                       "NAME 'OpenLDAPaci' "
+                       "DESC 'OpenLDAP access control information (experimental)' "
+                       "EQUALITY OpenLDAPaciMatch "
+                       "SYNTAX 1.3.6.1.4.1.4203.666.2.1 "
+                       "USAGE directoryOperation )",
+               NULL, 0, NULL, NULL, NULL,
+               offsetof(struct slap_internal_schema, si_ad_aci) },
+#endif
+
+       { "entryTtl", "( 1.3.6.1.4.1.1466.101.119.3 NAME 'entryTtl' "
+                       "DESC 'RFC2589: entry time-to-live' "
+                       "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE "
+                       "NO-USER-MODIFICATION USAGE dSAOperation )",
+               dynamicAttribute, 0, NULL, NULL, NULL,
+               offsetof(struct slap_internal_schema, si_ad_entryTtl) },
+       { "dynamicSubtrees", "( 1.3.6.1.4.1.1466.101.119.4 "
+                       "NAME 'dynamicSubtrees' "
+                       "DESC 'RFC2589: dynamic subtrees' "
+                       "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 NO-USER-MODIFICATION "
+                       "USAGE dSAOperation )",
+               rootDseAttribute, 0, NULL, NULL, NULL,
+               offsetof(struct slap_internal_schema, si_ad_dynamicSubtrees) },
+
+       /* userApplication attributes (which system schema depends upon) */
+       { "distinguishedName", "( 2.5.4.49 NAME 'distinguishedName' "
+                       "DESC 'RFC2256: common supertype of DN attributes' "
+                       "EQUALITY distinguishedNameMatch "
+                       "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
+               NULL, 0, NULL, NULL, NULL,
+               offsetof(struct slap_internal_schema, si_ad_distinguishedName) },
+       { "name", "( 2.5.4.41 NAME 'name' "
+                       "DESC 'RFC2256: common supertype of name attributes' "
+                       "EQUALITY caseIgnoreMatch "
+                       "SUBSTR caseIgnoreSubstringsMatch "
+                       "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32768} )",
+               NULL, 0, NULL, NULL, NULL,
+               offsetof(struct slap_internal_schema, si_ad_name) },
+       { "cn", "( 2.5.4.3 NAME ( 'cn' 'commonName' ) "
+                       "DESC 'RFC2256: common name(s) for which the entity is known by' "
+                       "SUP name )",
+               NULL, 0, NULL, NULL, NULL,
+               offsetof(struct slap_internal_schema, si_ad_cn) },
+       { "userPassword", "( 2.5.4.35 NAME 'userPassword' "
+                       "DESC 'RFC2256/2307: password of user' "
+                       "EQUALITY octetStringMatch "
+                       "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40{128} )",
+               NULL, 0, NULL, NULL, NULL,
+               offsetof(struct slap_internal_schema, si_ad_userPassword) },
+
+#ifdef SLAPD_AUTHPASSWD
+       { "authPassword", "( 1.3.6.1.4.1.4203.1.3.4 "
+                       "NAME 'authPassword' "
+                       "DESC 'RFC3112: authentication password attribute' "
+                       "EQUALITY 1.3.6.1.4.1.4203.1.2.2 "
+                       "SYNTAX 1.3.6.1.4.1.4203.1.1.2 )",
+               NULL, 0,
+               NULL, NULL, NULL,
+               offsetof(struct slap_internal_schema, si_ad_authPassword) },
+       { "supportedAuthPasswordSchemes", "( 1.3.6.1.4.1.4203.1.3.3 "
+                       "NAME 'supportedAuthPasswordSchemes' "
+                       "DESC 'RFC3112: supported authPassword schemes' "
+                       "EQUALITY caseExactIA5Match "
+                       "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} "
+                       "USAGE dSAOperation )",
+               subschemaAttribute, 0, NULL, NULL, NULL,
+               offsetof(struct slap_internal_schema, si_ad_authPassword) },
+#endif
+#ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
+       { "krbName", NULL,
+               NULL, 0, NULL, NULL, NULL,
+               offsetof(struct slap_internal_schema, si_ad_krbName) },
+#endif
+
+       { NULL, NULL, NULL, 0, NULL, NULL, NULL, 0 }
+};
+
+static AttributeType slap_at_undefined = {
+       { "1.1.1", NULL, NULL, 1, NULL,
+               NULL, NULL, NULL, NULL,
+               0, 0, 0, 1, 3 }, /* LDAPAttributeType */
+       { sizeof("UNDEFINED")-1, "UNDEFINED" }, /* cname */
+       NULL, /* sup */
+       NULL, /* subtypes */
+       NULL, NULL, NULL, NULL, /* matching rules */
+       NULL, /* syntax (this may need to be defined) */
+       (AttributeTypeSchemaCheckFN *) 0, 0, /* schema check function/mask */
+       NULL, /* next */
+       NULL /* attribute description */
+       /* mutex (don't know how to initialize it :) */
+};
+
+static struct slap_schema_mr_map {
+       char *ssmm_name;
+       size_t ssmm_offset;
+} mr_map[] = {
+       { "distinguishedNameMatch",
+               offsetof(struct slap_internal_schema, si_mr_distinguishedNameMatch) },
+       { "integerMatch",
+               offsetof(struct slap_internal_schema, si_mr_integerMatch) },
+       { NULL, 0 }
+};
+
+static struct slap_schema_syn_map {
+       char *sssm_name;
+       size_t sssm_offset;
+} syn_map[] = {
+       { "1.3.6.1.4.1.1466.115.121.1.12",
+               offsetof(struct slap_internal_schema, si_syn_distinguishedName) },
+       { "1.3.6.1.4.1.1466.115.121.1.27",
+               offsetof(struct slap_internal_schema, si_syn_integer) },
+       { NULL, 0 }
+};
+
+int
+slap_schema_load( void )
+{
+       int i;
+       for( i=0; ad_map[i].ssam_name; i++ ) {
+               if( ad_map[i].ssam_defn != NULL ) {
+                       LDAPAttributeType *at;
+                       int             code;
+                       const char      *err;
+
+                       at = ldap_str2attributetype( ad_map[i].ssam_defn,
+                               &code, &err, LDAP_SCHEMA_ALLOW_ALL );
+                       if ( !at ) {
+                               fprintf( stderr,
+                                       "slap_schema_load: %s: %s before %s\n",
+                                        ad_map[i].ssam_name, ldap_scherr2str(code), err );
+                               return code;
+                       }
+
+                       if ( at->at_oid == NULL ) {
+                               fprintf( stderr, "slap_schema_load: "
+                                       "attributeType \"%s\" has no OID\n",
+                                       ad_map[i].ssam_name );
+                               return LDAP_OTHER;
+                       }
+
+                       code = at_add( at, &err );
+                       if ( code ) {
+                               fprintf( stderr, "slap_schema_load: "
+                                       "%s: %s: \"%s\"\n",
+                                        ad_map[i].ssam_name, scherr2str(code), err );
+                               return code;
+                       }
+                       ldap_memfree( at );
+               }
+       }
+
+       for( i=0; oc_map[i].ssom_name; i++ ) {
+               if( oc_map[i].ssom_defn != NULL ) {
+                       LDAPObjectClass *oc;
+                       int             code;
+                       const char      *err;
+
+                       oc = ldap_str2objectclass( oc_map[i].ssom_defn, &code, &err,
+                               LDAP_SCHEMA_ALLOW_ALL );
+                       if ( !oc ) {
+                               fprintf( stderr, "slap_schema_load: "
+                                       "%s: %s before %s\n",
+                                       oc_map[i].ssom_name, ldap_scherr2str(code), err );
+                               return code;
+                       }
+
+                       if ( oc->oc_oid == NULL ) {
+                               fprintf( stderr, "slap_schema_load: "
+                                       "%s: objectclass has no OID\n",
+                                       oc_map[i].ssom_name );
+                               return LDAP_OTHER;
+                       }
+
+                       code = oc_add(oc,&err);
+                       if ( code ) {
+                               fprintf( stderr, "slap_schema_load: "
+                                       "%s: %s: \"%s\"\n",
+                                       oc_map[i].ssom_name, scherr2str(code), err);
+                               return code;
+                       }
+
+                       ldap_memfree(oc);
+               }
+       }
+
+       return LDAP_SUCCESS;
+}
+
+int
+slap_schema_check( void )
+{
+       int i;
+       /* we should only be called once after schema_init() was called */
+       assert( schema_init_done == 1 );
+
+       for( i=0; syn_map[i].sssm_name; i++ ) {
+               Syntax ** synp = (Syntax **)
+                       &(((char *) &slap_schema)[syn_map[i].sssm_offset]);
+
+               assert( *synp == NULL );
+
+               *synp = syn_find( syn_map[i].sssm_name );
+
+               if( *synp == NULL ) {
+                       fprintf( stderr, "slap_schema_check: "
+                               "No syntax \"%s\" defined in schema\n",
+                               syn_map[i].sssm_name );
+                       return LDAP_INVALID_SYNTAX;
+               }
+       }
+
+       for( i=0; mr_map[i].ssmm_name; i++ ) {
+               MatchingRule ** mrp = (MatchingRule **)
+                       &(((char *) &slap_schema)[mr_map[i].ssmm_offset]);
+
+               assert( *mrp == NULL );
+
+               *mrp = mr_find( mr_map[i].ssmm_name );
+
+               if( *mrp == NULL ) {
+                       fprintf( stderr, "slap_schema_check: "
+                               "No matching rule \"%s\" defined in schema\n",
+                               mr_map[i].ssmm_name );
+                       return LDAP_INAPPROPRIATE_MATCHING;
+               }
+       }
+
+       slap_at_undefined.sat_syntax = syn_find( SLAPD_OCTETSTRING_SYNTAX );
+       if( slap_at_undefined.sat_syntax == NULL ) {
+               fprintf( stderr, "slap_schema_check: "
+                       "No octetString syntax \"" SLAPD_OCTETSTRING_SYNTAX "\"\n" );
+               return LDAP_INVALID_SYNTAX;
+       }
+       slap_schema.si_at_undefined = &slap_at_undefined;
+
+       for( i=0; ad_map[i].ssam_name; i++ ) {
+               int rc;
+               const char *text;
+
+               AttributeDescription ** adp = (AttributeDescription **)
+                       &(((char *) &slap_schema)[ad_map[i].ssam_offset]);
+
+               assert( *adp == NULL );
+
+               rc = slap_str2ad( ad_map[i].ssam_name, adp, &text );
+               if( rc != LDAP_SUCCESS ) {
+                       fprintf( stderr, "slap_schema_check: "
+                               "No attribute \"%s\" defined in schema\n",
+                               ad_map[i].ssam_name );
+                       return rc;
+               }
+
+               if( ad_map[i].ssam_check ) {
+                       /* install check routine */
+                       (*adp)->ad_type->sat_check = ad_map[i].ssam_check;
+               }
+               /* install flags */
+               (*adp)->ad_type->sat_flags |= ad_map[i].ssam_flags;
+
+               if( ad_map[i].ssam_match ) {
+                       /* install custom matching routine */
+                       (*adp)->ad_type->sat_equality->smr_match = ad_map[i].ssam_match;
+               }
+       }
+
+       for( i=0; oc_map[i].ssom_name; i++ ) {
+               ObjectClass ** ocp = (ObjectClass **)
+                       &(((char *) &slap_schema)[oc_map[i].ssom_offset]);
+
+               assert( *ocp == NULL );
+
+               *ocp = oc_find( oc_map[i].ssom_name );
+               if( *ocp == NULL ) {
+                       fprintf( stderr, "slap_schema_check: "
+                               "No objectClass \"%s\" defined in schema\n",
+                               oc_map[i].ssom_name );
+                       return LDAP_OBJECT_CLASS_VIOLATION;
+               }
+
+               if( oc_map[i].ssom_check ) {
+                       /* install check routine */
+                       (*ocp)->soc_check = oc_map[i].ssom_check;
+               }
+               /* install flags */
+               (*ocp)->soc_flags |= oc_map[i].ssom_flags;
+       }
+
+       ++schema_init_done;
+       return LDAP_SUCCESS;
+}
+
+static int rootDseObjectClass (
+       Backend *be,
+       Entry *e,
+       ObjectClass *oc,
+       const char** text,
+       char *textbuf, size_t textlen )
+{
+       *text = textbuf;
+
+       if( e->e_nname.bv_len ) {
+               snprintf( textbuf, textlen,
+                       "objectClass \"%s\" only allowed in the root DSE",
+                       oc->soc_oid );
+               return LDAP_OBJECT_CLASS_VIOLATION;
+       }
+
+       /* we should not be called for the root DSE */
+       assert( 0 );
+       return LDAP_SUCCESS;
+}
+
+static int aliasObjectClass (
+       Backend *be,
+       Entry *e,
+       ObjectClass *oc,
+       const char** text,
+       char *textbuf, size_t textlen )
+{
+       *text = textbuf;
+
+       if( !SLAP_ALIASES(be) ) {
+               snprintf( textbuf, textlen,
+                       "objectClass \"%s\" not supported in context",
+                       oc->soc_oid );
+               return LDAP_OBJECT_CLASS_VIOLATION;
+       }
+
+       return LDAP_SUCCESS;
+}
+
+static int referralObjectClass (
+       Backend *be,
+       Entry *e,
+       ObjectClass *oc,
+       const char** text,
+       char *textbuf, size_t textlen )
+{
+       *text = textbuf;
+
+       if( !SLAP_REFERRALS(be) ) {
+               snprintf( textbuf, textlen,
+                       "objectClass \"%s\" not supported in context",
+                       oc->soc_oid );
+               return LDAP_OBJECT_CLASS_VIOLATION;
+       }
+
+       return LDAP_SUCCESS;
+}
+
+static int subentryObjectClass (
+       Backend *be,
+       Entry *e,
+       ObjectClass *oc,
+       const char** text,
+       char *textbuf, size_t textlen )
+{
+       *text = textbuf;
+
+       if( !SLAP_SUBENTRIES(be) ) {
+               snprintf( textbuf, textlen,
+                       "objectClass \"%s\" not supported in context",
+                       oc->soc_oid );
+               return LDAP_OBJECT_CLASS_VIOLATION;
+       }
+
+       if( oc != slap_schema.si_oc_subentry && !is_entry_subentry( e ) ) {
+               snprintf( textbuf, textlen,
+                       "objectClass \"%s\" only allowed in subentries",
+                       oc->soc_oid );
+               return LDAP_OBJECT_CLASS_VIOLATION;
+       }
+
+       return LDAP_SUCCESS;
+}
+
+static int dynamicObjectClass (
+       Backend *be,
+       Entry *e,
+       ObjectClass *oc,
+       const char** text,
+       char *textbuf, size_t textlen )
+{
+       *text = textbuf;
+
+       if( !SLAP_DYNAMIC(be) ) {
+               snprintf( textbuf, textlen,
+                       "objectClass \"%s\" not supported in context",
+                       oc->soc_oid );
+               return LDAP_OBJECT_CLASS_VIOLATION;
+       }
+
+       return LDAP_SUCCESS;
+}
+
+static int rootDseAttribute (
+       Backend *be,
+       Entry *e,
+       Attribute *attr,
+       const char** text,
+       char *textbuf, size_t textlen )
+{
+       *text = textbuf;
+
+       if( e->e_nname.bv_len ) {
+               snprintf( textbuf, textlen,
+                       "attribute \"%s\" only allowed in the root DSE",
+                       attr->a_desc->ad_cname.bv_val );
+               return LDAP_OBJECT_CLASS_VIOLATION;
+       }
+
+       /* we should not be called for the root DSE */
+       assert( 0 );
+       return LDAP_SUCCESS;
+}
+
+static int aliasAttribute (
+       Backend *be,
+       Entry *e,
+       Attribute *attr,
+       const char** text,
+       char *textbuf, size_t textlen )
+{
+       *text = textbuf;
+
+       if( !SLAP_ALIASES(be) ) {
+               snprintf( textbuf, textlen,
+                       "attribute \"%s\" not supported in context",
+                       attr->a_desc->ad_cname.bv_val );
+               return LDAP_OBJECT_CLASS_VIOLATION;
+       }
+
+       if( !is_entry_alias( e ) ) {
+               snprintf( textbuf, textlen,
+                       "attribute \"%s\" only allowed in the alias",
+                       attr->a_desc->ad_cname.bv_val );
+               return LDAP_OBJECT_CLASS_VIOLATION;
+       }
+
+       return LDAP_SUCCESS;
+}
+
+static int referralAttribute (
+       Backend *be,
+       Entry *e,
+       Attribute *attr,
+       const char** text,
+       char *textbuf, size_t textlen )
+{
+       *text = textbuf;
+
+       if( !SLAP_REFERRALS(be) ) {
+               snprintf( textbuf, textlen,
+                       "attribute \"%s\" not supported in context",
+                       attr->a_desc->ad_cname.bv_val );
+               return LDAP_OBJECT_CLASS_VIOLATION;
+       }
+
+       if( !is_entry_referral( e ) ) {
+               snprintf( textbuf, textlen,
+                       "attribute \"%s\" only allowed in the referral",
+                       attr->a_desc->ad_cname.bv_val );
+               return LDAP_OBJECT_CLASS_VIOLATION;
+       }
+
+       return LDAP_SUCCESS;
+}
+
+static int subentryAttribute (
+       Backend *be,
+       Entry *e,
+       Attribute *attr,
+       const char** text,
+       char *textbuf, size_t textlen )
+{
+       *text = textbuf;
+
+       if( !SLAP_SUBENTRIES(be) ) {
+               snprintf( textbuf, textlen,
+                       "attribute \"%s\" not supported in context",
+                       attr->a_desc->ad_cname.bv_val );
+               return LDAP_OBJECT_CLASS_VIOLATION;
+       }
+
+       if( !is_entry_subentry( e ) ) {
+               snprintf( textbuf, textlen,
+                       "attribute \"%s\" only allowed in the subentry",
+                       attr->a_desc->ad_cname.bv_val );
+               return LDAP_OBJECT_CLASS_VIOLATION;
+       }
+
+       return LDAP_SUCCESS;
+}
+
+static int administrativeRoleAttribute (
+       Backend *be,
+       Entry *e,
+       Attribute *attr,
+       const char** text,
+       char *textbuf, size_t textlen )
+{
+       *text = textbuf;
+
+       if( !SLAP_SUBENTRIES(be) ) {
+               snprintf( textbuf, textlen,
+                       "attribute \"%s\" not supported in context",
+                       attr->a_desc->ad_cname.bv_val );
+               return LDAP_OBJECT_CLASS_VIOLATION;
+       }
+
+       snprintf( textbuf, textlen,
+               "attribute \"%s\" not supported!",
+               attr->a_desc->ad_cname.bv_val );
+       return LDAP_OBJECT_CLASS_VIOLATION;
+}
+
+static int dynamicAttribute (
+       Backend *be,
+       Entry *e,
+       Attribute *attr,
+       const char** text,
+       char *textbuf, size_t textlen )
+{
+       *text = textbuf;
+
+       if( !SLAP_DYNAMIC(be) ) {
+               snprintf( textbuf, textlen,
+                       "attribute \"%s\" not supported in context",
+                       attr->a_desc->ad_cname.bv_val );
+               return LDAP_OBJECT_CLASS_VIOLATION;
+       }
+
+       if( !is_entry_dynamicObject( e ) ) {
+               snprintf( textbuf, textlen,
+                       "attribute \"%s\" only allowed in dynamic object",
+                       attr->a_desc->ad_cname.bv_val );
+               return LDAP_OBJECT_CLASS_VIOLATION;
+       }
+
+       return LDAP_SUCCESS;
+}
index bf0c9c82970748945a2f863a25cc76ec30779b10..25f911049fae36b21154fd063b3b7014481ef9aa 100644 (file)
 /* slap.h - stand alone ldap server include file */
+/* $OpenLDAP$ */
+/*
+ * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ */
+
+#ifndef _SLAP_H_
+#define _SLAP_H_
 
-#ifndef _SLDAPD_H_
-#define _SLDAPD_H_
+#include "ldap_defaults.h"
 
-#define LDAP_SYSLOG
+#include <stdio.h>
+#include <ac/stdlib.h>
+
+#include <sys/types.h>
+#include <ac/syslog.h>
+#include <ac/regex.h>
+#include <ac/socket.h>
+#include <ac/time.h>
+#include <ac/param.h>
 
-#include <syslog.h>
 #include "avl.h"
-#include "lber.h"
-#include "ldap.h"
-#include "lthread.h"
-#include "ldif.h"
 
-#define DN_DNS 0
-#define DN_X500        1
+#ifndef ldap_debug
+#define ldap_debug slap_debug
+#endif
+
+#include "ldap_log.h"
+
+#include <ldap.h>
+#include <ldap_schema.h>
 
-#define ON     1
-#define OFF    (-1)
+#include "ldap_pvt_thread.h"
+#include "ldap_queue.h"
 
+LDAP_BEGIN_DECL
 /*
- * represents an attribute value assertion (i.e., attr=value)
+ * SLAPD Memory allocation macros
+ *
+ * Unlike ch_*() routines, these routines do not assert() upon
+ * allocation error.  They are intended to be used instead of
+ * ch_*() routines where the caller has implemented proper
+ * checking for and handling of allocation errors.
+ *
+ * Patches to convert ch_*() calls to SLAP_*() calls welcomed.
  */
-typedef struct ava {
-       char            *ava_type;
-       struct berval   ava_value;
-} Ava;
+#define SLAP_MALLOC(s)      ber_memalloc((s))
+#define SLAP_CALLOC(n,s)    ber_memcalloc((n),(s))
+#define SLAP_REALLOC(p,s)   ber_memrealloc((p),(s))
+#define SLAP_FREE(p)        ber_memfree((p))
+#define SLAP_VFREE(v)       ber_memvfree((void**)(v))
+#define SLAP_STRDUP(s)      ber_strdup((s))
+#define SLAP_STRNDUP(s,l)   ber_strndup((s),(l))
+
+#ifdef f_next
+#undef f_next /* name conflict between sys/file.h on SCO and struct filter */
+#endif
+
+#define SERVICE_NAME  OPENLDAP_PACKAGE "-slapd"
+#define SLAPD_ANONYMOUS "cn=anonymous"
+
+/* LDAPMod.mod_op value ===> Must be kept in sync with ldap.h!
+ *
+ * This is a value used internally by the backends. It is needed to allow
+ * adding values that already exist without getting an error as required by
+ * modrdn when the new rdn was already an attribute value itself.
+ * JCG 05/1999 (gomez@engr.sgi.com)
+ */
+#define SLAP_MOD_SOFTADD       0x1000
+
+#define MAXREMATCHES (10)
+
+#define SLAP_MAX_WORKER_THREADS                (32)
+
+#define SLAP_SB_MAX_INCOMING_DEFAULT ((1<<18) - 1)
+#define SLAP_SB_MAX_INCOMING_AUTH ((1<<24) - 1)
+
+#define SLAP_TEXT_BUFLEN (256)
+
+/* psuedo error code indicating abandoned operation */
+#define SLAPD_ABANDON (-1)
+
+/* psuedo error code indicating disconnect */
+#define SLAPD_DISCONNECT (-2)
+
+
+/* We assume "C" locale, that is US-ASCII */
+#define ASCII_SPACE(c) ( (c) == ' ' )
+#define ASCII_LOWER(c) ( (c) >= 'a' && (c) <= 'z' )
+#define ASCII_UPPER(c) ( (c) >= 'A' && (c) <= 'Z' )
+#define ASCII_ALPHA(c) ( ASCII_LOWER(c) || ASCII_UPPER(c) )
+#define ASCII_DIGIT(c) ( (c) >= '0' && (c) <= '9' )
+#define ASCII_ALNUM(c) ( ASCII_ALPHA(c) || ASCII_DIGIT(c) )
+#define ASCII_PRINTABLE(c) ( (c) >= ' ' && (c) <= '~' )
+
+#define SLAP_NIBBLE(c) ((c)&0x0f)
+#define SLAP_ESCAPE_CHAR ('\\')
+#define SLAP_ESCAPE_LO(c) ( "0123456789ABCDEF"[SLAP_NIBBLE(c)] )
+#define SLAP_ESCAPE_HI(c) ( SLAP_ESCAPE_LO((c)>>4) )
+
+#define FILTER_ESCAPE(c) ( (c) == '*' || (c) == '\\' \
+       || (c) == '(' || (c) == ')' || !ASCII_PRINTABLE(c) )
+
+#define DN_ESCAPE(c)   ((c) == SLAP_ESCAPE_CHAR)
+#define DN_SEPARATOR(c)        ((c) == ',' || (c) == ';')
+#define RDN_ATTRTYPEANDVALUE_SEPARATOR(c) ((c) == '+') /* RFC 2253 */
+#define RDN_SEPARATOR(c) (DN_SEPARATOR(c) || RDN_ATTRTYPEANDVALUE_SEPARATOR(c))
+#define RDN_NEEDSESCAPE(c)     ((c) == '\\' || (c) == '"')
+
+#define DESC_LEADCHAR(c)       ( ASCII_ALPHA(c) )
+#define DESC_CHAR(c)   ( ASCII_ALNUM(c) || (c) == '-' )
+#define OID_LEADCHAR(c)        ( ASCII_DIGIT(c) )
+#define OID_SEPARATOR(c)       ( (c) == '.' )
+#define OID_CHAR(c)    ( OID_LEADCHAR(c) || OID_SEPARATOR(c) )
+
+#define ATTR_LEADCHAR(c)       ( DESC_LEADCHAR(c) || OID_LEADCHAR(c) )
+#define ATTR_CHAR(c)   ( DESC_CHAR((c)) || (c) == '.' )
+
+#define AD_LEADCHAR(c) ( ATTR_CHAR(c) )
+#define AD_CHAR(c)             ( ATTR_CHAR(c) || (c) == ';' )
+
+#define SLAP_NUMERIC(c) ( ASCII_DIGIT(c) || ASCII_SPACE(c) )
+
+#define SLAP_PRINTABLE(c)      ( ASCII_ALNUM(c) || (c) == '\'' || \
+       (c) == '(' || (c) == ')' || (c) == '+' || (c) == ',' || \
+       (c) == '-' || (c) == '.' || (c) == '/' || (c) == ':' || \
+       (c) == '?' || (c) == ' ' || (c) == '=' )
+#define SLAP_PRINTABLES(c)     ( SLAP_PRINTABLE(c) || (c) == '$' )
+
+/* must match in schema_init.c */
+#define SLAPD_DN_SYNTAX                        "1.3.6.1.4.1.1466.115.121.1.12"
+#define SLAPD_NAMEUID_SYNTAX   "1.3.6.1.4.1.1466.115.121.1.34"
+#define SLAPD_GROUP_ATTR               "member"
+#define SLAPD_GROUP_CLASS              "groupOfNames"
+#define SLAPD_ROLE_ATTR                        "roleOccupant"
+#define SLAPD_ROLE_CLASS               "organizationalRole"
+
+#ifdef SLAPD_ACI_ENABLED
+#define SLAPD_ACI_SYNTAX               "1.3.6.1.4.1.4203.666.2.1"
+#endif
+
+#define SLAPD_OCTETSTRING_SYNTAX "1.3.6.1.4.1.1466.115.121.1.40"
+
+/* change this to "OpenLDAPset" */
+#define SLAPD_ACI_SET_ATTR             "template"
+
+#define SLAPD_TOP_OID                  "2.5.6.0"
+
+LDAP_SLAPD_V (int) slap_debug;
+
+typedef unsigned long slap_mask_t;
+
+/* Security Strength Factor */
+typedef unsigned slap_ssf_t;
+
+typedef struct slap_ssf_set {
+       slap_ssf_t sss_ssf;
+       slap_ssf_t sss_transport;
+       slap_ssf_t sss_tls;
+       slap_ssf_t sss_sasl;
+       slap_ssf_t sss_update_ssf;
+       slap_ssf_t sss_update_transport;
+       slap_ssf_t sss_update_tls;
+       slap_ssf_t sss_update_sasl;
+} slap_ssf_set_t;
+
+/*
+ * Index types
+ */
+#define SLAP_INDEX_TYPE           0x00FFUL
+#define SLAP_INDEX_UNDEFINED      0x0001UL
+#define SLAP_INDEX_PRESENT        0x0002UL
+#define SLAP_INDEX_EQUALITY       0x0004UL
+#define SLAP_INDEX_APPROX         0x0008UL
+#define SLAP_INDEX_SUBSTR         0x0010UL
+#define SLAP_INDEX_EXTENDED              0x0020UL
+
+#define SLAP_INDEX_DEFAULT        SLAP_INDEX_EQUALITY
+
+#define IS_SLAP_INDEX(mask, type)      (((mask) & (type)) == (type))
+
+#define SLAP_INDEX_SUBSTR_TYPE    0x0F00UL
+
+#define SLAP_INDEX_SUBSTR_INITIAL ( SLAP_INDEX_SUBSTR | 0x0100UL ) 
+#define SLAP_INDEX_SUBSTR_ANY     ( SLAP_INDEX_SUBSTR | 0x0200UL )
+#define SLAP_INDEX_SUBSTR_FINAL   ( SLAP_INDEX_SUBSTR | 0x0400UL )
+#define SLAP_INDEX_SUBSTR_DEFAULT \
+       ( SLAP_INDEX_SUBSTR \
+       | SLAP_INDEX_SUBSTR_INITIAL \
+       | SLAP_INDEX_SUBSTR_ANY \
+       | SLAP_INDEX_SUBSTR_FINAL )
+
+#define SLAP_INDEX_SUBSTR_MINLEN       2
+#define SLAP_INDEX_SUBSTR_MAXLEN       4
+#define SLAP_INDEX_SUBSTR_STEP 2
+
+#define SLAP_INDEX_FLAGS         0xF000UL
+#define SLAP_INDEX_NOSUBTYPES    0x1000UL /* don't use index w/ subtypes */
+#define SLAP_INDEX_NOLANG        0x2000UL /* don't use index w/ lang */
+
+/*
+ * there is a single index for each attribute.  these prefixes ensure
+ * that there is no collision among keys.
+ */
+#define SLAP_INDEX_EQUALITY_PREFIX     '='     /* prefix for equality keys     */
+#define SLAP_INDEX_APPROX_PREFIX       '~'             /* prefix for approx keys       */
+#define SLAP_INDEX_SUBSTR_PREFIX       '*'             /* prefix for substring keys    */
+#define SLAP_INDEX_SUBSTR_INITIAL_PREFIX '^'
+#define SLAP_INDEX_SUBSTR_FINAL_PREFIX '$'
+#define SLAP_INDEX_CONT_PREFIX         '.'             /* prefix for continuation keys */
+
+#define SLAP_SYNTAX_MATCHINGRULES_OID  "1.3.6.1.4.1.1466.115.121.1.30"
+#define SLAP_SYNTAX_ATTRIBUTETYPES_OID "1.3.6.1.4.1.1466.115.121.1.3"
+#define SLAP_SYNTAX_OBJECTCLASSES_OID  "1.3.6.1.4.1.1466.115.121.1.37"
+
+/*
+ * represents schema information for a database
+ */
+#define SLAP_SCHERR_OUTOFMEM           1
+#define SLAP_SCHERR_CLASS_NOT_FOUND    2
+#define SLAP_SCHERR_CLASS_BAD_USAGE    3
+#define SLAP_SCHERR_ATTR_NOT_FOUND     4
+#define SLAP_SCHERR_ATTR_BAD_USAGE     5
+#define SLAP_SCHERR_DUP_CLASS          6
+#define SLAP_SCHERR_DUP_ATTR           7
+#define SLAP_SCHERR_DUP_SYNTAX         8
+#define SLAP_SCHERR_DUP_RULE           9
+#define SLAP_SCHERR_NO_NAME            10
+#define SLAP_SCHERR_ATTR_INCOMPLETE    11
+#define SLAP_SCHERR_MR_NOT_FOUND       12
+#define SLAP_SCHERR_SYN_NOT_FOUND      13
+#define SLAP_SCHERR_MR_INCOMPLETE      14
+#define SLAP_SCHERR_NOT_SUPPORTED      15
+#define SLAP_SCHERR_BAD_DESCR          16
+#define SLAP_SCHERR_OIDM                       17
+#define SLAP_SCHERR_LAST                       SLAP_SCHERR_OIDM
+
+typedef union slap_sockaddr {
+       struct sockaddr sa_addr;
+       struct sockaddr_in sa_in_addr;
+#ifdef LDAP_PF_INET6
+       struct sockaddr_in6 sa_in6_addr;
+#endif
+#ifdef LDAP_PF_LOCAL
+       struct sockaddr_un sa_un_addr;
+#endif
+} Sockaddr;
+
+typedef struct slap_oid_macro {
+       struct berval som_oid;
+       char **som_names;
+       struct slap_oid_macro *som_next;
+} OidMacro;
+
+/* forward declarations */
+struct slap_syntax;
+struct slap_matching_rule;
+
+typedef int slap_syntax_validate_func LDAP_P((
+       struct slap_syntax *syntax,
+       struct berval * in));
+
+typedef int slap_syntax_transform_func LDAP_P((
+       struct slap_syntax *syntax,
+       struct berval * in,
+       struct berval * out));
+
+typedef struct slap_syntax {
+       LDAPSyntax                      ssyn_syn;
+#define ssyn_oid               ssyn_syn.syn_oid
+#define ssyn_desc              ssyn_syn.syn_desc
+#define ssyn_extensions                ssyn_syn.syn_extensions
+       ber_len_t       ssyn_oidlen;
+
+       unsigned int ssyn_flags;
+
+#define SLAP_SYNTAX_NONE       0x0000U
+#define SLAP_SYNTAX_BLOB       0x0001U /* syntax treated as blob (audio) */
+#define SLAP_SYNTAX_BINARY     0x0002U /* binary transfer required (certificate) */
+#define SLAP_SYNTAX_BER                0x0004U /* stored in BER encoding (certificate) */
+#define SLAP_SYNTAX_HIDE       0x8000U /* hide (do not publish) */
+
+       slap_syntax_validate_func       *ssyn_validate;
+       slap_syntax_transform_func      *ssyn_normalize;
+       slap_syntax_transform_func      *ssyn_pretty;
+
+#ifdef SLAPD_BINARY_CONVERSION
+       /* convert to and from binary */
+       slap_syntax_transform_func      *ssyn_ber2str;
+       slap_syntax_transform_func      *ssyn_str2ber;
+#endif
+
+       struct slap_syntax              *ssyn_next;
+} Syntax;
+
+#define slap_syntax_is_flag(s,flag) ((int)((s)->ssyn_flags & (flag)) ? 1 : 0)
+#define slap_syntax_is_blob(s)         slap_syntax_is_flag((s),SLAP_SYNTAX_BLOB)
+#define slap_syntax_is_binary(s)       slap_syntax_is_flag((s),SLAP_SYNTAX_BINARY)
+#define slap_syntax_is_ber(s)          slap_syntax_is_flag((s),SLAP_SYNTAX_BER)
+#define slap_syntax_is_hidden(s)       slap_syntax_is_flag((s),SLAP_SYNTAX_HIDE)
+
+/* X -> Y Converter */
+typedef int slap_mr_convert_func LDAP_P((
+       struct berval * in,
+       struct berval * out ));
+
+/* Normalizer */
+typedef int slap_mr_normalize_func LDAP_P((
+       slap_mask_t use,
+       struct slap_syntax *syntax, /* NULL if in is asserted value */
+       struct slap_matching_rule *mr,
+       struct berval * in,
+       struct berval * out ));
+
+/* Match (compare) function */
+typedef int slap_mr_match_func LDAP_P((
+       int *match,
+       slap_mask_t use,
+       struct slap_syntax *syntax,     /* syntax of stored value */
+       struct slap_matching_rule *mr,
+       struct berval * value,
+       void * assertValue ));
+
+/* Index generation function */
+typedef int slap_mr_indexer_func LDAP_P((
+       slap_mask_t use,
+       slap_mask_t mask,
+       struct slap_syntax *syntax,     /* syntax of stored value */
+       struct slap_matching_rule *mr,
+       struct berval *prefix,
+       BerVarray values,
+       BerVarray *keys ));
+
+/* Filter index function */
+typedef int slap_mr_filter_func LDAP_P((
+       slap_mask_t use,
+       slap_mask_t mask,
+       struct slap_syntax *syntax,     /* syntax of stored value */
+       struct slap_matching_rule *mr,
+       struct berval *prefix,
+       void * assertValue,
+       BerVarray *keys ));
+
+typedef struct slap_matching_rule {
+       LDAPMatchingRule                smr_mrule;
+       ber_len_t                               smr_oidlen;
+       slap_mask_t                             smr_usage;
+
+#define SLAP_MR_HIDE                   0x8000U
+
+#define SLAP_MR_TYPE_MASK              0x0F00U
+#define SLAP_MR_SUBTYPE_MASK   0x00F0U
+#define SLAP_MR_USAGE                  0x000FU
+
+#define SLAP_MR_NONE                   0x0000U
+#define SLAP_MR_EQUALITY               0x0100U
+#define SLAP_MR_ORDERING               0x0200U
+#define SLAP_MR_SUBSTR                 0x0400U
+#define SLAP_MR_EXT                            0x0800U
+
+#define SLAP_MR_EQUALITY_APPROX        ( SLAP_MR_EQUALITY | 0x0010U )
+#define SLAP_MR_DN_FOLD                        0x0008U
+
+#define SLAP_MR_SUBSTR_INITIAL ( SLAP_MR_SUBSTR | 0x0010U )
+#define SLAP_MR_SUBSTR_ANY             ( SLAP_MR_SUBSTR | 0x0020U )
+#define SLAP_MR_SUBSTR_FINAL   ( SLAP_MR_SUBSTR | 0x0040U )
+
+/*
+ * normally the provided value is expected to conform to
+ * assertion syntax specified in the matching rule, however
+ * at times (such as during individual value modification),
+ * the provided value is expected to conform to the
+ * attribute's value syntax.
+ */
+#define SLAP_MR_ASSERTION_SYNTAX_MATCH                 0x0000U
+#define SLAP_MR_VALUE_SYNTAX_MATCH                             0x0001U
+#define SLAP_MR_VALUE_SYNTAX_CONVERTED_MATCH   0x0003U
+
+#define SLAP_IS_MR_ASSERTION_SYNTAX_MATCH( usage ) \
+       (!((usage) & SLAP_MR_VALUE_SYNTAX_MATCH))
+#define SLAP_IS_MR_VALUE_SYNTAX_MATCH( usage ) \
+       ((usage) & SLAP_MR_VALUE_SYNTAX_MATCH)
+
+#define SLAP_IS_MR_VALUE_SYNTAX_CONVERTED_MATCH( usage ) \
+       (((usage) & SLAP_MR_VALUE_SYNTAX_CONVERTED_MATCH) \
+               == SLAP_MR_VALUE_SYNTAX_CONVERTED_MATCH)
+#define SLAP_IS_MR_VALUE_SYNTAX_NONCONVERTED_MATCH( usage ) \
+       (((usage) & SLAP_MR_VALUE_SYNTAX_CONVERTED_MATCH) \
+               == SLAP_MR_VALUE_SYNTAX_MATCH)
+
+       Syntax                                  *smr_syntax;
+       slap_mr_convert_func    *smr_convert;
+       slap_mr_normalize_func  *smr_normalize;
+       slap_mr_match_func              *smr_match;
+       slap_mr_indexer_func    *smr_indexer;
+       slap_mr_filter_func             *smr_filter;
+
+       struct slap_matching_rule       *smr_associated;
+       struct slap_matching_rule       *smr_next;
+
+#define smr_oid                                smr_mrule.mr_oid
+#define smr_names                      smr_mrule.mr_names
+#define smr_desc                       smr_mrule.mr_desc
+#define smr_obsolete           smr_mrule.mr_obsolete
+#define smr_syntax_oid         smr_mrule.mr_syntax_oid
+#define smr_extensions         smr_mrule.mr_extensions
+} MatchingRule;
+
+struct slap_backend_db;
+struct slap_entry;
+struct slap_attr;
+
+typedef int (AttributeTypeSchemaCheckFN)(
+       struct slap_backend_db *be,
+       struct slap_entry *e,
+       struct slap_attr *attr,
+       const char** text,
+       char *textbuf, size_t textlen );
+
+typedef struct slap_attribute_type {
+       LDAPAttributeType               sat_atype;
+       struct berval                   sat_cname;
+       struct slap_attribute_type      *sat_sup;
+       struct slap_attribute_type      **sat_subtypes;
+       MatchingRule                    *sat_equality;
+       MatchingRule                    *sat_approx;
+       MatchingRule                    *sat_ordering;
+       MatchingRule                    *sat_substr;
+       Syntax                                  *sat_syntax;
+
+       AttributeTypeSchemaCheckFN      *sat_check;
+       slap_mask_t                                     sat_flags;
+
+       struct slap_attribute_type      *sat_next;
+
+#define sat_oid                                sat_atype.at_oid
+#define sat_names                      sat_atype.at_names
+#define sat_desc                       sat_atype.at_desc
+#define sat_obsolete           sat_atype.at_obsolete
+#define sat_sup_oid                    sat_atype.at_sup_oid
+#define sat_equality_oid       sat_atype.at_equality_oid
+#define sat_ordering_oid       sat_atype.at_ordering_oid
+#define sat_substr_oid         sat_atype.at_substr_oid
+#define sat_syntax_oid         sat_atype.at_syntax_oid
+#define sat_single_value       sat_atype.at_single_value
+#define sat_collective         sat_atype.at_collective
+#define sat_no_user_mod                sat_atype.at_no_user_mod
+#define sat_usage                      sat_atype.at_usage
+#define sat_extensions         sat_atype.at_extensions
+
+       struct slap_attr_desc           *sat_ad;
+       ldap_pvt_thread_mutex_t         sat_ad_mutex;
+} AttributeType;
+
+#define is_at_operational(at)  ((at)->sat_usage)
+#define is_at_single_value(at) ((at)->sat_single_value)
+#define is_at_collective(at)   ((at)->sat_collective)
+#define is_at_obsolete(at)             ((at)->sat_obsolete)
+#define is_at_no_user_mod(at)  ((at)->sat_no_user_mod)
+
+struct slap_object_class;
+
+typedef int (ObjectClassSchemaCheckFN)(
+       struct slap_backend_db *be,
+       struct slap_entry *e,
+       struct slap_object_class *oc,
+       const char** text,
+       char *textbuf, size_t textlen );
+
+typedef struct slap_object_class {
+       LDAPObjectClass         soc_oclass;
+       struct slap_object_class        **soc_sups;
+       AttributeType                           **soc_required;
+       AttributeType                           **soc_allowed;
+       ObjectClassSchemaCheckFN        *soc_check;
+       slap_mask_t                                     soc_flags;
+#define soc_oid                                soc_oclass.oc_oid
+#define soc_names                      soc_oclass.oc_names
+#define soc_desc                       soc_oclass.oc_desc
+#define soc_obsolete           soc_oclass.oc_obsolete
+#define soc_sup_oids           soc_oclass.oc_sup_oids
+#define soc_kind                       soc_oclass.oc_kind
+#define soc_at_oids_must       soc_oclass.oc_at_oids_must
+#define soc_at_oids_may                soc_oclass.oc_at_oids_may
+#define soc_extensions         soc_oclass.oc_extensions
+
+       struct slap_object_class        *soc_next;
+} ObjectClass;
+
+#define        SLAP_OC_ALIAS           0x01
+#define        SLAP_OC_REFERRAL        0x02
+#define        SLAP_OC_SUBENTRY        0x04
+#define        SLAP_OC_DYNAMICOBJECT   0x08
+#define        SLAP_OC_COLLECTIVEATTRIBUTESUBENTRY     0x10
+#define        SLAP_OC__MASK           0x1F
+#define        SLAP_OC__END            0x20
+
+#ifdef LDAP_EXTENDED_SCHEMA
+/*
+ * DIT content rule
+ */
+typedef struct slap_content_rule {
+       LDAPContentRule         scr_crule;
+       ObjectClass                     *scr_sclass;
+       ObjectClass                     **scr_auxiliaries;      /* optional */
+       AttributeType           **scr_required;         /* optional */
+       AttributeType           **scr_allowed;          /* optional */
+       AttributeType           **scr_precluded;        /* optional */
+#define scr_oid                        scr_crule.cr_oid
+#define scr_names              scr_crule.cr_names
+#define scr_desc               scr_crule.cr_desc
+#define scr_obsolete           soc_oclass.cr_obsolete
+#define scr_cr_oids_aux                soc_oclass.cr_oc_oids_aux
+#define scr_cr_oids_must       soc_oclass.cr_at_oids_must
+#define scr_cr_oids_may                soc_oclass.cr_at_oids_may
+#define scr_cr_oids_not                soc_oclass.cr_at_oids_not
+} ContentRule;
+#endif
+
+/*
+ * represents a recognized attribute description ( type + options )
+ */
+typedef struct slap_attr_desc {
+       struct slap_attr_desc *ad_next;
+       AttributeType *ad_type;         /* attribute type, must be specified */
+       struct berval ad_cname;         /* canonical name, must be specified */
+       struct berval ad_lang;          /* empty if no language tags */
+       unsigned ad_flags;
+#define SLAP_DESC_NONE                 0x00U
+#define SLAP_DESC_BINARY               0x01U
+#define SLAP_DESC_LANG_RANGE   0x80U
+} AttributeDescription;
+
+typedef struct slap_attr_name {
+       struct berval an_name;
+       AttributeDescription *an_desc;
+       ObjectClass *an_oc;
+} AttributeName;
+
+#define slap_ad_is_lang(ad)                    ( (ad)->ad_lang.bv_len != 0 )
+#define slap_ad_is_lang_range(ad)      \
+       ( ((ad)->ad_flags & SLAP_DESC_LANG_RANGE) ? 1 : 0 )
+#define slap_ad_is_binary(ad)          \
+       ( ((ad)->ad_flags & SLAP_DESC_BINARY) ? 1 : 0 )
+
+/*
+ * pointers to schema elements used internally
+ */
+struct slap_internal_schema {
+       /* objectClass */
+       ObjectClass *si_oc_top;
+       ObjectClass *si_oc_extensibleObject;
+       ObjectClass *si_oc_alias;
+       ObjectClass *si_oc_referral;
+       ObjectClass *si_oc_rootdse;
+       ObjectClass *si_oc_subentry;
+       ObjectClass *si_oc_subschema;
+       ObjectClass *si_oc_monitor;
+       ObjectClass *si_oc_collectiveAttributeSubentry;
+       ObjectClass *si_oc_dynamicObject;
+
+       /* objectClass attribute descriptions */
+       AttributeDescription *si_ad_objectClass;
+
+       /* operational attribute descriptions */
+       AttributeDescription *si_ad_structuralObjectClass;
+       AttributeDescription *si_ad_creatorsName;
+       AttributeDescription *si_ad_createTimestamp;
+       AttributeDescription *si_ad_modifiersName;
+       AttributeDescription *si_ad_modifyTimestamp;
+       AttributeDescription *si_ad_hasSubordinates;
+       AttributeDescription *si_ad_subschemaSubentry;
+       AttributeDescription *si_ad_collectiveSubentries;
+       AttributeDescription *si_ad_collectiveExclusions;
+       AttributeDescription *si_ad_entryUUID;
+       AttributeDescription *si_ad_entryCSN;
+
+       /* root DSE attribute descriptions */
+       AttributeDescription *si_ad_altServer;
+       AttributeDescription *si_ad_namingContexts;
+       AttributeDescription *si_ad_supportedControl;
+       AttributeDescription *si_ad_supportedExtension;
+       AttributeDescription *si_ad_supportedLDAPVersion;
+       AttributeDescription *si_ad_supportedSASLMechanisms;
+       AttributeDescription *si_ad_supportedFeatures;
+       AttributeDescription *si_ad_vendorName;
+       AttributeDescription *si_ad_vendorVersion;
+
+       /* subentry attribute descriptions */
+       AttributeDescription *si_ad_administrativeRole;
+       AttributeDescription *si_ad_subtreeSpecification;
+
+       /* subschema subentry attribute descriptions */
+       AttributeDescription *si_ad_ditStructureRules;
+       AttributeDescription *si_ad_ditContentRules;
+       AttributeDescription *si_ad_nameForms;
+       AttributeDescription *si_ad_objectClasses;
+       AttributeDescription *si_ad_attributeTypes;
+       AttributeDescription *si_ad_ldapSyntaxes;
+       AttributeDescription *si_ad_matchingRules;
+       AttributeDescription *si_ad_matchingRuleUse;
+
+       /* Aliases & Referrals */
+       AttributeDescription *si_ad_aliasedObjectName;
+       AttributeDescription *si_ad_ref;
+
+       /* Access Control Internals */
+       AttributeDescription *si_ad_entry;
+       AttributeDescription *si_ad_children;
+#ifdef SLAPD_ACI_ENABLED
+       AttributeDescription *si_ad_aci;
+#endif
+
+       /* dynamic entries */
+       AttributeDescription *si_ad_entryTtl;
+       AttributeDescription *si_ad_dynamicSubtrees;
+
+       /* Other attributes descriptions */
+       AttributeDescription *si_ad_distinguishedName;
+       AttributeDescription *si_ad_name;
+       AttributeDescription *si_ad_cn;
+       AttributeDescription *si_ad_userPassword;
+#ifdef SLAPD_AUTHPASSWD
+       AttributeDescription *si_ad_authPassword;
+#endif
+#ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
+       AttributeDescription *si_ad_krbName;
+#endif
+
+       /* Undefined Attribute Type */
+       AttributeType   *si_at_undefined;
+
+       /* Matching Rules */
+       MatchingRule    *si_mr_distinguishedNameMatch;
+       MatchingRule    *si_mr_integerMatch;
+
+       /* Syntaxes */
+       Syntax          *si_syn_distinguishedName;
+       Syntax          *si_syn_integer;
+};
+
+typedef struct slap_attr_assertion {
+       AttributeDescription    *aa_desc;
+       struct berval aa_value;
+} AttributeAssertion;
+
+typedef struct slap_ss_assertion {
+       AttributeDescription    *sa_desc;
+       struct berval           sa_initial;
+       struct berval           *sa_any;
+       struct berval           sa_final;
+} SubstringsAssertion;
+
+typedef struct slap_mr_assertion {
+       MatchingRule            *ma_rule;       /* optional */
+       struct berval           ma_rule_text;  /* optional */
+       AttributeDescription    *ma_desc;       /* optional */
+       int                                             ma_dnattrs; /* boolean */
+       struct berval           ma_value;       /* required */
+} MatchingRuleAssertion;
 
 /*
  * represents a search filter
  */
-typedef struct filter {
-       unsigned long   f_choice;       /* values taken from ldap.h */
+typedef struct slap_filter {
+       ber_tag_t       f_choice;       /* values taken from ldap.h, plus: */
+#define SLAPD_FILTER_COMPUTED  ((ber_tag_t) -1)
+#define SLAPD_FILTER_DN_ONE            ((ber_tag_t) -2)
+#define SLAPD_FILTER_DN_SUBTREE        ((ber_tag_t) -3)
+
+       union f_un_u {
+               /* precomputed result */
+               ber_int_t f_un_result;
+
+               /* DN */
+               struct berval *f_un_dn;
 
-       union {
                /* present */
-               char            *f_un_type;
+               AttributeDescription *f_un_desc;
+
+               /* simple value assertion */
+               AttributeAssertion *f_un_ava;
 
-               /* equality, lessorequal, greaterorequal, approx */
-               Ava             f_un_ava;
+               /* substring assertion */
+               SubstringsAssertion *f_un_ssa;
+
+               /* matching rule assertion */
+               MatchingRuleAssertion *f_un_mra;
+
+#define f_dn                   f_un.f_un_dn
+#define f_desc                 f_un.f_un_desc
+#define f_ava                  f_un.f_un_ava
+#define f_av_desc              f_un.f_un_ava->aa_desc
+#define f_av_value             f_un.f_un_ava->aa_value
+#define f_sub                  f_un.f_un_ssa
+#define f_sub_desc             f_un.f_un_ssa->sa_desc
+#define f_sub_initial  f_un.f_un_ssa->sa_initial
+#define f_sub_any              f_un.f_un_ssa->sa_any
+#define f_sub_final            f_un.f_un_ssa->sa_final
+#define f_mra                  f_un.f_un_mra
+#define f_mr_rule              f_un.f_un_mra->ma_rule
+#define f_mr_rule_text f_un.f_un_mra->ma_rule_text
+#define f_mr_desc              f_un.f_un_mra->ma_desc
+#define f_mr_value             f_un.f_un_mra->ma_value
+#define        f_mr_dnattrs    f_un.f_un_mra->ma_dnattrs
 
                /* and, or, not */
-               struct filter   *f_un_complex;
-
-               /* substrings */
-               struct sub {
-                       char    *f_un_sub_type;
-                       char    *f_un_sub_initial;
-                       char    **f_un_sub_any;
-                       char    *f_un_sub_final;
-               } f_un_sub;
+               struct slap_filter *f_un_complex;
        } f_un;
-#define f_type         f_un.f_un_type
-#define f_ava          f_un.f_un_ava
-#define f_avtype       f_un.f_un_ava.ava_type
-#define f_avvalue      f_un.f_un_ava.ava_value
+
+#define f_result       f_un.f_un_result
 #define f_and          f_un.f_un_complex
 #define f_or           f_un.f_un_complex
 #define f_not          f_un.f_un_complex
 #define f_list         f_un.f_un_complex
-#define f_sub          f_un.f_un_sub
-#define f_sub_type     f_un.f_un_sub.f_un_sub_type
-#define f_sub_initial  f_un.f_un_sub.f_un_sub_initial
-#define f_sub_any      f_un.f_un_sub.f_un_sub_any
-#define f_sub_final    f_un.f_un_sub.f_un_sub_final
 
-       struct filter   *f_next;
+       struct slap_filter      *f_next;
 } Filter;
 
+/* compare routines can return undefined */
+#define SLAPD_COMPARE_UNDEFINED        ((ber_int_t) -1)
+
 /*
- * represents an attribute (type + values + syntax)
+ * represents an attribute (description + values)
  */
-typedef struct attr {
-       char            *a_type;
-       struct berval   **a_vals;
-       int             a_syntax;
-       struct attr     *a_next;
+typedef struct slap_attr {
+       AttributeDescription *a_desc;
+       BerVarray       a_vals;
+       struct slap_attr        *a_next;
+       unsigned a_flags;
+#define SLAP_ATTR_IXADD                0x1U
+#define SLAP_ATTR_IXDEL                0x2U
 } Attribute;
 
-/*
- * the attr_syntax() routine returns one of these values
- * telling what kind of syntax an attribute supports.
- */
-#define SYNTAX_CIS     0x01    /* case insensitive string              */
-#define SYNTAX_CES     0x02    /* case sensitive string                */
-#define SYNTAX_BIN     0x04    /* binary data                          */
-#define SYNTAX_TEL     0x08    /* telephone number string              */
-#define SYNTAX_DN      0x10    /* dn string                            */
 
 /*
  * the id used in the indexes to refer to an entry
  */
 typedef unsigned long  ID;
-#define NOID   ((unsigned long)-1)
+#define NOID   ((ID)~0)
 
 /*
  * represents an entry in core
  */
-typedef struct entry {
-       char            *e_dn;          /* DN of this entry               */
-       Attribute       *e_attrs;       /* list of attributes + values    */
-
-       ID              e_id;           /* id of this entry - this should */
-                                       /* really be private to back-ldbm */
-       char            e_state;        /* for the cache                  */
-#define ENTRY_STATE_DELETED    1
-#define ENTRY_STATE_CREATING   2
-       int             e_refcnt;       /* # threads ref'ing this entry   */
-       struct entry    *e_lrunext;     /* for cache lru list             */
-       struct entry    *e_lruprev;
+typedef struct slap_entry {
+       /*
+        * The ID field should only be changed before entry is
+        * inserted into a cache.  The ID value is backend
+        * specific.
+        */
+       ID              e_id;
+
+       struct berval e_name;   /* name (DN) of this entry */
+       struct berval e_nname;  /* normalized name (DN) of this entry */
+
+       /* for migration purposes */
+#define e_dn e_name.bv_val
+#define e_ndn e_nname.bv_val
+
+       Attribute       *e_attrs;       /* list of attributes + values */
+
+       slap_mask_t     e_ocflags;
+
+       struct berval   e_bv;           /* For entry_encode/entry_decode */
+
+       /* for use by the backend for any purpose */
+       void*   e_private;
 } Entry;
 
+/*
+ * A list of LDAPMods
+ */
+typedef struct slap_mod {
+       int sm_op;
+       AttributeDescription *sm_desc;
+       struct berval sm_type;
+       BerVarray sm_bvalues;
+} Modification;
+
+typedef struct slap_mod_list {
+       Modification sml_mod;
+#define sml_op         sml_mod.sm_op
+#define sml_desc       sml_mod.sm_desc
+#define        sml_type        sml_mod.sm_type
+#define sml_bvalues    sml_mod.sm_bvalues
+       struct slap_mod_list *sml_next;
+} Modifications;
+
+typedef struct slap_ldap_modlist {
+       LDAPMod ml_mod;
+       struct slap_ldap_modlist *ml_next;
+#define ml_op          ml_mod.mod_op
+#define ml_type                ml_mod.mod_type
+#define ml_values      ml_mod.mod_values
+#define ml_bvalues     ml_mod.mod_bvalues
+} LDAPModList;
+
 /*
  * represents an access control list
  */
+typedef enum slap_access_e {
+       ACL_INVALID_ACCESS = -1,
+       ACL_NONE = 0,
+       ACL_AUTH,
+       ACL_COMPARE,
+       ACL_SEARCH,
+       ACL_READ,
+       ACL_WRITE
+} slap_access_t;
+
+typedef enum slap_control_e {
+       ACL_INVALID_CONTROL     = 0,
+       ACL_STOP,
+       ACL_CONTINUE,
+       ACL_BREAK
+} slap_control_t;
+
+typedef enum slap_style_e {
+       ACL_STYLE_REGEX = 0,
+       ACL_STYLE_BASE,
+       ACL_STYLE_ONE,
+       ACL_STYLE_SUBTREE,
+       ACL_STYLE_CHILDREN,
+       ACL_STYLE_ATTROF,
+
+       /* alternate names */
+       ACL_STYLE_EXACT = ACL_STYLE_BASE
+} slap_style_t;
+
+typedef struct slap_authz_info {
+       ber_tag_t       sai_method;             /* LDAP_AUTH_* from <ldap.h> */
+       struct berval   sai_mech;               /* SASL Mechanism */
+       struct berval   sai_dn;                 /* DN for reporting purposes */
+       struct berval   sai_ndn;                /* Normalized DN */
+
+       /* Security Strength Factors */
+       slap_ssf_t      sai_ssf;                        /* Overall SSF */
+       slap_ssf_t      sai_transport_ssf;      /* Transport SSF */
+       slap_ssf_t      sai_tls_ssf;            /* TLS SSF */
+       slap_ssf_t      sai_sasl_ssf;           /* SASL SSF */
+} AuthorizationInformation;
 
 /* the "by" part */
-struct access {
-       char            *a_dnpat;
-       char            *a_addrpat;
-       char            *a_domainpat;
-       char            *a_dnattr;
-       long            a_access;
-#define ACL_NONE       0x01
-#define ACL_COMPARE    0x02
-#define ACL_SEARCH     0x04
-#define ACL_READ       0x08
-#define ACL_WRITE      0x10
-#define ACL_SELF       0x40
-       struct access   *a_next;
-};
+typedef struct slap_access {
+       slap_control_t a_type;
+
+#define ACL_ACCESS2PRIV(access)        (0x01U << (access))
+
+#define ACL_PRIV_NONE                  ACL_ACCESS2PRIV( ACL_NONE )
+#define ACL_PRIV_AUTH                  ACL_ACCESS2PRIV( ACL_AUTH )
+#define ACL_PRIV_COMPARE               ACL_ACCESS2PRIV( ACL_COMPARE )
+#define ACL_PRIV_SEARCH                        ACL_ACCESS2PRIV( ACL_SEARCH )
+#define ACL_PRIV_READ                  ACL_ACCESS2PRIV( ACL_READ )
+#define ACL_PRIV_WRITE                 ACL_ACCESS2PRIV( ACL_WRITE )
+
+#define ACL_PRIV_MASK                  0x00ffUL
+
+/* priv flags */
+#define ACL_PRIV_LEVEL                 0x1000UL
+#define ACL_PRIV_ADDITIVE              0x2000UL
+#define ACL_PRIV_SUBSTRACTIVE  0x4000UL
+
+/* invalid privs */
+#define ACL_PRIV_INVALID               0x0UL
+
+#define ACL_PRIV_ISSET(m,p)            (((m) & (p)) == (p))
+#define ACL_PRIV_ASSIGN(m,p)   do { (m)  =  (p); } while(0)
+#define ACL_PRIV_SET(m,p)              do { (m) |=  (p); } while(0)
+#define ACL_PRIV_CLR(m,p)              do { (m) &= ~(p); } while(0)
+
+#define ACL_INIT(m)                            ACL_PRIV_ASSIGN(m, ACL_PRIV_NONE)
+#define ACL_INVALIDATE(m)              ACL_PRIV_ASSIGN(m, ACL_PRIV_INVALID)
+
+#define ACL_GRANT(m,a)                 ACL_PRIV_ISSET((m),ACL_ACCESS2PRIV(a))
+
+#define ACL_IS_INVALID(m)              ((m) == ACL_PRIV_INVALID)
+
+#define ACL_IS_LEVEL(m)                        ACL_PRIV_ISSET((m),ACL_PRIV_LEVEL)
+#define ACL_IS_ADDITIVE(m)             ACL_PRIV_ISSET((m),ACL_PRIV_ADDITIVE)
+#define ACL_IS_SUBTRACTIVE(m)  ACL_PRIV_ISSET((m),ACL_PRIV_SUBSTRACTIVE)
+
+#define ACL_LVL_NONE                   (ACL_PRIV_NONE|ACL_PRIV_LEVEL)
+#define ACL_LVL_AUTH                   (ACL_PRIV_AUTH|ACL_LVL_NONE)
+#define ACL_LVL_COMPARE                        (ACL_PRIV_COMPARE|ACL_LVL_AUTH)
+#define ACL_LVL_SEARCH                 (ACL_PRIV_SEARCH|ACL_LVL_COMPARE)
+#define ACL_LVL_READ                   (ACL_PRIV_READ|ACL_LVL_SEARCH)
+#define ACL_LVL_WRITE                  (ACL_PRIV_WRITE|ACL_LVL_READ)
+
+#define ACL_LVL(m,l)                   (((m)&ACL_PRIV_MASK) == ((l)&ACL_PRIV_MASK))
+#define ACL_LVL_IS_NONE(m)             ACL_LVL((m),ACL_LVL_NONE)
+#define ACL_LVL_IS_AUTH(m)             ACL_LVL((m),ACL_LVL_AUTH)
+#define ACL_LVL_IS_COMPARE(m)  ACL_LVL((m),ACL_LVL_COMPARE)
+#define ACL_LVL_IS_SEARCH(m)   ACL_LVL((m),ACL_LVL_SEARCH)
+#define ACL_LVL_IS_READ(m)             ACL_LVL((m),ACL_LVL_READ)
+#define ACL_LVL_IS_WRITE(m)            ACL_LVL((m),ACL_LVL_WRITE)
+
+#define ACL_LVL_ASSIGN_NONE(m)         ACL_PRIV_ASSIGN((m),ACL_LVL_NONE)
+#define ACL_LVL_ASSIGN_AUTH(m)         ACL_PRIV_ASSIGN((m),ACL_LVL_AUTH)
+#define ACL_LVL_ASSIGN_COMPARE(m)      ACL_PRIV_ASSIGN((m),ACL_LVL_COMPARE)
+#define ACL_LVL_ASSIGN_SEARCH(m)       ACL_PRIV_ASSIGN((m),ACL_LVL_SEARCH)
+#define ACL_LVL_ASSIGN_READ(m)         ACL_PRIV_ASSIGN((m),ACL_LVL_READ)
+#define ACL_LVL_ASSIGN_WRITE(m)                ACL_PRIV_ASSIGN((m),ACL_LVL_WRITE)
+
+       slap_mask_t     a_access_mask;
+
+       AuthorizationInformation        a_authz;
+#define a_dn_pat       a_authz.sai_dn
+
+       slap_style_t a_dn_style;
+       AttributeDescription    *a_dn_at;
+       int                     a_dn_self;
+
+       slap_style_t a_peername_style;
+       struct berval   a_peername_pat;
+       slap_style_t a_sockname_style;
+       struct berval   a_sockname_pat;
+
+       slap_style_t a_domain_style;
+       struct berval   a_domain_pat;
+       slap_style_t a_sockurl_style;
+       struct berval   a_sockurl_pat;
+       slap_style_t a_set_style;
+       struct berval   a_set_pat;
+
+#ifdef SLAPD_ACI_ENABLED
+       AttributeDescription    *a_aci_at;
+#endif
+
+       /* ACL Groups */
+       slap_style_t a_group_style;
+       struct berval   a_group_pat;
+       ObjectClass                             *a_group_oc;
+       AttributeDescription    *a_group_at;
+
+       struct slap_access      *a_next;
+} Access;
 
 /* the "to" part */
-struct acl {
+typedef struct slap_acl {
        /* "to" part: the entries this acl applies to */
        Filter          *acl_filter;
-       char            *acl_dnpat;
-       char            **acl_attrs;
+       slap_style_t acl_dn_style;
+       regex_t         acl_dn_re;
+       struct berval   acl_dn_pat;
+       AttributeName   *acl_attrs;
 
        /* "by" part: list of who has what access to the entries */
-       struct access   *acl_access;
+       Access  *acl_access;
 
-       struct acl      *acl_next;
-};
+       struct slap_acl *acl_next;
+} AccessControl;
+
+typedef struct slap_acl_state {
+       unsigned as_recorded;
+#define ACL_STATE_NOT_RECORDED                 0x0
+#define ACL_STATE_RECORDED_VD                  0x1
+#define ACL_STATE_RECORDED_NV                  0x2
+#define ACL_STATE_RECORDED                             0x3
+
+       /* Access state */
+       AccessControl *as_vd_acl;
+       slap_mask_t as_vd_acl_mask;
+       regmatch_t as_vd_acl_matches[MAXREMATCHES];
+       int as_vd_acl_count;
+
+       Access *as_vd_access;
+       int as_vd_access_count;
+
+       int as_result;
+} AccessControlState;
+#define ACL_STATE_INIT { ACL_STATE_NOT_RECORDED, NULL, 0UL, { 0 }, 0, NULL, 0 }
 
 /*
- * represents schema information for a database
+ * replog moddn param structure
  */
-
-struct objclass {
-       char            *oc_name;
-       char            **oc_required;
-       char            **oc_allowed;
-       struct objclass *oc_next;
+struct slap_replog_moddn {
+       struct berval *newrdn;
+       int     deloldrdn;
+       struct berval *newsup;
 };
 
 /*
- * represents a "database"
+ * Backend-info
+ * represents a backend 
  */
 
-typedef struct backend {
-       char    **be_suffix;    /* the DN suffixes of data in this backend */
-       char    *be_rootdn;     /* the magic "root" dn for this db         */
-       char    *be_rootpw;     /* the magic "root" password for this db   */
-       int     be_readonly;    /* 1 => db is in "read only" mode          */
-       int     be_sizelimit;   /* size limit for this backend             */
-       int     be_timelimit;   /* time limit for this backend             */
-       struct acl *be_acl;     /* access control list for this backend    */
-       int     be_dfltaccess;  /* access given if no acl matches          */
-       char    **be_replica;   /* replicas of this backend (in master)    */
+typedef struct slap_backend_info BackendInfo;  /* per backend type */
+typedef struct slap_backend_db BackendDB;              /* per backend database */
+
+LDAP_SLAPD_V (int) nBackendInfo;
+LDAP_SLAPD_V (int) nBackendDB;
+LDAP_SLAPD_V (BackendInfo *) backendInfo;
+LDAP_SLAPD_V (BackendDB *) backendDB;
+
+LDAP_SLAPD_V (int) slapMode;   
+#define SLAP_UNDEFINED_MODE    0x0000
+#define SLAP_SERVER_MODE       0x0001
+#define SLAP_TOOL_MODE         0x0002
+#define SLAP_MODE                      0x0003
+
+#define SLAP_TRUNCATE_MODE     0x0100
+
+struct slap_replica_info {
+       char *ri_host;                          /* supersedes be_replica */
+       struct berval **ri_nsuffix;     /* array of suffixes this replica accepts */
+       AttributeName *ri_attrs;        /* attrs to replicate, NULL=all */
+};
+
+struct slap_limits_set {
+       /* time limits */
+       int     lms_t_soft;
+       int     lms_t_hard;
+
+       /* size limits */
+       int     lms_s_soft;
+       int     lms_s_hard;
+       int     lms_s_unchecked;
+};
+
+struct slap_limits {
+       int     lm_type;        /* type of pattern */
+#define SLAP_LIMITS_UNDEFINED  0x0000
+#define SLAP_LIMITS_EXACT      0x0001
+#define SLAP_LIMITS_BASE       SLAP_LIMITS_EXACT
+#define SLAP_LIMITS_ONE                0x0002
+#define SLAP_LIMITS_SUBTREE    0x0003
+#define SLAP_LIMITS_CHILDREN   0x0004
+#define SLAP_LIMITS_REGEX      0x0005
+#define SLAP_LIMITS_ANONYMOUS  0x0006
+#define SLAP_LIMITS_USERS      0x0007
+       regex_t lm_dn_regex;            /* regex data for REGEX */
+
+       /*
+        * normalized DN for EXACT, BASE, ONE, SUBTREE, CHILDREN;
+        * pattern for REGEX; NULL for ANONYMOUS, USERS
+        */
+       struct berval lm_dn_pat;
+
+       struct slap_limits_set  lm_limits;
+};
+
+/* temporary aliases */
+typedef BackendDB Backend;
+#define nbackends nBackendDB
+#define backends backendDB
+
+struct slap_backend_db {
+       BackendInfo     *bd_info;       /* pointer to shared backend info */
+
+       /* BackendInfo accessors */
+#define                be_config       bd_info->bi_db_config
+#define                be_type         bd_info->bi_type
+
+#define                be_bind         bd_info->bi_op_bind
+#define                be_unbind       bd_info->bi_op_unbind
+#define                be_add          bd_info->bi_op_add
+#define                be_compare      bd_info->bi_op_compare
+#define                be_delete       bd_info->bi_op_delete
+#define                be_modify       bd_info->bi_op_modify
+#define                be_modrdn       bd_info->bi_op_modrdn
+#define                be_search       bd_info->bi_op_search
+
+#define                be_extended     bd_info->bi_extended
+
+#define                be_release      bd_info->bi_entry_release_rw
+#define                be_chk_referrals        bd_info->bi_chk_referrals
+#define                be_group        bd_info->bi_acl_group
+#define                be_attribute    bd_info->bi_acl_attribute
+#define                be_operational  bd_info->bi_operational
+
+#define                be_controls     bd_info->bi_controls
+
+#define                be_connection_init      bd_info->bi_connection_init
+#define                be_connection_destroy   bd_info->bi_connection_destroy
+
+#ifdef SLAPD_TOOLS
+#define                be_entry_open bd_info->bi_tool_entry_open
+#define                be_entry_close bd_info->bi_tool_entry_close
+#define                be_entry_first bd_info->bi_tool_entry_first
+#define                be_entry_next bd_info->bi_tool_entry_next
+#define                be_entry_reindex bd_info->bi_tool_entry_reindex
+#define                be_entry_get bd_info->bi_tool_entry_get
+#define                be_entry_put bd_info->bi_tool_entry_put
+#define                be_sync bd_info->bi_tool_sync
+#endif
+
+#define SLAP_BFLAG_NOLASTMOD           0x0001U
+#define        SLAP_BFLAG_GLUE_INSTANCE        0x0010U /* a glue backend */
+#define        SLAP_BFLAG_GLUE_SUBORDINATE     0x0020U /* child of a glue hierarchy */
+#define        SLAP_BFLAG_GLUE_LINKED          0x0040U /* child is connected to parent */
+#define SLAP_BFLAG_ALIASES             0x0100U
+#define SLAP_BFLAG_REFERRALS   0x0200U
+#define SLAP_BFLAG_SUBENTRIES  0x0400U
+#define SLAP_BFLAG_MONITOR             0x1000U
+#define SLAP_BFLAG_DYNAMIC             0x2000U
+       slap_mask_t     be_flags;
+#define SLAP_LASTMOD(be)       (!((be)->be_flags & SLAP_BFLAG_NOLASTMOD))
+#define SLAP_ALIASES(be)       ((be)->be_flags & SLAP_BFLAG_ALIASES)
+#define SLAP_REFERRALS(be)     ((be)->be_flags & SLAP_BFLAG_REFERRALS)
+#define SLAP_SUBENTRIES(be)    ((be)->be_flags & SLAP_BFLAG_SUBENTRIES)
+#define SLAP_MONITOR(be)       ((be)->be_flags & SLAP_BFLAG_MONITOR)
+#define SLAP_DYNAMIC(be)       ((be)->be_flags & SLAP_BFLAG_DYNAMIC)
+
+       slap_mask_t     be_restrictops;         /* restriction operations */
+#define SLAP_RESTRICT_OP_ADD           0x0001U
+#define        SLAP_RESTRICT_OP_BIND           0x0002U
+#define SLAP_RESTRICT_OP_COMPARE       0x0004U
+#define SLAP_RESTRICT_OP_DELETE                0x0008U
+#define        SLAP_RESTRICT_OP_EXTENDED       0x0010U
+#define SLAP_RESTRICT_OP_MODIFY                0x0020U
+#define SLAP_RESTRICT_OP_RENAME                0x0040U
+#define SLAP_RESTRICT_OP_SEARCH                0x0080U
+
+#define SLAP_RESTRICT_OP_READS \
+       ( SLAP_RESTRICT_OP_COMPARE    \
+       | SLAP_RESTRICT_OP_SEARCH )
+#define SLAP_RESTRICT_OP_WRITES        \
+       ( SLAP_RESTRICT_OP_ADD    \
+       | SLAP_RESTRICT_OP_DELETE \
+       | SLAP_RESTRICT_OP_MODIFY \
+       | SLAP_RESTRICT_OP_RENAME )
+
+#define SLAP_ALLOW_BIND_V2                     0x0001U /* LDAPv2 bind */
+#define SLAP_ALLOW_BIND_ANON_CRED      0x0002U /* cred should be empty */
+#define SLAP_ALLOW_BIND_ANON_DN                0x0003U /* dn should be empty */
+
+#define SLAP_DISALLOW_BIND_ANON                0x0001U /* no anonymous */
+#define SLAP_DISALLOW_BIND_SIMPLE      0x0002U /* simple authentication */
+#define SLAP_DISALLOW_BIND_KRBV4       0x0004U /* Kerberos V4 authentication */
+
+#define SLAP_DISALLOW_TLS_2_ANON       0x0010U /* StartTLS -> Anonymous */
+#define SLAP_DISALLOW_TLS_AUTHC                0x0020U /* TLS while authenticated */
+
+       slap_mask_t     be_requires;    /* pre-operation requirements */
+#define SLAP_REQUIRE_BIND              0x0001U /* bind before op */
+#define SLAP_REQUIRE_LDAP_V3   0x0002U /* LDAPv3 before op */
+#define SLAP_REQUIRE_AUTHC             0x0004U /* authentication before op */
+#define SLAP_REQUIRE_SASL              0x0008U /* SASL before op  */
+#define SLAP_REQUIRE_STRONG            0x0010U /* strong authentication before op */
+
+       /* Required Security Strength Factor */
+       slap_ssf_set_t be_ssf_set;
+
+       /* these should be renamed from be_ to bd_ */
+       struct berval **be_suffix;      /* the DN suffixes of data in this backend */
+       struct berval **be_nsuffix;     /* the normalized DN suffixes in this backend */
+       struct berval **be_suffixAlias; /* pairs of DN suffix aliases and deref values */
+       struct berval be_rootdn;        /* the magic "root" name (DN) for this db */
+       struct berval be_rootndn;       /* the magic "root" normalized name (DN) for this db */
+       struct berval be_rootpw;        /* the magic "root" password for this db        */
+       unsigned int be_max_deref_depth;       /* limit for depth of an alias deref  */
+#define be_sizelimit   be_def_limit.lms_s_soft
+#define be_timelimit   be_def_limit.lms_t_soft
+       struct slap_limits_set be_def_limit; /* default limits */
+       struct slap_limits **be_limits; /* regex-based size and time limits */
+       AccessControl *be_acl;  /* access control list for this backend    */
+       slap_access_t   be_dfltaccess;  /* access given if no acl matches          */
+       struct slap_replica_info **be_replica;  /* replicas of this backend (in master) */
        char    *be_replogfile; /* replication log file (in master)        */
-       char    *be_updatedn;   /* allowed to make changes (in replicas)   */
-       int     be_lastmod;     /* keep track of lastmodified{by,time}     */
-       char    *be_type;       /* type of database                        */
-
-       void    *be_private;    /* anything the backend needs              */
-
-       IFP     be_bind;        /* backend bind routine                    */
-       IFP     be_unbind;      /* backend unbind routine                  */
-       IFP     be_search;      /* backend search routine                  */
-       IFP     be_compare;     /* backend compare routine                 */
-       IFP     be_modify;      /* backend modify routine                  */
-       IFP     be_modrdn;      /* backend modrdn routine                  */
-       IFP     be_add;         /* backend add routine                     */
-       IFP     be_delete;      /* backend delete routine                  */
-       IFP     be_abandon;     /* backend abandon routine                 */
-       IFP     be_config;      /* backend config routine                  */
-       IFP     be_init;        /* backend init routine                    */
-       IFP     be_close;       /* backend close routine                   */
-} Backend;
+       struct berval be_update_ndn;    /* allowed to make changes (in replicas) */
+       BerVarray       be_update_refs; /* where to refer modifying clients to */
+       char    *be_realm;
+       void    *be_private;    /* anything the backend database needs     */
+};
+
+struct slap_conn;
+struct slap_op;
+
+/* Backend function typedefs */
+typedef int (BI_init) LDAP_P((BackendInfo *bi));
+typedef int (BI_config) LDAP_P((BackendInfo *bi,
+       const char *fname, int lineno,
+       int argc, char **argv));
+typedef int (BI_open) LDAP_P((BackendInfo *bi));
+typedef int (BI_close) LDAP_P((BackendInfo *bi));
+typedef int (BI_destroy) LDAP_P((BackendInfo *bi));
+
+typedef int (BI_db_init) LDAP_P((Backend *bd));
+typedef int (BI_db_config) LDAP_P((Backend *bd,
+       const char *fname, int lineno,
+       int argc, char **argv));
+typedef int (BI_db_open) LDAP_P((Backend *bd));
+typedef int (BI_db_close) LDAP_P((Backend *bd));
+typedef int (BI_db_destroy) LDAP_P((Backend *bd));
+
+typedef int (BI_op_bind)  LDAP_P(( BackendDB *bd,
+               struct slap_conn *c, struct slap_op *o,
+               struct berval *dn, struct berval *ndn, int method,
+               struct berval *cred, struct berval *edn ));
+typedef int (BI_op_unbind) LDAP_P((BackendDB *bd,
+               struct slap_conn *c, struct slap_op *o ));
+typedef int (BI_op_search) LDAP_P((BackendDB *bd,
+               struct slap_conn *c, struct slap_op *o,
+               struct berval *base, struct berval *nbase,
+               int scope, int deref,
+               int slimit, int tlimit,
+               Filter *f, struct berval *filterstr,
+               AttributeName *attrs, int attrsonly));
+typedef int (BI_op_compare)LDAP_P((BackendDB *bd,
+               struct slap_conn *c, struct slap_op *o,
+               struct berval *dn, struct berval *ndn,
+               AttributeAssertion *ava));
+typedef int (BI_op_modify) LDAP_P((BackendDB *bd,
+               struct slap_conn *c, struct slap_op *o,
+               struct berval *dn, struct berval *ndn,
+               Modifications *m));
+typedef int (BI_op_modrdn) LDAP_P((BackendDB *bd,
+               struct slap_conn *c, struct slap_op *o,
+               struct berval *dn, struct berval *ndn,
+               struct berval *newrdn, struct berval *nnewrdn,
+               int deleteoldrdn,
+               struct berval *newSup, struct berval *nnewSup ));
+typedef int (BI_op_add)    LDAP_P((BackendDB *bd,
+               struct slap_conn *c, struct slap_op *o,
+               Entry *e));
+typedef int (BI_op_delete) LDAP_P((BackendDB *bd,
+               struct slap_conn *c, struct slap_op *o,
+               struct berval *dn, struct berval *ndn));
+typedef int (BI_op_abandon) LDAP_P((BackendDB *bd,
+               struct slap_conn *c, struct slap_op *o,
+               ber_int_t msgid));
+
+typedef int (BI_op_extended) LDAP_P((
+    BackendDB          *be,
+    struct slap_conn   *conn,
+    struct slap_op             *op,
+       const char              *reqoid,
+    struct berval * reqdata,
+       char            **rspoid,
+    struct berval ** rspdata,
+       LDAPControl *** rspctrls,
+       const char **   text,
+       BerVarray *refs ));
+
+typedef int (BI_entry_release_rw) LDAP_P((BackendDB *bd,
+               struct slap_conn *c, struct slap_op *o,
+               Entry *e, int rw));
+
+typedef int (BI_chk_referrals) LDAP_P((BackendDB *bd,
+               struct slap_conn *c, struct slap_op *o,
+               struct berval *dn, struct berval *ndn,
+               const char **text ));
+
+typedef int (BI_acl_group)  LDAP_P((Backend *bd,
+               struct slap_conn *c, struct slap_op *o,
+               Entry *e,
+               struct berval *bdn,
+               struct berval *edn,
+               ObjectClass *group_oc,
+               AttributeDescription *group_at ));
+
+typedef int (BI_acl_attribute)  LDAP_P((Backend *bd,
+               struct slap_conn *c, struct slap_op *o,
+               Entry *e, struct berval *edn,
+               AttributeDescription *entry_at,
+               BerVarray *vals ));
+
+typedef int (BI_operational)  LDAP_P((Backend *bd,
+               struct slap_conn *c, struct slap_op *o,
+               Entry *e, AttributeName *attrs, int opattrs, Attribute **a ));
+
+typedef int (BI_connection_init) LDAP_P((BackendDB *bd,
+               struct slap_conn *c));
+typedef int (BI_connection_destroy) LDAP_P((BackendDB *bd,
+               struct slap_conn *c));
+
+typedef int (BI_tool_entry_open) LDAP_P(( BackendDB *be, int mode ));
+typedef int (BI_tool_entry_close) LDAP_P(( BackendDB *be ));
+typedef ID (BI_tool_entry_first) LDAP_P(( BackendDB *be ));
+typedef ID (BI_tool_entry_next) LDAP_P(( BackendDB *be ));
+typedef Entry* (BI_tool_entry_get) LDAP_P(( BackendDB *be, ID id ));
+typedef ID (BI_tool_entry_put) LDAP_P(( BackendDB *be, Entry *e, 
+                       struct berval *text ));
+typedef int (BI_tool_entry_reindex) LDAP_P(( BackendDB *be, ID id ));
+typedef int (BI_tool_sync) LDAP_P(( BackendDB *be ));
+
+struct slap_backend_info {
+       char    *bi_type; /* type of backend */
+
+       /*
+        * per backend type routines:
+        * bi_init: called to allocate a backend_info structure,
+        *              called once BEFORE configuration file is read.
+        *              bi_init() initializes this structure hence is
+        *              called directly from be_initialize()
+        * bi_config: called per 'backend' specific option
+        *              all such options must before any 'database' options
+        *              bi_config() is called only from read_config()
+        * bi_open: called to open each database, called
+        *              once AFTER configuration file is read but
+        *              BEFORE any bi_db_open() calls.
+        *              bi_open() is called from backend_startup()
+        * bi_close: called to close each database, called
+        *              once during shutdown after all bi_db_close calls.
+        *              bi_close() is called from backend_shutdown()
+        * bi_destroy: called to destroy each database, called
+        *              once during shutdown after all bi_db_destroy calls.
+        *              bi_destory() is called from backend_destroy()
+        */
+       BI_init *bi_init;
+       BI_config       *bi_config;
+       BI_open *bi_open;
+       BI_close        *bi_close;
+       BI_destroy      *bi_destroy;
+
+       /*
+        * per database routines:
+        * bi_db_init: called to initialize each database,
+        *      called upon reading 'database <type>' 
+        *      called only from backend_db_init()
+        * bi_db_config: called to configure each database,
+        *  called per database to handle per database options
+        *      called only from read_config()
+        * bi_db_open: called to open each database
+        *      called once per database immediately AFTER bi_open()
+        *      calls but before daemon startup.
+        *  called only by backend_startup()
+        * bi_db_close: called to close each database
+        *      called once per database during shutdown but BEFORE
+        *  any bi_close call.
+        *  called only by backend_shutdown()
+        * bi_db_destroy: called to destroy each database
+        *  called once per database during shutdown AFTER all
+        *  bi_close calls but before bi_destory calls.
+        *  called only by backend_destory()
+        */
+       BI_db_init      *bi_db_init;
+       BI_db_config    *bi_db_config;
+       BI_db_open      *bi_db_open;
+       BI_db_close     *bi_db_close;
+       BI_db_destroy   *bi_db_destroy;
+
+       /* LDAP Operations Handling Routines */
+       BI_op_bind      *bi_op_bind;
+       BI_op_unbind    *bi_op_unbind;
+       BI_op_search    *bi_op_search;
+       BI_op_compare   *bi_op_compare;
+       BI_op_modify    *bi_op_modify;
+       BI_op_modrdn    *bi_op_modrdn;
+       BI_op_add       *bi_op_add;
+       BI_op_delete    *bi_op_delete;
+       BI_op_abandon   *bi_op_abandon;
+
+       /* Extended Operations Helper */
+       BI_op_extended  *bi_extended;
+
+       /* Auxilary Functions */
+       BI_entry_release_rw     *bi_entry_release_rw;
+       BI_chk_referrals        *bi_chk_referrals;
+
+       BI_acl_group    *bi_acl_group;
+       BI_acl_attribute        *bi_acl_attribute;
+
+       BI_operational  *bi_operational;
+
+       BI_connection_init      *bi_connection_init;
+       BI_connection_destroy   *bi_connection_destroy;
+
+       /* hooks for slap tools */
+       BI_tool_entry_open      *bi_tool_entry_open;
+       BI_tool_entry_close     *bi_tool_entry_close;
+       BI_tool_entry_first     *bi_tool_entry_first;
+       BI_tool_entry_next      *bi_tool_entry_next;
+       BI_tool_entry_get       *bi_tool_entry_get;
+       BI_tool_entry_put       *bi_tool_entry_put;
+       BI_tool_entry_reindex   *bi_tool_entry_reindex;
+       BI_tool_sync            *bi_tool_sync;
+
+#define SLAP_INDEX_ADD_OP              0x0001
+#define SLAP_INDEX_DELETE_OP   0x0002
+
+       char **bi_controls;             /* supported controls */
+
+       unsigned int bi_nDB;    /* number of databases of this type */
+       void    *bi_private;    /* anything the backend type needs */
+};
+
+#define c_authtype     c_authz.sai_method
+#define c_authmech     c_authz.sai_mech
+#define c_dn           c_authz.sai_dn
+#define c_ndn          c_authz.sai_ndn
+#define c_ssf                  c_authz.sai_ssf
+#define c_transport_ssf        c_authz.sai_transport_ssf
+#define c_tls_ssf              c_authz.sai_tls_ssf
+#define c_sasl_ssf             c_authz.sai_sasl_ssf
+
+#define o_authtype     o_authz.sai_method
+#define o_authmech     o_authz.sai_mech
+#define o_dn           o_authz.sai_dn
+#define o_ndn          o_authz.sai_ndn
+#define o_ssf                  o_authz.sai_ssf
+#define o_transport_ssf        o_authz.sai_transport_ssf
+#define o_tls_ssf              o_authz.sai_tls_ssf
+#define o_sasl_ssf             o_authz.sai_sasl_ssf
+
+typedef void (slap_response)( struct slap_conn *, struct slap_op *,
+       ber_tag_t, ber_int_t, ber_int_t, const char *, const char *,
+       BerVarray, const char *, struct berval *,
+       struct berval *, LDAPControl ** );
+
+typedef void (slap_sresult)( struct slap_conn *, struct slap_op *,
+       ber_int_t, const char *, const char *, BerVarray,
+       LDAPControl **, int nentries);
+
+typedef int (slap_sendentry)( BackendDB *, struct slap_conn *,
+       struct slap_op *, Entry *, AttributeName *, int, LDAPControl **);
+
+typedef struct slap_callback {
+       slap_response *sc_response;
+       slap_sresult *sc_sresult;
+       slap_sendentry *sc_sendentry;
+       void *sc_private;
+} slap_callback;
 
 /*
  * represents an operation pending from an ldap client
  */
-
-typedef struct op {
-       BerElement      *o_ber;         /* ber of the request             */
-       long            o_msgid;        /* msgid of the request           */
-       unsigned long   o_tag;          /* tag of the request             */
+typedef struct slap_op {
+       ber_int_t       o_opid;         /* id of this operation           */
+       ber_int_t       o_msgid;        /* msgid of the request           */
+       ber_int_t       o_protocol;     /* version of the LDAP protocol used by client */
+       ber_tag_t       o_tag;          /* tag of the request             */
        time_t          o_time;         /* time op was initiated          */
-       char            *o_dn;          /* dn bound when op was initiated */
-       int             o_authtype;     /* auth method used to bind dn    */
-                                       /* values taken from ldap.h       */
-                                       /* LDAP_AUTH_*                    */
-       int             o_opid;         /* id of this operation           */
-       int             o_connid;       /* id of conn initiating this op  */
-#ifdef CLDAP
-       int             o_cldap;        /* != 0 if this came in via CLDAP */
-       struct sockaddr o_clientaddr;   /* client address if via CLDAP    */
-       char            o_searchbase;   /* search base if via CLDAP       */
+       unsigned long   o_connid; /* id of conn initiating this op  */
+       ldap_pvt_thread_t       o_tid;  /* thread handling this op        */
+
+#define SLAP_NO_CONTROL 0
+#define SLAP_NONCRITICAL_CONTROL 1
+#define SLAP_CRITICAL_CONTROL 2
+       char o_managedsait;
+       char o_subentries;
+       char o_subentries_visibility;
+       char o_noop;
+
+       char o_abandon; /* abandon flag */
+       ldap_pvt_thread_mutex_t o_abandonmutex; /* protects o_abandon  */
+
+#ifdef LDAP_CONNECTIONLESS
+       Sockaddr        o_peeraddr;     /* UDP peer address               */
 #endif
-       struct op       *o_next;        /* next operation pending         */
-       pthread_t       o_tid;          /* thread handling this op        */
-       int             o_abandon;      /* signals op has been abandoned  */
-       pthread_mutex_t o_abandonmutex; /* signals op has been abandoned  */
+       AuthorizationInformation o_authz;
+
+       BerElement      *o_ber;         /* ber of the request             */
+       slap_callback   *o_callback;    /* callback pointers */
+       LDAPControl     **o_ctrls;       /* controls */
 
-       int             o_private;      /* anything the backend needs     */
+       void    *o_private;     /* anything the backend needs */
+
+       LDAP_STAILQ_ENTRY(slap_op)      o_next; /* next operation in list         */
 } Operation;
 
+#define get_manageDSAit(op)                            ((int)(op)->o_managedsait)
+#define get_subentries(op)                             ((int)(op)->o_subentries)
+#define get_subentries_visibility(op)  ((int)(op)->o_subentries_visibility)
+
+/*
+ * Caches the result of a backend_group check for ACL evaluation
+ */
+typedef struct slap_gacl {
+       struct slap_gacl *ga_next;
+       Backend *ga_be;
+       ObjectClass *ga_oc;
+       AttributeDescription *ga_at;
+       int ga_res;
+       ber_len_t ga_len;
+       char ga_ndn[1];
+} GroupAssertion;
+
 /*
  * represents a connection from an ldap client
  */
+typedef struct slap_conn {
+       int                     c_struct_state; /* structure management state */
+       int                     c_conn_state;   /* connection state */
 
-typedef struct conn {
-       Sockbuf         c_sb;           /* ber connection stuff           */
-       char            *c_dn;          /* current DN bound to this conn  */
-       pthread_mutex_t c_dnmutex;      /* mutex for c_dn field           */
-       int             c_authtype;     /* auth method used to bind c_dn  */
-#ifdef COMPAT
-       int             c_version;      /* for compatibility w/2.0, 3.0   */
-#endif
-       char            *c_addr;        /* address of client on this conn */
-       char            *c_domain;      /* domain of client on this conn  */
-       Operation       *c_ops;         /* list of pending operations     */
-       pthread_mutex_t c_opsmutex;     /* mutex for c_ops list & stats   */
-       pthread_mutex_t c_pdumutex;     /* only one pdu written at a time */
-       pthread_cond_t  c_wcv;          /* used to wait for sd write-ready*/
-       int             c_gettingber;   /* in the middle of ber_get_next  */
-       BerElement      *c_currentber;  /* ber we're getting              */
-       int             c_writewaiter;  /* signals write-ready sd waiter  */
-       int             c_pduwaiters;   /* signals threads waiting 4 pdu  */
+       ldap_pvt_thread_mutex_t c_mutex; /* protect the connection */
+       Sockbuf         *c_sb;                  /* ber connection stuff           */
+
+       /* only can be changed by connect_init */
        time_t          c_starttime;    /* when the connection was opened */
-       int             c_connid;       /* id of this connection for stats*/
-       int             c_opsinitiated; /* # ops initiated/next op id     */
-       int             c_opscompleted; /* # ops completed                */
+       time_t          c_activitytime; /* when the connection was last used */
+       unsigned long           c_connid;       /* id of this connection for stats*/
+
+       struct berval   c_listener_url; /* listener URL */
+       struct berval   c_peer_domain;  /* DNS name of client */
+       struct berval   c_peer_name;    /* peer name (trans=addr:port) */
+       struct berval   c_sock_name;    /* sock name (trans=addr:port) */
+
+       /* only can be changed by binding thread */
+       int             c_sasl_bind_in_progress;        /* multi-op bind in progress */
+       struct berval   c_sasl_bind_mech;                       /* mech in progress */
+       struct berval   c_cdn;
+
+       /* authentication backend */
+       Backend *c_authc_backend;
+
+       /* authorization backend - normally same as c_authc_backend */
+       Backend *c_authz_backend;
+
+       AuthorizationInformation c_authz;
+       GroupAssertion *c_groups;
+
+       ber_int_t       c_protocol;     /* version of the LDAP protocol used by client */
+
+       LDAP_STAILQ_HEAD(c_o, slap_op) c_ops;   /* list of operations being processed */
+       LDAP_STAILQ_HEAD(c_po, slap_op) c_pending_ops;  /* list of pending operations */
+
+       ldap_pvt_thread_mutex_t c_write_mutex;  /* only one pdu written at a time */
+       ldap_pvt_thread_cond_t  c_write_cv;             /* used to wait for sd write-ready*/
+
+       BerElement      *c_currentber;  /* ber we're attempting to read */
+       int             c_writewaiter;  /* true if writer is waiting */
+
+#ifdef LDAP_CONNECTIONLESS
+       int     c_is_udp;               /* true if this is (C)LDAP over UDP */
+#endif
+#ifdef HAVE_TLS
+       int     c_is_tls;               /* true if this LDAP over raw TLS */
+       int     c_needs_tls_accept;     /* true if SSL_accept should be called */
+#endif
+       int             c_sasl_layers;   /* true if we need to install SASL i/o handlers */
+       void    *c_sasl_context;        /* SASL session context */
+       void    *c_sasl_extra;          /* SASL session extra stuff */
+
+       long    c_n_ops_received;       /* num of ops received (next op_id) */
+       long    c_n_ops_executing;      /* num of ops currently executing */
+       long    c_n_ops_pending;        /* num of ops pending execution */
+       long    c_n_ops_completed;      /* num of ops completed */
+
+       long    c_n_get;                /* num of get calls */
+       long    c_n_read;               /* num of read calls */
+       long    c_n_write;              /* num of write calls */
 } Connection;
 
 #if defined(LDAP_SYSLOG) && defined(LDAP_DEBUG)
 #define Statslog( level, fmt, connid, opid, arg1, arg2, arg3 ) \
-       { \
-               if ( ldap_debug & level ) \
-                       fprintf( stderr, fmt, connid, opid, arg1, arg2, arg3 );\
-               if ( ldap_syslog & level ) \
-                       syslog( ldap_syslog_level, fmt, connid, opid, arg1, \
-                           arg2, arg3 ); \
-       }
+       do { \
+               if ( ldap_debug & (level) ) \
+                       fprintf( stderr, (fmt), (connid), (opid), (arg1), (arg2), (arg3) );\
+               if ( ldap_syslog & (level) ) \
+                       syslog( ldap_syslog_level, (fmt), (connid), (opid), (arg1), \
+                               (arg2), (arg3) ); \
+       } while (0)
 #else
 #define Statslog( level, fmt, connid, opid, arg1, arg2, arg3 )
 #endif
 
-#ifdef NEEDPROTOS
-#include "proto-slap.h"
+
+#define SASLREGEX_REPLACE 10
+#define SASL_AUTHZ_SOURCE_ATTR "saslAuthzTo"
+#define SASL_AUTHZ_DEST_ATTR "saslAuthzFrom"
+
+typedef struct sasl_regexp {
+  char *sr_match;                                                      /* regexp match pattern */
+  char *sr_replace;                                                    /* regexp replace pattern */
+  regex_t sr_workspace;                                                /* workspace for regexp engine */
+  regmatch_t sr_strings[SASLREGEX_REPLACE];    /* strings matching $1,$2 ... */
+  int sr_offset[SASLREGEX_REPLACE+2];          /* offsets of $1,$2... in *replace */
+} SaslRegexp_t;
+
+/*
+ * listener; need to access it from monitor backend
+ */
+typedef struct slap_listener {
+       char* sl_url;
+       char* sl_name;
+#ifdef HAVE_TLS
+       int             sl_is_tls;
 #endif
+#ifdef LDAP_CONNECTIONLESS
+       int     sl_is_udp;              /* UDP listener is also data port */
+#endif
+       ber_socket_t sl_sd;
+       Sockaddr sl_sa;
+#define sl_addr        sl_sa.sa_in_addr
+} Listener;
+
+LDAP_END_DECL
+
+#include "proto-slap.h"
 
-#endif /* _slap_h_ */
+#endif /* _SLAP_H_ */
diff --git a/tests/data/slapd-schema.conf b/tests/data/slapd-schema.conf
new file mode 100644 (file)
index 0000000..3bc338e
--- /dev/null
@@ -0,0 +1,36 @@
+# $OpenLDAP$
+#
+# stand-alone slapd config -- for testing
+#      with indexing
+#
+ucdata-path    ./ucdata
+#
+include ./schema/core.schema
+include ./schema/cosine.schema
+#
+include ./schema/corba.schema
+include ./schema/java.schema
+include ./schema/inetorgperson.schema
+include ./schema/krb5-kdc.schema
+include ./schema/misc.schema
+include ./schema/nis.schema
+include ./schema/openldap.schema
+#
+schemacheck    on
+pidfile     ./test-db/slapd.pid
+argsfile    ./test-db/slapd.args
+
+#######################################################################
+# ldbm database definitions
+#######################################################################
+
+database       @BACKEND@
+suffix         "o=OpenLDAP Project,l=Internet"
+directory      ./test-db
+#ldbm#index            objectClass eq
+#bdb#index             objectClass eq
+
+#database      @BACKEND@
+#suffix                "dc=example,dc=com"
+#directory     ./test-repl
+#index         objectClass eq