]> git.sur5r.net Git - openldap/commitdiff
LDAPv3 Referrals (using old style referral entries) initial commit.
authorKurt Zeilenga <kurt@openldap.org>
Fri, 9 Jul 1999 18:31:10 +0000 (18:31 +0000)
committerKurt Zeilenga <kurt@openldap.org>
Fri, 9 Jul 1999 18:31:10 +0000 (18:31 +0000)
Have not completed work on backends other than LDBM.
All send_() routines have new parameters (which will likely change
some more to support responses with controls).
slapd/back-ldbm only compiles.  NOT TESTED.  This is a work in progress.

33 files changed:
include/ldap.h
servers/slapd/abandon.c
servers/slapd/add.c
servers/slapd/back-bdb2/search.c [new file with mode: 0644]
servers/slapd/back-ldap/search.c [new file with mode: 0644]
servers/slapd/back-ldbm/add.c
servers/slapd/back-ldbm/alias.c [new file with mode: 0644]
servers/slapd/back-ldbm/bind.c
servers/slapd/back-ldbm/compare.c
servers/slapd/back-ldbm/delete.c
servers/slapd/back-ldbm/modify.c
servers/slapd/back-ldbm/modrdn.c
servers/slapd/back-ldbm/search.c
servers/slapd/bind.c
servers/slapd/charray.c
servers/slapd/compare.c
servers/slapd/config.c
servers/slapd/configinfo.c
servers/slapd/controls.c [new file with mode: 0644]
servers/slapd/delete.c
servers/slapd/extended.c [new file with mode: 0644]
servers/slapd/init.c
servers/slapd/modify.c
servers/slapd/modrdn.c
servers/slapd/monitor.c
servers/slapd/proto-slap.h
servers/slapd/result.c
servers/slapd/root_dse.c [new file with mode: 0644]
servers/slapd/schema.c
servers/slapd/schema/core.schema [new file with mode: 0644]
servers/slapd/search.c
servers/slapd/slapd.dsw [new file with mode: 0644]
servers/slapd/tools/mimic.c [new file with mode: 0644]

index 1eab5bda62322dce07c67affdfe65f8db84eaa2c..876607e5bb203b1ffbea876b9e16185ab994a4e5 100644 (file)
@@ -1,4 +1,13 @@
 /*
+ * Copyright 1998,1999 The OpenLDAP Foundation, Redwood City, California, USA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms 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
-
+#include <ldap_cdefs.h>
 
-#ifdef WINSOCK
-#include "msdos.h"
-#include <winsock.h>
-#endif
+/* draft spec requires ldap.h include lber declarations */
+#include <lber.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       2003
+#define LDAP_VENDOR_NAME       "OpenLDAP"
+/* We'll eventually release as 200 */
+#define LDAP_VENDOR_VERSION    192
+
+/* OpenLDAP API Features */
+#define LDAP_API_FEATURE_X_OPENLDAP LDAP_VENDOR_VERSION
+
+/* include LDAP_API_FEATURE defines */
+#include <ldap_features.h>
+
+#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
+
+#define LDAP_ROOT_DSE                          ""
+#define LDAP_NO_ATTRS                          "1.1"
+#define LDAP_ALL_USER_ATTRIBUTES       "*"
+
+/*
+ * 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
+#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
+
+/* 0x33 - 0x0fff not defined by current draft */
+
+/* extended options - none */
+
+/* private and experimental options */
+#define LDAP_OPT_DNS                           0x4001  /* use DN & DNS */
+
+/* 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_MATCHED_DN                    0x5004  /* should have been in draft */
+
+/* on/off values */
+#define LDAP_OPT_ON            ((void *) 1)
+#define LDAP_OPT_OFF   ((void *) 0)
+
+#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 */
+       /* chase referrals controls */
+#define LDAP_CONTROL_REFERRALS "1.2.840.113666.1.4.616"
+#define LDAP_CHASE_SUBORDINATE_REFERRALS       0x0020
+#define LDAP_CHASE_EXTERNAL_REFERRALS  0x0040
+
+#define LDAP_CONTROL_MANAGEDSAIT "2.16.16.840.1.113730.3.4.2"
+
+/* LDAP Unsolicited Notifications */
+#define        LDAP_NOTICE_DISCONNECT  "1.3.6.1.4.1.1466.20036"
+
+/* LDAP Extended Operations */
 
-/* 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 */
 
 /* 
  * 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       /* octect string */
+#define LDAP_TAG_LDAPCRED      (ber_tag_t) 0x04U       /* octect 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 */
 
-/* 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
+#define LDAP_TAG_NEWSUPERIOR   (ber_tag_t) 0x80U       /* context-specific + primitive + 0 */
 
-/* 
- * 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_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                  (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_MODRDN                        (ber_tag_t) 0x6cU       /* application + constructed */
+#define LDAP_REQ_MODDN                 LDAP_REQ_MODRDN 
+#define LDAP_REQ_RENAME                        LDAP_REQ_MODRDN 
+#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_MODRDN                        (ber_tag_t) 0x6dU       /* application + constructed */
+#define LDAP_RES_MODDN                 LDAP_RES_MODRDN /* application + constructed */
+#define LDAP_RES_RENAME                        LDAP_RES_MODRDN /* 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_ANY                   ((ber_tag_t)(~0))
+
+
+/* sasl methods */
+#define LDAP_SASL_SIMPLE                       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 + primitive   */
+#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_EXTENDED   (ber_tag_t) 0xa9U       /* context specific + constructed */
+
+/* extended filter component types */
+#define LDAP_FILTER_EXTENDED_OID       (ber_tag_t) 0x81U       /* context specific */
+#define LDAP_FILTER_EXTENDED_TYPE      (ber_tag_t) 0x82U       /* context specific */
+#define LDAP_FILTER_EXTENDED_VALUE     (ber_tag_t) 0x83U       /* context specific */
+#define LDAP_FILTER_EXTENDED_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_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
+#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)
+ * JCG 05/1999 (gomez@engr.sgi.com)
+ */
        char            *mod_type;
-       union {
+       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
-       struct ldapmod  *mod_next;
 } LDAPMod;
 
 /* 
  * 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 +300,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    /* not listed in v3 */
+
+#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 +320,42 @@ 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,0xff) /* 81+ */
+
 #define LDAP_SERVER_DOWN               0x51
 #define LDAP_LOCAL_ERROR               0x52
 #define LDAP_ENCODING_ERROR            0x53
@@ -279,9 +367,13 @@ typedef struct ldapmod {
 #define LDAP_PARAM_ERROR               0x59
 #define LDAP_NO_MEMORY                 0x5a
 
-
-/* default limit on nesting of referrals */
-#define LDAP_DEFAULT_REFHOPLIMIT       5
+#define LDAP_CONNECT_ERROR                             0x5b    /* new */
+#define LDAP_NOT_SUPPORTED                             0x5c    /* new */
+#define LDAP_CONTROL_NOT_FOUND                 0x5d    /* new */
+#define LDAP_NO_RESULTS_RETURNED               0x5e    /* new */
+#define LDAP_MORE_RESULTS_TO_RETURN            0x5f    /* new */
+#define LDAP_CLIENT_LOOP                               0x60    /* new */
+#define LDAP_REFERRAL_LIMIT_EXCEEDED   0x61    /* new */
 
 /*
  * This structure represents both ldap messages and ldap responses.
@@ -289,89 +381,7 @@ 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;
 
 /*
  * structures for ldap getfilter routines
@@ -413,85 +423,28 @@ typedef struct ldap_filt_desc {
  * structure representing an ldap connection
  */
 
-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
+typedef struct ldap LDAP;
 
-       int             ld_timelimit;
-       int             ld_sizelimit;
-#define LDAP_NO_LIMIT          0
+#define LDAP_DEREF_NEVER       0x00
+#define LDAP_DEREF_SEARCHING   0x01
+#define LDAP_DEREF_FINDING     0x02
+#define LDAP_DEREF_ALWAYS      0x03
 
-       LDAPFiltDesc    *ld_filtd;      /* from getfilter for ufn searches */
-       char            *ld_ufnprefix;  /* for incomplete ufn's */
-
-       int             ld_errno;
-       char            *ld_error;
-       char            *ld_matched;
-       int             ld_msgid;
-
-       /* 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 */
-
-       /* 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 */
-
-       /* 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;
+#define LDAP_NO_LIMIT          0
 
+/* how many messages to retrieve results for */
+#define LDAP_MSG_ONE           0x00
+#define LDAP_MSG_ALL           0x01
+#define LDAP_MSG_RECEIVED      0x02
 
 /*
  * structure for ldap friendly mapping routines
  */
 
-typedef struct friendly {
-       char    *f_unfriendly;
-       char    *f_friendly;
-} FriendlyMap;
-
-
-/*
- * handy macro to check whether LDAP struct is set up for CLDAP or not
- */
-#define LDAP_IS_CLDAP( ld )    ( ld->ld_sb.sb_naddr > 0 )
-
+typedef struct ldap_friendly {
+       char    *lf_unfriendly;
+       char    *lf_friendly;
+} LDAPFriendlyMap;
 
 /*
  * types for ldap URL handling
@@ -505,88 +458,1029 @@ typedef struct ldap_url_desc {
     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
 
-#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
+#define LDAP_URL_ERR_NOTLDAP   0x01    /* URL doesn't begin with "ldap://" */
+#define LDAP_URL_ERR_NODN              0x02    /* URL has no DN (required) */
+#define LDAP_URL_ERR_BADSCOPE  0x03    /* URL scope string is invalid */
+#define LDAP_URL_ERR_MEM               0x04    /* can't allocate memory space */
 
-#ifdef VMS
-extern char *strdup( const char *s );
-#endif
-#if defined(ultrix) || defined( nextstep )
-extern char *strdup();
-#endif
+/*
+ * The API draft spec says we should declare (or cause to be declared)
+ * 'struct timeval'.   We don't.  See LDAPext discussions.
+ */
+struct timeval;
 
-#endif /* NEEDPROTOS */
+/*
+ * in options.c:
+ */
+LDAP_F( int )
+ldap_get_option LDAP_P((
+       LDAP_CONST LDAP *ld,
+       int option,
+       void *outvalue));
+
+LDAP_F( int )
+ldap_set_option LDAP_P((
+       LDAP *ld,
+       int option,
+       LDAP_CONST void *invalue));
+
+
+/*
+ * in controls.c:
+ */
+LDAP_F( void )
+ldap_control_free LDAP_P((
+       LDAPControl *ctrl ));
+
+LDAP_F( void )
+ldap_controls_free LDAP_P((
+       LDAPControl **ctrls ));
+
+  
+/*
+ * in extended.c:
+ */
+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 ));
+
+/*
+ * in abandon.c:
+ */
+LDAP_F( int )
+ldap_abandon LDAP_P((
+       LDAP *ld,
+       int msgid ));
+
+LDAP_F( int )
+ldap_abandon_ext LDAP_P((
+       LDAP                    *ld,
+       int                             msgid,
+       LDAPControl             **serverctrls,
+       LDAPControl             **clientctrls ));
+
+
+/*
+ * 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((
+       LDAP *ld,
+       LDAP_CONST char *dn,
+       LDAPMod **attrs ));
+
+LDAP_F( int )
+ldap_add_s LDAP_P((
+       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 ));
+
+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((
+       LDAP *ld,
+       LDAP_CONST char *who,
+       LDAP_CONST char *passwd,
+       int authmethod ));
+
+LDAP_F( int )
+ldap_bind_s LDAP_P((
+       LDAP *ld,
+       LDAP_CONST char *who,
+       LDAP_CONST char *cred,
+       int authmethod ));
+
+LDAP_F( void )
+ldap_set_rebind_proc LDAP_P((
+       LDAP *ld,
+       int (*rebindproc) LDAP_P((
+               LDAP *ld,
+               char **dnp,
+               char **passwdp,
+               int *authmethodp,
+               int freeit ))));
+
+
+/*
+ * 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((
+       LDAP *ld,
+       LDAP_CONST char *who ));
+
+LDAP_F( int )
+ldap_kerberos_bind1 LDAP_P((
+       LDAP *ld,
+       LDAP_CONST char *who ));
+
+LDAP_F( int )
+ldap_kerberos_bind1_s LDAP_P((
+       LDAP *ld,
+       LDAP_CONST char *who ));
+
+LDAP_F( int )
+ldap_kerberos_bind2 LDAP_P((
+       LDAP *ld,
+       LDAP_CONST char *who ));
+
+LDAP_F( int )
+ldap_kerberos_bind2_s LDAP_P((
+       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((
+       LDAP *ld,
+       LDAP_CONST char *dn,
+       LDAP_CONST char *attr,
+       LDAP_CONST char *value ));
+
+LDAP_F( int )
+ldap_compare_s LDAP_P((
+       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((
+       LDAP *ld,
+       LDAP_CONST char *dn ));
+
+LDAP_F( int )
+ldap_delete_s LDAP_P((
+       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((
+       LDAP *ld,
+       LDAP_CONST char *dn,
+       LDAPMod **mods ));
+
+LDAP_F( int )
+ldap_modify_s LDAP_P((
+       LDAP *ld,
+       LDAP_CONST char *dn,
+       LDAPMod **mods ));
+
+
+/*
+ * in modrdn.c:
+ */
+LDAP_F( int )
+ldap_rename_ext LDAP_P((
+       LDAP                    *ld,
+       LDAP_CONST char *dn,
+       LDAP_CONST char *newrdn,
+       LDAP_CONST char *newparent,
+       int                             deleteoldrdn,
+       LDAPControl             **serverctrls,
+       LDAPControl             **clientctrls,
+       int                     *msgidp ));
+
+LDAP_F( int )
+ldap_rename_ext_s LDAP_P((
+       LDAP                    *ld,
+       LDAP_CONST char *dn,
+       LDAP_CONST char *newrdn,
+       LDAP_CONST char *newparent,
+       int                             deleteoldrdn,
+       LDAPControl             **serverctrls,
+       LDAPControl             **clientctrls ));
+
+LDAP_F( int )
+ldap_rename2 LDAP_P((
+       LDAP *ld,
+       LDAP_CONST char *dn,
+       LDAP_CONST char *newrdn,
+       int deleteoldrdn,
+       LDAP_CONST char *newSuperior ));
+
+LDAP_F( int )
+ldap_rename2_s LDAP_P((
+       LDAP *ld,
+       LDAP_CONST char *dn,
+       LDAP_CONST char *newrdn,
+       int deleteoldrdn,
+       LDAP_CONST char *newSuperior));
+
+LDAP_F( int )
+ldap_modrdn LDAP_P((
+       LDAP *ld,
+       LDAP_CONST char *dn,
+       LDAP_CONST char *newrdn ));
+
+LDAP_F( int )
+ldap_modrdn_s LDAP_P((
+       LDAP *ld,
+       LDAP_CONST char *dn,
+       LDAP_CONST char *newrdn ));
+
+LDAP_F( int )
+ldap_modrdn2 LDAP_P((
+       LDAP *ld,
+       LDAP_CONST char *dn,
+       LDAP_CONST char *newrdn,
+       int deleteoldrdn ));
+
+LDAP_F( int )
+ldap_modrdn2_s LDAP_P((
+       LDAP *ld,
+       LDAP_CONST char *dn,
+       LDAP_CONST char *newrdn,
+       int deleteoldrdn));
+
+
+/*
+ * in open.c:
+ */
+LDAP_F( LDAP *)
+ldap_open LDAP_P((
+       LDAP_CONST char *host,
+       int port ));
+
+LDAP_F( LDAP *)
+ldap_init LDAP_P((
+       LDAP_CONST char *host,
+       int port ));
+
+
+/*
+ * 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 ));
+
+LDAP_F( char *)
+ldap_dn2ufn LDAP_P((
+       LDAP_CONST char *dn ));
+
+LDAP_F( char **)
+ldap_explode_dn LDAP_P((
+       LDAP_CONST char *dn,
+       int notypes ));
+
+LDAP_F( char **)
+ldap_explode_rdn LDAP_P((
+       LDAP_CONST char *rdn,
+       int notypes ));
+
+LDAP_F( char *)
+ldap_parent_dn LDAP_P((        /* new (from slapd) */
+       LDAP_CONST char *dn ));
+
+LDAP_F( char *)
+ldap_relative_dn LDAP_P((      /* new (from slapd) */
+       LDAP_CONST char *dn ));
+
+LDAP_F( char *)
+ldap_normalize_dn LDAP_P((     /* new (from slapd) */
+       LDAP_CONST char *dn ));
+
+LDAP_F( char **)
+ldap_explode_dns LDAP_P(( /* deprecated */
+       LDAP_CONST char *dn ));
+
+LDAP_F( int )
+ldap_is_dns_dn LDAP_P((        /* deprecated */
+       LDAP_CONST char *dn ));
+
+
+/*
+ * 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( char **)
+ldap_get_values LDAP_P((
+       LDAP *ld,
+       LDAPMessage *entry,
+       LDAP_CONST char *target ));
+
+LDAP_F( struct berval **)
+ldap_get_values_len LDAP_P((
+       LDAP *ld,
+       LDAPMessage *entry,
+       LDAP_CONST char *target ));
+
+LDAP_F( int )
+ldap_count_values LDAP_P((
+       char **vals ));
+
+LDAP_F( int )
+ldap_count_values_len LDAP_P((
+       struct berval **vals ));
+
+LDAP_F( void )
+ldap_value_free LDAP_P((
+       char **vals ));
+
+LDAP_F( void )
+ldap_value_free_len LDAP_P((
+       struct berval **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((
+       LDAP *ld,
+       LDAP_CONST char *base,
+       int scope,
+       LDAP_CONST char *filter,
+       char **attrs,
+       int attrsonly ));
+
+LDAP_F( int )
+ldap_search_s LDAP_P((
+       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((                                                         
+       LDAP *ld,
+       LDAP_CONST char *base,
+       int scope,
+       LDAP_CONST char *filter,
+    char **attrs,
+       int attrsonly,
+       struct timeval *timeout,
+       LDAPMessage **res ));
+
+
+/*
+ * in ufn.c
+ */
+LDAP_F( int )
+ldap_ufn_search_c LDAP_P((
+       LDAP *ld,
+       LDAP_CONST char *ufn,
+       char **attrs,
+       int attrsonly,
+       LDAPMessage **res,
+       int (*cancelproc)( void *cl ),
+       void *cancelparm ));
+
+LDAP_F( int )
+ldap_ufn_search_ct LDAP_P((
+       LDAP *ld,
+       LDAP_CONST char *ufn,
+       char **attrs,
+       int attrsonly,
+       LDAPMessage **res,
+       int (*cancelproc)( void *cl ),
+       void *cancelparm,
+       char *tag1,
+       char *tag2,
+       char *tag3 ));
+
+LDAP_F( int )
+ldap_ufn_search_s LDAP_P((
+       LDAP *ld,
+       LDAP_CONST char *ufn,
+       char **attrs,
+       int attrsonly,
+       LDAPMessage **res ));
+
+LDAP_F( LDAPFiltDesc *)
+ldap_ufn_setfilter LDAP_P((
+       LDAP *ld,
+       LDAP_CONST char *fname ));
+
+LDAP_F( void )
+ldap_ufn_setprefix LDAP_P((
+       LDAP *ld,
+       LDAP_CONST char *prefix ));
+
+LDAP_F( int )
+ldap_ufn_timeout LDAP_P((
+       void *tvparam ));
+
+
+/*
+ * in unbind.c
+ */
+LDAP_F( int )
+ldap_unbind LDAP_P((
+       LDAP *ld ));
+
+LDAP_F( int )
+ldap_unbind_s LDAP_P((
+       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
+ */
+LDAP_F( LDAPFiltDesc *)
+ldap_init_getfilter LDAP_P((
+       LDAP_CONST char *fname ));
+
+LDAP_F( LDAPFiltDesc *)
+ldap_init_getfilter_buf LDAP_P((
+       /* LDAP_CONST */ char *buf,
+       ber_len_t buflen ));
+
+LDAP_F( LDAPFiltInfo *)
+ldap_getfirstfilter LDAP_P((
+       LDAPFiltDesc *lfdp,
+       /* LDAP_CONST */ char *tagpat,
+       /* LDAP_CONST */ char *value ));
+
+LDAP_F( LDAPFiltInfo *)
+ldap_getnextfilter LDAP_P((
+       LDAPFiltDesc *lfdp ));
+
+LDAP_F( void )
+ldap_setfilteraffixes LDAP_P((
+       LDAPFiltDesc *lfdp,
+       LDAP_CONST char *prefix,
+       LDAP_CONST char *suffix ));
+
+LDAP_F( void )
+ldap_build_filter LDAP_P((
+       char *buf,
+       ber_len_t buflen,
+       LDAP_CONST char *pattern,
+       LDAP_CONST char *prefix,
+       LDAP_CONST char *suffix,
+       LDAP_CONST char *attr,
+       LDAP_CONST char *value,
+       char **valwords ));
+
+
+/*
+ * 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 friendly.c
+ */
+LDAP_F( char * )
+ldap_friendly_name LDAP_P((
+       LDAP_CONST char *filename,
+       /* LDAP_CONST */ char *uname,
+       LDAPFriendlyMap **map ));
+
+LDAP_F( void )
+ldap_free_friendlymap LDAP_P((
+       LDAPFriendlyMap **map ));
+
+
+/*
+ * in cldap.c
+ */
+LDAP_F( LDAP * )
+cldap_open LDAP_P((
+       LDAP_CONST char *host,
+       int port ));
+
+LDAP_F( void )
+cldap_close LDAP_P((
+       LDAP *ld ));
+
+LDAP_F( int )
+cldap_search_s LDAP_P(( LDAP *ld,
+       LDAP_CONST char *base,
+       int scope,
+       LDAP_CONST char *filter,
+       char **attrs,
+       int attrsonly,
+       LDAPMessage **res,
+       char *logdn ));
+
+LDAP_F( void )
+cldap_setretryinfo LDAP_P((
+       LDAP *ld,
+       int tries,
+       int timeout ));
+
+
+/*
+ * in sort.c
+ */
+LDAP_F( int )
+ldap_sort_entries LDAP_P(( LDAP *ld,
+       LDAPMessage **chain,
+       LDAP_CONST char *attr,
+       int (*cmp) (LDAP_CONST char *, LDAP_CONST char *) ));
+
+LDAP_F( int )
+ldap_sort_values LDAP_P((
+       LDAP *ld,
+       char **vals,
+       int (*cmp) (LDAP_CONST void *, LDAP_CONST void *) ));
+
+LDAP_F( int )
+ldap_sort_strcasecmp LDAP_P((
+       LDAP_CONST void *a,
+       LDAP_CONST void *b ));
+
+
+/*
+ * in url.c
+ *
+ * need _ext varients
+ */
+LDAP_F( int )
+ldap_is_ldap_url LDAP_P((
+       LDAP_CONST char *url ));
+
+LDAP_F( int )
+ldap_url_parse LDAP_P((
+       LDAP_CONST char *url,
+       LDAPURLDesc **ludpp ));
+
+LDAP_F( void )
+ldap_free_urldesc LDAP_P((
+       LDAPURLDesc *ludp ));
+
+LDAP_F( int )
+ldap_url_search LDAP_P((
+       LDAP *ld,
+       LDAP_CONST char *url,
+       int attrsonly ));
+
+LDAP_F( int )
+ldap_url_search_s LDAP_P((
+       LDAP *ld,
+       LDAP_CONST char *url,
+       int attrsonly,
+       LDAPMessage **res ));
+
+LDAP_F( int )
+ldap_url_search_st LDAP_P((
+       LDAP *ld,
+       LDAP_CONST char *url,
+       int attrsonly,
+       struct timeval *timeout,
+       LDAPMessage **res ));
+
+
+/*
+ * in charset.c
+ *     DEPRECATED
+ */
+LDAP_F( void )
+ldap_set_string_translators LDAP_P((
+       LDAP *ld,
+       BERTranslateProc encode_proc,
+       BERTranslateProc decode_proc ));
+
+LDAP_F( int )
+ldap_translate_from_t61 LDAP_P((
+       LDAP *ld,
+       char **bufp,
+       ber_len_t *lenp,
+       int free_input ));
+
+LDAP_F( int )
+ldap_translate_to_t61 LDAP_P((
+       LDAP *ld,
+       char **bufp,
+       ber_len_t *lenp,
+       int free_input ));
+
+LDAP_F( void )
+ldap_enable_translation LDAP_P((
+       LDAP *ld,
+       LDAPMessage *entry,
+       int enable ));
+
+LDAP_F( int )
+ldap_t61_to_8859 LDAP_P((
+       char **bufp,
+       ber_len_t *buflenp,
+       int free_input ));
+
+LDAP_F( int )
+ldap_8859_to_t61 LDAP_P((
+       char **bufp,
+       ber_len_t *buflenp,
+       int free_input ));
+
+LDAP_END_DECL
 
-#ifdef __cplusplus
-}
-#endif
 #endif /* _LDAP_H */
index d6f7291c7817f83558d1e222cadbd6bc0eb5e647..3069ed7452d25de19f04a6aa593c999a3d86afff 100644 (file)
  * is provided ``as is'' without express or implied warranty.
  */
 
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include "slap.h"
+#include "portable.h"
 
-extern Backend *select_backend();
+#include <stdio.h>
+#include <ac/socket.h>
 
-extern char    *default_referral;
+#include "slap.h"
 
-void
+int
 do_abandon(
     Connection *conn,
     Operation  *op
 )
 {
-       int             id;
-       Backend         *be;
+       ber_int_t               id;
        Operation       *o;
+       Operation       **oo;
+       int rc, notfound;
 
        Debug( LDAP_DEBUG_TRACE, "do_abandon\n", 0, 0, 0 );
 
@@ -40,31 +39,63 @@ do_abandon(
         */
 
        if ( ber_scanf( op->o_ber, "i", &id ) == LBER_ERROR ) {
-               Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0 ,0 );
-               return;
+               Debug( LDAP_DEBUG_ANY, "do_abandon: ber_scanf failed\n", 0, 0 ,0 );
+               send_ldap_disconnect( conn, op,
+                       LDAP_PROTOCOL_ERROR, "decoding error" );
+               return -1;
        }
 
+       if( (rc = get_ctrls( conn, op, 0 )) != LDAP_SUCCESS ) {
+               Debug( LDAP_DEBUG_ANY, "do_abandon: get_ctrls failed\n", 0, 0 ,0 );
+               return rc;
+       } 
+
        Debug( LDAP_DEBUG_ARGS, "do_abandon: id %d\n", id, 0 ,0 );
 
+       if( id <= 0 ) {
+               Debug( LDAP_DEBUG_ANY,
+                       "do_abandon: bad msgid %ld\n", (long) id, 0, 0 );
+               return LDAP_SUCCESS;
+       }
+
+       notfound = 1; /* not found */
+       ldap_pvt_thread_mutex_lock( &conn->c_mutex );
        /*
         * find the operation being abandoned and set the o_abandon
         * flag.  It's up to the backend to periodically check this
         * flag and abort the operation at a convenient time.
         */
 
-       pthread_mutex_lock( &conn->c_opsmutex );
        for ( o = conn->c_ops; o != NULL; o = o->o_next ) {
-               if ( o->o_msgid == id )
-                       break;
+               if ( o->o_msgid == id ) {
+                       ldap_pvt_thread_mutex_lock( &o->o_abandonmutex );
+                       o->o_abandon = 1;
+                       ldap_pvt_thread_mutex_unlock( &o->o_abandonmutex );
+
+                       notfound = 0;
+                       goto done;
+               }
+       }
+
+       for ( oo = &conn->c_pending_ops;
+               (*oo != NULL) && ((*oo)->o_msgid != id);
+               oo = &(*oo)->o_next )
+       {
+               /* EMPTY */ ;
        }
 
-       if ( o != NULL ) {
-               pthread_mutex_lock( &o->o_abandonmutex );
-               o->o_abandon = 1;
-               pthread_mutex_unlock( &o->o_abandonmutex );
-       } else {
-               Debug( LDAP_DEBUG_TRACE, "do_abandon: op not found\n", 0, 0,
-                   0 );
+       if( *oo != NULL ) {
+               o = *oo;
+               *oo = (*oo)->o_next;
+               slap_op_free( o );
+               notfound = 0;
        }
-       pthread_mutex_unlock( &conn->c_opsmutex );
+
+done:
+       ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
+
+       Debug( LDAP_DEBUG_TRACE, "do_abandon: op=%ld %sfound\n",
+               id, notfound ? "not " : "", 0 );
+
+       return LDAP_SUCCESS;
 }
index 027e40a8e4d2af935172366a8266aeb7a7bd41ca..962374c32a0061a06def30825ede34f0f105eab9 100644 (file)
  * is provided ``as is'' without express or implied warranty.
  */
 
+#include "portable.h"
+
 #include <stdio.h>
-#include <string.h>
-#include <time.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include "slap.h"
 
-extern Backend *select_backend();
-extern char    *dn_normalize();
+#include <ac/string.h>
+#include <ac/time.h>
+#include <ac/socket.h>
 
-extern char            *default_referral;
-extern time_t          currenttime;
-extern pthread_mutex_t currenttime_mutex;
-extern int             global_lastmod;
+#include "slap.h"
 
-static void    add_created_attrs();
+static void    add_created_attrs(Operation *op, Entry *e);
 
-void
-do_add( conn, op )
-    Connection *conn;
-    Operation  *op;
+int
+do_add( Connection *conn, Operation *op )
 {
        BerElement      *ber = op->o_ber;
        char            *dn, *last;
-       unsigned long   len, tag;
+       ber_len_t       len;
+       ber_tag_t       tag;
        Entry           *e;
        Backend         *be;
+       int                     rc = LDAP_SUCCESS;
 
        Debug( LDAP_DEBUG_TRACE, "do_add\n", 0, 0, 0 );
 
+       if( op->o_bind_in_progress ) {
+               Debug( LDAP_DEBUG_ANY, "do_add: SASL bind in progress.\n", 0, 0, 0 );
+               send_ldap_result( conn, op, LDAP_SASL_BIND_IN_PROGRESS, NULL,
+                   "SASL bind in progress", NULL );
+               return LDAP_SASL_BIND_IN_PROGRESS;
+       }
+
        /*
         * Parse the add request.  It looks like this:
         *
@@ -52,18 +54,23 @@ do_add( conn, op )
         *      }
         */
 
-       e = (Entry *) ch_calloc( 1, sizeof(Entry) );
-
        /* get the name */
-       if ( ber_scanf( ber, "{a", &dn ) == LBER_ERROR ) {
-               Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 );
-               send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL,
-                   "decoding error" );
-               return;
+       if ( ber_scanf( ber, "{a", /*}*/ &dn ) == LBER_ERROR ) {
+               Debug( LDAP_DEBUG_ANY, "do_add: ber_scanf failed\n", 0, 0, 0 );
+               send_ldap_disconnect( conn, op,
+                       LDAP_PROTOCOL_ERROR, "decoding error" );
+               return -1;
        }
+
+       e = (Entry *) ch_calloc( 1, sizeof(Entry) );
+
        e->e_dn = dn;
-       dn = dn_normalize( strdup( dn ) );
-       Debug( LDAP_DEBUG_ARGS, "    do_add: dn (%s)\n", dn, 0, 0 );
+       e->e_ndn = dn_normalize_case( ch_strdup( dn ) );
+       e->e_private = NULL;
+
+       dn = NULL;
+
+       Debug( LDAP_DEBUG_ARGS, "    do_add: ndn (%s)\n", e->e_ndn, 0, 0 );
 
        /* get the attrs */
        e->e_attrs = NULL;
@@ -73,19 +80,20 @@ do_add( conn, op )
                struct berval   **vals;
 
                if ( ber_scanf( ber, "{a{V}}", &type, &vals ) == LBER_ERROR ) {
-                       send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR,
-                           NULL, "decoding error" );
+                       send_ldap_disconnect( conn, op,
+                               LDAP_PROTOCOL_ERROR, "decoding error" );
                        entry_free( e );
-                       return;
+                       return -1;
                }
 
                if ( vals == NULL ) {
                        Debug( LDAP_DEBUG_ANY, "no values for type %s\n", type,
                            0, 0 );
-                       send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL,
-                           NULL );
+                       send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR,
+                               NULL, "no values for type", NULL );
+                       free( type );
                        entry_free( e );
-                       return;
+                       return LDAP_PROTOCOL_ERROR;
                }
 
                attr_merge( e, type, vals );
@@ -94,19 +102,34 @@ do_add( conn, op )
                ber_bvecfree( vals );
        }
 
+       if ( ber_scanf( ber, /*{*/ "}") == LBER_ERROR ) {
+               entry_free( e );
+               Debug( LDAP_DEBUG_ANY, "do_add: ber_scanf failed\n", 0, 0, 0 );
+               send_ldap_disconnect( conn, op,
+                       LDAP_PROTOCOL_ERROR, "decoding error" );
+               return -1;
+       }
+
+       if( (rc = get_ctrls( conn, op, 1 )) != LDAP_SUCCESS ) {
+               entry_free( e );
+               Debug( LDAP_DEBUG_ANY, "do_add: get_ctrls failed\n", 0, 0, 0 );
+               return rc;
+       } 
+
        Statslog( LDAP_DEBUG_STATS, "conn=%d op=%d ADD dn=\"%s\"\n",
-           conn->c_connid, op->o_opid, dn, 0, 0 );
+           conn->c_connid, op->o_opid, e->e_ndn, 0, 0 );
 
        /*
         * We could be serving multiple database backends.  Select the
         * appropriate one, or send a referral to our "referral server"
         * if we don't hold it.
         */
-       if ( (be = select_backend( dn )) == NULL ) {
+       be = select_backend( e->e_ndn );
+       if ( be == NULL ) {
                entry_free( e );
-               send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL,
-                   default_referral );
-               return;
+               send_ldap_result( conn, op, LDAP_REFERRAL, NULL,
+                   NULL, default_referral );
+               return rc;
        }
 
        /*
@@ -115,38 +138,46 @@ do_add( conn, op )
         * 2) this backend is master for what it holds;
         * 3) it's a replica and the dn supplied is the updatedn.
         */
-       if ( be->be_add != NULL ) {
+       if ( be->be_add ) {
                /* do the update here */
-               if ( be->be_updatedn == NULL || strcasecmp( be->be_updatedn,
-                   op->o_dn ) == 0 ) {
-                       if ( (be->be_lastmod == ON || be->be_lastmod == 0 &&
-                           global_lastmod == ON) && be->be_updatedn == NULL ) {
+               if ( be->be_update_ndn == NULL ||
+                       strcmp( be->be_update_ndn, op->o_ndn ) == 0 )
+               {
+                       if ( (be->be_lastmod == ON || (be->be_lastmod == UNDEFINED &&
+                               global_lastmod == ON)) && be->be_update_ndn == NULL ) {
+
                                add_created_attrs( op, e );
                        }
                        if ( (*be->be_add)( be, conn, op, e ) == 0 ) {
                                replog( be, LDAP_REQ_ADD, e->e_dn, e, 0 );
+                               be_entry_release_w( be, e );
                        }
+
                } else {
                        entry_free( e );
-                       send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL,
-                           default_referral );
+                       send_ldap_result( conn, op, rc = LDAP_REFERRAL, NULL,
+                               NULL, default_referral );
                }
        } else {
+           Debug( LDAP_DEBUG_ARGS, "    do_add: HHH\n", 0, 0, 0 );
                entry_free( e );
-               send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
-                   "Function not implemented" );
+               send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
+                       NULL, "Function not implemented", NULL );
        }
+
+       return rc;
 }
 
 static void
 add_created_attrs( Operation *op, Entry *e )
 {
-       char            buf[20];
+       char            buf[22];
        struct berval   bv;
        struct berval   *bvals[2];
        Attribute       **a, **next;
        Attribute       *tmp;
        struct tm       *ltm;
+       time_t          currenttime;
 
        Debug( LDAP_DEBUG_TRACE, "add_created_attrs\n", 0, 0, 0 );
 
@@ -155,8 +186,7 @@ add_created_attrs( Operation *op, Entry *e )
 
        /* remove any attempts by the user to add these attrs */
        for ( a = &e->e_attrs; *a != NULL; a = next ) {
-               if ( strcasecmp( (*a)->a_type, "createtimestamp" ) == 0
-                   || strcasecmp( (*a)->a_type, "creatorsname" ) == 0 ) {
+               if ( oc_check_no_usermod_attr( (*a)->a_type ) ) {
                        tmp = *a;
                        *a = (*a)->a_next;
                        attr_free( tmp );
@@ -167,7 +197,7 @@ add_created_attrs( Operation *op, Entry *e )
        }
 
        if ( op->o_dn == NULL || op->o_dn[0] == '\0' ) {
-               bv.bv_val = "NULLDN";
+               bv.bv_val = "<anonymous>";
                bv.bv_len = strlen( bv.bv_val );
        } else {
                bv.bv_val = op->o_dn;
@@ -175,10 +205,16 @@ add_created_attrs( Operation *op, Entry *e )
        }
        attr_merge( e, "creatorsname", bvals );
 
-       pthread_mutex_lock( &currenttime_mutex );
-        ltm = localtime( &currenttime );
-        strftime( buf, sizeof(buf), "%y%m%d%H%M%SZ", ltm );
-       pthread_mutex_unlock( &currenttime_mutex );
+       currenttime = slap_get_time();
+       ldap_pvt_thread_mutex_lock( &gmtime_mutex );
+#ifndef LDAP_LOCALTIME
+       ltm = gmtime( &currenttime );
+       strftime( buf, sizeof(buf), "%Y%m%d%H%M%SZ", ltm );
+#else
+       ltm = localtime( &currenttime );
+       strftime( buf, sizeof(buf), "%y%m%d%H%M%SZ", ltm );
+#endif
+       ldap_pvt_thread_mutex_unlock( &gmtime_mutex );
 
        bv.bv_val = buf;
        bv.bv_len = strlen( bv.bv_val );
diff --git a/servers/slapd/back-bdb2/search.c b/servers/slapd/back-bdb2/search.c
new file mode 100644 (file)
index 0000000..9ae5992
--- /dev/null
@@ -0,0 +1,547 @@
+/* search.c - bdb2 backend search function */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/string.h>
+#include <ac/socket.h>
+#include <ac/time.h>
+
+#include "slap.h"
+#include "back-bdb2.h"
+#include "proto-back-bdb2.h"
+
+static ID_BLOCK        *base_candidates(BackendDB *be, Connection *conn, Operation *op, char *base, Filter *filter, char **attrs, int attrsonly, char **matched, int *err);
+static ID_BLOCK        *onelevel_candidates(BackendDB *be, Connection *conn, Operation *op, char *base, Filter *filter, char **attrs, int attrsonly, char **matched, int *err);
+static ID_BLOCK        *subtree_candidates(BackendDB *be, Connection *conn, Operation *op, char *base, Filter *filter, char **attrs, int attrsonly, char **matched, Entry *e, int *err, int lookupbase);
+
+#define GRABSIZE       BUFSIZ
+
+#define MAKE_SPACE( n ) { \
+       if ( rcur + (n) > rbuf + rmaxsize ) { \
+               int     offset = rcur - rbuf; \
+               rbuf =  ch_realloc( rbuf, rmaxsize + GRABSIZE ); \
+               rmaxsize += GRABSIZE; \
+               rcur = rbuf + offset; \
+       } \
+}
+
+static int
+bdb2i_back_search_internal(
+    BackendDB  *be,
+    Connection *conn,
+    Operation  *op,
+    char       *base,
+    int                scope,
+    int                deref,
+    int                slimit,
+    int                tlimit,
+    Filter     *filter,
+    char       *filterstr,
+    char       **attrs,
+    int                attrsonly
+)
+{
+       struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+       int             err;
+       time_t          stoptime;
+       ID_BLOCK                *candidates;
+       ID              id;
+       Entry           *e;
+       Attribute       *ref;
+       char            *matched = NULL;
+       int             rmaxsize, nrefs;
+       char            *rbuf, *rcur;
+       int             nentries = 0;
+       char            *realBase;
+
+       Debug(LDAP_DEBUG_ARGS, "=> bdb2i_back_search\n", 0, 0, 0);
+
+       if ( tlimit == 0 && be_isroot( be, op->o_ndn ) ) {
+               tlimit = -1;    /* allow root to set no limit */
+       } else {
+               tlimit = (tlimit > be->be_timelimit || tlimit < 1) ?
+                   be->be_timelimit : tlimit;
+               stoptime = op->o_time + tlimit;
+       }
+       if ( slimit == 0 && be_isroot( be, op->o_ndn ) ) {
+               slimit = -1;    /* allow root to set no limit */
+       } else {
+               slimit = (slimit > be->be_sizelimit || slimit < 1) ?
+                   be->be_sizelimit : slimit;
+       }
+
+       /*
+        * check and apply aliasing where the dereferencing applies to
+        * the subordinates of the base
+        */
+
+       switch ( deref ) {
+       case LDAP_DEREF_FINDING:
+       case LDAP_DEREF_ALWAYS:
+               realBase = bdb2i_derefDN ( be, conn, op, base );
+               break;
+       default:
+               realBase = ch_strdup(base);
+       }
+
+       (void) dn_normalize_case( realBase );
+
+       Debug( LDAP_DEBUG_TRACE, "using base \"%s\"\n",
+               realBase, 0, 0 );
+
+       switch ( scope ) {
+       case LDAP_SCOPE_BASE:
+               candidates = base_candidates( be, conn, op, realBase, filter,
+                   attrs, attrsonly, &matched, &err );
+               break;
+
+       case LDAP_SCOPE_ONELEVEL:
+               candidates = onelevel_candidates( be, conn, op, realBase, filter,
+                   attrs, attrsonly, &matched, &err );
+               break;
+
+       case LDAP_SCOPE_SUBTREE:
+               candidates = subtree_candidates( be, conn, op, realBase, filter,
+                   attrs, attrsonly, &matched, NULL, &err, 1 );
+               break;
+
+       default:
+               send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, "",
+                   "Bad scope" );
+               if( realBase != NULL) {
+                       free( realBase );
+               }
+               return( -1 );
+       }
+
+       /* null candidates means we could not find the base object */
+       if ( candidates == NULL ) {
+               send_ldap_result( conn, op, err, matched, "" );
+               if ( matched != NULL ) {
+                       free( matched );
+               }
+               if( realBase != NULL) {
+                       free( realBase );
+               }
+               return( -1 );
+       }
+
+       if ( matched != NULL ) {
+               free( matched );
+       }
+
+       rmaxsize = 0;
+       nrefs = 0;
+       rbuf = rcur = NULL;
+       MAKE_SPACE( sizeof("Referral:") + 1 );
+       strcpy( rbuf, "Referral:" );
+       rcur = strchr( rbuf, '\0' );
+       for ( id = bdb2i_idl_firstid( candidates ); id != NOID;
+           id = bdb2i_idl_nextid( candidates, id ) ) {
+               /* check for abandon */
+               ldap_pvt_thread_mutex_lock( &op->o_abandonmutex );
+               if ( op->o_abandon ) {
+                       ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
+                       bdb2i_idl_free( candidates );
+                       free( rbuf );
+                       if( realBase != NULL) {
+                               free( realBase );
+                       }
+                       return( 0 );
+               }
+               ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
+
+               /* check time limit */
+               if ( tlimit != -1 && slap_get_time() > stoptime ) {
+                       send_search_result( conn, op,
+                           LDAP_TIMELIMIT_EXCEEDED, NULL, nrefs > 0 ? rbuf :
+                           NULL, nentries );
+                       bdb2i_idl_free( candidates );
+                       free( rbuf );
+                       if( realBase != NULL) {
+                               free( realBase );
+                       }
+                       return( 0 );
+               }
+
+               /* get the entry with reader lock */
+               if ( (e = bdb2i_id2entry_r( be, id )) == NULL ) {
+                       Debug( LDAP_DEBUG_ARGS, "candidate %ld not found\n",
+                              id, 0, 0 );
+                       continue;
+               }
+
+               /*
+                * if it's a referral, add it to the list of referrals. only do
+                * this for subtree searches, and don't check the filter explicitly
+                * here since it's only a candidate anyway.
+                */
+               if ( scope == LDAP_SCOPE_SUBTREE &&
+                       e->e_ndn != NULL &&
+                       strncmp( e->e_ndn, "REF=", 4 ) == 0 &&
+                       (ref = attr_find( e->e_attrs, "ref" )) != NULL )
+               {
+                       int     i;
+
+                       if ( ref->a_vals == NULL ) {
+                               Debug( LDAP_DEBUG_ANY, "null ref in (%s)\n", 
+                                       e->e_dn, 0, 0 );
+                       } else {
+                               if( op->o_protocol < LDAP_VERSION3 ) {
+                                       for ( i = 0; ref->a_vals[i] != NULL; i++ ) {
+                                               /* referral + newline + null */
+                                               MAKE_SPACE( ref->a_vals[i]->bv_len + 2 );
+                                               *rcur++ = '\n';
+                                               strncpy( rcur, ref->a_vals[i]->bv_val,
+                                               ref->a_vals[i]->bv_len );
+                                               rcur = rcur + ref->a_vals[i]->bv_len;
+                                               *rcur = '\0';
+                                               nrefs++;
+                                       }
+                               } else {
+                                       send_search_reference( conn, op, ref->a_vals );
+                               }
+                       }
+
+               /* otherwise it's an entry - see if it matches the filter */
+               } else {
+                       /* if it matches the filter and scope, send it */
+                       if ( test_filter( be, conn, op, e, filter ) == 0 ) {
+                               int             scopeok;
+                               char    *dn;
+
+                               /* check scope */
+                               scopeok = 1;
+                               if ( scope == LDAP_SCOPE_ONELEVEL ) {
+                                       if ( (dn = dn_parent( be, e->e_dn )) != NULL ) {
+                                               (void) dn_normalize_case( dn );
+                                               scopeok = (dn == realBase)
+                                                       ? 1
+                                                       : (strcmp( dn, realBase ) ? 0 : 1 );
+                                               free( dn );
+                                       } else {
+                                               scopeok = (realBase == NULL || *realBase == '\0');
+                                       }
+                               } else if ( scope == LDAP_SCOPE_SUBTREE ) {
+                                       dn = ch_strdup( e->e_ndn );
+                                       scopeok = dn_issuffix( dn, realBase );
+                                       free( dn );
+                               }
+
+                               if ( scopeok ) {
+                                       /* check size limit */
+                                       if ( --slimit == -1 ) {
+                                               bdb2i_cache_return_entry_r( &li->li_cache, e );
+                                               send_search_result( conn, op,
+                                                       LDAP_SIZELIMIT_EXCEEDED, NULL,
+                                                       nrefs > 0 ? rbuf : NULL, nentries );
+                                               bdb2i_idl_free( candidates );
+                                               free( rbuf );
+
+                                               if( realBase != NULL) {
+                                                       free( realBase );
+                                               }
+                                               return( 0 );
+                                       }
+
+                                       /*
+                                        * check and apply aliasing where the dereferencing applies to
+                                        * the subordinates of the base
+                                        */
+                                       switch ( deref ) {
+                                       case LDAP_DEREF_SEARCHING:
+                                       case LDAP_DEREF_ALWAYS:
+                                               {
+                                                       Entry *newe = bdb2i_derefAlias_r( be, conn, op, e );
+                                                       if ( newe == NULL ) { /* problem with the alias */
+                                                               bdb2i_cache_return_entry_r( &li->li_cache, e );
+                                                               e = NULL;
+                                                       }
+                                                       else if ( newe != e ) { /* reassign e */
+                                                               bdb2i_cache_return_entry_r( &li->li_cache, e );
+                                                               e = newe;
+                                                       }
+                                               }
+                                               break;
+                                       }
+
+                                       if (e) {
+                                               switch ( send_search_entry( be, conn, op, e,
+                                                       attrs, attrsonly, 0 ) ) {
+                                               case 0:         /* entry sent ok */
+                                                       nentries++;
+                                                       break;
+                                               case 1:         /* entry not sent */
+                                                       break;
+                                               case -1:        /* connection closed */
+                                                       bdb2i_cache_return_entry_r( &li->li_cache, e );
+                                                       bdb2i_idl_free( candidates );
+                                                       free( rbuf );
+
+                                                       if( realBase != NULL) {
+                                                               free( realBase );
+                                                       }
+                                                       return( 0 );
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               if( e != NULL ) {
+                       /* free reader lock */
+                       bdb2i_cache_return_entry_r( &li->li_cache, e );
+               }
+
+               ldap_pvt_thread_yield();
+       }
+       bdb2i_idl_free( candidates );
+       if ( nrefs > 0 ) {
+               send_search_result( conn, op, LDAP_REFERRALS, NULL,
+                   rbuf, nentries );
+       } else {
+               send_search_result( conn, op, LDAP_SUCCESS, NULL, NULL,
+                   nentries );
+       }
+       free( rbuf );
+
+       if( realBase != NULL) {
+               free( realBase );
+       }
+
+       return( 0 );
+}
+
+
+int
+bdb2_back_search(
+    BackendDB  *be,
+    Connection *conn,
+    Operation  *op,
+    char       *base,
+    int                scope,
+    int                deref,
+    int                slimit,
+    int                tlimit,
+    Filter     *filter,
+    char       *filterstr,
+    char       **attrs,
+    int                attrsonly
+)
+{
+       DB_LOCK         lock;
+       struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+       struct timeval  time1;
+       int             ret;
+
+       bdb2i_start_timing( be->bd_info, &time1 );
+
+       if ( bdb2i_enter_backend_r( &lock ) != 0 ) {
+
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
+               return( -1 );
+
+       }
+
+       ret = bdb2i_back_search_internal( be, conn, op, base, scope, deref,
+                                       slimit, tlimit, filter, filterstr, attrs, attrsonly );
+
+       (void) bdb2i_leave_backend_r( lock );
+       bdb2i_stop_timing( be->bd_info, time1, "SRCH", conn, op );
+
+       return( ret );
+}
+
+
+static ID_BLOCK *
+base_candidates(
+    BackendDB  *be,
+    Connection *conn,
+    Operation  *op,
+    char       *base,
+    Filter     *filter,
+    char       **attrs,
+    int                attrsonly,
+    char       **matched,
+    int                *err
+)
+{
+       struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+       ID_BLOCK                *idl;
+       Entry           *e;
+
+       Debug(LDAP_DEBUG_TRACE, "base_candidates: base: \"%s\"\n", base, 0, 0);
+
+       *err = LDAP_SUCCESS;
+
+       /* get entry with reader lock */
+       if ( (e = bdb2i_dn2entry_r( be, base, matched )) == NULL ) {
+               *err = LDAP_NO_SUCH_OBJECT;
+               return( NULL );
+       }
+
+       /* check for deleted */
+
+       idl = bdb2i_idl_alloc( 1 );
+       bdb2i_idl_insert( &idl, e->e_id, 1 );
+
+
+       /* free reader lock */
+       bdb2i_cache_return_entry_r( &li->li_cache, e );
+
+       return( idl );
+}
+
+static ID_BLOCK *
+onelevel_candidates(
+    BackendDB  *be,
+    Connection *conn,
+    Operation  *op,
+    char       *base,
+    Filter     *filter,
+    char       **attrs,
+    int                attrsonly,
+    char       **matched,
+    int                *err
+)
+{
+       struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+       Entry           *e = NULL;
+       Filter          *f;
+       char            buf[20];
+       ID_BLOCK                *candidates;
+
+       Debug(LDAP_DEBUG_TRACE, "onelevel_candidates: base: \"%s\"\n", base, 0, 0);
+
+       *err = LDAP_SUCCESS;
+
+       /* get the base object with reader lock */
+       if ( base != NULL && *base != '\0' &&
+               (e = bdb2i_dn2entry_r( be, base, matched )) == NULL )
+       {
+               *err = LDAP_NO_SUCH_OBJECT;
+               return( NULL );
+       }
+
+       /*
+        * modify the filter to be something like this:
+        *
+        *      parent=baseobject & originalfilter
+        */
+
+       f = (Filter *) ch_malloc( sizeof(Filter) );
+       f->f_next = NULL;
+       f->f_choice = LDAP_FILTER_AND;
+       f->f_and = (Filter *) ch_malloc( sizeof(Filter) );
+       f->f_and->f_choice = LDAP_FILTER_EQUALITY;
+       f->f_and->f_ava.ava_type = ch_strdup( "id2children" );
+       sprintf( buf, "%ld", e != NULL ? e->e_id : 0 );
+       f->f_and->f_ava.ava_value.bv_val = ch_strdup( buf );
+       f->f_and->f_ava.ava_value.bv_len = strlen( buf );
+       f->f_and->f_next = filter;
+
+       /* from here, it's just like subtree_candidates */
+       candidates = subtree_candidates( be, conn, op, base, f, attrs,
+           attrsonly, matched, e, err, 0 );
+
+       /* free up just the filter stuff we allocated above */
+       f->f_and->f_next = NULL;
+       filter_free( f );
+
+       /* free entry and reader lock */
+       if( e != NULL ) {
+               bdb2i_cache_return_entry_r( &li->li_cache, e );
+       }
+       return( candidates );
+}
+
+static ID_BLOCK *
+subtree_candidates(
+    BackendDB  *be,
+    Connection *conn,
+    Operation  *op,
+    char       *base,
+    Filter     *filter,
+    char       **attrs,
+    int                attrsonly,
+    char       **matched,
+    Entry      *e,
+    int                *err,
+    int                lookupbase
+)
+{
+       struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+       Filter          *f, **filterarg_ptr;
+       ID_BLOCK                *candidates;
+
+       Debug(LDAP_DEBUG_TRACE, "subtree_candidates: base: \"%s\" %s\n",
+               base ? base : "NULL", lookupbase ? "lookupbase" : "", 0);
+
+       /*
+        * get the base object - unless we already have it (from one-level).
+        * also, unless this is a one-level search or a subtree search
+        * starting at the very top of our subtree, we need to modify the
+        * filter to be something like this:
+        *
+        *      dn=*baseobjectdn & (originalfilter | ref=*)
+        *
+        * the "objectclass=referral" part is used to select referrals to return
+        */
+
+       *err = LDAP_SUCCESS;
+       f = NULL;
+       if ( lookupbase ) {
+               e = NULL;
+
+               if ( base != NULL && *base != '\0' &&
+                       (e = bdb2i_dn2entry_r( be, base, matched )) == NULL )
+               {
+                       *err = LDAP_NO_SUCH_OBJECT;
+                       return( NULL );
+               }
+
+               if (e) {
+                       bdb2i_cache_return_entry_r( &li->li_cache, e );
+               }
+
+               f = (Filter *) ch_malloc( sizeof(Filter) );
+               f->f_next = NULL;
+               f->f_choice = LDAP_FILTER_OR;
+               f->f_or = (Filter *) ch_malloc( sizeof(Filter) );
+               f->f_or->f_choice = LDAP_FILTER_EQUALITY;
+               f->f_or->f_avtype = ch_strdup( "objectclass" );
+               /* Patch to use normalized uppercase */
+               f->f_or->f_avvalue.bv_val = ch_strdup( "REFERRAL" );
+               f->f_or->f_avvalue.bv_len = strlen( "REFERRAL" );
+               filterarg_ptr = &f->f_or->f_next;
+               *filterarg_ptr = filter;
+               filter = f;
+
+               if ( ! be_issuffix( be, base ) ) {
+                       f = (Filter *) ch_malloc( sizeof(Filter) );
+                       f->f_next = NULL;
+                       f->f_choice = LDAP_FILTER_AND;
+                       f->f_and = (Filter *) ch_malloc( sizeof(Filter) );
+                       f->f_and->f_choice = LDAP_FILTER_SUBSTRINGS;
+                       f->f_and->f_sub_type = ch_strdup( "dn" );
+                       f->f_and->f_sub_initial = NULL;
+                       f->f_and->f_sub_any = NULL;
+                       f->f_and->f_sub_final = ch_strdup( base );
+                       value_normalize( f->f_and->f_sub_final, SYNTAX_CIS );
+                       f->f_and->f_next = filter;
+                       filter = f;
+               }
+       }
+
+       candidates = bdb2i_filter_candidates( be, filter );
+
+       /* free up just the parts we allocated above */
+       if ( f != NULL ) {
+               *filterarg_ptr = NULL;
+               filter_free( f );
+       }
+
+       return( candidates );
+}
diff --git a/servers/slapd/back-ldap/search.c b/servers/slapd/back-ldap/search.c
new file mode 100644 (file)
index 0000000..7654bd3
--- /dev/null
@@ -0,0 +1,172 @@
+/* search.c - ldap backend search function */
+
+/*
+ * Copyright 1999, Howard Chu, All rights reserved. <hyc@highlandsun.com>
+ * 
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ * 
+ * 1. The author is not responsible for the consequences of use of this
+ *    software, no matter how awful, even if they arise from flaws in it.
+ * 
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Since few users ever read sources,
+ *    credits should appear in the documentation.
+ * 
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.  Since few users
+ *    ever read sources, credits should appear in the documentation.
+ * 
+ * 4. This notice may not be removed or altered.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/socket.h>
+#include <ac/string.h>
+#include <ac/time.h>
+
+#include "slap.h"
+#include "back-ldap.h"
+
+int
+ldap_back_search(
+    Backend    *be,
+    Connection *conn,
+    Operation  *op,
+    char       *base,
+    int                scope,
+    int                deref,
+    int                size,
+    int                time,
+    Filter     *filter,
+    char       *filterstr,
+    char       **attrs,
+    int                attrsonly
+)
+{
+       struct ldapinfo *li = (struct ldapinfo *) be->be_private;
+       struct ldapconn *lc;
+       struct timeval  tv;
+       LDAPMessage             *res, *e;
+       int                     i, rc, msgid, sres = LDAP_SUCCESS; 
+       char *match = NULL, *err = NULL;
+
+       lc = ldap_back_getconn(li, conn, op);
+       if (!lc)
+               return( -1 );
+
+       if (deref != -1)
+               ldap_set_option( lc->ld, LDAP_OPT_DEREF, (void *)&deref);
+       if (time != -1)
+               ldap_set_option( lc->ld, LDAP_OPT_TIMELIMIT, (void *)&time);
+       if (size != -1)
+               ldap_set_option( lc->ld, LDAP_OPT_SIZELIMIT, (void *)&size);
+       if (!lc->bound) {
+               ldap_back_dobind(lc, op);
+               if (!lc->bound)
+                       return( -1 );
+       }
+
+       if ((msgid = ldap_search(lc->ld, base, scope, filterstr, attrs,
+               attrsonly)) == -1)
+fail:          return( ldap_back_op_result(lc, op) );
+
+       /* We pull apart the ber result, stuff it into a slapd entry, and
+        * let send_search_entry stuff it back into ber format. Slow & ugly,
+        * but this is necessary for version matching, and for ACL processing.
+        */
+       
+       for (i=0, rc=0; rc != -1;
+               rc = ldap_result(lc->ld, LDAP_RES_ANY, 0, &tv, &res)) {
+               int ab;
+
+               /* check for abandon */
+               ldap_pvt_thread_mutex_lock( &op->o_abandonmutex );
+               ab = op->o_abandon;
+               ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
+
+               if (ab) {
+                       ldap_abandon(lc->ld, msgid);
+               } else if (rc == 0) {
+                       tv.tv_sec = 0;
+                       tv.tv_usec = 100000;
+                       ldap_pvt_thread_yield();
+                       continue;
+               } else if (rc == LDAP_RES_SEARCH_ENTRY) {
+                       e = ldap_first_entry(lc->ld,res);
+                       ldap_send_entry(be, op, lc, e, attrs, attrsonly);
+                       i++;
+               } else {
+                       sres = ldap_result2error(lc->ld, res, 1);
+                       ldap_get_option(lc->ld, LDAP_OPT_ERROR_STRING, &err);
+                       ldap_get_option(lc->ld, LDAP_OPT_MATCHED_DN, &match);
+                       rc = 0;
+               }
+               ldap_msgfree(res);
+               if (ab)
+                       return (0);
+               else if (rc == 0)
+                       break;
+       }
+
+       if (rc == -1)
+               goto fail;
+
+       send_search_result( conn, op, sres, match, err, i );
+       if (match)
+               free(match);
+       if (err)
+               free(err);
+       return( 0 );
+}
+
+ldap_send_entry(
+       Backend *be,
+       Operation *op,
+       struct ldapconn *lc,
+       LDAPMessage *e,
+       char **attrs,
+       int attrsonly
+)
+{
+       char *a;
+       Entry ent;
+       BerElement *ber = NULL;
+       Attribute *attr;
+       struct berval *dummy = NULL;
+
+       ent.e_dn = ldap_get_dn(lc->ld, e);
+       ent.e_ndn = dn_normalize_case( ch_strdup( ent.e_dn));
+       ent.e_id = 0;
+       ent.e_attrs = 0;
+       ent.e_private = 0;
+       attr = (Attribute *)4;
+       attr = (Attribute *)((long)&ent.e_attrs - ((long)&attr->a_next-4));
+
+       for (a = ldap_first_attribute(lc->ld, e, &ber); a;
+               a = ldap_next_attribute(lc->ld, e, ber)) {
+               attr->a_next = (Attribute *)ch_malloc( sizeof(Attribute) );
+               attr=attr->a_next;
+               attr->a_next = 0;
+               attr->a_type = ch_strdup(a);
+               attr->a_syntax = attr_syntax(a);
+               attr->a_vals = ldap_get_values_len(lc->ld, e, a);
+               if (!attr->a_vals)
+                       attr->a_vals = &dummy;
+       }
+       send_search_entry( be, lc->conn, op, &ent, attrs, attrsonly, 0 );
+       for (;ent.e_attrs;) {
+               attr=ent.e_attrs;
+               ent.e_attrs = attr->a_next;
+               free(attr->a_type);
+               if (attr->a_vals != &dummy)
+                       ber_bvecfree(attr->a_vals);
+               free(attr);
+       }
+       if (ber)
+               ber_free(ber,0);
+}
index 3dacd6da3dba445dece437a7eff58708971c2e65..b28fc55a48470365e9b807263900b21c0c75110c 100644 (file)
@@ -1,16 +1,15 @@
 /* add.c - ldap ldbm back-end add routine */
 
+#include "portable.h"
+
 #include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
+
+#include <ac/socket.h>
+#include <ac/string.h>
+
 #include "slap.h"
 #include "back-ldbm.h"
-
-extern int     global_schemacheck;
-extern char    *dn_parent();
-extern char    *dn_normalize();
-extern Entry   *dn2entry();
+#include "proto-back-ldbm.h"
 
 int
 ldbm_back_add(
@@ -21,49 +20,33 @@ ldbm_back_add(
 )
 {
        struct ldbminfo *li = (struct ldbminfo *) be->be_private;
-       char            *matched;
-       char            *dn = NULL, *pdn = NULL;
-       Entry           *p;
-
-       dn = dn_normalize( strdup( e->e_dn ) );
-       matched = NULL;
-       if ( (p = dn2entry( be, dn, &matched )) != NULL ) {
-               cache_return_entry( &li->li_cache, p );
+       char            *pdn;
+       Entry           *p = NULL;
+       int                     rootlock = 0;
+       int                     rc; 
+
+       Debug(LDAP_DEBUG_ARGS, "==> ldbm_back_add: %s\n", e->e_dn, 0, 0);
+
+       /* nobody else can add until we lock our parent */
+       ldap_pvt_thread_mutex_lock(&li->li_add_mutex);
+
+       if ( ( dn2id( be, e->e_ndn ) ) != NOID ) {
+               ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
                entry_free( e );
-               free( dn );
-               send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, "", "" );
+               send_ldap_result( conn, op, LDAP_ALREADY_EXISTS,
+                       NULL, NULL, NULL );
                return( -1 );
        }
-       if ( matched != NULL ) {
-               free( matched );
-       }
-       /* XXX race condition here til we cache_add_entry_lock below XXX */
 
        if ( global_schemacheck && oc_schema_check( e ) != 0 ) {
-               Debug( LDAP_DEBUG_TRACE, "entry failed schema check\n", 0, 0,
-                   0 );
-               entry_free( e );
-               free( dn );
-               send_ldap_result( conn, op, LDAP_OBJECT_CLASS_VIOLATION, "",
-                   "" );
-               return( -1 );
-       }
+               ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
 
-       /*
-        * Try to add the entry to the cache, assign it a new dnid
-        * and mark it locked.  This should only fail if the entry
-        * already exists.
-        */
+               Debug( LDAP_DEBUG_TRACE, "entry failed schema check\n",
+                       0, 0, 0 );
 
-       e->e_id = next_id( be );
-       if ( cache_add_entry_lock( &li->li_cache, e, ENTRY_STATE_CREATING )
-           != 0 ) {
-               Debug( LDAP_DEBUG_ANY, "cache_add_entry_lock failed\n", 0, 0,
-                   0 );
-               next_id_return( be, e->e_id );
                entry_free( e );
-               free( dn );
-               send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, "", "" );
+               send_ldap_result( conn, op, LDAP_OBJECT_CLASS_VIOLATION,
+                       NULL, NULL, NULL );
                return( -1 );
        }
 
@@ -73,42 +56,122 @@ ldbm_back_add(
         * add the entry.
         */
 
-       if ( (pdn = dn_parent( be, dn )) != NULL ) {
-               /* no parent */
-               matched = NULL;
-               if ( (p = dn2entry( be, pdn, &matched )) == NULL ) {
+       pdn = dn_parent( be, e->e_ndn );
+
+       if( pdn != NULL && *pdn != '\0' && !be_issuffix(be, "") ) {
+               char *matched = NULL;
+
+               assert( *pdn != '\0' );
+
+               /* get parent with writer lock */
+               if ( (p = dn2entry_w( be, pdn, &matched )) == NULL ) {
+                       ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
+                       Debug( LDAP_DEBUG_TRACE, "parent does not exist\n", 0,
+                           0, 0 );
                        send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT,
-                           matched, "" );
+                           matched, NULL, NULL );
+
                        if ( matched != NULL ) {
                                free( matched );
                        }
-                       Debug( LDAP_DEBUG_TRACE, "parent does not exist\n", 0,
-                           0, 0 );
-                       goto error_return;
+
+                       entry_free( e );
+                       free( pdn );
+                       return -1;
                }
+
+               /* don't need the add lock anymore */
+               ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
+
+               free(pdn);
+
                if ( matched != NULL ) {
                        free( matched );
                }
 
-               if ( ! access_allowed( be, conn, op, p, "children", NULL,
-                   op->o_dn, ACL_WRITE ) ) {
+               if ( ! access_allowed( be, conn, op, p,
+                       "children", NULL, ACL_WRITE ) )
+               {
                        Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0,
                            0, 0 );
                        send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
-                           "", "" );
-                       goto error_return;
+                           NULL, NULL, NULL );
+
+                       /* free parent and writer lock */
+                       cache_return_entry_w( &li->li_cache, p ); 
+
+                       entry_free( e );
+                       return -1;
                }
+
        } else {
-               if ( ! be_isroot( be, op->o_dn ) ) {
-                       Debug( LDAP_DEBUG_TRACE, "no parent & not root\n", 0,
-                           0, 0 );
+               if(pdn != NULL) {
+                       assert( *pdn == '\0' );
+                       free(pdn);
+               }
+
+               /* no parent, must be adding entry to root */
+               if ( ! be_isroot( be, op->o_ndn ) ) {
+                       ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
+
+                       Debug( LDAP_DEBUG_TRACE, "%s add denied\n",
+                                       pdn == NULL ? "suffix" : "entry at root",
+                                       0, 0 );
+
                        send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
-                           "", "" );
-                       goto error_return;
+                           NULL, NULL, NULL );
+
+                       entry_free( e );
+                       return -1;
+               }
+
+               /*
+                * no parent, acquire the root write lock
+                * and release the add lock.
+                */
+               ldap_pvt_thread_mutex_lock(&li->li_root_mutex);
+               rootlock = 1;
+               ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
+       }
+
+       e->e_id = next_id( be );
+
+       /*
+        * Try to add the entry to the cache, assign it a new dnid.
+        */
+       rc = cache_add_entry_rw(&li->li_cache, e, CACHE_WRITE_LOCK);
+
+       if ( rc != 0 ) {
+               if( p != NULL) {
+                       /* free parent and writer lock */
+                       cache_return_entry_w( &li->li_cache, p ); 
+               }
+
+               if ( rootlock ) {
+                       /* release root lock */
+                       ldap_pvt_thread_mutex_unlock(&li->li_root_mutex);
+               }
+
+               Debug( LDAP_DEBUG_ANY, "cache_add_entry_lock failed\n", 0, 0,
+                   0 );
+
+               /* return the id */
+               next_id_return( be, e->e_id );
+
+               /* free the entry */
+               entry_free( e );
+
+               if(rc > 0) {
+                       send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, NULL, NULL, NULL );
+               } else {
+                       send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL, NULL );
                }
-               p = NULL;
+
+               return( -1 );
        }
 
+       rc = -1;
+
        /*
         * add it to the id2children index for the parent
         */
@@ -116,9 +179,9 @@ ldbm_back_add(
        if ( id2children_add( be, p, e ) != 0 ) {
                Debug( LDAP_DEBUG_TRACE, "id2children_add failed\n", 0,
                    0, 0 );
-               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "",
-                   "" );
-               goto error_return;
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL, NULL );
+
+               goto return_results;
        }
 
        /*
@@ -130,44 +193,48 @@ ldbm_back_add(
        if ( index_add_entry( be, e ) != 0 ) {
                Debug( LDAP_DEBUG_TRACE, "index_add_entry failed\n", 0,
                    0, 0 );
-               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
-               goto error_return;
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL, NULL );
+
+               goto return_results;
        }
 
        /* dn2id index */
-       if ( dn2id_add( be, dn, e->e_id ) != 0 ) {
+       if ( dn2id_add( be, e->e_ndn, e->e_id ) != 0 ) {
                Debug( LDAP_DEBUG_TRACE, "dn2id_add failed\n", 0,
                    0, 0 );
-               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
-               goto error_return;
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL, NULL );
+
+               goto return_results;
        }
 
        /* id2entry index */
        if ( id2entry_add( be, e ) != 0 ) {
                Debug( LDAP_DEBUG_TRACE, "id2entry_add failed\n", 0,
                    0, 0 );
-               (void) dn2id_delete( be, dn );
-               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
-               goto error_return;
+               (void) dn2id_delete( be, e->e_ndn );
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL, NULL );
+
+               goto return_results;
+       }
+
+       send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL, NULL );
+       rc = 0;
+
+return_results:;
+       if (p != NULL) {
+               /* free parent and writer lock */
+               cache_return_entry_w( &li->li_cache, p ); 
+       }
+
+       if ( rootlock ) {
+               /* release root lock */
+               ldap_pvt_thread_mutex_unlock(&li->li_root_mutex);
+       }
+
+       if ( rc ) {
+               /* free entry and writer lock */
+               cache_return_entry_w( &li->li_cache, e );
        }
 
-       send_ldap_result( conn, op, LDAP_SUCCESS, "", "" );
-       if ( dn != NULL )
-               free( dn );
-       if ( pdn != NULL )
-               free( pdn );
-       cache_set_state( &li->li_cache, e, 0 );
-       cache_return_entry( &li->li_cache, e );
-       return( 0 );
-
-error_return:;
-       if ( dn != NULL )
-               free( dn );
-       if ( pdn != NULL )
-               free( pdn );
-       next_id_return( be, e->e_id );
-       cache_delete_entry( &li->li_cache, e );
-       cache_return_entry( &li->li_cache, e );
-
-       return( -1 );
+       return( rc );
 }
diff --git a/servers/slapd/back-ldbm/alias.c b/servers/slapd/back-ldbm/alias.c
new file mode 100644 (file)
index 0000000..9717dc3
--- /dev/null
@@ -0,0 +1,321 @@
+/*
+ * Copyright (c) 1998 Will Ballantyne, ITSD, Government of BC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to ITSD, Government of BC. The name of ITSD
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <ac/string.h>
+#include <ac/socket.h>
+#include "slap.h"
+#include "back-ldbm.h"
+#include "proto-back-ldbm.h"
+
+/*
+ * given an alias object, dereference it to its end point.
+ * Entry returned has reader lock or is NULL.  Starting entry is not released.
+ */
+Entry *derefAlias_r ( Backend     *be,
+                   Connection  *conn,
+                   Operation   *op,
+                   Entry       *e)
+{
+  struct ldbminfo *li = (struct ldbminfo *) be->be_private; /* to free cache entries */
+  Attribute *a;
+  int       depth;
+  char      *matched;
+  Entry     *origDN = e;
+
+  if (!e) return NULL;  /* be sure we have a starting entry */
+
+  Debug( LDAP_DEBUG_TRACE, "<= checking for alias for dn %s\n", e->e_dn, 0, 0 );
+
+  /*
+   * try to deref fully, up to a maximum depth.  If the max depth exceeded
+   * then send an error
+   */
+  for ( depth = 0;
+       ( ( a = attr_find( e->e_attrs, "aliasedobjectname" ) ) != NULL) &&
+         ( depth < be->be_maxDerefDepth );
+       ++depth) 
+  {
+
+    /* 
+     * make sure there is a defined aliasedobjectname.  
+     * can only have one value so just use first value (0) in the attr list. 
+     */            
+    if (a->a_vals[0] && a->a_vals[0]->bv_val) {
+      char *newDN, *oldDN;
+
+      Debug( LDAP_DEBUG_TRACE, "<= %s is an alias for %s\n", 
+            e->e_dn, a->a_vals[0]->bv_val, 0 );
+      newDN = ch_strdup (a->a_vals[0]->bv_val);
+      oldDN = ch_strdup (e->e_ndn);
+
+      /* 
+       * release past lock if not original
+       */
+      if ( (depth > 0) && e ) {
+          cache_return_entry_r(&li->li_cache, e);      
+      }
+
+      /* make sure new and old DN are not same to avoid loops */
+      dn_normalize_case (newDN);
+      if ( strcmp (newDN, oldDN) == 0 ) {
+       
+       Debug( LDAP_DEBUG_TRACE, 
+              "<= %s alias is same as current %s\n", 
+              oldDN, newDN, 0 );
+       send_ldap_result( conn, op, LDAP_ALIAS_DEREF_PROBLEM,
+               NULL, "circular alias", NULL );
+       free (newDN);
+       free (oldDN);
+       break;
+      }
+
+      /* make sure new and original are not same to avoid deadlocks */
+      if ( strcmp (newDN, origDN->e_ndn) == 0 ) {
+       Debug( LDAP_DEBUG_TRACE, 
+              "<= %s alias is same as original %s\n", 
+              oldDN, origDN->e_ndn, 0 );
+       send_ldap_result( conn, op, LDAP_ALIAS_DEREF_PROBLEM,
+               NULL, "circular alias", NULL );
+       free (newDN);
+       free (oldDN);
+       break;
+      }
+
+      /*
+       * ok, so what happens if there is an alias in the DN of a dereferenced
+       * alias object?  
+       */
+      if ( (e = dn2entry_r( be, newDN, &matched )) == NULL ) {
+
+       /* could not deref return error  */
+       Debug( LDAP_DEBUG_TRACE, 
+              "<= %s is a dangling alias to %s\n", 
+              oldDN, newDN, 0 );
+       send_ldap_result( conn, op, LDAP_ALIAS_DEREF_PROBLEM,
+               NULL, "dangling alias", NULL );
+
+       if (matched != NULL) free(matched);
+       free (newDN);
+       free (oldDN);
+       break;
+      }
+
+      free (newDN);
+      free (oldDN);
+    }
+    else {
+      /*
+       * there was an aliasedobjectname defined but no data.
+       * this can't happen, right?
+       */
+       Debug( LDAP_DEBUG_TRACE, 
+              "<= %s has no data in aliasedobjectname attribute\n", 
+              (e && e->e_dn) ? e->e_dn : "(null)", 0, 0 );
+       send_ldap_result( conn, op, LDAP_ALIAS_PROBLEM,
+               NULL, "alias missing aliasedObjectName", NULL );
+       break;
+    }
+  }
+
+  /*
+   * warn if we pulled out due to exceeding the maximum deref depth
+   */
+  if ( depth >= be->be_maxDerefDepth ) {
+    Debug( LDAP_DEBUG_TRACE, 
+          "<= deref(\"%s\") exceeded maximum deref depth (%d) at \"%s\"\n", 
+          origDN->e_dn ? origDN->e_dn : "(null)", 
+          be->be_maxDerefDepth, 
+          (e && e->e_ndn) ? e->e_ndn : "(null)");
+    send_ldap_result( conn, op, LDAP_ALIAS_DEREF_PROBLEM,
+               NULL, "maximum alias dereference depth exceeded", NULL );
+  }
+
+  return e;
+}
+
+/*
+ * given a DN fully deref it and return the real DN or original DN if it fails
+ * This involves finding the last matched part then reconstructing forward
+ * e.g. 
+ * ou=MyOU,o=MyAliasedOrg,c=MyCountry where o=MyAliasedOrg is an alias for o=MyOrg
+ * loop starts with newDN = ou=MyOU,o=MyAliasedOrg,c=MyCountry
+ *   dn2entry_r on newDN gives null entry and o=MyAliasedOrg,c=MyCountry matched
+ *   dn2entry_r on matched gives o=MyAliasedOrg,c=MyCountry entry
+ *   remainder is ou=MyOU
+ *   dereferencing o=MyAliasedOrg,c=MyCountry yields entry o=MyOrg,c=MyCountry
+ *   release lock on o=MyAliasedOrg,c=MyCountry entry
+ *   reconstructed dn is ou=MyOU,o=MyOrg,c=MyCountry
+ *   release lock on o=MyOrg,c=MyCountry entry
+ */
+char *derefDN ( Backend     *be,
+                Connection  *conn,
+                Operation   *op,
+                char        *dn
+)
+{
+  struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+  char         *matched = 0;
+  char         *newDN = NULL;
+  int  depth, i;
+  Entry        *eMatched;
+  Entry        *eDeref;
+  Entry         *eNew;
+  
+  if (!dn) return NULL; 
+
+  Debug( LDAP_DEBUG_TRACE, 
+        "<= dereferencing dn: \"%s\"\n", 
+        dn, 0, 0 );
+  
+  newDN = ch_strdup ( dn );
+
+  /* while we don't have a matched dn, deref the DN */
+  for ( depth = 0;
+       ( (eMatched = dn2entry_r( be, newDN, &matched )) == NULL) &&
+         (depth < be->be_maxDerefDepth);
+       ++depth ) {
+    
+    if ((matched != NULL) && *matched) {       
+      char *submatch;
+   
+      /* 
+       * make sure there actually is an entry for the matched part 
+       */
+      if ( (eMatched = dn2entry_r( be, matched, &submatch )) != NULL) {
+       char  *remainder; /* part before the aliased part */
+       int  rlen = strlen(newDN) - strlen(matched);
+       
+       Debug( LDAP_DEBUG_TRACE, "<= matched %s\n", matched, 0, 0 );
+       
+       remainder = ch_malloc (rlen + 1);
+       strncpy ( remainder, newDN, rlen );
+       remainder[rlen] = '\0';
+       
+       Debug( LDAP_DEBUG_TRACE, "<= remainder %s\n", remainder, 0, 0 );
+       
+       if ((eNew = derefAlias_r( be, conn, op, eMatched )) == NULL) {
+         free (matched);
+         matched = NULL;
+         free (newDN);
+         newDN = NULL;
+         free (remainder);
+         remainder = NULL;
+         
+         cache_return_entry_r(&li->li_cache, eMatched);
+         eMatched = NULL;
+         break; /*  no associated entry, dont deref */
+       }
+       else {
+
+         Debug( LDAP_DEBUG_TRACE, "<= l&g we have %s vs %s \n", matched, eNew->e_dn, 0 );
+
+         i = strcasecmp (matched, eNew->e_dn);
+          /* free reader lock */
+          cache_return_entry_r(&li->li_cache, eNew);
+
+         free (matched);
+         matched = NULL;
+
+         if (! i) {
+           /* newDN same as old so not an alias, no need to go further */
+           free (newDN);
+           newDN = NULL;
+           free (remainder);
+
+           cache_return_entry_r(&li->li_cache, eMatched);
+           eMatched = NULL;
+           break;
+         }
+
+         /* 
+          * we have dereferenced the aliased part so put
+          * the new dn together
+          */
+         free (newDN);
+         newDN = ch_malloc (strlen(eMatched->e_dn) + rlen + 1);
+         strcpy (newDN, remainder);
+         strcat (newDN, eMatched->e_dn);
+         Debug( LDAP_DEBUG_TRACE, "<= expanded to %s\n", newDN, 0, 0 );
+
+         free (remainder);
+       }
+       /* free reader lock */
+       cache_return_entry_r(&li->li_cache, eMatched);
+      }
+      else {
+       if(submatch != NULL) free(submatch);
+       break; /* there was no entry for the matched part */
+      }
+    }
+    else {
+      break; /* there was no matched part */
+    }
+  }
+  
+  /* release lock if a match terminated the loop, there should be no
+   * outstanding locks at this point
+   */
+  if(eMatched != NULL) {
+    /* free reader lock */
+    cache_return_entry_r(&li->li_cache, eMatched);
+  }
+
+  /*
+   * the final part of the DN might be an alias so try to dereference it.
+   * e.g. if we had started with dn = o=MyAliasedOrg,c=MyCountry the dn would match
+   * and the above loop complete but we would still be left with an aliased DN.
+   */
+  if (newDN != NULL) {
+    if ( (eNew = dn2entry_r( be, newDN, &matched )) != NULL) {
+      if ((eDeref = derefAlias_r( be, conn, op, eNew )) != NULL) {
+        free (newDN);
+        newDN = ch_strdup (eDeref->e_dn);
+        /* free reader lock */
+        cache_return_entry_r(&li->li_cache, eDeref);
+      }
+      /* free reader lock */
+      cache_return_entry_r(&li->li_cache, eNew);
+    }
+  }
+  if (matched != NULL) free(matched);
+  
+  /*
+   * warn if we exceeded the max depth as the resulting DN may not be dereferenced
+   */
+  if (depth >= be->be_maxDerefDepth) {
+    if (newDN) {
+      Debug( LDAP_DEBUG_TRACE, 
+            "<= max deref depth exceeded in derefDN for \"%s\", result \"%s\"\n", 
+            dn, newDN, 0 );
+      free (newDN);
+      newDN = NULL;
+    }
+    else {
+      Debug( LDAP_DEBUG_TRACE, 
+            "<= max deref depth exceeded in derefDN for \"%s\", result NULL\n", 
+            dn, 0, 0 );
+    }
+    send_ldap_result( conn, op, LDAP_ALIAS_DEREF_PROBLEM,
+               NULL, "maximum alias dereference depth exceeded for base", NULL );
+  }
+
+  if (newDN == NULL) {
+    newDN = ch_strdup ( dn );
+  }
+  
+  Debug( LDAP_DEBUG_TRACE, "<= returning deref DN of \"%s\"\n", newDN, 0, 0 ); 
+
+  return newDN;
+}
index 88fd4030c41df52a20815451fdc6491f4f431449..2fb2abedc76c0e35fa0f464d591583d0fbc8ffa9 100644 (file)
@@ -1,22 +1,63 @@
 /* bind.c - ldbm backend bind and unbind routines */
 
+#include "portable.h"
+
 #include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
+
+#include <ac/krb.h>
+#include <ac/socket.h>
+#include <ac/string.h>
+#include <ac/unistd.h>
+
 #include "slap.h"
 #include "back-ldbm.h"
-#ifdef KERBEROS
-#include "krb.h"
-#endif
+#include "proto-back-ldbm.h"
 
-extern Entry           *dn2entry();
-extern Attribute       *attr_find();
+#include <lutil.h>
 
-#ifdef KERBEROS
+#ifdef HAVE_KERBEROS
 extern int     krbv4_ldap_auth();
 #endif
 
+static int
+crypted_value_find(
+       struct berval       **vals,
+       struct berval       *v,
+       int                 syntax,
+       int                 normalize,
+       struct berval           *cred
+)
+{
+       int     i;
+       for ( i = 0; vals[i] != NULL; i++ ) {
+               if ( syntax != SYNTAX_BIN ) {
+                       int result;
+
+#ifdef SLAPD_CRYPT
+                       ldap_pvt_thread_mutex_lock( &crypt_mutex );
+#endif
+
+                       result = lutil_passwd(
+                               (char*) cred->bv_val,
+                               (char*) vals[i]->bv_val,
+                               NULL );
+
+#ifdef SLAPD_CRYPT
+                       ldap_pvt_thread_mutex_unlock( &crypt_mutex );
+#endif
+
+                       return result;
+
+               } else {
+                if ( value_cmp( vals[i], v, syntax, normalize ) == 0 ) {
+                        return( 0 );
+                }
+        }
+       }
+
+       return( 1 );
+}
+
 int
 ldbm_back_bind(
     Backend            *be,
@@ -24,127 +65,209 @@ ldbm_back_bind(
     Operation          *op,
     char               *dn,
     int                        method,
-    struct berval      *cred
+       char            *mech,
+    struct berval      *cred,
+       char**  edn
 )
 {
        struct ldbminfo *li = (struct ldbminfo *) be->be_private;
        Entry           *e;
        Attribute       *a;
        int             rc;
-       char            *matched = NULL;
-#ifdef KERBEROS
+       char            *matched;
+#ifdef HAVE_KERBEROS
        char            krbname[MAX_K_NAME_SZ + 1];
        AUTH_DAT        ad;
 #endif
 
-       if ( (e = dn2entry( be, dn, &matched )) == NULL ) {
+       Debug(LDAP_DEBUG_ARGS, "==> ldbm_back_bind: dn: %s\n", dn, 0, 0);
+
+       *edn = NULL;
+
+       /* get entry with reader lock */
+       if ( (e = dn2entry_r( be, dn, &matched )) == NULL ) {
                /* allow noauth binds */
-               if ( method == LDAP_AUTH_SIMPLE && cred->bv_len == 0 ) {
-                       /*
-                        * bind successful, but return 1 so we don't
-                        * authorize based on noauth credentials
-                        */
-                       send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
-                       rc = 1;
-               } else if ( be_isroot_pw( be, dn, cred ) ) {
-                       /* front end will send result */
-                       rc = 0;
+               rc = 1;
+               if ( method == LDAP_AUTH_SIMPLE ) {
+                       if( cred->bv_len == 0 ) {
+                               /* SUCCESS */
+                               send_ldap_result( conn, op, LDAP_SUCCESS,
+                                       NULL, NULL, NULL );
+
+                       } else if ( be_isroot_pw( be, dn, cred ) ) {
+                               *edn = ch_strdup( be_root_dn( be ) );
+                               rc = 0; /* front end will send result */
+
+                       } else {
+                               send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT,
+                                       matched, NULL, NULL );
+                       }
+
+               } else if ( method == LDAP_AUTH_SASL ) {
+                       if( mech != NULL && strcasecmp(mech,"DIGEST-MD5") == 0 ) {
+                               /* insert DIGEST calls here */
+                               send_ldap_result( conn, op, LDAP_AUTH_METHOD_NOT_SUPPORTED,
+                                       NULL, NULL, NULL );
+                               
+                       } else {
+                               send_ldap_result( conn, op, LDAP_AUTH_METHOD_NOT_SUPPORTED,
+                                       NULL, NULL, NULL );
+                       }
+
                } else {
                        send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT,
-                           matched, NULL );
-                       rc = 1;
+                               matched, NULL, NULL );
                }
+
                if ( matched != NULL ) {
                        free( matched );
                }
                return( rc );
        }
 
+       *edn = ch_strdup( e->e_dn );
+
+       /* check for deleted */
+
+       if ( ! access_allowed( be, conn, op, e,
+               "entry", NULL, ACL_AUTH ) )
+       {
+               send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
+                       NULL, NULL, NULL );
+               rc = 1;
+               goto return_results;
+       }
+
        switch ( method ) {
        case LDAP_AUTH_SIMPLE:
                if ( cred->bv_len == 0 ) {
-                       send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
-                       return( 1 );
-               } else if ( be_isroot_pw( be, dn, cred ) ) {
+                       send_ldap_result( conn, op, LDAP_SUCCESS,
+                               NULL, NULL, NULL );
+
+                       /* stop front end from sending result */
+                       rc = 1;
+                       goto return_results;
+               } 
+
+               /* check for root dn/passwd */
+               if ( be_isroot_pw( be, dn, cred ) ) {
                        /* front end will send result */
-                       return( 0 );
+                       if(*edn != NULL) free( *edn );
+                       *edn = ch_strdup( be_root_dn( be ) );
+                       rc = 0;
+                       goto return_results;
+               }
+
+               if ( ! access_allowed( be, conn, op, e,
+                       "userpassword", NULL, ACL_AUTH ) )
+               {
+                       send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
+                               NULL, NULL, NULL );
+                       rc = 1;
+                       goto return_results;
                }
 
                if ( (a = attr_find( e->e_attrs, "userpassword" )) == NULL ) {
-                       if ( be_isroot_pw( be, dn, cred ) ) {
-                               /* front end will send result */
-                               return( 0 );
-                       }
                        send_ldap_result( conn, op, LDAP_INAPPROPRIATE_AUTH,
-                           NULL, NULL );
-                       cache_return_entry( &li->li_cache, e );
-                       return( 1 );
+                           NULL, NULL, NULL );
+
+                       /* stop front end from sending result */
+                       rc = 1;
+                       goto return_results;
                }
 
-               if ( value_find( a->a_vals, cred, a->a_syntax, 0 ) != 0 ) {
-                       if ( be_isroot_pw( be, dn, cred ) ) {
-                               /* front end will send result */
-                               return( 0 );
-                       }
+               if ( crypted_value_find( a->a_vals, cred, a->a_syntax, 0, cred ) != 0 )
+               {
                        send_ldap_result( conn, op, LDAP_INVALID_CREDENTIALS,
-                           NULL, NULL );
-                       cache_return_entry( &li->li_cache, e );
-                       return( 1 );
+                               NULL, NULL, NULL );
+                       /* stop front end from sending result */
+                       rc = 1;
+                       goto return_results;
                }
+
+               rc = 0;
                break;
 
-#ifdef KERBEROS
+#ifdef HAVE_KERBEROS
        case LDAP_AUTH_KRBV41:
+               if ( ! access_allowed( be, conn, op, e,
+                       "krbname", NULL, ACL_AUTH ) )
+               {
+                       send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, NULL, NULL, NULL );
+                       rc = 1;
+                       goto return_results;
+               }
+
                if ( krbv4_ldap_auth( be, cred, &ad ) != LDAP_SUCCESS ) {
                        send_ldap_result( conn, op, LDAP_INVALID_CREDENTIALS,
                            NULL, NULL );
-                       cache_return_entry( &li->li_cache, e );
-                       return( 1 );
+                       rc = 1;
+                       goto return_results;
+               }
+
+               if ( ! access_allowed( be, conn, op, e,
+                       "krbname", NULL, ACL_AUTH ) )
+               {
+                       send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, "", "" );
+                       rc = 1;
+                       goto return_results;
                }
+
                sprintf( krbname, "%s%s%s@%s", ad.pname, *ad.pinst ? "."
                    : "", ad.pinst, ad.prealm );
+
+
                if ( (a = attr_find( e->e_attrs, "krbname" )) == NULL ) {
                        /*
                         * no krbName values present:  check against DN
                         */
                        if ( strcasecmp( dn, krbname ) == 0 ) {
+                               rc = 0;
                                break;
                        }
                        send_ldap_result( conn, op, LDAP_INAPPROPRIATE_AUTH,
                            NULL, NULL );
-                       cache_return_entry( &li->li_cache, e );
-                       return( 1 );
+                       rc = 1;
+                       goto return_results;
+
                } else {        /* look for krbName match */
                        struct berval   krbval;
 
                        krbval.bv_val = krbname;
                        krbval.bv_len = strlen( krbname );
 
-                       if ( value_find( a->a_vals, &krbval, a->a_syntax, 3 )
-                           != 0 ) {
+                       if ( value_find( a->a_vals, &krbval, a->a_syntax, 3 ) != 0 ) {
                                send_ldap_result( conn, op,
                                    LDAP_INVALID_CREDENTIALS, NULL, NULL );
-                               cache_return_entry( &li->li_cache, e );
-                               return( 1 );
+                               rc = 1;
+                               goto return_results;
                        }
                }
+               rc = 0;
                break;
 
        case LDAP_AUTH_KRBV42:
                send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
-               cache_return_entry( &li->li_cache, e );
-               return( 1 );
+               /* stop front end from sending result */
+               rc = 1;
+               goto return_results;
 #endif
 
+       case LDAP_AUTH_SASL:
+               /* insert SASL code here */
+
        default:
                send_ldap_result( conn, op, LDAP_STRONG_AUTH_NOT_SUPPORTED,
-                   NULL, "auth method not supported" );
-               cache_return_entry( &li->li_cache, e );
-               return( 1 );
+                   NULL, "auth method not supported", NULL );
+               rc = 1;
+               goto return_results;
        }
 
-       cache_return_entry( &li->li_cache, e );
+return_results:;
+       /* free entry and reader lock */
+       cache_return_entry_r( &li->li_cache, e );
 
-       /* success:  front end will send result */
-       return( 0 );
+       /* front end with send result on success (rc==0) */
+       return( rc );
 }
+
index 4757a29b9228684dbfb6e834b74ed8fa0c66e857..160d5fab91f412e0c4799d8889528150407e8d7a 100644 (file)
@@ -1,14 +1,15 @@
 /* compare.c - ldbm backend compare routine */
 
+#include "portable.h"
+
 #include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
+
+#include <ac/socket.h>
+#include <ac/string.h>
+
 #include "slap.h"
 #include "back-ldbm.h"
-
-extern Entry           *dn2entry();
-extern Attribute       *attr_find();
+#include "proto-back-ldbm.h"
 
 int
 ldbm_back_compare(
@@ -23,33 +24,44 @@ ldbm_back_compare(
        char            *matched;
        Entry           *e;
        Attribute       *a;
-       int             i;
+       int             rc;
+
+       /* get entry with reader lock */
+       if ( (e = dn2entry_r( be, dn, &matched )) == NULL ) {
+               send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT,
+                       matched, NULL, NULL );
 
-       if ( (e = dn2entry( be, dn, &matched )) == NULL ) {
-               send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched, "" );
+               if(matched == NULL) free(matched);
                return( 1 );
        }
 
-       if ( ! access_allowed( be, conn, op, e, ava->ava_type, &ava->ava_value,
-           op->o_dn, ACL_COMPARE ) ) {
-               send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, "", "" );
-               cache_return_entry( &li->li_cache, e );
-               return( 1 );
+       /* check for deleted */
+       if ( ! access_allowed( be, conn, op, e,
+               ava->ava_type, &ava->ava_value, ACL_COMPARE ) )
+       {
+               send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
+                       NULL, NULL, NULL );
+               rc = 1;
+               goto return_results;
        }
 
        if ( (a = attr_find( e->e_attrs, ava->ava_type )) == NULL ) {
-               send_ldap_result( conn, op, LDAP_NO_SUCH_ATTRIBUTE, "", "" );
-               cache_return_entry( &li->li_cache, e );
-               return( 1 );
+               send_ldap_result( conn, op, LDAP_NO_SUCH_ATTRIBUTE,
+                       NULL, NULL, NULL );
+               rc = 1;
+               goto return_results;
        }
 
-       if ( value_find( a->a_vals, &ava->ava_value, a->a_syntax, 1 ) == 0 ) {
-               send_ldap_result( conn, op, LDAP_COMPARE_TRUE, "", "" );
-               cache_return_entry( &li->li_cache, e );
-               return( 0 );
-       }
+       if ( value_find( a->a_vals, &ava->ava_value, a->a_syntax, 1 ) == 0 ) 
+               send_ldap_result( conn, op, LDAP_COMPARE_TRUE,
+                       NULL, NULL, NULL );
+       else
+               send_ldap_result( conn, op, LDAP_COMPARE_FALSE,
+                       NULL, NULL, NULL );
+
+       rc = 0;
 
-       send_ldap_result( conn, op, LDAP_COMPARE_FALSE, "", "" );
-       cache_return_entry( &li->li_cache, e );
-       return( 0 );
+return_results:;
+       cache_return_entry_r( &li->li_cache, e );
+       return( rc );
 }
index c773929ffb43a64eb73ba3e3b7c28124a5655b08..2324f16b0087cbde0b8f2289aef2e3b9ee79d2fe 100644 (file)
@@ -1,14 +1,15 @@
 /* delete.c - ldbm backend delete routine */
 
+#include "portable.h"
+
 #include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
+
+#include <ac/string.h>
+#include <ac/socket.h>
+
 #include "slap.h"
 #include "back-ldbm.h"
-
-extern Entry           *dn2entry();
-extern Attribute       *attr_find();
+#include "proto-back-ldbm.h"
 
 int
 ldbm_back_delete(
@@ -19,49 +20,137 @@ ldbm_back_delete(
 )
 {
        struct ldbminfo *li = (struct ldbminfo *) be->be_private;
-       char            *matched = NULL;
-       Entry           *e;
+       char    *matched = NULL;
+       char    *pdn = NULL;
+       Entry   *e, *p = NULL;
+       int rootlock = 0;
+       int     rc = -1;
 
-       if ( (e = dn2entry( be, dn, &matched )) == NULL ) {
-               send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched, "" );
+       Debug(LDAP_DEBUG_ARGS, "==> ldbm_back_delete: %s\n", dn, 0, 0);
+
+       /* get entry with writer lock */
+       if ( (e = dn2entry_w( be, dn, &matched )) == NULL ) {
+               Debug(LDAP_DEBUG_ARGS, "<=- ldbm_back_delete: no such object %s\n",
+                       dn, 0, 0);
+               send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT,
+                       matched, NULL, NULL );
                if ( matched != NULL ) {
                        free( matched );
                }
                return( -1 );
        }
 
+       /* check for deleted */
+
        if ( has_children( be, e ) ) {
-               send_ldap_result( conn, op, LDAP_NOT_ALLOWED_ON_NONLEAF, "",
-                   "" );
-               cache_return_entry( &li->li_cache, e );
-               return( -1 );
+               Debug(LDAP_DEBUG_ARGS, "<=- ldbm_back_delete: non leaf %s\n",
+                       dn, 0, 0);
+               send_ldap_result( conn, op, LDAP_NOT_ALLOWED_ON_NONLEAF,
+                       NULL, NULL, NULL );
+               goto return_results;
        }
 
-       if ( ! access_allowed( be, conn, op, e, "entry", NULL, op->o_dn,
-           ACL_WRITE ) ) {
-               send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, "", "" );
-               cache_return_entry( &li->li_cache, e );
-               return( -1 );
+#ifdef SLAPD_CHILD_MODIFICATION_WITH_ENTRY_ACL
+       if ( ! access_allowed( be, conn, op, e,
+               "entry", NULL, ACL_WRITE ) )
+       {
+               Debug(LDAP_DEBUG_ARGS,
+                       "<=- ldbm_back_delete: insufficient access %s\n",
+                       dn, 0, 0);
+               send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
+                       NULL, NULL, NULL );
+               goto return_results;
+       }
+#endif
+
+       /* delete from parent's id2children entry */
+       if( (pdn = dn_parent( be, e->e_ndn )) != NULL ) {
+               if( (p = dn2entry_w( be, pdn, &matched )) == NULL) {
+                       Debug( LDAP_DEBUG_TRACE,
+                               "<=- ldbm_back_delete: parent does not exist\n",
+                               0, 0, 0);
+                       send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
+                               NULL, NULL, NULL );
+                       goto return_results;
+               }
+
+               /* check parent for "children" acl */
+               if ( ! access_allowed( be, conn, op, p,
+                       "children", NULL, ACL_WRITE ) )
+               {
+                       Debug( LDAP_DEBUG_TRACE,
+                               "<=- ldbm_back_delete: no access to parent\n", 0,
+                               0, 0 );
+                       send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
+                               NULL, NULL, NULL );
+                       goto return_results;
+               }
+
+       } else {
+               /* no parent, must be root to delete */
+               if( ! be_isroot( be, op->o_ndn ) ) {
+                       Debug( LDAP_DEBUG_TRACE,
+                               "<=- ldbm_back_delete: no parent & not root\n",
+                               0, 0, 0);
+                       send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
+                               NULL, NULL, NULL );
+                       goto return_results;
+               }
+
+               ldap_pvt_thread_mutex_lock(&li->li_root_mutex);
+               rootlock = 1;
        }
 
-       /* XXX delete from parent's id2children entry XXX */
+       if ( id2children_remove( be, p, e ) != 0 ) {
+               Debug(LDAP_DEBUG_ARGS,
+                       "<=- ldbm_back_delete: operations error %s\n",
+                       dn, 0, 0);
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
+                       NULL, NULL, NULL );
+               goto return_results;
+       }
 
        /* delete from dn2id mapping */
-       if ( dn2id_delete( be, e->e_dn ) != 0 ) {
-               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
-               cache_return_entry( &li->li_cache, e );
-               return( -1 );
+       if ( dn2id_delete( be, e->e_ndn ) != 0 ) {
+               Debug(LDAP_DEBUG_ARGS,
+                       "<=- ldbm_back_delete: operations error %s\n",
+                       dn, 0, 0);
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
+                       NULL, NULL, NULL );
+               goto return_results;
        }
 
        /* delete from disk and cache */
        if ( id2entry_delete( be, e ) != 0 ) {
-               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
-               cache_return_entry( &li->li_cache, e );
-               return( -1 );
+               Debug(LDAP_DEBUG_ARGS,
+                       "<=- ldbm_back_delete: operations error %s\n",
+                       dn, 0, 0);
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
+                       NULL, NULL, NULL );
+               goto return_results;
        }
-       cache_return_entry( &li->li_cache, e );
 
-       send_ldap_result( conn, op, LDAP_SUCCESS, "", "" );
+       send_ldap_result( conn, op, LDAP_SUCCESS,
+               NULL, NULL, NULL );
+       rc = 0;
+
+return_results:;
+       if ( pdn != NULL ) free(pdn);
+
+       if( p != NULL ) {
+               /* free parent and writer lock */
+               cache_return_entry_w( &li->li_cache, p );
+       }
+
+       if ( rootlock ) {
+               /* release root lock */
+               ldap_pvt_thread_mutex_unlock(&li->li_root_mutex);
+       }
+
+       /* free entry and writer lock */
+       cache_return_entry_w( &li->li_cache, e );
+
+       if ( matched != NULL ) free(matched);
 
-       return( 0 );
+       return rc;
 }
index 3fa6c61a92cc317e3294b906f70ecaeac9c10002..941203a1007d2a9625d7f275ba6b212e1c4b416e 100644 (file)
 /* modify.c - ldbm backend modify routine */
 
+#include "portable.h"
+
 #include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
+
+#include <ac/string.h>
+#include <ac/socket.h>
+#include <ac/time.h>
+
 #include "slap.h"
 #include "back-ldbm.h"
+#include "proto-back-ldbm.h"
 
-extern int             global_schemacheck;
-extern Entry           *dn2entry();
-extern Attribute       *attr_find();
+static void    add_lastmods(Operation *op, LDAPModList **ml);
 
-static int     add_values();
-static int     delete_values();
-static int     replace_values();
 
-int
-ldbm_back_modify(
+static void
+add_lastmods( Operation *op, LDAPModList **modlist )
+{
+       char            buf[22];
+       struct berval   bv;
+       struct berval   *bvals[2];
+       LDAPModList             **m;
+       LDAPModList             *tmp;
+       struct tm       *ltm;
+       time_t          currenttime;
+
+       Debug( LDAP_DEBUG_TRACE, "add_lastmods\n", 0, 0, 0 );
+
+       bvals[0] = &bv;
+       bvals[1] = NULL;
+
+       /* remove any attempts by the user to modify these attrs */
+       for ( m = modlist; *m != NULL; m = &(*m)->ml_next ) {
+            if ( oc_check_no_usermod_attr( (*m)->ml_type ) ) {
+                Debug( LDAP_DEBUG_TRACE,
+                                       "add_lastmods: found no user mod attr: %s\n",
+                                       (*m)->ml_type, 0, 0 );
+                tmp = *m;
+                *m = (*m)->ml_next;
+                free( tmp->ml_type );
+                if ( tmp->ml_bvalues != NULL ) {
+                    ber_bvecfree( tmp->ml_bvalues );
+                }
+                free( tmp );
+                if (!*m)
+                    break;
+            }
+        }
+
+       if ( op->o_dn == NULL || op->o_dn[0] == '\0' ) {
+               bv.bv_val = "NULLDN";
+               bv.bv_len = strlen( bv.bv_val );
+       } else {
+               bv.bv_val = op->o_dn;
+               bv.bv_len = strlen( bv.bv_val );
+       }
+       tmp = (LDAPModList *) ch_calloc( 1, sizeof(LDAPModList) );
+       tmp->ml_type = ch_strdup( "modifiersname" );
+       tmp->ml_op = LDAP_MOD_REPLACE;
+       tmp->ml_bvalues = (struct berval **) ch_calloc(2, sizeof(struct berval *));
+       tmp->ml_bvalues[0] = ber_bvdup( &bv );
+       tmp->ml_next = *modlist;
+       *modlist = tmp;
+
+       currenttime = slap_get_time();
+       ldap_pvt_thread_mutex_lock( &gmtime_mutex );
+#ifndef LDAP_LOCALTIME
+       ltm = gmtime( &currenttime );
+       strftime( buf, sizeof(buf), "%Y%m%d%H%M%SZ", ltm );
+#else
+       ltm = localtime( &currenttime );
+       strftime( buf, sizeof(buf), "%y%m%d%H%M%SZ", ltm );
+#endif
+       ldap_pvt_thread_mutex_unlock( &gmtime_mutex );
+
+       bv.bv_val = buf;
+       bv.bv_len = strlen( bv.bv_val );
+       tmp = (LDAPModList *) ch_calloc( 1, sizeof(LDAPModList) );
+       tmp->ml_type = ch_strdup( "modifytimestamp" );
+       tmp->ml_op = LDAP_MOD_REPLACE;
+       tmp->ml_bvalues = (struct berval **) ch_calloc(2, sizeof(struct berval *));
+       tmp->ml_bvalues[0] = ber_bvdup( &bv );
+       tmp->ml_next = *modlist;
+       *modlist = tmp;
+
+}
+
+/* We need this function because of LDAP modrdn. If we do not 
+ * add this there would be a bunch of code replication here 
+ * and there and of course the likelihood of bugs increases.
+ * Juan C. Gomez (gomez@engr.sgi.com) 05/18/99
+ */ 
+
+int ldbm_modify_internal(
     Backend    *be,
     Connection *conn,
     Operation  *op,
     char       *dn,
-    LDAPMod    *mods
+    LDAPModList        *modlist,
+    Entry      *e 
 )
 {
-       struct ldbminfo *li = (struct ldbminfo *) be->be_private;
-       char            *matched = NULL;
-       Entry           *e;
-       int             i, err, modtype;
+       int err;
        LDAPMod         *mod;
+       LDAPModList     *ml;
+       Attribute       *a;
+
+       if ( ((be->be_lastmod == ON)
+             || ((be->be_lastmod == UNDEFINED)&&(global_lastmod == ON)))
+            && (be->be_update_ndn == NULL)) {
+
+               /* XXX: It may be wrong, it changes mod time even if 
+                * mod fails!
+                */
+               add_lastmods( op, &modlist );
 
-       if ( (e = dn2entry( be, dn, &matched )) == NULL ) {
-               send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched,
-                   NULL );
-               if ( matched != NULL ) {
-                       free( matched );
-               }
-               return( -1 );
        }
-       /* lock entry */
 
-       if ( (err = acl_check_mods( be, conn, op, e, mods )) != LDAP_SUCCESS ) {
-               send_ldap_result( conn, op, err, NULL, NULL );
-               cache_return_entry( &li->li_cache, e );
-               return( -1 );
+
+       if ( (err = acl_check_modlist( be, conn, op, e, modlist ))
+            != LDAP_SUCCESS ) {
+               send_ldap_result( conn, op, err, NULL, NULL, NULL );
+               return -1;
        }
 
-       for ( mod = mods; mod != NULL; mod = mod->mod_next ) {
+       for ( ml = modlist; ml != NULL; ml = ml->ml_next ) {
+
+               mod = &ml->ml_mod;
+
                switch ( mod->mod_op & ~LDAP_MOD_BVALUES ) {
                case LDAP_MOD_ADD:
-                       err = add_values( e, mod, op->o_dn );
+                       err = add_values( e, mod, op->o_ndn );
                        break;
 
                case LDAP_MOD_DELETE:
-                       err = delete_values( e, mod, op->o_dn );
+                       err = delete_values( e, mod, op->o_ndn );
                        break;
 
                case LDAP_MOD_REPLACE:
-                       err = replace_values( e, mod, op->o_dn );
+                       /* Need to remove all values from indexes before they
+                        * are lost.
+                        */
+                       if( e->e_attrs
+                           && ((a = attr_find( e->e_attrs, mod->mod_type ))
+                          != NULL) ) {
+
+                           (void) index_change_values( be,
+                                                       mod->mod_type,
+                                                       a->a_vals,
+                                                       e->e_id,
+                                                       __INDEX_DELETE_OP);
+                       }
+
+                       err = replace_values( e, mod, op->o_ndn );
                        break;
+
+               case LDAP_MOD_SOFTADD:
+                       /* Avoid problems in index_add_mods()
+                        * We need to add index if necessary.
+                        */
+                       mod->mod_op = LDAP_MOD_ADD;
+                       if ( (err = add_values( e, mod, op->o_ndn ))
+                               ==  LDAP_TYPE_OR_VALUE_EXISTS ) {
+                               err = LDAP_SUCCESS;
+                               mod->mod_op = LDAP_MOD_SOFTADD;
+                       }
+                       break;
                }
 
                if ( err != LDAP_SUCCESS ) {
                        /* unlock entry, delete from cache */
-                       send_ldap_result( conn, op, err, NULL, NULL );
-                       cache_return_entry( &li->li_cache, e );
-                       return( -1 );
+                       send_ldap_result( conn, op, err, NULL, NULL, NULL );
+                       return -1;
                }
        }
 
-       /* check for abandon */
-       pthread_mutex_lock( &op->o_abandonmutex );
-       if ( op->o_abandon ) {
-               pthread_mutex_unlock( &op->o_abandonmutex );
-               cache_return_entry( &li->li_cache, e );
-               return( -1 );
-       }
-       pthread_mutex_unlock( &op->o_abandonmutex );
-
        /* check that the entry still obeys the schema */
        if ( global_schemacheck && oc_schema_check( e ) != 0 ) {
-               send_ldap_result( conn, op, LDAP_OBJECT_CLASS_VIOLATION, NULL,
-                   NULL );
-               cache_return_entry( &li->li_cache, e );
-               return( -1 );
+               Debug( LDAP_DEBUG_ANY, "entry failed schema check\n", 0, 0, 0 );
+               send_ldap_result( conn, op, LDAP_OBJECT_CLASS_VIOLATION,
+                       NULL, NULL, NULL );
+               return -1;
+       }
+
+       /* check for abandon */
+       ldap_pvt_thread_mutex_lock( &op->o_abandonmutex );
+       if ( op->o_abandon ) {
+               ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
+               return -1;
        }
+       ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
 
        /* modify indexes */
-       if ( index_add_mods( be, mods, e->e_id ) != 0 ) {
-               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL );
-               cache_return_entry( &li->li_cache, e );
-               return( -1 );
+       if ( index_add_mods( be, modlist, e->e_id ) != 0 ) {
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
+                       NULL, NULL, NULL );
+               return -1;
        }
 
        /* check for abandon */
-       pthread_mutex_lock( &op->o_abandonmutex );
+       ldap_pvt_thread_mutex_lock( &op->o_abandonmutex );
        if ( op->o_abandon ) {
-               pthread_mutex_unlock( &op->o_abandonmutex );
-               cache_return_entry( &li->li_cache, e );
+               ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
+               return -1;
+       }
+       ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
+
+       return 0;
+
+}/* int ldbm_modify_internal() */
+
+
+int
+ldbm_back_modify(
+    Backend    *be,
+    Connection *conn,
+    Operation  *op,
+    char       *dn,
+    LDAPModList        *modlist
+)
+{
+       struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+       char            *matched;
+       Entry           *e;
+
+       Debug(LDAP_DEBUG_ARGS, "ldbm_back_modify:\n", 0, 0, 0);
+
+       /* acquire and lock entry */
+       if ( (e = dn2entry_w( be, dn, &matched )) == NULL ) {
+               send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT,
+                       matched, NULL, NULL );
+               if ( matched != NULL ) {
+                       free( matched );
+               }
                return( -1 );
        }
-       pthread_mutex_unlock( &op->o_abandonmutex );
+
+       /* Modify the entry */
+       if ( ldbm_modify_internal( be, conn, op, dn, modlist, e ) != 0 ) {
+               goto error_return;
+       }
 
        /* change the entry itself */
        if ( id2entry_add( be, e ) != 0 ) {
-               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL );
-               cache_return_entry( &li->li_cache, e );
-               return( -1 );
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
+                       NULL, NULL, NULL );
+               goto error_return;
        }
 
-       send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
-       cache_return_entry( &li->li_cache, e );
-
+       send_ldap_result( conn, op, LDAP_SUCCESS,
+               NULL, NULL, NULL );
+       cache_return_entry_w( &li->li_cache, e );
        return( 0 );
+
+error_return:;
+       cache_return_entry_w( &li->li_cache, e );
+       return( -1 );
 }
 
-static int
+int
 add_values(
     Entry      *e,
     LDAPMod    *mod,
@@ -143,7 +289,7 @@ add_values(
        return( LDAP_SUCCESS );
 }
 
-static int
+int
 delete_values(
     Entry      *e,
     LDAPMod    *mod,
@@ -199,13 +345,18 @@ delete_values(
        return( LDAP_SUCCESS );
 }
 
-static int
+int
 replace_values(
     Entry      *e,
     LDAPMod    *mod,
     char       *dn
 )
 {
+
+       /* XXX: BEFORE YOU GET RID OF PREVIOUS VALUES REMOVE FROM INDEX
+        * FILES
+        */
+
        (void) attr_delete( &e->e_attrs, mod->mod_type );
 
        if ( attr_merge( e, mod->mod_type, mod->mod_bvalues ) != 0 ) {
index fcd9fcc35a6f6c14ca2444386ed6f2eb48d093fb..e724b9c18b8f20cc9f34a3ea3727cdc4f0138f56 100644 (file)
@@ -1,14 +1,31 @@
 /* modrdn.c - ldbm backend modrdn routine */
 
+/*
+ * LDAP v3 newSuperior support. Add new rdn as an attribute.
+ * (Full support for v2 also used software/ideas contributed
+ * by Roy Hooper rhooper@cyberus.ca, thanks to him for his
+ * submission!.)
+ *
+ * Copyright 1999, Juan C. Gomez, All rights reserved.
+ * This software is not subject to any license of Silicon Graphics 
+ * Inc. or Purdue University.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * without restriction or fee of any kind as long as this notice
+ * is preserved.
+ *
+ */
+
+#include "portable.h"
+
 #include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
+
+#include <ac/string.h>
+#include <ac/socket.h>
+
 #include "slap.h"
 #include "back-ldbm.h"
-
-extern Entry   *dn2entry();
-extern char    *dn_parent();
+#include "proto-back-ldbm.h"
 
 int
 ldbm_back_modrdn(
@@ -17,116 +34,422 @@ ldbm_back_modrdn(
     Operation  *op,
     char       *dn,
     char       *newrdn,
-    int                deleteoldrdn
+    int                deleteoldrdn,
+    char       *newSuperior
 )
 {
        struct ldbminfo *li = (struct ldbminfo *) be->be_private;
-       char            *matched;
-       char            *pdn, *newdn, *p;
-       char            sep[2];
-       Entry           *e, *e2;
-
-       matched = NULL;
-       if ( (e = dn2entry( be, dn, &matched )) == NULL ) {
-               send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched, "" );
+       char            *matched = NULL;
+       char            *p_dn = NULL, *p_ndn = NULL;
+       char            *new_dn = NULL, *new_ndn = NULL;
+       Entry           *e, *p = NULL;
+       int                     rootlock = 0;
+       int                     rc = -1;
+       /* Added to support LDAP v2 correctly (deleteoldrdn thing) */
+       char            *new_rdn_val = NULL;    /* Val of new rdn */
+       char            *new_rdn_type = NULL;   /* Type of new rdn */
+       char            *old_rdn;               /* Old rdn's attr type & val */
+       char            *old_rdn_type = NULL;   /* Type of old rdn attr. */
+       char            *old_rdn_val = NULL;    /* Old rdn attribute value */
+       /* Added to support newSuperior */ 
+       Entry           *np = NULL;     /* newSuperior Entry */
+       char            *np_dn = NULL;  /* newSuperior dn */
+       char            *np_ndn = NULL; /* newSuperior ndn */
+       char            *new_parent_dn = NULL;  /* np_dn, p_dn, or NULL */
+       /* Used to interface with ldbm_modify_internal() */
+       struct berval   add_bv;                 /* Stores new rdn att */
+       struct berval   *add_bvals[2];          /* Stores new rdn att */
+       struct berval   del_bv;                 /* Stores old rdn att */
+       struct berval   *del_bvals[2];          /* Stores old rdn att */
+       LDAPModList     mod[2];                 /* Used to delete old rdn */
+
+
+       Debug( LDAP_DEBUG_TRACE, "==>ldbm_back_modrdn(newSuperior=%s)\n",
+              (newSuperior ? newSuperior : "NULL"),
+              0, 0 );
+
+       /* get entry with writer lock */
+       if ( (e = dn2entry_w( be, dn, &matched )) == NULL ) {
+               send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT,
+                       matched, NULL, NULL );
                if ( matched != NULL ) {
                        free( matched );
                }
                return( -1 );
        }
 
-       if ( (pdn = dn_parent( be, dn )) != NULL ) {
-               /* parent + rdn + separator(s) + null */
-               newdn = (char *) ch_malloc( strlen( pdn ) + strlen( newrdn )
-                   + 3 );
-               if ( dn_type( dn ) == DN_X500 ) {
-                       strcpy( newdn, newrdn );
-                       strcat( newdn, ", " );
-                       strcat( newdn, pdn );
-               } else {
-                       strcpy( newdn, newrdn );
-                       p = strchr( newrdn, '\0' );
-                       p--;
-                       if ( *p != '.' && *p != '@' ) {
-                               if ( (p = strpbrk( dn, ".@" )) != NULL ) {
-                                       sep[0] = *p;
-                                       sep[1] = '\0';
-                                       strcat( newdn, sep );
-                               }
-                       }
-                       strcat( newdn, pdn );
+#ifdef SLAPD_CHILD_MODIFICATION_WITH_ENTRY_ACL
+               /* check parent for "children" acl */
+       if ( ! access_allowed( be, conn, op, e,
+               "entry", NULL, ACL_WRITE ) )
+       {
+               Debug( LDAP_DEBUG_TRACE, "no access to entry\n", 0,
+                       0, 0 );
+               send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
+                       "", "" );
+               goto return_results;
+       }
+#endif
+
+       if ( (p_ndn = dn_parent( be, e->e_ndn )) != NULL ) {
+
+               /* Make sure parent entry exist and we can write its 
+                * children.
+                */
+
+               if( (p = dn2entry_w( be, p_ndn, &matched )) == NULL) {
+                       Debug( LDAP_DEBUG_TRACE, "parent does not exist\n",
+                               0, 0, 0);
+                       send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
+                               NULL, NULL, NULL );
+                       goto return_results;
                }
+
+               /* check parent for "children" acl */
+               if ( ! access_allowed( be, conn, op, p,
+                       "children", NULL, ACL_WRITE ) )
+               {
+                       Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0,
+                               0, 0 );
+                       send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
+                               NULL, NULL, NULL );
+                       goto return_results;
+               }
+
+               Debug( LDAP_DEBUG_TRACE,
+                      "ldbm_back_modrdn: wr to children of entry %s OK\n",
+                      p_ndn, 0, 0 );
+               
+               p_dn = dn_parent( be, e->e_dn );
+       
+
+               Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: parent dn=%s\n",
+                      p_dn, 0, 0 );
+
        } else {
-               newdn = strdup( newrdn );
-       }
-       (void) dn_normalize( newdn );
+               /* no parent, modrdn entry directly under root */
+               if( ! be_isroot( be, op->o_ndn ) ) {
+                       Debug( LDAP_DEBUG_TRACE, "no parent & not root\n",
+                               0, 0, 0);
+                       send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
+                               NULL, NULL, NULL );
+                       goto return_results;
+               }
+
+               ldap_pvt_thread_mutex_lock(&li->li_root_mutex);
+               rootlock = 1;
+               
+               Debug( LDAP_DEBUG_TRACE,
+                      "ldbm_back_modrdn: no parent, locked root\n",
+                      0, 0, 0 );
+
+       }/* if ( (p_ndn = dn_parent( be, e->e_ndn )) != NULL ) else */
+
+       new_parent_dn = p_dn;   /* New Parent unless newSuperior given */
+
+       if ( (np_dn = newSuperior) != NULL) {
+
+
+               Debug( LDAP_DEBUG_TRACE, 
+                      "ldbm_back_modrdn: new parent requested...\n",
+                      0, 0, 0 );
+
+               np_ndn = dn_normalize_case( ch_strdup( np_dn ) );
+
+               /* newSuperior == oldParent?, if so ==> ERROR */
+
+               /* newSuperior == entry being moved?, if so ==> ERROR */
+
+               /* Get Entry with dn=newSuperior. Does newSuperior exist? */
+
+               if( (np = dn2entry_w( be, np_ndn, &matched )) == NULL) {
+
+                       Debug( LDAP_DEBUG_TRACE,
+                              "ldbm_back_modrdn: newSup(ndn=%s) not here!\n",
+                              np_ndn, 0, 0);
+                       send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
+                               NULL, NULL, NULL );
+                       goto return_results;
+               }
+
+               Debug( LDAP_DEBUG_TRACE,
+                      "ldbm_back_modrdn: wr to new parent OK np=%p, id=%d\n",
+                      np, np->e_id, 0 );
+           
+               /* check newSuperior for "children" acl */
+               if ( !access_allowed( be, conn, op, np, "children", NULL,
+                                     ACL_WRITE ) )
+               {
+                       Debug( LDAP_DEBUG_TRACE,
+                              "ldbm_back_modrdn: no wr to newSup children\n",
+                              0, 0, 0 );
+                       send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
+                                         NULL, NULL, NULL );
+                       goto return_results;
+               }
+
+               Debug( LDAP_DEBUG_TRACE,
+                      "ldbm_back_modrdn: wr to new parent's children OK\n",
+                      0, 0 , 0 );
+
+
+               new_parent_dn = np_dn;
 
-       matched = NULL;
-       if ( (e2 = dn2entry( be, newdn, &matched )) != NULL ) {
-               free( newdn );
-               free( pdn );
-               send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, NULL, NULL );
-               cache_return_entry( &li->li_cache, e2 );
-               cache_return_entry( &li->li_cache, e );
-               return( -1 );
        }
-       if ( matched != NULL ) {
-               free( matched );
+       
+       /* Build target dn and make sure target entry doesn't exist already. */
+
+       build_new_dn( &new_dn, e->e_dn, new_parent_dn, newrdn ); 
+
+
+       new_ndn = dn_normalize_case( ch_strdup(new_dn) );
+
+       Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: new ndn=%s\n",
+              new_ndn, 0, 0 );
+
+       if (dn2id ( be, new_ndn ) != NOID) {
+               send_ldap_result( conn, op, LDAP_ALREADY_EXISTS,
+                       NULL, NULL, NULL );
+               goto return_results;
        }
 
+       Debug( LDAP_DEBUG_TRACE,
+              "ldbm_back_modrdn: new ndn=%s does not exist\n",
+              new_ndn, 0, 0 );
+
        /* check for abandon */
-       pthread_mutex_lock( &op->o_abandonmutex );
+       ldap_pvt_thread_mutex_lock( &op->o_abandonmutex );
        if ( op->o_abandon ) {
-               pthread_mutex_unlock( &op->o_abandonmutex );
-               free( newdn );
-               free( pdn );
-               cache_return_entry( &li->li_cache, e2 );
-               cache_return_entry( &li->li_cache, e );
-               return( -1 );
-       }
-       pthread_mutex_unlock( &op->o_abandonmutex );
-
-       /* add new one */
-       if ( dn2id_add( be, newdn, e->e_id ) != 0 ) {
-               free( newdn );
-               free( pdn );
-               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL );
-               cache_return_entry( &li->li_cache, e );
-               return( -1 );
+               ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
+               goto return_results;
        }
+       ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
 
        /* delete old one */
-       if ( dn2id_delete( be, dn ) != 0 ) {
-               free( newdn );
-               free( pdn );
-               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL );
-               cache_return_entry( &li->li_cache, e );
-               return( -1 );
+       if ( dn2id_delete( be, e->e_ndn ) != 0 ) {
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
+                       NULL, NULL, NULL );
+               goto return_results;
        }
 
        (void) cache_delete_entry( &li->li_cache, e );
        free( e->e_dn );
-       e->e_dn = newdn;
-
-       /* XXX
-        * At some point here we need to update the attribute values in
-        * the entry itself that were effected by this RDN change
-        * (respecting the value of the deleteoldrdn parameter).
-        *
-        * Since the code to do this has not yet been written, treat this
-        * omission as a (documented) bug.
+       free( e->e_ndn );
+       e->e_dn = new_dn;
+       e->e_ndn = new_ndn;
+
+       /* add new one */
+       if ( dn2id_add( be, e->e_ndn, e->e_id ) != 0 ) {
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
+                       NULL, NULL, NULL );
+               goto return_results;
+       }
+
+
+       /* Get attribute type and attribute value of our new rdn, we will
+        * need to add that to our new entry
+        */
+
+       if ( (new_rdn_type = rdn_attr_type( newrdn )) == NULL ) {
+           
+               Debug( LDAP_DEBUG_TRACE,
+                      "ldbm_back_modrdn: can't figure out type of newrdn\n",
+                      0, 0, 0 );
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
+                       NULL, NULL, NULL );
+               goto return_results;            
+
+       }
+
+       if ( (new_rdn_val = rdn_attr_value( newrdn )) == NULL ) {
+           
+               Debug( LDAP_DEBUG_TRACE,
+                      "ldbm_back_modrdn: can't figure out val of newrdn\n",
+                      0, 0, 0 );
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
+                       NULL, NULL, NULL );
+               goto return_results;            
+
+       }
+
+       Debug( LDAP_DEBUG_TRACE,
+              "ldbm_back_modrdn: new_rdn_val=\"%s\", new_rdn_type=\"%s\"\n",
+              new_rdn_val, new_rdn_type, 0 );
+
+       /* Retrieve the old rdn from the entry's dn */
+
+       if ( (old_rdn = dn_rdn( be, dn )) == NULL ) {
+
+               Debug( LDAP_DEBUG_TRACE,
+                      "ldbm_back_modrdn: can't figure out old_rdn from dn\n",
+                      0, 0, 0 );
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
+                       NULL, NULL, NULL );
+               goto return_results;            
+
+       }
+
+       if ( (old_rdn_type = rdn_attr_type( old_rdn )) == NULL ) {
+           
+               Debug( LDAP_DEBUG_TRACE,
+                      "ldbm_back_modrdn: can't figure out the old_rdn type\n",
+                      0, 0, 0 );
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
+                       NULL, NULL, NULL );
+               goto return_results;            
+               
+       }
+       
+       if ( strcasecmp( old_rdn_type, new_rdn_type ) != 0 ) {
+
+           /* Not a big deal but we may say something */
+           Debug( LDAP_DEBUG_TRACE,
+                  "ldbm_back_modrdn: old_rdn_type=%s, new_rdn_type=%s!\n",
+                  old_rdn_type, new_rdn_type, 0 );
+           
+       }               
+
+       if ( dn_type( old_rdn ) == DN_X500 ) {
+
+               Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: DN_X500\n",
+                      0, 0, 0 );
+               
+               /* Add new attribute value to the entry.
+                */
+
+               add_bvals[0] = &add_bv;         /* Array of bervals */
+               add_bvals[1] = NULL;
+
+               add_bv.bv_val = new_rdn_val;
+               add_bv.bv_len = strlen(new_rdn_val);
+               
+               mod[0].ml_type = new_rdn_type;  
+               mod[0].ml_bvalues = add_bvals;
+               mod[0].ml_op = LDAP_MOD_SOFTADD;
+               mod[0].ml_next = NULL;
+
+               /* Remove old rdn value if required */
+
+               if (deleteoldrdn) {
+
+                       /* Get value of old rdn */
+       
+                       if ((old_rdn_val = rdn_attr_value( old_rdn ))
+                           == NULL) {
+                           
+                               Debug( LDAP_DEBUG_TRACE,
+                                      "ldbm_back_modrdn: can't figure out old_rdn_val from old_rdn\n",
+                                      0, 0, 0 );
+                               send_ldap_result( conn, op,
+                                                 LDAP_OPERATIONS_ERROR,
+                                                 NULL, NULL, NULL );
+                               goto return_results;            
+
+
+                       }
+
+                       del_bvals[0] = &del_bv;         /* Array of bervals */
+                       del_bvals[1] = NULL;
+
+                       /* Remove old value of rdn as an attribute. */
+                   
+                       del_bv.bv_val = old_rdn_val;
+                       del_bv.bv_len = strlen(old_rdn_val);
+
+                       /* No need to normalize old_rdn_type, delete_values()
+                        * does that for us
+                        */
+                       mod[0].ml_next = &mod[1];
+                       mod[1].ml_type = old_rdn_type;  
+                       mod[1].ml_bvalues = del_bvals;
+                       mod[1].ml_op = LDAP_MOD_DELETE;
+                       mod[1].ml_next = NULL;
+
+                       Debug( LDAP_DEBUG_TRACE,
+                              "ldbm_back_modrdn: removing old_rdn_val=%s\n",
+                              old_rdn_val, 0, 0 );
+               
+               }/* if (deleteoldrdn) */
+
+       
+       } else {
+           
+
+               Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: DNS DN\n",
+                      0, 0, 0 );
+               /* XXXV3: not sure of what to do here */
+               Debug( LDAP_DEBUG_TRACE,
+                      "ldbm_back_modrdn: not fully implemented...\n",
+                      0, 0, 0 );
+  
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
+                       NULL, NULL, NULL );
+               goto return_results;
+
+       }
+
+       /* modify memory copy of entry */
+       if ( ldbm_modify_internal( be, conn, op, dn, &mod[0], e )
+            != 0 ) {
+           
+           goto return_results;
+           
+       }
+       
+       (void) cache_update_entry( &li->li_cache, e );
+
+       /* NOTE: after this you must not free new_dn or new_ndn!
+        * They are used by cache.
         */
 
        /* id2entry index */
        if ( id2entry_add( be, e ) != 0 ) {
                entry_free( e );
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
+                       NULL, NULL, NULL );
+               goto return_results_after;
+       }
 
-               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
-               return( -1 );
+       send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL, NULL );
+       rc = 0;
+       goto return_results_after;      
+
+return_results:
+       if( new_dn != NULL ) free( new_dn );
+       if( new_ndn != NULL ) free( new_ndn );
+return_results_after:
+       /* NOTE:
+        * new_dn and new_ndn are not deallocated because they are used by
+        * the cache entry.
+        */
+       if( p_dn != NULL ) free( p_dn );
+       if( p_ndn != NULL ) free( p_ndn );
+
+       if( matched != NULL ) free( matched );
+
+       /* LDAP v2 supporting correct attribute handling. */
+       if( new_rdn_type != NULL ) free(new_rdn_type);
+       if( new_rdn_val != NULL ) free(new_rdn_val);
+       if( old_rdn != NULL ) free(old_rdn);
+       if( old_rdn_type != NULL ) free(old_rdn_type);
+       if( old_rdn_val != NULL ) free(old_rdn_val);
+
+
+       /* LDAP v3 Support */
+       if ( np_dn != NULL ) free( np_dn );
+       if ( np_ndn != NULL ) free( np_ndn );
+
+       if( p != NULL ) {
+               /* free parent and writer lock */
+               cache_return_entry_w( &li->li_cache, p );
+       }
+
+       if ( rootlock ) {
+               /* release root writer lock */
+               ldap_pvt_thread_mutex_unlock(&li->li_root_mutex);
        }
-       free( pdn );
-       cache_return_entry( &li->li_cache, e );
-       send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
 
-       return( 0 );
+       /* free entry and writer lock */
+       cache_return_entry_w( &li->li_cache, e );
+       return( rc );
 }
index 6a53be4f112485ab38b91886aafa8f2f438d941c..6fa1d9b7dc0ff30ab2ac84c956b3016259fd819d 100644 (file)
@@ -1,38 +1,19 @@
 /* search.c - ldbm backend search function */
 
+#include "portable.h"
+
 #include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
+
+#include <ac/string.h>
+#include <ac/socket.h>
+
 #include "slap.h"
 #include "back-ldbm.h"
+#include "proto-back-ldbm.h"
 
-extern time_t          currenttime;
-extern pthread_mutex_t currenttime_mutex;
-
-extern ID              dn2id();
-extern IDList          *idl_alloc();
-extern Entry           *id2entry();
-extern Entry           *dn2entry();
-extern Attribute       *attr_find();
-extern IDList          *filter_candidates();
-extern char            *ch_realloc();
-extern char            *dn_parent();
-
-static IDList  *base_candidates();
-static IDList  *onelevel_candidates();
-static IDList  *subtree_candidates();
-
-#define GRABSIZE       BUFSIZ
-
-#define MAKE_SPACE( n ) { \
-       if ( rcur + n > rbuf + rmaxsize ) { \
-               int     offset = rcur - rbuf; \
-               rbuf =  ch_realloc( rbuf, rmaxsize + GRABSIZE ); \
-               rmaxsize += GRABSIZE; \
-               rcur = rbuf + offset; \
-       } \
-}
+static ID_BLOCK        *base_candidates(Backend *be, Connection *conn, Operation *op, char *base, Filter *filter, char **attrs, int attrsonly, char **matched, int *err);
+static ID_BLOCK        *onelevel_candidates(Backend *be, Connection *conn, Operation *op, char *base, Filter *filter, char **attrs, int attrsonly, char **matched, int *err);
+static ID_BLOCK        *subtree_candidates(Backend *be, Connection *conn, Operation *op, char *base, Filter *filter, char **attrs, int attrsonly, char **matched, Entry *e, int *err, int lookupbase);
 
 int
 ldbm_back_search(
@@ -53,125 +34,141 @@ ldbm_back_search(
        struct ldbminfo *li = (struct ldbminfo *) be->be_private;
        int             err;
        time_t          stoptime;
-       IDList          *candidates;
+       ID_BLOCK                *candidates;
        ID              id;
        Entry           *e;
        Attribute       *ref;
+       struct berval **refs;
        char            *matched = NULL;
-       int             rmaxsize, nrefs;
-       char            *rbuf, *rcur, *r;
        int             nentries = 0;
+       char            *realBase;
 
-       if ( tlimit == 0 && be_isroot( be, op->o_dn ) ) {
+       Debug(LDAP_DEBUG_ARGS, "=> ldbm_back_search\n", 0, 0, 0);
+
+       if ( tlimit == 0 && be_isroot( be, op->o_ndn ) ) {
                tlimit = -1;    /* allow root to set no limit */
        } else {
                tlimit = (tlimit > be->be_timelimit || tlimit < 1) ?
                    be->be_timelimit : tlimit;
                stoptime = op->o_time + tlimit;
        }
-       if ( slimit == 0 && be_isroot( be, op->o_dn ) ) {
+       if ( slimit == 0 && be_isroot( be, op->o_ndn ) ) {
                slimit = -1;    /* allow root to set no limit */
        } else {
                slimit = (slimit > be->be_sizelimit || slimit < 1) ?
                    be->be_sizelimit : slimit;
        }
 
+       /*
+        * check and apply aliasing where the dereferencing applies to
+        * the subordinates of the base
+        */
+
+       switch ( deref ) {
+       case LDAP_DEREF_FINDING:
+       case LDAP_DEREF_ALWAYS:
+               realBase = derefDN ( be, conn, op, base );
+               break;
+       default:
+               realBase = ch_strdup(base);
+       }
+
+       (void) dn_normalize_case( realBase );
+
+       Debug( LDAP_DEBUG_TRACE, "using base \"%s\"\n",
+               realBase, 0, 0 );
+
        switch ( scope ) {
        case LDAP_SCOPE_BASE:
-               candidates = base_candidates( be, conn, op, base, filter,
+               candidates = base_candidates( be, conn, op, realBase, filter,
                    attrs, attrsonly, &matched, &err );
                break;
 
        case LDAP_SCOPE_ONELEVEL:
-               candidates = onelevel_candidates( be, conn, op, base, filter,
+               candidates = onelevel_candidates( be, conn, op, realBase, filter,
                    attrs, attrsonly, &matched, &err );
                break;
 
        case LDAP_SCOPE_SUBTREE:
-               candidates = subtree_candidates( be, conn, op, base, filter,
+               candidates = subtree_candidates( be, conn, op, realBase, filter,
                    attrs, attrsonly, &matched, NULL, &err, 1 );
                break;
 
        default:
-               send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, "",
-                   "Bad scope" );
+               send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR,
+                       "", "Bad search scope", NULL );
+               if( realBase != NULL) {
+                       free( realBase );
+               }
                return( -1 );
        }
 
        /* null candidates means we could not find the base object */
        if ( candidates == NULL ) {
-               send_ldap_result( conn, op, err, matched, "" );
+               send_ldap_result( conn, op, err,
+                       matched, NULL, NULL );
                if ( matched != NULL ) {
                        free( matched );
                }
+               if( realBase != NULL) {
+                       free( realBase );
+               }
                return( -1 );
        }
 
-       rmaxsize = 0;
-       nrefs = 0;
-       rbuf = rcur = NULL;
-       MAKE_SPACE( sizeof("Referral:") + 1 );
-       strcpy( rbuf, "Referral:" );
-       rcur = strchr( rbuf, '\0' );
+       if ( matched != NULL ) {
+               free( matched );
+       }
+
+       refs = NULL;
+
        for ( id = idl_firstid( candidates ); id != NOID;
            id = idl_nextid( candidates, id ) ) {
+
                /* check for abandon */
-               pthread_mutex_lock( &op->o_abandonmutex );
+               ldap_pvt_thread_mutex_lock( &op->o_abandonmutex );
                if ( op->o_abandon ) {
-                       pthread_mutex_unlock( &op->o_abandonmutex );
+                       ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
                        idl_free( candidates );
-                       free( rbuf );
+                       ber_bvecfree( refs );
+                       if( realBase != NULL) {
+                               free( realBase );
+                       }
                        return( 0 );
                }
-               pthread_mutex_unlock( &op->o_abandonmutex );
+               ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
 
                /* check time limit */
-               pthread_mutex_lock( &currenttime_mutex );
-               time( &currenttime );
-               if ( tlimit != -1 && currenttime > stoptime ) {
-                       pthread_mutex_unlock( &currenttime_mutex );
-                       send_ldap_search_result( conn, op,
-                           LDAP_TIMELIMIT_EXCEEDED, NULL, nrefs > 0 ? rbuf :
-                           NULL, nentries );
+               if ( tlimit != -1 && slap_get_time() > stoptime ) {
+                       send_search_result( conn, op, LDAP_TIMELIMIT_EXCEEDED,
+                               NULL, NULL, refs, nentries );
                        idl_free( candidates );
-                       free( rbuf );
+                       ber_bvecfree( refs );
+                       if( realBase != NULL) {
+                               free( realBase );
+                       }
                        return( 0 );
                }
-               pthread_mutex_unlock( &currenttime_mutex );
 
-               /* get the entry */
-               if ( (e = id2entry( be, id )) == NULL ) {
-                       Debug( LDAP_DEBUG_ARGS, "candidate %d not found\n", id,
-                           0, 0 );
+               /* get the entry with reader lock */
+               if ( (e = id2entry_r( be, id )) == NULL ) {
+                       Debug( LDAP_DEBUG_ARGS, "candidate %ld not found\n",
+                              id, 0, 0 );
                        continue;
                }
 
                /*
                 * if it's a referral, add it to the list of referrals. only do
-                * this for subtree searches, and don't check the filter explicitly
-                * here since it's only a candidate anyway.
+                * this for subtree searches, and don't check the filter
+                * explicitly here since it's only a candidate anyway.
                 */
-               if ( e->e_dn != NULL && strncasecmp( e->e_dn, "ref=", 4 )
-                   == 0 && (ref = attr_find( e->e_attrs, "ref" )) != NULL &&
-                   scope == LDAP_SCOPE_SUBTREE )
+               if ( scope == LDAP_SCOPE_SUBTREE &&
+                       e->e_ndn != NULL &&
+                       strncmp( e->e_ndn, "REF=", 4 ) == 0 &&
+                       (ref = attr_find( e->e_attrs, "ref" )) != NULL )
                {
-                       int     i, len;
-
-                       if ( ref->a_vals == NULL ) {
-                               Debug( LDAP_DEBUG_ANY, "null ref in (%s)\n", 0,
-                                   0, 0 );
-                       } else {
-                               for ( i = 0; ref->a_vals[i] != NULL; i++ ) {
-                                       /* referral + newline + null */
-                                       MAKE_SPACE( ref->a_vals[i]->bv_len + 2 );
-                                       *rcur++ = '\n';
-                                       strncpy( rcur, ref->a_vals[i]->bv_val,
-                                         ref->a_vals[i]->bv_len );
-                                       rcur = rcur + ref->a_vals[i]->bv_len;
-                                       *rcur = '\0';
-                                       nrefs++;
-                               }
-                       }
+                       send_search_reference( be, conn, op,
+                               e, ref->a_vals, &refs );
 
                /* otherwise it's an entry - see if it matches the filter */
                } else {
@@ -184,66 +181,102 @@ ldbm_back_search(
                                scopeok = 1;
                                if ( scope == LDAP_SCOPE_ONELEVEL ) {
                                        if ( (dn = dn_parent( be, e->e_dn )) != NULL ) {
-                                               (void) dn_normalize( dn );
-                                               scopeok = (dn == base) ? 1 : (! strcasecmp( dn, base ));
+                                               (void) dn_normalize_case( dn );
+                                               scopeok = (dn == realBase)
+                                                       ? 1
+                                                       : (strcmp( dn, realBase ) ? 0 : 1 );
+                                               free( dn );
                                        } else {
-                                               scopeok = (base == NULL || *base == '\0');
+                                               scopeok = (realBase == NULL || *realBase == '\0');
                                        }
-                                       free( dn );
                                } else if ( scope == LDAP_SCOPE_SUBTREE ) {
-                                       dn = strdup( e->e_dn );
-                                       (void) dn_normalize( dn );
-                                       scopeok = dn_issuffix( dn, base );
+                                       dn = ch_strdup( e->e_ndn );
+                                       scopeok = dn_issuffix( dn, realBase );
                                        free( dn );
                                }
 
                                if ( scopeok ) {
                                        /* check size limit */
                                        if ( --slimit == -1 ) {
-                                               cache_return_entry( &li->li_cache, e );
-                                               send_ldap_search_result( conn, op,
-                                                       LDAP_SIZELIMIT_EXCEEDED, NULL,
-                                                       nrefs > 0 ? rbuf : NULL, nentries );
+                                               cache_return_entry_r( &li->li_cache, e );
+                                               send_search_result( conn, op,
+                                                       LDAP_SIZELIMIT_EXCEEDED, NULL, NULL,
+                                                       refs, nentries );
                                                idl_free( candidates );
-                                               free( rbuf );
+                                               ber_bvecfree( refs );
+
+                                               if( realBase != NULL) {
+                                                       free( realBase );
+                                               }
                                                return( 0 );
                                        }
 
-                                       switch ( send_search_entry( be, conn, op, e,
-                                               attrs, attrsonly ) ) {
-                                       case 0:         /* entry sent ok */
-                                               nentries++;
+                                       /*
+                                        * check and apply aliasing where the dereferencing applies to
+                                        * the subordinates of the base
+                                        */
+                                       switch ( deref ) {
+                                       case LDAP_DEREF_SEARCHING:
+                                       case LDAP_DEREF_ALWAYS:
+                                               {
+                                                       Entry *newe = derefAlias_r( be, conn, op, e );
+                                                       if ( newe == NULL ) { /* problem with the alias */
+                                                               cache_return_entry_r( &li->li_cache, e );
+                                                               e = NULL;
+                                                       }
+                                                       else if ( newe != e ) { /* reassign e */
+                                                               cache_return_entry_r( &li->li_cache, e );
+                                                               e = newe;
+                                                       }       
+                                               }
                                                break;
-                                       case 1:         /* entry not sent */
-                                               break;
-                                       case -1:        /* connection closed */
-                                               cache_return_entry( &li->li_cache, e );
-                                               idl_free( candidates );
-                                               free( rbuf );
-                                               return( 0 );
+                                       }
+                                       if (e) {
+                                               switch ( send_search_entry( be, conn, op, e,
+                                                       attrs, attrsonly, 0 ) ) {
+                                               case 0:         /* entry sent ok */
+                                                       nentries++;
+                                                       break;
+                                               case 1:         /* entry not sent */
+                                                       break;
+                                               case -1:        /* connection closed */
+                                                       cache_return_entry_r( &li->li_cache, e );
+                                                       idl_free( candidates );
+                                                       ber_bvecfree( refs );
+
+                                                       if( realBase != NULL) {
+                                                               free( realBase );
+                                                       }
+                                                       return( 0 );
+                                               }
                                        }
                                }
                        }
                }
 
-               cache_return_entry( &li->li_cache, e );
+               if( e != NULL ) {
+                       /* free reader lock */
+                       cache_return_entry_r( &li->li_cache, e );
+               }
 
-               pthread_yield();
+               ldap_pvt_thread_yield();
        }
        idl_free( candidates );
-       if ( nrefs > 0 ) {
-               send_ldap_search_result( conn, op, LDAP_PARTIAL_RESULTS, NULL,
-                   rbuf, nentries );
-       } else {
-               send_ldap_search_result( conn, op, LDAP_SUCCESS, NULL, NULL,
-                   nentries );
+
+       send_search_result( conn, op,
+               refs == NULL ? LDAP_SUCCESS : LDAP_REFERRAL,
+               NULL, NULL, refs, nentries );
+
+       ber_bvecfree( refs );
+
+       if( realBase != NULL) {
+               free( realBase );
        }
-       free( rbuf );
 
        return( 0 );
 }
 
-static IDList *
+static ID_BLOCK *
 base_candidates(
     Backend    *be,
     Connection *conn,
@@ -257,26 +290,32 @@ base_candidates(
 )
 {
        struct ldbminfo *li = (struct ldbminfo *) be->be_private;
-       int             rc;
-       ID              id;
-       IDList          *idl;
+       ID_BLOCK                *idl;
        Entry           *e;
 
+       Debug(LDAP_DEBUG_TRACE, "base_candidates: base: \"%s\"\n", base, 0, 0);
+
        *err = LDAP_SUCCESS;
-       if ( (e = dn2entry( be, base, matched )) == NULL ) {
+
+       /* get entry with reader lock */
+       if ( (e = dn2entry_r( be, base, matched )) == NULL ) {
                *err = LDAP_NO_SUCH_OBJECT;
                return( NULL );
        }
 
+       /* check for deleted */
+
        idl = idl_alloc( 1 );
        idl_insert( &idl, e->e_id, 1 );
 
-       cache_return_entry( &li->li_cache, e );
+
+       /* free reader lock */
+       cache_return_entry_r( &li->li_cache, e );
 
        return( idl );
 }
 
-static IDList *
+static ID_BLOCK *
 onelevel_candidates(
     Backend    *be,
     Connection *conn,
@@ -290,16 +329,19 @@ onelevel_candidates(
 )
 {
        struct ldbminfo *li = (struct ldbminfo *) be->be_private;
-       Entry           *e;
+       Entry           *e = NULL;
        Filter          *f;
        char            buf[20];
-       IDList          *candidates;
+       ID_BLOCK                *candidates;
+
+       Debug(LDAP_DEBUG_TRACE, "onelevel_candidates: base: \"%s\"\n", base, 0, 0);
 
        *err = LDAP_SUCCESS;
-       e = NULL;
-       /* get the base object */
-       if ( base != NULL && *base != '\0' && (e = dn2entry( be, base,
-           matched )) == NULL ) {
+
+       /* get the base object with reader lock */
+       if ( base != NULL && *base != '\0' &&
+               (e = dn2entry_r( be, base, matched )) == NULL )
+       {
                *err = LDAP_NO_SUCH_OBJECT;
                return( NULL );
        }
@@ -315,9 +357,9 @@ onelevel_candidates(
        f->f_choice = LDAP_FILTER_AND;
        f->f_and = (Filter *) ch_malloc( sizeof(Filter) );
        f->f_and->f_choice = LDAP_FILTER_EQUALITY;
-       f->f_and->f_ava.ava_type = strdup( "id2children" );
-       sprintf( buf, "%d", e != NULL ? e->e_id : 0 );
-       f->f_and->f_ava.ava_value.bv_val = strdup( buf );
+       f->f_and->f_ava.ava_type = ch_strdup( "id2children" );
+       sprintf( buf, "%ld", e != NULL ? e->e_id : 0 );
+       f->f_and->f_ava.ava_value.bv_val = ch_strdup( buf );
        f->f_and->f_ava.ava_value.bv_len = strlen( buf );
        f->f_and->f_next = filter;
 
@@ -329,10 +371,14 @@ onelevel_candidates(
        f->f_and->f_next = NULL;
        filter_free( f );
 
+       /* free entry and reader lock */
+       if( e != NULL ) {
+               cache_return_entry_r( &li->li_cache, e );
+       }
        return( candidates );
 }
 
-static IDList *
+static ID_BLOCK *
 subtree_candidates(
     Backend    *be,
     Connection *conn,
@@ -348,8 +394,11 @@ subtree_candidates(
 )
 {
        struct ldbminfo *li = (struct ldbminfo *) be->be_private;
-       Filter          *f;
-       IDList          *candidates;
+       Filter          *f, **filterarg_ptr;
+       ID_BLOCK                *candidates;
+
+       Debug(LDAP_DEBUG_TRACE, "subtree_candidates: base: \"%s\" %s\n",
+               base ? base : "NULL", lookupbase ? "lookupbase" : "", 0);
 
        /*
         * get the base object - unless we already have it (from one-level).
@@ -365,21 +414,30 @@ subtree_candidates(
        *err = LDAP_SUCCESS;
        f = NULL;
        if ( lookupbase ) {
-               if ( base != NULL && *base != '\0' && (e = dn2entry( be, base,
-                   matched )) == NULL ) {
+               e = NULL;
+
+               if ( base != NULL && *base != '\0' &&
+                       (e = dn2entry_r( be, base, matched )) == NULL )
+               {
                        *err = LDAP_NO_SUCH_OBJECT;
                        return( NULL );
                }
 
+               if (e) {
+                       cache_return_entry_r( &li->li_cache, e );
+               }
+
                f = (Filter *) ch_malloc( sizeof(Filter) );
                f->f_next = NULL;
                f->f_choice = LDAP_FILTER_OR;
                f->f_or = (Filter *) ch_malloc( sizeof(Filter) );
                f->f_or->f_choice = LDAP_FILTER_EQUALITY;
-               f->f_or->f_avtype = strdup( "objectclass" );
-               f->f_or->f_avvalue.bv_val = strdup( "referral" );
-               f->f_or->f_avvalue.bv_len = strlen( "referral" );
-               f->f_or->f_next = filter;
+               f->f_or->f_avtype = ch_strdup( "objectclass" );
+               /* Patch to use normalized uppercase */
+               f->f_or->f_avvalue.bv_val = ch_strdup( "REFERRAL" );
+               f->f_or->f_avvalue.bv_len = strlen( "REFERRAL" );
+               filterarg_ptr = &f->f_or->f_next;
+               *filterarg_ptr = filter;
                filter = f;
 
                if ( ! be_issuffix( be, base ) ) {
@@ -388,10 +446,10 @@ subtree_candidates(
                        f->f_choice = LDAP_FILTER_AND;
                        f->f_and = (Filter *) ch_malloc( sizeof(Filter) );
                        f->f_and->f_choice = LDAP_FILTER_SUBSTRINGS;
-                       f->f_and->f_sub_type = strdup( "dn" );
+                       f->f_and->f_sub_type = ch_strdup( "dn" );
                        f->f_and->f_sub_initial = NULL;
                        f->f_and->f_sub_any = NULL;
-                       f->f_and->f_sub_final = strdup( base );
+                       f->f_and->f_sub_final = ch_strdup( base );
                        value_normalize( f->f_and->f_sub_final, SYNTAX_CIS );
                        f->f_and->f_next = filter;
                        filter = f;
@@ -402,13 +460,9 @@ subtree_candidates(
 
        /* free up just the parts we allocated above */
        if ( f != NULL ) {
-               f->f_and->f_next = NULL;
+               *filterarg_ptr = NULL;
                filter_free( f );
        }
 
-       if ( e != NULL ) {
-               cache_return_entry( &li->li_cache, e );
-       }
-
        return( candidates );
 }
index 562ce5b54ab6c08665074201735a7ab76cc798a2..df2a1845deb7cedf7ad8bae1d0010927bb319b64 100644 (file)
  * is provided ``as is'' without express or implied warranty.
  */
 
+#include "portable.h"
+
 #include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include "slap.h"
 
-extern Backend *select_backend();
+#include <ac/string.h>
+#include <ac/socket.h>
 
-extern char    *default_referral;
+#include "slap.h"
 
-void
+char *supportedSASLMechanisms[] = {
+       "X-DIGEST-MD5",
+       NULL
+};
+
+int
 do_bind(
     Connection *conn,
     Operation  *op
 )
 {
        BerElement      *ber = op->o_ber;
-       int             version, method, len, rc;
-       char            *dn;
+       ber_int_t               version;
+       ber_tag_t method;
+       char            *mech;
+       char            *cdn, *ndn;
+       ber_tag_t       tag;
+       int                     rc = LDAP_SUCCESS;
        struct berval   cred;
        Backend         *be;
 
        Debug( LDAP_DEBUG_TRACE, "do_bind\n", 0, 0, 0 );
 
+       cdn = NULL;
+       ndn = NULL;
+       mech = NULL;
+       cred.bv_val = NULL;
+
+       ldap_pvt_thread_mutex_lock( &conn->c_mutex );
+
+       /* Force to connection to "anonymous" until bind succeeds.
+        * This may need to be relocated or done on a case by case basis
+        * to handle certain SASL mechanisms.
+        */
+
+       if ( conn->c_cdn != NULL ) {
+               free( conn->c_cdn );
+               conn->c_cdn = NULL;
+       }
+
+       if ( conn->c_dn != NULL ) {
+               free( conn->c_dn );
+               conn->c_dn = NULL;
+       }
+
+       ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
+
+       if ( op->o_dn != NULL ) {
+               free( op->o_dn );
+               op->o_dn = ch_strdup( "" );
+       }
+
+       if ( op->o_ndn != NULL ) {
+               free( op->o_ndn );
+               op->o_ndn = ch_strdup( "" );
+       }
+
        /*
         * Parse the bind request.  It looks like this:
         *
@@ -45,90 +87,163 @@ do_bind(
         *              authentication  CHOICE {
         *                      simple          [0] OCTET STRING -- passwd
         *                      krbv42ldap      [1] OCTET STRING
-        *                      krbv42dsa       [1] OCTET STRING
+        *                      krbv42dsa       [2] OCTET STRING
+        *                      SASL            [3] SaslCredentials
         *              }
+        *      }
+        *
+        *      SaslCredentials ::= SEQUENCE {
+     *         mechanism           LDAPString,
+     *         credentials         OCTET STRING OPTIONAL
         *      }
         */
 
-#ifdef COMPAT30
-       /*
-        * in version 3.0 there is an extra SEQUENCE tag after the
-        * BindRequest SEQUENCE tag.
-        */
+       tag = ber_scanf( ber, "{iat" /*}*/, &version, &cdn, &method );
+
+       if ( tag == LBER_ERROR ) {
+               Debug( LDAP_DEBUG_ANY, "bind: ber_scanf failed\n", 0, 0, 0 );
+               send_ldap_disconnect( conn, op,
+                       LDAP_PROTOCOL_ERROR, "decoding error" );
+               rc = -1;
+               goto cleanup;
+       }
+
+       op->o_protocol = version;
 
-       {
-       BerElement      tber;
-       unsigned long   tlen, ttag;
+       if( method != LDAP_AUTH_SASL ) {
+               tag = ber_scanf( ber, /*{*/ "o}", &cred );
 
-       tber = *op->o_ber;
-       ttag = ber_skip_tag( &tber, &tlen );
-       if ( ber_peek_tag( &tber, &tlen ) == LBER_SEQUENCE ) {
-               Debug( LDAP_DEBUG_ANY, "version 3.0 detected\n", 0, 0, 0 );
-               conn->c_version = 30;
-               rc = ber_scanf(ber, "{{iato}}", &version, &dn, &method, &cred);
        } else {
-               rc = ber_scanf( ber, "{iato}", &version, &dn, &method, &cred );
+               tag = ber_scanf( ber, "{a" /*}*/, &mech );
+
+               if ( tag != LBER_ERROR ) {
+                       ber_len_t len;
+                       tag = ber_peek_tag( ber, &len );
+
+                       if ( tag == LDAP_TAG_LDAPCRED ) { 
+                               tag = ber_scanf( ber, "o", &cred );
+                       }
+
+                       if ( tag != LBER_ERROR ) {
+                               tag = ber_scanf( ber, /*{{*/ "}}" );
+                       }
+               }
        }
+
+       if ( tag == LBER_ERROR ) {
+               send_ldap_disconnect( conn, op,
+                       LDAP_PROTOCOL_ERROR,
+               "decoding error" );
+               rc = -1;
+               goto cleanup;
        }
-#else
-       rc = ber_scanf( ber, "{iato}", &version, &dn, &method, &cred );
-#endif
-       if ( rc == LBER_ERROR ) {
-               Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 );
-               send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL,
-                   "decoding error" );
-               return;
-       }
-#ifdef COMPAT30
-       if ( conn->c_version == 30 ) {
-               switch ( method ) {
-               case LDAP_AUTH_SIMPLE_30:
-                       method = LDAP_AUTH_SIMPLE;
-                       break;
-#ifdef KERBEROS
-               case LDAP_AUTH_KRBV41_30:
-                       method = LDAP_AUTH_KRBV41;
-                       break;
-               case LDAP_AUTH_KRBV42_30:
-                       method = LDAP_AUTH_KRBV42;
-                       break;
-#endif
-               }
+
+       if( (rc = get_ctrls( conn, op, 1 )) != LDAP_SUCCESS ) {
+               Debug( LDAP_DEBUG_ANY, "do_bind: get_ctrls failed\n", 0, 0, 0 );
+               goto cleanup;
+       } 
+
+       if( method == LDAP_AUTH_SASL ) {
+               Debug( LDAP_DEBUG_TRACE, "do_sasl_bind: dn (%s) mech %s\n",
+                       cdn, mech, NULL );
+       } else {
+               Debug( LDAP_DEBUG_TRACE, "do_bind: version %d dn (%s) method %d\n",
+                       version, cdn, method );
        }
-#endif /* compat30 */
-       dn_normalize( dn );
+
+       ndn = dn_normalize_case( ch_strdup( cdn ) );
 
        Statslog( LDAP_DEBUG_STATS, "conn=%d op=%d BIND dn=\"%s\" method=%d\n",
-           conn->c_connid, op->o_opid, dn, method, 0 );
+           conn->c_connid, op->o_opid, ndn, method, 0 );
 
-       if ( version != LDAP_VERSION2 ) {
-               if ( dn != NULL ) {
-                       free( dn );
+       if ( version < LDAP_VERSION_MIN || version > LDAP_VERSION_MAX ) {
+               Debug( LDAP_DEBUG_ANY, "unknown version %d\n", version, 0, 0 );
+               send_ldap_result( conn, op, rc = LDAP_PROTOCOL_ERROR,
+                       NULL, "version not supported", NULL );
+               goto cleanup;
+       }
+
+       if ( method == LDAP_AUTH_SASL ) {
+               if ( version < LDAP_VERSION3 ) {
+                       Debug( LDAP_DEBUG_ANY, "do_bind: sasl with LDAPv%d\n",
+                               version, 0, 0 );
+                       send_ldap_disconnect( conn, op,
+                               LDAP_PROTOCOL_ERROR, "sasl bind requires LDAPv3" );
+                       rc = -1;
+                       goto cleanup;
                }
-               if ( cred.bv_val != NULL ) {
-                       free( cred.bv_val );
+
+               if( mech == NULL || *mech == '\0' ) {
+                       Debug( LDAP_DEBUG_ANY,
+                               "do_bind: no sasl mechanism provided\n",
+                               version, 0, 0 );
+                       send_ldap_result( conn, op, rc = LDAP_AUTH_METHOD_NOT_SUPPORTED,
+                               NULL, "no sasl mechanism provided", NULL );
+                       goto cleanup;
                }
 
-               Debug( LDAP_DEBUG_ANY, "unknown version %d\n", version, 0, 0 );
-               send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL,
-                   "version not supported" );
-               return;
-       }
+               if( !charray_inlist( supportedSASLMechanisms, mech ) ) {
+                       Debug( LDAP_DEBUG_ANY,
+                               "do_bind: sasl mechanism \"%s\" not supported.\n",
+                               mech, 0, 0 );
+                       send_ldap_result( conn, op, rc = LDAP_AUTH_METHOD_NOT_SUPPORTED,
+                               NULL, "sasl mechanism not supported", NULL );
+                       goto cleanup;
+               }
 
-       Debug( LDAP_DEBUG_TRACE, "do_bind: version %d dn (%s) method %d\n",
-           version, dn, method );
+               ldap_pvt_thread_mutex_lock( &conn->c_mutex );
 
-       /* accept null binds */
-       if ( dn == NULL || *dn == '\0' ) {
-               if ( dn != NULL ) {
-                       free( dn );
+               if ( conn->c_authmech != NULL ) {
+                       assert( conn->c_bind_in_progress );
+
+                       if((strcmp(conn->c_authmech, mech) != 0)) {
+                               /* mechanism changed, cancel in progress bind */
+                               conn->c_bind_in_progress = 0;
+                               if( conn->c_authstate != NULL ) {
+                                       free(conn->c_authstate);
+                                       conn->c_authstate = NULL;
+                               }
+                               free(conn->c_authmech);
+                               conn->c_authmech = NULL;
+                       }
+
+#ifdef LDAP_DEBUG
+               } else {
+                       assert( !conn->c_bind_in_progress );
+                       assert( conn->c_authmech == NULL );
+                       assert( conn->c_authstate == NULL );
+#endif
                }
-               if ( cred.bv_val != NULL ) {
-                       free( cred.bv_val );
+
+       } else {
+               ldap_pvt_thread_mutex_lock( &conn->c_mutex );
+
+               if ( conn->c_authmech != NULL ) {
+                       assert( conn->c_bind_in_progress );
+
+                       /* cancel in progress bind */
+                       conn->c_bind_in_progress = 0;
+
+                       if( conn->c_authstate != NULL ) {
+                               free(conn->c_authstate);
+                               conn->c_authstate = NULL;
+                       }
+                       free(conn->c_authmech);
+                       conn->c_authmech = NULL;
                }
+       }
+
+       conn->c_protocol = version;
+       ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
 
-               send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
-               return;
+       /* accept null binds */
+       if ( ndn == NULL || *ndn == '\0' ) {
+               /*
+                * we already forced connection to "anonymous", we just
+                * need to send success
+                */
+               send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL, NULL );
+               goto cleanup;
        }
 
        /*
@@ -137,39 +252,73 @@ do_bind(
         * if we don't hold it.
         */
 
-       if ( (be = select_backend( dn )) == NULL ) {
-               free( dn );
-               if ( cred.bv_val != NULL ) {
-                       free( cred.bv_val );
-               }
+       if ( (be = select_backend( ndn )) == NULL ) {
                if ( cred.bv_len == 0 ) {
-                       send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
+                       send_ldap_result( conn, op, LDAP_SUCCESS,
+                               NULL, NULL, NULL );
+
+               } else if ( default_referral ) {
+                       send_ldap_result( conn, op, rc = LDAP_REFERRAL,
+                               NULL, NULL, default_referral );
+
                } else {
-                       send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL,
-                           default_referral );
+                       send_ldap_result( conn, op, rc = LDAP_INVALID_CREDENTIALS,
+                               NULL, NULL, NULL );
                }
-               return;
+
+               goto cleanup;
        }
 
-       if ( be->be_bind != NULL ) {
-               if ( (*be->be_bind)( be, conn, op, dn, method, &cred ) == 0 ) {
-                       pthread_mutex_lock( &conn->c_dnmutex );
-                       if ( conn->c_dn != NULL ) {
-                               free( conn->c_dn );
+       if ( be->be_bind ) {
+               /* alias suffix */
+               char *edn;
+
+               ndn = suffixAlias( ndn, op, be );
+
+               if ( (*be->be_bind)( be, conn, op, ndn, method, mech, &cred, &edn ) == 0 ) {
+                       ldap_pvt_thread_mutex_lock( &conn->c_mutex );
+
+                       conn->c_cdn = cdn;
+                       cdn = NULL;
+
+                       if(edn != NULL) {
+                               conn->c_dn = edn;
+                       } else {
+                               conn->c_dn = ndn;
+                               ndn = NULL;
                        }
-                       conn->c_dn = strdup( dn );
-                       pthread_mutex_unlock( &conn->c_dnmutex );
+
+                       Debug( LDAP_DEBUG_TRACE, "do_bind: bound \"%s\" to \"%s\"\n",
+                       conn->c_cdn, conn->c_dn, method );
+
+                       ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
 
                        /* send this here to avoid a race condition */
-                       send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
+                       send_ldap_result( conn, op, LDAP_SUCCESS,
+                               NULL, NULL, NULL );
+
+               } else if (edn != NULL) {
+                       free( edn );
                }
+
        } else {
-               send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
-                   "Function not implemented" );
+               send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
+                       NULL, "Function not implemented", NULL );
        }
 
-       free( dn );
+cleanup:
+       if( cdn != NULL ) {
+               free( cdn );
+       }
+       if( ndn != NULL ) {
+               free( ndn );
+       }
+       if ( mech != NULL ) {
+               free( mech );
+       }
        if ( cred.bv_val != NULL ) {
                free( cred.bv_val );
        }
+
+       return rc;
 }
index b731cf1e9021fe81d93ee6cc3b79e2dffdcdacfe..e972d22ec426f8f2c5ec8f618b77c8e29bbbb5e3 100644 (file)
@@ -1,9 +1,12 @@
 /* charray.c - routines for dealing with char * arrays */
 
+#include "portable.h"
+
 #include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
+
+#include <ac/string.h>
+#include <ac/socket.h>
+
 #include "slap.h"
 
 void
@@ -26,7 +29,7 @@ charray_add(
                    (n + 2) * sizeof(char *) );
        }
 
-       (*a)[n++] = s;
+       (*a)[n++] = ch_strdup(s);
        (*a)[n] = NULL;
 }
 
@@ -48,7 +51,7 @@ charray_merge(
        *a = (char **) ch_realloc( (char *) *a, (n + nn + 1) * sizeof(char *) );
 
        for ( i = 0; i < nn; i++ ) {
-               (*a)[n + i] = s[i];
+               (*a)[n + i] = ch_strdup(s[i]);
        }
        (*a)[n + nn] = NULL;
 }
@@ -99,20 +102,53 @@ charray_dup( char **a )
        new = (char **) ch_malloc( (i + 1) * sizeof(char *) );
 
        for ( i = 0; a[i] != NULL; i++ ) {
-               new[i] = strdup( a[i] );
+               new[i] = ch_strdup( a[i] );
        }
        new[i] = NULL;
 
        return( new );
 }
 
+
+char *
+charray2str( char **a )
+{
+       char *s;
+       int i;
+       size_t cur, len = 0;
+
+       if( a == NULL ) return NULL;
+
+       for( i=0 ; a[i] != NULL ; i++ ) {
+               len += strlen( a[i] );
+       }
+
+       if( len == 0 ) return NULL;
+
+       s = ch_malloc( len + 1 );
+
+       cur = 0;
+       for( i=0 ; a[i] != NULL ; i++ ) {
+               len = strlen( a[i] );
+               strncpy( &s[cur], a[i], len );
+               cur += len;
+       }
+       s[len] = '\0';
+       return s;
+}
+
+
 char **
 str2charray( char *str, char *brkstr )
 {
        char    **res;
        char    *s;
+       char    *lasts;
        int     i;
 
+       /* protect the input string from strtok */
+       str = ch_strdup( str );
+
        i = 1;
        for ( s = str; *s; s++ ) {
                if ( strchr( brkstr, *s ) != NULL ) {
@@ -122,11 +158,16 @@ str2charray( char *str, char *brkstr )
 
        res = (char **) ch_malloc( (i + 1) * sizeof(char *) );
        i = 0;
-       for ( s = strtok( str, brkstr ); s != NULL; s = strtok( NULL,
-           brkstr ) ) {
-               res[i++] = strdup( s );
+
+       for ( s = ldap_pvt_strtok( str, brkstr, &lasts );
+               s != NULL;
+               s = ldap_pvt_strtok( NULL, brkstr, &lasts ) )
+       {
+               res[i++] = ch_strdup( s );
        }
+
        res[i] = NULL;
 
+       free( str );
        return( res );
 }
index 248c8b1ec7f9884cb49845af0d65abf065bf84a7..6430dcf1348e694c69d4a45ddceded57df48d69c 100644 (file)
  * is provided ``as is'' without express or implied warranty.
  */
 
+#include "portable.h"
+
 #include <stdio.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include "slap.h"
 
-extern Backend *select_backend();
+#include <ac/socket.h>
 
-extern char    *default_referral;
+#include "slap.h"
 
-void
+int
 do_compare(
     Connection *conn,
     Operation  *op
 )
 {
-       char    *dn;
+       char    *ndn;
        Ava     ava;
-       int     rc;
        Backend *be;
+       int rc = LDAP_SUCCESS;
 
        Debug( LDAP_DEBUG_TRACE, "do_compare\n", 0, 0, 0 );
 
+       if( op->o_bind_in_progress ) {
+               Debug( LDAP_DEBUG_ANY, "do_compare: SASL bind in progress.\n",
+                       0, 0, 0 );
+               send_ldap_result( conn, op, LDAP_SASL_BIND_IN_PROGRESS,
+                       NULL, "SASL bind in progress", NULL );
+               return LDAP_SASL_BIND_IN_PROGRESS;
+       }
+
        /*
         * Parse the compare request.  It looks like this:
         *
@@ -44,42 +51,57 @@ do_compare(
         *      }
         */
 
-       if ( ber_scanf( op->o_ber, "{a{ao}}", &dn, &ava.ava_type,
+       if ( ber_scanf( op->o_ber, "{a{ao}}", &ndn, &ava.ava_type,
            &ava.ava_value ) == LBER_ERROR ) {
                Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 );
-               send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL, "" );
-               return;
+               send_ldap_disconnect( conn, op,
+                       LDAP_PROTOCOL_ERROR, "decoding error" );
+               return -1;
        }
+
+       if( ( rc = get_ctrls( conn, op, 1 )) != LDAP_SUCCESS ) {
+               free( ndn );
+               ava_free( &ava, 0 );
+               Debug( LDAP_DEBUG_ANY, "do_compare: get_ctrls failed\n", 0, 0, 0 );
+               return rc;
+       } 
+
        value_normalize( ava.ava_value.bv_val, attr_syntax( ava.ava_type ) );
-       dn_normalize( dn );
 
        Debug( LDAP_DEBUG_ARGS, "do_compare: dn (%s) attr (%s) value (%s)\n",
-           dn, ava.ava_type, ava.ava_value.bv_val );
+           ndn, ava.ava_type, ava.ava_value.bv_val );
+
+       ndn = dn_normalize_case( ndn );
 
        Statslog( LDAP_DEBUG_STATS, "conn=%d op=%d CMP dn=\"%s\" attr=\"%s\"\n",
-           conn->c_connid, op->o_opid, dn, ava.ava_type, 0 );
+           conn->c_connid, op->o_opid, ndn, ava.ava_type, 0 );
 
        /*
         * We could be serving multiple database backends.  Select the
         * appropriate one, or send a referral to our "referral server"
         * if we don't hold it.
         */
-       if ( (be = select_backend( dn )) == NULL ) {
-               free( dn );
+       if ( (be = select_backend( ndn )) == NULL ) {
+               free( ndn );
                ava_free( &ava, 0 );
 
-               send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL,
-                   default_referral );
-               return;
+               send_ldap_result( conn, op, rc = LDAP_REFERRAL,
+                       NULL, NULL, default_referral );
+               return 1;
        }
 
-       if ( be->be_compare != NULL ) {
-               (*be->be_compare)( be, conn, op, dn, &ava );
+       /* alias suffix if approp */
+       ndn = suffixAlias( ndn, op, be );
+
+       if ( be->be_compare ) {
+               (*be->be_compare)( be, conn, op, ndn, &ava );
        } else {
-               send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
-                   "Function not implemented" );
+               send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
+                       NULL, "Function not implemented", NULL );
        }
 
-       free( dn );
+       free( ndn );
        ava_free( &ava, 0 );
+
+       return rc;
 }
index 66050586ab794ac4f4e258306e58de0e293206ac..0b169a5c1dc4cbf737a706588d743bb2f59c5edd 100644 (file)
@@ -1,19 +1,21 @@
 /* config.c - configuration file handling routines */
 
+#include "portable.h"
+
 #include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#endif
+
+#include <ac/string.h>
+#include <ac/ctype.h>
+#include <ac/socket.h>
+
+#include "ldap_defaults.h"
 #include "slap.h"
-#include "ldapconfig.h"
 
 #define MAXARGS        100
 
-extern Backend *new_backend();
-extern char    *default_referral;
-extern int     ldap_syslog;
-extern int     global_schemacheck;
-
 /*
  * defaults for various global variables
  */
@@ -23,36 +25,57 @@ struct acl  *global_acl = NULL;
 int            global_default_access = ACL_READ;
 char           *replogfile;
 int            global_lastmod;
+int            global_idletimeout = 0;
+char   *global_realm = NULL;
 char           *ldap_srvtab = "";
 
-static char    *fp_getline();
-static void    fp_getline_init();
-static void    fp_parse_line();
+char   *slapd_pid_file  = NULL;
+char   *slapd_args_file = NULL;
 
-static char    *strtok_quote();
+static char    *fp_getline(FILE *fp, int *lineno);
+static void    fp_getline_init(int *lineno);
+static int     fp_parse_line(char *line, int *argcp, char **argv);
 
-void
-read_config( char *fname, Backend **bep, FILE *pfp )
+static char    *strtok_quote(char *line, char *sep);
+
+int
+read_config( char *fname )
 {
        FILE    *fp;
-       char    *line, *savefname, *dn;
+       char    *line, *savefname, *saveline;
        int     cargc, savelineno;
        char    *cargv[MAXARGS];
        int     lineno, i;
-       Backend *be;
 
-       if ( (fp = pfp) == NULL && (fp = fopen( fname, "r" )) == NULL ) {
+       struct berval *vals[2];
+       struct berval val;
+
+       static BackendInfo *bi = NULL;
+       static BackendDB        *be = NULL;
+
+       vals[0] = &val;
+       vals[1] = NULL;
+
+       if ( (fp = fopen( fname, "r" )) == NULL ) {
                ldap_syslog = 1;
                Debug( LDAP_DEBUG_ANY,
                    "could not open config file \"%s\" - absolute path?\n",
                    fname, 0, 0 );
                perror( fname );
-               exit( 1 );
+               return 1;
        }
 
        Debug( LDAP_DEBUG_CONFIG, "reading config file %s\n", fname, 0, 0 );
-       be = *bep;
+
+       if ( schema_init( ) != 0 ) {
+               Debug( LDAP_DEBUG_ANY,
+                   "error initializing the schema\n",
+                   0, 0, 0 );
+               return( 1 );
+       }
+
        fp_getline_init( &lineno );
+
        while ( (line = fp_getline( fp, &lineno )) != NULL ) {
                /* skip comments and blank lines */
                if ( line[0] == '#' || line[0] == '\0' ) {
@@ -61,7 +84,12 @@ read_config( char *fname, Backend **bep, FILE *pfp )
 
                Debug( LDAP_DEBUG_CONFIG, "line %d (%s)\n", lineno, line, 0 );
 
-               fp_parse_line( line, &cargc, cargv );
+               /* fp_parse_line is destructive, we save a copy */
+               saveline = ch_strdup( line );
+
+               if ( fp_parse_line( line, &cargc, cargv ) != 0 ) {
+                       return( 1 );
+               }
 
                if ( cargc < 1 ) {
                        Debug( LDAP_DEBUG_ANY,
@@ -70,24 +98,87 @@ read_config( char *fname, Backend **bep, FILE *pfp )
                        continue;
                }
 
+               if ( strcasecmp( cargv[0], "backend" ) == 0 ) {
+                       if ( cargc < 2 ) {
+                               Debug( LDAP_DEBUG_ANY,
+               "%s: line %d: missing type in \"backend <type>\" line\n",
+                                   fname, lineno, 0 );
+                               return( 1 );
+                       }
+
+                       if( be != NULL ) {
+                               Debug( LDAP_DEBUG_ANY,
+"%s: line %d: backend line must appear before any database definition\n",
+                                   fname, lineno, 0 );
+                               return( 1 );
+                       }
+
+                       bi = backend_info( cargv[1] );
+
                /* start of a new database definition */
-               if ( strcasecmp( cargv[0], "database" ) == 0 ) {
+               } else if ( strcasecmp( cargv[0], "database" ) == 0 ) {
                        if ( cargc < 2 ) {
                                Debug( LDAP_DEBUG_ANY,
                "%s: line %d: missing type in \"database <type>\" line\n",
                                    fname, lineno, 0 );
-                               exit( 1 );
+                               return( 1 );
                        }
-                       *bep = new_backend( cargv[1] );
-                       be = *bep;
+                       bi = NULL;
+                       be = backend_db_init( cargv[1] );
 
-               /* set size limit */
+               /* assign a default depth limit for alias deref */
+               be->be_maxDerefDepth = SLAPD_DEFAULT_MAXDEREFDEPTH; 
+
+               /* get pid file name */
+               } else if ( strcasecmp( cargv[0], "pidfile" ) == 0 ) {
+                       if ( cargc < 2 ) {
+                               Debug( LDAP_DEBUG_ANY,
+           "%s: line %d: missing file name in \"pidfile <file>\" line\n",
+                                   fname, lineno, 0 );
+                               return( 1 );
+                       }
+
+                       slapd_pid_file = ch_strdup( cargv[1] );
+
+               /* get args file name */
+               } else if ( strcasecmp( cargv[0], "argsfile" ) == 0 ) {
+                       if ( cargc < 2 ) {
+                               Debug( LDAP_DEBUG_ANY,
+           "%s: line %d: missing file name in \"argsfile <file>\" line\n",
+                                   fname, lineno, 0 );
+                               return( 1 );
+                       }
+
+                       slapd_args_file = ch_strdup( cargv[1] );
+
+               /* set DIGEST realm */
+               } else if ( strcasecmp( cargv[0], "digest-realm" ) == 0 ) {
+                       if ( cargc < 2 ) {
+                               Debug( LDAP_DEBUG_ANY,
+           "%s: line %d: missing realm in \"digest-realm <realm>\" line\n",
+                                   fname, lineno, 0 );
+                               return( 1 );
+                       }
+                       if ( be != NULL ) {
+                               be->be_realm = ch_strdup( cargv[1] );
+
+                       } else if ( global_realm != NULL ) {
+                               Debug( LDAP_DEBUG_ANY,
+                                       "%s: line %d: already set global realm!\n",
+                                       fname, lineno, 0 );
+                               return 1;
+
+                       } else {
+                               global_realm = ch_strdup( cargv[1] );
+                       }
+
+               /* set time limit */
                } else if ( strcasecmp( cargv[0], "sizelimit" ) == 0 ) {
                        if ( cargc < 2 ) {
                                Debug( LDAP_DEBUG_ANY,
            "%s: line %d: missing limit in \"sizelimit <limit>\" line\n",
                                    fname, lineno, 0 );
-                               exit( 1 );
+                               return( 1 );
                        }
                        if ( be == NULL ) {
                                defsize = atoi( cargv[1] );
@@ -101,7 +192,7 @@ read_config( char *fname, Backend **bep, FILE *pfp )
                                Debug( LDAP_DEBUG_ANY,
            "%s: line %d: missing limit in \"timelimit <limit>\" line\n",
                                    fname, lineno, 0 );
-                               exit( 1 );
+                               return( 1 );
                        }
                        if ( be == NULL ) {
                                deftime = atoi( cargv[1] );
@@ -115,7 +206,7 @@ read_config( char *fname, Backend **bep, FILE *pfp )
                                Debug( LDAP_DEBUG_ANY,
                    "%s: line %d: missing dn in \"suffix <dn>\" line\n",
                                    fname, lineno, 0 );
-                               exit( 1 );
+                               return( 1 );
                        } else if ( cargc > 2 ) {
                                Debug( LDAP_DEBUG_ANY,
     "%s: line %d: extra cruft after <dn> in \"suffix %s\" line (ignored)\n",
@@ -126,10 +217,76 @@ read_config( char *fname, Backend **bep, FILE *pfp )
 "%s: line %d: suffix line must appear inside a database definition (ignored)\n",
                                    fname, lineno, 0 );
                        } else {
-                               dn = strdup( cargv[1] );
+                               char *dn = ch_strdup( cargv[1] );
                                (void) dn_normalize( dn );
                                charray_add( &be->be_suffix, dn );
-                       }
+                               (void) dn_upcase( dn );
+                               charray_add( &be->be_nsuffix, dn );
+                               free( dn );
+                       }
+
+                /* set database suffixAlias */
+                } else if ( strcasecmp( cargv[0], "suffixAlias" ) == 0 ) {
+                        if ( cargc < 2 ) {
+                                Debug( LDAP_DEBUG_ANY,
+                    "%s: line %d: missing alias and aliased_dn in \"suffixAlias <alias> <aliased_dn>\" line\n",
+                                    fname, lineno, 0 );
+                                return( 1 );
+                        } else if ( cargc < 3 ) {
+                                Debug( LDAP_DEBUG_ANY,
+                    "%s: line %d: missing aliased_dn in \"suffixAlias <alias> <aliased_dn>\" line\n",
+                                    fname, lineno, 0 );
+                                return( 1 );
+                        } else if ( cargc > 3 ) {
+                                Debug( LDAP_DEBUG_ANY,
+    "%s: line %d: extra cruft in suffixAlias line (ignored)\n",
+                                    fname, lineno, 0 );
+                        }
+                        if ( be == NULL ) {
+                                Debug( LDAP_DEBUG_ANY,
+"%s: line %d: suffixAlias line must appear inside a database definition (ignored)\n",
+                                    fname, lineno, 0 );
+                        } else {
+                                char *alias, *aliased_dn;
+
+                                                               alias = ch_strdup( cargv[1] );
+                                (void) dn_normalize( alias );
+
+                                aliased_dn = ch_strdup( cargv[2] );
+                                (void) dn_normalize( aliased_dn );
+
+
+                                                               if ( strcasecmp( alias, aliased_dn) == 0 ) {
+                                       Debug( LDAP_DEBUG_ANY,
+"%s: line %d: suffixAlias %s is not different from aliased dn (ignored)\n",
+                                    fname, lineno, alias );
+                                                               } else {
+                                       (void) dn_normalize_case( alias );
+                                       (void) dn_normalize_case( aliased_dn );
+                                       charray_add( &be->be_suffixAlias, alias );
+                                       charray_add( &be->be_suffixAlias, aliased_dn );
+                                                               }
+
+                                                               free(alias);
+                                                               free(aliased_dn);
+                        }
+
+               /* set max deref depth */
+               } else if ( strcasecmp( cargv[0], "maxDerefDepth" ) == 0 ) {
+                       if ( cargc < 2 ) {
+                               Debug( LDAP_DEBUG_ANY,
+                   "%s: line %d: missing depth in \"maxDerefDepth <depth>\" line\n",
+                                   fname, lineno, 0 );
+                               return( 1 );
+                       }
+                       if ( be == NULL ) {
+                               Debug( LDAP_DEBUG_ANY,
+"%s: line %d: depth line must appear inside a database definition (ignored)\n",
+                                   fname, lineno, 0 );
+                       } else {
+                           be->be_maxDerefDepth = atoi (cargv[1]);
+                       }
+
 
                /* set magic "root" dn for this database */
                } else if ( strcasecmp( cargv[0], "rootdn" ) == 0 ) {
@@ -137,16 +294,15 @@ read_config( char *fname, Backend **bep, FILE *pfp )
                                Debug( LDAP_DEBUG_ANY,
                    "%s: line %d: missing dn in \"rootdn <dn>\" line\n",
                                    fname, lineno, 0 );
-                               exit( 1 );
+                               return( 1 );
                        }
                        if ( be == NULL ) {
                                Debug( LDAP_DEBUG_ANY,
 "%s: line %d: rootdn line must appear inside a database definition (ignored)\n",
                                    fname, lineno, 0 );
                        } else {
-                               dn = strdup( cargv[1] );
-                               (void) dn_normalize( dn );
-                               be->be_rootdn = dn;
+                               be->be_root_dn = ch_strdup( cargv[1] );
+                               be->be_root_ndn = dn_normalize_case( ch_strdup( cargv[1] ) );
                        }
 
                /* set super-secret magic database password */
@@ -155,14 +311,14 @@ read_config( char *fname, Backend **bep, FILE *pfp )
                                Debug( LDAP_DEBUG_ANY,
            "%s: line %d: missing passwd in \"rootpw <passwd>\" line\n",
                                    fname, lineno, 0 );
-                               exit( 1 );
+                               return( 1 );
                        }
                        if ( be == NULL ) {
                                Debug( LDAP_DEBUG_ANY,
 "%s: line %d: rootpw line must appear inside a database definition (ignored)\n",
                                    fname, lineno, 0 );
                        } else {
-                               be->be_rootpw = strdup( cargv[1] );
+                               be->be_root_pw = ch_strdup( cargv[1] );
                        }
 
                /* make this database read-only */
@@ -171,7 +327,7 @@ read_config( char *fname, Backend **bep, FILE *pfp )
                                Debug( LDAP_DEBUG_ANY,
            "%s: line %d: missing on|off in \"readonly <on|off>\" line\n",
                                    fname, lineno, 0 );
-                               exit( 1 );
+                               return( 1 );
                        }
                        if ( be == NULL ) {
                                Debug( LDAP_DEBUG_ANY,
@@ -191,21 +347,62 @@ read_config( char *fname, Backend **bep, FILE *pfp )
                                Debug( LDAP_DEBUG_ANY,
                    "%s: line %d: missing URL in \"referral <URL>\" line\n",
                                    fname, lineno, 0 );
-                               exit( 1 );
+                               return( 1 );
+                       }
+
+                       vals[0]->bv_val = cargv[1];
+                       vals[0]->bv_len = strlen( vals[0]->bv_val );
+                       value_add( &default_referral, vals );
+
+               /* specify locale */
+               } else if ( strcasecmp( cargv[0], "locale" ) == 0 ) {
+#ifdef HAVE_LOCALE_H
+                       char *locale;
+                       if ( cargc < 2 ) {
+                               Debug( LDAP_DEBUG_ANY,
+       "%s: line %d: missing locale in \"locale <name | on | off>\" line\n",
+                                      fname, lineno, 0 );
+                               return( 1 );
                        }
-                       default_referral = (char *) malloc( strlen( cargv[1] )
-                           + sizeof("Referral:\n") + 1 );
-                       strcpy( default_referral, "Referral:\n" );
-                       strcat( default_referral, cargv[1] );
 
+                       locale = (strcasecmp(   cargv[1], "on"  ) == 0 ? ""
+                                 : strcasecmp( cargv[1], "off" ) == 0 ? "C"
+                                 : ch_strdup( cargv[1] )                    );
+
+                       if ( setlocale( LC_CTYPE, locale ) == 0 ) {
+                               Debug( LDAP_DEBUG_ANY,
+                                      (*locale
+                                       ? "%s: line %d: bad locale \"%s\"\n"
+                                       : "%s: line %d: bad locale\n"),
+                                      fname, lineno, locale );
+                               return( 1 );
+                       }
+#else
+                       Debug( LDAP_DEBUG_ANY,
+                              "%s: line %d: \"locale\" unsupported\n",
+                              fname, lineno, 0 );
+                       return( 1 );
+#endif
                /* specify an objectclass */
                } else if ( strcasecmp( cargv[0], "objectclass" ) == 0 ) {
-                       parse_oc( be, fname, lineno, cargc, cargv );
+                       if ( *cargv[1] == '(' ) {
+                               char * p;
+                               p = strchr(saveline,'(');
+                               parse_oc( fname, lineno, p );
+                       } else {
+                               parse_oc_old( be, fname, lineno, cargc, cargv );
+                       }
 
                /* specify an attribute */
                } else if ( strcasecmp( cargv[0], "attribute" ) == 0 ) {
-                       attr_syntax_config( fname, lineno, cargc - 1,
-                           &cargv[1] );
+                       if ( *cargv[1] == '(' ) {
+                               char * p;
+                               p = strchr(saveline,'(');
+                               parse_at( fname, lineno, p );
+                       } else {
+                               attr_syntax_config( fname, lineno, cargc - 1,
+                                   &cargv[1] );
+                       }
 
                /* turn on/off schema checking */
                } else if ( strcasecmp( cargv[0], "schemacheck" ) == 0 ) {
@@ -213,12 +410,12 @@ read_config( char *fname, Backend **bep, FILE *pfp )
                                Debug( LDAP_DEBUG_ANY,
     "%s: line %d: missing on|off in \"schemacheck <on|off>\" line\n",
                                    fname, lineno, 0 );
-                               exit( 1 );
+                               return( 1 );
                        }
-                       if ( strcasecmp( cargv[1], "on" ) == 0 ) {
-                               global_schemacheck = 1;
-                       } else {
+                       if ( strcasecmp( cargv[1], "off" ) == 0 ) {
                                global_schemacheck = 0;
+                       } else {
+                               global_schemacheck = 1;
                        }
 
                /* specify access control info */
@@ -231,23 +428,26 @@ read_config( char *fname, Backend **bep, FILE *pfp )
                                Debug( LDAP_DEBUG_ANY,
            "%s: line %d: missing limit in \"defaultaccess <access>\" line\n",
                                    fname, lineno, 0 );
-                               exit( 1 );
+                               return( 1 );
                        }
                        if ( be == NULL ) {
-                               if ( (global_default_access =
-                                   str2access( cargv[1] )) == -1 ) {
+                               if ( ACL_IS_INVALID(ACL_SET(global_default_access,
+                                               str2access(cargv[1]))) )
+                               {
                                        Debug( LDAP_DEBUG_ANY,
 "%s: line %d: bad access \"%s\" expecting [self]{none|compare|read|write}\n",
                                            fname, lineno, cargv[1] );
-                                       exit( 1 );
+                                       return( 1 );
                                }
                        } else {
-                               if ( (be->be_dfltaccess =
-                                   str2access( cargv[1] )) == -1 ) {
+                               if ( ACL_IS_INVALID(ACL_SET(be->be_dfltaccess,
+                                               str2access(cargv[1]))) )
+                               {
                                        Debug( LDAP_DEBUG_ANY,
-"%s: line %d: bad access \"%s\" expecting [self]{none|compare|read|write}\n",
+                                               "%s: line %d: bad access \"%s\", "
+                                               "expecting [self]{none|compare|search|read|write}\n",
                                            fname, lineno, cargv[1] );
-                                       exit( 1 );
+                                       return( 1 );
                                }
                        }
 
@@ -257,7 +457,7 @@ read_config( char *fname, Backend **bep, FILE *pfp )
                                Debug( LDAP_DEBUG_ANY,
                    "%s: line %d: missing level in \"loglevel <level>\" line\n",
                                    fname, lineno, 0 );
-                               exit( 1 );
+                               return( 1 );
                        }
                        ldap_syslog = atoi( cargv[1] );
 
@@ -267,7 +467,7 @@ read_config( char *fname, Backend **bep, FILE *pfp )
                                Debug( LDAP_DEBUG_ANY,
            "%s: line %d: missing host in \"replica <host[:port]>\" line\n",
                                    fname, lineno, 0 );
-                               exit( 1 );
+                               return( 1 );
                        }
                        if ( be == NULL ) {
                                Debug( LDAP_DEBUG_ANY,
@@ -278,7 +478,7 @@ read_config( char *fname, Backend **bep, FILE *pfp )
                                        if ( strncasecmp( cargv[i], "host=", 5 )
                                            == 0 ) {
                                                charray_add( &be->be_replica,
-                                                   strdup( cargv[i] + 5 ) );
+                                                            cargv[i] + 5 );
                                                break;
                                        }
                                }
@@ -295,15 +495,15 @@ read_config( char *fname, Backend **bep, FILE *pfp )
                                Debug( LDAP_DEBUG_ANY,
                    "%s: line %d: missing dn in \"updatedn <dn>\" line\n",
                                    fname, lineno, 0 );
-                               exit( 1 );
+                               return( 1 );
                        }
                        if ( be == NULL ) {
                                Debug( LDAP_DEBUG_ANY,
 "%s: line %d: updatedn line must appear inside a database definition (ignored)\n",
                                    fname, lineno, 0 );
                        } else {
-                               be->be_updatedn = strdup( cargv[1] );
-                               (void) dn_normalize( be->be_updatedn );
+                               be->be_update_ndn = ch_strdup( cargv[1] );
+                               (void) dn_normalize_case( be->be_update_ndn );
                        }
 
                /* replication log file to which changes are appended */
@@ -312,12 +512,12 @@ read_config( char *fname, Backend **bep, FILE *pfp )
                                Debug( LDAP_DEBUG_ANY,
            "%s: line %d: missing dn in \"replogfile <filename>\" line\n",
                                    fname, lineno, 0 );
-                               exit( 1 );
+                               return( 1 );
                        }
                        if ( be ) {
-                               be->be_replogfile = strdup( cargv[1] );
+                               be->be_replogfile = ch_strdup( cargv[1] );
                        } else {
-                               replogfile = strdup( cargv[1] );
+                               replogfile = ch_strdup( cargv[1] );
                        }
 
                /* maintain lastmodified{by,time} attributes */
@@ -326,7 +526,7 @@ read_config( char *fname, Backend **bep, FILE *pfp )
                                Debug( LDAP_DEBUG_ANY,
            "%s: line %d: missing on|off in \"lastmod <on|off>\" line\n",
                                    fname, lineno, 0 );
-                               exit( 1 );
+                               return( 1 );
                        }
                        if ( strcasecmp( cargv[1], "on" ) == 0 ) {
                                if ( be )
@@ -340,18 +540,42 @@ read_config( char *fname, Backend **bep, FILE *pfp )
                                        global_lastmod = OFF;
                        }
 
+               /* set idle timeout value */
+               } else if ( strcasecmp( cargv[0], "idletimeout" ) == 0 ) {
+                       int i;
+                       if ( cargc < 2 ) {
+                               Debug( LDAP_DEBUG_ANY,
+           "%s: line %d: missing timeout value in \"idletimeout <seconds>\" line\n",
+                                   fname, lineno, 0 );
+                               return( 1 );
+                       }
+
+                       i = atoi( cargv[1] );
+
+                       if( i < 0 ) {
+                               Debug( LDAP_DEBUG_ANY,
+           "%s: line %d: timeout value (%d) invalid \"idletimeout <seconds>\" line\n",
+                                   fname, lineno, i );
+                               return( 1 );
+                       }
+
+                       global_idletimeout = i;
+
                /* include another config file */
                } else if ( strcasecmp( cargv[0], "include" ) == 0 ) {
                        if ( cargc < 2 ) {
                                Debug( LDAP_DEBUG_ANY,
     "%s: line %d: missing filename in \"include <filename>\" line\n",
                                    fname, lineno, 0 );
-                               exit( 1 );
+                               return( 1 );
                        }
-                       savefname = strdup( cargv[1] );
+                       savefname = ch_strdup( cargv[1] );
                        savelineno = lineno;
-                       read_config( savefname, bep, NULL );
-                       be = *bep;
+
+                       if ( read_config( savefname ) != 0 ) {
+                               return( 1 );
+                       }
+
                        free( savefname );
                        lineno = savelineno - 1;
 
@@ -361,30 +585,66 @@ read_config( char *fname, Backend **bep, FILE *pfp )
                                Debug( LDAP_DEBUG_ANY,
            "%s: line %d: missing filename in \"srvtab <filename>\" line\n",
                                    fname, lineno, 0 );
-                               exit( 1 );
-                       }
-                       ldap_srvtab = strdup( cargv[1] );
-
-               /* pass anything else to the current backend config routine */
+                               return( 1 );
+                       }
+                       ldap_srvtab = ch_strdup( cargv[1] );
+
+#ifdef SLAPD_MODULES
+                } else if (strcasecmp( cargv[0], "loadmodule") == 0 ) {
+                   if ( cargc < 2 ) {
+                      Debug( LDAP_DEBUG_ANY,
+                             "%s: line %d: missing filename in \"loadmodule <filename>\" line\n",
+                             fname, lineno, 0 );
+                      exit( 1 );
+                   }
+                   if (!load_module(cargv[1], cargc - 2, (cargc > 2) ? cargv + 2 : NULL)) {
+                      Debug( LDAP_DEBUG_ANY,
+                             "%s: line %d: failed to load or initialize module %s\n",
+                             fname, lineno, cargv[1]);
+                      exit( 1 );
+                   }
+                  
+#endif /*SLAPD_MODULES*/
+
+               /* pass anything else to the current backend info/db config routine */
                } else {
-                       if ( be == NULL ) {
-                               Debug( LDAP_DEBUG_ANY,
-"%s: line %d: unknown directive \"%s\" outside database definition (ignored)\n",
-                                   fname, lineno, cargv[0] );
-                       } else if ( be->be_config == NULL ) {
+                       if ( bi != NULL ) {
+                               if ( bi->bi_config == 0 ) {
+                                       Debug( LDAP_DEBUG_ANY,
+"%s: line %d: unknown directive \"%s\" inside backend info definition (ignored)\n",
+                                               fname, lineno, cargv[0] );
+                               } else {
+                                       if ( (*bi->bi_config)( bi, fname, lineno, cargc, cargv )
+                                               != 0 )
+                                       {
+                                               return( 1 );
+                                       }
+                               }
+                       } else if ( be != NULL ) {
+                               if ( be->be_config == 0 ) {
+                                       Debug( LDAP_DEBUG_ANY,
+"%s: line %d: unknown directive \"%s\" inside backend database definition (ignored)\n",
+                                       fname, lineno, cargv[0] );
+                               } else {
+                                       if ( (*be->be_config)( be, fname, lineno, cargc, cargv )
+                                               != 0 )
+                                       {
+                                               return( 1 );
+                                       }
+                               }
+                       } else {
                                Debug( LDAP_DEBUG_ANY,
-"%s: line %d: unknown directive \"%s\" inside database definition (ignored)\n",
+"%s: line %d: unknown directive \"%s\" outside backend info and database definitions (ignored)\n",
                                    fname, lineno, cargv[0] );
-                       } else {
-                               (*be->be_config)( be, fname, lineno, cargc,
-                                   cargv );
                        }
                }
+               free( saveline );
        }
        fclose( fp );
+       return( 0 );
 }
 
-static void
+static int
 fp_parse_line(
     char       *line,
     int                *argcp,
@@ -399,11 +659,12 @@ fp_parse_line(
                if ( *argcp == MAXARGS ) {
                        Debug( LDAP_DEBUG_ANY, "Too many tokens (max %d)\n",
                            MAXARGS, 0, 0 );
-                       exit( 1 );
+                       return( 1 );
                }
                argv[(*argcp)++] = token;
        }
        argv[*argcp] = NULL;
+       return 0;
 }
 
 static char *
@@ -434,11 +695,14 @@ strtok_quote( char *line, char *sep )
                        } else {
                                inquote = 1;
                        }
-                       strcpy( next, next + 1 );
+                       SAFEMEMCPY( next, next + 1, strlen( next + 1 ) + 1 );
                        break;
 
                case '\\':
-                       strcpy( next, next + 1 );
+                       if ( next[1] )
+                               SAFEMEMCPY( next,
+                                           next + 1, strlen( next + 1 ) + 1 );
+                       next++;         /* dont parse the escaped character */
                        break;
 
                default:
@@ -490,7 +754,7 @@ fp_getline( FILE *fp, int *lineno )
                if ( (p = strchr( buf, '\n' )) != NULL ) {
                        *p = '\0';
                }
-               if ( ! isspace( buf[0] ) ) {
+               if ( ! isspace( (unsigned char) buf[0] ) ) {
                        return( line );
                }
 
index 5599193006cdf4a53cdc6f32354036aaf5ad9d4c..a8051991bb8137afa52817b8e30e5c89286ead75 100644 (file)
  * is provided ``as is'' without express or implied warranty.
  */
 
+#include "portable.h"
+
 #include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
+
+#include <ac/string.h>
+#include <ac/socket.h>
+
+#include "ldap_defaults.h"
 #include "slap.h"
-#include "ldapconfig.h"
 
 #if defined( SLAPD_CONFIG_DN )
 
-extern int             nbackends;
-extern Backend         *backends;
-extern char            *default_referral;
-
 /*
  * no mutex protection in here - take our chances!
  */
@@ -40,8 +39,11 @@ config_info( Connection *conn, Operation *op )
        vals[1] = NULL;
 
        e = (Entry *) ch_calloc( 1, sizeof(Entry) );
+
        e->e_attrs = NULL;
-       e->e_dn = strdup( SLAPD_CONFIG_DN );
+       e->e_dn = ch_strdup( SLAPD_CONFIG_DN );
+       e->e_ndn = dn_normalize_case( ch_strdup( SLAPD_CONFIG_DN ));
+       e->e_private = NULL;
 
        for ( i = 0; i < nbackends; i++ ) {
                strcpy( buf, backends[i].be_type );
@@ -54,15 +56,8 @@ config_info( Connection *conn, Operation *op )
                attr_merge( e, "database", vals );
        }
 
-       if ( default_referral != NULL ) {
-               strcpy( buf, default_referral );
-               val.bv_val = buf;
-               val.bv_len = strlen( buf );
-               attr_merge( e, "database", vals );
-       }
-
-       send_search_entry( &backends[0], conn, op, e, NULL, 0 );
-       send_ldap_search_result( conn, op, LDAP_SUCCESS, NULL, NULL, 1 );
+       send_search_entry( &backends[0], conn, op, e, NULL, 0, 1 );
+       send_search_result( conn, op, LDAP_SUCCESS, NULL, NULL, NULL, 1 );
 
        entry_free( e );
 }
diff --git a/servers/slapd/controls.c b/servers/slapd/controls.c
new file mode 100644 (file)
index 0000000..9580ea0
--- /dev/null
@@ -0,0 +1,163 @@
+/* 
+ * Copyright 1999 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms 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.
+ */
+#include "portable.h"
+
+#include <stdio.h>
+#include <ac/socket.h>
+
+#include "slap.h"
+
+#include "../../libraries/liblber/lber-int.h"
+
+char *supportedControls[] = {
+       LDAP_CONTROL_MANAGEDSAIT,
+       NULL
+};
+
+int get_ctrls(
+       Connection *conn,
+       Operation *op,
+       int sendres )
+{
+       int nctrls;
+       ber_tag_t tag;
+       ber_len_t len;
+       char *opaque;
+       BerElement *ber = op->o_ber;
+       LDAPControl ***ctrls = &op->o_ctrls;
+       int rc = LDAP_SUCCESS;
+       char *errmsg = NULL;
+
+       len = ber_pvt_ber_remaining(ber);
+
+       if( len == 0) {
+               /* no controls */
+               rc = LDAP_SUCCESS;
+               goto return_results;
+       }
+
+       if(( tag = ber_peek_tag( ber, &len )) != LDAP_TAG_CONTROLS ) {
+               if( tag == LBER_ERROR ) {
+                       rc = -1;
+                       errmsg = "unexpected data in PDU";
+               }
+
+               goto return_results;
+       }
+
+       if( op->o_protocol < LDAP_VERSION3 ) {
+               rc = -1;
+               errmsg = "controls require LDAPv3";
+               goto return_results;
+       }
+
+       /* set through each element */
+       nctrls = 0;
+       *ctrls = ch_malloc( 1 * sizeof(LDAPControl *) );
+
+#if 0
+       if( *ctrls == NULL ) {
+               rc = LDAP_NO_MEMORY;
+               errmsg = "no memory";
+               goto return_results;
+       }
+#endif
+
+       ctrls[nctrls] = NULL;
+
+       for( tag = ber_first_element( ber, &len, &opaque );
+               tag != LBER_ERROR;
+               tag = ber_next_element( ber, &len, opaque ) )
+       {
+               LDAPControl *tctrl;
+               LDAPControl **tctrls;
+
+               tctrl = ch_calloc( 1, sizeof(LDAPControl) );
+
+               /* allocate pointer space for current controls (nctrls)
+                * + this control + extra NULL
+                */
+               tctrls = (tctrl == NULL) ? NULL :
+                       ch_realloc(*ctrls, (nctrls+2) * sizeof(LDAPControl *));
+
+#if 0
+               if( tctrls == NULL ) {
+                       /* one of the above allocation failed */
+
+                       if( tctrl != NULL ) {
+                               ch_free( tctrl );
+                       }
+
+                       ldap_controls_free(*ctrls);
+                       *ctrls = NULL;
+
+                       rc = LDAP_NO_MEMORY;
+                       errmsg = "no memory";
+                       goto return_results;
+               }
+#endif
+
+
+               tctrls[nctrls++] = tctrl;
+               tctrls[nctrls] = NULL;
+
+               tag = ber_scanf( ber, "{a" /*}*/, &tctrl->ldctl_oid );
+
+               if( tag != LBER_ERROR ) {
+                       tag = ber_peek_tag( ber, &len );
+               }
+
+               if( tag == LBER_BOOLEAN ) {
+                       ber_int_t crit;
+                       tag = ber_scanf( ber, "b", &crit );
+                       tctrl->ldctl_iscritical = crit ? (char) 0 : (char) ~0;
+               }
+
+               if( tag != LBER_ERROR ) {
+                       tag = ber_peek_tag( ber, &len );
+               }
+
+               if( tag == LBER_OCTETSTRING ) {
+                       tag = ber_scanf( ber, "o", &tctrl->ldctl_value );
+
+               } else {
+                       tctrl->ldctl_value.bv_val = NULL;
+               }
+
+               if( tag == LBER_ERROR ) {
+                       *ctrls = NULL;
+                       ldap_controls_free( tctrls );
+                       rc = -1;
+                       errmsg = "decoding controls error";
+                       goto return_results;
+               }
+
+               if( tctrl->ldctl_iscritical &&
+                       !charray_inlist( supportedControls, tctrl->ldctl_oid ) )
+               {
+                       rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
+                       errmsg = "critical extension is unavailable ";
+                       goto return_results;
+               }
+
+               *ctrls = tctrls;
+       }
+
+return_results:
+       if( sendres && rc != LDAP_SUCCESS ) {
+               if( rc == -1 ) {
+                       send_ldap_disconnect( conn, op, rc, errmsg );
+               } else {
+                       send_ldap_result( conn, op, rc, NULL, errmsg, NULL );
+               }
+       }
+
+       return rc;
+}
index bbab47806c0d7d24d7181125d39cfc485bdc898f..53d3f5007795279ff965c5f1dc3ed0cc93188b48 100644 (file)
  * is provided ``as is'' without express or implied warranty.
  */
 
+#include "portable.h"
+
 #include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include "slap.h"
 
-extern Backend *select_backend();
+#include <ac/string.h>
+#include <ac/socket.h>
 
-extern char    *default_referral;
+#include "slap.h"
 
-void
+int
 do_delete(
     Connection *conn,
     Operation  *op
 )
 {
-       char    *dn, *odn;
+       char    *ndn;
        Backend *be;
+       int rc;
 
        Debug( LDAP_DEBUG_TRACE, "do_delete\n", 0, 0, 0 );
 
+       if( op->o_bind_in_progress ) {
+               Debug( LDAP_DEBUG_ANY, "do_delete: SASL bind in progress.\n",
+                       0, 0, 0 );
+               send_ldap_result( conn, op, LDAP_SASL_BIND_IN_PROGRESS,
+                       NULL, "SASL bind in progress", NULL );
+               return LDAP_SASL_BIND_IN_PROGRESS;
+       }
+
        /*
         * Parse the delete request.  It looks like this:
         *
         *      DelRequest := DistinguishedName
         */
 
-       if ( ber_scanf( op->o_ber, "a", &dn ) == LBER_ERROR ) {
+       if ( ber_scanf( op->o_ber, "a", &ndn ) == LBER_ERROR ) {
                Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 );
-               send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL, "" );
-               return;
+               send_ldap_disconnect( conn, op,
+                       LDAP_PROTOCOL_ERROR, "decoding error" );
+               return -1;
        }
-       odn = strdup( dn );
-       dn_normalize( dn );
 
-       Debug( LDAP_DEBUG_ARGS, "do_delete: dn (%s)\n", dn, 0, 0 );
+       if( ( rc = get_ctrls( conn, op, 1 ) ) != LDAP_SUCCESS ) {
+               free( ndn );
+               Debug( LDAP_DEBUG_ANY, "do_add: get_ctrls failed\n", 0, 0, 0 );
+               return rc;
+       } 
+
+       Debug( LDAP_DEBUG_ARGS, "do_delete: dn (%s)\n", ndn, 0, 0 );
 
-       Debug( LDAP_DEBUG_STATS, "DEL dn=\"%s\"\n", dn, 0, 0 );
+       dn_normalize_case( ndn );
+
+       Debug( LDAP_DEBUG_STATS, "DEL dn=\"%s\"\n", ndn, 0, 0 );
 
        /*
         * We could be serving multiple database backends.  Select the
         * appropriate one, or send a referral to our "referral server"
         * if we don't hold it.
         */
-       if ( (be = select_backend( dn )) == NULL ) {
-               free( dn );
-               free( odn );
-               send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL,
-                   default_referral );
-               return;
+       if ( (be = select_backend( ndn )) == NULL ) {
+               free( ndn );
+               send_ldap_result( conn, op, rc = LDAP_REFERRAL,
+                       NULL, NULL, default_referral );
+               return rc;
        }
 
+       /* alias suffix if approp */
+       ndn = suffixAlias( ndn, op, be );
+
        /*
         * do the delete if 1 && (2 || 3)
         * 1) there is a delete function implemented in this backend;
         * 2) this backend is master for what it holds;
-        * 3) it's a replica and the dn supplied is the updatedn.
+        * 3) it's a replica and the dn supplied is the update_ndn.
         */
-       if ( be->be_delete != NULL ) {
+       if ( be->be_delete ) {
                /* do the update here */
-               if ( be->be_updatedn == NULL || strcasecmp( be->be_updatedn,
-                   op->o_dn ) == 0 ) {
-                       if ( (*be->be_delete)( be, conn, op, dn ) == 0 ) {
-                               replog( be, LDAP_REQ_DELETE, odn, NULL, 0 );
+               if ( be->be_update_ndn == NULL ||
+                       strcmp( be->be_update_ndn, op->o_ndn ) == 0 )
+               {
+                       if ( (*be->be_delete)( be, conn, op, ndn ) == 0 ) {
+                               replog( be, LDAP_REQ_DELETE, ndn, NULL, 0 );
                        }
                } else {
-                       send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL,
-                           default_referral );
+                       send_ldap_result( conn, op, rc = LDAP_REFERRAL,
+                               NULL, NULL, default_referral );
                }
        } else {
-               send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
-                   "Function not implemented" );
+               send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
+                       NULL, "Function not implemented", NULL );
        }
 
-       free( dn );
-       free( odn );
+       free( ndn );
+       return rc;
 }
diff --git a/servers/slapd/extended.c b/servers/slapd/extended.c
new file mode 100644 (file)
index 0000000..7082448
--- /dev/null
@@ -0,0 +1,112 @@
+/* 
+ * Copyright 1999 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms 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.
+ */
+
+/*
+ * LDAPv3 Extended Operation Request
+ *     ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
+ *             requestName      [0] LDAPOID,
+ *             requestValue     [1] OCTET STRING OPTIONAL
+ *     }
+ *
+ * LDAPv3 Extended Operation Response
+ *     ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
+ *             COMPONENTS OF LDAPResult,
+ *             responseName     [10] LDAPOID OPTIONAL,
+ *             response         [11] OCTET STRING OPTIONAL
+ *     }
+ *
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <ac/socket.h>
+
+#include "slap.h"
+
+char *supportedExtensions[] = {
+       NULL
+};
+
+
+int
+do_extended(
+    Connection *conn,
+    Operation  *op
+)
+{
+       int rc = LDAP_SUCCESS;
+       char* reqoid ;
+       struct berval reqdata;
+       ber_tag_t tag;
+       ber_len_t len;
+
+       Debug( LDAP_DEBUG_TRACE, "do_extended\n", 0, 0, 0 );
+
+       reqoid = NULL;
+       reqdata.bv_val = NULL;
+
+       if( op->o_protocol < LDAP_VERSION3 ) {
+               Debug( LDAP_DEBUG_ANY, "do_extended: protocol version (%d) too low\n",
+                       op->o_protocol, 0 ,0 );
+               send_ldap_disconnect( conn, op,
+                       LDAP_PROTOCOL_ERROR, "requires LDAPv3" );
+               rc = -1;
+               goto done;
+       }
+
+       if ( ber_scanf( op->o_ber, "a", &reqoid ) == LBER_ERROR ) {
+               Debug( LDAP_DEBUG_ANY, "do_extended: ber_scanf failed\n", 0, 0 ,0 );
+               send_ldap_disconnect( conn, op,
+                       LDAP_PROTOCOL_ERROR, "decoding error" );
+               rc = -1;
+               goto done;
+       }
+
+       if( !charray_inlist( supportedExtensions, reqoid ) ) {
+               Debug( LDAP_DEBUG_ANY, "do_extended: unsupported operation \"%s\"\n",
+                       reqoid, 0 ,0 );
+               send_ldap_result( conn, op, rc = LDAP_PROTOCOL_ERROR,
+                       NULL, "unsuppored extended operation", NULL );
+               goto done;
+       }
+
+       tag = ber_peek_tag( op->o_ber, &len );
+       
+       if( ber_peek_tag( op->o_ber, &len ) == LDAP_TAG_EXOP_REQ_VALUE ) {
+               if( ber_scanf( op->o_ber, "o", &reqdata ) != LBER_ERROR ) {
+                       Debug( LDAP_DEBUG_ANY, "do_extended: ber_scanf failed\n", 0, 0 ,0 );
+                       send_ldap_disconnect( conn, op,
+                               LDAP_PROTOCOL_ERROR, "decoding error" );
+                       rc = -1;
+                       goto done;
+               }
+       }
+
+       if( (rc = get_ctrls( conn, op, 1 )) != LDAP_SUCCESS ) {
+               Debug( LDAP_DEBUG_ANY, "do_extended: get_ctrls failed\n", 0, 0 ,0 );
+               return rc;
+       } 
+
+       Debug( LDAP_DEBUG_ARGS, "do_extended: oid \"%s\"\n", reqoid, 0 ,0 );
+
+       send_ldap_result( conn, op, rc = LDAP_PROTOCOL_ERROR,
+               NULL, "unsupported extended operation", NULL );
+
+done:
+       if ( reqoid != NULL ) {
+               free( reqoid );
+       }
+       if ( reqdata.bv_val != NULL ) {
+               free( reqdata.bv_val );
+       }
+
+       return rc;
+}
\ No newline at end of file
index 03dd850f0e86c8e92e6fa4371741334114c32e9f..dc5091066331c30df0bd8eec0bbc602b66d470ff 100644 (file)
 /* init.c - initialize various things */
 
-#include <stdio.h>
-#include <string.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
 #include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/socket.h>
+#include <ac/string.h>
+#include <ac/time.h>
+
 #include "slap.h"
 
-extern pthread_mutex_t active_threads_mutex;
-extern pthread_mutex_t new_conn_mutex;
-extern pthread_mutex_t currenttime_mutex;
-extern pthread_mutex_t entry2str_mutex;
-extern pthread_mutex_t replog_mutex;
-extern pthread_mutex_t ops_mutex;
-extern pthread_mutex_t num_sent_mutex;
-#ifndef sunos5
-extern pthread_mutex_t regex_mutex;
+/*
+ * read-only global variables or variables only written by the listener
+ * thread (after they are initialized) - no need to protect them with a mutex.
+ */
+int            slap_debug = 0;
+
+#ifdef LDAP_DEBUG
+int            ldap_syslog = LDAP_DEBUG_STATS;
+#else
+int            ldap_syslog;
 #endif
 
-init()
+int            ldap_syslog_level = LOG_DEBUG;
+struct berval **default_referral = NULL;
+int            g_argc;
+char           **g_argv;
+
+/*
+ * global variables that need mutex protection
+ */
+int                            active_threads;
+ldap_pvt_thread_mutex_t        active_threads_mutex;
+ldap_pvt_thread_cond_t active_threads_cond;
+
+ldap_pvt_thread_mutex_t        gmtime_mutex;
+#ifdef SLAPD_CRYPT
+ldap_pvt_thread_mutex_t        crypt_mutex;
+#endif
+
+int                            num_conns;
+long                   num_ops_initiated;
+long                   num_ops_completed;
+ldap_pvt_thread_mutex_t        num_ops_mutex;
+
+long                   num_entries_sent;
+long                   num_refs_sent;
+long                   num_bytes_sent;
+long                   num_pdu_sent;
+ldap_pvt_thread_mutex_t        num_sent_mutex;
+/*
+ * these mutexes must be used when calling the entry2str()
+ * routine since it returns a pointer to static data.
+ */
+ldap_pvt_thread_mutex_t        entry2str_mutex;
+ldap_pvt_thread_mutex_t        replog_mutex;
+
+static char* slap_name;
+int slapMode = SLAP_UNDEFINED_MODE;
+
+static ldap_pvt_thread_mutex_t currenttime_mutex;
+
+int
+slap_init( int mode, char *name )
 {
-       pthread_mutex_init( &active_threads_mutex, pthread_mutexattr_default );
-       pthread_mutex_init( &new_conn_mutex, pthread_mutexattr_default );
-       pthread_mutex_init( &currenttime_mutex, pthread_mutexattr_default );
-       pthread_mutex_init( &entry2str_mutex, pthread_mutexattr_default );
-       pthread_mutex_init( &replog_mutex, pthread_mutexattr_default );
-       pthread_mutex_init( &ops_mutex, pthread_mutexattr_default );
-       pthread_mutex_init( &num_sent_mutex, pthread_mutexattr_default );
-#ifndef sunos5
-       pthread_mutex_init( &regex_mutex, pthread_mutexattr_default );
+       int rc;
+
+       if( slapMode != SLAP_UNDEFINED_MODE ) {
+               Debug( LDAP_DEBUG_ANY,
+                "%s init: init called twice (old=%d, new=%d)\n",
+                name, slapMode, mode );
+               return 1;
+       }
+
+       slapMode = mode;
+
+       switch ( slapMode ) {
+
+               case SLAP_SERVER_MODE:
+               case SLAP_TOOL_MODE:
+#ifdef SLAPD_BDB2
+               case SLAP_TIMEDSERVER_MODE:
+               case SLAP_TOOLID_MODE:
+#endif
+
+                       Debug( LDAP_DEBUG_TRACE,
+                               "%s init: initiated %s.\n",
+                               name, mode == SLAP_TOOL_MODE ? "tool" : "server", 0 );
+
+                       slap_name = name;
+       
+                       (void) ldap_pvt_thread_initialize();
+
+                       ldap_pvt_thread_mutex_init( &active_threads_mutex );
+                       ldap_pvt_thread_cond_init( &active_threads_cond );
+
+                       ldap_pvt_thread_mutex_init( &currenttime_mutex );
+                       ldap_pvt_thread_mutex_init( &entry2str_mutex );
+                       ldap_pvt_thread_mutex_init( &replog_mutex );
+                       ldap_pvt_thread_mutex_init( &num_ops_mutex );
+                       ldap_pvt_thread_mutex_init( &num_sent_mutex );
+
+                       ldap_pvt_thread_mutex_init( &gmtime_mutex );
+#ifdef SLAPD_CRYPT
+                       ldap_pvt_thread_mutex_init( &crypt_mutex );
 #endif
+
+                       rc = backend_init();
+                       break;
+
+               default:
+                       Debug( LDAP_DEBUG_ANY,
+                               "%s init: undefined mode (%d).\n", name, mode, 0 );
+                       rc = 1;
+                       break;
+       }
+
+       return rc;
+}
+
+int slap_startup(int dbnum)
+{
+       int rc;
+
+       Debug( LDAP_DEBUG_TRACE,
+               "%s startup: initiated.\n",
+               slap_name, 0, 0 );
+
+       rc = backend_startup(dbnum);
+
+       return rc;
+}
+
+int slap_shutdown(int dbnum)
+{
+       int rc;
+
+       Debug( LDAP_DEBUG_TRACE,
+               "%s shutdown: initiated\n",
+               slap_name, 0, 0 );
+
+       /* let backends do whatever cleanup they need to do */
+       rc = backend_shutdown(dbnum); 
+
+       return rc;
+}
+
+int slap_destroy(void)
+{
+       int rc;
+
+       Debug( LDAP_DEBUG_TRACE,
+               "%s shutdown: freeing system resources.\n",
+               slap_name, 0, 0 );
+
+       rc = backend_destroy();
+
+       ldap_pvt_thread_destroy();
+
+       /* should destory the above mutex */
+       return rc;
+}
+
+/* should create a utils.c for these */
+time_t slap_get_time(void)
+{
+       time_t t;
+       ldap_pvt_thread_mutex_lock( &currenttime_mutex );
+       time( &t );
+       ldap_pvt_thread_mutex_unlock( &currenttime_mutex );
+       return t;
 }
index 6575fe36adbd7a434c772d6ab328acd9fc51ad77..cfc62e8d697aa1034f3427c606a2aba6a45f8f32 100644 (file)
  * is provided ``as is'' without express or implied warranty.
  */
 
+#include "portable.h"
+
 #include <stdio.h>
-#include <string.h>
-#include <time.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include "slap.h"
 
-extern Backend *select_backend();
+#include <ac/socket.h>
+#include <ac/string.h>
+#include <ac/time.h>
 
-extern char            *default_referral;
-extern time_t          currenttime;
-extern pthread_mutex_t currenttime_mutex;
-extern int             global_lastmod;
+#include "slap.h"
 
-static void    modlist_free();
-static void    add_lastmods();
+static void    modlist_free(LDAPModList *ml);
 
-void
+int
 do_modify(
     Connection *conn,
     Operation  *op
 )
 {
-       char            *dn, *odn;
+       char            *ndn;
        char            *last;
-       unsigned long   tag, len;
-       LDAPMod         *mods, *tmp;
-       LDAPMod         **modtail;
+       ber_tag_t       tag;
+       ber_len_t       len;
+       LDAPModList     *modlist;
+       LDAPModList     **modtail;
+#ifdef LDAP_DEBUG
+       LDAPModList *tmp;
+#endif
        Backend         *be;
+       int rc;
 
        Debug( LDAP_DEBUG_TRACE, "do_modify\n", 0, 0, 0 );
 
+       if( op->o_bind_in_progress ) {
+               Debug( LDAP_DEBUG_ANY, "do_modify: SASL bind in progress.\n",
+                       0, 0, 0 );
+               send_ldap_result( conn, op, LDAP_SASL_BIND_IN_PROGRESS, NULL,
+                   "SASL bind in progress", NULL );
+               return LDAP_SASL_BIND_IN_PROGRESS;
+       }
+
        /*
         * Parse the modify request.  It looks like this:
         *
@@ -62,198 +69,150 @@ do_modify(
         *      }
         */
 
-       if ( ber_scanf( op->o_ber, "{a", &dn ) == LBER_ERROR ) {
+       if ( ber_scanf( op->o_ber, "{a" /*}*/, &ndn ) == LBER_ERROR ) {
                Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 );
-               send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL, "" );
-               return;
+               send_ldap_disconnect( conn, op,
+                       LDAP_PROTOCOL_ERROR, "decoding error" );
+               return -1;
        }
-       odn = strdup( dn );
-       dn_normalize( dn );
 
-       Debug( LDAP_DEBUG_ARGS, "do_modify: dn (%s)\n", dn, 0, 0 );
+       Debug( LDAP_DEBUG_ARGS, "do_modify: dn (%s)\n", ndn, 0, 0 );
+
+       (void) dn_normalize_case( ndn );
 
        /* collect modifications & save for later */
-       mods = NULL;
-       modtail = &mods;
+       modlist = NULL;
+       modtail = &modlist;
+
        for ( tag = ber_first_element( op->o_ber, &len, &last );
            tag != LBER_DEFAULT;
            tag = ber_next_element( op->o_ber, &len, last ) )
        {
-               (*modtail) = (LDAPMod *) ch_calloc( 1, sizeof(LDAPMod) );
+               ber_int_t mop;
 
-               if ( ber_scanf( op->o_ber, "{i{a[V]}}", &(*modtail)->mod_op,
-                   &(*modtail)->mod_type, &(*modtail)->mod_bvalues )
+               (*modtail) = (LDAPModList *) ch_calloc( 1, sizeof(LDAPModList) );
+
+               if ( ber_scanf( op->o_ber, "{i{a[V]}}", &mop,
+                   &(*modtail)->ml_type, &(*modtail)->ml_bvalues )
                    == LBER_ERROR )
                {
-                       send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL,
-                           "decoding error" );
-                       free( dn );
-                       free( odn );
+                       send_ldap_disconnect( conn, op,
+                               LDAP_PROTOCOL_ERROR, "decoding modlist error" );
+                       free( ndn );
                        free( *modtail );
-                       modlist_free( mods );
-                       return;
+                       *modtail = NULL;
+                       modlist_free( modlist );
+                       return -1;
                }
 
-               if ( (*modtail)->mod_op != LDAP_MOD_ADD &&
-                   (*modtail)->mod_op != LDAP_MOD_DELETE &&
-                   (*modtail)->mod_op != LDAP_MOD_REPLACE )
+               (*modtail)->ml_op = mop;
+               
+               if ( (*modtail)->ml_op != LDAP_MOD_ADD &&
+                   (*modtail)->ml_op != LDAP_MOD_DELETE &&
+                   (*modtail)->ml_op != LDAP_MOD_REPLACE )
                {
-                       send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL,
-                           "unrecognized modify operation" );
-                       free( dn );
-                       free( odn );
-                       modlist_free( mods );
-                       return;
+                       send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR,
+                           NULL, "unrecognized modify operation", NULL );
+                       free( ndn );
+                       modlist_free( modlist );
+                       return LDAP_PROTOCOL_ERROR;
                }
 
-               if ( (*modtail)->mod_bvalues == NULL && (*modtail)->mod_op
-                 != LDAP_MOD_DELETE ) {
-                       send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL,
-                           "no values given" );
-                       free( dn );
-                       free( odn );
-                       modlist_free( mods );
-                       return;
+               if ( (*modtail)->ml_bvalues == NULL
+                       && (*modtail)->ml_op != LDAP_MOD_DELETE )
+               {
+                       send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR,
+                           NULL, "unrecognized modify operation", NULL );
+                       free( ndn );
+                       modlist_free( modlist );
+                       return LDAP_PROTOCOL_ERROR;
                }
-               attr_normalize( (*modtail)->mod_type );
+               attr_normalize( (*modtail)->ml_type );
 
-               modtail = &(*modtail)->mod_next;
+               modtail = &(*modtail)->ml_next;
        }
        *modtail = NULL;
 
 #ifdef LDAP_DEBUG
        Debug( LDAP_DEBUG_ARGS, "modifications:\n", 0, 0, 0 );
-       for ( tmp = mods; tmp != NULL; tmp = tmp->mod_next ) {
-               Debug( LDAP_DEBUG_ARGS, "\t%s: %s\n", tmp->mod_op
-                   == LDAP_MOD_ADD ? "add" : (tmp->mod_op == LDAP_MOD_DELETE ?
-                   "delete" : "replace"), tmp->mod_type, 0 );
+       for ( tmp = modlist; tmp != NULL; tmp = tmp->ml_next ) {
+               Debug( LDAP_DEBUG_ARGS, "\t%s: %s\n",
+                       tmp->ml_op == LDAP_MOD_ADD
+                               ? "add" : (tmp->ml_op == LDAP_MOD_DELETE
+                                       ? "delete" : "replace"), tmp->ml_type, 0 );
        }
 #endif
 
+       if( (rc = get_ctrls( conn, op, 1 )) != LDAP_SUCCESS ) {
+               free( ndn );
+               modlist_free( modlist );
+               Debug( LDAP_DEBUG_ANY, "do_modify: get_ctrls failed\n", 0, 0, 0 );
+               return rc;
+       } 
+
        Statslog( LDAP_DEBUG_STATS, "conn=%d op=%d MOD dn=\"%s\"\n",
-           conn->c_connid, op->o_opid, dn, 0, 0 );
+           conn->c_connid, op->o_opid, ndn, 0, 0 );
 
        /*
         * We could be serving multiple database backends.  Select the
         * appropriate one, or send a referral to our "referral server"
         * if we don't hold it.
         */
-       if ( (be = select_backend( dn )) == NULL ) {
-               free( dn );
-               free( odn );
-               modlist_free( mods );
-               send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL,
-                   default_referral );
-               return;
+       if ( (be = select_backend( ndn )) == NULL ) {
+               free( ndn );
+               modlist_free( modlist );
+               send_ldap_result( conn, op, rc = LDAP_REFERRAL,
+                       NULL, NULL, default_referral );
+               return rc;
        }
 
+       /* alias suffix if approp */
+       ndn = suffixAlias ( ndn, op, be );
+
        /*
         * do the modify if 1 && (2 || 3)
         * 1) there is a modify function implemented in this backend;
         * 2) this backend is master for what it holds;
-        * 3) it's a replica and the dn supplied is the updatedn.
+        * 3) it's a replica and the dn supplied is the update_ndn.
         */
-       if ( be->be_modify != NULL ) {
+       if ( be->be_modify ) {
                /* do the update here */
-               if ( be->be_updatedn == NULL || strcasecmp( be->be_updatedn,
-                   op->o_dn ) == 0 ) {
-                       if ( (be->be_lastmod == ON || be->be_lastmod == 0 &&
-                           global_lastmod == ON) && be->be_updatedn == NULL ) {
-                               add_lastmods( op, &mods );
-                       }
-                       if ( (*be->be_modify)( be, conn, op, odn, mods )
-                           == 0 ) {
-                               replog( be, LDAP_REQ_MODIFY, dn, mods, 0 );
+               if ( be->be_update_ndn == NULL ||
+                       strcmp( be->be_update_ndn, op->o_ndn ) == 0 )
+               {
+                       if ( (*be->be_modify)( be, conn, op, ndn, modlist ) == 0 ) {
+                               replog( be, LDAP_REQ_MODIFY, ndn, modlist, 0 );
                        }
 
                /* send a referral */
                } else {
-                       send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL,
-                           default_referral );
+                       send_ldap_result( conn, op, rc = LDAP_REFERRAL,
+                               NULL, NULL, default_referral );
                }
        } else {
-               send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
-                   "Function not implemented" );
+               send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
+                   NULL, "Function not implemented", NULL );
        }
 
-       free( dn );
-       free( odn );
-       modlist_free( mods );
+       free( ndn );
+       modlist_free( modlist );
+       return rc;
 }
 
 static void
 modlist_free(
-    LDAPMod    *mods
+    LDAPModList        *ml
 )
 {
-       LDAPMod *next;
-
-       for ( ; mods != NULL; mods = next ) {
-               next = mods->mod_next;
-               free( mods->mod_type );
-               if ( mods->mod_bvalues != NULL )
-                       ber_bvecfree( mods->mod_bvalues );
-               free( mods );
-       }
-}
-
-static void
-add_lastmods( Operation *op, LDAPMod **mods )
-{
-       char            buf[20];
-       struct berval   bv;
-       struct berval   *bvals[2];
-       LDAPMod         **m;
-       LDAPMod         *tmp;
-       struct tm       *ltm;
+       LDAPModList *next;
 
-       Debug( LDAP_DEBUG_TRACE, "add_lastmods\n", 0, 0, 0 );
+       for ( ; ml != NULL; ml = next ) {
+               next = ml->ml_next;
 
-       bvals[0] = &bv;
-       bvals[1] = NULL;
+               free( ml->ml_type );
+               if ( ml->ml_bvalues != NULL )
+                       ber_bvecfree( ml->ml_bvalues );
 
-       /* remove any attempts by the user to modify these attrs */
-       for ( m = mods; *m != NULL; m = &(*m)->mod_next ) {
-               if ( strcasecmp( (*m)->mod_type, "modifytimestamp" ) == 0
-                   || strcasecmp( (*m)->mod_type, "modifiersname" ) == 0 ) {
-                       tmp = *m;
-                       *m = (*m)->mod_next;
-                       free( tmp->mod_type );
-                       if ( tmp->mod_bvalues != NULL ) {
-                               ber_bvecfree( tmp->mod_bvalues );
-                       }
-                       free( tmp );
-               }
-       }
-
-       if ( op->o_dn == NULL || op->o_dn[0] == '\0' ) {
-               bv.bv_val = "NULLDN";
-               bv.bv_len = strlen( bv.bv_val );
-       } else {
-               bv.bv_val = op->o_dn;
-               bv.bv_len = strlen( bv.bv_val );
+               free( ml );
        }
-       tmp = (LDAPMod *) ch_calloc( 1, sizeof(LDAPMod) );
-       tmp->mod_type = strdup( "modifiersname" );
-       tmp->mod_op = LDAP_MOD_REPLACE;
-       tmp->mod_bvalues = (struct berval **) ch_calloc( 1,
-           2 * sizeof(struct berval *) );
-       tmp->mod_bvalues[0] = ber_bvdup( &bv );
-       tmp->mod_next = *mods;
-       *mods = tmp;
-
-       pthread_mutex_lock( &currenttime_mutex );
-        ltm = localtime( &currenttime );
-        strftime( buf, sizeof(buf), "%y%m%d%H%M%SZ", ltm );
-       pthread_mutex_unlock( &currenttime_mutex );
-       bv.bv_val = buf;
-       bv.bv_len = strlen( bv.bv_val );
-       tmp = (LDAPMod *) ch_calloc( 1, sizeof(LDAPMod) );
-       tmp->mod_type = strdup( "modifytimestamp" );
-       tmp->mod_op = LDAP_MOD_REPLACE;
-       tmp->mod_bvalues = (struct berval **) ch_calloc( 1,
-           2 * sizeof(struct berval *) );
-       tmp->mod_bvalues[0] = ber_bvdup( &bv );
-       tmp->mod_next = *mods;
-       *mods = tmp;
 }
index 802dda55acb4cf4f20fe02cde7a5b0ce69cd4d9e..439fb41452c82f827a5c2274b5a180065c47b41b 100644 (file)
  * is provided ``as is'' without express or implied warranty.
  */
 
+/*
+ * LDAP v3 newSuperior support.
+ *
+ * Copyright 1999, Juan C. Gomez, All rights reserved.
+ * This software is not subject to any license of Silicon Graphics 
+ * Inc. or Purdue University.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * without restriction or fee of any kind as long as this notice
+ * is preserved.
+ *
+ */
+
+#include "portable.h"
+
 #include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include "slap.h"
 
-extern Backend *select_backend();
+#include <ac/socket.h>
+#include <ac/string.h>
 
-extern char    *default_referral;
+#include "slap.h"
 
-void
+int
 do_modrdn(
     Connection *conn,
     Operation  *op
 )
 {
-       char    *dn, *odn, *newrdn;
-       int     deloldrdn;
+       char    *ndn, *newrdn;
+       ber_int_t       deloldrdn;
        Backend *be;
+       /* Vars for LDAP v3 newSuperior support */
+       char    *newSuperior = NULL;
+       char    *nnewSuperior = NULL;
+       Backend *newSuperior_be = NULL;
+       ber_len_t       length;
+       int rc;
 
        Debug( LDAP_DEBUG_TRACE, "do_modrdn\n", 0, 0, 0 );
 
+       if( op->o_bind_in_progress ) {
+               Debug( LDAP_DEBUG_ANY, "do_modrdn: SASL bind in progress.\n",
+                       0, 0, 0 );
+               send_ldap_result( conn, op, LDAP_SASL_BIND_IN_PROGRESS, NULL,
+                   "SASL bind in progress", NULL );
+               return LDAP_SASL_BIND_IN_PROGRESS;
+       }
+
        /*
         * Parse the modrdn request.  It looks like this:
         *
         *      ModifyRDNRequest := SEQUENCE {
         *              entry   DistinguishedName,
         *              newrdn  RelativeDistinguishedName
+        *              deleteoldrdn    BOOLEAN,
+        *              newSuperior     [0] LDAPDN OPTIONAL (v3 Only!)
         *      }
         */
 
-       if ( ber_scanf( op->o_ber, "{aab}", &dn, &newrdn, &deloldrdn )
+       if ( ber_scanf( op->o_ber, "{aab", &ndn, &newrdn, &deloldrdn )
            == LBER_ERROR ) {
                Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 );
-               send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL, "" );
-               return;
+               send_ldap_disconnect( conn, op,
+                       LDAP_PROTOCOL_ERROR, "decoding error" );
+               return -1;
+       }
+
+       /* Check for newSuperior parameter, if present scan it */
+
+       if ( ber_peek_tag( op->o_ber, &length ) == LDAP_TAG_NEWSUPERIOR ) {
+
+               if ( op->o_protocol == 0 ) {
+                       /*
+                        * Promote to LDAPv3
+                        */
+                       ldap_pvt_thread_mutex_lock( &conn->c_mutex );
+                       conn->c_protocol = LDAP_VERSION3;
+                       ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
+                       op->o_protocol = LDAP_VERSION3;
+
+               } else if ( op->o_protocol < LDAP_VERSION3 ) {
+                       /* Conection record indicates v2 but field 
+                        * newSuperior is present: report error.
+                        */
+                       Debug( LDAP_DEBUG_ANY,
+                              "modrdn(v2): invalid field newSuperior!\n",
+                              0, 0, 0 );
+                       send_ldap_disconnect( conn, op,
+                               LDAP_PROTOCOL_ERROR, "newSuperior requires LDAPv3" );
+                       return -1;
+               }
+
+               if ( ber_scanf( op->o_ber, "a", &newSuperior ) 
+                    == LBER_ERROR ) {
+
+                   Debug( LDAP_DEBUG_ANY, "ber_scanf(\"a\"}) failed\n",
+                          0, 0, 0 );
+                       send_ldap_disconnect( conn, op,
+                               LDAP_PROTOCOL_ERROR, "decoding error" );
+                   return -1;
+
+               }
+
        }
-       odn = strdup( dn );
-       dn_normalize( dn );
 
        Debug( LDAP_DEBUG_ARGS,
-           "do_modrdn: dn (%s) newrdn (%s) deloldrdn (%d)\n", dn, newrdn,
-           deloldrdn );
+           "do_modrdn: dn (%s) newrdn (%s) newsuperior (%s)\n",
+               ndn, newrdn,
+               newSuperior != NULL ? newSuperior : "" );
+
+       if ( ber_scanf( op->o_ber, /*{*/ "}") == LBER_ERROR ) {
+               free( ndn );
+               free( newrdn ); 
+               free( newSuperior );
+               Debug( LDAP_DEBUG_ANY, "do_modrdn: ber_scanf failed\n", 0, 0, 0 );
+               send_ldap_disconnect( conn, op,
+                               LDAP_PROTOCOL_ERROR, "decoding error" );
+               return -1;
+       }
+
+       if( (rc = get_ctrls( conn, op, 1 )) != LDAP_SUCCESS ) {
+               free( ndn );
+               free( newrdn ); 
+               free( newSuperior );
+               Debug( LDAP_DEBUG_ANY, "do_modrdn: get_ctrls failed\n", 0, 0, 0 );
+               return rc;
+       } 
+
+       if( newSuperior != NULL ) {
+               /* GET BACKEND FOR NEW SUPERIOR */
+
+               nnewSuperior = strdup( newSuperior );
+               dn_normalize_case( nnewSuperior );
+
+               if ( (newSuperior_be = select_backend( nnewSuperior )) 
+                    == NULL ) {
+                   
+                       /* We do not have a backend for newSuperior so we send
+                        * a referral.
+                        * XXX: We may need to do something else here, not sure
+                        * what though.
+                        */
+
+                       Debug( LDAP_DEBUG_ARGS,
+                              "do_modrdn: cant find backend for=(%s)\n",
+                              newSuperior, 0, 0 );
+                       
+                       free( ndn );
+                       free( newrdn );
+                       free( newSuperior );
+                       free( nnewSuperior );
+                       send_ldap_result( conn, op, LDAP_REFERRAL,
+                               NULL, NULL, default_referral );
+                       return 0;
+               }
+       }
+
+       dn_normalize_case( ndn );
 
        Statslog( LDAP_DEBUG_STATS, "conn=%d op=%d MODRDN dn=\"%s\"\n",
-           conn->c_connid, op->o_opid, dn, 0, 0 );
+           conn->c_connid, op->o_opid, ndn, 0, 0 );
 
        /*
         * We could be serving multiple database backends.  Select the
@@ -63,40 +178,70 @@ do_modrdn(
         * if we don't hold it.
         */
 
-       if ( (be = select_backend( dn )) == NULL ) {
-               free( dn );
-               free( odn );
+       if ( (be = select_backend( ndn )) == NULL ) {
+               free( ndn );
+               free( newrdn ); 
+               free( newSuperior );
+               free( nnewSuperior );
+               send_ldap_result( conn, op, rc = LDAP_REFERRAL,
+                       NULL, NULL, default_referral );
+               return rc;
+       }
+
+       /* Make sure that the entry being changed and the newSuperior are in 
+        * the same backend, otherwise we return an error.
+        */
+
+       if ( (newSuperior_be != NULL) && ( be != newSuperior_be) ) {
+
+               Debug( LDAP_DEBUG_ANY, "dn=(%s), newSuperior=(%s)\n", ndn,
+                      newSuperior, 0 );
+               
+               free( ndn );
                free( newrdn );
-               send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL,
-                   default_referral );
-               return;
+               free( newSuperior );
+               free( nnewSuperior );
+               
+               send_ldap_result( conn, op, rc = LDAP_AFFECTS_MULTIPLE_DSAS,
+                       NULL, NULL, NULL );
+           
+               return rc;
+
        }
 
+
+       /* alias suffix if approp */
+       ndn = suffixAlias( ndn, op, be );
+
        /*
         * do the add if 1 && (2 || 3)
         * 1) there is an add function implemented in this backend;
         * 2) this backend is master for what it holds;
-        * 3) it's a replica and the dn supplied is the updatedn.
+        * 3) it's a replica and the dn supplied is the update_ndn.
         */
-       if ( be->be_modrdn != NULL ) {
+       if ( be->be_modrdn ) {
                /* do the update here */
-               if ( be->be_updatedn == NULL || strcasecmp( be->be_updatedn,
-                   op->o_dn ) == 0 ) {
-                       if ( (*be->be_modrdn)( be, conn, op, dn, newrdn,
-                           deloldrdn ) == 0 ) {
-                               replog( be, LDAP_REQ_MODRDN, odn, newrdn,
+               if ( be->be_update_ndn == NULL ||
+                       strcmp( be->be_update_ndn, op->o_ndn ) == 0 )
+               {
+                       if ( (*be->be_modrdn)( be, conn, op, ndn, newrdn,
+                           deloldrdn, newSuperior ) == 0 ) {
+                               /* XXX: MAY NEED TO ADD newSuperior HERE */
+                               replog( be, LDAP_REQ_MODRDN, ndn, newrdn,
                                    deloldrdn );
                        }
                } else {
-                       send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL,
-                           default_referral );
+                       send_ldap_result( conn, op, rc = LDAP_REFERRAL,
+                               NULL, NULL, default_referral );
                }
        } else {
-               send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
-                   "Function not implemented" );
+               send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
+                       NULL, "Function not implemented", NULL );
        }
 
-       free( dn );
-       free( odn );
-       free( newrdn );
+       free( ndn );
+       free( newrdn ); 
+       free( newSuperior );
+       free( nnewSuperior );
+       return rc;
 }
index 7dbabc93772c071c9c180645aa8cbef8b251227f..251f8b5ec3d0df99cd7ae2b87c3902e220dc2041 100644 (file)
  * is provided ``as is'' without express or implied warranty.
  */
 
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include "slap.h"
-#include "ldapconfig.h"
+#include "portable.h"
 
-#if defined( SLAPD_MONITOR_DN )
-
-extern int             nbackends;
-extern Backend         *backends;
-extern int             active_threads;
-extern int             dtblsize;
-extern Connection      *c;
-extern long            ops_initiated;
-extern long            ops_completed;
-extern long            num_entries_sent;
-extern long            num_bytes_sent;
-extern time_t          currenttime;
-extern time_t          starttime;
-extern int             num_conns;
+#include <stdio.h>
 
+#include <ac/socket.h>
+#include <ac/string.h>
+#include <ac/time.h>
 
-extern char Versionstr[];
+#include "ldap_defaults.h"
+#include "slap.h"
 
-/*
- * no mutex protection in here - take our chances!
- */
+#if defined( SLAPD_MONITOR_DN )
 
 void
 monitor_info( Connection *conn, Operation *op )
 {
        Entry           *e;
-       char            buf[BUFSIZ], buf2[20];
+       char            buf[BUFSIZ];
        struct berval   val;
        struct berval   *vals[2];
-       int             i, nconns, nwritewaiters, nreadwaiters;
+       int    nconns, nwritewaiters, nreadwaiters;
        struct tm       *ltm;
-       char            *p, *tmpdn;
+       char            *p;
+    char       buf2[22];
+    char       buf3[22];
+       Connection *c;
+       int                     connindex;
+    time_t             currenttime;
 
        vals[0] = &val;
        vals[1] = NULL;
 
        e = (Entry *) ch_calloc( 1, sizeof(Entry) );
+       /* initialize reader/writer lock */
        e->e_attrs = NULL;
-       e->e_dn = strdup( SLAPD_MONITOR_DN );
+       e->e_dn = ch_strdup( SLAPD_MONITOR_DN );
+       e->e_ndn = dn_normalize_case( ch_strdup(SLAPD_MONITOR_DN) );
+       e->e_private = NULL;
 
-       val.bv_val = Versionstr;
+       val.bv_val = (char *) Versionstr;
        if (( p = strchr( Versionstr, '\n' )) == NULL ) {
                val.bv_len = strlen( Versionstr );
        } else {
@@ -65,7 +57,9 @@ monitor_info( Connection *conn, Operation *op )
        }
        attr_merge( e, "version", vals );
 
+       ldap_pvt_thread_mutex_lock( &active_threads_mutex );
        sprintf( buf, "%d", active_threads );
+       ldap_pvt_thread_mutex_unlock( &active_threads_mutex );
        val.bv_val = buf;
        val.bv_len = strlen( buf );
        attr_merge( e, "threads", vals );
@@ -73,82 +67,165 @@ monitor_info( Connection *conn, Operation *op )
        nconns = 0;
        nwritewaiters = 0;
        nreadwaiters = 0;
-       for ( i = 0; i < dtblsize; i++ ) {
-               if ( c[i].c_sb.sb_sd != -1 ) {
-                       nconns++;
-                       if ( c[i].c_writewaiter ) {
-                               nwritewaiters++;
-                       }
-                       if ( c[i].c_gettingber ) {
-                               nreadwaiters++;
-                       }
-                       ltm = localtime( &c[i].c_starttime );
-                       strftime( buf2, sizeof(buf2), "%y%m%d%H%M%SZ", ltm );
-                       pthread_mutex_lock( &c[i].c_dnmutex );
-                       sprintf( buf, "%d : %s : %ld : %ld : %s : %s%s", i,
-                           buf2, c[i].c_opsinitiated, c[i].c_opscompleted,
-                           c[i].c_dn ? c[i].c_dn : "NULLDN",
-                           c[i].c_gettingber ? "r" : "",
-                           c[i].c_writewaiter ? "w" : "" );
-                       pthread_mutex_unlock( &c[i].c_dnmutex );
-                       val.bv_val = buf;
-                       val.bv_len = strlen( buf );
-                       attr_merge( e, "connection", vals );
+
+       /* loop through the connections */
+       for ( c = connection_first( &connindex );
+               c != NULL;
+               c = connection_next( c, &connindex ))
+       {
+               nconns++;
+               if ( c->c_writewaiter ) {
+                       nwritewaiters++;
+               }
+               if ( c->c_currentber != NULL ) {
+                       nreadwaiters++;
                }
+
+               ldap_pvt_thread_mutex_lock( &gmtime_mutex );
+#ifndef LDAP_LOCALTIME
+               ltm = gmtime( &c->c_starttime );
+               strftime( buf2, sizeof(buf2), "%Y%m%d%H%M%SZ", ltm );
+
+               ltm = gmtime( &c->c_activitytime );
+               strftime( buf3, sizeof(buf2), "%Y%m%d%H%M%SZ", ltm );
+#else
+               ltm = localtime( &c->.c_starttime );
+               strftime( buf2, sizeof(buf2), "%y%m%d%H%M%SZ", ltm );
+
+               ltm = localtime( &c->c_activitytime );
+               strftime( buf3, sizeof(buf2), "%y%m%d%H%M%SZ", ltm );
+#endif
+
+               ldap_pvt_thread_mutex_unlock( &gmtime_mutex );
+
+               sprintf( buf,
+                       "%ld : %ld "
+                       ": %ld/%ld/%ld/%ld "
+                       ": %ld/%ld/%ld "
+                       ": %s%s%s%s%s%s "
+                       ": %s : %s : %s "
+                       ": %s : %s",
+
+                       c->c_connid,
+                       (long) c->c_protocol,
+
+                       c->c_n_ops_received, c->c_n_ops_executing,
+                       c->c_n_ops_pending, c->c_n_ops_completed,
+
+                       /* add low-level counters here */
+                       c->c_n_get, c->c_n_read, c->c_n_write,
+
+                   c->c_currentber ? "r" : "",
+                   c->c_writewaiter ? "w" : "",
+                   c->c_ops != NULL ? "x" : "",
+                   c->c_pending_ops != NULL ? "p" : "",
+                       connection_state2str( c->c_conn_state ),
+                       c->c_bind_in_progress ? "S" : "",
+
+                   c->c_cdn ? c->c_cdn : "<anonymous>",
+                   c->c_client_addr ? c->c_client_addr : "unknown",
+                   c->c_client_name ? c->c_client_name : "unknown",
+
+                   buf2,
+                       buf3
+               );
+
+               val.bv_val = buf;
+               val.bv_len = strlen( buf );
+               attr_merge( e, "connection", vals );
        }
+       connection_done(c);
+
        sprintf( buf, "%d", nconns );
        val.bv_val = buf;
        val.bv_len = strlen( buf );
-       attr_merge( e, "currentconnections", vals );
+       attr_merge( e, "currentConnections", vals );
 
-       sprintf( buf, "%d", num_conns );
+       sprintf( buf, "%ld", connections_nextid() );
        val.bv_val = buf;
        val.bv_len = strlen( buf );
-       attr_merge( e, "totalconnections", vals );
+       attr_merge( e, "totalConnections", vals );
 
-       sprintf( buf, "%d", dtblsize );
+       sprintf( buf, "%ld", (long) dtblsize );
        val.bv_val = buf;
        val.bv_len = strlen( buf );
-       attr_merge( e, "dtablesize", vals );
+       attr_merge( e, "dTableSize", vals );
 
        sprintf( buf, "%d", nwritewaiters );
        val.bv_val = buf;
        val.bv_len = strlen( buf );
-       attr_merge( e, "writewaiters", vals );
+       attr_merge( e, "writeWaiters", vals );
 
        sprintf( buf, "%d", nreadwaiters );
        val.bv_val = buf;
        val.bv_len = strlen( buf );
-       attr_merge( e, "readwaiters", vals );
+       attr_merge( e, "readWaiters", vals );
 
-       sprintf( buf, "%ld", ops_initiated );
+       ldap_pvt_thread_mutex_lock(&num_ops_mutex);
+       sprintf( buf, "%ld", num_ops_initiated );
+       ldap_pvt_thread_mutex_unlock(&num_ops_mutex);
        val.bv_val = buf;
        val.bv_len = strlen( buf );
-       attr_merge( e, "opsinitiated", vals );
+       attr_merge( e, "opsInitiated", vals );
 
-       sprintf( buf, "%ld", ops_completed );
+       ldap_pvt_thread_mutex_lock(&num_ops_mutex);
+       sprintf( buf, "%ld", num_ops_completed );
+       ldap_pvt_thread_mutex_unlock(&num_ops_mutex);
        val.bv_val = buf;
        val.bv_len = strlen( buf );
-       attr_merge( e, "opscompleted", vals );
+       attr_merge( e, "opsCompleted", vals );
 
+       ldap_pvt_thread_mutex_lock(&num_sent_mutex);
        sprintf( buf, "%ld", num_entries_sent );
+       ldap_pvt_thread_mutex_unlock(&num_sent_mutex);
        val.bv_val = buf;
        val.bv_len = strlen( buf );
-       attr_merge( e, "entriessent", vals );
+       attr_merge( e, "entriesSent", vals );
 
+       ldap_pvt_thread_mutex_lock(&num_sent_mutex);
+       sprintf( buf, "%ld", num_refs_sent );
+       ldap_pvt_thread_mutex_unlock(&num_sent_mutex);
+       val.bv_val = buf;
+       val.bv_len = strlen( buf );
+       attr_merge( e, "referencesSent", vals );
+
+       ldap_pvt_thread_mutex_lock(&num_sent_mutex);
+       sprintf( buf, "%ld", num_pdu_sent );
+       ldap_pvt_thread_mutex_unlock(&num_sent_mutex);
+       val.bv_val = buf;
+       val.bv_len = strlen( buf );
+       attr_merge( e, "pduSent", vals );
+
+       ldap_pvt_thread_mutex_lock(&num_sent_mutex);
        sprintf( buf, "%ld", num_bytes_sent );
+       ldap_pvt_thread_mutex_unlock(&num_sent_mutex);
        val.bv_val = buf;
        val.bv_len = strlen( buf );
-       attr_merge( e, "bytessent", vals );
+       attr_merge( e, "bytesSent", vals );
 
-        ltm = localtime( &currenttime );
-        strftime( buf, sizeof(buf), "%y%m%d%H%M%SZ", ltm );
+       currenttime = slap_get_time();
+
+       ldap_pvt_thread_mutex_lock( &gmtime_mutex );
+#ifndef LDAP_LOCALTIME
+       ltm = gmtime( &currenttime );
+       strftime( buf, sizeof(buf), "%Y%m%d%H%M%SZ", ltm );
+#else
+       ltm = localtime( &currenttime );
+       strftime( buf, sizeof(buf), "%y%m%d%H%M%SZ", ltm );
+#endif
        val.bv_val = buf;
        val.bv_len = strlen( buf );
        attr_merge( e, "currenttime", vals );
 
-        ltm = localtime( &starttime );
-        strftime( buf, sizeof(buf), "%y%m%d%H%M%SZ", ltm );
+#ifndef LDAP_LOCALTIME
+       ltm = gmtime( &starttime );
+       strftime( buf, sizeof(buf), "%Y%m%d%H%M%SZ", ltm );
+#else
+       ltm = localtime( &starttime );
+       strftime( buf, sizeof(buf), "%y%m%d%H%M%SZ", ltm );
+#endif
+       ldap_pvt_thread_mutex_unlock( &gmtime_mutex );
+
        val.bv_val = buf;
        val.bv_len = strlen( buf );
        attr_merge( e, "starttime", vals );
@@ -158,15 +235,15 @@ monitor_info( Connection *conn, Operation *op )
        val.bv_len = strlen( buf );
        attr_merge( e, "nbackends", vals );
 
-#ifdef THREAD_SUNOS5_LWP
-       sprintf( buf, "%d", thr_getconcurrency() );
+#ifdef HAVE_THREAD_CONCURRENCY
+       sprintf( buf, "%d", ldap_pvt_thread_get_concurrency() );
        val.bv_val = buf;
        val.bv_len = strlen( buf );
        attr_merge( e, "concurrency", vals );
 #endif
 
-       send_search_entry( &backends[0], conn, op, e, NULL, 0 );
-       send_ldap_search_result( conn, op, LDAP_SUCCESS, NULL, NULL, 1 );
+       send_search_entry( &backends[0], conn, op, e, NULL, 0, 1 );
+       send_search_result( conn, op, LDAP_SUCCESS, NULL, NULL, NULL, 1 );
 
        entry_free( e );
 }
index a1ff6e5e755cb202ec1fb25028591eb53c45af47..6e29f71056c9486a8039e1d8773ca8d48c4c31ab 100644 (file)
 #ifndef _PROTO_SLAP
 #define _PROTO_SLAP
 
+#include <ldap_cdefs.h>
+
+LDAP_BEGIN_DECL
+
 /*
  * acl.c
  */
 
-int access_allowed( Backend *be, Connection *conn, Operation *op, Entry *e,
-       char *attr, struct berval *val, char *dn, int  access );
-struct acl * acl_get_applicable( Backend *be, Operation *op, Entry *e,
-       char *attr );
-int acl_access_allowed( struct acl *a, Backend *be, Connection *conn, Entry *e,
-       struct berval *val, Operation *op, int  access );
-int acl_check_mods( Backend *be, Connection *conn, Operation *op, Entry *e,
-       LDAPMod *mods );
+int access_allowed LDAP_P(( Backend *be, Connection *conn,
+       Operation *op, Entry *e,
+       char *attr, struct berval *val, int access ));
+
+struct acl * acl_get_applicable LDAP_P(( Backend *be,
+       Operation *op, Entry *e,
+       char *attr, int nmatches, regmatch_t *matches ));
+
+int acl_access_allowed LDAP_P(( struct acl *a, Backend *be, Connection *conn, Entry *e,
+       struct berval *val, Operation *op, int  access, char *edn,
+       regmatch_t *matches ));
+
+int acl_check_modlist LDAP_P(( Backend *be,
+       Connection *conn,
+       Operation *op,
+       Entry *e,
+       LDAPModList *ml ));
 
 /*
  * aclparse.c
  */
 
-void parse_acl( Backend *be, char *fname, int lineno, int argc, char **argv );
-char * access2str( int access );
-int str2access( char *str );
+void parse_acl LDAP_P(( Backend *be, char *fname, int lineno, int argc, char **argv ));
+char * access2str LDAP_P(( int access ));
+int str2access LDAP_P(( char *str ));
 
 /*
  * attr.c
  */
 
-void attr_free( Attribute *a );
-char * attr_normalize( char *s );
-int attr_merge_fast( Entry *e, char *type, struct berval **vals, int  nvals,
-       int  naddvals, int  *maxvals, Attribute ***a );
-int attr_merge( Entry *e, char *type, struct berval **vals );
-Attribute * attr_find( Attribute *a, char *type );
-int attr_delete( Attribute **attrs, char *type );
-int attr_syntax( char *type );
-void attr_syntax_config( char *fname, int lineno, int argc, char **argv );
+void attr_free LDAP_P(( Attribute *a ));
+char * attr_normalize LDAP_P(( char *s ));
+int attr_merge_fast LDAP_P(( Entry *e, char *type, struct berval **vals, int  nvals,
+       int  naddvals, int  *maxvals, Attribute ***a ));
+int attr_merge LDAP_P(( Entry *e, char *type, struct berval **vals ));
+Attribute * attr_find LDAP_P(( Attribute *a, char *type ));
+int attr_delete LDAP_P(( Attribute **attrs, char *type ));
+int attr_syntax LDAP_P(( char *type ));
+void attr_syntax_config LDAP_P(( char *fname, int lineno, int argc, char **argv ));
+AttributeType * at_find LDAP_P(( const char *name ));
+int at_find_in_list LDAP_P(( AttributeType *sat, AttributeType **list ));
+int at_append_to_list LDAP_P(( AttributeType *sat, AttributeType ***listp ));
+int at_delete_from_list LDAP_P(( int pos, AttributeType ***listp ));
+int at_fake_if_needed LDAP_P(( char *name ));
+int at_schema_info LDAP_P(( Entry *e ));
+int at_add LDAP_P(( LDAP_ATTRIBUTE_TYPE *at, const char **err ));
+char * at_canonical_name LDAP_P(( char * a_type ));
 
 /*
  * ava.c
  */
 
-int get_ava( BerElement *ber, Ava *ava );
-void ava_free( Ava *ava, int freeit );
+int get_ava LDAP_P(( BerElement *ber, Ava *ava ));
+void ava_free LDAP_P(( Ava *ava, int freeit ));
 
 /*
  * backend.c
  */
 
-Backend * new_backend( char *type );
-Backend * select_backend( char * dn );
-int be_issuffix( Backend *be, char *suffix );
-int be_isroot( Backend *be, char *dn );
-int be_isroot_pw( Backend *be, char *dn, struct berval *cred );
-void be_close();
+int backend_init LDAP_P((void));
+int backend_add LDAP_P((BackendInfo *aBackendInfo));
+int backend_startup LDAP_P((int dbnum));
+int backend_shutdown LDAP_P((int dbnum));
+int backend_destroy LDAP_P((void));
+
+BackendInfo * backend_info LDAP_P(( char *type ));
+BackendDB * backend_db_init LDAP_P(( char *type ));
+
+BackendDB * select_backend LDAP_P(( char * dn ));
+
+int be_issuffix LDAP_P(( Backend *be, char *suffix ));
+int be_isroot LDAP_P(( Backend *be, char *ndn ));
+int be_isroot_pw LDAP_P(( Backend *be, char *ndn, struct berval *cred ));
+char* be_root_dn LDAP_P(( Backend *be ));
+int be_entry_release_rw LDAP_P(( Backend *be, Entry *e, int rw ));
+#define be_entry_release_r( be, e ) be_entry_release_rw( be, e, 0 )
+#define be_entry_release_w( be, e ) be_entry_release_rw( be, e, 1 )
+
+
+extern int     backend_unbind LDAP_P((Connection *conn, Operation *op));
+
+extern int     backend_connection_init LDAP_P((Connection *conn));
+extern int     backend_connection_destroy LDAP_P((Connection *conn));
+
+extern int     backend_group LDAP_P((Backend *be,
+       Entry *target,
+       char *gr_ndn, char *op_ndn,
+       char *objectclassValue, char *groupattrName));
 
 /*
  * ch_malloc.c
  */
 
-char * ch_malloc( unsigned long size );
-char * ch_realloc( char *block, unsigned long size );
-char * ch_calloc( unsigned long nelem, unsigned long size );
+void * ch_malloc LDAP_P(( ber_len_t size ));
+void * ch_realloc LDAP_P(( void *block, ber_len_t size ));
+void * ch_calloc LDAP_P(( ber_len_t nelem, ber_len_t size ));
+char * ch_strdup LDAP_P(( const char *string ));
+void   ch_free LDAP_P(( void * ));
+#define free ch_free
 
 /*
  * charray.c
  */
 
-void charray_add( char ***a, char *s );
-void charray_merge( char ***a, char **s );
-void charray_free( char **array );
-int charray_inlist( char **a, char *s );
-char ** charray_dup( char **a );
-char ** str2charray( char *str, char *brkstr );
+void charray_add LDAP_P(( char ***a, char *s ));
+void charray_merge LDAP_P(( char ***a, char **s ));
+void charray_free LDAP_P(( char **array ));
+int charray_inlist LDAP_P(( char **a, char *s ));
+char ** charray_dup LDAP_P(( char **a ));
+char ** str2charray LDAP_P(( char *str, char *brkstr ));
+char * charray2str LDAP_P(( char **a ));
+
+/*
+ * controls.c
+ */
+int get_ctrls LDAP_P((
+       Connection *co,
+       Operation *op,
+       int senderrors ));
 
 /*
  * config.c
  */
 
-void read_config( char *fname, Backend **bep, FILE *pfp );
+int read_config LDAP_P(( char *fname ));
 
 /*
  * connection.c
  */
+int connections_init LDAP_P((void));
+int connections_shutdown LDAP_P((void));
+int connections_destroy LDAP_P((void));
+int connections_timeout_idle LDAP_P((time_t));
+
+long connection_init LDAP_P((
+       ber_socket_t s,
+       const char* name, const char* addr));
 
-void connection_activity( Connection *conn );
+void connection_closing LDAP_P(( Connection *c ));
+int connection_state_closing LDAP_P(( Connection *c ));
+char *connection_state2str LDAP_P(( int state ));
+
+int connection_write LDAP_P((ber_socket_t s));
+int connection_read LDAP_P((ber_socket_t s));
+
+unsigned long connections_nextid(void);
+
+Connection* connection_first LDAP_P((ber_socket_t *));
+Connection* connection_next LDAP_P((Connection *, ber_socket_t *));
+void connection_done LDAP_P((Connection *));
 
 /*
  * dn.c
  */
 
-char * dn_normalize( char *dn );
-char * dn_normalize_case( char *dn );
-char * dn_parent( Backend *be, char *dn );
-int dn_issuffix( char *dn, char *suffix );
-int dn_type( char *dn );
-char * dn_upcase( char *dn );
-
+char * dn_normalize LDAP_P(( char *dn ));
+char * dn_normalize_case LDAP_P(( char *dn ));
+char * dn_parent LDAP_P(( Backend *be, char *dn ));
+char * dn_rdn LDAP_P(( Backend *be, char *dn ));
+int dn_issuffix LDAP_P(( char *dn, char *suffix ));
+int dn_type LDAP_P(( char *dn ));
+char * dn_upcase LDAP_P(( char *dn ));
+char * rdn_attr_value LDAP_P(( char * rdn ));
+char * rdn_attr_type LDAP_P(( char * rdn ));
+void build_new_dn LDAP_P(( char ** new_dn, char *e_dn, char * p_dn,
+                          char * newrdn ));
 /*
  * entry.c
  */
 
-Entry * str2entry( char        *s );
-char * entry2str( Entry *e, int *len, int printid );
-void entry_free( Entry *e );
+Entry * str2entry LDAP_P(( char        *s ));
+char * entry2str LDAP_P(( Entry *e, int *len, int printid ));
+void entry_free LDAP_P(( Entry *e ));
+
+int entry_cmp LDAP_P(( Entry *a, Entry *b ));
+int entry_dn_cmp LDAP_P(( Entry *a, Entry *b ));
+int entry_id_cmp LDAP_P(( Entry *a, Entry *b ));
 
 /*
  * filter.c
  */
 
-int get_filter( Connection *conn, BerElement *ber, Filter **filt, char **fstr );
-void filter_free( Filter *f );
-void filter_print( Filter *f );
+int get_filter LDAP_P(( Connection *conn, BerElement *ber, Filter **filt, char **fstr ));
+void filter_free LDAP_P(( Filter *f ));
+void filter_print LDAP_P(( Filter *f ));
 
 /*
  * filterentry.c
  */
 
-int test_filter( Backend *be, Connection *conn, Operation *op, Entry *e,
-       Filter  *f );
+int test_filter LDAP_P(( Backend *be, Connection *conn, Operation *op, Entry *e,
+       Filter  *f ));
 
 /*
  * lock.c
  */
 
-FILE * lock_fopen( char *fname, char *type, FILE **lfp );
-int lock_fclose( FILE *fp, FILE *lfp );
+FILE * lock_fopen LDAP_P(( char *fname, char *type, FILE **lfp ));
+int lock_fclose LDAP_P(( FILE *fp, FILE *lfp ));
+
+/*
+ * module.c
+ */
+
+#ifdef SLAPD_MODULES
+int load_module LDAP_P(( const char* file_name, int argc, char *argv[] ));
+#endif /* SLAPD_MODULES */
 
 /*
  * monitor.c
  */
+extern char *supportedExtensions[];
+extern char *supportedControls[];
+extern char *supportedSASLMechanisms[];
 
-void monitor_info( Connection *conn, Operation *op );
+void monitor_info LDAP_P(( Connection *conn, Operation *op ));
 
 /*
  * operation.c
  */
 
-void op_free( Operation *op );
-Operation * op_add( Operation **olist, BerElement *ber, unsigned long msgid,
-       unsigned long tag, char *dn, int id, int connid );
-void op_delete( Operation **olist, Operation *op );
+void slap_op_free LDAP_P(( Operation *op ));
+Operation * slap_op_alloc LDAP_P((
+       BerElement *ber, ber_int_t msgid,
+       ber_tag_t tag, ber_int_t id ));
+
+int slap_op_add LDAP_P(( Operation **olist, Operation *op ));
+int slap_op_remove LDAP_P(( Operation **olist, Operation *op ));
+Operation * slap_op_pop LDAP_P(( Operation **olist ));
 
 /*
  * phonetic.c
  */
 
-char * first_word( char *s );
-char * next_word( char *s );
-char * word_dup( char *w );
-char * phonetic( char *s );
+char * first_word LDAP_P(( char *s ));
+char * next_word LDAP_P(( char *s ));
+char * word_dup LDAP_P(( char *w ));
+char * phonetic LDAP_P(( char *s ));
 
 /*
  * repl.c
  */
 
-void replog( Backend *be, int optype, char *dn, void *change, int flag );
+void replog LDAP_P(( Backend *be, int optype, char *dn, void *change, int flag ));
 
 /*
  * result.c
  */
 
-void send_ldap_result( Connection *conn, Operation *op, int err, char *matched,
-       char *text );
-void send_ldap_search_result( Connection *conn, Operation *op, int err,
-       char *matched, char *text, int nentries );
-void close_connection( Connection *conn, int opconnid, int opid );
+void send_ldap_result LDAP_P((
+       Connection *conn, Operation *op,
+       int err, char *matched, char *text,
+       struct berval **refs ));
+
+void send_ldap_disconnect LDAP_P((
+       Connection *conn, Operation *op,
+       int err, char *text ));
+
+void send_search_result LDAP_P((
+       Connection *conn, Operation *op,
+       int err, char *matched, char *text,
+       struct berval **refs,
+       int nentries ));
+
+int send_search_reference LDAP_P((
+       Backend *be, Connection *conn, Operation *op,
+       Entry *e, struct berval **refs,
+       struct berval ***v2refs ));
+
+int send_search_entry LDAP_P((
+       Backend *be, Connection *conn, Operation *op,
+       Entry *e, char **attrs, int attrsonly, int opattrs ));
+
+int str2result LDAP_P(( char *s,
+       int *code, char **matched, char **info ));
 
 /*
  * schema.c
  */
 
-int oc_schema_check( Entry *e );
+int oc_schema_check LDAP_P(( Entry *e ));
+int oc_check_operational_attr LDAP_P(( char *type ));
+int oc_check_usermod_attr LDAP_P(( char *type ));
+int oc_check_no_usermod_attr LDAP_P(( char *type ));
+ObjectClass *oc_find LDAP_P((const char *ocname));
+int oc_add LDAP_P((LDAP_OBJECT_CLASS *oc, const char **err));
+Syntax *syn_find LDAP_P((const char *synname));
+int syn_add LDAP_P((LDAP_SYNTAX *syn, slap_syntax_check_func *check, const char **err));
+MatchingRule *mr_find LDAP_P((const char *mrname));
+int mr_add LDAP_P((LDAP_MATCHING_RULE *mr, slap_mr_normalize_func *normalize, slap_mr_compare_func *compare, const char **err));
+void schema_info LDAP_P((Connection *conn, Operation *op, char **attrs, int attrsonly));
+int schema_init LDAP_P((void));
+
 
 /*
  * schemaparse.c
  */
 
-void parse_oc( Backend *be, char *fname, int lineno, int argc, char **argv );
-
+void parse_oc_old LDAP_P(( Backend *be, char *fname, int lineno, int argc, char **argv ));
+void parse_oc LDAP_P(( char *fname, int lineno, char *line ));
+void parse_at LDAP_P(( char *fname, int lineno, char *line ));
+char *scherr2str LDAP_P((int code));
 /*
  * str2filter.c
  */
 
-Filter * str2filter( char *str );
+Filter * str2filter LDAP_P(( char *str ));
 
 /*
  * value.c
  */
 
-int value_add_fast( struct berval ***vals, struct berval **addvals, int nvals,
-       int naddvals, int *maxvals );
-int value_add( struct berval ***vals, struct berval **addvals );
-void value_normalize( char *s, int syntax );
-int value_cmp( struct berval *v1, struct berval *v2, int syntax,
-       int normalize );
-int value_ncmp( struct berval *v1, struct berval *v2, int syntax, int len,
-       int normalize );
-int value_find( struct berval **vals, struct berval *v, int syntax,
-       int normalize );
+int value_add_fast LDAP_P(( struct berval ***vals, struct berval **addvals, int nvals,
+       int naddvals, int *maxvals ));
+int value_add LDAP_P(( struct berval ***vals, struct berval **addvals ));
+void value_normalize LDAP_P(( char *s, int syntax ));
+int value_cmp LDAP_P(( struct berval *v1, struct berval *v2, int syntax,
+       int normalize ));
+int value_find LDAP_P(( struct berval **vals, struct berval *v, int syntax,
+       int normalize ));
+
+/*
+ * suffixAlias.c
+ */
+char *suffixAlias LDAP_P(( char *dn, Operation *op, Backend *be ));
+
+/*
+ * user.c
+ */
+#if defined(HAVE_PWD_H) && defined(HAVE_GRP_H)
+void slap_init_user LDAP_P(( char *username, char *groupname ));
+#endif
+
+/*
+ * Other...
+ */
+
+extern struct berval **default_referral;
+extern char            *replogfile;
+extern const char Versionstr[];
+extern int             active_threads;
+extern int             defsize;
+extern int             deftime;
+extern int             g_argc;
+extern int             global_default_access;
+extern int             global_lastmod;
+extern int             global_idletimeout;
+extern int             global_schemacheck;
+extern char            *global_realm;
+extern int             lber_debug;
+extern int             ldap_syslog;
+
+extern ldap_pvt_thread_mutex_t num_sent_mutex;
+extern long            num_bytes_sent;
+extern long            num_pdu_sent;
+extern long            num_entries_sent;
+extern long            num_refs_sent;
+
+extern ldap_pvt_thread_mutex_t num_ops_mutex;
+extern long            num_ops_completed;
+extern long            num_ops_initiated;
+
+extern char   *slapd_pid_file;
+extern char   *slapd_args_file;
+extern char            **g_argv;
+extern time_t  starttime;
+
+time_t slap_get_time LDAP_P((void));
+
+extern ldap_pvt_thread_mutex_t active_threads_mutex;
+extern ldap_pvt_thread_cond_t  active_threads_cond;
+
+extern ldap_pvt_thread_mutex_t entry2str_mutex;
+extern ldap_pvt_thread_mutex_t replog_mutex;
+
+#ifdef SLAPD_CRYPT
+extern ldap_pvt_thread_mutex_t crypt_mutex;
+#endif
+extern ldap_pvt_thread_mutex_t gmtime_mutex;
+
+extern struct acl              *global_acl;
+
+int    slap_init LDAP_P((int mode, char* name));
+int    slap_startup LDAP_P((int dbnum));
+int    slap_shutdown LDAP_P((int dbnum));
+int    slap_destroy LDAP_P((void));
+
+struct sockaddr_in;
+
+struct slapd_args {
+       struct sockaddr_in *addr;
+       int tcps;
+};
+
+extern int     slapd_daemon LDAP_P((struct slapd_args *args));
+extern int     set_socket LDAP_P((struct sockaddr_in *addr));
+
+extern void slapd_set_write LDAP_P((ber_socket_t s, int wake));
+extern void slapd_clr_write LDAP_P((ber_socket_t s, int wake));
+extern void slapd_set_read LDAP_P((ber_socket_t s, int wake));
+extern void slapd_clr_read LDAP_P((ber_socket_t s, int wake));
+
+extern void slapd_remove LDAP_P((ber_socket_t s, int wake));
+
+extern void    slap_set_shutdown LDAP_P((int sig));
+extern void    slap_do_nothing   LDAP_P((int sig));
+
+extern void    config_info LDAP_P((Connection *conn, Operation *op));
+extern void    root_dse_info LDAP_P((Connection *conn, Operation *op, char **attrs, int attrsonly));
+
+extern int     do_abandon LDAP_P((Connection *conn, Operation *op));
+extern int     do_add LDAP_P((Connection *conn, Operation *op));
+extern int     do_bind LDAP_P((Connection *conn, Operation *op));
+extern int     do_compare LDAP_P((Connection *conn, Operation *op));
+extern int     do_delete LDAP_P((Connection *conn, Operation *op));
+extern int     do_modify LDAP_P((Connection *conn, Operation *op));
+extern int     do_modrdn LDAP_P((Connection *conn, Operation *op));
+extern int     do_search LDAP_P((Connection *conn, Operation *op));
+extern int     do_unbind LDAP_P((Connection *conn, Operation *op));
+extern int     do_extended LDAP_P((Connection *conn, Operation *op));
+
+
+extern ber_socket_t dtblsize;
+
+LDAP_END_DECL
 
 #endif /* _proto_slap */
+
index 0ef82a7b3e36e03f85a4a71a91040153fe182064..8ebb81bab863735f81b2c916d606016e4e6bb49f 100644 (file)
 /* result.c - routines to send ldap results, errors, and referrals */
 
-#include <stdio.h>
-#include <string.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <errno.h>
-#include <signal.h>
 #include "portable.h"
-#include "slap.h"
 
-#ifndef SYSERRLIST_IN_STDIO
-extern int             sys_nerr;
-extern char            *sys_errlist[];
-#endif
-extern int             active_threads;
-extern pthread_mutex_t active_threads_mutex;
-extern pthread_mutex_t new_conn_mutex;
-extern pthread_t       listener_tid;
-extern struct acl      *acl_get_applicable();
-extern long            num_entries_sent;
-extern long            num_bytes_sent;
-extern pthread_mutex_t num_sent_mutex;
+#include <stdio.h>
 
-void   close_connection();
+#include <ac/socket.h>
+#include <ac/errno.h>
+#include <ac/signal.h>
+#include <ac/string.h>
+#include <ac/time.h>
+#include <ac/unistd.h>
 
-static void
-send_ldap_result2(
-    Connection *conn,
-    Operation  *op,
-    int                err,
-    char       *matched,
-    char       *text,
-    int                nentries
-)
+#include "slap.h"
+
+/* we need LBER internals */
+#include "../../libraries/liblber/lber-int.h"
+
+static char *v2ref( struct berval **ref )
 {
-       BerElement      *ber;
-       int             rc, sd;
-       unsigned long   tag, bytes;
+       size_t len, i;
+       char *v2;
 
-       Debug( LDAP_DEBUG_TRACE, "send_ldap_result %d:%s:%s\n", err, matched ?
-           matched : "", text ? text : "" );
+       if(ref == NULL) return NULL;
 
-       switch ( op->o_tag ) {
-       case LBER_DEFAULT:
-               tag = LBER_SEQUENCE;
-               break;
+       len = sizeof("Referral:");
+       v2 = ch_strdup("Referral:");
+
+       for( i=0; ref[i] != NULL; i++ ) {
+               v2 = ch_realloc( v2, len + ref[i]->bv_len + 1 );
+               v2[len-1] = '\n';
+               memcpy(&v2[len], ref[i]->bv_val, ref[i]->bv_len );
+               len += ref[i]->bv_len;
+       }
 
-       case LDAP_REQ_SEARCH:
-               tag = LDAP_RES_SEARCH_RESULT;
+       v2[len-1] = '\0';
+       return v2;
+}
+
+static ber_tag_t req2res( ber_tag_t tag )
+{
+       switch( tag ) {
+       case LDAP_REQ_ADD:
+       case LDAP_REQ_BIND:
+       case LDAP_REQ_COMPARE:
+       case LDAP_REQ_EXTENDED:
+       case LDAP_REQ_MODIFY:
+       case LDAP_REQ_MODRDN:
+               tag++;
                break;
 
        case LDAP_REQ_DELETE:
                tag = LDAP_RES_DELETE;
                break;
 
-       default:
-               tag = op->o_tag + 1;
+       case LDAP_REQ_ABANDON:
+       case LDAP_REQ_UNBIND:
+               tag = LBER_SEQUENCE;
                break;
        }
+       return tag;
+}
 
-#ifdef COMPAT30
-       if ( (ber = ber_alloc_t( conn->c_version == 30 ? 0 : LBER_USE_DER ))
-           == NULLBER ) {
-#else
-       if ( (ber = der_alloc()) == NULLBER ) {
-#endif
-               Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 );
-               return;
-       }
 
-#ifdef CLDAP
-       if ( op->o_cldap ) {
-               rc = ber_printf( ber, "{is{t{ess}}}", op->o_msgid, "", tag,
-                   err, matched ? matched : "", text ? text : "" );
-       } else
-#endif
-#ifdef COMPAT30
-       if ( conn->c_version == 30 ) {
-               rc = ber_printf( ber, "{it{{ess}}}", op->o_msgid, tag, err,
-                   matched ? matched : "", text ? text : "" );
-       } else
-#endif
-               rc = ber_printf( ber, "{it{ess}}", op->o_msgid, tag, err,
-                   matched ? matched : "", text ? text : "" );
-
-       if ( rc == -1 ) {
-               Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
-               return;
-       }
+long send_ldap_ber(
+       Connection *conn,
+       BerElement *ber )
+{
+       ber_len_t bytes = ber_pvt_ber_bytes( ber );
 
        /* write only one pdu at a time - wait til it's our turn */
-       pthread_mutex_lock( &conn->c_pdumutex );
+       ldap_pvt_thread_mutex_lock( &conn->c_write_mutex );
+
+       /* lock the connection */ 
+       ldap_pvt_thread_mutex_lock( &conn->c_mutex );
 
        /* write the pdu */
-       bytes = ber->ber_ptr - ber->ber_buf;
-       pthread_mutex_lock( &new_conn_mutex );
-       while ( conn->c_connid == op->o_connid && ber_flush( &conn->c_sb, ber,
-           1 ) != 0 ) {
-               pthread_mutex_unlock( &new_conn_mutex );
+       while( 1 ) {
+               int err;
+
+               if ( connection_state_closing( conn ) ) {
+                       ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
+                       ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
+                       return 0;
+               }
+
+               if ( ber_flush( conn->c_sb, ber, 1 ) == 0 ) {
+                       break;
+               }
+
+               err = errno;
+
                /*
                 * we got an error.  if it's ewouldblock, we need to
                 * wait on the socket being writable.  otherwise, figure
@@ -107,77 +97,281 @@ send_ldap_result2(
                 */
 
                Debug( LDAP_DEBUG_CONNS, "ber_flush failed errno %d msg (%s)\n",
-                   errno, errno > -1 && errno < sys_nerr ? sys_errlist[errno]
+                   err, err > -1 && err < sys_nerr ? sys_errlist[err]
                    : "unknown", 0 );
 
-               if ( errno != EWOULDBLOCK && errno != EAGAIN ) {
-                       close_connection( conn, op->o_connid, op->o_opid );
+               if ( err != EWOULDBLOCK && err != EAGAIN ) {
+                       connection_closing( conn );
 
-                       pthread_mutex_unlock( &conn->c_pdumutex );
-                       return;
+                       ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
+                       ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
+                       return( -1 );
                }
 
                /* wait for socket to be write-ready */
-               pthread_mutex_lock( &active_threads_mutex );
-               active_threads--;
                conn->c_writewaiter = 1;
-               pthread_kill( listener_tid, SIGUSR1 );
-               pthread_cond_wait( &conn->c_wcv, &active_threads_mutex );
-               pthread_mutex_unlock( &active_threads_mutex );
+               slapd_set_write( ber_pvt_sb_get_desc( conn->c_sb ), 1 );
 
-               pthread_yield();
-               pthread_mutex_lock( &new_conn_mutex );
+               ldap_pvt_thread_cond_wait( &conn->c_write_cv, &conn->c_mutex );
+               conn->c_writewaiter = 0;
        }
-       pthread_mutex_unlock( &new_conn_mutex );
-       pthread_mutex_unlock( &conn->c_pdumutex );
 
-       pthread_mutex_lock( &num_sent_mutex );
-       num_bytes_sent += bytes;
-       pthread_mutex_unlock( &num_sent_mutex );
+       ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
+       ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
 
-       Statslog( LDAP_DEBUG_STATS,
-           "conn=%d op=%d RESULT err=%d tag=%d nentries=%d\n", conn->c_connid,
-           op->o_opid, err, tag, nentries );
+       Debug( LDAP_DEBUG_TRACE, "<= send_ldap_ber\n", 0, 0, 0 );
+       return bytes;
+}
+
+static void
+send_ldap_response(
+    Connection *conn,
+    Operation  *op,
+       ber_tag_t       tag,
+       ber_int_t       msgid,
+    ber_int_t  err,
+    char       *matched,
+    char       *text,
+       struct berval   **ref,
+       char    *resoid,
+       struct berval   *resdata
+)
+{
+       BerElement      *ber;
+       int             rc;
+       long    bytes;
+
+       ber = ber_alloc_t( LBER_USE_DER );
+
+       if ( ber == NULL ) {
+               Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 );
+               return;
+       }
+
+#ifdef LDAP_CONNECTIONLESS
+       if ( op->o_cldap ) {
+               rc = ber_printf( ber, "{is{t{ess}}}", msgid, "", tag,
+                   err, matched ? matched : "", text ? text : "" );
+       } else
+#endif
+       {
+               rc = ber_printf( ber, "{it{ess",
+                       msgid, tag, err,
+                       matched == NULL ? "" : matched,
+                       text == NULL ? "" : text );
+
+               if( rc != -1 && ref != NULL ) {
+                       rc = ber_printf( ber, "{v}", ref );
+               }
+
+               if( rc != -1 && resoid != NULL ) {
+                       rc = ber_printf( ber, "s", resoid );
+               }
+
+               if( rc != -1 && resdata != NULL ) {
+                       rc = ber_printf( ber, "O", resdata );
+
+               }
+
+               if( rc != -1 ) {
+                       rc = ber_printf( ber, "}}" );
+               }
+       }
+
+       if ( rc == -1 ) {
+               Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
+               return;
+       }
+
+       /* send BER */
+       bytes = send_ldap_ber( conn, ber );
 
+       if ( bytes < 0 ) {
+               Debug( LDAP_DEBUG_ANY,
+                       "send_ldap_response: ber write failed\n",
+                       0, 0, 0 );
+               return;
+       }
+
+       ldap_pvt_thread_mutex_lock( &num_sent_mutex );
+       num_bytes_sent += bytes;
+       num_pdu_sent++;
+       ldap_pvt_thread_mutex_unlock( &num_sent_mutex );
        return;
 }
 
+
 void
-send_ldap_result(
+send_ldap_disconnect(
     Connection *conn,
     Operation  *op,
-    int                err,
-    char       *matched,
+    ber_int_t  err,
     char       *text
 )
 {
-#ifdef CLDAP
+       ber_tag_t tag;
+       ber_int_t msgid;
+       char *reqoid;
+
+#define LDAP_UNSOLICITED_ERROR(e) \
+       (  (e) == LDAP_PROTOCOL_ERROR \
+       || (e) == LDAP_STRONG_AUTH_REQUIRED \
+       || (e) == LDAP_UNAVAILABLE )
+
+       assert( LDAP_UNSOLICITED_ERROR( err ) );
+
+       Debug( LDAP_DEBUG_TRACE,
+               "send_ldap_disconnect %d:%s\n",
+               err, text ? text : "", NULL );
+
+       if ( op->o_protocol < LDAP_VERSION3 ) {
+               reqoid = NULL;
+               tag = req2res( op->o_tag );
+               msgid = (tag != LBER_SEQUENCE) ? op->o_msgid : 0;
+
+       } else {
+               reqoid = LDAP_NOTICE_DISCONNECT;
+               tag = LDAP_RES_EXTENDED;
+               msgid = 0;
+       }
+
+#ifdef LDAP_CONNECTIONLESS
        if ( op->o_cldap ) {
-               SAFEMEMCPY( (char *)conn->c_sb.sb_useaddr, &op->o_clientaddr,
-                   sizeof( struct sockaddr ));
+               ber_pvt_sb_udp_set_dst( &conn->c_sb, &op->o_clientaddr );
                Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", 
                    inet_ntoa(((struct sockaddr_in *)
-                   conn->c_sb.sb_useaddr)->sin_addr ),
-                   ((struct sockaddr_in *) conn->c_sb.sb_useaddr)->sin_port,
+                   &op->o_clientaddr)->sin_addr ),
+                   ((struct sockaddr_in *) &op->o_clientaddr)->sin_port,
                    0 );
        }
 #endif
-       send_ldap_result2( conn, op, err, matched, text, 0 );
+       send_ldap_response( conn, op, tag, msgid,
+               err, NULL, text, NULL,
+               reqoid, NULL );
+
+       Statslog( LDAP_DEBUG_STATS,
+           "conn=%ld op=%ld DISCONNECT err=%ld tag=%lu text=%s\n",
+               (long) conn->c_connid, (long) op->o_opid,
+               (long) tag, (long) err, text );
 }
 
 void
-send_ldap_search_result(
+send_ldap_result(
     Connection *conn,
     Operation  *op,
-    int                err,
+    ber_int_t  err,
     char       *matched,
     char       *text,
+       struct berval **ref
+)
+{
+       ber_tag_t tag;
+       ber_int_t msgid;
+       char *tmp = NULL;
+
+       assert( !LDAP_API_ERROR( err ) );
+
+       Debug( LDAP_DEBUG_TRACE, "send_ldap_result %d:%s:%s\n",
+               err, matched ?  matched : "", text ? text : "" );
+
+       assert( err != LDAP_PARTIAL_RESULTS );
+
+       if ( err == LDAP_REFERRAL ) {
+               if( ref == NULL ) {
+                       err = LDAP_NO_SUCH_OBJECT;
+               } else if ( op->o_protocol < LDAP_VERSION3 ) {
+                       err = LDAP_PARTIAL_RESULTS;
+                       tmp = text = v2ref( ref );
+                       ref = NULL;
+               }
+       }
+
+#ifdef LDAP_CONNECTIONLESS
+       if ( op->o_cldap ) {
+               ber_pvt_sb_udp_set_dst( &conn->c_sb, &op->o_clientaddr );
+               Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", 
+                   inet_ntoa(((struct sockaddr_in *)
+                   &op->o_clientaddr)->sin_addr ),
+                   ((struct sockaddr_in *) &op->o_clientaddr)->sin_port,
+                   0 );
+       }
+#endif
+
+       send_ldap_response( conn, op, tag, msgid,
+               err, matched, text, ref,
+               NULL, NULL );
+
+       Statslog( LDAP_DEBUG_STATS,
+           "conn=%ld op=%ld RESULT err=%ld tag=%lu text=%s\n",
+               (long) conn->c_connid, (long) op->o_opid,
+               (long) err, (long) tag, text );
+
+       if( tmp != NULL ) {
+               free(tmp);
+       }
+}
+
+
+void
+send_search_result(
+    Connection *conn,
+    Operation  *op,
+    ber_int_t  err,
+    char       *matched,
+       char    *text,
+    struct berval **refs,
     int                nentries
 )
 {
-       send_ldap_result2( conn, op, err, matched, text, nentries );
+       ber_tag_t tag;
+       ber_int_t msgid;
+       char *tmp = NULL;
+       assert( !LDAP_API_ERROR( err ) );
+
+       Debug( LDAP_DEBUG_TRACE, "send_ldap_search_result %d:%s:%s\n",
+               err, matched ?  matched : "", text ? text : "" );
+
+       assert( err != LDAP_PARTIAL_RESULTS );
+
+       if( op->o_protocol < LDAP_VERSION3 ) {
+               /* send references in search results */
+               if( err == LDAP_REFERRAL ) {
+                       err = LDAP_PARTIAL_RESULTS;
+                       tmp = text = v2ref( refs );
+                       refs = NULL;
+               }
+
+       } else {
+               /* don't send references in search results */
+               if( err == LDAP_REFERRAL ) {
+                       err = LDAP_SUCCESS;
+                       refs = NULL;
+               }
+       }
+
+#ifdef LDAP_CONNECTIONLESS
+       if ( op->o_cldap ) {
+               ber_pvt_sb_udp_set_dst( &conn->c_sb, &op->o_clientaddr );
+               Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", 
+                   inet_ntoa(((struct sockaddr_in *)
+                   &op->o_clientaddr)->sin_addr ),
+                   ((struct sockaddr_in *) &op->o_clientaddr)->sin_port,
+                   0 );
+       }
+#endif
+
+       send_ldap_response( conn, op, tag, msgid,
+               err, matched, text, refs,
+               NULL, NULL );
+
+       Statslog( LDAP_DEBUG_STATS,
+           "conn=%ld op=%ld SEARCH RESULT err=%ld tag=%lu text=%s\n",
+               (long) conn->c_connid, (long) op->o_opid,
+               (long) err, (long) tag, text );
+
 }
 
+
 int
 send_search_entry(
     Backend    *be,
@@ -185,179 +379,247 @@ send_search_entry(
     Operation  *op,
     Entry      *e,
     char       **attrs,
-    int                attrsonly
+    int                attrsonly,
+       int             opattrs
 )
 {
        BerElement      *ber;
        Attribute       *a;
-       int             i, rc, bytes, sd;
+       int             i, rc=-1, bytes;
        struct acl      *acl;
+       char            *edn;
 
        Debug( LDAP_DEBUG_TRACE, "=> send_search_entry (%s)\n", e->e_dn, 0, 0 );
 
-       if ( ! access_allowed( be, conn, op, e, "entry", NULL, op->o_dn,
-           ACL_READ ) ) {
+#if defined( SLAPD_SCHEMA_DN )
+       {
+               /* this could be backend specific */
+               struct  berval  val;
+               val.bv_val = SLAPD_SCHEMA_DN;
+               val.bv_len = strlen( val.bv_val );
+               attr_merge( e, "subschemaSubentry", vals );
+               ldap_memfree( val.bv_val );
+       }
+#endif
+
+       if ( ! access_allowed( be, conn, op, e,
+               "entry", NULL, ACL_READ ) )
+       {
                Debug( LDAP_DEBUG_ACL, "acl: access to entry not allowed\n",
                    0, 0, 0 );
                return( 1 );
        }
 
-#ifdef COMPAT30
-       if ( (ber = ber_alloc_t( conn->c_version == 30 ? 0 : LBER_USE_DER ))
-           == NULLBER ) {
-#else
-       if ( (ber = der_alloc()) == NULLBER ) {
-#endif
+       edn = e->e_ndn;
+
+       ber = ber_alloc_t( LBER_USE_DER );
+
+       if ( ber == NULL ) {
                Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 );
-               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL,
-                   "ber_alloc" );
-               return( 1 );
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
+                       NULL, "allocating BER error", NULL );
+               goto error_return;
        }
 
-#ifdef COMPAT30
-       if ( conn->c_version == 30 ) {
-               rc = ber_printf( ber, "{it{{s{", op->o_msgid,
-                   LDAP_RES_SEARCH_ENTRY, e->e_dn );
-       } else
-#endif
-               rc = ber_printf( ber, "{it{s{", op->o_msgid,
-                   LDAP_RES_SEARCH_ENTRY, e->e_dn );
+       rc = ber_printf( ber, "{it{s{", op->o_msgid,
+               LDAP_RES_SEARCH_ENTRY, e->e_dn );
 
        if ( rc == -1 ) {
                Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
                ber_free( ber, 1 );
-               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL,
-                   "ber_printf dn" );
-               return( 1 );
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
+                   NULL, "encoding dn error", NULL );
+               goto error_return;
        }
 
        for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
-               if ( attrs != NULL && ! charray_inlist( attrs, a->a_type ) ) {
-                       continue;
+               regmatch_t       matches[MAXREMATCHES];
+
+               if ( attrs == NULL ) {
+                       /* all addrs request, skip operational attributes */
+                       if( !opattrs && oc_check_operational_attr( a->a_type )) {
+                               continue;
+                       }
+
+               } else {
+                       /* specific addrs requested */
+                       if ( !charray_inlist( attrs, a->a_type )
+                               && !charray_inlist( attrs, LDAP_ALL_USER_ATTRIBUTES ) )
+                       {
+                               continue;
+                       }
                }
 
-               acl = acl_get_applicable( be, op, e, a->a_type );
+               acl = acl_get_applicable( be, op, e, a->a_type,
+                       MAXREMATCHES, matches );
 
-               if ( ! acl_access_allowed( acl, be, conn, e, NULL, op,
-                   ACL_READ ) ) {
+               if ( ! acl_access_allowed( acl, be, conn, e,
+                       NULL, op, ACL_READ, edn, matches ) ) 
+               {
                        continue;
                }
 
-               if ( ber_printf( ber, "{s[", a->a_type ) == -1 ) {
+               if (( rc = ber_printf( ber, "{s[" /*]}*/ , a->a_type )) == -1 ) {
                        Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
                        ber_free( ber, 1 );
                        send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
-                           NULL, "ber_printf type" );
-                       return( 1 );
+                           NULL, "encoding type error", NULL );
+                       goto error_return;
                }
 
                if ( ! attrsonly ) {
                        for ( i = 0; a->a_vals[i] != NULL; i++ ) {
-                               if ( a->a_syntax & SYNTAX_DN &&
-                                   ! acl_access_allowed( acl, be, conn, e,
-                                   a->a_vals[i], op, ACL_READ ) )
+                               if ( a->a_syntax & SYNTAX_DN && 
+                                       ! acl_access_allowed( acl, be, conn, e, a->a_vals[i], op,
+                                               ACL_READ, edn, matches) )
                                {
                                        continue;
                                }
 
-                               if ( ber_printf( ber, "o",
-                                   a->a_vals[i]->bv_val,
-                                   a->a_vals[i]->bv_len ) == -1 )
-                               {
+                               if (( rc = ber_printf( ber, "O", a->a_vals[i] )) == -1 ) {
                                        Debug( LDAP_DEBUG_ANY,
                                            "ber_printf failed\n", 0, 0, 0 );
                                        ber_free( ber, 1 );
-                                       send_ldap_result( conn, op,
-                                           LDAP_OPERATIONS_ERROR, NULL,
-                                           "ber_printf value" );
-                                       return( 1 );
+                                       send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
+                                               NULL, "encoding value error", NULL );
+                                       goto error_return;
                                }
                        }
                }
 
-               if ( ber_printf( ber, "]}" ) == -1 ) {
+               if (( rc = ber_printf( ber, /*{[*/ "]}" )) == -1 ) {
                        Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
                        ber_free( ber, 1 );
                        send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
-                           NULL, "ber_printf type end" );
-                       return( 1 );
+                           NULL, "encode end error", NULL );
+                       goto error_return;
                }
        }
 
-#ifdef COMPAT30
-       if ( conn->c_version == 30 ) {
-               rc = ber_printf( ber, "}}}}" );
-       } else
-#endif
-               rc = ber_printf( ber, "}}}" );
+       rc = ber_printf( ber, /*{{{*/ "}}}" );
 
        if ( rc == -1 ) {
                Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
                ber_free( ber, 1 );
-               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL,
-                   "ber_printf entry end" );
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
+                       NULL, "encode entry end error", NULL );
                return( 1 );
        }
 
-       /* write only one pdu at a time - wait til it's our turn */
-       pthread_mutex_lock( &conn->c_pdumutex );
+       bytes = send_ldap_ber( conn, ber );
 
-       bytes = ber->ber_ptr - ber->ber_buf;
-       pthread_mutex_lock( &new_conn_mutex );
-       while ( conn->c_connid == op->o_connid && ber_flush( &conn->c_sb, ber,
-           1 ) != 0 ) {
-               pthread_mutex_unlock( &new_conn_mutex );
-               /*
-                * we got an error.  if it's ewouldblock, we need to
-                * wait on the socket being writable.  otherwise, figure
-                * it's a hard error and return.
-                */
+       if ( bytes < 0 ) {
+               Debug( LDAP_DEBUG_ANY,
+                       "send_ldap_response: ber write failed\n",
+                       0, 0, 0 );
+               return -1;
+       }
 
-               Debug( LDAP_DEBUG_CONNS, "ber_flush failed errno %d msg (%s)\n",
-                   errno, errno > -1 && errno < sys_nerr ? sys_errlist[errno]
-                   : "unknown", 0 );
+       ldap_pvt_thread_mutex_lock( &num_sent_mutex );
+       num_bytes_sent += bytes;
+       num_entries_sent++;
+       num_pdu_sent++;
+       ldap_pvt_thread_mutex_unlock( &num_sent_mutex );
 
-               if ( errno != EWOULDBLOCK && errno != EAGAIN ) {
-                       close_connection( conn, op->o_connid, op->o_opid );
+       Statslog( LDAP_DEBUG_STATS2, "conn=%ld op=%ld ENTRY dn=\"%s\"\n",
+           (long) conn->c_connid, (long) op->o_opid, e->e_dn, 0, 0 );
 
-                       pthread_mutex_unlock( &conn->c_pdumutex );
-                       return( -1 );
+       Debug( LDAP_DEBUG_TRACE, "<= send_search_entry\n", 0, 0, 0 );
+
+       rc = 0;
+
+error_return:;
+       return( rc );
+}
+
+int
+send_search_reference(
+    Backend    *be,
+    Connection *conn,
+    Operation  *op,
+    Entry      *e,
+       struct berval **refs,
+    struct berval ***v2refs
+)
+{
+       BerElement      *ber;
+       int rc;
+       int bytes;
+
+       Debug( LDAP_DEBUG_TRACE, "=> send_search_entry (%s)\n", e->e_dn, 0, 0 );
+
+       if ( ! access_allowed( be, conn, op, e,
+               "entry", NULL, ACL_READ ) )
+       {
+               Debug( LDAP_DEBUG_ACL,
+                       "send_search_reference: access to entry not allowed\n",
+                   0, 0, 0 );
+               return( 1 );
+       }
+
+       if ( ! access_allowed( be, conn, op, e,
+               "ref", NULL, ACL_READ ) )
+       {
+               Debug( LDAP_DEBUG_ACL,
+                       "send_search_reference: access to reference not allowed\n",
+                   0, 0, 0 );
+               return( 1 );
+       }
+
+       if( refs == NULL ) {
+               Debug( LDAP_DEBUG_ANY,
+                       "send_search_reference: null ref in (%s)\n", 
+                       e->e_dn, 0, 0 );
+               return( 1 );
+       }
+
+       if( op->o_protocol < LDAP_VERSION3 ) {
+               /* save the references for the result */
+               if( *refs == NULL ) {
+                       value_add( v2refs, refs );
                }
+               return 0;
+       }
 
-               /* wait for socket to be write-ready */
-               pthread_mutex_lock( &active_threads_mutex );
-               active_threads--;
-               conn->c_writewaiter = 1;
-               pthread_kill( listener_tid, SIGUSR1 );
-               pthread_cond_wait( &conn->c_wcv, &active_threads_mutex );
-               pthread_mutex_unlock( &active_threads_mutex );
+       ber = ber_alloc_t( LBER_USE_DER );
 
-               pthread_yield();
-               pthread_mutex_lock( &new_conn_mutex );
+       if ( ber == NULL ) {
+               Debug( LDAP_DEBUG_ANY,
+                       "send_search_reference: ber_alloc failed\n", 0, 0, 0 );
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
+                       NULL, "alloc BER error", NULL );
+               return -1;
        }
-       pthread_mutex_unlock( &new_conn_mutex );
-       pthread_mutex_unlock( &conn->c_pdumutex );
 
-       pthread_mutex_lock( &num_sent_mutex );
-       num_bytes_sent += bytes;
-       num_entries_sent++;
-       pthread_mutex_unlock( &num_sent_mutex );
+       rc = ber_printf( ber, "{it{V}}", op->o_msgid,
+               LDAP_RES_SEARCH_REFERENCE, refs );
 
-       pthread_mutex_lock( &new_conn_mutex );
-       if ( conn->c_connid == op->o_connid ) {
-               rc = 0;
-               Statslog( LDAP_DEBUG_STATS2, "conn=%d op=%d ENTRY dn=\"%s\"\n",
-                   conn->c_connid, op->o_opid, e->e_dn, 0, 0 );
-       } else {
-               rc = -1;
+       if ( rc == -1 ) {
+               Debug( LDAP_DEBUG_ANY,
+                       "send_search_reference: ber_printf failed\n", 0, 0, 0 );
+               ber_free( ber, 1 );
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
+                       NULL, "encode dn error", NULL );
+               return -1;
        }
-       pthread_mutex_unlock( &new_conn_mutex );
+
+       bytes = send_ldap_ber( conn, ber );
+
+       ldap_pvt_thread_mutex_lock( &num_sent_mutex );
+       num_bytes_sent += bytes;
+       num_refs_sent++;
+       num_pdu_sent++;
+       ldap_pvt_thread_mutex_unlock( &num_sent_mutex );
+
+       Statslog( LDAP_DEBUG_STATS2, "conn=%ld op=%ld ENTRY dn=\"%s\"\n",
+           (long) conn->c_connid, (long) op->o_opid, e->e_dn, 0, 0 );
 
        Debug( LDAP_DEBUG_TRACE, "<= send_search_entry\n", 0, 0, 0 );
 
-       return( rc );
+       return 0;
 }
 
+
 int
 str2result(
     char       *s,
@@ -411,24 +673,3 @@ str2result(
 
        return( rc );
 }
-
-/*
- * close_connection - close a connection. takes the connection to close,
- * the connid associated with the operation generating the close (so we
- * don't accidentally close a connection that's not ours), and the opid
- * of the operation generating the close (for logging purposes).
- */
-void
-close_connection( Connection *conn, int opconnid, int opid )
-{
-       pthread_mutex_lock( &new_conn_mutex );
-       if ( conn->c_sb.sb_sd != -1 && conn->c_connid == opconnid ) {
-               Statslog( LDAP_DEBUG_STATS,
-                   "conn=%d op=%d fd=%d closed errno=%d\n", conn->c_connid,
-                   opid, conn->c_sb.sb_sd, errno, 0 );
-               close( conn->c_sb.sb_sd );
-               conn->c_sb.sb_sd = -1;
-               conn->c_version = 0;
-       }
-       pthread_mutex_unlock( &new_conn_mutex );
-}
diff --git a/servers/slapd/root_dse.c b/servers/slapd/root_dse.c
new file mode 100644 (file)
index 0000000..edb655c
--- /dev/null
@@ -0,0 +1,105 @@
+/* root_dse.c - Provides the ROOT DSA-Specific Entry
+ *
+ * Copyright 1999 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms 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.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include "ldap_defaults.h"
+#include "slap.h"
+
+void
+root_dse_info( Connection *conn, Operation *op, char **attrs, int attrsonly )
+{
+       char buf[BUFSIZ];
+       Entry           *e;
+       struct berval   val;
+       struct berval   *vals[2];
+       int             i, j;
+
+       vals[0] = &val;
+       vals[1] = NULL;
+
+       e = (Entry *) ch_calloc( 1, sizeof(Entry) );
+
+       e->e_attrs = NULL;
+       e->e_dn = ch_strdup( LDAP_ROOT_DSE );
+       e->e_ndn = dn_normalize_case( ch_strdup( LDAP_ROOT_DSE ));
+       e->e_private = NULL;
+
+       for ( i = 0; i < nbackends; i++ ) {
+               for ( j = 0; backends[i].be_suffix[j] != NULL; j++ ) {
+                       val.bv_val = backends[i].be_suffix[j];
+                       val.bv_len = strlen( val.bv_val );
+                       attr_merge( e, "namingContexts", vals );
+               }
+       }
+
+#if defined( SLAPD_MONITOR_DN )
+       val.bv_val = SLAPD_MONITOR_DN;
+       val.bv_len = strlen( val.bv_val );
+       attr_merge( e, "namingContexts", vals );
+       /* subschemasubentry is added by send_search_entry() */
+#endif
+
+#if defined( SLAPD_CONFIG_DN )
+       val.bv_val = SLAPD_CONFIG_DN;
+       val.bv_len = strlen( val.bv_val );
+       attr_merge( e, "namingContexts", vals );
+#endif
+
+#if defined( SLAPD_SCHEMA_DN )
+       val.bv_val = SLAPD_SCHEMA_DN;
+       val.bv_len = strlen( val.bv_val );
+       attr_merge( e, "namingContexts", vals );
+#endif
+
+       /* altServer unsupported */
+
+       /* supportedControl */
+       for ( i=0; supportedControls[i] != NULL; i++ ) {
+               val.bv_val = supportedControls[i];
+               val.bv_len = strlen( val.bv_val );
+               attr_merge( e, "supportedControl", vals );
+       }
+
+       /* supportedExtension */
+       for ( i=0; supportedExtensions[i] != NULL; i++ ) {
+               val.bv_val = supportedExtensions[i];
+               val.bv_len = strlen( val.bv_val );
+               attr_merge( e, "supportedExtension", vals );
+       }
+
+       /* supportedLDAPVersion */
+       for ( i=LDAP_VERSION_MIN; i<=LDAP_VERSION_MAX; i++ ) {
+               sprintf(buf,"%d",i);
+               val.bv_val = buf;
+               val.bv_len = strlen( val.bv_val );
+               attr_merge( e, "supportedLDAPVersion", vals );
+       }
+
+       /* supportedSASLMechanism */
+       for ( i=0; supportedSASLMechanisms[i] != NULL; i++ ) {
+               val.bv_val = supportedSASLMechanisms[i];
+               val.bv_len = strlen( val.bv_val );
+               attr_merge( e, "supportedSASLMechanism", vals );
+       }
+
+       if ( default_referral != NULL ) {
+               attr_merge( e, "ref", default_referral );
+       }
+
+       send_search_entry( &backends[0], conn, op, e, attrs, attrsonly, 1 );
+       send_search_result( conn, op, LDAP_SUCCESS, NULL, NULL, NULL, 1 );
+
+       entry_free( e );
+}
+
index ba16d9b0f13540041d9b221fcc4db4888f99a794..fc2ce4188c59dbe851a62c77562bb3cd8af49e19 100644 (file)
@@ -1,21 +1,18 @@
 /* schema.c - routines to enforce schema definitions */
 
+#include "portable.h"
+
 #include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include "slap.h"
 
-extern Attribute       *attr_find();
-extern char            **str2charray();
-extern void            charray_merge();
+#include <ac/ctype.h>
+#include <ac/string.h>
+#include <ac/socket.h>
 
-extern struct objclass *global_oc;
-extern int             global_schemacheck;
+#include "ldap_defaults.h"
+#include "slap.h"
 
-static struct objclass *oc_find();
-static int             oc_check_required();
-static int             oc_check_allowed();
+static char *  oc_check_required(Entry *e, char *ocname);
+static int             oc_check_allowed(char *type, struct berval **ocl);
 
 /*
  * oc_check - check that entry e conforms to the schema required by
@@ -26,7 +23,6 @@ int
 oc_schema_check( Entry *e )
 {
        Attribute       *a, *aoc;
-       struct objclass *oc;
        int             i;
        int             ret = 0;
 
@@ -34,15 +30,17 @@ oc_schema_check( Entry *e )
        if ( (aoc = attr_find( e->e_attrs, "objectclass" )) == NULL ) {
                Debug( LDAP_DEBUG_ANY, "No object class for entry (%s)\n",
                    e->e_dn, 0, 0 );
-               return( 0 );
+               return( 1 );
        }
 
        /* check that the entry has required attrs for each oc */
        for ( i = 0; aoc->a_vals[i] != NULL; i++ ) {
-               if ( oc_check_required( e, aoc->a_vals[i]->bv_val ) != 0 ) {
+               char *s = oc_check_required( e, aoc->a_vals[i]->bv_val );
+
+               if (s != NULL) {
                        Debug( LDAP_DEBUG_ANY,
-                           "Entry (%s), required attr (%s) missing\n",
-                           e->e_dn, aoc->a_vals[i]->bv_val, 0 );
+                           "Entry (%s), oc \"%s\" requires attr \"%s\"\n",
+                           e->e_dn, aoc->a_vals[i]->bv_val, s );
                        ret = 1;
                }
        }
@@ -55,7 +53,7 @@ oc_schema_check( Entry *e )
        for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
                if ( oc_check_allowed( a->a_type, aoc->a_vals ) != 0 ) {
                        Debug( LDAP_DEBUG_ANY,
-                           "Entry (%s), attr (%s) not allowed\n",
+                           "Entry (%s), attr \"%s\" not allowed\n",
                            e->e_dn, a->a_type, 0 );
                        ret = 1;
                }
@@ -64,67 +62,204 @@ oc_schema_check( Entry *e )
        return( ret );
 }
 
-static int
+static char *
 oc_check_required( Entry *e, char *ocname )
 {
-       struct objclass *oc;
+       ObjectClass     *oc;
+       AttributeType   *at;
        int             i;
        Attribute       *a;
+       char            **pp;
+
+       Debug( LDAP_DEBUG_TRACE,
+              "oc_check_required entry (%s), objectclass \"%s\"\n",
+              e->e_dn, ocname, 0 );
 
        /* find global oc defn. it we don't know about it assume it's ok */
        if ( (oc = oc_find( ocname )) == NULL ) {
                return( 0 );
        }
 
+       /* check for empty oc_required */
+       if(oc->soc_required == NULL) {
+               return( 0 );
+       }
+
        /* for each required attribute */
-       for ( i = 0; oc->oc_required[i] != NULL; i++ ) {
+       for ( i = 0; oc->soc_required[i] != NULL; i++ ) {
+               at = oc->soc_required[i];
                /* see if it's in the entry */
                for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
-                       if ( strcasecmp( a->a_type, oc->oc_required[i] )
-                           == 0 ) {
+                       if ( at->sat_oid &&
+                            strcmp( a->a_type, at->sat_oid ) == 0 ) {
+                               break;
+                       }
+                       pp = at->sat_names;
+                       if ( pp  == NULL ) {
+                               /* Empty name list => not found */
+                               a = NULL;
+                               break;
+                       }
+                       while ( *pp ) {
+                               if ( strcasecmp( a->a_type, *pp ) == 0 ) {
+                                       break;
+                               }
+                               pp++;
+                       }
+                       if ( *pp ) {
                                break;
                        }
                }
-
                /* not there => schema violation */
                if ( a == NULL ) {
-                       return( 1 );
+                       if ( at->sat_names && at->sat_names[0] ) {
+                               return at->sat_names[0];
+                       } else {
+                               return at->sat_oid;
+                       }
                }
        }
 
-       return( 0 );
+       return( NULL );
+}
+
+static char *oc_usermod_attrs[] = {
+       /*
+        * OpenLDAP doesn't support any user modification of
+        * operational attributes.
+        */
+       NULL
+};
+
+static char *oc_operational_attrs[] = {
+       /*
+        * these are operational attributes that *could* be
+        * modified by users if we supported such.
+        */
+       "objectClasses",
+       "attributeTypes",
+       "matchingRules",
+       "matchingRuleUse",
+       "dITStructureRules",
+       "dITContentRules",
+       "nameForms",
+       "ldapSyntaxes",
+       NULL
+
+};
+
+/* this list should be extensible  */
+static char *oc_no_usermod_attrs[] = {
+       /*
+        * Operational and 'no user modification' attributes
+        */
+
+       /* RFC2252, 3.2.1 */
+       "creatorsName",
+       "createTimestamp",
+       "modifiersName",
+       "modifyTimestamp",
+       "subschemaSubentry",
+
+       NULL
+};
+
+
+/*
+ * check to see if attribute is 'operational' or not.
+ */
+int
+oc_check_operational_attr( char *type )
+{
+       return charray_inlist( oc_operational_attrs, type )
+               || charray_inlist( oc_usermod_attrs, type )
+               || charray_inlist( oc_no_usermod_attrs, type );
+}
+
+/*
+ * check to see if attribute can be user modified or not.
+ */
+int
+oc_check_usermod_attr( char *type )
+{
+       return charray_inlist( oc_usermod_attrs, type );
+}
+
+/*
+ * check to see if attribute is 'no user modification' or not.
+ */
+int
+oc_check_no_usermod_attr( char *type )
+{
+       return charray_inlist( oc_no_usermod_attrs, type );
 }
 
+
 static int
 oc_check_allowed( char *type, struct berval **ocl )
 {
-       struct objclass *oc;
+       ObjectClass     *oc;
+       AttributeType   *at;
        int             i, j;
+       char            **pp;
+
+       Debug( LDAP_DEBUG_TRACE,
+              "oc_check_allowed type \"%s\"\n", type, 0, 0 );
 
        /* always allow objectclass attribute */
        if ( strcasecmp( type, "objectclass" ) == 0 ) {
                return( 0 );
        }
 
+       /*
+        * All operational attributions are allowed by schema rules.
+        * However, we only check attributions which are stored in the
+        * the directory regardless if they are user or non-user modified.
+        */
+       if ( oc_check_usermod_attr( type ) || oc_check_no_usermod_attr( type ) ) {
+               return( 0 );
+       }
+
        /* check that the type appears as req or opt in at least one oc */
        for ( i = 0; ocl[i] != NULL; i++ ) {
                /* if we know about the oc */
                if ( (oc = oc_find( ocl[i]->bv_val )) != NULL ) {
                        /* does it require the type? */
-                       for ( j = 0; oc->oc_required[j] != NULL; j++ ) {
-                               if ( strcasecmp( oc->oc_required[j], type )
-                                   == 0 ) {
+                       for ( j = 0; oc->soc_required != NULL && 
+                               oc->soc_required[j] != NULL; j++ ) {
+                               at = oc->soc_required[j];
+                               if ( at->sat_oid &&
+                                    strcmp(at->sat_oid, type ) == 0 ) {
                                        return( 0 );
                                }
+                               pp = at->sat_names;
+                               if ( pp == NULL )
+                                       continue;
+                               while ( *pp ) {
+                                       if ( strcasecmp( *pp, type ) == 0 ) {
+                                               return( 0 );
+                                       }
+                                       pp++;
+                               }
                        }
                        /* does it allow the type? */
-                       for ( j = 0; oc->oc_allowed[j] != NULL; j++ ) {
-                               if ( strcasecmp( oc->oc_allowed[j], type )
-                                   == 0 || strcmp( oc->oc_allowed[j], "*" )
-                                   == 0 )
-                               {
+                       for ( j = 0; oc->soc_allowed != NULL && 
+                               oc->soc_allowed[j] != NULL; j++ ) {
+                               at = oc->soc_allowed[j];
+                               if ( at->sat_oid &&
+                                    strcmp(at->sat_oid, type ) == 0 ) {
                                        return( 0 );
                                }
+                               pp = at->sat_names;
+                               if ( pp == NULL )
+                                       continue;
+                               while ( *pp ) {
+                                       if ( strcasecmp( *pp, type ) == 0 ||
+                                            strcmp( *pp, "*" ) == 0 ) {
+                                               return( 0 );
+                                       }
+                                       pp++;
+                               }
                        }
                        /* maybe the next oc allows it */
 
@@ -138,39 +273,906 @@ oc_check_allowed( char *type, struct berval **ocl )
        return( 1 );
 }
 
-static struct objclass *
-oc_find( char *ocname )
+struct oindexrec {
+       char            *oir_name;
+       ObjectClass     *oir_oc;
+};
+
+static Avlnode *oc_index = NULL;
+static ObjectClass *oc_list = NULL;
+
+static int
+oc_index_cmp(
+    struct oindexrec   *oir1,
+    struct oindexrec   *oir2
+)
+{
+       return (strcasecmp( oir1->oir_name, oir2->oir_name ));
+}
+
+static int
+oc_index_name_cmp(
+    char               *name,
+    struct oindexrec   *oir
+)
+{
+       return (strcasecmp( name, oir->oir_name ));
+}
+
+ObjectClass *
+oc_find( const char *ocname )
+{
+       struct oindexrec        *oir = NULL;
+
+       if ( (oir = (struct oindexrec *) avl_find( oc_index, ocname,
+            (AVL_CMP) oc_index_name_cmp )) != NULL ) {
+               return( oir->oir_oc );
+       }
+       return( NULL );
+}
+
+static int
+oc_create_required(
+    ObjectClass                *soc,
+    char               **attrs,
+    const char         **err
+)
 {
-       struct objclass *oc;
+       char            **attrs1;
+       AttributeType   *sat;
+       AttributeType   **satp;
+       int             i;
 
-       for ( oc = global_oc; oc != NULL; oc = oc->oc_next ) {
-               if ( strcasecmp( oc->oc_name, ocname ) == 0 ) {
-                       return( oc );
+       if ( attrs ) {
+               attrs1 = attrs;
+               while ( *attrs1 ) {
+                       sat = at_find(*attrs1);
+                       if ( !sat ) {
+                               *err = *attrs1;
+                               return SLAP_SCHERR_ATTR_NOT_FOUND;
+                       }
+                       if ( at_find_in_list(sat, soc->soc_required) < 0) {
+                               if ( at_append_to_list(sat, &soc->soc_required) ) {
+                                       *err = *attrs1;
+                                       return SLAP_SCHERR_OUTOFMEM;
+                               }
+                       }
+                       attrs1++;
+               }
+               /* Now delete duplicates from the allowed list */
+               for ( satp = soc->soc_required; *satp; satp++ ) {
+                       i = at_find_in_list(*satp,soc->soc_allowed);
+                       if ( i >= 0 ) {
+                               at_delete_from_list(i, &soc->soc_allowed);
+                       }
+               }
+       }
+       return 0;
+}
+
+static int
+oc_create_allowed(
+    ObjectClass                *soc,
+    char               **attrs,
+    const char         **err
+)
+{
+       char            **attrs1;
+       AttributeType   *sat;
+
+       if ( attrs ) {
+               attrs1 = attrs;
+               while ( *attrs1 ) {
+                       sat = at_find(*attrs1);
+                       if ( !sat ) {
+                               *err = *attrs1;
+                               return SLAP_SCHERR_ATTR_NOT_FOUND;
+                       }
+                       if ( at_find_in_list(sat, soc->soc_required) < 0 &&
+                            at_find_in_list(sat, soc->soc_allowed) < 0 ) {
+                               if ( at_append_to_list(sat, &soc->soc_allowed) ) {
+                                       *err = *attrs1;
+                                       return SLAP_SCHERR_OUTOFMEM;
+                               }
+                       }
+                       attrs1++;
+               }
+       }
+       return 0;
+}
+
+static int
+oc_add_sups(
+    ObjectClass                *soc,
+    char               **sups,
+    const char         **err
+)
+{
+       int             code;
+       ObjectClass     *soc1;
+       int             nsups;
+       char            **sups1;
+       int             add_sups = 0;
+
+       if ( sups ) {
+               if ( !soc->soc_sups ) {
+                       /* We are at the first recursive level */
+                       add_sups = 1;
+                       nsups = 0;
+                       sups1 = sups;
+                       while ( *sups1 ) {
+                               nsups++;
+                               sups1++;
+                       }
+                       nsups++;
+                       soc->soc_sups = (ObjectClass **)ch_calloc(1,
+                                         nsups*sizeof(ObjectClass *));
                }
+               nsups = 0;
+               sups1 = sups;
+               while ( *sups1 ) {
+                       soc1 = oc_find(*sups1);
+                       if ( !soc1 ) {
+                               *err = *sups1;
+                               return SLAP_SCHERR_CLASS_NOT_FOUND;
+                       }
+
+                       if ( add_sups )
+                               soc->soc_sups[nsups] = soc1;
+
+                       code = oc_add_sups(soc,soc1->soc_sup_oids, err);
+                       if ( code )
+                               return code;
+                       
+                       if ( code = oc_create_required(soc,
+                               soc1->soc_at_oids_must,err) )
+                               return code;
+                       if ( code = oc_create_allowed(soc,
+                               soc1->soc_at_oids_may,err) )
+                               return code;
+                       nsups++;
+                       sups1++;
+               }
+       }
+       return 0;
+}
+
+static int
+oc_insert(
+    ObjectClass                *soc,
+    const char         **err
+)
+{
+       ObjectClass     **ocp;
+       struct oindexrec        *oir;
+       char                    **names;
+
+       ocp = &oc_list;
+       while ( *ocp != NULL ) {
+               ocp = &(*ocp)->soc_next;
        }
+       *ocp = soc;
 
+       if ( soc->soc_oid ) {
+               oir = (struct oindexrec *)
+                       ch_calloc( 1, sizeof(struct oindexrec) );
+               oir->oir_name = soc->soc_oid;
+               oir->oir_oc = soc;
+               if ( avl_insert( &oc_index, (caddr_t) oir,
+                                (AVL_CMP) oc_index_cmp,
+                                (AVL_DUP) avl_dup_error ) ) {
+                       *err = soc->soc_oid;
+                       ldap_memfree(oir);
+                       return SLAP_SCHERR_DUP_CLASS;
+               }
+               /* FIX: temporal consistency check */
+               oc_find(oir->oir_name);
+       }
+       if ( (names = soc->soc_names) ) {
+               while ( *names ) {
+                       oir = (struct oindexrec *)
+                               ch_calloc( 1, sizeof(struct oindexrec) );
+                       oir->oir_name = ch_strdup(*names);
+                       oir->oir_oc = soc;
+                       if ( avl_insert( &oc_index, (caddr_t) oir,
+                                        (AVL_CMP) oc_index_cmp,
+                                        (AVL_DUP) avl_dup_error ) ) {
+                               *err = *names;
+                               ldap_memfree(oir);
+                               return SLAP_SCHERR_DUP_CLASS;
+                       }
+                       /* FIX: temporal consistency check */
+                       oc_find(oir->oir_name);
+                       names++;
+               }
+       }
+       return 0;
+}
+
+int
+oc_add(
+    LDAP_OBJECT_CLASS  *oc,
+    const char         **err
+)
+{
+       ObjectClass     *soc;
+       int             code;
+
+       soc = (ObjectClass *) ch_calloc( 1, sizeof(ObjectClass) );
+       memcpy( &soc->soc_oclass, oc, sizeof(LDAP_OBJECT_CLASS));
+       if ( code = oc_add_sups(soc,soc->soc_sup_oids,err) )
+               return code;
+       if ( code = oc_create_required(soc,soc->soc_at_oids_must,err) )
+               return code;
+       if ( code = oc_create_allowed(soc,soc->soc_at_oids_may,err) )
+               return code;
+       code = oc_insert(soc,err);
+       return code;
+}
+
+struct sindexrec {
+       char            *sir_name;
+       Syntax          *sir_syn;
+};
+
+static Avlnode *syn_index = NULL;
+static Syntax *syn_list = NULL;
+
+static int
+syn_index_cmp(
+    struct sindexrec   *sir1,
+    struct sindexrec   *sir2
+)
+{
+       return (strcmp( sir1->sir_name, sir2->sir_name ));
+}
+
+static int
+syn_index_name_cmp(
+    char               *name,
+    struct sindexrec   *sir
+)
+{
+       return (strcmp( name, sir->sir_name ));
+}
+
+Syntax *
+syn_find( const char *synname )
+{
+       struct sindexrec        *sir = NULL;
+
+       if ( (sir = (struct sindexrec *) avl_find( syn_index, synname,
+            (AVL_CMP) syn_index_name_cmp )) != NULL ) {
+               return( sir->sir_syn );
+       }
        return( NULL );
 }
 
+static int
+syn_insert(
+    Syntax             *ssyn,
+    const char         **err
+)
+{
+       Syntax          **synp;
+       struct sindexrec        *sir;
+
+       synp = &syn_list;
+       while ( *synp != NULL ) {
+               synp = &(*synp)->ssyn_next;
+       }
+       *synp = ssyn;
+
+       if ( ssyn->ssyn_oid ) {
+               sir = (struct sindexrec *)
+                       ch_calloc( 1, sizeof(struct sindexrec) );
+               sir->sir_name = ssyn->ssyn_oid;
+               sir->sir_syn = ssyn;
+               if ( avl_insert( &syn_index, (caddr_t) sir,
+                                (AVL_CMP) syn_index_cmp,
+                                (AVL_DUP) avl_dup_error ) ) {
+                       *err = ssyn->ssyn_oid;
+                       ldap_memfree(sir);
+                       return SLAP_SCHERR_DUP_SYNTAX;
+               }
+               /* FIX: temporal consistency check */
+               syn_find(sir->sir_name);
+       }
+       return 0;
+}
+
+int
+syn_add(
+    LDAP_SYNTAX                *syn,
+    slap_syntax_check_func     *check,
+    const char         **err
+)
+{
+       Syntax          *ssyn;
+       int             code;
+
+       ssyn = (Syntax *) ch_calloc( 1, sizeof(Syntax) );
+       memcpy( &ssyn->ssyn_syn, syn, sizeof(LDAP_SYNTAX));
+       ssyn->ssyn_check = check;
+       code = syn_insert(ssyn,err);
+       return code;
+}
+
+struct mindexrec {
+       char            *mir_name;
+       MatchingRule    *mir_mr;
+};
+
+static Avlnode *mr_index = NULL;
+static MatchingRule *mr_list = NULL;
+
+static int
+mr_index_cmp(
+    struct mindexrec   *mir1,
+    struct mindexrec   *mir2
+)
+{
+       return (strcmp( mir1->mir_name, mir2->mir_name ));
+}
+
+static int
+mr_index_name_cmp(
+    char               *name,
+    struct mindexrec   *mir
+)
+{
+       return (strcmp( name, mir->mir_name ));
+}
+
+MatchingRule *
+mr_find( const char *mrname )
+{
+       struct mindexrec        *mir = NULL;
+
+       if ( (mir = (struct mindexrec *) avl_find( mr_index, mrname,
+            (AVL_CMP) mr_index_name_cmp )) != NULL ) {
+               return( mir->mir_mr );
+       }
+       return( NULL );
+}
+
+static int
+mr_insert(
+    MatchingRule       *smr,
+    const char         **err
+)
+{
+       MatchingRule            **mrp;
+       struct mindexrec        *mir;
+       char                    **names;
+
+       mrp = &mr_list;
+       while ( *mrp != NULL ) {
+               mrp = &(*mrp)->smr_next;
+       }
+       *mrp = smr;
+
+       if ( smr->smr_oid ) {
+               mir = (struct mindexrec *)
+                       ch_calloc( 1, sizeof(struct mindexrec) );
+               mir->mir_name = smr->smr_oid;
+               mir->mir_mr = smr;
+               if ( avl_insert( &mr_index, (caddr_t) mir,
+                                (AVL_CMP) mr_index_cmp,
+                                (AVL_DUP) avl_dup_error ) ) {
+                       *err = smr->smr_oid;
+                       ldap_memfree(mir);
+                       return SLAP_SCHERR_DUP_RULE;
+               }
+               /* FIX: temporal consistency check */
+               mr_find(mir->mir_name);
+       }
+       if ( (names = smr->smr_names) ) {
+               while ( *names ) {
+                       mir = (struct mindexrec *)
+                               ch_calloc( 1, sizeof(struct mindexrec) );
+                       mir->mir_name = ch_strdup(*names);
+                       mir->mir_mr = smr;
+                       if ( avl_insert( &mr_index, (caddr_t) mir,
+                                        (AVL_CMP) mr_index_cmp,
+                                        (AVL_DUP) avl_dup_error ) ) {
+                               *err = *names;
+                               ldap_memfree(mir);
+                               return SLAP_SCHERR_DUP_RULE;
+                       }
+                       /* FIX: temporal consistency check */
+                       mr_find(mir->mir_name);
+                       names++;
+               }
+       }
+       return 0;
+}
+
+int
+mr_add(
+    LDAP_MATCHING_RULE         *mr,
+    slap_mr_normalize_func     *normalize,
+    slap_mr_compare_func       *compare,
+    const char         **err
+)
+{
+       MatchingRule    *smr;
+       Syntax          *syn;
+       int             code;
+
+       smr = (MatchingRule *) ch_calloc( 1, sizeof(MatchingRule) );
+       memcpy( &smr->smr_mrule, mr, sizeof(LDAP_MATCHING_RULE));
+       smr->smr_normalize = normalize;
+       smr->smr_compare = compare;
+       if ( smr->smr_syntax_oid ) {
+               if ( (syn = syn_find(smr->smr_syntax_oid)) ) {
+                       smr->smr_syntax = syn;
+               } else {
+                       *err = smr->smr_syntax_oid;
+                       return SLAP_SCHERR_SYN_NOT_FOUND;
+               }
+       } else {
+               *err = "";
+               return SLAP_SCHERR_MR_INCOMPLETE;
+       }
+       code = mr_insert(smr,err);
+       return code;
+}
+
+static int
+case_exact_normalize(
+       struct berval *val,
+       struct berval **normalized
+)
+{
+       struct berval *newval;
+       char *p, *q;
+
+       newval = ber_bvdup( val );
+       p = q = newval->bv_val;
+       /* Ignore initial whitespace */
+       while ( isspace( *p++ ) )
+               ;
+       while ( *p ) {
+               if ( isspace( *p ) ) {
+                       *q++ = *p++;
+                       /* Ignore the extra whitespace */
+                       while ( isspace(*p++) )
+                               ;
+               } else {
+                       *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 ( p != newval->bv_val && isspace( *(p-1) ) ) {
+               *(q-1) = '\0';
+       }
+       newval->bv_len = strlen( newval->bv_val );
+       normalized = &newval;
+
+       return 0;
+}
+
+static int
+case_exact_compare(
+       struct berval *val1,
+       struct berval *val2
+)
+{
+       return strcmp( val1->bv_val, val2->bv_val );
+}
+
+int
+case_ignore_normalize(
+       struct berval *val,
+       struct berval **normalized
+)
+{
+       struct berval *newval;
+       char *p, *q;
+
+       newval = ber_bvdup( val );
+       p = q = newval->bv_val;
+       /* Ignore initial whitespace */
+       while ( isspace( *p++ ) )
+               ;
+       while ( *p ) {
+               if ( isspace( *p ) ) {
+                       *q++ = *p++;
+                       /* Ignore the extra whitespace */
+                       while ( isspace(*p++) )
+                               ;
+               } else {
+                       *q++ = TOUPPER( *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 ( p != newval->bv_val && isspace( *(p-1) ) ) {
+               *(q-1) = '\0';
+       }
+       newval->bv_len = strlen( newval->bv_val );
+       normalized = &newval;
+
+       return 0;
+}
+
+static int
+case_ignore_compare(
+       struct berval *val1,
+       struct berval *val2
+)
+{
+       return strcasecmp( val1->bv_val, val2->bv_val );
+}
+
+int
+register_syntax(
+       char * desc,
+       slap_syntax_check_func *check )
+{
+       LDAP_SYNTAX     *syn;
+       int             code;
+       const char      *err;
+
+       syn = ldap_str2syntax( desc, &code, &err);
+       if ( !syn ) {
+               Debug( LDAP_DEBUG_ANY, "Error in register_syntax: %s before %s in %s\n",
+                   ldap_scherr2str(code), err, desc );
+               return( -1 );
+       }
+       code = syn_add( syn, check, &err );
+       if ( code ) {
+               Debug( LDAP_DEBUG_ANY, "Error in register_syntax: %s %s in %s\n",
+                   scherr2str(code), err, desc );
+               return( -1 );
+       }
+       return( 0 );
+}
+
+int
+register_matching_rule(
+       char * desc,
+       slap_mr_normalize_func *normalize,
+       slap_mr_compare_func *compare )
+{
+       LDAP_MATCHING_RULE *mr;
+       int             code;
+       const char      *err;
+
+       mr = ldap_str2matchingrule( desc, &code, &err);
+       if ( !mr ) {
+               Debug( LDAP_DEBUG_ANY, "Error in register_matching_rule: %s before %s in %s\n",
+                   ldap_scherr2str(code), err, desc );
+               return( -1 );
+       }
+       code = mr_add( mr, normalize, compare, &err );
+       if ( code ) {
+               Debug( LDAP_DEBUG_ANY, "Error in register_syntax: %s for %s in %s\n",
+                   scherr2str(code), err, desc );
+               return( -1 );
+       }
+       return( 0 );
+}
+
+struct syntax_defs_rec {
+       char *sd_desc;
+       slap_syntax_check_func *sd_check;
+};
+
+struct syntax_defs_rec syntax_defs[] = {
+       {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )", NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' )", NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' )", NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )", NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' )", NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' )", NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' )", NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'DN' )", NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )", NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )", NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )", NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )", NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )", NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )", NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )", NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )", NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )", NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'INTEGER' )", NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )", NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )", NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )", NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )", NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )", NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )", NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )", NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )", NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )", NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )", NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )", NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )", NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )", NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )", NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' )", NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )", NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )", NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )", NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )", NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )", NULL},
+       {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )", NULL},
+       {"( 1.3.6.1.1.1.0.0 DESC 'NIS netgroup triple' )", NULL},
+       {"( 1.3.6.1.1.1.0.1 DESC 'Boot parameter' )", NULL},
+       {NULL, NULL}
+};
+
+struct mrule_defs_rec {
+       char *mrd_desc;
+       slap_mr_normalize_func *mrd_normalize;
+       slap_mr_compare_func *mrd_compare;
+};
+
+/*
+ * Other matching rules in X.520 that we do not use:
+ *
+ * 2.5.13.9    numericStringOrderingMatch
+ * 2.5.13.12   caseIgnoreListSubstringsMatch
+ * 2.5.13.13   booleanMatch
+ * 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.34   certificateExactMatch
+ * 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
+ */
+
+struct mrule_defs_rec mrule_defs[] = {
+       {"( 2.5.13.0 NAME 'objectIdentifierMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )", NULL, NULL},
+       {"( 2.5.13.1 NAME 'distinguishedNameMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )", NULL, NULL},
+       {"( 2.5.13.2 NAME 'caseIgnoreMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
+        case_ignore_normalize, case_ignore_compare},
+       {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
+        case_ignore_normalize, case_ignore_compare},
+       {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
+        case_ignore_normalize, case_ignore_compare},
+       /* Next three are not in the RFC's, but are needed for compatibility */
+       {"( 2.5.13.5 NAME 'caseExactMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
+        case_exact_normalize, case_exact_compare},
+       {"( 2.5.13.6 NAME 'caseExactOrderingMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
+        case_exact_normalize, case_exact_compare},
+       {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
+        case_exact_normalize, case_exact_compare},
+       {"( 2.5.13.8 NAME 'numericStringMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )", NULL, NULL},
+       {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", NULL, NULL},
+       {"( 2.5.13.11 NAME 'caseIgnoreListMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )", NULL, NULL},
+       {"( 2.5.13.14 NAME 'integerMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", NULL, NULL},
+       {"( 2.5.13.16 NAME 'bitStringMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )", NULL, NULL},
+       {"( 2.5.13.17 NAME 'octetStringMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )", NULL, NULL},
+       {"( 2.5.13.20 NAME 'telephoneNumberMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )", NULL, NULL},
+       {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", NULL, NULL},
+       {"( 2.5.13.22 NAME 'presentationAddressMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )", NULL, NULL},
+       {"( 2.5.13.23 NAME 'uniqueMemberMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )", NULL, NULL},
+       {"( 2.5.13.24 NAME 'protocolInformationMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )", NULL, NULL},
+       {"( 2.5.13.27 NAME 'generalizedTimeMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )", NULL, NULL},
+       {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )", NULL, NULL},
+       {"( 2.5.13.29 NAME 'integerFirstComponentMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", NULL, NULL},
+       {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )", NULL, NULL},
+       {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
+        case_exact_normalize, case_exact_compare},
+       {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
+        case_ignore_normalize, case_ignore_compare},
+       {NULL, NULL, NULL}
+};
+
+int
+schema_init( void )
+{
+       int             res;
+       int             i;
+       static int      schema_init_done = 0;
+
+       /* We are called from read_config that is recursive */
+       if ( schema_init_done )
+               return( 0 );
+       for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
+               res = register_syntax( syntax_defs[i].sd_desc,
+                   syntax_defs[i].sd_check );
+               if ( res ) {
+                       fprintf( stderr, "schema_init: Error registering syntax %s\n",
+                                syntax_defs[i].sd_desc );
+                       exit( 1 );
+               }
+       }
+       for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
+               res = register_matching_rule( mrule_defs[i].mrd_desc,
+                   ( mrule_defs[i].mrd_normalize ?
+                     mrule_defs[i].mrd_normalize : case_ignore_normalize ),
+                   ( mrule_defs[i].mrd_compare ?
+                     mrule_defs[i].mrd_compare : case_ignore_compare ) );
+               if ( res ) {
+                       fprintf( stderr, "schema_init: Error registering matching rule %s\n",
+                                mrule_defs[i].mrd_desc );
+                       exit( 1 );
+               }
+       }
+       schema_init_done = 1;
+       return( 0 );
+}
+
+#if defined( SLAPD_SCHEMA_DN )
+
+static int
+syn_schema_info( Entry *e )
+{
+       struct berval   val;
+       struct berval   *vals[2];
+       Syntax          *syn;
+
+       vals[0] = &val;
+       vals[1] = NULL;
+
+       for ( syn = syn_list; syn; syn = syn->ssyn_next ) {
+               val.bv_val = ldap_syntax2str( &syn->ssyn_syn );
+               if ( val.bv_val ) {
+                       val.bv_len = strlen( val.bv_val );
+                       Debug( LDAP_DEBUG_TRACE, "Merging syn [%d] %s\n",
+                              val.bv_len, val.bv_val, 0 );
+                       attr_merge( e, "ldapSyntaxes", vals );
+                       ldap_memfree( val.bv_val );
+               } else {
+                       return -1;
+               }
+       }
+       return 0;
+}
+
+static int
+mr_schema_info( Entry *e )
+{
+       struct berval   val;
+       struct berval   *vals[2];
+       MatchingRule    *mr;
+
+       vals[0] = &val;
+       vals[1] = NULL;
+
+       for ( mr = mr_list; mr; mr = mr->smr_next ) {
+               val.bv_val = ldap_matchingrule2str( &mr->smr_mrule );
+               if ( val.bv_val ) {
+                       val.bv_len = strlen( val.bv_val );
+                       Debug( LDAP_DEBUG_TRACE, "Merging mr [%d] %s\n",
+                              val.bv_len, val.bv_val, 0 );
+                       attr_merge( e, "matchingRules", vals );
+                       ldap_memfree( val.bv_val );
+               } else {
+                       return -1;
+               }
+       }
+       return 0;
+}
+
+static int
+oc_schema_info( Entry *e )
+{
+       struct berval   val;
+       struct berval   *vals[2];
+       ObjectClass     *oc;
+
+       vals[0] = &val;
+       vals[1] = NULL;
+
+       for ( oc = oc_list; oc; oc = oc->soc_next ) {
+               val.bv_val = ldap_objectclass2str( &oc->soc_oclass );
+               if ( val.bv_val ) {
+                       val.bv_len = strlen( val.bv_val );
+                       Debug( LDAP_DEBUG_TRACE, "Merging oc [%d] %s\n",
+                              val.bv_len, val.bv_val, 0 );
+                       attr_merge( e, "objectClasses", vals );
+                       ldap_memfree( val.bv_val );
+               } else {
+                       return -1;
+               }
+       }
+       return 0;
+}
+
+void
+schema_info( Connection *conn, Operation *op, char **attrs, int attrsonly )
+{
+       Entry           *e;
+       struct berval   val;
+       struct berval   *vals[2];
+
+       vals[0] = &val;
+       vals[1] = NULL;
+
+       e = (Entry *) ch_calloc( 1, sizeof(Entry) );
+
+       e->e_attrs = NULL;
+       e->e_dn = ch_strdup( SLAPD_SCHEMA_DN );
+       e->e_ndn = dn_normalize_case( ch_strdup( SLAPD_SCHEMA_DN ));
+       e->e_private = NULL;
+
+       val.bv_val = ch_strdup( "top" );
+       val.bv_len = strlen( val.bv_val );
+       attr_merge( e, "objectClass", vals );
+       ldap_memfree( val.bv_val );
+
+       val.bv_val = ch_strdup( "subschema" );
+       val.bv_len = strlen( val.bv_val );
+       attr_merge( e, "objectClass", vals );
+       ldap_memfree( val.bv_val );
+
+       if ( syn_schema_info( e ) ) {
+               /* Out of memory, do something about it */
+               entry_free( e );
+               return;
+       }
+       if ( mr_schema_info( e ) ) {
+               /* Out of memory, do something about it */
+               entry_free( e );
+               return;
+       }
+       if ( at_schema_info( e ) ) {
+               /* Out of memory, do something about it */
+               entry_free( e );
+               return;
+       }
+       if ( oc_schema_info( e ) ) {
+               /* Out of memory, do something about it */
+               entry_free( e );
+               return;
+       }
+       
+       send_search_entry( &backends[0], conn, op, e, attrs, attrsonly, 0 );
+       send_search_result( conn, op, LDAP_SUCCESS, NULL, NULL, NULL, 1 );
+
+       entry_free( e );
+}
+#endif
+
 #ifdef LDAP_DEBUG
 
-static
-oc_print( struct objclass *oc )
+static void
+oc_print( ObjectClass *oc )
 {
        int     i;
 
-       printf( "objectclass %s\n", oc->oc_name );
-       if ( oc->oc_required != NULL ) {
-               printf( "\trequires %s", oc->oc_required[0] );
-               for ( i = 1; oc->oc_required[i] != NULL; i++ ) {
-                       printf( ",%s", oc->oc_required[i] );
+       if ( oc->soc_names && oc->soc_names[0] ) {
+               printf( "objectclass %s\n", oc->soc_names[0] );
+       } else {
+               printf( "objectclass %s\n", oc->soc_oid );
+       }
+       if ( oc->soc_required != NULL ) {
+               printf( "\trequires %s", oc->soc_required[0] );
+               for ( i = 1; oc->soc_required[i] != NULL; i++ ) {
+                       printf( ",%s", oc->soc_required[i] );
                }
                printf( "\n" );
        }
-       if ( oc->oc_allowed != NULL ) {
-               printf( "\tallows %s", oc->oc_allowed[0] );
-               for ( i = 1; oc->oc_allowed[i] != NULL; i++ ) {
-                       printf( ",%s", oc->oc_allowed[i] );
+       if ( oc->soc_allowed != NULL ) {
+               printf( "\tallows %s", oc->soc_allowed[0] );
+               for ( i = 1; oc->soc_allowed[i] != NULL; i++ ) {
+                       printf( ",%s", oc->soc_allowed[i] );
                }
                printf( "\n" );
        }
diff --git a/servers/slapd/schema/core.schema b/servers/slapd/schema/core.schema
new file mode 100644 (file)
index 0000000..18d5430
--- /dev/null
@@ -0,0 +1,445 @@
+
+# OpenLDAP Core schema
+# Includes "standard" schema items from RFC2251-RFC2256
+
+# Standard X.501(93) Operational Attribute Types from RFC2252
+
+attribute ( 2.5.18.1 NAME 'createTimestamp' EQUALITY generalizedTimeMatch
+      ORDERING generalizedTimeOrderingMatch
+      SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
+      SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )
+
+attribute ( 2.5.18.2 NAME 'modifyTimestamp' EQUALITY generalizedTimeMatch
+      ORDERING generalizedTimeOrderingMatch
+      SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
+      SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )
+
+attribute ( 2.5.18.3 NAME 'creatorsName' EQUALITY distinguishedNameMatch
+      SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
+      SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )
+
+attribute ( 2.5.18.4 NAME 'modifiersName' EQUALITY distinguishedNameMatch
+      SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
+      SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )
+
+attribute ( 2.5.18.10 NAME 'subschemaSubentry'
+      EQUALITY distinguishedNameMatch
+      SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 NO-USER-MODIFICATION
+      SINGLE-VALUE USAGE directoryOperation )
+
+attribute ( 2.5.21.5 NAME 'attributeTypes'
+      EQUALITY objectIdentifierFirstComponentMatch
+      SYNTAX 1.3.6.1.4.1.1466.115.121.1.3 USAGE directoryOperation )
+
+attribute ( 2.5.21.6 NAME 'objectClasses'
+      EQUALITY objectIdentifierFirstComponentMatch
+      SYNTAX 1.3.6.1.4.1.1466.115.121.1.37 USAGE directoryOperation )
+
+attribute ( 2.5.21.4 NAME 'matchingRules'
+      EQUALITY objectIdentifierFirstComponentMatch
+      SYNTAX 1.3.6.1.4.1.1466.115.121.1.30 USAGE directoryOperation )
+
+attribute ( 2.5.21.8 NAME 'matchingRuleUse'
+      EQUALITY objectIdentifierFirstComponentMatch
+      SYNTAX 1.3.6.1.4.1.1466.115.121.1.31 USAGE directoryOperation )
+
+# LDAP Operational Attributes from RFC2252
+
+attribute ( 1.3.6.1.4.1.1466.101.120.5 NAME 'namingContexts'
+     SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 USAGE dSAOperation )
+
+attribute ( 1.3.6.1.4.1.1466.101.120.6 NAME 'altServer'
+     SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 USAGE dSAOperation )
+
+attribute ( 1.3.6.1.4.1.1466.101.120.7 NAME 'supportedExtension'
+     SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 USAGE dSAOperation )
+
+attribute ( 1.3.6.1.4.1.1466.101.120.13 NAME 'supportedControl'
+     SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 USAGE dSAOperation )
+
+attribute ( 1.3.6.1.4.1.1466.101.120.14 NAME 'supportedSASLMechanisms'
+     SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 USAGE dSAOperation )
+
+attribute ( 1.3.6.1.4.1.1466.101.120.15 NAME 'supportedLDAPVersion'
+     SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 USAGE dSAOperation )
+
+# LDAP Subschema Atrribute from RFC2252
+
+attribute ( 1.3.6.1.4.1.1466.101.120.16 NAME 'ldapSyntaxes'
+      EQUALITY objectIdentifierFirstComponentMatch
+      SYNTAX 1.3.6.1.4.1.1466.115.121.1.54 USAGE directoryOperation )
+
+# X.500 Subschema attributes from RFC2252
+
+attribute ( 2.5.21.1 NAME 'dITStructureRules' EQUALITY integerFirstComponentMatch
+   SYNTAX 1.3.6.1.4.1.1466.115.121.1.17 USAGE directoryOperation )
+
+attribute ( 2.5.21.7 NAME 'nameForms'
+      EQUALITY objectIdentifierFirstComponentMatch
+      SYNTAX 1.3.6.1.4.1.1466.115.121.1.35 USAGE directoryOperation )
+
+attribute ( 2.5.21.2 NAME 'dITContentRules'
+      EQUALITY objectIdentifierFirstComponentMatch
+      SYNTAX 1.3.6.1.4.1.1466.115.121.1.16 USAGE directoryOperation )
+
+# Object Classes from RFC2252
+
+# extensibleObject moved forward, since it depends on top
+# ldapSyntaxes (operational) is admissible in next:
+
+objectclass ( 2.5.20.1 NAME 'subschema' AUXILIARY
+      MAY ( dITStructureRules $ nameForms $ ditContentRules $
+      objectClasses $ attributeTypes $ matchingRules $
+      matchingRuleUse ) )
+
+# Standard attribute types from RFC2256
+
+attribute ( 2.5.4.0 NAME 'objectClass' EQUALITY objectIdentifierMatch
+      SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )
+
+attribute ( 2.5.4.1 NAME 'aliasedObjectName' EQUALITY distinguishedNameMatch
+      SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE )
+
+# Defined, but no longer used
+
+attribute ( 2.5.4.2 NAME 'knowledgeInformation' EQUALITY caseIgnoreMatch
+      SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32768} )
+
+# Place here since other attribute types derive from it
+
+attribute ( 2.5.4.41 NAME 'name' EQUALITY caseIgnoreMatch
+      SUBSTR caseIgnoreSubstringsMatch
+      SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32768} )
+
+attribute ( 2.5.4.3 NAME ( 'cn' 'commonName' ) SUP name )
+
+attribute ( 2.5.4.4 NAME ( 'sn' 'surname' ) SUP name )
+
+attribute ( 2.5.4.5 NAME 'serialNumber' EQUALITY caseIgnoreMatch
+      SUBSTR caseIgnoreSubstringsMatch
+      SYNTAX 1.3.6.1.4.1.1466.115.121.1.44{64} )
+
+# (2-letter code from ISO 3166)
+
+attribute ( 2.5.4.6 NAME ( 'c' 'countryName' ) SUP name SINGLE-VALUE )
+
+attribute ( 2.5.4.7 NAME ( 'l' 'localityName' ) SUP name )
+
+attribute ( 2.5.4.8 NAME ( 'st' 'stateOrProvinceName' ) SUP name )
+
+attribute ( 2.5.4.9 NAME ( 'street' 'streetAddress' ) EQUALITY caseIgnoreMatch
+      SUBSTR caseIgnoreSubstringsMatch
+      SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
+
+attribute ( 2.5.4.10 NAME ( 'o' 'organizationName' ) SUP name )
+
+attribute ( 2.5.4.11 NAME ( 'ou' 'organizationalUnitName' ) SUP name )
+
+attribute ( 2.5.4.12 NAME 'title' SUP name )
+
+attribute ( 2.5.4.13 NAME 'description' EQUALITY caseIgnoreMatch
+      SUBSTR caseIgnoreSubstringsMatch
+      SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} )
+
+# Obsoleted by enhancedSearchGuide
+
+attribute ( 2.5.4.14 NAME 'searchGuide'
+      SYNTAX 1.3.6.1.4.1.1466.115.121.1.25 )
+
+attribute ( 2.5.4.15 NAME 'businessCategory' EQUALITY caseIgnoreMatch
+     SUBSTR caseIgnoreSubstringsMatch
+     SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
+
+# Show stopper: we don't have the definition of caseIgnoreListSubstringsMatch
+#attribute ( 2.5.4.16 NAME 'postalAddress' EQUALITY caseIgnoreListMatch
+#     SUBSTR caseIgnoreListSubstringsMatch
+#     SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )
+attribute ( 2.5.4.16 NAME 'postalAddress' EQUALITY caseIgnoreListMatch
+     SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )
+
+attribute ( 2.5.4.17 NAME 'postalCode' EQUALITY caseIgnoreMatch
+     SUBSTR caseIgnoreSubstringsMatch
+     SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{40} )
+
+attribute ( 2.5.4.18 NAME 'postOfficeBox' EQUALITY caseIgnoreMatch
+     SUBSTR caseIgnoreSubstringsMatch
+     SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{40} )
+
+attribute ( 2.5.4.19 NAME 'physicalDeliveryOfficeName' EQUALITY caseIgnoreMatch
+     SUBSTR caseIgnoreSubstringsMatch
+     SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
+
+attribute ( 2.5.4.20 NAME 'telephoneNumber' EQUALITY telephoneNumberMatch
+     SUBSTR telephoneNumberSubstringsMatch
+     SYNTAX 1.3.6.1.4.1.1466.115.121.1.50{32} )
+
+attribute ( 2.5.4.21 NAME 'telexNumber'
+     SYNTAX 1.3.6.1.4.1.1466.115.121.1.52 )
+
+attribute ( 2.5.4.22 NAME 'teletexTerminalIdentifier'
+     SYNTAX 1.3.6.1.4.1.1466.115.121.1.51 )
+
+attribute ( 2.5.4.23 NAME ( 'facsimileTelephoneNumber' 'fax' )
+     SYNTAX 1.3.6.1.4.1.1466.115.121.1.22 )
+
+attribute ( 2.5.4.24 NAME 'x121Address' EQUALITY numericStringMatch
+     SUBSTR numericStringSubstringsMatch
+     SYNTAX 1.3.6.1.4.1.1466.115.121.1.36{15} )
+
+attribute ( 2.5.4.25 NAME 'internationaliSDNNumber' EQUALITY numericStringMatch
+     SUBSTR numericStringSubstringsMatch
+     SYNTAX 1.3.6.1.4.1.1466.115.121.1.36{16} )
+
+attribute ( 2.5.4.26 NAME 'registeredAddress' SUP postalAddress
+      SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )
+
+attribute ( 2.5.4.27 NAME 'destinationIndicator' EQUALITY caseIgnoreMatch
+      SUBSTR caseIgnoreSubstringsMatch
+      SYNTAX 1.3.6.1.4.1.1466.115.121.1.44{128} )
+
+attribute ( 2.5.4.28 NAME 'preferredDeliveryMethod'
+      SYNTAX 1.3.6.1.4.1.1466.115.121.1.14
+      SINGLE-VALUE )
+
+attribute ( 2.5.4.29 NAME 'presentationAddress'
+      EQUALITY presentationAddressMatch
+      SYNTAX 1.3.6.1.4.1.1466.115.121.1.43
+      SINGLE-VALUE )
+
+attribute ( 2.5.4.30 NAME 'supportedApplicationContext'
+      EQUALITY objectIdentifierMatch
+      SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )
+
+# Placed here because others derive from it
+# We had a dn definition in slapd.at.conf and Netscape lists both
+# names for that OID
+
+attribute ( 2.5.4.49 NAME ( 'distinguishedName' 'dn' )
+      EQUALITY distinguishedNameMatch
+      SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )
+
+attribute ( 2.5.4.31 NAME 'member' SUP distinguishedName )
+
+attribute ( 2.5.4.32 NAME 'owner' SUP distinguishedName )
+
+attribute ( 2.5.4.33 NAME 'roleOccupant' SUP distinguishedName )
+
+attribute ( 2.5.4.34 NAME 'seeAlso' SUP distinguishedName )
+
+attribute ( 2.5.4.35 NAME 'userPassword' EQUALITY octetStringMatch
+      SYNTAX 1.3.6.1.4.1.1466.115.121.1.40{128} )
+
+# Must be stored and requested in the binary form, as
+# userCertificate;binary
+
+attribute ( 2.5.4.36 NAME 'userCertificate'
+      SYNTAX 1.3.6.1.4.1.1466.115.121.1.8 )
+
+# As above
+
+attribute ( 2.5.4.37 NAME 'cACertificate'
+      SYNTAX 1.3.6.1.4.1.1466.115.121.1.8 )
+
+# As above
+
+attribute ( 2.5.4.38 NAME 'authorityRevocationList'
+      SYNTAX 1.3.6.1.4.1.1466.115.121.1.9 )
+
+# As above
+
+attribute ( 2.5.4.39 NAME 'certificateRevocationList'
+      SYNTAX 1.3.6.1.4.1.1466.115.121.1.9 )
+
+# As above
+
+attribute ( 2.5.4.40 NAME 'crossCertificatePair'
+      SYNTAX 1.3.6.1.4.1.1466.115.121.1.10 )
+
+# 2.5.4.41 is 'name', moved above since other attribute types derive from it
+
+attribute ( 2.5.4.42 NAME 'givenName' SUP name )
+
+attribute ( 2.5.4.43 NAME 'initials' SUP name )
+
+attribute ( 2.5.4.45 NAME 'x500UniqueIdentifier' EQUALITY bitStringMatch
+      SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )
+
+attribute ( 2.5.4.46 NAME 'dnQualifier' EQUALITY caseIgnoreMatch
+      ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch
+      SYNTAX 1.3.6.1.4.1.1466.115.121.1.44 )
+
+attribute ( 2.5.4.47 NAME 'enhancedSearchGuide'
+      SYNTAX 1.3.6.1.4.1.1466.115.121.1.21 )
+
+attribute ( 2.5.4.48 NAME 'protocolInformation'
+      EQUALITY protocolInformationMatch
+      SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )
+
+# 2.5.4.49 is distinguishedName, moved up
+
+attribute ( 2.5.4.50 NAME 'uniqueMember' EQUALITY uniqueMemberMatch
+      SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )
+
+attribute ( 2.5.4.51 NAME 'houseIdentifier' EQUALITY caseIgnoreMatch
+      SUBSTR caseIgnoreSubstringsMatch
+      SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32768} )
+
+# This attribute is to be stored and requested in the binary form, as
+# 'supportedAlgorithms;binary'.
+
+attribute ( 2.5.4.52 NAME 'supportedAlgorithms'
+      SYNTAX 1.3.6.1.4.1.1466.115.121.1.49 )
+
+# This attribute is to be stored and requested in the binary form, as
+# 'deltaRevocationList;binary'.
+
+attribute ( 2.5.4.53 NAME 'deltaRevocationList'
+      SYNTAX 1.3.6.1.4.1.1466.115.121.1.9 )
+
+attribute ( 2.5.4.54 NAME 'dmdName' SUP name )
+
+# Standard object classes from RFC2256
+
+objectclass ( 2.5.6.0 NAME 'top' ABSTRACT MUST objectClass )
+
+objectclass ( 2.5.6.1 NAME 'alias' SUP top STRUCTURAL MUST aliasedObjectName )
+
+objectclass ( 2.5.6.2 NAME 'country' SUP top STRUCTURAL MUST c
+     MAY ( searchGuide $ description ) )
+
+objectclass ( 2.5.6.3 NAME 'locality' SUP top STRUCTURAL
+     MAY ( street $ seeAlso $ searchGuide $ st $ l $ description ) )
+
+objectclass ( 2.5.6.4 NAME 'organization' SUP top STRUCTURAL MUST o
+     MAY ( userPassword $ searchGuide $ seeAlso $ businessCategory $
+     x121Address $ registeredAddress $ destinationIndicator $
+     preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
+     telephoneNumber $ internationaliSDNNumber $
+     facsimileTelephoneNumber $
+     street $ postOfficeBox $ postalCode $ postalAddress $
+     physicalDeliveryOfficeName $ st $ l $ description ) )
+
+objectclass ( 2.5.6.5 NAME 'organizationalUnit' SUP top STRUCTURAL MUST ou
+     MAY ( userPassword $ searchGuide $ seeAlso $ businessCategory $
+     x121Address $ registeredAddress $ destinationIndicator $
+     preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
+     telephoneNumber $ internationaliSDNNumber $
+     facsimileTelephoneNumber $
+     street $ postOfficeBox $ postalCode $ postalAddress $
+     physicalDeliveryOfficeName $ st $ l $ description ) )
+
+objectclass ( 2.5.6.6 NAME 'person' SUP top STRUCTURAL MUST ( sn $ cn )
+     MAY ( userPassword $ telephoneNumber $ seeAlso $ description ) )
+
+objectclass ( 2.5.6.7 NAME 'organizationalPerson' SUP person STRUCTURAL
+     MAY ( title $ x121Address $ registeredAddress $
+     destinationIndicator $
+     preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
+     telephoneNumber $ internationaliSDNNumber $
+     facsimileTelephoneNumber $
+     street $ postOfficeBox $ postalCode $ postalAddress $
+     physicalDeliveryOfficeName $ ou $ st $ l ) )
+
+# Notice that preferredDeliveryMethod is duplicate
+
+objectclass ( 2.5.6.8 NAME 'organizationalRole' SUP top STRUCTURAL MUST cn
+     MAY ( x121Address $ registeredAddress $ destinationIndicator $
+     preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
+     telephoneNumber $ internationaliSDNNumber $
+     facsimileTelephoneNumber $
+     seeAlso $ roleOccupant $ preferredDeliveryMethod $ street $
+     postOfficeBox $ postalCode $ postalAddress $
+     physicalDeliveryOfficeName $ ou $ st $ l $ description ) )
+
+objectclass ( 2.5.6.9 NAME 'groupOfNames' SUP top STRUCTURAL MUST ( member $ cn )
+     MAY ( businessCategory $ seeAlso $ owner $ ou $ o $ description ) )
+
+# Notice that preferredDeliveryMethod is duplicate
+# It seems they could not agree on wheter telephoneNumber is MAY
+# in person.  Probably it wasn't originally at was added as an
+# afterthought
+
+objectclass ( 2.5.6.10 NAME 'residentialPerson' SUP person STRUCTURAL MUST l
+     MAY ( businessCategory $ x121Address $ registeredAddress $
+     destinationIndicator $ preferredDeliveryMethod $ telexNumber $
+     teletexTerminalIdentifier $ telephoneNumber $
+     internationaliSDNNumber $
+     facsimileTelephoneNumber $ preferredDeliveryMethod $ street $
+     postOfficeBox $ postalCode $ postalAddress $
+     physicalDeliveryOfficeName $ st $ l ) )
+
+objectclass ( 2.5.6.11 NAME 'applicationProcess' SUP top STRUCTURAL MUST cn
+     MAY ( seeAlso $ ou $ l $ description ) )
+
+objectclass ( 2.5.6.12 NAME 'applicationEntity' SUP top STRUCTURAL
+     MUST ( presentationAddress $ cn )
+     MAY ( supportedApplicationContext $ seeAlso $ ou $ o $ l $
+     description ) )
+
+# This one was wrong in our schema, it only allowed the aditional
+# knowledgeInformation attribute, while it is derived from
+# applicationEntity and should allow all its attributes as well.
+
+objectclass ( 2.5.6.13 NAME 'dSA' SUP applicationEntity STRUCTURAL
+     MAY knowledgeInformation )
+
+objectclass ( 2.5.6.14 NAME 'device' SUP top STRUCTURAL MUST cn
+     MAY ( serialNumber $ seeAlso $ owner $ ou $ o $ l $ description ) )
+
+objectclass ( 2.5.6.15 NAME 'strongAuthenticationUser' SUP top AUXILIARY
+     MUST userCertificate )
+
+objectclass ( 2.5.6.16 NAME 'certificationAuthority' SUP top AUXILIARY
+     MUST ( authorityRevocationList $ certificateRevocationList $
+     cACertificate ) MAY crossCertificatePair )
+
+# New
+
+objectclass ( 2.5.6.17 NAME 'groupOfUniqueNames' SUP top STRUCTURAL
+     MUST ( uniqueMember $ cn )
+     MAY ( businessCategory $ seeAlso $ owner $ ou $ o $ description ) )
+
+# New
+
+objectclass ( 2.5.6.18 NAME 'userSecurityInformation' SUP top AUXILIARY
+     MAY ( supportedAlgorithms ) )
+
+# New
+
+objectclass ( 2.5.6.16.2 NAME 'certificationAuthority-V2' SUP
+     certificationAuthority
+     AUXILIARY MAY ( deltaRevocationList ) )
+
+# New
+
+objectclass ( 2.5.6.19 NAME 'cRLDistributionPoint' SUP top STRUCTURAL
+     MUST ( cn ) MAY ( certificateRevocationList $
+     authorityRevocationList $
+     deltaRevocationList ) )
+
+# New
+
+objectclass ( 2.5.6.20 NAME 'dmd' SUP top STRUCTURAL MUST ( dmdName )
+     MAY ( userPassword $ searchGuide $ seeAlso $ businessCategory $
+     x121Address $ registeredAddress $ destinationIndicator $
+     preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
+     telephoneNumber $ internationaliSDNNumber $
+     facsimileTelephoneNumber $
+     street $ postOfficeBox $ postalCode $ postalAddress $
+     physicalDeliveryOfficeName $ st $ l $ description ) )
+
+# Next objectclass is defined in RFC2252, but has to be put after top
+
+objectclass ( 1.3.6.1.4.1.1466.101.120.111 NAME 'extensibleObject'
+      SUP top AUXILIARY )
+
+#
+# From draft-ietf-ldapext-nameref-00.txt
+#      used to represent referrals in the directory
+#
+attribute ( 2.16.840.1.113730.3.1.34 NAME 'ref' DESC 'URL Reference'
+       EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.1466.115.121.1.26
+       USAGE distributedOperation )
+
+objectclass ( 2.16.840.1.113730.3.2.6 NAME 'referral'
+       SUP top STRUCTURAL MAY ( ref ) )
index fc96d2fd021727bd9f14c04445f3ace096defa32..dbdff19a1d08892acdde2b6e18634c775a580e66 100644 (file)
  * is provided ``as is'' without express or implied warranty.
  */
 
+#include "portable.h"
+
 #include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include "slap.h"
-#include "ldapconfig.h"
 
-extern int     get_filter();
-extern Backend *select_backend();
+#include <ac/string.h>
+#include <ac/socket.h>
 
-extern char    *default_referral;
+#include "ldap_defaults.h"
+#include "slap.h"
 
-void
-do_search( conn, op )
-    Connection *conn;  /* where to send results                       */
-    Operation  *op;    /* info about the op to which we're responding */
+
+int
+do_search(
+    Connection *conn,  /* where to send results                       */
+    Operation  *op     /* info about the op to which we're responding */
+)
 {
        int             i, err;
-       int             scope, deref, attrsonly;
-       int             sizelimit, timelimit;
-       char            *base, *fstr;
-       Filter          *filter;
-       char            **attrs;
+       ber_int_t               scope, deref, attrsonly;
+       ber_int_t               sizelimit, timelimit;
+       char            *base = NULL, *fstr = NULL;
+       Filter          *filter = NULL;
+       char            **attrs = NULL;
        Backend         *be;
+       int                     rc;
 
        Debug( LDAP_DEBUG_TRACE, "do_search\n", 0, 0, 0 );
 
+       if( op->o_bind_in_progress ) {
+               Debug( LDAP_DEBUG_ANY, "do_search: SASL bind in progress.\n",
+                       0, 0, 0 );
+               send_ldap_result( conn, op, LDAP_SASL_BIND_IN_PROGRESS, NULL,
+                   "SASL bind in progress", NULL );
+               return LDAP_SASL_BIND_IN_PROGRESS;
+       }
+
        /*
         * Parse the search request.  It looks like this:
         *
@@ -62,52 +71,67 @@ do_search( conn, op )
         */
 
        /* baseObject, scope, derefAliases, sizelimit, timelimit, attrsOnly */
-       if ( ber_scanf( op->o_ber, "{aiiiib", &base, &scope, &deref, &sizelimit,
+       if ( ber_scanf( op->o_ber, "{aiiiib",
+               &base, &scope, &deref, &sizelimit,
            &timelimit, &attrsonly ) == LBER_ERROR ) {
-               send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL, "" );
-               return;
+               send_ldap_disconnect( conn, op,
+                       LDAP_PROTOCOL_ERROR, "decoding error" );
+               rc = -1;
+               goto return_results;
        }
+
        if ( scope != LDAP_SCOPE_BASE && scope != LDAP_SCOPE_ONELEVEL
            && scope != LDAP_SCOPE_SUBTREE ) {
-               free( base );
-               send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL,
-                   "Unknown search scope" );
-               return;
+               send_ldap_disconnect( conn, op,
+                       LDAP_PROTOCOL_ERROR, "decoding error" );
+               rc = -1;
+               goto return_results;
        }
-       (void) dn_normalize( base );
+
+       (void) dn_normalize_case( base );
 
        Debug( LDAP_DEBUG_ARGS, "SRCH \"%s\" %d %d", base, scope, deref );
        Debug( LDAP_DEBUG_ARGS, "    %d %d %d\n", sizelimit, timelimit,
            attrsonly);
 
        /* filter - returns a "normalized" version */
-       filter = NULL;
-       fstr = NULL;
        if ( (err = get_filter( conn, op->o_ber, &filter, &fstr )) != 0 ) {
-               if ( fstr != NULL ) {
-                       free( fstr );
+               if( err == -1 ) {
+                       send_ldap_disconnect( conn, op,
+                               LDAP_PROTOCOL_ERROR, "decode error" );
+               } else {
+                       send_ldap_result( conn, op, err,
+                               NULL, "Bad search filter", NULL );
                }
-               free( base );
-               send_ldap_result( conn, op, err, NULL, "Bad search filter" );
-               return;
+               goto return_results;
        }
+
        Debug( LDAP_DEBUG_ARGS, "    filter: %s\n", fstr, 0, 0 );
 
        /* attributes */
-       attrs = NULL;
-       if ( ber_scanf( op->o_ber, "{v}}", &attrs ) == LBER_ERROR ) {
-               free( base );
-               free( fstr );
-               send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL, "" );
-               return;
+       if ( ber_scanf( op->o_ber, /*{*/ "{v}}", &attrs ) == LBER_ERROR ) {
+               send_ldap_disconnect( conn, op,
+                       LDAP_PROTOCOL_ERROR, "decoding error" );
+               rc = -1;
+               goto return_results;
        }
+
+       if( (rc = get_ctrls( conn, op, 1 )) != LDAP_SUCCESS ) {
+               Debug( LDAP_DEBUG_ANY, "do_search: get_ctrls failed\n", 0, 0, 0 );
+               goto return_results;
+       } 
+
+       rc = 0;
+
        Debug( LDAP_DEBUG_ARGS, "    attrs:", 0, 0, 0 );
+
        if ( attrs != NULL ) {
                for ( i = 0; attrs[i] != NULL; i++ ) {
                        attr_normalize( attrs[i] );
                        Debug( LDAP_DEBUG_ARGS, " %s", attrs[i], 0, 0 );
                }
        }
+
        Debug( LDAP_DEBUG_ARGS, "\n", 0, 0, 0 );
 
        Statslog( LDAP_DEBUG_STATS,
@@ -117,63 +141,62 @@ do_search( conn, op )
 #if defined( SLAPD_MONITOR_DN ) || defined( SLAPD_CONFIG_DN ) || defined( SLAPD_SCHEMA_DN )
        if ( scope == LDAP_SCOPE_BASE ) {
 #if defined( SLAPD_MONITOR_DN )
-               if ( strcasecmp( base, SLAPD_MONITOR_DN ) == 0 ) {
-                       free( base );
-                       free( fstr );
+               if ( strcmp( base, SLAPD_MONITOR_DN ) == 0 ) {
                        monitor_info( conn, op );
-                       return;
+                       goto return_results;
                }
 #endif
 #if defined( SLAPD_CONFIG_DN )
-               if ( strcasecmp( base, SLAPD_CONFIG_DN ) == 0 ) {
-                       free( base );
-                       free( fstr );
+               if ( strcmp( base, SLAPD_CONFIG_DN ) == 0 ) {
                        config_info( conn, op );
-                       return;
+                       goto return_results;
                }
 #endif
 #if defined( SLAPD_SCHEMA_DN )
-               if ( strcasecmp( base, SLAPD_SCHEMA_DN ) == 0 ) {
-                       free( base );
-                       free( fstr );
-                       schema_info( conn, op );
-                       return;
+               if ( strcmp( base, SLAPD_SCHEMA_DN ) == 0 ) {
+                       schema_info( conn, op, attrs, attrsonly );
+                       goto return_results;
                }
 #endif
        }
 #endif /* monitor or config or schema dn */
 
+       if ( strcmp( base, LDAP_ROOT_DSE ) == 0 && scope == LDAP_SCOPE_BASE ) {
+               root_dse_info( conn, op, attrs, attrsonly );
+               goto return_results;
+       }
+
        /*
         * We could be serving multiple database backends.  Select the
         * appropriate one, or send a referral to our "referral server"
         * if we don't hold it.
         */
        if ( (be = select_backend( base )) == NULL ) {
-               send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL,
-                   default_referral );
-
-               free( base );
-               free( fstr );
-               filter_free( filter );
-               if ( attrs != NULL ) {
-                       charray_free( attrs );
-               }
-               return;
+               send_ldap_result( conn, op, rc = LDAP_REFERRAL,
+                       NULL, NULL, default_referral );
+
+               goto return_results;
        }
 
+       /* translate the base if it matches an aliased base part */
+       base = suffixAlias ( base, op, be );
+
        /* actually do the search and send the result(s) */
-       if ( be->be_search != NULL ) {
+       if ( be->be_search ) {
                (*be->be_search)( be, conn, op, base, scope, deref, sizelimit,
                    timelimit, filter, fstr, attrs, attrsonly );
        } else {
-               send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
-                   "Function not implemented" );
+               send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
+                       NULL, "Function not implemented", NULL );
        }
 
-       free( base );
-       free( fstr );
-       filter_free( filter );
+return_results:;
+       if( base != NULL) free( base );
+       if( fstr != NULL) free( fstr );
+       if( filter != NULL) filter_free( filter );
        if ( attrs != NULL ) {
                charray_free( attrs );
        }
+
+       return rc;
 }
diff --git a/servers/slapd/slapd.dsw b/servers/slapd/slapd.dsw
new file mode 100644 (file)
index 0000000..b3c3ca4
--- /dev/null
@@ -0,0 +1,167 @@
+Microsoft Developer Studio Workspace File, Format Version 5.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "backldbm"=".\back-ldbm\backldbm.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "libavl"=..\..\libraries\libavl\libavl.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "liblber"=..\..\libraries\liblber\liblber.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "libldap_r"=..\..\libraries\libldap_r\libldap_r.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+    Begin Project Dependency
+    Project_Dep_Name liblber
+    End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "libldbm"=..\..\libraries\libldbm\libldbm.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "libldif"=..\..\libraries\libldif\libldif.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "liblutil"=..\..\libraries\liblutil\liblutil.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "libslapd"=.\libslapd.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "setup"=..\..\include\setup.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "slapd"=.\slapd.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+    Begin Project Dependency
+    Project_Dep_Name libavl
+    End Project Dependency
+    Begin Project Dependency
+    Project_Dep_Name liblber
+    End Project Dependency
+    Begin Project Dependency
+    Project_Dep_Name libldbm
+    End Project Dependency
+    Begin Project Dependency
+    Project_Dep_Name libldif
+    End Project Dependency
+    Begin Project Dependency
+    Project_Dep_Name liblutil
+    End Project Dependency
+    Begin Project Dependency
+    Project_Dep_Name libldap_r
+    End Project Dependency
+    Begin Project Dependency
+    Project_Dep_Name backldbm
+    End Project Dependency
+    Begin Project Dependency
+    Project_Dep_Name libslapd
+    End Project Dependency
+    Begin Project Dependency
+    Project_Dep_Name setup
+    End Project Dependency
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/servers/slapd/tools/mimic.c b/servers/slapd/tools/mimic.c
new file mode 100644 (file)
index 0000000..1facaa2
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Mimic unused interfaces of slapd...
+ * needed for linking.
+ */
+#include "portable.h"
+
+#include <stdio.h>
+
+#include "../slap.h"
+
+#ifdef WIN32
+time_t starttime;
+#endif
+
+/* bogus ../results.c */
+int str2result(
+       char* s,
+       int *code, 
+       char **matched,
+       char **info )
+{
+       assert(0);
+    return 0;
+}
+
+void
+send_ldap_result(
+       Connection  *conn, 
+       Operation   *op,
+       int     err,
+       char    *matched,
+       char    *text
+)        
+{
+       assert(0);
+}
+
+void
+send_search_result(
+       Connection  *conn, 
+       Operation   *op,
+       int     err,
+       char    *matched,
+       char    *text,
+       int             nentries
+)        
+{
+       assert(0);
+}
+
+int
+send_search_entry(
+       Backend *be,
+       Connection  *conn, 
+       Operation   *op,
+       Entry   *e,
+       char    **attrs,
+       int             attrsonly,
+       int             opattrs
+)        
+{
+       assert(0);
+       return -1;
+}