From 317d65875d7b6ce3e3ac6b3b67fe12b634d761d9 Mon Sep 17 00:00:00 2001 From: Kurt Zeilenga Date: Fri, 9 Jul 1999 20:02:57 +0000 Subject: [PATCH] Add additional args to send_ldap_result calls. --- servers/slapd/back-bdb2/add.c | 294 +++++++++++++++++ servers/slapd/back-bdb2/alias.c | 320 +++++++++++++++++++ servers/slapd/back-bdb2/bind.c | 298 +++++++++++++++++ servers/slapd/back-bdb2/compare.c | 101 ++++++ servers/slapd/back-bdb2/delete.c | 176 ++++++++++ servers/slapd/back-bdb2/modify.c | 347 ++++++++++++++++++++ servers/slapd/back-bdb2/modrdn.c | 462 +++++++++++++++++++++++++++ servers/slapd/back-bdb2/search.c | 76 ++--- servers/slapd/back-ldap/bind.c | 119 +++++++ servers/slapd/back-ldap/search.c | 2 +- servers/slapd/back-passwd/search.c | 252 +++++++++++---- servers/slapd/back-perl/add.c | 72 +++++ servers/slapd/back-perl/compare.c | 84 +++++ servers/slapd/back-perl/delete.c | 71 ++++ servers/slapd/back-perl/modify.c | 105 ++++++ servers/slapd/back-perl/modrdn.c | 94 ++++++ servers/slapd/back-perl/search.c | 127 ++++++++ servers/slapd/back-perl/unbind.c | 40 +++ servers/slapd/back-shell/add.c | 31 +- servers/slapd/back-shell/bind.c | 31 +- servers/slapd/back-shell/compare.c | 26 +- servers/slapd/back-shell/delete.c | 26 +- servers/slapd/back-shell/modify.c | 45 +-- servers/slapd/back-shell/modrdn.c | 45 ++- servers/slapd/back-shell/result.c | 16 +- servers/slapd/back-shell/search.c | 28 +- servers/slapd/back-shell/unbind.c | 34 +- servers/slapd/back-tcl/tcl_add.c | 70 ++++ servers/slapd/back-tcl/tcl_bind.c | 74 +++++ servers/slapd/back-tcl/tcl_compare.c | 70 ++++ servers/slapd/back-tcl/tcl_delete.c | 66 ++++ servers/slapd/back-tcl/tcl_modify.c | 117 +++++++ servers/slapd/back-tcl/tcl_modrdn.c | 91 ++++++ servers/slapd/back-tcl/tcl_search.c | 87 +++++ servers/slapd/back-tcl/tcl_unbind.c | 58 ++++ servers/slapd/back-tcl/tcl_util.c | 190 +++++++++++ servers/slapd/result.c | 2 +- 37 files changed, 3913 insertions(+), 234 deletions(-) create mode 100644 servers/slapd/back-bdb2/add.c create mode 100644 servers/slapd/back-bdb2/alias.c create mode 100644 servers/slapd/back-bdb2/bind.c create mode 100644 servers/slapd/back-bdb2/compare.c create mode 100644 servers/slapd/back-bdb2/delete.c create mode 100644 servers/slapd/back-bdb2/modify.c create mode 100644 servers/slapd/back-bdb2/modrdn.c create mode 100644 servers/slapd/back-ldap/bind.c create mode 100644 servers/slapd/back-perl/add.c create mode 100644 servers/slapd/back-perl/compare.c create mode 100644 servers/slapd/back-perl/delete.c create mode 100644 servers/slapd/back-perl/modify.c create mode 100644 servers/slapd/back-perl/modrdn.c create mode 100644 servers/slapd/back-perl/search.c create mode 100644 servers/slapd/back-perl/unbind.c create mode 100644 servers/slapd/back-tcl/tcl_add.c create mode 100644 servers/slapd/back-tcl/tcl_bind.c create mode 100644 servers/slapd/back-tcl/tcl_compare.c create mode 100644 servers/slapd/back-tcl/tcl_delete.c create mode 100644 servers/slapd/back-tcl/tcl_modify.c create mode 100644 servers/slapd/back-tcl/tcl_modrdn.c create mode 100644 servers/slapd/back-tcl/tcl_search.c create mode 100644 servers/slapd/back-tcl/tcl_unbind.c create mode 100644 servers/slapd/back-tcl/tcl_util.c diff --git a/servers/slapd/back-bdb2/add.c b/servers/slapd/back-bdb2/add.c new file mode 100644 index 0000000000..da41b7d830 --- /dev/null +++ b/servers/slapd/back-bdb2/add.c @@ -0,0 +1,294 @@ +/* add.c - ldap bdb2 back-end add routine */ + +#include "portable.h" + +#include + +#include +#include + +#include "slap.h" +#include "back-bdb2.h" +#include "proto-back-bdb2.h" + +static DB_LOCK lock; + + +static int +bdb2i_back_add_internal( + BackendDB *be, + Connection *conn, + Operation *op, + Entry *e +) +{ + struct ldbminfo *li = (struct ldbminfo *) be->be_private; + char *pdn; + Entry *p = NULL; + int rc; + struct timeval time1; + + Debug(LDAP_DEBUG_ARGS, "==> bdb2i_back_add: %s\n", e->e_dn, 0, 0); + + if ( ( bdb2i_dn2id( be, e->e_ndn ) ) != NOID ) { + entry_free( e ); + send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, NULL, NULL, NULL ); + return( -1 ); + } + + if ( global_schemacheck && oc_schema_check( e ) != 0 ) { + Debug( LDAP_DEBUG_TRACE, "entry failed schema check\n", + 0, 0, 0 ); + + entry_free( e ); + send_ldap_result( conn, op, LDAP_OBJECT_CLASS_VIOLATION, + NULL, NULL, NULL ); + return( -1 ); + } + + /* + * Get the parent dn and see if the corresponding entry exists. + * If the parent does not exist, only allow the "root" user to + * add the entry. + */ + + 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 = bdb2i_dn2entry_w( be, pdn, &matched )) == NULL ) { + Debug( LDAP_DEBUG_TRACE, "parent does not exist\n", 0, + 0, 0 ); + send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, + matched, NULL, NULL ); + + if ( matched != NULL ) { + free( matched ); + } + + entry_free( e ); + free( pdn ); + return -1; + } + + free(pdn); + + if ( matched != NULL ) { + free( matched ); + } + + 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 ); + + /* free parent and writer lock */ + bdb2i_cache_return_entry_w( &li->li_cache, p ); + + entry_free( e ); + return -1; + } + + } else { + if(pdn != NULL) { + assert( *pdn == '\0' ); + free(pdn); + } + + /* no parent, must be adding entry to root */ + if ( ! be_isroot( be, op->o_ndn ) ) { + Debug( LDAP_DEBUG_TRACE, "%s add denied\n", + pdn == NULL ? "suffix" : "entry at root", + 0, 0 ); + + send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, + NULL, NULL, NULL ); + + entry_free( e ); + return -1; + } + } + + e->e_id = bdb2i_next_id( be ); + + /* + * Try to add the entry to the cache, assign it a new dnid. + */ + bdb2i_start_timing( be->bd_info, &time1 ); + + rc = bdb2i_cache_add_entry_rw( &li->li_cache, e, CACHE_WRITE_LOCK ); + + bdb2i_stop_timing( be->bd_info, time1, "ADD-CACHE", conn, op ); + + if ( rc != 0 ) { + if( p != NULL) { + /* free parent and writer lock */ + bdb2i_cache_return_entry_w( &li->li_cache, p ); + } + + Debug( LDAP_DEBUG_ANY, "cache_add_entry_lock failed\n", 0, 0, + 0 ); + + /* return the id */ + bdb2i_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 ); + } + + return( -1 ); + } + + rc = -1; + + /* + * add it to the id2children index for the parent + */ + + bdb2i_start_timing( be->bd_info, &time1 ); + + if ( bdb2i_id2children_add( be, p, e ) != 0 ) { + Debug( LDAP_DEBUG_TRACE, "bdb2i_id2children_add failed\n", 0, + 0, 0 ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL, NULL ); + + bdb2i_stop_timing( be->bd_info, time1, "ADD-ID2CHILDREN", conn, op ); + + goto return_results; + } + + bdb2i_stop_timing( be->bd_info, time1, "ADD-ID2CHILDREN", conn, op ); + + /* + * Add the entry to the attribute indexes, then add it to + * the id2children index, dn2id index, and the id2entry index. + */ + + bdb2i_start_timing( be->bd_info, &time1 ); + + /* attribute indexes */ + if ( bdb2i_index_add_entry( be, e ) != 0 ) { + Debug( LDAP_DEBUG_TRACE, "bdb2i_index_add_entry failed\n", 0, + 0, 0 ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL, NULL ); + + bdb2i_stop_timing( be->bd_info, time1, "ADD-INDEX", conn, op ); + + goto return_results; + } + + bdb2i_stop_timing( be->bd_info, time1, "ADD-INDEX", conn, op ); + + bdb2i_start_timing( be->bd_info, &time1 ); + + /* dn2id index */ + if ( bdb2i_dn2id_add( be, e->e_ndn, e->e_id ) != 0 ) { + Debug( LDAP_DEBUG_TRACE, "bdb2i_dn2id_add failed\n", 0, + 0, 0 ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL, NULL ); + + bdb2i_stop_timing( be->bd_info, time1, "ADD-DN2ID", conn, op ); + + goto return_results; + } + + bdb2i_stop_timing( be->bd_info, time1, "ADD-DN2ID", conn, op ); + + bdb2i_start_timing( be->bd_info, &time1 ); + + /* id2entry index */ + if ( bdb2i_id2entry_add( be, e ) != 0 ) { + Debug( LDAP_DEBUG_TRACE, "bdb2i_id2entry_add failed\n", 0, + 0, 0 ); + (void) bdb2i_dn2id_delete( be, e->e_ndn ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL, NULL ); + + bdb2i_stop_timing( be->bd_info, time1, "ADD-ID2ENTRY", conn, op ); + + goto return_results; + } + + bdb2i_stop_timing( be->bd_info, time1, "ADD-ID2ENTRY", conn, op ); + + send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL, NULL ); + rc = 0; + +return_results:; + if (p != NULL) { + /* free parent and writer lock */ + bdb2i_cache_return_entry_w( &li->li_cache, p ); + } + + if ( rc ) { + /* free entry and writer lock */ + bdb2i_cache_return_entry_w( &li->li_cache, e ); + } + + return( rc ); +} + + +int +bdb2_back_add( + BackendDB *be, + Connection *conn, + Operation *op, + Entry *e +) +{ + struct ldbminfo *li = (struct ldbminfo *) be->be_private; + struct timeval time1; + int ret; + + bdb2i_start_timing( be->bd_info, &time1 ); + + if ( bdb2i_enter_backend_w( &lock ) != 0 ) { + + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL, NULL ); + return( -1 ); + + } + + /* check, if a new default attribute index will be created, + in which case we have to open the index file BEFORE TP */ + switch ( slapMode ) { + case SLAP_SERVER_MODE: + case SLAP_TIMEDSERVER_MODE: + case SLAP_TOOL_MODE: + case SLAP_TOOLID_MODE: + bdb2i_check_default_attr_index_add( li, e ); + break; + } + + ret = bdb2i_back_add_internal( be, conn, op, e ); + + /* if the operation was successful, we will delay the unlock */ + if ( ret ) + (void) bdb2i_leave_backend_w( lock ); + + bdb2i_stop_timing( be->bd_info, time1, "ADD", conn, op ); + + return( ret ); +} + + +int +bdb2i_release_add_lock( void ) +{ + (void) bdb2i_leave_backend_w( lock ); + return 0; +} + + diff --git a/servers/slapd/back-bdb2/alias.c b/servers/slapd/back-bdb2/alias.c new file mode 100644 index 0000000000..107b5bc984 --- /dev/null +++ b/servers/slapd/back-bdb2/alias.c @@ -0,0 +1,320 @@ +/* + * 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-bdb2.h" +#include "proto-back-bdb2.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 *bdb2i_derefAlias_r ( BackendDB *be, + Connection *conn, + Operation *op, + Entry *e) +{ + /* to free cache entries */ + struct ldbminfo *li = (struct ldbminfo *) be->be_private; + 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 ) { + bdb2i_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 = bdb2i_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 *bdb2i_derefDN ( BackendDB *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 = bdb2i_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 = bdb2i_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 = bdb2i_derefAlias_r( be, conn, op, eMatched )) == NULL) { + free (matched); + matched = NULL; + free (newDN); + newDN = NULL; + free (remainder); + remainder = NULL; + + bdb2i_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 */ + bdb2i_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); + + bdb2i_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 */ + bdb2i_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 */ + bdb2i_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 = bdb2i_dn2entry_r( be, newDN, &matched )) != NULL) { + if ((eDeref = bdb2i_derefAlias_r( be, conn, op, eNew )) != NULL) { + free (newDN); + newDN = ch_strdup (eDeref->e_dn); + /* free reader lock */ + bdb2i_cache_return_entry_r(&li->li_cache, eDeref); + } + /* free reader lock */ + bdb2i_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-bdb2/bind.c b/servers/slapd/back-bdb2/bind.c new file mode 100644 index 0000000000..6bb6006b9e --- /dev/null +++ b/servers/slapd/back-bdb2/bind.c @@ -0,0 +1,298 @@ +/* bind.c - bdb2 backend bind and unbind routines */ + +#include "portable.h" + +#include + +#include +#include +#include +#include + +#include "slap.h" +#include "back-bdb2.h" +#include "proto-back-bdb2.h" + +#include + +#ifdef HAVE_KERBEROS +extern int bdb2i_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 ); +} + +static int +bdb2i_back_bind_internal( + BackendDB *be, + Connection *conn, + Operation *op, + char *dn, + int method, + char *mech, + struct berval *cred, + char** edn +) +{ + struct ldbminfo *li = (struct ldbminfo *) be->be_private; + Entry *e; + Attribute *a; + int rc; + char *matched; +#ifdef HAVE_KERBEROS + char krbname[MAX_K_NAME_SZ + 1]; + AUTH_DAT ad; +#endif + + Debug(LDAP_DEBUG_ARGS, "==> bdb2_back_bind: dn: %s\n", dn, 0, 0); + + *edn = NULL; + + /* get entry with reader lock */ + if ( (e = bdb2i_dn2entry_r( be, dn, &matched )) == NULL ) { + /* allow noauth binds */ + 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 ) ) { + /* front end will send result */ + *edn = ch_strdup( be_root_dn( be ) ); + rc = 0; + + } 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, NULL ); + rc = 1; + } + 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, 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 */ + 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 ) { + send_ldap_result( conn, op, LDAP_INAPPROPRIATE_AUTH, + NULL, NULL, NULL); + + /* stop front end from sending result */ + rc = 1; + goto return_results; + } + + if ( crypted_value_find( a->a_vals, cred, a->a_syntax, 0, cred ) != 0 ) + { + send_ldap_result( conn, op, LDAP_INVALID_CREDENTIALS, + NULL, NULL, NULL); + /* stop front end from sending result */ + rc = 1; + goto return_results; + } + rc = 0; + break; + +#ifdef HAVE_KERBEROS + case LDAP_AUTH_KRBV41: + if ( bdb2i_krbv4_ldap_auth( be, cred, &ad ) != LDAP_SUCCESS ) { + send_ldap_result( conn, op, LDAP_INVALID_CREDENTIALS, + NULL, NULL, NULL); + rc = 1; + goto return_results; + } + + 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; + } + + 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; /* XXX wild ass guess */ + break; + } + send_ldap_result( conn, op, LDAP_INAPPROPRIATE_AUTH, + NULL, NULL, NULL); + 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 ) { + send_ldap_result( conn, op, LDAP_INVALID_CREDENTIALS, + NULL, NULL, NULL); + rc = 1; + goto return_results; + } + } + rc = 0; + break; + + case LDAP_AUTH_KRBV42: + send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL, NULL ); + /* 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", NULL ); + rc = 1; + goto return_results; + } + +return_results:; + /* free entry and reader lock */ + bdb2i_cache_return_entry_r( &li->li_cache, e ); + + /* front end with send result on success (rc==0) */ + return( rc ); +} + + +int +bdb2_back_bind( + BackendDB *be, + Connection *conn, + Operation *op, + char *dn, + int method, + char *mech, + struct berval *cred, + char** edn +) +{ + 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, + NULL, NULL, NULL ); + return( 1 ); + } + + ret = bdb2i_back_bind_internal( be, conn, op, dn, method, mech, cred, edn ); + + (void) bdb2i_leave_backend_r( lock ); + + bdb2i_stop_timing( be->bd_info, time1, "BIND", conn, op ); + + return( ret ); +} + + diff --git a/servers/slapd/back-bdb2/compare.c b/servers/slapd/back-bdb2/compare.c new file mode 100644 index 0000000000..0da11c9194 --- /dev/null +++ b/servers/slapd/back-bdb2/compare.c @@ -0,0 +1,101 @@ +/* compare.c - bdb2 backend compare routine */ + +#include "portable.h" + +#include + +#include +#include + +#include "slap.h" +#include "back-bdb2.h" +#include "proto-back-bdb2.h" + +static int +bdb2i_back_compare_internal( + BackendDB *be, + Connection *conn, + Operation *op, + char *dn, + Ava *ava +) +{ + struct ldbminfo *li = (struct ldbminfo *) be->be_private; + char *matched; + Entry *e; + Attribute *a; + int rc; + + /* get entry with reader lock */ + if ( (e = bdb2i_dn2entry_r( be, dn, &matched )) == NULL ) { + send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, + matched, NULL, NULL ); + + if(matched == NULL) free(matched); + 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, + 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, + NULL, NULL, NULL ); + else + send_ldap_result( conn, op, LDAP_COMPARE_FALSE, + NULL, NULL, NULL ); + + rc = 0; + +return_results:; + bdb2i_cache_return_entry_r( &li->li_cache, e ); + return( rc ); +} + + +int +bdb2_back_compare( + BackendDB *be, + Connection *conn, + Operation *op, + char *dn, + Ava *ava +) +{ + 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, + NULL, NULL, NULL ); + return( 1 ); + + } + + ret = bdb2i_back_compare_internal( be, conn, op, dn, ava ); + (void) bdb2i_leave_backend_r( lock ); + bdb2i_stop_timing( be->bd_info, time1, "CMP", conn, op ); + + return( ret ); +} + + diff --git a/servers/slapd/back-bdb2/delete.c b/servers/slapd/back-bdb2/delete.c new file mode 100644 index 0000000000..04a508afe0 --- /dev/null +++ b/servers/slapd/back-bdb2/delete.c @@ -0,0 +1,176 @@ +/* delete.c - bdb2 backend delete routine */ + +#include "portable.h" + +#include + +#include +#include + +#include "slap.h" +#include "back-bdb2.h" +#include "proto-back-bdb2.h" + +static int +bdb2i_back_delete_internal( + BackendDB *be, + Connection *conn, + Operation *op, + char *dn +) +{ + struct ldbminfo *li = (struct ldbminfo *) be->be_private; + char *matched = NULL; + char *pdn = NULL; + Entry *e, *p = NULL; + int rc = -1; + + Debug(LDAP_DEBUG_ARGS, "==> bdb2i_back_delete: %s\n", dn, 0, 0); + + /* get entry with writer lock */ + if ( (e = bdb2i_dn2entry_w( be, dn, &matched )) == NULL ) { + Debug(LDAP_DEBUG_ARGS, "<=- bdb2i_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 ( bdb2i_has_children( be, e ) ) { + Debug(LDAP_DEBUG_ARGS, "<=- bdb2i_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; + } + +#ifdef SLAPD_CHILD_MODIFICATION_WITH_ENTRY_ACL + if ( ! access_allowed( be, conn, op, e, + "entry", NULL, ACL_WRITE ) ) + { + Debug(LDAP_DEBUG_ARGS, + "<=- bdb2i_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 = bdb2i_dn2entry_w( be, pdn, &matched )) == NULL) { + Debug( LDAP_DEBUG_TRACE, + "<=- bdb2i_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, + "<=- bdb2i_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, + "<=- bdb2i_back_delete: no parent & not root\n", 0, 0, 0); + send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, + NULL, NULL, NULL ); + goto return_results; + } + } + + if ( bdb2i_id2children_remove( be, p, e ) != 0 ) { + Debug(LDAP_DEBUG_ARGS, + "<=- bdb2i_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 ( bdb2i_dn2id_delete( be, e->e_ndn ) != 0 ) { + Debug(LDAP_DEBUG_ARGS, + "<=- bdb2i_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 ( bdb2i_id2entry_delete( be, e ) != 0 ) { + Debug(LDAP_DEBUG_ARGS, + "<=- bdb2i_back_delete: operations error %s\n", + dn, 0, 0); + 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 ( pdn != NULL ) free(pdn); + + if( p != NULL ) { + /* free parent and writer lock */ + bdb2i_cache_return_entry_w( &li->li_cache, p ); + + } + + /* free entry and writer lock */ + bdb2i_cache_return_entry_w( &li->li_cache, e ); + + if ( matched != NULL ) free(matched); + + return rc; +} + + +int +bdb2_back_delete( + BackendDB *be, + Connection *conn, + Operation *op, + char *dn +) +{ + 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_w( &lock ) != 0 ) { + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL ); + return( -1 ); + + } + + ret = bdb2i_back_delete_internal( be, conn, op, dn ); + (void) bdb2i_leave_backend_w( lock ); + bdb2i_stop_timing( be->bd_info, time1, "DEL", conn, op ); + + return( ret ); +} + + diff --git a/servers/slapd/back-bdb2/modify.c b/servers/slapd/back-bdb2/modify.c new file mode 100644 index 0000000000..61a3a7201c --- /dev/null +++ b/servers/slapd/back-bdb2/modify.c @@ -0,0 +1,347 @@ +/* modify.c - bdb2 backend modify routine */ + +#include "portable.h" + +#include + +#include +#include + +#include "slap.h" +#include "back-bdb2.h" +#include "proto-back-bdb2.h" + + +static void add_lastmods(Operation *op, LDAPModList **ml); + + +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; + +} + +int +bdb2i_back_modify_internal( + BackendDB *be, + Connection *conn, + Operation *op, + char *dn, + LDAPModList *modlist, + Entry *e +) +{ + struct ldbminfo *li = (struct ldbminfo *) be->be_private; + LDAPModList *ml; + int err; + + Debug(LDAP_DEBUG_ARGS, "bdb2i_back_modify:\n", 0, 0, 0); + + if ( (err = acl_check_modlist( be, conn, op, e, modlist )) != LDAP_SUCCESS ) { + send_ldap_result( conn, op, err, NULL, NULL, NULL ); + goto error_return; + } + + for ( ml = modlist; ml != NULL; ml = ml->ml_next ) { + LDAPMod *mod = &ml->ml_mod; + + switch ( mod->mod_op & ~LDAP_MOD_BVALUES ) { + case LDAP_MOD_ADD: + err = bdb2i_add_values( e, mod, op->o_ndn ); + break; + + case LDAP_MOD_DELETE: + err = bdb2i_delete_values( e, mod, op->o_ndn ); + break; + + case LDAP_MOD_REPLACE: + err = bdb2i_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 = bdb2i_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, NULL ); + goto error_return; + } + } + + /* check that the entry still obeys the schema */ + if ( global_schemacheck && oc_schema_check( e ) != 0 ) { + Debug( LDAP_DEBUG_ANY, "entry failed schema check\n", 0, 0, 0 ); + send_ldap_result( conn, op, LDAP_OBJECT_CLASS_VIOLATION, + NULL, NULL, NULL ); + goto error_return; + } + + /* check for abandon */ + ldap_pvt_thread_mutex_lock( &op->o_abandonmutex ); + if ( op->o_abandon ) { + ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex ); + goto error_return; + } + ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex ); + + /* modify indexes */ + if ( bdb2i_index_add_mods( be, modlist, e->e_id ) != 0 ) { + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL ); + goto error_return; + } + + /* check for abandon */ + ldap_pvt_thread_mutex_lock( &op->o_abandonmutex ); + if ( op->o_abandon ) { + ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex ); + goto error_return; + } + ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex ); + + /* change the entry itself */ + if ( bdb2i_id2entry_add( be, e ) != 0 ) { + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL ); + goto error_return; + } + + send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL, NULL ); + bdb2i_cache_return_entry_w( &li->li_cache, e ); + return( 0 ); + +error_return:; + bdb2i_cache_return_entry_w( &li->li_cache, e ); + return( -1 ); +} + + +int +bdb2_back_modify( + BackendDB *be, + Connection *conn, + Operation *op, + char *dn, + LDAPModList *modlist +) +{ + DB_LOCK lock; + struct ldbminfo *li = (struct ldbminfo *) be->be_private; + struct timeval time1; + int ret; + char *matched; + Entry *e; + + bdb2i_start_timing( be->bd_info, &time1 ); + + if ( bdb2i_enter_backend_w( &lock ) != 0 ) { + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL ); + return( -1 ); + } + + /* check, if a new default attribute index will be created, + in which case we have to open the index file BEFORE TP */ + switch ( slapMode ) { + case SLAP_SERVER_MODE: + case SLAP_TIMEDSERVER_MODE: + case SLAP_TOOL_MODE: + case SLAP_TOOLID_MODE: + bdb2i_check_default_attr_index_mod( li, modlist ); + break; + } + + if ( (e = bdb2i_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 ); + } + + ret = bdb2i_back_modify_internal( be, conn, op, dn, modlist, e ); + (void) bdb2i_leave_backend_w( lock ); + bdb2i_stop_timing( be->bd_info, time1, "MOD", conn, op ); + + return( ret ); +} + + +int +bdb2i_add_values( + Entry *e, + LDAPMod *mod, + char *dn +) +{ + int i; + Attribute *a; + + /* check if the values we're adding already exist */ + if ( (a = attr_find( e->e_attrs, mod->mod_type )) != NULL ) { + for ( i = 0; mod->mod_bvalues[i] != NULL; i++ ) { + if ( value_find( a->a_vals, mod->mod_bvalues[i], + a->a_syntax, 3 ) == 0 ) { + return( LDAP_TYPE_OR_VALUE_EXISTS ); + } + } + } + + /* no - add them */ + if( attr_merge( e, mod->mod_type, mod->mod_bvalues ) != 0 ) { + return( LDAP_CONSTRAINT_VIOLATION ); + } + + return( LDAP_SUCCESS ); +} + +int +bdb2i_delete_values( + Entry *e, + LDAPMod *mod, + char *dn +) +{ + int i, j, k, found; + Attribute *a; + + /* delete the entire attribute */ + if ( mod->mod_bvalues == NULL ) { + Debug( LDAP_DEBUG_ARGS, "removing entire attribute %s\n", + mod->mod_type, 0, 0 ); + return( attr_delete( &e->e_attrs, mod->mod_type ) ? + LDAP_NO_SUCH_ATTRIBUTE : LDAP_SUCCESS ); + } + + /* delete specific values - find the attribute first */ + if ( (a = attr_find( e->e_attrs, mod->mod_type )) == NULL ) { + Debug( LDAP_DEBUG_ARGS, "could not find attribute %s\n", + mod->mod_type, 0, 0 ); + return( LDAP_NO_SUCH_ATTRIBUTE ); + } + + /* find each value to delete */ + for ( i = 0; mod->mod_bvalues[i] != NULL; i++ ) { + found = 0; + for ( j = 0; a->a_vals[j] != NULL; j++ ) { + if ( value_cmp( mod->mod_bvalues[i], a->a_vals[j], + a->a_syntax, 3 ) != 0 ) { + continue; + } + found = 1; + + /* found a matching value - delete it */ + ber_bvfree( a->a_vals[j] ); + for ( k = j + 1; a->a_vals[k] != NULL; k++ ) { + a->a_vals[k - 1] = a->a_vals[k]; + } + a->a_vals[k - 1] = NULL; + break; + } + + /* looked through them all w/o finding it */ + if ( ! found ) { + Debug( LDAP_DEBUG_ARGS, + "could not find value for attr %s\n", + mod->mod_type, 0, 0 ); + return( LDAP_NO_SUCH_ATTRIBUTE ); + } + } + + return( LDAP_SUCCESS ); +} + +int +bdb2i_replace_values( + Entry *e, + LDAPMod *mod, + char *dn +) +{ + (void) attr_delete( &e->e_attrs, mod->mod_type ); + + if ( attr_merge( e, mod->mod_type, mod->mod_bvalues ) != 0 ) { + return( LDAP_CONSTRAINT_VIOLATION ); + } + + return( LDAP_SUCCESS ); +} diff --git a/servers/slapd/back-bdb2/modrdn.c b/servers/slapd/back-bdb2/modrdn.c new file mode 100644 index 0000000000..0aca35b508 --- /dev/null +++ b/servers/slapd/back-bdb2/modrdn.c @@ -0,0 +1,462 @@ +/* modrdn.c - bdb2 backend modrdn routine */ + +/* + * 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 "slap.h" +#include "back-bdb2.h" +#include "proto-back-bdb2.h" + +static int +bdb2i_back_modrdn_internal( + BackendDB *be, + Connection *conn, + Operation *op, + char *dn, + char *newrdn, + int deleteoldrdn, + char *newSuperior +) +{ + struct ldbminfo *li = (struct ldbminfo *) be->be_private; + char *matched = NULL; + char *p_dn = NULL, *p_ndn = NULL; + char *new_dn = NULL, *new_ndn = NULL; + char sep[2]; + Entry *e, *p = NULL; + 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 */ + 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 */ + /* 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 */ + + Debug( LDAP_DEBUG_TRACE, "==>ldbm_back_modrdn(newSuperior=%s)\n", + (newSuperior ? newSuperior : "NULL"), + 0, 0 ); + + /* get entry with writer lock */ + if ( (e = bdb2i_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 ); + } + +#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, + NULL, NULL, NULL ); + goto return_results; + } +#endif + + if ( (p_ndn = dn_parent( be, e->e_ndn )) != NULL ) { + /* parent + rdn + separator(s) + null */ + if( (p = bdb2i_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; + } + + p_dn = dn_parent( be, e->e_dn ); + + Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: parent dn=%s\n", + p_dn, 0, 0 ); + + + } else { + /* 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; + } + + Debug( LDAP_DEBUG_TRACE, + "ldbm_back_modrdn: no parent!, working on root\n", + 0, 0, 0 ); + + } + + 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 = bdb2i_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; + + } + + /* 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 ( (bdb2i_dn2id ( be, new_ndn ) ) != NOID ) { + send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, NULL, NULL, NULL ); + goto return_results; + } + + /* check for abandon */ + ldap_pvt_thread_mutex_lock( &op->o_abandonmutex ); + if ( op->o_abandon ) { + ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex ); + goto return_results; + } + ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex ); + + /* delete old one */ + if ( bdb2i_dn2id_delete( be, e->e_ndn ) != 0 ) { + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL ); + goto return_results; + } + + (void) bdb2i_cache_delete_entry( &li->li_cache, e ); + free( e->e_dn ); + free( e->e_ndn ); + e->e_dn = new_dn; + e->e_ndn = new_ndn; + + + /* add new one */ + if ( bdb2i_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; + + Debug( LDAP_DEBUG_TRACE, + "ldbm_back_modrdn: adding new rdn attr val =%s\n", + new_rdn_val, 0, 0 ); + + /* Remove old rdn value if required */ + + if (deleteoldrdn) { + + del_bvals[0] = &del_bv; /* Array of bervals */ + del_bvals[1] = NULL; + /* 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; + + + } + + /* Remove old value of rdn as an attribute. */ + + del_bv.bv_val = old_rdn_val; + del_bv.bv_len = strlen(old_rdn_val); + + 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 ); + + } + + /* modify memory copy of entry */ + if ( bdb2i_back_modify_internal( be, conn, op, dn, &mod[0], e ) + != 0 ) { + + goto return_results; + + } + + (void) bdb2i_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 ( bdb2i_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_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 */ + bdb2i_cache_return_entry_w( &li->li_cache, p ); + + } + + /* free entry and writer lock */ + bdb2i_cache_return_entry_w( &li->li_cache, e ); + return( rc ); +} + + +int +bdb2_back_modrdn( + BackendDB *be, + Connection *conn, + Operation *op, + char *dn, + char *newrdn, + int deleteoldrdn, + char *newSuperior +) +{ + 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_w( &lock ) != 0 ) { + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL ); + return( -1 ); + + } + + ret = bdb2i_back_modrdn_internal( be, conn, op, dn, + newrdn, deleteoldrdn, + newSuperior ); + + (void) bdb2i_leave_backend_w( lock ); + bdb2i_stop_timing( be->bd_info, time1, "MODRDN", conn, op ); + + return( ret ); +} + + diff --git a/servers/slapd/back-bdb2/search.c b/servers/slapd/back-bdb2/search.c index 9ae5992917..49335a61ad 100644 --- a/servers/slapd/back-bdb2/search.c +++ b/servers/slapd/back-bdb2/search.c @@ -50,9 +50,8 @@ bdb2i_back_search_internal( ID id; Entry *e; Attribute *ref; + struct berval **refs; char *matched = NULL; - int rmaxsize, nrefs; - char *rbuf, *rcur; int nentries = 0; char *realBase; @@ -108,8 +107,8 @@ bdb2i_back_search_internal( break; default: - send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, "", - "Bad scope" ); + send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, + NULL, "Bad scope", NULL ); if( realBase != NULL) { free( realBase ); } @@ -118,7 +117,7 @@ bdb2i_back_search_internal( /* 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 ); } @@ -132,12 +131,8 @@ bdb2i_back_search_internal( free( matched ); } - rmaxsize = 0; - nrefs = 0; - rbuf = rcur = NULL; - MAKE_SPACE( sizeof("Referral:") + 1 ); - strcpy( rbuf, "Referral:" ); - rcur = strchr( rbuf, '\0' ); + refs = NULL; + for ( id = bdb2i_idl_firstid( candidates ); id != NOID; id = bdb2i_idl_nextid( candidates, id ) ) { /* check for abandon */ @@ -145,7 +140,7 @@ bdb2i_back_search_internal( if ( op->o_abandon ) { ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex ); bdb2i_idl_free( candidates ); - free( rbuf ); + ber_bvecfree( refs ); if( realBase != NULL) { free( realBase ); } @@ -155,11 +150,10 @@ bdb2i_back_search_internal( /* check time limit */ if ( tlimit != -1 && slap_get_time() > stoptime ) { - send_search_result( conn, op, - LDAP_TIMELIMIT_EXCEEDED, NULL, nrefs > 0 ? rbuf : - NULL, nentries ); + send_search_result( conn, op, LDAP_TIMELIMIT_EXCEEDED, + NULL, NULL, refs, nentries ); bdb2i_idl_free( candidates ); - free( rbuf ); + ber_bvecfree( refs ); if( realBase != NULL) { free( realBase ); } @@ -183,27 +177,8 @@ bdb2i_back_search_internal( 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 ); - } - } + send_search_reference( be, conn, op, + e, ref->a_vals, &refs ); /* otherwise it's an entry - see if it matches the filter */ } else { @@ -234,11 +209,10 @@ bdb2i_back_search_internal( /* 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 ); + send_search_result( conn, op, LDAP_SIZELIMIT_EXCEEDED, + NULL, NULL, refs, nentries ); bdb2i_idl_free( candidates ); - free( rbuf ); + ber_bvecfree( refs ); if( realBase != NULL) { free( realBase ); @@ -278,7 +252,7 @@ bdb2i_back_search_internal( case -1: /* connection closed */ bdb2i_cache_return_entry_r( &li->li_cache, e ); bdb2i_idl_free( candidates ); - free( rbuf ); + ber_bvecfree( refs ); if( realBase != NULL) { free( realBase ); @@ -298,14 +272,12 @@ bdb2i_back_search_internal( 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 ); + + send_search_result( conn, op, + refs == NULL ? LDAP_SUCCESS : LDAP_REFERRAL, + NULL, NULL, refs, nentries ); + + ber_bvecfree( refs ); if( realBase != NULL) { free( realBase ); @@ -339,8 +311,8 @@ bdb2_back_search( bdb2i_start_timing( be->bd_info, &time1 ); if ( bdb2i_enter_backend_r( &lock ) != 0 ) { - - send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, NULL, NULL ); return( -1 ); } diff --git a/servers/slapd/back-ldap/bind.c b/servers/slapd/back-ldap/bind.c new file mode 100644 index 0000000000..a0352f17c4 --- /dev/null +++ b/servers/slapd/back-ldap/bind.c @@ -0,0 +1,119 @@ +/* bind.c - ldap backend bind 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 "slap.h" +#include "back-ldap.h" + +int +ldap_back_bind( + Backend *be, + Connection *conn, + Operation *op, + char *dn, + int method, + char *mech, + struct berval *cred, + char **edn +) +{ + struct ldapinfo *li = (struct ldapinfo *) be->be_private; + struct ldapconn *lc; + + *edn = NULL; + + lc = ldap_back_getconn(li, conn, op); + if (!lc) + return( -1 ); + + if (ldap_bind_s(lc->ld, dn, cred->bv_val, method) != LDAP_SUCCESS) + return( ldap_back_op_result(lc, op) ); + + lc->bound = 1; + return( 0 ); +} + +struct ldapconn * +ldap_back_getconn(struct ldapinfo *li, Connection *conn, Operation *op) +{ + struct ldapconn *lc; + LDAP *ld; + + ldap_pvt_thread_mutex_lock( &li->conn_mutex ); + for (lc = li->lcs; lc; lc=lc->next) + if (lc->conn == conn) + break; + ldap_pvt_thread_mutex_unlock( &li->conn_mutex ); + + /* Looks like we didn't get a bind. Open a new session... */ + if (!lc) { + ld = ldap_init(li->host, li->port); + if (!ld) { + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, "ldap_init failed", NULL ); + return( NULL ); + } + lc = (struct ldapconn *)ch_malloc(sizeof(struct ldapconn)); + lc->conn = conn; + lc->ld = ld; + lc->bound = 0; + ldap_pvt_thread_mutex_lock( &li->conn_mutex ); + lc->next = li->lcs; + li->lcs = lc; + ldap_pvt_thread_mutex_unlock( &li->conn_mutex ); + } + return( lc ); +} + +ldap_back_dobind(struct ldapconn *lc, Operation *op) +{ + if (lc->bound) + return; + + if (ldap_bind_s(lc->ld, lc->conn->c_cdn, NULL, LDAP_AUTH_SIMPLE) != + LDAP_SUCCESS) + ldap_back_op_result(lc, op); + else + lc->bound = 1; +} + +ldap_back_op_result(struct ldapconn *lc, Operation *op) +{ + int err; + char *msg; + char *match; + + ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, &err); + ldap_get_option(lc->ld, LDAP_OPT_ERROR_STRING, &msg); + ldap_get_option(lc->ld, LDAP_OPT_MATCHED_DN, &match); + send_ldap_result( lc->conn, op, err, match, msg, NULL ); + free(match); + free(msg); + return( (err==LDAP_SUCCESS) ? 0 : -1 ); +} diff --git a/servers/slapd/back-ldap/search.c b/servers/slapd/back-ldap/search.c index 7654bd3b2d..b0f0930ad4 100644 --- a/servers/slapd/back-ldap/search.c +++ b/servers/slapd/back-ldap/search.c @@ -116,7 +116,7 @@ fail: return( ldap_back_op_result(lc, op) ); if (rc == -1) goto fail; - send_search_result( conn, op, sres, match, err, i ); + send_search_result( conn, op, sres, match, err, NULL, i ); if (match) free(match); if (err) diff --git a/servers/slapd/back-passwd/search.c b/servers/slapd/back-passwd/search.c index 11c1d8e719..752517c1ca 100644 --- a/servers/slapd/back-passwd/search.c +++ b/servers/slapd/back-passwd/search.c @@ -1,18 +1,23 @@ /* search.c - /etc/passwd backend search function */ +#include "portable.h" + #include -#include -#include -#include -#include + +#include +#include +#include +#include + #include -#include "portable.h" -#include "slap.h" -extern time_t currenttime; -extern pthread_mutex_t currenttime_mutex; +#include "slap.h" +#include "external.h" -static Entry *pw2entry(); +static Entry *pw2entry( + Backend *be, + struct passwd *pw, + char *rdn); int passwd_back_search( @@ -30,10 +35,17 @@ passwd_back_search( int attrsonly ) { + int sent = 0; struct passwd *pw; Entry *e; char *s; time_t stoptime; + int err = LDAP_NO_SUCH_OBJECT; + + char *rdn = NULL; + char *parent = NULL; + char *matched = NULL; + char *user = NULL; tlimit = (tlimit > be->be_timelimit || tlimit < 1) ? be->be_timelimit : tlimit; @@ -41,81 +53,154 @@ passwd_back_search( slimit = (slimit > be->be_sizelimit || slimit < 1) ? be->be_sizelimit : slimit; + endpwent(); + #ifdef HAVE_SETPWFILE if ( be->be_private != NULL ) { - endpwent(); (void) setpwfile( (char *) be->be_private ); } #endif /* HAVE_SETPWFILE */ - if ( scope == LDAP_SCOPE_BASE ) { - if ( (s = strchr( base, '@' )) != NULL ) { - *s = '\0'; - } + /* Handle a query for the base of this backend */ + if ( be_issuffix( be, base ) ) { + struct berval val, *vals[2]; - if ( (pw = getpwnam( base )) == NULL ) { - send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, - s != NULL ? s + 1 : NULL, NULL ); - return( -1 ); + vals[0] = &val; + vals[1] = NULL; + + /* Create an entry corresponding to the base DN */ + e = (Entry *) ch_calloc(1, sizeof(Entry)); + e->e_attrs = NULL; + e->e_dn = strdup(base); + + /* Use the first attribute of the DN + * as an attribute within the entry itself. + */ + rdn = dn_rdn(NULL, base); + + if( rdn == NULL || (s = strchr(rdn, '=')) == NULL ) { + err = LDAP_INVALID_DN_SYNTAX; + goto done; } - e = pw2entry( be, pw ); + val.bv_val = rdn_attr_value(rdn); + val.bv_len = strlen( val.bv_val ); + attr_merge( e, rdn_attr_type(rdn), vals ); + + free(rdn); + rdn = NULL; + + /* Every entry needs an objectclass. We don't really + * know if our hardcoded choice here agrees with the + * DN that was configured for this backend, but it's + * better than nothing. + * + * should be a configuratable item + */ + val.bv_val = "organizationalUnit"; + val.bv_len = strlen( val.bv_val ); + attr_merge( e, "objectClass", vals ); + if ( test_filter( be, conn, op, e, filter ) == 0 ) { - send_search_entry( be, conn, op, e, attrs, attrsonly ); + send_search_entry( be, conn, op, e, attrs, attrsonly, 0 ); + matched = strdup( be->be_suffix[0] ); + sent++; } - entry_free( e ); - send_ldap_result( conn, op, LDAP_SUCCESS, "", "" ); + if ( scope != LDAP_SCOPE_BASE ) { + /* check all our "children" */ - return( 0 ); - } + for ( pw = getpwent(); pw != NULL; pw = getpwent() ) { + /* check for abandon */ + ldap_pvt_thread_mutex_lock( &op->o_abandonmutex ); + if ( op->o_abandon ) { + ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex ); + endpwent(); + return( -1 ); + } + ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex ); + + /* check time limit */ + if ( slap_get_time() > stoptime ) { + send_ldap_result( conn, op, LDAP_TIMELIMIT_EXCEEDED, + NULL, NULL, NULL ); + endpwent(); + return( 0 ); + } + + e = pw2entry( be, pw, NULL ); - for ( pw = getpwent(); pw != NULL; pw = getpwent() ) { - /* check for abandon */ - pthread_mutex_lock( &op->o_abandonmutex ); - if ( op->o_abandon ) { - pthread_mutex_unlock( &op->o_abandonmutex ); + if ( test_filter( be, conn, op, e, filter ) == 0 ) { + /* check size limit */ + if ( --slimit == -1 ) { + send_ldap_result( conn, op, LDAP_SIZELIMIT_EXCEEDED, + NULL, NULL, NULL ); + endpwent(); + return( 0 ); + } + + send_search_entry( be, conn, op, e, attrs, attrsonly, 0 ); + sent++; + } + + entry_free( e ); + } endpwent(); - return( -1 ); } - pthread_mutex_unlock( &op->o_abandonmutex ); - /* check size limit */ - if ( --slimit == -1 ) { - send_ldap_result( conn, op, LDAP_SIZELIMIT_EXCEEDED, - NULL, NULL ); - endpwent(); - return( 0 ); + } else { + parent = dn_parent( be, base ); + + /* This backend is only one layer deep. Don't answer requests for + * anything deeper than that. + */ + if( !be_issuffix( be, parent ) ) { + goto done; } - /* check time limit */ - pthread_mutex_lock( ¤ttime_mutex ); - time( ¤ttime ); - if ( currenttime > stoptime ) { - pthread_mutex_unlock( ¤ttime_mutex ); - send_ldap_result( conn, op, LDAP_TIMELIMIT_EXCEEDED, - NULL, NULL ); - endpwent(); - return( 0 ); + rdn = dn_rdn( NULL, base ); + + if ( (user = rdn_attr_value(rdn)) == NULL) { + err = LDAP_INVALID_DN_SYNTAX; + goto done; + } + + for( s = user; *s ; s++ ) { + *s = TOLOWER( *s ); + } + + if ( (pw = getpwnam( user )) == NULL ) { + goto done; } - pthread_mutex_unlock( ¤ttime_mutex ); - e = pw2entry( be, pw ); + e = pw2entry( be, pw, rdn ); if ( test_filter( be, conn, op, e, filter ) == 0 ) { - send_search_entry( be, conn, op, e, attrs, attrsonly ); + send_search_entry( be, conn, op, e, attrs, attrsonly, 0 ); + sent++; } entry_free( e ); } - endpwent(); - send_ldap_result( conn, op, LDAP_SUCCESS, "", "" ); + +done: + if( sent ) { + send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL, NULL ); + + } else { + send_ldap_result( conn, op, err, matched, NULL, NULL); + } + + if( matched != NULL ) free( matched ); + if( parent != NULL ) free( parent ); + if( rdn != NULL ) free( rdn ); + if( user != NULL ) free( user ); return( 0 ); } static Entry * -pw2entry( Backend *be, struct passwd *pw ) +pw2entry( Backend *be, struct passwd *pw, char *rdn ) { Entry *e; char buf[256]; @@ -126,28 +211,69 @@ pw2entry( Backend *be, struct passwd *pw ) vals[1] = NULL; /* - * from pw we get pw_name and make it uid and cn and sn and - * we get pw_gecos and make it cn and we give it an objectclass - * of person. + * from pw we get pw_name and make it cn + * give it an objectclass of person. */ e = (Entry *) ch_calloc( 1, sizeof(Entry) ); e->e_attrs = NULL; - sprintf( buf, "%s@%s", pw->pw_name, be->be_suffix[0] ); - e->e_dn = strdup( buf ); + /* rdn attribute type should be a configuratable item */ + sprintf( buf, "uid=%s,%s", pw->pw_name, be->be_suffix[0] ); + e->e_dn = ch_strdup( buf ); + e->e_ndn = dn_normalize_case( ch_strdup( buf ) ); val.bv_val = pw->pw_name; val.bv_len = strlen( pw->pw_name ); - attr_merge( e, "cn", vals ); - attr_merge( e, "sn", vals ); - attr_merge( e, "uid", vals ); - val.bv_val = pw->pw_gecos; - val.bv_len = strlen( pw->pw_gecos ); - attr_merge( e, "cn", vals ); + attr_merge( e, "uid", vals ); /* required by uidObject */ + attr_merge( e, "cn", vals ); /* required by person */ + attr_merge( e, "sn", vals ); /* required by person */ + +#ifdef HAVE_PW_GECOS + /* + * if gecos is present, add it as a cn. first process it + * according to standard BSD usage. If the processed cn has + * a space, use the tail as the surname. + */ + if (pw->pw_gecos[0]) { + char *s; + + val.bv_val = pw->pw_gecos; + val.bv_len = strlen(val.bv_val); + attr_merge(e, "description", vals); + + s = strchr(val.bv_val, ','); + if (s) + *s = '\0'; + s = strchr(val.bv_val, '&'); + if (s) { + int i = s - val.bv_val; + strncpy(buf, val.bv_val, i); + s = buf+i; + strcpy(s, pw->pw_name); + if (islower(*s)) + *s = toupper(*s); + strcat(s, val.bv_val+i+1); + val.bv_val = buf; + } + val.bv_len = strlen(val.bv_val); + if ( strcmp( val.bv_val, pw->pw_name )) + attr_merge( e, "cn", vals ); + if ( (s=strrchr(val.bv_val, ' '))) { + val.bv_val = s + 1; + val.bv_len = strlen(val.bv_val); + attr_merge(e, "sn", vals); + } + } +#endif + + /* objectclasses should be configuratable items */ val.bv_val = "person"; val.bv_len = strlen( val.bv_val ); attr_merge( e, "objectclass", vals ); + val.bv_val = "uidObject"; + val.bv_len = strlen( val.bv_val ); + attr_merge( e, "objectclass", vals ); return( e ); } diff --git a/servers/slapd/back-perl/add.c b/servers/slapd/back-perl/add.c new file mode 100644 index 0000000000..4e9fa2d1a0 --- /dev/null +++ b/servers/slapd/back-perl/add.c @@ -0,0 +1,72 @@ +/* + * Copyright 1999, John C. Quillan, 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 +*/ + +#include +#include + +#include "slap.h" +#include "perl_back.h" + +int +perl_back_add( + Backend *be, + Connection *conn, + Operation *op, + Entry *e +) +{ + int len; + int count; + int return_code; + + PerlBackend *perl_back = (PerlBackend *) be->be_private; + + ldap_pvt_thread_mutex_lock( &perl_interpreter_mutex ); + + { + dSP; ENTER; SAVETMPS; + + PUSHMARK(sp); + XPUSHs( perl_back->pb_obj_ref ); + XPUSHs(sv_2mortal(newSVpv( entry2str( e, &len, 0 ), 0 ))); + + PUTBACK; + + count = perl_call_method("add", G_SCALAR); + + SPAGAIN; + + if (count != 1) { + croak("Big trouble in back_search\n"); + } + + return_code = POPi; + + PUTBACK; FREETMPS; LEAVE; + } + + ldap_pvt_thread_mutex_unlock( &perl_interpreter_mutex ); + + if( return_code != 0 ) { + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL, NULL ); + + } else { + send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL, NULL ); + } + + Debug( LDAP_DEBUG_ANY, "Here ADD\n", 0, 0, 0 ); + return( 0 ); +} diff --git a/servers/slapd/back-perl/compare.c b/servers/slapd/back-perl/compare.c new file mode 100644 index 0000000000..d66d94fd2b --- /dev/null +++ b/servers/slapd/back-perl/compare.c @@ -0,0 +1,84 @@ +/* + * Copyright 1999, John C. Quillan, 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 +*/ + +#include +#include + +#include "slap.h" +#include "perl_back.h" + +/********************************************************** + * + * Compare + * + **********************************************************/ + +perl_back_compare( + Backend *be, + Connection *conn, + Operation *op, + char *dn, + Ava *ava +) +{ + int return_code; + int count; + + PerlBackend *perl_back = (PerlBackend *)be->be_private; + + send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, + NULL, "not yet implemented", NULL ); + +#ifdef notdef + ldap_pvt_thread_mutex_lock( &perl_interpreter_mutex ); + + { + dSP; ENTER; SAVETMPS; + + PUSHMARK(sp); + XPUSHs( perl_back->pb_obj_ref ); + XPUSHs(sv_2mortal(newSVpv( dn , 0))); + /* XPUSHs(sv_2mortal(newSVpv( cred->bv_val , cred->bv_len))); */ + PUTBACK; + + count = perl_call_method("bind", G_SCALAR); + + SPAGAIN; + + if (count != 1) { + croak("Big trouble in back_search\n"); + } + + return_code = POPi; + + PUTBACK; FREETMPS; LEAVE; + } + + ldap_pvt_thread_mutex_unlock( &perl_interpreter_mutex ); + + if( return_code != 0 ) { + send_ldap_result( conn, op, LDAP_COMPARE_TRUE, NULL, NULL ); + + } else { + send_ldap_result( conn, op, LDAP_COMPARE_FALSE, NULL, NULL ); + } +#endif + + Debug( LDAP_DEBUG_ANY, "Here BIND\n", 0, 0, 0 ); + + return (0); +} + diff --git a/servers/slapd/back-perl/delete.c b/servers/slapd/back-perl/delete.c new file mode 100644 index 0000000000..f32b38eb2e --- /dev/null +++ b/servers/slapd/back-perl/delete.c @@ -0,0 +1,71 @@ +/* + * Copyright 1999, John C. Quillan, 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 +*/ + +#include +#include + +#include "slap.h" +#include "perl_back.h" + +perl_back_delete( + Backend *be, + Connection *conn, + Operation *op, + char *dn +) +{ + int len; + int count; + int return_code; + + PerlBackend *perl_back = (PerlBackend *) be->be_private; + + ldap_pvt_thread_mutex_lock( &perl_interpreter_mutex ); + + { + dSP; ENTER; SAVETMPS; + + PUSHMARK(sp); + XPUSHs( perl_back->pb_obj_ref ); + XPUSHs(sv_2mortal(newSVpv( dn , 0 ))); + + PUTBACK; + + count = perl_call_method("delete", G_SCALAR); + + SPAGAIN; + + if (count != 1) { + croak("Big trouble in perl-back_delete\n"); + } + + return_code = POPi; + + PUTBACK; FREETMPS; LEAVE; + } + + ldap_pvt_thread_mutex_unlock( &perl_interpreter_mutex ); + + if( return_code != 0 ) { + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL, NULL ); + + } else { + send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL, NULL ); + } + + Debug( LDAP_DEBUG_ANY, "Here DELETE\n", 0, 0, 0 ); + return( 0 ); +} diff --git a/servers/slapd/back-perl/modify.c b/servers/slapd/back-perl/modify.c new file mode 100644 index 0000000000..19a83c412b --- /dev/null +++ b/servers/slapd/back-perl/modify.c @@ -0,0 +1,105 @@ +/* + * Copyright 1999, John C. Quillan, 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 +*/ + +#include +#include + +#include "slap.h" +#include "perl_back.h" + +int +perl_back_modify( + Backend *be, + Connection *conn, + Operation *op, + char *dn, + LDAPModList *modlist +) +{ + char test[500]; + int return_code; + int count; + int i; + int err = 0; + char *matched = NULL, *info = NULL; + + PerlBackend *perl_back = (PerlBackend *)be->be_private; + + ldap_pvt_thread_mutex_lock( &perl_interpreter_mutex ); + + { + dSP; ENTER; SAVETMPS; + + PUSHMARK(sp); + XPUSHs( perl_back->pb_obj_ref ); + XPUSHs(sv_2mortal(newSVpv( dn , 0))); + + for (; modlist != NULL; modlist = modlist->ml_next ) { + LDAPMod *mods = &modlist->ml_mod; + + switch ( mods->mod_op & ~LDAP_MOD_BVALUES ) { + case LDAP_MOD_ADD: + XPUSHs(sv_2mortal(newSVpv("ADD", 0 ))); + break; + + case LDAP_MOD_DELETE: + XPUSHs(sv_2mortal(newSVpv("DELETE", 0 ))); + break; + + case LDAP_MOD_REPLACE: + XPUSHs(sv_2mortal(newSVpv("REPLACE", 0 ))); + break; + } + + + XPUSHs(sv_2mortal(newSVpv( mods->mod_type, 0 ))); + + for ( i = 0; + mods->mod_bvalues != NULL && mods->mod_bvalues[i] != NULL; + i++ ) + { + XPUSHs(sv_2mortal(newSVpv( mods->mod_bvalues[i]->bv_val, 0 ))); + } + } + + PUTBACK; + + count = perl_call_method("modify", G_SCALAR); + + SPAGAIN; + + if (count != 1) { + croak("Big trouble in back_search\n"); + } + + return_code = POPi; + + PUTBACK; FREETMPS; LEAVE; + } + + ldap_pvt_thread_mutex_unlock( &perl_interpreter_mutex ); + + if( return_code != 0 ) { + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL, NULL ); + + } else { + send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL, NULL ); + } + + Debug( LDAP_DEBUG_ANY, "Perl MODIFY\n", 0, 0, 0 ); + return( 0 ); +} + diff --git a/servers/slapd/back-perl/modrdn.c b/servers/slapd/back-perl/modrdn.c new file mode 100644 index 0000000000..125bd7157e --- /dev/null +++ b/servers/slapd/back-perl/modrdn.c @@ -0,0 +1,94 @@ +/* + * Copyright 1999, John C. Quillan, 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. + */ + +/* + * 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 + +#include "slap.h" +#include "perl_back.h" + +int +perl_back_modrdn( + Backend *be, + Connection *conn, + Operation *op, + char *dn, + char *newrdn, + int deleteoldrdn, + char *newSuperior +) +{ + int len; + int count; + int return_code; + + PerlBackend *perl_back = (PerlBackend *) be->be_private; + + ldap_pvt_thread_mutex_lock( &perl_interpreter_mutex ); + + { + dSP; ENTER; SAVETMPS; + + PUSHMARK(sp) ; + XPUSHs( perl_back->pb_obj_ref ); + XPUSHs(sv_2mortal(newSVpv( dn , 0 ))); + XPUSHs(sv_2mortal(newSVpv( newrdn , 0 ))); + XPUSHs(sv_2mortal(newSViv( deleteoldrdn ))); + if ( newSuperior != NULL ) { + XPUSHs(sv_2mortal(newSVpv( newSuperior , 0 ))); + } + PUTBACK ; + + count = perl_call_method("modrdn", G_SCALAR); + + SPAGAIN ; + + if (count != 1) { + croak("Big trouble in back_search\n") ; + } + + return_code = POPi; + + PUTBACK; FREETMPS; LEAVE ; + } + + ldap_pvt_thread_mutex_unlock( &perl_interpreter_mutex ); + + if( return_code != 0 ) { + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL, NULL ); + + } else { + send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL, NULL ); + } + + Debug( LDAP_DEBUG_ANY, "Perl MODRDN\n", 0, 0, 0 ); + return( 0 ); +} + + diff --git a/servers/slapd/back-perl/search.c b/servers/slapd/back-perl/search.c new file mode 100644 index 0000000000..b8451e7d8e --- /dev/null +++ b/servers/slapd/back-perl/search.c @@ -0,0 +1,127 @@ +/* + * Copyright 1999, John C. Quillan, 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 +*/ + +#include +#include + +#include "slap.h" +#include "perl_back.h" + +/********************************************************** + * + * Search + * + **********************************************************/ +int +perl_back_search( + Backend *be, + Connection *conn, + Operation *op, + char *base, + int scope, + int deref, + int sizelimit, + int timelimit, + Filter *filter, + char *filterstr, + char **attrs, + int attrsonly + ) +{ + char test[500]; + int count ; + int err = 0; + char *matched = NULL, *info = NULL; + PerlBackend *perl_back = (PerlBackend *)be->be_private; + Entry *e; + char *buf; + int i; + int return_code; + + ldap_pvt_thread_mutex_lock( &perl_interpreter_mutex ); + + { + dSP; ENTER; SAVETMPS; + + PUSHMARK(sp) ; + XPUSHs( perl_back->pb_obj_ref ); + XPUSHs(sv_2mortal(newSVpv( filterstr , 0))); + XPUSHs(sv_2mortal(newSViv( sizelimit ))); + XPUSHs(sv_2mortal(newSViv( timelimit ))); + XPUSHs(sv_2mortal(newSViv( attrsonly ))); + + for ( i = 0; attrs != NULL && attrs[i] != NULL; i++ ) { + XPUSHs(sv_2mortal(newSVpv( attrs[i] , 0))); + } + PUTBACK; + + count = perl_call_method("search", G_ARRAY ); + + SPAGAIN; + + if (count < 1) { + croak("Big trouble in back_search\n") ; + } + + if ( count > 1 ) { + + for ( i = 1; i < count; i++ ) { + + buf = POPp; + + if ( (e = str2entry( buf )) == NULL ) { + Debug( LDAP_DEBUG_ANY, "str2entry(%s) failed\n", buf, 0, 0 ); + + } else { + send_search_entry( be, + conn, + op, + e, + attrs, + attrsonly, + 0 ); + + entry_free( e ); + } + } + } + + /* + * We grab the return code last because the stack comes + * from perl in reverse order. + * + * ex perl: return ( 0, $res_1, $res_2 ); + * + * ex stack: <$res_2> <$res_1> <0> + */ + + return_code = POPi; + + + + PUTBACK; FREETMPS; LEAVE; + } + + ldap_pvt_thread_mutex_unlock( &perl_interpreter_mutex ); + + if( return_code != 0 ) { + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL, NULL ); + + } else { + send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL, NULL ); + } +} + diff --git a/servers/slapd/back-perl/unbind.c b/servers/slapd/back-perl/unbind.c new file mode 100644 index 0000000000..9d972195c6 --- /dev/null +++ b/servers/slapd/back-perl/unbind.c @@ -0,0 +1,40 @@ +/* + * Copyright 1999, John C. Quillan, 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" + /* init.c - initialize shell backend */ + +#include +/* #include + #include +*/ + +#include +#include + +#include "slap.h" +#include "perl_back.h" + + +/********************************************************** + * + * UnBind + * + **********************************************************/ +int +perl_back_unbind( + Backend *be, + Connection *conn, + Operation *op +) +{ + Debug( LDAP_DEBUG_TRACE, "Perl UNBIND\n", 0, 0, 0 ); + return 0; +} + diff --git a/servers/slapd/back-shell/add.c b/servers/slapd/back-shell/add.c index 89f054cc9c..10c51b02c7 100644 --- a/servers/slapd/back-shell/add.c +++ b/servers/slapd/back-shell/add.c @@ -1,16 +1,16 @@ /* add.c - shell backend add function */ +#include "portable.h" + #include -#include -#include -#include + +#include +#include + #include "slap.h" #include "shell.h" -extern pthread_mutex_t entry2str_mutex; -extern char *entry2str(); - -void +int shell_back_add( Backend *be, Connection *conn, @@ -24,27 +24,28 @@ shell_back_add( if ( si->si_add == NULL ) { send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, - "add not implemented" ); - return; + "add not implemented", NULL ); + return( -1 ); } - if ( (op->o_private = forkandexec( si->si_add, &rfp, &wfp )) == -1 ) { + if ( (op->o_private = (void *) forkandexec( si->si_add, &rfp, &wfp )) == (void *) -1 ) { send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, - "could not fork/exec" ); - return; + "could not fork/exec", NULL ); + return( -1 ); } /* write out the request to the add process */ fprintf( wfp, "ADD\n" ); - fprintf( wfp, "msgid: %d\n", op->o_msgid ); + fprintf( wfp, "msgid: %ld\n", op->o_msgid ); print_suffixes( wfp, be ); - pthread_mutex_lock( &entry2str_mutex ); + ldap_pvt_thread_mutex_lock( &entry2str_mutex ); fprintf( wfp, "%s", entry2str( e, &len, 0 ) ); - pthread_mutex_unlock( &entry2str_mutex ); + ldap_pvt_thread_mutex_unlock( &entry2str_mutex ); fclose( wfp ); /* read in the result and send it along */ read_and_send_results( be, conn, op, rfp, NULL, 0 ); fclose( rfp ); + return( 0 ); } diff --git a/servers/slapd/back-shell/bind.c b/servers/slapd/back-shell/bind.c index dea149e410..ffb3542181 100644 --- a/servers/slapd/back-shell/bind.c +++ b/servers/slapd/back-shell/bind.c @@ -1,9 +1,12 @@ /* bind.c - shell backend bind function */ +#include "portable.h" + #include -#include -#include -#include + +#include +#include + #include "slap.h" #include "shell.h" @@ -14,33 +17,37 @@ shell_back_bind( Operation *op, char *dn, int method, - struct berval *cred + char *mech, + struct berval *cred, + char **edn ) { struct shellinfo *si = (struct shellinfo *) be->be_private; FILE *rfp, *wfp; int rc; + *edn = NULL; + if ( si->si_bind == NULL ) { send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, - "bind not implemented" ); - return; + "bind not implemented", NULL ); + return( -1 ); } - if ( (op->o_private = forkandexec( si->si_bind, &rfp, &wfp )) - == -1 ) { + if ( (op->o_private = (void *) forkandexec( si->si_bind, &rfp, &wfp )) + == (void *) -1 ) { send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, - "could not fork/exec" ); - return; + "could not fork/exec", NULL ); + return( -1 ); } /* write out the request to the bind process */ fprintf( wfp, "BIND\n" ); - fprintf( wfp, "msgid: %d\n", op->o_msgid ); + fprintf( wfp, "msgid: %ld\n", op->o_msgid ); print_suffixes( wfp, be ); fprintf( wfp, "dn: %s\n", dn ); fprintf( wfp, "method: %d\n", method ); - fprintf( wfp, "credlen: %d\n", cred->bv_len ); + fprintf( wfp, "credlen: %lu\n", cred->bv_len ); fprintf( wfp, "cred: %s\n", cred->bv_val ); /* XXX */ fclose( wfp ); diff --git a/servers/slapd/back-shell/compare.c b/servers/slapd/back-shell/compare.c index 48dfbb553b..780fea1256 100644 --- a/servers/slapd/back-shell/compare.c +++ b/servers/slapd/back-shell/compare.c @@ -1,13 +1,16 @@ /* compare.c - shell backend compare function */ +#include "portable.h" + #include -#include -#include -#include + +#include +#include + #include "slap.h" #include "shell.h" -void +int shell_back_compare( Backend *be, Connection *conn, @@ -21,20 +24,20 @@ shell_back_compare( if ( si->si_compare == NULL ) { send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, - "compare not implemented" ); - return; + "compare not implemented", NULL ); + return( -1 ); } - if ( (op->o_private = forkandexec( si->si_compare, &rfp, &wfp )) - == -1 ) { + if ( (op->o_private = (void *) forkandexec( si->si_compare, &rfp, &wfp )) + == (void *) -1 ) { send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, - "could not fork/exec" ); - return; + "could not fork/exec", NULL ); + return( -1 ); } /* write out the request to the compare process */ fprintf( wfp, "COMPARE\n" ); - fprintf( wfp, "msgid: %d\n", op->o_msgid ); + fprintf( wfp, "msgid: %ld\n", op->o_msgid ); print_suffixes( wfp, be ); fprintf( wfp, "dn: %s\n", dn ); fprintf( wfp, "%s: %s\n", ava->ava_type, ava->ava_value.bv_val ); @@ -44,4 +47,5 @@ shell_back_compare( read_and_send_results( be, conn, op, rfp, NULL, 0 ); fclose( rfp ); + return( 0 ); } diff --git a/servers/slapd/back-shell/delete.c b/servers/slapd/back-shell/delete.c index 0dc3439c00..dc0617d865 100644 --- a/servers/slapd/back-shell/delete.c +++ b/servers/slapd/back-shell/delete.c @@ -1,13 +1,16 @@ /* delete.c - shell backend delete function */ +#include "portable.h" + #include -#include -#include -#include + +#include +#include + #include "slap.h" #include "shell.h" -void +int shell_back_delete( Backend *be, Connection *conn, @@ -20,20 +23,20 @@ shell_back_delete( if ( si->si_delete == NULL ) { send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, - "delete not implemented" ); - return; + "delete not implemented", NULL ); + return( -1 ); } - if ( (op->o_private = forkandexec( si->si_delete, &rfp, &wfp )) - == -1 ) { + if ( (op->o_private = (void *) forkandexec( si->si_delete, &rfp, &wfp )) + == (void *) -1 ) { send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, - "could not fork/exec" ); - return; + "could not fork/exec", NULL ); + return( -1 ); } /* write out the request to the delete process */ fprintf( wfp, "DELETE\n" ); - fprintf( wfp, "msgid: %d\n", op->o_msgid ); + fprintf( wfp, "msgid: %ld\n", op->o_msgid ); print_suffixes( wfp, be ); fprintf( wfp, "dn: %s\n", dn ); fclose( wfp ); @@ -41,4 +44,5 @@ shell_back_delete( /* read in the results and send them along */ read_and_send_results( be, conn, op, rfp, NULL, 0 ); fclose( rfp ); + return( 0 ); } diff --git a/servers/slapd/back-shell/modify.c b/servers/slapd/back-shell/modify.c index d05b79639d..ac6cefaed7 100644 --- a/servers/slapd/back-shell/modify.c +++ b/servers/slapd/back-shell/modify.c @@ -1,19 +1,22 @@ /* modify.c - shell backend modify function */ +#include "portable.h" + #include -#include -#include -#include + +#include +#include + #include "slap.h" #include "shell.h" -void +int shell_back_modify( Backend *be, Connection *conn, Operation *op, char *dn, - LDAPMod *mods + LDAPModList *ml ) { struct shellinfo *si = (struct shellinfo *) be->be_private; @@ -22,41 +25,41 @@ shell_back_modify( if ( si->si_modify == NULL ) { send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, - "modify not implemented" ); - return; + "modify not implemented", NULL ); + return( -1 ); } - if ( (op->o_private = forkandexec( si->si_modify, &rfp, &wfp )) - == -1 ) { + if ( (op->o_private = (void *) forkandexec( si->si_modify, &rfp, &wfp )) + == (void *) -1 ) { send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, - "could not fork/exec" ); - return; + "could not fork/exec", NULL ); + return( -1 ); } /* write out the request to the modify process */ fprintf( wfp, "MODIFY\n" ); - fprintf( wfp, "msgid: %d\n", op->o_msgid ); + fprintf( wfp, "msgid: %ld\n", op->o_msgid ); print_suffixes( wfp, be ); fprintf( wfp, "dn: %s\n", dn ); - for ( ; mods != NULL; mods = mods->mod_next ) { - switch ( mods->mod_op & ~LDAP_MOD_BVALUES ) { + for ( ; ml != NULL; ml = ml->ml_next ) { + switch ( ml->ml_op & ~LDAP_MOD_BVALUES ) { case LDAP_MOD_ADD: - fprintf( wfp, "add: %s", mods->mod_type ); + fprintf( wfp, "add: %s\n", ml->ml_type ); break; case LDAP_MOD_DELETE: - fprintf( wfp, "delete: %s", mods->mod_type ); + fprintf( wfp, "delete: %s\n", ml->ml_type ); break; case LDAP_MOD_REPLACE: - fprintf( wfp, "replace: %s", mods->mod_type ); + fprintf( wfp, "replace: %s\n", ml->ml_type ); break; } - for ( i = 0; mods->mod_bvalues != NULL && mods->mod_bvalues[i] + for ( i = 0; ml->ml_bvalues != NULL && ml->ml_bvalues[i] != NULL; i++ ) { - fprintf( wfp, "%s: %s\n", mods->mod_type, - mods->mod_bvalues[i]->bv_val ); + fprintf( wfp, "%s: %s\n", ml->ml_type, + ml->ml_bvalues[i]->bv_val ); } } fclose( wfp ); @@ -64,4 +67,6 @@ shell_back_modify( /* read in the results and send them along */ read_and_send_results( be, conn, op, rfp, NULL, 0 ); fclose( rfp ); + return( 0 ); + } diff --git a/servers/slapd/back-shell/modrdn.c b/servers/slapd/back-shell/modrdn.c index 9fd793317d..b208d606a3 100644 --- a/servers/slapd/back-shell/modrdn.c +++ b/servers/slapd/back-shell/modrdn.c @@ -1,20 +1,37 @@ /* modrdn.c - shell backend modrdn function */ +/* + * 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 +#include + #include "slap.h" #include "shell.h" -void +int shell_back_modrdn( Backend *be, Connection *conn, Operation *op, char *dn, char *newrdn, - int deleteoldrdn + int deleteoldrdn, + char *newSuperior ) { struct shellinfo *si = (struct shellinfo *) be->be_private; @@ -22,27 +39,31 @@ shell_back_modrdn( if ( si->si_modrdn == NULL ) { send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, - "modrdn not implemented" ); - return; + "modrdn not implemented", NULL ); + return( -1 ); } - if ( (op->o_private = forkandexec( si->si_modrdn, &rfp, &wfp )) - == -1 ) { + if ( (op->o_private = (void *) forkandexec( si->si_modrdn, &rfp, &wfp )) + == (void *) -1 ) { send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, - "could not fork/exec" ); - return; + "could not fork/exec", NULL ); + return( -1 ); } /* write out the request to the modrdn process */ fprintf( wfp, "MODRDN\n" ); - fprintf( wfp, "msgid: %d\n", op->o_msgid ); + fprintf( wfp, "msgid: %ld\n", op->o_msgid ); print_suffixes( wfp, be ); fprintf( wfp, "dn: %s\n", dn ); fprintf( wfp, "newrdn: %s\n", newrdn ); fprintf( wfp, "deleteoldrdn: %d\n", deleteoldrdn ? 1 : 0 ); + if (newSuperior != NULL) { + fprintf( wfp, "newSuperior: %s\n", newSuperior ); + } fclose( wfp ); /* read in the results and send them along */ read_and_send_results( be, conn, op, rfp, NULL, 0 ); fclose( rfp ); + return( 0 ); } diff --git a/servers/slapd/back-shell/result.c b/servers/slapd/back-shell/result.c index 675aa1f144..b15d3f3e8d 100644 --- a/servers/slapd/back-shell/result.c +++ b/servers/slapd/back-shell/result.c @@ -1,14 +1,16 @@ /* result.c - shell backend result reading function */ +#include "portable.h" + #include -#include -#include -#include + +#include +#include +#include + #include "slap.h" #include "shell.h" -extern Entry *str2entry(); - int read_and_send_results( Backend *be, @@ -57,7 +59,7 @@ read_and_send_results( buf, 0, 0 ); } else { send_search_entry( be, conn, op, e, attrs, - attrsonly ); + attrsonly, 0 ); entry_free( e ); } @@ -68,7 +70,7 @@ read_and_send_results( /* otherwise, front end will send this result */ if ( err != 0 || op->o_tag != LDAP_REQ_BIND ) { - send_ldap_result( conn, op, err, matched, info ); + send_ldap_result( conn, op, err, matched, info, NULL ); } free( buf ); diff --git a/servers/slapd/back-shell/search.c b/servers/slapd/back-shell/search.c index 749b112a94..ae2aba312c 100644 --- a/servers/slapd/back-shell/search.c +++ b/servers/slapd/back-shell/search.c @@ -1,15 +1,16 @@ /* search.c - shell backend search function */ +#include "portable.h" + #include -#include -#include -#include + +#include +#include + #include "slap.h" #include "shell.h" -extern Entry *str2entry(); - -void +int shell_back_search( Backend *be, Connection *conn, @@ -33,20 +34,20 @@ shell_back_search( if ( si->si_search == NULL ) { send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, - "search not implemented" ); - return; + "search not implemented", NULL ); + return( -1 ); } - if ( (op->o_private = forkandexec( si->si_search, &rfp, &wfp )) - == -1 ) { + if ( (op->o_private = (void *) forkandexec( si->si_search, &rfp, &wfp )) + == (void *) -1 ) { send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, - "could not fork/exec" ); - return; + "could not fork/exec", NULL ); + return( -1 ); } /* write out the request to the search process */ fprintf( wfp, "SEARCH\n" ); - fprintf( wfp, "msgid: %d\n", op->o_msgid ); + fprintf( wfp, "msgid: %ld\n", op->o_msgid ); print_suffixes( wfp, be ); fprintf( wfp, "base: %s\n", base ); fprintf( wfp, "scope: %d\n", scope ); @@ -66,4 +67,5 @@ shell_back_search( read_and_send_results( be, conn, op, rfp, attrs, attrsonly ); fclose( rfp ); + return( 0 ); } diff --git a/servers/slapd/back-shell/unbind.c b/servers/slapd/back-shell/unbind.c index 649fe96c13..63d628eacd 100644 --- a/servers/slapd/back-shell/unbind.c +++ b/servers/slapd/back-shell/unbind.c @@ -1,20 +1,20 @@ /* unbind.c - shell backend unbind function */ +#include "portable.h" + #include -#include -#include -#include + +#include +#include + #include "slap.h" #include "shell.h" -void +int shell_back_unbind( Backend *be, Connection *conn, - Operation *op, - char *dn, - int method, - struct berval *cred + Operation *op ) { struct shellinfo *si = (struct shellinfo *) be->be_private; @@ -22,24 +22,26 @@ shell_back_unbind( if ( si->si_unbind == NULL ) { send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, - "unbind not implemented" ); - return; + "unbind not implemented", NULL ); + return 0; } - if ( (op->o_private = forkandexec( si->si_unbind, &rfp, &wfp )) - == -1 ) { + if ( (op->o_private = (void *) forkandexec( si->si_unbind, &rfp, &wfp )) + == (void *) -1 ) { send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, - "could not fork/exec" ); - return; + "could not fork/exec", NULL ); + return 0; } /* write out the request to the unbind process */ fprintf( wfp, "UNBIND\n" ); - fprintf( wfp, "msgid: %d\n", op->o_msgid ); + fprintf( wfp, "msgid: %ld\n", op->o_msgid ); print_suffixes( wfp, be ); - fprintf( wfp, "dn: %s\n", dn ); + fprintf( wfp, "dn: %s\n", (conn->c_dn ? conn->c_dn : "") ); fclose( wfp ); /* no response to unbind */ fclose( rfp ); + + return 0; } diff --git a/servers/slapd/back-tcl/tcl_add.c b/servers/slapd/back-tcl/tcl_add.c new file mode 100644 index 0000000000..7224df01b2 --- /dev/null +++ b/servers/slapd/back-tcl/tcl_add.c @@ -0,0 +1,70 @@ +/* add.c - tcl add routine + * + * $Id: tcl_add.c,v 1.5 1999/02/28 04:55:48 bcollins Exp $ + * + * Copyright 1999, Ben Collins , 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 "slap.h" +#include "tcl_back.h" + +int +tcl_back_add ( + Backend * be, + Connection * conn, + Operation * op, + Entry * e +) +{ + char *command, *suf_tcl, *entrystr, *results; + int i, code, err = 0; + struct tclinfo *ti = (struct tclinfo *) be->be_private; + + if (ti->ti_add == NULL) { + send_ldap_result (conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, + "add not implemented", NULL ); + return (-1); + } + + for (i = 0; be->be_suffix[i] != NULL; i++); + suf_tcl = Tcl_Merge (i, be->be_suffix); + + entrystr = tcl_clean_entry (e); + + command = (char *) ch_malloc (strlen (ti->ti_add) + strlen + (suf_tcl) + + strlen (entrystr) + 32); + sprintf (command, "%s ADD {%ld} {%s} {%s}", + ti->ti_add, op->o_msgid, suf_tcl, entrystr); + Tcl_Free (suf_tcl); + free (entrystr); + + ldap_pvt_thread_mutex_lock (&tcl_interpreter_mutex); + code = Tcl_GlobalEval (ti->ti_ii->interp, command); + results = (char *) ch_strdup (ti->ti_ii->interp->result); + ldap_pvt_thread_mutex_unlock (&tcl_interpreter_mutex); + free (command); + + if (code != TCL_OK) { + err = LDAP_OPERATIONS_ERROR; + Debug (LDAP_DEBUG_SHELL, "tcl_add_error: %s\n", results, 0, 0); + } else { + interp_send_results (be, conn, op, results, NULL, 0); + } + + if (err != LDAP_SUCCESS) + send_ldap_result (conn, op, err, NULL, + "internal backend error", NULL ); + + free (results); + return (err); +} diff --git a/servers/slapd/back-tcl/tcl_bind.c b/servers/slapd/back-tcl/tcl_bind.c new file mode 100644 index 0000000000..dd8d66dbe8 --- /dev/null +++ b/servers/slapd/back-tcl/tcl_bind.c @@ -0,0 +1,74 @@ +/* bind.c - tcl bind routines + * + * $Id: tcl_bind.c,v 1.6 1999/06/29 01:29:27 kdz Exp $ + * + * Copyright 1999, Ben Collins , 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 "slap.h" +#include "tcl_back.h" + +int +tcl_back_bind ( + Backend * be, + Connection * conn, + Operation * op, + char *dn, + int method, + char *mech, + struct berval *cred, + char **edn +) +{ + char *command, *suf_tcl, *results; + int i, code, err = 0; + struct tclinfo *ti = (struct tclinfo *) be->be_private; + + *edn = NULL; + + if (ti->ti_bind == NULL) { + send_ldap_result (conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, + "bind not implemented", NULL ); + return (-1); + } + + for (i = 0; be->be_suffix[i] != NULL; i++); + suf_tcl = Tcl_Merge (i, be->be_suffix); + + command = (char *) ch_malloc (strlen (ti->ti_bind) + strlen + (suf_tcl) + + strlen (dn) + strlen (cred->bv_val) + 64); + sprintf (command, "%s BIND {%ld} {%s} {%s} {%d} {%lu} {%s}", + ti->ti_bind, op->o_msgid, suf_tcl, dn, method, cred->bv_len, + cred->bv_val); + Tcl_Free (suf_tcl); + + ldap_pvt_thread_mutex_lock (&tcl_interpreter_mutex); + code = Tcl_GlobalEval (ti->ti_ii->interp, command); + results = (char *) ch_strdup (ti->ti_ii->interp->result); + ldap_pvt_thread_mutex_unlock (&tcl_interpreter_mutex); + free (command); + + if (code != TCL_OK) { + err = LDAP_OPERATIONS_ERROR; + Debug (LDAP_DEBUG_SHELL, "tcl_bind_error: %s\n", results, 0, 0); + } else { + err = interp_send_results (be, conn, op, results, NULL, 0); + } + + if (err != LDAP_SUCCESS) + send_ldap_result (conn, op, err, NULL, + "internal backend error", NULL ); + + free (results); + return (err); +} diff --git a/servers/slapd/back-tcl/tcl_compare.c b/servers/slapd/back-tcl/tcl_compare.c new file mode 100644 index 0000000000..1352100d83 --- /dev/null +++ b/servers/slapd/back-tcl/tcl_compare.c @@ -0,0 +1,70 @@ +/* compare.c - tcl compare routines + * + * $Id: tcl_compare.c,v 1.5 1999/02/28 04:55:48 bcollins Exp $ + * + * Copyright 1999, Ben Collins , 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 "slap.h" +#include "tcl_back.h" + +int +tcl_back_compare ( + Backend * be, + Connection * conn, + Operation * op, + char *dn, + Ava * ava +) +{ + char *command, *suf_tcl, *results; + int i, code, err = 0; + struct tclinfo *ti = (struct tclinfo *) be->be_private; + + if (ti->ti_compare == NULL) { + send_ldap_result (conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, + "compare not implemented", NULL ); + return (-1); + } + + for (i = 0; be->be_suffix[i] != NULL; i++); + suf_tcl = Tcl_Merge (i, be->be_suffix); + + command = (char *) ch_malloc (strlen (ti->ti_compare) + + strlen (suf_tcl) + strlen (dn) + strlen (ava->ava_type) + + strlen (ava->ava_value.bv_val) + 64); + sprintf (command, "%s COMPARE {%ld} {%s} {%s} {%s: %s}", + ti->ti_compare, op->o_msgid, suf_tcl, dn, ava->ava_type, + ava->ava_value.bv_val); + Tcl_Free (suf_tcl); + + ldap_pvt_thread_mutex_lock (&tcl_interpreter_mutex); + code = Tcl_GlobalEval (ti->ti_ii->interp, command); + results = (char *) ch_strdup (ti->ti_ii->interp->result); + ldap_pvt_thread_mutex_unlock (&tcl_interpreter_mutex); + free (command); + + if (code != TCL_OK) { + err = LDAP_OPERATIONS_ERROR; + Debug (LDAP_DEBUG_SHELL, "tcl_compare_error: %s\n", results, + 0, 0); + } else { + interp_send_results (be, conn, op, results, NULL, 0); + } + + if (err != LDAP_SUCCESS) + send_ldap_result (conn, op, err, NULL, + "internal backend error", NULL ); + + free (results); + return (err); +} diff --git a/servers/slapd/back-tcl/tcl_delete.c b/servers/slapd/back-tcl/tcl_delete.c new file mode 100644 index 0000000000..a8e2a86f86 --- /dev/null +++ b/servers/slapd/back-tcl/tcl_delete.c @@ -0,0 +1,66 @@ +/* delete.c - tcl delete routines + * + * $Id: tcl_delete.c,v 1.5 1999/02/28 04:55:48 bcollins Exp $ + * + * Copyright 1999, Ben Collins , 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 "slap.h" +#include "tcl_back.h" + +tcl_back_delete ( + Backend * be, + Connection * conn, + Operation * op, + char *dn +) +{ + char *command, *suf_tcl, *results; + int i, code, err = 0; + struct tclinfo *ti = (struct tclinfo *) be->be_private; + + if (ti->ti_delete == NULL) { + send_ldap_result (conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, + "delete not implemented", NULL ); + return (-1); + } + + for (i = 0; be->be_suffix[i] != NULL; i++); + suf_tcl = Tcl_Merge (i, be->be_suffix); + + command = (char *) ch_malloc (strlen (ti->ti_delete) + strlen (suf_tcl) + + strlen (dn) + 64); + sprintf (command, "%s DELETE {%ld} {%s} {%s}", + ti->ti_delete, op->o_msgid, suf_tcl, dn); + Tcl_Free (suf_tcl); + + ldap_pvt_thread_mutex_lock (&tcl_interpreter_mutex); + code = Tcl_GlobalEval (ti->ti_ii->interp, command); + results = (char *) ch_strdup (ti->ti_ii->interp->result); + ldap_pvt_thread_mutex_unlock (&tcl_interpreter_mutex); + free (command); + + if (code != TCL_OK) { + err = LDAP_OPERATIONS_ERROR; + Debug (LDAP_DEBUG_SHELL, "tcl_delete_error: %s\n", results, + 0, 0); + } else { + interp_send_results (be, conn, op, results, NULL, 0); + } + + if (err != LDAP_SUCCESS) + send_ldap_result (conn, op, err, NULL, + "internal backend error", NULL ); + + free (results); + return (err); +} diff --git a/servers/slapd/back-tcl/tcl_modify.c b/servers/slapd/back-tcl/tcl_modify.c new file mode 100644 index 0000000000..3c81584827 --- /dev/null +++ b/servers/slapd/back-tcl/tcl_modify.c @@ -0,0 +1,117 @@ +/* modify.c - tcl modify routines + * + * $Id: tcl_modify.c,v 1.5 1999/02/28 04:55:48 bcollins Exp $ + * + * Copyright 1999, Ben Collins , 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 "slap.h" +#include "tcl_back.h" + +int +tcl_back_modify ( + Backend * be, + Connection * conn, + Operation * op, + char *dn, + LDAPModList * modlist +) +{ + char *command, *suf_tcl, *bp, *tcl_mods, *results; + int i, code, err = 0, len, bsize; + struct tclinfo *ti = (struct tclinfo *) be->be_private; + + if (ti->ti_modify == NULL) { + send_ldap_result (conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, + "modify not implemented", NULL ); + return (-1); + } + + for (i = 0; be->be_suffix[i] != NULL; i++); + suf_tcl = Tcl_Merge (i, be->be_suffix); + + tcl_mods = (char *) ch_malloc (BUFSIZ); + tcl_mods[0] = '\0'; + bsize = BUFSIZ; + bp = tcl_mods; + + for (; modlist != NULL; modlist = modlist->ml_next) { + LDAPMod *mods = &modlist->ml_mod; + char *op = NULL; + + switch (mods->mod_op & ~LDAP_MOD_BVALUES) { + case LDAP_MOD_ADD: + op = "add"; + break; + case LDAP_MOD_DELETE: + op = "delete"; + break; + case LDAP_MOD_REPLACE: + op = "replace"; + break; + } + + len = strlen (mods->mod_type) + strlen (op) + 7; + while (bp + len - tcl_mods > bsize) { + bsize += BUFSIZ; + tcl_mods = (char *) ch_realloc (tcl_mods, bsize); + } + sprintf (bp, "{ {%s: %s} ", op, mods->mod_type); + bp += len; + for (i = 0; + mods->mod_bvalues != NULL && mods->mod_bvalues[i] + != NULL; + i++) { + len = strlen (mods->mod_type) + strlen ( + mods->mod_bvalues[i]->bv_val) + 5 + + (mods->mod_bvalues[i + 1] == NULL ? 2 : 0); + while (bp + len - tcl_mods > bsize) { + bsize += BUFSIZ; + tcl_mods = (char *) ch_realloc (tcl_mods, bsize); + } + sprintf (bp, "{%s: %s} %s", mods->mod_type, + mods->mod_bvalues[i]->bv_val, + mods->mod_bvalues[i + 1] == + NULL ? "} " : ""); + bp += len; + } + } + + command = (char *) ch_malloc (strlen (ti->ti_modify) + strlen (suf_tcl) + + strlen (dn) + strlen (tcl_mods) + 64); + /* This space is simply for aesthetics--\ */ + sprintf (command, "%s MODIFY {%ld} {%s} {%s} { %s}", + ti->ti_modify, op->o_msgid, suf_tcl, dn, tcl_mods); + Tcl_Free (suf_tcl); + free (tcl_mods); + + ldap_pvt_thread_mutex_lock (&tcl_interpreter_mutex); + code = Tcl_GlobalEval (ti->ti_ii->interp, command); + results = (char *) ch_strdup (ti->ti_ii->interp->result); + ldap_pvt_thread_mutex_unlock (&tcl_interpreter_mutex); + free (command); + + if (code != TCL_OK) { + err = LDAP_OPERATIONS_ERROR; + Debug (LDAP_DEBUG_SHELL, "tcl_modify_error: %s\n", results, + 0, 0); + } else { + interp_send_results (be, conn, op, results, NULL, 0); + } + + if (err != LDAP_SUCCESS) + send_ldap_result (conn, op, err, NULL, + "internal backend error", NULL ); + + free (results); + return (err); +} diff --git a/servers/slapd/back-tcl/tcl_modrdn.c b/servers/slapd/back-tcl/tcl_modrdn.c new file mode 100644 index 0000000000..e5dde6ac79 --- /dev/null +++ b/servers/slapd/back-tcl/tcl_modrdn.c @@ -0,0 +1,91 @@ +/* modrdn.c - tcl modify rdn routines + * + * $Id: tcl_modrdn.c,v 1.7 1999/03/05 18:21:35 gomez Exp $ + * + * Copyright 1999, Ben Collins , 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. + */ + +/* + * 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 "slap.h" +#include "tcl_back.h" + +int +tcl_back_modrdn ( + Backend * be, + Connection * conn, + Operation * op, + char *dn, + char *newrdn, + int deleteoldrdn, + char *newSuperior +) +{ + char *command, *suf_tcl, *results; + int i, code, err = 0; + struct tclinfo *ti = (struct tclinfo *) be->be_private; + + if (ti->ti_modrdn == NULL) { + send_ldap_result (conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, + "modrdn not implemented", NULL ); + return (-1); + } + + for (i = 0; be->be_suffix[i] != NULL; i++); + suf_tcl = Tcl_Merge (i, be->be_suffix); + + command = (char *) ch_malloc (strlen (ti->ti_modrdn) + strlen (suf_tcl) + + strlen (dn) + strlen (newrdn) + + (newSuperior ? strlen(newSuperior) : 0) + 64); + if ( newSuperior ) { + sprintf (command, "%s MODRDN {%ld} {%s} {%s} {%s} %d {%s}", + ti->ti_add, op->o_msgid, suf_tcl, dn, newrdn, + deleteoldrdn ? 1 : 0, newSuperior ); + } else { + sprintf (command, "%s MODRDN {%ld} {%s} {%s} {%s} %d", + ti->ti_add, op->o_msgid, suf_tcl, dn, newrdn, + deleteoldrdn ? 1 : 0 ); + } + Tcl_Free (suf_tcl); + + ldap_pvt_thread_mutex_lock (&tcl_interpreter_mutex); + code = Tcl_GlobalEval (ti->ti_ii->interp, command); + results = (char *) ch_strdup (ti->ti_ii->interp->result); + ldap_pvt_thread_mutex_unlock (&tcl_interpreter_mutex); + free (command); + + if (code != TCL_OK) { + err = LDAP_OPERATIONS_ERROR; + Debug (LDAP_DEBUG_SHELL, "tcl_modrdn_error: %s\n", results, + 0, 0); + } else { + interp_send_results (be, conn, op, results, NULL, 0); + } + + if (err != LDAP_SUCCESS) + send_ldap_result (conn, op, err, NULL, + "internal backend error", NULL ); + + free (results); + return (err); +} diff --git a/servers/slapd/back-tcl/tcl_search.c b/servers/slapd/back-tcl/tcl_search.c new file mode 100644 index 0000000000..f01104a10b --- /dev/null +++ b/servers/slapd/back-tcl/tcl_search.c @@ -0,0 +1,87 @@ +/* search.c - tcl search routines + * + * $Id: tcl_search.c,v 1.5 1999/02/28 04:55:49 bcollins Exp $ + * + * Copyright 1999, Ben Collins , 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 "slap.h" +#include "tcl_back.h" + +int +tcl_back_search ( + Backend * be, + Connection * conn, + Operation * op, + char *base, + int scope, + int deref, + int sizelimit, + int timelimit, + Filter * filter, + char *filterstr, + char **attrs, + int attrsonly +) +{ + char *attrs_tcl = NULL, *suf_tcl, *results, *command; + int i, err = 0, code; + struct tclinfo *ti = (struct tclinfo *) be->be_private; + Entry *e; + + if (ti->ti_search == NULL) { + send_ldap_result (conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, + "search not implemented", NULL ); + return (-1); + } + + for (i = 0; attrs != NULL && attrs[i] != NULL; i++); + if (i > 0) + attrs_tcl = Tcl_Merge (i, attrs); + + for (i = 0; be->be_suffix[i] != NULL; i++); + suf_tcl = Tcl_Merge (i, be->be_suffix); + + command = (char *) ch_malloc (strlen (ti->ti_search) + strlen (suf_tcl) + + strlen (base) + 40 + strlen (filterstr) + (attrs_tcl == + NULL ? 5 + : strlen (attrs_tcl)) + 72); + sprintf (command, + "%s SEARCH {%ld} {%s} {%s} {%d} {%d} {%d} {%d} {%s} {%d} {%s}", + ti->ti_search, op->o_msgid, suf_tcl, base, scope, deref, + sizelimit, timelimit, filterstr, attrsonly ? 1 : 0, + attrs_tcl == + NULL ? "{all}" : attrs_tcl); + Tcl_Free (attrs_tcl); + Tcl_Free (suf_tcl); + + ldap_pvt_thread_mutex_lock (&tcl_interpreter_mutex); + code = Tcl_GlobalEval (ti->ti_ii->interp, command); + results = (char *) ch_strdup (ti->ti_ii->interp->result); + ldap_pvt_thread_mutex_unlock (&tcl_interpreter_mutex); + free (command); + + if (code != TCL_OK) { + err = LDAP_OPERATIONS_ERROR; + Debug (LDAP_DEBUG_SHELL, "tcl_search_error: %s\n", results, + 0, 0); + } else { + interp_send_results (be, conn, op, results, NULL, 0); + } + + if (err != LDAP_SUCCESS) + send_ldap_result (conn, op, err, NULL, + "internal backend error", NULL ); + + free (results); + return (err); +} diff --git a/servers/slapd/back-tcl/tcl_unbind.c b/servers/slapd/back-tcl/tcl_unbind.c new file mode 100644 index 0000000000..7872da4d5a --- /dev/null +++ b/servers/slapd/back-tcl/tcl_unbind.c @@ -0,0 +1,58 @@ +/* unbind.c - tcl unbind routines + * + * $Id: tcl_unbind.c,v 1.5 1999/02/28 04:55:49 bcollins Exp $ + * + * Copyright 1999, Ben Collins , 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 "slap.h" +#include "tcl_back.h" + +int +tcl_back_unbind ( + Backend * be, + Connection * conn, + Operation * op +) +{ + char *command, *suf_tcl, *results; + int i, code, err = 0; + struct tclinfo *ti = (struct tclinfo *) be->be_private; + + if (ti->ti_unbind == NULL) { + return (-1); + } + + for (i = 0; be->be_suffix[i] != NULL; i++); + suf_tcl = Tcl_Merge (i, be->be_suffix); + + command = (char *) ch_malloc (strlen (ti->ti_unbind) + strlen (suf_tcl) + + strlen (conn->c_dn ? conn->c_dn : "") + 64); + sprintf (command, "%s UNBIND {%ld} {%s} {%s}", + ti->ti_unbind, op->o_msgid, suf_tcl, conn->c_dn ? + conn->c_dn : ""); + Tcl_Free (suf_tcl); + + ldap_pvt_thread_mutex_lock (&tcl_interpreter_mutex); + code = Tcl_GlobalEval (ti->ti_ii->interp, command); + results = (char *) ch_strdup (ti->ti_ii->interp->result); + ldap_pvt_thread_mutex_unlock (&tcl_interpreter_mutex); + free (command); + + if (code != TCL_OK) { + Debug (LDAP_DEBUG_SHELL, "tcl_unbind_error: %s\n", results, + 0, 0); + } + + free (results); + return (err); +} diff --git a/servers/slapd/back-tcl/tcl_util.c b/servers/slapd/back-tcl/tcl_util.c new file mode 100644 index 0000000000..994b24ab96 --- /dev/null +++ b/servers/slapd/back-tcl/tcl_util.c @@ -0,0 +1,190 @@ +/* result.c - tcl backend utility functions + * + * $Id: tcl_util.c,v 1.6 1999/07/07 16:51:41 kdz Exp $ + * + * Copyright 1999, Ben Collins , 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 +#include + +#include "slap.h" +#include "tcl_back.h" + +int +interp_send_results ( + Backend * be, + Connection * conn, + Operation * op, + char *result, + char **attrs, + int attrsonly +) +{ + int bsize, len, argcPtr, i, err, code; + char *buf, *bp, **argvPtr, *line, *matched, *info; + Entry *e; + struct tclinfo *ti = (struct tclinfo *) be->be_private; + + /* + * read in the result and send it along + */ + buf = (char *) ch_malloc (BUFSIZ); + buf[0] = '\0'; + bsize = BUFSIZ; + bp = buf; + code = Tcl_SplitList (ti->ti_ii->interp, result, &argcPtr, &argvPtr); + if (code != TCL_OK) { + argcPtr = 0; + send_ldap_result (conn, op, LDAP_UNWILLING_TO_PERFORM, NULL, + "internal backend error", NULL ); + return -1; + } + for (i = 0; i < argcPtr; i++) { + line = argvPtr[i]; + + /* + * ignore lines beginning with DEBUG: + */ + if (strncasecmp (line, "DEBUG:", 6) == 0) { + continue; + } + len = strlen (line) + 1; + while (bp + len - buf > bsize) { + bsize += BUFSIZ; + buf = (char *) ch_realloc (buf, bsize); + } + sprintf (bp, "%s\n", line); + bp += len; + + /* + * line marked the end of an entry or result + */ + if (line[0] == '\0') { + if (strncasecmp (buf, "RESULT", 6) == 0) { + break; + } + if ((e = str2entry (buf)) == NULL) { + Debug (LDAP_DEBUG_SHELL, + "str2entry(%s) failed\n", + buf, 0, 0); + } else { + send_search_entry (be, conn, op, e, attrs, + attrsonly, 0 ); + entry_free (e); + } + + bp = buf; + } + } + + (void) str2result (buf, &err, &matched, &info); + + /* + * otherwise, front end will send this result + */ + if (err != 0 || op->o_tag != LDAP_REQ_BIND) { + send_ldap_result (conn, op, err, matched, info, NULL ); + } + + free (buf); + Tcl_Free ((char *) argvPtr); + return (err); +} + +char * +tcl_clean_entry ( + Entry * e +) +{ + char *entrystr, *mark1, *mark2, *buf, *bp, *dup; + int len, bsize; + + pthread_mutex_lock (&entry2str_mutex); + entrystr = entry2str (e, &len, 0); + pthread_mutex_unlock (&entry2str_mutex); + + buf = (char *) ch_malloc (BUFSIZ); + buf[0] = '\0'; + bsize = BUFSIZ; + bp = buf; + bp++[0] = ' '; + + mark1 = entrystr; + do { + if (mark1[0] == '\n') { + mark1++; + } + dup = (char *) ch_strdup (mark1); + if (dup[0] != '\0') { + if ((mark2 = (char *) strchr (dup, '\n')) != NULL) { + mark2[0] = '\0'; + } + len = strlen (dup) + 3; + while (bp + len - buf > bsize) { + bsize += BUFSIZ; + buf = (char *) ch_realloc (buf, bsize); + } + if (mark1[0] == '\0') { + sprintf (bp, "{} "); + } else { + sprintf (bp, "{%s} ", dup); + } + bp += len; + if (mark2 != NULL) { + mark2[0] = '\n'; + } + } + free (dup); + } while ((mark1 = (char *) strchr (mark1, '\n')) != NULL); + return buf; +} + +int +tcl_ldap_debug ( + ClientData clientData, + Tcl_Interp * interp, + int argc, + char *argv[] +) +{ + if (argv[1] != NULL) { + Debug (LDAP_DEBUG_SHELL, "tcl_debug: %s\n", argv[1], 0, 0); + } + return TCL_OK; +} + +void +readtclscript ( + char *script, + Tcl_Interp * my_tcl) +{ + int code; + FILE *f; + + f = fopen (script, "r"); + if (f == NULL) { + Debug (LDAP_DEBUG_SHELL, "Could not open scriptpath %s\n", script, + 0, 0); + return; + } + fclose (f); + code = Tcl_EvalFile (my_tcl, script); + if (code != TCL_OK) { + Debug (LDAP_DEBUG_SHELL, "%s: %s\n", script, + Tcl_GetVar (my_tcl, "errorInfo", TCL_GLOBAL_ONLY), 0); + Debug (LDAP_DEBUG_SHELL, "%s: error at line\n", script, + my_tcl->errorLine, 0); + return; + } +} diff --git a/servers/slapd/result.c b/servers/slapd/result.c index 8ebb81bab8..f1496e4ca5 100644 --- a/servers/slapd/result.c +++ b/servers/slapd/result.c @@ -161,7 +161,7 @@ send_ldap_response( text == NULL ? "" : text ); if( rc != -1 && ref != NULL ) { - rc = ber_printf( ber, "{v}", ref ); + rc = ber_printf( ber, "{V}", ref ); } if( rc != -1 && resoid != NULL ) { -- 2.39.5