From: Kurt Zeilenga Date: Fri, 9 Jul 1999 18:31:10 +0000 (+0000) Subject: LDAPv3 Referrals (using old style referral entries) initial commit. X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=fe242e3ca79753c8cbf0aa38d43f0ca5b58070d7;p=openldap LDAPv3 Referrals (using old style referral entries) initial commit. 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. --- diff --git a/include/ldap.h b/include/ldap.h index 1eab5bda62..876607e5bb 100644 --- a/include/ldap.h +++ b/include/ldap.h @@ -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. * @@ -13,218 +22,277 @@ #ifndef _LDAP_H #define _LDAP_H -#ifdef __cplusplus -extern "C" { -#endif - +#include -#ifdef WINSOCK -#include "msdos.h" -#include -#endif +/* draft spec requires ldap.h include lber declarations */ +#include -#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 + +#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 -#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 */ diff --git a/servers/slapd/abandon.c b/servers/slapd/abandon.c index d6f7291c78..3069ed7452 100644 --- a/servers/slapd/abandon.c +++ b/servers/slapd/abandon.c @@ -12,24 +12,23 @@ * is provided ``as is'' without express or implied warranty. */ -#include -#include -#include -#include "slap.h" +#include "portable.h" -extern Backend *select_backend(); +#include +#include -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; } diff --git a/servers/slapd/add.c b/servers/slapd/add.c index 027e40a8e4..962374c32a 100644 --- a/servers/slapd/add.c +++ b/servers/slapd/add.c @@ -10,36 +10,38 @@ * is provided ``as is'' without express or implied warranty. */ +#include "portable.h" + #include -#include -#include -#include -#include -#include "slap.h" -extern Backend *select_backend(); -extern char *dn_normalize(); +#include +#include +#include -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 = ""; 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( ¤ttime_mutex ); - ltm = localtime( ¤ttime ); - strftime( buf, sizeof(buf), "%y%m%d%H%M%SZ", ltm ); - pthread_mutex_unlock( ¤ttime_mutex ); + currenttime = slap_get_time(); + ldap_pvt_thread_mutex_lock( &gmtime_mutex ); +#ifndef LDAP_LOCALTIME + ltm = gmtime( ¤ttime ); + strftime( buf, sizeof(buf), "%Y%m%d%H%M%SZ", ltm ); +#else + ltm = localtime( ¤ttime ); + 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 index 0000000000..9ae5992917 --- /dev/null +++ b/servers/slapd/back-bdb2/search.c @@ -0,0 +1,547 @@ +/* search.c - bdb2 backend search function */ + +#include "portable.h" + +#include + +#include +#include +#include + +#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 index 0000000000..7654bd3b2d --- /dev/null +++ b/servers/slapd/back-ldap/search.c @@ -0,0 +1,172 @@ +/* search.c - ldap backend search function */ + +/* + * Copyright 1999, Howard Chu, All rights reserved. + * + * 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 + +#include +#include +#include + +#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); +} diff --git a/servers/slapd/back-ldbm/add.c b/servers/slapd/back-ldbm/add.c index 3dacd6da3d..b28fc55a48 100644 --- a/servers/slapd/back-ldbm/add.c +++ b/servers/slapd/back-ldbm/add.c @@ -1,16 +1,15 @@ /* add.c - ldap ldbm back-end add routine */ +#include "portable.h" + #include -#include -#include -#include + +#include +#include + #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 index 0000000000..9717dc336f --- /dev/null +++ b/servers/slapd/back-ldbm/alias.c @@ -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 +#include +#include +#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; +} diff --git a/servers/slapd/back-ldbm/bind.c b/servers/slapd/back-ldbm/bind.c index 88fd4030c4..2fb2abedc7 100644 --- a/servers/slapd/back-ldbm/bind.c +++ b/servers/slapd/back-ldbm/bind.c @@ -1,22 +1,63 @@ /* bind.c - ldbm backend bind and unbind routines */ +#include "portable.h" + #include -#include -#include -#include + +#include +#include +#include +#include + #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 -#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 ); } + diff --git a/servers/slapd/back-ldbm/compare.c b/servers/slapd/back-ldbm/compare.c index 4757a29b92..160d5fab91 100644 --- a/servers/slapd/back-ldbm/compare.c +++ b/servers/slapd/back-ldbm/compare.c @@ -1,14 +1,15 @@ /* compare.c - ldbm backend compare routine */ +#include "portable.h" + #include -#include -#include -#include + +#include +#include + #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 ); } diff --git a/servers/slapd/back-ldbm/delete.c b/servers/slapd/back-ldbm/delete.c index c773929ffb..2324f16b00 100644 --- a/servers/slapd/back-ldbm/delete.c +++ b/servers/slapd/back-ldbm/delete.c @@ -1,14 +1,15 @@ /* delete.c - ldbm backend delete routine */ +#include "portable.h" + #include -#include -#include -#include + +#include +#include + #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; } diff --git a/servers/slapd/back-ldbm/modify.c b/servers/slapd/back-ldbm/modify.c index 3fa6c61a92..941203a100 100644 --- a/servers/slapd/back-ldbm/modify.c +++ b/servers/slapd/back-ldbm/modify.c @@ -1,121 +1,267 @@ /* modify.c - ldbm backend modify routine */ +#include "portable.h" + #include -#include -#include -#include + +#include +#include +#include + #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( ¤ttime ); + strftime( buf, sizeof(buf), "%Y%m%d%H%M%SZ", ltm ); +#else + ltm = localtime( ¤ttime ); + 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 ) { diff --git a/servers/slapd/back-ldbm/modrdn.c b/servers/slapd/back-ldbm/modrdn.c index fcd9fcc35a..e724b9c18b 100644 --- a/servers/slapd/back-ldbm/modrdn.c +++ b/servers/slapd/back-ldbm/modrdn.c @@ -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 -#include -#include -#include + +#include +#include + #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 ); } diff --git a/servers/slapd/back-ldbm/search.c b/servers/slapd/back-ldbm/search.c index 6a53be4f11..6fa1d9b7dc 100644 --- a/servers/slapd/back-ldbm/search.c +++ b/servers/slapd/back-ldbm/search.c @@ -1,38 +1,19 @@ /* search.c - ldbm backend search function */ +#include "portable.h" + #include -#include -#include -#include + +#include +#include + #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( ¤ttime_mutex ); - time( ¤ttime ); - if ( tlimit != -1 && currenttime > stoptime ) { - pthread_mutex_unlock( ¤ttime_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( ¤ttime_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 ); } diff --git a/servers/slapd/bind.c b/servers/slapd/bind.c index 562ce5b54a..df2a1845de 100644 --- a/servers/slapd/bind.c +++ b/servers/slapd/bind.c @@ -12,30 +12,72 @@ * is provided ``as is'' without express or implied warranty. */ +#include "portable.h" + #include -#include -#include -#include -#include "slap.h" -extern Backend *select_backend(); +#include +#include -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; } diff --git a/servers/slapd/charray.c b/servers/slapd/charray.c index b731cf1e90..e972d22ec4 100644 --- a/servers/slapd/charray.c +++ b/servers/slapd/charray.c @@ -1,9 +1,12 @@ /* charray.c - routines for dealing with char * arrays */ +#include "portable.h" + #include -#include -#include -#include + +#include +#include + #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 ); } diff --git a/servers/slapd/compare.c b/servers/slapd/compare.c index 248c8b1ec7..6430dcf134 100644 --- a/servers/slapd/compare.c +++ b/servers/slapd/compare.c @@ -10,28 +10,35 @@ * is provided ``as is'' without express or implied warranty. */ +#include "portable.h" + #include -#include -#include -#include "slap.h" -extern Backend *select_backend(); +#include -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; } diff --git a/servers/slapd/config.c b/servers/slapd/config.c index 66050586ab..0b169a5c1d 100644 --- a/servers/slapd/config.c +++ b/servers/slapd/config.c @@ -1,19 +1,21 @@ /* config.c - configuration file handling routines */ +#include "portable.h" + #include -#include -#include -#include +#ifdef HAVE_LOCALE_H +#include +#endif + +#include +#include +#include + +#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 \" 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 \" 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 \" 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 \" 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 \" 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 \" 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 \" 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 \" line\n", fname, lineno, 0 ); - exit( 1 ); + return( 1 ); } else if ( cargc > 2 ) { Debug( LDAP_DEBUG_ANY, "%s: line %d: extra cruft after 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 \" line\n", + fname, lineno, 0 ); + return( 1 ); + } else if ( cargc < 3 ) { + Debug( LDAP_DEBUG_ANY, + "%s: line %d: missing aliased_dn in \"suffixAlias \" 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 \" 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 \" 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 \" 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 \" 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 \" 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 \" 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 \" 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 \" 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 \" 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 \" 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 \" 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 \" 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 \" 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 \" 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 \" 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 \" 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 \" 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 \" 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 ); } diff --git a/servers/slapd/configinfo.c b/servers/slapd/configinfo.c index 5599193006..a8051991bb 100644 --- a/servers/slapd/configinfo.c +++ b/servers/slapd/configinfo.c @@ -10,19 +10,18 @@ * is provided ``as is'' without express or implied warranty. */ +#include "portable.h" + #include -#include -#include -#include + +#include +#include + +#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 index 0000000000..9580ea0fd4 --- /dev/null +++ b/servers/slapd/controls.c @@ -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 +#include + +#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; +} diff --git a/servers/slapd/delete.c b/servers/slapd/delete.c index bbab47806c..53d3f50077 100644 --- a/servers/slapd/delete.c +++ b/servers/slapd/delete.c @@ -10,80 +10,98 @@ * is provided ``as is'' without express or implied warranty. */ +#include "portable.h" + #include -#include -#include -#include -#include "slap.h" -extern Backend *select_backend(); +#include +#include -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 index 0000000000..7082448fca --- /dev/null +++ b/servers/slapd/extended.c @@ -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 +#include + +#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 diff --git a/servers/slapd/init.c b/servers/slapd/init.c index 03dd850f0e..dc50910663 100644 --- a/servers/slapd/init.c +++ b/servers/slapd/init.c @@ -1,37 +1,173 @@ /* init.c - initialize various things */ -#include -#include -#include -#include -#include -#include -#include -#include #include "portable.h" + +#include + +#include +#include +#include + #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( ¤ttime_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( ®ex_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( ¤ttime_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( ¤ttime_mutex ); + time( &t ); + ldap_pvt_thread_mutex_unlock( ¤ttime_mutex ); + return t; } diff --git a/servers/slapd/modify.c b/servers/slapd/modify.c index 6575fe36ad..cfc62e8d69 100644 --- a/servers/slapd/modify.c +++ b/servers/slapd/modify.c @@ -10,39 +10,46 @@ * is provided ``as is'' without express or implied warranty. */ +#include "portable.h" + #include -#include -#include -#include -#include -#include -#include "slap.h" -extern Backend *select_backend(); +#include +#include +#include -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( ¤ttime_mutex ); - ltm = localtime( ¤ttime ); - strftime( buf, sizeof(buf), "%y%m%d%H%M%SZ", ltm ); - pthread_mutex_unlock( ¤ttime_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; } diff --git a/servers/slapd/modrdn.c b/servers/slapd/modrdn.c index 802dda55ac..439fb41452 100644 --- a/servers/slapd/modrdn.c +++ b/servers/slapd/modrdn.c @@ -10,52 +10,167 @@ * 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 -#include -#include -#include -#include "slap.h" -extern Backend *select_backend(); +#include +#include -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; } diff --git a/servers/slapd/monitor.c b/servers/slapd/monitor.c index 7dbabc9377..251f8b5ec3 100644 --- a/servers/slapd/monitor.c +++ b/servers/slapd/monitor.c @@ -10,54 +10,46 @@ * is provided ``as is'' without express or implied warranty. */ -#include -#include -#include -#include -#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 +#include +#include +#include -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 : "", + 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( ¤ttime ); - 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( ¤ttime ); + strftime( buf, sizeof(buf), "%Y%m%d%H%M%SZ", ltm ); +#else + ltm = localtime( ¤ttime ); + 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 ); } diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h index a1ff6e5e75..6e29f71056 100644 --- a/servers/slapd/proto-slap.h +++ b/servers/slapd/proto-slap.h @@ -1,202 +1,439 @@ #ifndef _PROTO_SLAP #define _PROTO_SLAP +#include + +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 */ + diff --git a/servers/slapd/result.c b/servers/slapd/result.c index 0ef82a7b3e..8ebb81bab8 100644 --- a/servers/slapd/result.c +++ b/servers/slapd/result.c @@ -1,105 +1,95 @@ /* result.c - routines to send ldap results, errors, and referrals */ -#include -#include -#include -#include -#include -#include -#include -#include #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 -void close_connection(); +#include +#include +#include +#include +#include +#include -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 index 0000000000..edb655c24d --- /dev/null +++ b/servers/slapd/root_dse.c @@ -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 + +#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 ); +} + diff --git a/servers/slapd/schema.c b/servers/slapd/schema.c index ba16d9b0f1..fc2ce4188c 100644 --- a/servers/slapd/schema.c +++ b/servers/slapd/schema.c @@ -1,21 +1,18 @@ /* schema.c - routines to enforce schema definitions */ +#include "portable.h" + #include -#include -#include -#include -#include "slap.h" -extern Attribute *attr_find(); -extern char **str2charray(); -extern void charray_merge(); +#include +#include +#include -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 index 0000000000..18d5430be4 --- /dev/null +++ b/servers/slapd/schema/core.schema @@ -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 ) ) diff --git a/servers/slapd/search.c b/servers/slapd/search.c index fc96d2fd02..dbdff19a1d 100644 --- a/servers/slapd/search.c +++ b/servers/slapd/search.c @@ -10,33 +10,42 @@ * is provided ``as is'' without express or implied warranty. */ +#include "portable.h" + #include -#include -#include -#include -#include "slap.h" -#include "ldapconfig.h" -extern int get_filter(); -extern Backend *select_backend(); +#include +#include -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 index 0000000000..b3c3ca4ded --- /dev/null +++ b/servers/slapd/slapd.dsw @@ -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 index 0000000000..1facaa2f27 --- /dev/null +++ b/servers/slapd/tools/mimic.c @@ -0,0 +1,64 @@ +/* + * Mimic unused interfaces of slapd... + * needed for linking. + */ +#include "portable.h" + +#include + +#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; +}