ITS#8303 Asynchronous meta back-end for OpenLDAP

This commit is contained in:
Nadezhda Ivanova 2016-01-30 20:14:29 +02:00 committed by Howard Chu
parent a4c7943d39
commit 6cafdfa8d8
25 changed files with 14692 additions and 7 deletions

View file

@ -316,6 +316,8 @@ OL_ARG_ENABLE(mdb,[ --enable-mdb enable mdb database backend],
yes, [no yes mod], ol_enable_backends)dnl yes, [no yes mod], ol_enable_backends)dnl
OL_ARG_ENABLE(meta,[ --enable-meta enable metadirectory backend], OL_ARG_ENABLE(meta,[ --enable-meta enable metadirectory backend],
no, [no yes mod], ol_enable_backends)dnl no, [no yes mod], ol_enable_backends)dnl
OL_ARG_ENABLE(asyncmeta,[ --enable-asyncmeta enable asynchronous metadirectory backend],
no, [no yes mod], ol_enable_backends)dnl
OL_ARG_ENABLE(monitor,[ --enable-monitor enable monitor backend], OL_ARG_ENABLE(monitor,[ --enable-monitor enable monitor backend],
yes, [no yes mod], ol_enable_backends)dnl yes, [no yes mod], ol_enable_backends)dnl
OL_ARG_ENABLE(ndb,[ --enable-ndb enable MySQL NDB Cluster backend], OL_ARG_ENABLE(ndb,[ --enable-ndb enable MySQL NDB Cluster backend],
@ -504,6 +506,10 @@ if test $ol_enable_meta/$ol_enable_ldap = yes/no ; then
AC_MSG_ERROR([--enable-meta requires --enable-ldap]) AC_MSG_ERROR([--enable-meta requires --enable-ldap])
fi fi
if test $ol_enable_meta_async/$ol_enable_ldap = yes/no ; then
AC_MSG_ERROR([--enable-asyncmeta requires --enable-ldap])
fi
if test $ol_enable_lmpasswd = yes ; then if test $ol_enable_lmpasswd = yes ; then
if test $ol_with_tls = no ; then if test $ol_with_tls = no ; then
AC_MSG_ERROR([LAN Manager passwords require OpenSSL]) AC_MSG_ERROR([LAN Manager passwords require OpenSSL])
@ -543,6 +549,7 @@ BUILD_HDB=no
BUILD_LDAP=no BUILD_LDAP=no
BUILD_MDB=no BUILD_MDB=no
BUILD_META=no BUILD_META=no
BUILD_ASYNCMETA=no
BUILD_MONITOR=no BUILD_MONITOR=no
BUILD_NDB=no BUILD_NDB=no
BUILD_NULL=no BUILD_NULL=no
@ -2736,6 +2743,20 @@ if test "$ol_enable_meta" != no ; then
AC_DEFINE_UNQUOTED(SLAPD_META,$MFLAG,[define to support LDAP Metadirectory backend]) AC_DEFINE_UNQUOTED(SLAPD_META,$MFLAG,[define to support LDAP Metadirectory backend])
fi fi
if test "$ol_enable_meta_async" != no ; then
BUILD_SLAPD=yes
BUILD_ASYNCMETA=$ol_enable_meta_async
BUILD_REWRITE=yes
if test "$ol_enable_meta_async" = mod ; then
SLAPD_DYNAMIC_BACKENDS="$SLAPD_DYNAMIC_BACKENDS back-asyncmeta"
MFLAG=SLAPD_MOD_DYNAMIC
else
SLAPD_STATIC_BACKENDS="$SLAPD_STATIC_BACKENDS back-asyncmeta"
MFLAG=SLAPD_MOD_STATIC
fi
AC_DEFINE_UNQUOTED(SLAPD_ASYNCMETA,$MFLAG,[define to support LDAP Async Metadirectory backend])
fi
if test "$ol_enable_ndb" != no ; then if test "$ol_enable_ndb" != no ; then
BUILD_SLAPD=yes BUILD_SLAPD=yes
BUILD_NDB=$ol_enable_ndb BUILD_NDB=$ol_enable_ndb
@ -3142,6 +3163,7 @@ dnl backends
AC_SUBST(BUILD_LDAP) AC_SUBST(BUILD_LDAP)
AC_SUBST(BUILD_MDB) AC_SUBST(BUILD_MDB)
AC_SUBST(BUILD_META) AC_SUBST(BUILD_META)
AC_SUBST(BUILD_ASYNCMETA)
AC_SUBST(BUILD_MONITOR) AC_SUBST(BUILD_MONITOR)
AC_SUBST(BUILD_NDB) AC_SUBST(BUILD_NDB)
AC_SUBST(BUILD_NULL) AC_SUBST(BUILD_NULL)
@ -3253,6 +3275,7 @@ AC_CONFIG_FILES([Makefile:build/top.mk:Makefile.in:build/dir.mk]
[servers/slapd/back-ldif/Makefile:build/top.mk:servers/slapd/back-ldif/Makefile.in:build/mod.mk] [servers/slapd/back-ldif/Makefile:build/top.mk:servers/slapd/back-ldif/Makefile.in:build/mod.mk]
[servers/slapd/back-mdb/Makefile:build/top.mk:servers/slapd/back-mdb/Makefile.in:build/mod.mk] [servers/slapd/back-mdb/Makefile:build/top.mk:servers/slapd/back-mdb/Makefile.in:build/mod.mk]
[servers/slapd/back-meta/Makefile:build/top.mk:servers/slapd/back-meta/Makefile.in:build/mod.mk] [servers/slapd/back-meta/Makefile:build/top.mk:servers/slapd/back-meta/Makefile.in:build/mod.mk]
[servers/slapd/back-asyncmeta/Makefile:build/top.mk:servers/slapd/back-asyncmeta/Makefile.in:build/mod.mk]
[servers/slapd/back-monitor/Makefile:build/top.mk:servers/slapd/back-monitor/Makefile.in:build/mod.mk] [servers/slapd/back-monitor/Makefile:build/top.mk:servers/slapd/back-monitor/Makefile.in:build/mod.mk]
[servers/slapd/back-ndb/Makefile:build/top.mk:servers/slapd/back-ndb/Makefile.in:build/mod.mk] [servers/slapd/back-ndb/Makefile:build/top.mk:servers/slapd/back-ndb/Makefile.in:build/mod.mk]
[servers/slapd/back-null/Makefile:build/top.mk:servers/slapd/back-null/Makefile.in:build/mod.mk] [servers/slapd/back-null/Makefile:build/top.mk:servers/slapd/back-null/Makefile.in:build/mod.mk]

View file

@ -0,0 +1,487 @@
.TH SLAPD-ASYNCMETA 5 "RELEASEDATE" "OpenLDAP LDVERSION"
.\" Copyright 2016 The OpenLDAP Foundation.
.\" Portions Copyright 2016 Symas Corporation.
.\" Copying restrictions apply. See the COPYRIGHT file.
.\" $OpenLDAP$
.\"
.SH NAME
slapd\-asyncmeta \- asynchronous metadirectory backend to slapd
.SH SYNOPSIS
ETCDIR/slapd.conf
.SH DESCRIPTION
The
.B asyncmeta
backend to
.BR slapd (8)
performs basic LDAP proxying with respect to a set of remote LDAP
servers, called "targets".
The information contained in these servers can be presented as
belonging to a single Directory Information Tree (DIT).
.LP
A good knowledge of the functionality of the
.BR slapd\-meta(5)
backend is recommended. This backend has been designed as
an asynchronous version of the
.B meta
backend. Unlike
.B meta
, the operation handling threads are no longer pending
on the response from the remote server, thus decreasing the
number of threads necessary to handle the same load. While
.B asyncmeta
maintains the functionality of
.B meta
and has a largely similar codebase,
some changes in operation and some new configuration directives have been
added. Some configuration options, such as
.B conn-ttl,
.B single-conn
and
.B use-temporary-conn
have been removed, as they are no longer relevant.
.LP
.B New connection handling:
.LP
Unlike
.B meta,
which caches bound connections, the
.B asyncmeta
works with a configured maximum number of connections per target.
For each request redirected to a target, a different connection is selected.
Each connection has a queue, to which the request is added before it is sent to the
remote server, and is removed after the last response for that request is received.
For each new request, the connection with the smallest number of pending requests
is selected, or using round\-robin if the numbers are equal.
.LP
.B Overlays:
.LP
Due to implementation specifics, there is no guarantee that any of the existing OpenLDAP overlays will work with
.B asyncmeta
backend.
.SH EXAMPLES
Refer to
.B slapd\-meta(5)
for configuration examples.
.SH CONFIGURATION
These
.B slapd.conf
options apply to the ASYNCMETA backend database.
That is, they must follow a "database asyncmeta" line and come before any
subsequent "backend" or "database" lines.
Other database options are described in the
.BR slapd.conf (5)
manual page.
.SH SPECIAL CONFIGURATION DIRECTIVES
Target configuration starts with the "uri" directive.
All the configuration directives that are not specific to targets
should be defined first for clarity, including those that are common
to all backends.
They are:
.TP
.B default\-target none
This directive forces the backend to reject all those operations
that must resolve to a single target in case none or multiple
targets are selected.
They include: add, delete, modify, modrdn; compare is not included, as
well as bind since, as they don't alter entries, in case of multiple
matches an attempt is made to perform the operation on any candidate
target, with the constraint that at most one must succeed.
This directive can also be used when processing targets to mark a
specific target as default.
.TP
.B dncache\-ttl {DISABLED|forever|<ttl>}
This directive sets the time-to-live of the DN cache.
This caches the target that holds a given DN to speed up target
selection in case multiple targets would result from an uncached
search; forever means cache never expires; disabled means no DN
caching; otherwise a valid ( > 0 ) ttl is required, in the format
illustrated for the
.B idle\-timeout
directive.
.TP
.B onerr {CONTINUE|report|stop}
This directive allows to select the behavior in case an error is returned
by one target during a search.
The default, \fBcontinue\fP, consists in continuing the operation,
trying to return as much data as possible.
If the value is set to \fBstop\fP, the search is terminated as soon
as an error is returned by one target, and the error is immediately
propagated to the client.
If the value is set to \fBreport\fP, the search is continuated to the end
but, in case at least one target returned an error code, the first
non-success error code is returned.
.TP
.B max\-timeout\-ops <number>
Specify the number of consecutive timed out requests,
after which the connection will be considered faulty and dropped.
.TP
.B max-pending-ops <number>
The maximum number of pending requests stored in a connection's queue.
The default is 128. When this number is exceeded,
.B LDAP_BUSY
will be returned to the client.
.TP
.B max-target-conns <number>
The maximum number of connections per target. Unlike
.B slapd\-meta(5),
no new connections will be created
once this number is reached. The default value is 255.
.TP
.B norefs <NO|yes>
If
.BR yes ,
do not return search reference responses.
By default, they are returned unless request is LDAPv2.
If set before any target specification, it affects all targets, unless
overridden by any per-target directive.
.TP
.B noundeffilter <NO|yes>
If
.BR yes ,
return success instead of searching if a filter is undefined or contains
undefined portions.
By default, the search is propagated after replacing undefined portions
with
.BR (!(objectClass=*)) ,
which corresponds to the empty result set.
If set before any target specification, it affects all targets, unless
overridden by any per-target directive.
.TP
.B protocol\-version {0,2,3}
This directive indicates what protocol version must be used to contact
the remote server.
If set to 0 (the default), the proxy uses the same protocol version
used by the client, otherwise the requested protocol is used.
The proxy returns \fIunwillingToPerform\fP if an operation that is
incompatible with the requested protocol is attempted.
If set before any target specification, it affects all targets, unless
overridden by any per-target directive.
.TP
.B pseudoroot\-bind\-defer {YES|no}
This directive, when set to
.BR yes ,
causes the authentication to the remote servers with the pseudo-root
identity (the identity defined in each
.B idassert-bind
directive) to be deferred until actually needed by subsequent operations.
Otherwise, all binds as the rootdn are propagated to the targets.
.TP
.B quarantine <interval>,<num>[;<interval>,<num>[...]]
Turns on quarantine of URIs that returned
.IR LDAP_UNAVAILABLE ,
so that an attempt to reconnect only occurs at given intervals instead
of any time a client requests an operation.
The pattern is: retry only after at least
.I interval
seconds elapsed since last attempt, for exactly
.I num
times; then use the next pattern.
If
.I num
for the last pattern is "\fB+\fP", it retries forever; otherwise,
no more retries occur.
This directive must appear before any target specification;
it affects all targets with the same pattern.
.TP
.B rebind\-as\-user {NO|yes}
If this option is given, the client's bind credentials are remembered
for rebinds, when trying to re-establish a broken connection,
or when chasing a referral, if
.B chase\-referrals
is set to
.IR yes .
.TP
.B session\-tracking\-request {NO|yes}
Adds session tracking control for all requests.
The client's IP and hostname, and the identity associated to each request,
if known, are sent to the remote server for informational purposes.
This directive is incompatible with setting \fIprotocol\-version\fP to 2.
If set before any target specification, it affects all targets, unless
overridden by any per-target directive.
.SH TARGET SPECIFICATION
Target specification starts with a "uri" directive:
.TP
.B uri <protocol>://[<host>]/<naming context> [...]
Identical to
.B meta.
See
.B slapd\-meta(5)
for details.
.TP
.B acl\-authcDN "<administrative DN for access control purposes>"
DN which is used to query the target server for acl checking,
as in the LDAP backend; it is supposed to have read access
on the target server to attributes used on the proxy for acl checking.
There is no risk of giving away such values; they are only used to
check permissions.
.B The acl\-authcDN identity is by no means implicitly used by the proxy
.B when the client connects anonymously.
.TP
.B acl\-passwd <password>
Password used with the
.B
acl\-authcDN
above.
.TP
.B bind\-timeout <microseconds>
This directive defines the timeout, in microseconds, used when polling
for response after an asynchronous bind connection. See
.B slapd\-meta(5)
for details.
.TP
.B chase\-referrals {YES|no}
enable/disable automatic referral chasing, which is delegated to the
underlying libldap, with rebinding eventually performed if the
\fBrebind\-as\-user\fP directive is used. The default is to chase referrals.
If set before any target specification, it affects all targets, unless
overridden by any per-target directive.
.TP
.B client\-pr {accept-unsolicited|DISABLE|<size>}
This feature allows to use RFC 2696 Paged Results control when performing
search operations with a specific target,
irrespective of the client's request. See
.B slapd\-meta(5)
for details.
.TP
.B default\-target [<target>]
The "default\-target" directive can also be used during target specification.
With no arguments it marks the current target as the default.
The optional number marks target <target> as the default one, starting
from 1.
Target <target> must be defined.
.TP
.B filter <pattern>
This directive allows specifying a
.BR regex (5)
pattern to indicate what search filter terms are actually served by a target.
In a search request, if the search filter matches the \fIpattern\fP
the target is considered while fulfilling the request; otherwise
the target is ignored. There may be multiple occurrences of
the
.B filter
directive for each target.
.TP
.B idassert\-authzFrom <authz-regexp>
if defined, selects what
.I local
identities are authorized to exploit the identity assertion feature.
The string
.B <authz-regexp>
follows the rules defined for the
.I authzFrom
attribute.
See
.BR slapd.conf (5),
section related to
.BR authz\-policy ,
for details on the syntax of this field.
.HP
.hy 0
.B idassert\-bind
.B bindmethod=none|simple|sasl [binddn=<simple DN>] [credentials=<simple password>]
.B [saslmech=<SASL mech>] [secprops=<properties>] [realm=<realm>]
.B [authcId=<authentication ID>] [authzId=<authorization ID>]
.B [authz={native|proxyauthz}] [mode=<mode>] [flags=<flags>]
.B [starttls=no|yes|critical]
.B [tls_cert=<file>]
.B [tls_key=<file>]
.B [tls_cacert=<file>]
.B [tls_cacertdir=<path>]
.B [tls_reqcert=never|allow|try|demand]
.B [tls_ciphersuite=<ciphers>]
.B [tls_protocol_min=<major>[.<minor>]]
.B [tls_crlcheck=none|peer|all]
Allows to define the parameters of the authentication method that is
internally used by the proxy to authorize connections that are
authenticated by other databases. See
.B slapd\-meta(5)
for details.
.TP
.B idle\-timeout <time>
This directive causes a a persistent connection to be dropped after
it has been idle for the specified time. The connection will be re-created
the next time it is selected for use. A connection is considered idle if no
attempts have been made by the backend to use it to send a request to
the backend server. If there are still pending requests in
its queue, the connection will be dropped after the last
request one has either received a result or has timed out.
[<d>d][<h>h][<m>m][<s>[s]]
where <d>, <h>, <m> and <s> are respectively treated as days, hours,
minutes and seconds.
If set before any target specification, it affects all targets, unless
overridden by any per-target directive.
.TP
.B keepalive <idle>:<probes>:<interval>
The
.B keepalive
parameter sets the values of \fIidle\fP, \fIprobes\fP, and \fIinterval\fP
used to check whether a socket is alive;
.I idle
is the number of seconds a connection needs to remain idle before TCP
starts sending keepalive probes;
.I probes
is the maximum number of keepalive probes TCP should send before dropping
the connection;
.I interval
is interval in seconds between individual keepalive probes.
Only some systems support the customization of these values;
the
.B keepalive
parameter is ignored otherwise, and system-wide settings are used.
.TP
.B map "{attribute|objectclass} [<local name>|*] {<foreign name>|*}"
This maps object classes and attributes as in the LDAP backend.
See
.BR slapd\-ldap (5).
.TP
.B network\-timeout <time>
Sets the network timeout value after which
.BR poll (2)/ select (2)
following a
.BR connect (2)
returns in case of no activity.
The value is in seconds, and it can be specified as for
.BR idle\-timeout .
If set before any target specification, it affects all targets, unless
overridden by any per-target directive.
.TP
.B nretries {forever|never|<nretries>}
This directive defines how many times a bind should be retried
in case of temporary failure in contacting a target. If defined
before any target specification, it applies to all targets (by default,
.BR 3
times);
the global value can be overridden by redefinitions inside each target
specification.
.TP
.B rewrite* ...
The rewrite options are identical to the
.B meta
backend. See the
.B REWRITING
section of
.B slapd\-meta(5).
.TP
.B subtree\-{exclude|include} "<rule>"
This directive allows to indicate what subtrees are actually served
by a target. See
.B slapd\-meta(5)
for details.
.TP
.B suffixmassage "<virtual naming context>" "<real naming context>"
All the directives starting with "rewrite" refer to the rewrite engine
that has been added to slapd. See
.B slapd\-meta(5)
for details.
.TP
.B t\-f\-support {NO|yes|discover}
enable if the remote server supports absolute filters
(see \fIRFC 4526\fP for details).
If set to
.BR discover ,
support is detected by reading the remote server's root DSE.
If set before any target specification, it affects all targets, unless
overridden by any per-target directive.
.TP
.B timeout [<op>=]<val> [...]
This directive allows to set per-operation timeouts.
Operations can be
\fB<op> ::= bind, add, delete, modrdn, modify, compare, search\fP
See
.B slapd\-meta(5)
for details.
.TP
.B tls {[try\-]start|[try\-]propagate}
execute the StartTLS extended operation when the connection is initialized;
only works if the URI directive protocol scheme is not \fBldaps://\fP.
\fBpropagate\fP issues the StartTLS operation only if the original
connection did.
The \fBtry\-\fP prefix instructs the proxy to continue operations
if the StartTLS operation failed; its use is highly deprecated.
If set before any target specification, it affects all targets, unless
overridden by any per-target directive.
.SH SCENARIOS
See
.B slapd\-meta(5)
for configuration scenarios.
.SH ACLs
ACL behavior is identical to meta. See
.B slapd\-meta(5).
.SH ACCESS CONTROL
The
.B asyncmeta
backend does not honor all ACL semantics as described in
.BR slapd.access (5).
In general, access checking is delegated to the remote server(s).
Only
.B read (=r)
access to the
.B entry
pseudo-attribute and to the other attribute values of the entries
returned by the
.B search
operation is honored, which is performed by the frontend.
.SH FILES
.TP
ETCDIR/slapd.conf
default slapd configuration file
.SH SEE ALSO
.BR slapd.conf (5),
.BR slapd\-meta (5),
.BR slapd\-ldap (5),
.BR slapo\-pcache (5),
.BR slapd (8),
.BR regex (7),
.BR re_format (7).
.SH AUTHOR
Nadezhda Ivanova, based on back-meta by Pierangelo Masarati.

View file

@ -0,0 +1,50 @@
## Makefile.in for back-asyncmeta
## $OpenLDAP$
## This work is part of OpenLDAP Software <http://www.openldap.org/>.
##
## Copyright 2016 The OpenLDAP Foundation.
## Portions Copyright 2016 Symas Corporation.
## All rights reserved.
##
## Redistribution and use in source and binary forms, with or without
## modification, are permitted only as authorized by the OpenLDAP
## Public License.
##
## A copy of this license is available in the file LICENSE in the
## top-level directory of the distribution or, alternatively, at
## <http://www.OpenLDAP.org/license.html>.
##
## ACKNOWLEDGEMENTS:
## This work was developed by Symas Corporation
## based on back-meta module for inclusion in OpenLDAP Software.
## This work was sponsored by Ericsson
SRCS = init.c config.c search.c message_queue.c bind.c unbind.c add.c compare.c \
delete.c modify.c modrdn.c suffixmassage.c map.c \
conn.c candidates.c dncache.c meta_result.c abandon.c
OBJS = init.lo config.lo search.lo message_queue.lo bind.lo unbind.lo add.lo compare.lo \
delete.lo modify.lo modrdn.lo suffixmassage.lo map.lo \
conn.lo candidates.lo dncache.lo meta_result.lo abandon.lo
LDAP_INCDIR= ../../../include
LDAP_LIBDIR= ../../../libraries
BUILD_OPT = "--enable-asyncmeta"
BUILD_MOD = @BUILD_ASYNCMETA@
mod_DEFS = -DSLAPD_IMPORT
MOD_DEFS = $(@BUILD_ASYNCMETA@_DEFS)
shared_LDAP_LIBS = $(LDAP_LIBLDAP_R_LA) $(LDAP_LIBLBER_LA)
NT_LINK_LIBS = -L.. -lslapd $(LIBS) $(@BUILD_LIBS_DYNAMIC@_LDAP_LIBS)
UNIX_LINK_LIBS = $(@BUILD_LIBS_DYNAMIC@_LDAP_LIBS)
LIBBASE = back_asyncmeta
XINCPATH = -I.. -I$(srcdir)/..
XDEFS = $(MODULES_CPPFLAGS)
all-local-lib: ../.backend
../.backend: lib$(LIBBASE).a
@touch $@

View file

@ -0,0 +1,52 @@
/* abandon.c - abandon request handler for back-asyncmeta */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2016 The OpenLDAP Foundation.
* Portions Copyright 2016 Symas Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
/* ACKNOWLEDGEMENTS:
* This work was developed by Symas Corporation
* based on back-meta module for inclusion in OpenLDAP Software.
* This work was sponsored by Ericsson. */
#include "portable.h"
#include <stdio.h>
#include <ac/string.h>
#include <ac/socket.h>
#include "slap.h"
#include "../back-ldap/back-ldap.h"
#include "back-asyncmeta.h"
#include "ldap_rq.h"
/* function is unused */
int
asyncmeta_back_abandon( Operation *op, SlapReply *rs )
{
Operation *t_op;
/* Find the ops being abandoned */
ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
LDAP_STAILQ_FOREACH( t_op, &op->o_conn->c_ops, o_next ) {
if ( t_op->o_msgid == op->orn_msgid ) {
t_op->o_abandon = 1;
}
}
ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
return LDAP_SUCCESS;
}

View file

@ -0,0 +1,368 @@
/* add.c - add request handler for back-asyncmeta */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2016 The OpenLDAP Foundation.
* Portions Copyright 2016 Symas Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
/* ACKNOWLEDGEMENTS:
* This work was developed by Symas Corporation
* based on back-meta module for inclusion in OpenLDAP Software.
* This work was sponsored by Ericsson. */
#include "portable.h"
#include <stdio.h>
#include <ac/string.h>
#include <ac/socket.h>
#include "slap.h"
#include "../back-ldap/back-ldap.h"
#include "back-asyncmeta.h"
#include "ldap_rq.h"
#include "../../../libraries/liblber/lber-int.h"
#include "../../../libraries/libldap/ldap-int.h"
void
asyncmeta_sender_error(Operation *op,
SlapReply *rs,
slap_callback *cb)
{
if (cb != NULL) {
op->o_callback = cb;
}
send_ldap_result(op, rs);
}
meta_search_candidate_t
asyncmeta_back_add_start(Operation *op,
SlapReply *rs,
a_metaconn_t *mc,
bm_context_t *bc,
int candidate)
{
int isupdate;
Attribute *a;
int i;
LDAPMod **attrs;
struct berval mapped;
a_dncookie dc;
a_metainfo_t *mi = mc->mc_info;
a_metatarget_t *mt = mi->mi_targets[ candidate ];
struct berval mdn;
meta_search_candidate_t retcode = META_SEARCH_CANDIDATE;
BerElement *ber = NULL;
a_metasingleconn_t *msc = &mc->mc_conns[ candidate ];
SlapReply *candidates = bc->candidates;
ber_int_t msgid;
LDAPControl **ctrls = NULL;
int rc, nretries = 1;
dc.target = mt;
dc.conn = op->o_conn;
dc.rs = rs;
dc.ctx = "addDN";
mdn.bv_len = 0;
switch (asyncmeta_dn_massage( &dc, &bc->op->o_req_dn, &mdn ) )
{
case LDAP_SUCCESS:
break;
case LDAP_UNWILLING_TO_PERFORM:
rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
rs->sr_text = "Operation not allowed";
retcode = META_SEARCH_ERR;
goto doreturn;
default:
rs->sr_err = LDAP_NO_SUCH_OBJECT;
retcode = META_SEARCH_NOT_CANDIDATE;
goto doreturn;
}
/* Count number of attributes in entry ( +1 ) */
for ( i = 1, a = op->ora_e->e_attrs; a; i++, a = a->a_next );
/* Create array of LDAPMods for ldap_add() */
attrs = ch_malloc( sizeof( LDAPMod * )*i );
dc.ctx = "addAttrDN";
isupdate = be_shadow_update( op );
for ( i = 0, a = op->ora_e->e_attrs; a; a = a->a_next ) {
int j, is_oc = 0;
if ( !isupdate && !get_relax( op ) && a->a_desc->ad_type->sat_no_user_mod )
{
continue;
}
if ( a->a_desc == slap_schema.si_ad_objectClass
|| a->a_desc == slap_schema.si_ad_structuralObjectClass )
{
is_oc = 1;
mapped = a->a_desc->ad_cname;
} else {
asyncmeta_map( &mt->mt_rwmap.rwm_at,
&a->a_desc->ad_cname, &mapped, BACKLDAP_MAP );
if ( BER_BVISNULL( &mapped ) || BER_BVISEMPTY( &mapped ) ) {
continue;
}
}
attrs[ i ] = ch_malloc( sizeof( LDAPMod ) );
if ( attrs[ i ] == NULL ) {
continue;
}
attrs[ i ]->mod_op = LDAP_MOD_BVALUES;
attrs[ i ]->mod_type = mapped.bv_val;
if ( is_oc ) {
for ( j = 0; !BER_BVISNULL( &a->a_vals[ j ] ); j++ );
attrs[ i ]->mod_bvalues =
(struct berval **)ch_malloc( ( j + 1 ) *
sizeof( struct berval * ) );
for ( j = 0; !BER_BVISNULL( &a->a_vals[ j ] ); ) {
struct ldapmapping *mapping;
asyncmeta_mapping( &mt->mt_rwmap.rwm_oc,
&a->a_vals[ j ], &mapping, BACKLDAP_MAP );
if ( mapping == NULL ) {
if ( mt->mt_rwmap.rwm_oc.drop_missing ) {
continue;
}
attrs[ i ]->mod_bvalues[ j ] = &a->a_vals[ j ];
} else {
attrs[ i ]->mod_bvalues[ j ] = &mapping->dst;
}
j++;
}
attrs[ i ]->mod_bvalues[ j ] = NULL;
} else {
/*
* FIXME: dn-valued attrs should be rewritten
* to allow their use in ACLs at the back-ldap
* level.
*/
if ( a->a_desc->ad_type->sat_syntax ==
slap_schema.si_syn_distinguishedName )
{
(void)asyncmeta_dnattr_rewrite( &dc, a->a_vals );
if ( a->a_vals == NULL ) {
continue;
}
}
for ( j = 0; !BER_BVISNULL( &a->a_vals[ j ] ); j++ )
;
attrs[ i ]->mod_bvalues = ch_malloc( ( j + 1 ) * sizeof( struct berval * ) );
for ( j = 0; !BER_BVISNULL( &a->a_vals[ j ] ); j++ ) {
attrs[ i ]->mod_bvalues[ j ] = &a->a_vals[ j ];
}
attrs[ i ]->mod_bvalues[ j ] = NULL;
}
i++;
}
attrs[ i ] = NULL;
retry:;
ctrls = op->o_ctrls;
if ( asyncmeta_controls_add( op, rs, mc, candidate, &ctrls ) != LDAP_SUCCESS )
{
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
retcode = META_SEARCH_ERR;
goto done;
}
ber = ldap_build_add_req( msc->msc_ld, mdn.bv_val, attrs, ctrls, NULL, &msgid);
if (ber) {
candidates[ candidate ].sr_msgid = msgid;
rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_ADD,
mdn.bv_val, ber, msgid );
if (rc == msgid)
rc = LDAP_SUCCESS;
else
rc = LDAP_SERVER_DOWN;
switch ( rc ) {
case LDAP_SUCCESS:
retcode = META_SEARCH_CANDIDATE;
asyncmeta_set_msc_time(msc);
break;
case LDAP_SERVER_DOWN:
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
asyncmeta_clear_one_msc(NULL, mc, candidate);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
if ( nretries && asyncmeta_retry( op, rs, &mc, candidate, LDAP_BACK_DONTSEND ) ) {
nretries = 0;
/* if the identity changed, there might be need to re-authz */
(void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
goto retry;
}
default:
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
retcode = META_SEARCH_ERR;
}
}
done:
(void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
for ( --i; i >= 0; --i ) {
free( attrs[ i ]->mod_bvalues );
free( attrs[ i ] );
}
free( attrs );
if ( mdn.bv_val != op->ora_e->e_dn ) {
free( mdn.bv_val );
BER_BVZERO( &mdn );
}
doreturn:;
Debug( LDAP_DEBUG_TRACE, "%s <<< asyncmeta_back_add_start[%p]=%d\n", op->o_log_prefix, msc, candidates[candidate].sr_msgid );
return retcode;
}
int
asyncmeta_back_add( Operation *op, SlapReply *rs )
{
a_metainfo_t *mi = ( a_metainfo_t * )op->o_bd->be_private;
a_metatarget_t *mt;
a_metaconn_t *mc;
int rc, candidate = -1;
OperationBuffer opbuf;
bm_context_t *bc;
SlapReply *candidates;
slap_callback *cb = op->o_callback;
Debug(LDAP_DEBUG_ARGS, "==> asyncmeta_back_add: %s\n",
op->o_req_dn.bv_val, 0, 0 );
asyncmeta_new_bm_context(op, rs, &bc, mi->mi_ntargets );
if (bc == NULL) {
rs->sr_err = LDAP_OTHER;
asyncmeta_sender_error(op, rs, cb);
return rs->sr_err;
}
candidates = bc->candidates;
mc = asyncmeta_getconn( op, rs, candidates, &candidate, LDAP_BACK_DONTSEND, 0);
if ( !mc || rs->sr_err != LDAP_SUCCESS) {
asyncmeta_sender_error(op, rs, cb);
asyncmeta_clear_bm_context(bc);
return rs->sr_err;
}
mt = mi->mi_targets[ candidate ];
bc->timeout = mt->mt_timeout[ SLAP_OP_ADD ];
bc->retrying = LDAP_BACK_RETRYING;
bc->sendok = ( LDAP_BACK_SENDRESULT | bc->retrying );
bc->stoptime = op->o_time + bc->timeout;
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
rc = asyncmeta_add_message_queue(mc, bc);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
if (rc != LDAP_SUCCESS) {
rs->sr_err = LDAP_BUSY;
rs->sr_text = "Maximum pending ops limit exceeded";
asyncmeta_clear_bm_context(bc);
asyncmeta_sender_error(op, rs, cb);
goto finish;
}
rc = asyncmeta_dobind_init_with_retry(op, rs, bc, mc, candidate);
switch (rc)
{
case META_SEARCH_CANDIDATE:
/* target is already bound, just send the request */
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_add: "
"cnd=\"%ld\"\n", op->o_log_prefix, candidate , 0);
rc = asyncmeta_back_add_start( op, rs, mc, bc, candidate);
if (rc == META_SEARCH_ERR) {
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
asyncmeta_drop_bc(mc, bc);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
asyncmeta_sender_error(op, rs, cb);
asyncmeta_clear_bm_context(bc);
goto finish;
}
break;
case META_SEARCH_NOT_CANDIDATE:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_add: NOT_CANDIDATE "
"cnd=\"%ld\"\n", op->o_log_prefix, candidate , 0);
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
asyncmeta_drop_bc(mc, bc);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
asyncmeta_sender_error(op, rs, cb);
asyncmeta_clear_bm_context(bc);
goto finish;
case META_SEARCH_NEED_BIND:
case META_SEARCH_CONNECTING:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_add: NEED_BIND "
"cnd=\"%ld\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]);
rc = asyncmeta_dobind_init(op, rs, bc, mc, candidate);
if (rc == META_SEARCH_ERR) {
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
asyncmeta_drop_bc(mc, bc);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
asyncmeta_sender_error(op, rs, cb);
asyncmeta_clear_bm_context(bc);
goto finish;
}
break;
case META_SEARCH_BINDING:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_add: BINDING "
"cnd=\"%ld\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]);
/* Todo add the context to the message queue but do not send the request
the receiver must send this when we are done binding */
/* question - how would do receiver know to which targets??? */
break;
case META_SEARCH_ERR:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_add: ERR "
"cnd=\"%ldd\"\n", op->o_log_prefix, candidate , 0);
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
candidates[ candidate ].sr_type = REP_RESULT;
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
asyncmeta_drop_bc(mc, bc);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
asyncmeta_sender_error(op, rs, cb);
asyncmeta_clear_bm_context(bc);
goto finish;
default:
assert( 0 );
break;
}
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
asyncmeta_start_one_listener(mc, candidates, candidate);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
finish:
return rs->sr_err;
}

View file

@ -0,0 +1,847 @@
/* back-asyncmeta.h - main header file for back-asyncmeta module */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2016 The OpenLDAP Foundation.
* Portions Copyright 2016 Symas Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
/* ACKNOWLEDGEMENTS:
* This work was developed by Symas Corporation
* based on back-meta module for inclusion in OpenLDAP Software.
* This work was sponsored by Ericsson. */
#ifndef SLAPD_LDAP_H
#error "include servers/slapd/back-ldap/back-ldap.h before this file!"
#endif /* SLAPD_LDAP_H */
#ifndef SLAPD_ASYNCMETA_H
#define SLAPD_ASYNCMETA_H
#ifndef ENABLE_REWRITE
#error "--enable-rewrite is required!"
#endif
#ifdef LDAP_DEVEL
#define SLAPD_META_CLIENT_PR 1
#endif /* LDAP_DEVEL */
#include "proto-asyncmeta.h"
/* String rewrite library */
#include "rewrite.h"
#include "ldap_rq.h"
LDAP_BEGIN_DECL
/*
* Set META_BACK_PRINT_CONNTREE larger than 0 to dump the connection tree (debug only)
*/
#ifndef META_BACK_PRINT_CONNTREE
#define META_BACK_PRINT_CONNTREE 0
#endif /* !META_BACK_PRINT_CONNTREE */
/* from back-ldap.h before rwm removal */
struct ldapmap {
int drop_missing;
Avlnode *map;
Avlnode *remap;
};
struct ldapmapping {
struct berval src;
struct berval dst;
};
struct ldaprwmap {
/*
* DN rewriting
*/
struct rewrite_info *rwm_rw;
BerVarray rwm_bva_rewrite;
/*
* Attribute/objectClass mapping
*/
struct ldapmap rwm_oc;
struct ldapmap rwm_at;
BerVarray rwm_bva_map;
};
/* Whatever context asyncmeta_dn_massage needs... */
typedef struct a_dncookie {
struct a_metatarget_t *target;
Connection *conn;
char *ctx;
SlapReply *rs;
} a_dncookie;
int asyncmeta_dn_massage(a_dncookie *dc, struct berval *dn,
struct berval *res);
extern int asyncmeta_conn_dup( void *c1, void *c2 );
extern void asyncmeta_conn_free( void *c );
/* attributeType/objectClass mapping */
int asyncmeta_mapping_cmp (const void *, const void *);
int asyncmeta_mapping_dup (void *, void *);
void asyncmeta_map_init ( struct ldapmap *lm, struct ldapmapping ** );
int asyncmeta_mapping ( struct ldapmap *map, struct berval *s,
struct ldapmapping **m, int remap );
void asyncmeta_map ( struct ldapmap *map, struct berval *s, struct berval *m,
int remap );
#define BACKLDAP_MAP 0
#define BACKLDAP_REMAP 1
char *
asyncmeta_map_filter(
struct ldapmap *at_map,
struct ldapmap *oc_map,
struct berval *f,
int remap );
int
asyncmeta_map_attrs(
Operation *op,
struct ldapmap *at_map,
AttributeName *a,
int remap,
char ***mapped_attrs );
extern int
asyncmeta_filter_map_rewrite(
a_dncookie *dc,
Filter *f,
struct berval *fstr,
int remap,
void *memctx );
/* suffix massaging by means of librewrite */
extern int
asyncmeta_suffix_massage_config( struct rewrite_info *info,
struct berval *pvnc,
struct berval *nvnc,
struct berval *prnc,
struct berval *nrnc );
extern int
asyncmeta_back_referral_result_rewrite(
a_dncookie *dc,
BerVarray a_vals,
void *memctx );
extern int
asyncmeta_dnattr_rewrite(
a_dncookie *dc,
BerVarray a_vals );
extern int
asyncmeta_dnattr_result_rewrite(
a_dncookie *dc,
BerVarray a_vals );
/* (end of) from back-ldap.h before rwm removal */
/*
* A a_metasingleconn_t can be in the following, mutually exclusive states:
*
* - none (0x0U)
* - creating META_BACK_FCONN_CREATING
* - initialized META_BACK_FCONN_INITED
* - binding LDAP_BACK_FCONN_BINDING
* - bound/anonymous LDAP_BACK_FCONN_ISBOUND/LDAP_BACK_FCONN_ISANON
*
* possible modifiers are:
*
* - privileged LDAP_BACK_FCONN_ISPRIV
* - privileged, TLS LDAP_BACK_FCONN_ISTLS
* - subjected to idassert LDAP_BACK_FCONN_ISIDASR
* - tainted LDAP_BACK_FCONN_TAINTED
*/
#define META_BACK_FCONN_INITED (0x00100000U)
#define META_BACK_FCONN_CREATING (0x00200000U)
#define META_BACK_CONN_INITED(lc) LDAP_BACK_CONN_ISSET((lc), META_BACK_FCONN_INITED)
#define META_BACK_CONN_INITED_SET(lc) LDAP_BACK_CONN_SET((lc), META_BACK_FCONN_INITED)
#define META_BACK_CONN_INITED_CLEAR(lc) LDAP_BACK_CONN_CLEAR((lc), META_BACK_FCONN_INITED)
#define META_BACK_CONN_INITED_CPY(lc, mlc) LDAP_BACK_CONN_CPY((lc), META_BACK_FCONN_INITED, (mlc))
#define META_BACK_CONN_CREATING(lc) LDAP_BACK_CONN_ISSET((lc), META_BACK_FCONN_CREATING)
#define META_BACK_CONN_CREATING_SET(lc) LDAP_BACK_CONN_SET((lc), META_BACK_FCONN_CREATING)
#define META_BACK_CONN_CREATING_CLEAR(lc) LDAP_BACK_CONN_CLEAR((lc), META_BACK_FCONN_CREATING)
#define META_BACK_CONN_CREATING_CPY(lc, mlc) LDAP_BACK_CONN_CPY((lc), META_BACK_FCONN_CREATING, (mlc))
struct a_metainfo_t;
struct a_metaconn_t;
struct a_metatarget_t;
#define META_NOT_CANDIDATE ((ber_tag_t)0x0)
#define META_CANDIDATE ((ber_tag_t)0x1)
#define META_BINDING ((ber_tag_t)0x2)
#define META_RETRYING ((ber_tag_t)0x4)
typedef struct bm_context_t {
LDAP_SLIST_ENTRY(bm_context_t) bc_next;
time_t timeout;
time_t stoptime;
ldap_back_send_t sendok;
ldap_back_send_t retrying;
int candidate_match;
int sent;
int bc_active;
int searchtime; /* stoptime is a search timelimit */
int is_ok;
SlapReply rs;
Operation *op;
LDAPControl **ctrls;
SlapReply *candidates;
} bm_context_t;
typedef struct a_metasingleconn_t {
#define META_CND_ISSET(rs,f) ( ( (rs)->sr_tag & (f) ) == (f) )
#define META_CND_SET(rs,f) ( (rs)->sr_tag |= (f) )
#define META_CND_CLEAR(rs,f) ( (rs)->sr_tag &= ~(f) )
#define META_CANDIDATE_RESET(rs) ( (rs)->sr_tag = 0 )
#define META_IS_CANDIDATE(rs) META_CND_ISSET( (rs), META_CANDIDATE )
#define META_CANDIDATE_SET(rs) META_CND_SET( (rs), META_CANDIDATE )
#define META_CANDIDATE_CLEAR(rs) META_CND_CLEAR( (rs), META_CANDIDATE )
#define META_IS_BINDING(rs) META_CND_ISSET( (rs), META_BINDING )
#define META_BINDING_SET(rs) META_CND_SET( (rs), META_BINDING )
#define META_BINDING_CLEAR(rs) META_CND_CLEAR( (rs), META_BINDING )
#define META_IS_RETRYING(rs) META_CND_ISSET( (rs), META_RETRYING )
#define META_RETRYING_SET(rs) META_CND_SET( (rs), META_RETRYING )
#define META_RETRYING_CLEAR(rs) META_CND_CLEAR( (rs), META_RETRYING )
LDAP *msc_ld;
LDAP *msc_ldr;
time_t msc_time;
struct berval msc_bound_ndn;
struct berval msc_cred;
unsigned msc_mscflags;
/* NOTE: lc_lcflags is redefined to msc_mscflags to reuse the macros
* defined for back-ldap */
#define lc_lcflags msc_mscflags
int msc_timeout_ops;
/* Connection for the select */
Connection *conn;
} a_metasingleconn_t;
typedef struct a_metaconn_t {
ldapconn_base_t lc_base;
#define mc_base lc_base
//#define mc_conn mc_base.lcb_conn
//#define mc_local_ndn mc_base.lcb_local_ndn
//#define mc_refcnt mc_base.lcb_refcnt
//#define mc_create_time mc_base.lcb_create_time
//#define mc_time mc_base.lcb_time
LDAP_TAILQ_ENTRY(a_metaconn_t) mc_q;
/* NOTE: msc_mscflags is used to recycle the #define
* in metasingleconn_t */
unsigned msc_mscflags;
int mc_active;
/*
* means that the connection is bound;
* of course only one target actually is ...
*/
int mc_authz_target;
#define META_BOUND_NONE (-1)
#define META_BOUND_ALL (-2)
struct a_metainfo_t *mc_info;
int pending_ops;
ldap_pvt_thread_mutex_t mc_om_mutex;
/* queue for pending operations */
LDAP_SLIST_HEAD(BCList, bm_context_t) mc_om_list;
/* supersedes the connection stuff */
a_metasingleconn_t *mc_conns;
} a_metaconn_t;
typedef enum meta_st_t {
#if 0 /* todo */
META_ST_EXACT = LDAP_SCOPE_BASE,
#endif
META_ST_SUBTREE = LDAP_SCOPE_SUBTREE,
META_ST_SUBORDINATE = LDAP_SCOPE_SUBORDINATE,
META_ST_REGEX /* last + 1 */
} meta_st_t;
typedef struct a_metasubtree_t {
meta_st_t ms_type;
union {
struct berval msu_dn;
struct {
struct berval msr_regex_pattern;
regex_t msr_regex;
} msu_regex;
} ms_un;
#define ms_dn ms_un.msu_dn
#define ms_regex ms_un.msu_regex.msr_regex
#define ms_regex_pattern ms_un.msu_regex.msr_regex_pattern
struct a_metasubtree_t *ms_next;
} a_metasubtree_t;
typedef struct metafilter_t {
struct metafilter_t *mf_next;
struct berval mf_regex_pattern;
regex_t mf_regex;
} metafilter_t;
typedef struct a_metacommon_t {
int mc_version;
int mc_nretries;
#define META_RETRY_UNDEFINED (-2)
#define META_RETRY_FOREVER (-1)
#define META_RETRY_NEVER (0)
#define META_RETRY_DEFAULT (10)
unsigned mc_flags;
#define META_BACK_CMN_ISSET(mc,f) ( ( (mc)->mc_flags & (f) ) == (f) )
#define META_BACK_CMN_QUARANTINE(mc) META_BACK_CMN_ISSET( (mc), LDAP_BACK_F_QUARANTINE )
#define META_BACK_CMN_CHASE_REFERRALS(mc) META_BACK_CMN_ISSET( (mc), LDAP_BACK_F_CHASE_REFERRALS )
#define META_BACK_CMN_NOREFS(mc) META_BACK_CMN_ISSET( (mc), LDAP_BACK_F_NOREFS )
#define META_BACK_CMN_NOUNDEFFILTER(mc) META_BACK_CMN_ISSET( (mc), LDAP_BACK_F_NOUNDEFFILTER )
#define META_BACK_CMN_SAVECRED(mc) META_BACK_CMN_ISSET( (mc), LDAP_BACK_F_SAVECRED )
#define META_BACK_CMN_ST_REQUEST(mc) META_BACK_CMN_ISSET( (mc), LDAP_BACK_F_ST_REQUEST )
#ifdef SLAPD_META_CLIENT_PR
/*
* client-side paged results:
* -1: accept unsolicited paged results responses
* 0: off
* >0: always request paged results with size == mt_ps
*/
#define META_CLIENT_PR_DISABLE (0)
#define META_CLIENT_PR_ACCEPT_UNSOLICITED (-1)
ber_int_t mc_ps;
#endif /* SLAPD_META_CLIENT_PR */
slap_retry_info_t mc_quarantine;
time_t mc_network_timeout;
struct timeval mc_bind_timeout;
#define META_BIND_TIMEOUT LDAP_BACK_RESULT_UTIMEOUT
time_t mc_timeout[ SLAP_OP_LAST ];
} a_metacommon_t;
typedef struct a_metatarget_t {
char *mt_uri;
ldap_pvt_thread_mutex_t mt_uri_mutex;
/* TODO: we might want to enable different strategies
* for different targets */
LDAP_REBIND_PROC *mt_rebind_f;
LDAP_URLLIST_PROC *mt_urllist_f;
void *mt_urllist_p;
metafilter_t *mt_filter;
a_metasubtree_t *mt_subtree;
/* F: subtree-include; T: subtree-exclude */
int mt_subtree_exclude;
int mt_scope;
struct berval mt_psuffix; /* pretty suffix */
struct berval mt_nsuffix; /* normalized suffix */
struct berval mt_binddn;
struct berval mt_bindpw;
/* we only care about the TLS options here */
slap_bindconf mt_tls;
slap_idassert_t mt_idassert;
#define mt_idassert_mode mt_idassert.si_mode
#define mt_idassert_authcID mt_idassert.si_bc.sb_authcId
#define mt_idassert_authcDN mt_idassert.si_bc.sb_binddn
#define mt_idassert_passwd mt_idassert.si_bc.sb_cred
#define mt_idassert_authzID mt_idassert.si_bc.sb_authzId
#define mt_idassert_authmethod mt_idassert.si_bc.sb_method
#define mt_idassert_sasl_mech mt_idassert.si_bc.sb_saslmech
#define mt_idassert_sasl_realm mt_idassert.si_bc.sb_realm
#define mt_idassert_secprops mt_idassert.si_bc.sb_secprops
#define mt_idassert_tls mt_idassert.si_bc.sb_tls
#define mt_idassert_flags mt_idassert.si_flags
#define mt_idassert_authz mt_idassert.si_authz
struct ldaprwmap mt_rwmap;
sig_atomic_t mt_isquarantined;
ldap_pvt_thread_mutex_t mt_quarantine_mutex;
a_metacommon_t mt_mc;
#define mt_nretries mt_mc.mc_nretries
#define mt_flags mt_mc.mc_flags
#define mt_version mt_mc.mc_version
#define mt_ps mt_mc.mc_ps
#define mt_network_timeout mt_mc.mc_network_timeout
#define mt_bind_timeout mt_mc.mc_bind_timeout
#define mt_timeout mt_mc.mc_timeout
#define mt_quarantine mt_mc.mc_quarantine
#define META_BACK_TGT_ISSET(mt,f) ( ( (mt)->mt_flags & (f) ) == (f) )
#define META_BACK_TGT_ISMASK(mt,m,f) ( ( (mt)->mt_flags & (m) ) == (f) )
#define META_BACK_TGT_SAVECRED(mt) META_BACK_TGT_ISSET( (mt), LDAP_BACK_F_SAVECRED )
#define META_BACK_TGT_USE_TLS(mt) META_BACK_TGT_ISSET( (mt), LDAP_BACK_F_USE_TLS )
#define META_BACK_TGT_PROPAGATE_TLS(mt) META_BACK_TGT_ISSET( (mt), LDAP_BACK_F_PROPAGATE_TLS )
#define META_BACK_TGT_TLS_CRITICAL(mt) META_BACK_TGT_ISSET( (mt), LDAP_BACK_F_TLS_CRITICAL )
#define META_BACK_TGT_CHASE_REFERRALS(mt) META_BACK_TGT_ISSET( (mt), LDAP_BACK_F_CHASE_REFERRALS )
#define META_BACK_TGT_T_F(mt) META_BACK_TGT_ISMASK( (mt), LDAP_BACK_F_T_F_MASK, LDAP_BACK_F_T_F )
#define META_BACK_TGT_T_F_DISCOVER(mt) META_BACK_TGT_ISMASK( (mt), LDAP_BACK_F_T_F_MASK2, LDAP_BACK_F_T_F_DISCOVER )
#define META_BACK_TGT_ABANDON(mt) META_BACK_TGT_ISMASK( (mt), LDAP_BACK_F_CANCEL_MASK, LDAP_BACK_F_CANCEL_ABANDON )
#define META_BACK_TGT_IGNORE(mt) META_BACK_TGT_ISMASK( (mt), LDAP_BACK_F_CANCEL_MASK, LDAP_BACK_F_CANCEL_IGNORE )
#define META_BACK_TGT_CANCEL(mt) META_BACK_TGT_ISMASK( (mt), LDAP_BACK_F_CANCEL_MASK, LDAP_BACK_F_CANCEL_EXOP )
#define META_BACK_TGT_CANCEL_DISCOVER(mt) META_BACK_TGT_ISMASK( (mt), LDAP_BACK_F_CANCEL_MASK2, LDAP_BACK_F_CANCEL_EXOP_DISCOVER )
#define META_BACK_TGT_QUARANTINE(mt) META_BACK_TGT_ISSET( (mt), LDAP_BACK_F_QUARANTINE )
#ifdef SLAP_CONTROL_X_SESSION_TRACKING
#define META_BACK_TGT_ST_REQUEST(mt) META_BACK_TGT_ISSET( (mt), LDAP_BACK_F_ST_REQUEST )
#define META_BACK_TGT_ST_RESPONSE(mt) META_BACK_TGT_ISSET( (mt), LDAP_BACK_F_ST_RESPONSE )
#endif /* SLAP_CONTROL_X_SESSION_TRACKING */
#define META_BACK_TGT_NOREFS(mt) META_BACK_TGT_ISSET( (mt), LDAP_BACK_F_NOREFS )
#define META_BACK_TGT_NOUNDEFFILTER(mt) META_BACK_TGT_ISSET( (mt), LDAP_BACK_F_NOUNDEFFILTER )
#define META_BACK_CFG_MAX_PENDING_OPS 0x80
#define META_BACK_CFG_MAX_TARGET_CONNS 0xFF
/* the interval of the timeout checking loop in microseconds
* possibly make this configurabe? */
#define META_BACK_CFG_MAX_TIMEOUT_LOOP 0x70000
slap_mask_t mt_rep_flags;
int mt_timeout_ops;
} a_metatarget_t;
typedef struct a_metadncache_t {
ldap_pvt_thread_mutex_t mutex;
Avlnode *tree;
#define META_DNCACHE_DISABLED (0)
#define META_DNCACHE_FOREVER ((time_t)(-1))
time_t ttl; /* seconds; 0: no cache, -1: no expiry */
} a_metadncache_t;
typedef struct a_metacandidates_t {
int mc_ntargets;
SlapReply *mc_candidates;
} a_metacandidates_t;
/*
* Hook to allow mucking with a_metainfo_t/a_metatarget_t when quarantine is over
*/
typedef int (*asyncmeta_quarantine_f)( struct a_metainfo_t *, int target, void * );
struct meta_out_message_t;
typedef struct a_metainfo_t {
int mi_ntargets;
int mi_defaulttarget;
#define META_DEFAULT_TARGET_NONE (-1)
#define mi_nretries mi_mc.mc_nretries
#define mi_flags mi_mc.mc_flags
#define mi_version mi_mc.mc_version
#define mi_ps mi_mc.mc_ps
#define mi_network_timeout mi_mc.mc_network_timeout
#define mi_bind_timeout mi_mc.mc_bind_timeout
#define mi_timeout mi_mc.mc_timeout
#define mi_quarantine mi_mc.mc_quarantine
a_metatarget_t **mi_targets;
a_metacandidates_t *mi_candidates;
LDAP_REBIND_PROC *mi_rebind_f;
LDAP_URLLIST_PROC *mi_urllist_f;
a_metadncache_t mi_cache;
struct {
int mic_num;
LDAP_TAILQ_HEAD(mc_conn_priv_q, a_metaconn_t) mic_priv;
} mi_conn_priv[ LDAP_BACK_PCONN_LAST ];
int mi_conn_priv_max;
/* NOTE: quarantine uses the connection mutex */
asyncmeta_quarantine_f mi_quarantine_f;
void *mi_quarantine_p;
#define li_flags mi_flags
/* uses flags as defined in <back-ldap/back-ldap.h> */
#define META_BACK_F_ONERR_STOP LDAP_BACK_F_ONERR_STOP
#define META_BACK_F_ONERR_REPORT (0x02000000U)
#define META_BACK_F_ONERR_MASK (META_BACK_F_ONERR_STOP|META_BACK_F_ONERR_REPORT)
#define META_BACK_F_DEFER_ROOTDN_BIND (0x04000000U)
#define META_BACK_F_PROXYAUTHZ_ALWAYS (0x08000000U) /* users always proxyauthz */
#define META_BACK_F_PROXYAUTHZ_ANON (0x10000000U) /* anonymous always proxyauthz */
#define META_BACK_F_PROXYAUTHZ_NOANON (0x20000000U) /* anonymous remains anonymous */
#define META_BACK_ONERR_STOP(mi) LDAP_BACK_ISSET( (mi), META_BACK_F_ONERR_STOP )
#define META_BACK_ONERR_REPORT(mi) LDAP_BACK_ISSET( (mi), META_BACK_F_ONERR_REPORT )
#define META_BACK_ONERR_CONTINUE(mi) ( !LDAP_BACK_ISSET( (mi), META_BACK_F_ONERR_MASK ) )
#define META_BACK_DEFER_ROOTDN_BIND(mi) LDAP_BACK_ISSET( (mi), META_BACK_F_DEFER_ROOTDN_BIND )
#define META_BACK_PROXYAUTHZ_ALWAYS(mi) LDAP_BACK_ISSET( (mi), META_BACK_F_PROXYAUTHZ_ALWAYS )
#define META_BACK_PROXYAUTHZ_ANON(mi) LDAP_BACK_ISSET( (mi), META_BACK_F_PROXYAUTHZ_ANON )
#define META_BACK_PROXYAUTHZ_NOANON(mi) LDAP_BACK_ISSET( (mi), META_BACK_F_PROXYAUTHZ_NOANON )
#define META_BACK_QUARANTINE(mi) LDAP_BACK_ISSET( (mi), LDAP_BACK_F_QUARANTINE )
time_t mi_idle_timeout;
struct re_s *mi_task;
a_metacommon_t mi_mc;
ldap_extra_t *mi_ldap_extra;
int mi_max_timeout_ops;
int mi_max_pending_ops;
int mi_max_target_conns;
/* mutex for access to the connection structures */
ldap_pvt_thread_mutex_t mi_mc_mutex;
int mi_num_conns;
int mi_next_conn;
a_metaconn_t *mi_conns;
} a_metainfo_t;
typedef enum meta_op_type {
META_OP_ALLOW_MULTIPLE = 0,
META_OP_REQUIRE_SINGLE,
META_OP_REQUIRE_ALL
} meta_op_type;
extern a_metaconn_t *
asyncmeta_getconn(
Operation *op,
SlapReply *rs,
SlapReply *candidates,
int *candidate,
ldap_back_send_t sendok,
int alloc_new);
extern int
asyncmeta_retry(
Operation *op,
SlapReply *rs,
a_metaconn_t **mcp,
int candidate,
ldap_back_send_t sendok );
extern void
asyncmeta_conn_free(
void *v_mc );
extern int
asyncmeta_init_one_conn(
Operation *op,
SlapReply *rs,
a_metaconn_t *mc,
int candidate,
int ispriv,
ldap_back_send_t sendok,
int dolock );
extern void
asyncmeta_quarantine(
Operation *op,
a_metainfo_t *mi,
SlapReply *rs,
int candidate );
extern int
asyncmeta_dobind(
Operation *op,
SlapReply *rs,
a_metaconn_t *mc,
ldap_back_send_t sendok,
SlapReply *candidates);
extern int
asyncmeta_single_dobind(
Operation *op,
SlapReply *rs,
a_metaconn_t **mcp,
int candidate,
ldap_back_send_t sendok,
int retries,
int dolock );
extern int
asyncmeta_proxy_authz_cred(
a_metaconn_t *mc,
int candidate,
Operation *op,
SlapReply *rs,
ldap_back_send_t sendok,
struct berval *binddn,
struct berval *bindcred,
int *method );
extern int
asyncmeta_cancel(
a_metaconn_t *mc,
Operation *op,
SlapReply *rs,
ber_int_t msgid,
int candidate,
ldap_back_send_t sendok );
extern int
asyncmeta_op_result(
a_metaconn_t *mc,
Operation *op,
SlapReply *rs,
int candidate,
ber_int_t msgid,
time_t timeout,
ldap_back_send_t sendok );
extern int
asyncmeta_controls_add(
Operation *op,
SlapReply *rs,
a_metaconn_t *mc,
int candidate,
LDAPControl ***pctrls );
extern int
asyncmeta_LTX_init_module(
int argc,
char *argv[] );
/*
* Candidate stuff
*/
extern int
asyncmeta_is_candidate(
a_metatarget_t *mt,
struct berval *ndn,
int scope );
extern int
asyncmeta_select_unique_candidate(
a_metainfo_t *mi,
struct berval *ndn );
extern int
asyncmeta_clear_unused_candidates(
Operation *op,
int candidate,
a_metaconn_t *mc,
SlapReply *candidates);
/*
* Dn cache stuff (experimental)
*/
extern int
asyncmeta_dncache_cmp(
const void *c1,
const void *c2 );
extern int
asyncmeta_dncache_dup(
void *c1,
void *c2 );
#define META_TARGET_NONE (-1)
#define META_TARGET_MULTIPLE (-2)
extern int
asyncmeta_dncache_get_target(
a_metadncache_t *cache,
struct berval *ndn );
extern int
meta_dncache_update_entry(
a_metadncache_t *cache,
struct berval *ndn,
int target );
extern int
asyncmeta_dncache_delete_entry(
a_metadncache_t *cache,
struct berval *ndn );
extern void
asyncmeta_dncache_free( void *entry );
extern void
asyncmeta_back_map_free( struct ldapmap *lm );
extern int
asyncmeta_subtree_destroy( a_metasubtree_t *ms );
extern void
asyncmeta_filter_destroy( metafilter_t *mf );
extern int
asyncmeta_target_finish( a_metainfo_t *mi, a_metatarget_t *mt,
const char *log, char *msg, size_t msize
);
extern LDAP_REBIND_PROC asyncmeta_back_default_rebind;
extern LDAP_URLLIST_PROC asyncmeta_back_default_urllist;
/* IGNORE means that target does not (no longer) participate
* in the search;
* NOTREADY means the search on that target has not been initialized yet
*/
#define META_MSGID_IGNORE (-1)
#define META_MSGID_NEED_BIND (-2)
#define META_MSGID_CONNECTING (-3)
#define META_MSGID_UNDEFINED (-4)
typedef enum meta_search_candidate_t {
META_SEARCH_UNDEFINED = -2,
META_SEARCH_ERR = -1,
META_SEARCH_NOT_CANDIDATE,
META_SEARCH_CANDIDATE,
META_SEARCH_BINDING,
META_SEARCH_NEED_BIND,
META_SEARCH_CONNECTING
} meta_search_candidate_t;
Operation* asyncmeta_copy_op(Operation *op);
void asyncmeta_clear_bm_context(bm_context_t *bc);
int asyncmeta_add_message_queue(a_metaconn_t *mc, bm_context_t *bc);
void asyncmeta_drop_bc(a_metaconn_t *mc, bm_context_t *bc);
bm_context_t *
asyncmeta_find_message(ber_int_t msgid, a_metaconn_t *mc, int candidate);
bm_context_t *
asyncmeta_find_message_by_opmsguid(ber_int_t msgid, a_metaconn_t *mc, int remove);
void* asyncmeta_op_handle_result(void *ctx, void *arg);
int asyncmeta_back_cleanup( Operation *op, SlapReply *rs, bm_context_t *bm );
int
asyncmeta_clear_one_msc(
Operation *op,
a_metaconn_t *msc,
int candidate );
a_metaconn_t *
asyncmeta_get_next_mc( a_metainfo_t *mi );
void* asyncmeta_timeout_loop(void *ctx, void *arg);
int
asyncmeta_start_timeout_loop(a_metatarget_t *mt, a_metainfo_t *mi);
void asyncmeta_set_msc_time(a_metasingleconn_t *msc);
void asyncmeta_clear_message_queue(a_metasingleconn_t *msc);
int asyncmeta_back_cancel(
a_metaconn_t *mc,
Operation *op,
ber_int_t msgid,
int candidate );
int
asyncmeta_back_cancel_msc(
Operation *op,
SlapReply *rs,
ber_int_t msgid,
a_metasingleconn_t *msc,
int candidate,
ldap_back_send_t sendok );
int
asyncmeta_back_abandon_candidate(
a_metaconn_t *mc,
Operation *op,
ber_int_t msgid,
int candidate );
void
asyncmeta_send_result(bm_context_t* bc, int error, char *text);
int asyncmeta_new_bm_context(Operation *op, SlapReply *rs, bm_context_t **new_bc, int ntargets);
int asyncmeta_start_listeners(a_metaconn_t *mc, SlapReply *candidates);
int asyncmeta_start_one_listener(a_metaconn_t *mc, SlapReply *candidates, int candidate);
meta_search_candidate_t
asyncmeta_back_search_start(
Operation *op,
SlapReply *rs,
a_metaconn_t *mc,
bm_context_t *bc,
int candidate,
struct berval *prcookie,
ber_int_t prsize );
meta_search_candidate_t
asyncmeta_dobind_init(
Operation *op,
SlapReply *rs,
bm_context_t *bc,
a_metaconn_t *mc,
int candidate);
meta_search_candidate_t
asyncmeta_dobind_init_with_retry(
Operation *op,
SlapReply *rs,
bm_context_t *bc,
a_metaconn_t *mc,
int candidate);
meta_search_candidate_t
asyncmeta_back_add_start(Operation *op,
SlapReply *rs,
a_metaconn_t *mc,
bm_context_t *bc,
int candidate);
meta_search_candidate_t
asyncmeta_back_modify_start(Operation *op,
SlapReply *rs,
a_metaconn_t *mc,
bm_context_t *bc,
int candidate);
meta_search_candidate_t
asyncmeta_back_modrdn_start(Operation *op,
SlapReply *rs,
a_metaconn_t *mc,
bm_context_t *bc,
int candidate);
meta_search_candidate_t
asyncmeta_back_delete_start(Operation *op,
SlapReply *rs,
a_metaconn_t *mc,
bm_context_t *bc,
int candidate);
meta_search_candidate_t
asyncmeta_back_compare_start(Operation *op,
SlapReply *rs,
a_metaconn_t *mc,
bm_context_t *bc,
int candidate);
void
asyncmeta_sender_error(Operation *op,
SlapReply *rs,
slap_callback *cb);
LDAP_END_DECL
#endif /* SLAPD_ASYNCMETA_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,289 @@
/* candidates.c - candidate targets selection and processing for
* back-asyncmeta */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2016 The OpenLDAP Foundation.
* Portions Copyright 2016 Symas Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
/* ACKNOWLEDGEMENTS:
+ * This work was developed by Symas Corporation
+ * based on back-meta module for inclusion in OpenLDAP Software.
+ * This work was sponsored by Ericsson. */
#include "portable.h"
#include <stdio.h>
#include "ac/string.h"
#include "slap.h"
#include "../back-ldap/back-ldap.h"
#include "back-asyncmeta.h"
/*
* The meta-directory has one suffix, called <suffix>.
* It handles a pool of target servers, each with a branch suffix
* of the form <branch X>,<suffix>, where <branch X> may be empty.
*
* When the meta-directory receives a request with a request DN that belongs
* to a branch, the corresponding target is invoked. When the request DN
* does not belong to a specific branch, all the targets that
* are compatible with the request DN are selected as candidates, and
* the request is spawned to all the candidate targets
*
* A request is characterized by a request DN. The following cases are
* handled:
* - the request DN is the suffix: <dn> == <suffix>,
* all the targets are candidates (search ...)
* - the request DN is a branch suffix: <dn> == <branch X>,<suffix>, or
* - the request DN is a subtree of a branch suffix:
* <dn> == <rdn>,<branch X>,<suffix>,
* the target is the only candidate.
*
* A possible extension will include the handling of multiple suffixes
*/
static a_metasubtree_t *
asyncmeta_subtree_match( a_metatarget_t *mt, struct berval *ndn, int scope )
{
a_metasubtree_t *ms = mt->mt_subtree;
for ( ms = mt->mt_subtree; ms; ms = ms->ms_next ) {
switch ( ms->ms_type ) {
case META_ST_SUBTREE:
if ( dnIsSuffix( ndn, &ms->ms_dn ) ) {
return ms;
}
break;
case META_ST_SUBORDINATE:
if ( dnIsSuffix( ndn, &ms->ms_dn ) &&
( ndn->bv_len > ms->ms_dn.bv_len || scope != LDAP_SCOPE_BASE ) )
{
return ms;
}
break;
case META_ST_REGEX:
/* NOTE: cannot handle scope */
if ( regexec( &ms->ms_regex, ndn->bv_val, 0, NULL, 0 ) == 0 ) {
return ms;
}
break;
}
}
return NULL;
}
/*
* returns 1 if suffix is candidate for dn, otherwise 0
*
* Note: this function should never be called if dn is the <suffix>.
*/
int
asyncmeta_is_candidate(
a_metatarget_t *mt,
struct berval *ndn,
int scope )
{
struct berval rdn;
int d = ndn->bv_len - mt->mt_nsuffix.bv_len;
if ( d >= 0 ) {
if ( !dnIsSuffix( ndn, &mt->mt_nsuffix ) ) {
return META_NOT_CANDIDATE;
}
/*
* | match | exclude |
* +---------+---------+-------------------+
* | T | T | not candidate |
* | F | T | continue checking |
* +---------+---------+-------------------+
* | T | F | candidate |
* | F | F | not candidate |
* +---------+---------+-------------------+
*/
if ( mt->mt_subtree ) {
int match = ( asyncmeta_subtree_match( mt, ndn, scope ) != NULL );
if ( !mt->mt_subtree_exclude ) {
return match ? META_CANDIDATE : META_NOT_CANDIDATE;
}
if ( match /* && mt->mt_subtree_exclude */ ) {
return META_NOT_CANDIDATE;
}
}
switch ( mt->mt_scope ) {
case LDAP_SCOPE_SUBTREE:
default:
return META_CANDIDATE;
case LDAP_SCOPE_SUBORDINATE:
if ( d > 0 ) {
return META_CANDIDATE;
}
break;
/* nearly useless; not allowed by config */
case LDAP_SCOPE_ONELEVEL:
if ( d > 0 ) {
rdn.bv_val = ndn->bv_val;
rdn.bv_len = (ber_len_t)d - STRLENOF( "," );
if ( dnIsOneLevelRDN( &rdn ) ) {
return META_CANDIDATE;
}
}
break;
/* nearly useless; not allowed by config */
case LDAP_SCOPE_BASE:
if ( d == 0 ) {
return META_CANDIDATE;
}
break;
}
} else /* if ( d < 0 ) */ {
if ( !dnIsSuffix( &mt->mt_nsuffix, ndn ) ) {
return META_NOT_CANDIDATE;
}
switch ( scope ) {
case LDAP_SCOPE_SUBTREE:
case LDAP_SCOPE_SUBORDINATE:
/*
* suffix longer than dn, but common part matches
*/
return META_CANDIDATE;
case LDAP_SCOPE_ONELEVEL:
rdn.bv_val = mt->mt_nsuffix.bv_val;
rdn.bv_len = (ber_len_t)(-d) - STRLENOF( "," );
if ( dnIsOneLevelRDN( &rdn ) ) {
return META_CANDIDATE;
}
break;
}
}
return META_NOT_CANDIDATE;
}
/*
* meta_back_select_unique_candidate
*
* returns the index of the candidate in case it is unique, otherwise
* META_TARGET_NONE if none matches, or
* META_TARGET_MULTIPLE if more than one matches
* Note: ndn MUST be normalized.
*/
int
asyncmeta_select_unique_candidate(
a_metainfo_t *mi,
struct berval *ndn )
{
int i, candidate = META_TARGET_NONE;
for ( i = 0; i < mi->mi_ntargets; i++ ) {
a_metatarget_t *mt = mi->mi_targets[ i ];
if ( asyncmeta_is_candidate( mt, ndn, LDAP_SCOPE_BASE ) ) {
if ( candidate == META_TARGET_NONE ) {
candidate = i;
} else {
return META_TARGET_MULTIPLE;
}
}
}
return candidate;
}
/*
* asyncmeta_clear_unused_candidates
*
* clears all candidates except candidate
*/
int
asyncmeta_clear_unused_candidates(
Operation *op,
int candidate,
a_metaconn_t *mc,
SlapReply *candidates)
{
a_metainfo_t *mi = mc->mc_info;
int i;
for ( i = 0; i < mi->mi_ntargets; ++i ) {
if ( i == candidate ) {
continue;
}
META_CANDIDATE_RESET( &candidates[ i ] );
}
return 0;
}
int
asyncmeta_clear_one_msc(
Operation *op,
a_metaconn_t *mc,
int candidate )
{
a_metasingleconn_t *msc;
if (mc == NULL) {
return 0;
}
msc = &mc->mc_conns[candidate];
if (msc->conn) {
connection_client_stop( msc->conn );
msc->conn = NULL;
}
if ( msc->msc_ld != NULL ) {
#ifdef DEBUG_205
char buf[ BUFSIZ ];
snprintf( buf, sizeof( buf ), "asyncmeta_clear_one_msc ldap_unbind_ext[%d] ld=%p",
candidate, (void *)msc->msc_ld );
Debug( LDAP_DEBUG_ANY, "### %s %s\n",
op ? op->o_log_prefix : "", buf, 0 );
#endif /* DEBUG_205 */
ldap_unbind_ext( msc->msc_ld, NULL, NULL );
msc->msc_ld = NULL;
ldap_ld_free( msc->msc_ldr, 0, NULL, NULL );
msc->msc_ldr = NULL;
}
if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) {
ber_memfree_x( msc->msc_bound_ndn.bv_val, NULL );
BER_BVZERO( &msc->msc_bound_ndn );
}
if ( !BER_BVISNULL( &msc->msc_cred ) ) {
memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len );
ber_memfree_x( msc->msc_cred.bv_val, NULL );
BER_BVZERO( &msc->msc_cred );
}
msc->msc_time = 0;
msc->msc_mscflags = 0;
msc->msc_timeout_ops = 0;
return 0;
}

View file

@ -0,0 +1,293 @@
/* compare.c - compare exop handler for back-asyncmeta */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2016 The OpenLDAP Foundation.
* Portions Copyright 2016 Symas Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
/* ACKNOWLEDGEMENTS:
+ * This work was developed by Symas Corporation
+ * based on back-meta module for inclusion in OpenLDAP Software.
+ * This work was sponsored by Ericsson. */
#include "portable.h"
#include <stdio.h>
#include <ac/string.h>
#include <ac/socket.h>
#include "slap.h"
#include "../back-ldap/back-ldap.h"
#include "back-asyncmeta.h"
#include "../../../libraries/liblber/lber-int.h"
#include "../../../libraries/libldap/ldap-int.h"
meta_search_candidate_t
asyncmeta_back_compare_start(Operation *op,
SlapReply *rs,
a_metaconn_t *mc,
bm_context_t *bc,
int candidate)
{
a_dncookie dc;
a_metainfo_t *mi = mc->mc_info;
a_metatarget_t *mt = mi->mi_targets[ candidate ];
struct berval mdn = BER_BVNULL;
struct berval mapped_attr = op->orc_ava->aa_desc->ad_cname;
struct berval mapped_value = op->orc_ava->aa_value;
int rc = 0, nretries = 1;
LDAPControl **ctrls = NULL;
meta_search_candidate_t retcode = META_SEARCH_CANDIDATE;
BerElement *ber = NULL;
a_metasingleconn_t *msc = &mc->mc_conns[ candidate ];
SlapReply *candidates = bc->candidates;
ber_int_t msgid;
dc.target = mt;
dc.conn = op->o_conn;
dc.rs = rs;
dc.ctx = "compareDN";
switch ( asyncmeta_dn_massage( &dc, &op->o_req_dn, &mdn ) ) {
case LDAP_UNWILLING_TO_PERFORM:
rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
retcode = META_SEARCH_ERR;
goto doreturn;
default:
break;
}
/*
* if attr is objectClass, try to remap the value
*/
if ( op->orc_ava->aa_desc == slap_schema.si_ad_objectClass ) {
asyncmeta_map( &mt->mt_rwmap.rwm_oc,
&op->orc_ava->aa_value,
&mapped_value, BACKLDAP_MAP );
if ( BER_BVISNULL( &mapped_value ) || BER_BVISEMPTY( &mapped_value ) ) {
rs->sr_err = LDAP_OTHER;
retcode = META_SEARCH_ERR;
goto done;
}
/*
* else try to remap the attribute
*/
} else {
asyncmeta_map( &mt->mt_rwmap.rwm_at,
&op->orc_ava->aa_desc->ad_cname,
&mapped_attr, BACKLDAP_MAP );
if ( BER_BVISNULL( &mapped_attr ) || BER_BVISEMPTY( &mapped_attr ) ) {
rs->sr_err = LDAP_OTHER;
retcode = META_SEARCH_ERR;
goto done;
}
if ( op->orc_ava->aa_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName )
{
dc.ctx = "compareAttrDN";
switch ( asyncmeta_dn_massage( &dc, &op->orc_ava->aa_value, &mapped_value ) )
{
case LDAP_UNWILLING_TO_PERFORM:
rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
retcode = META_SEARCH_ERR;
goto done;
default:
break;
}
}
}
retry:;
ctrls = op->o_ctrls;
if ( asyncmeta_controls_add( op, rs, mc, candidate, &ctrls ) != LDAP_SUCCESS )
{
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
retcode = META_SEARCH_ERR;
goto done;
}
ber = ldap_build_compare_req( msc->msc_ld, mdn.bv_val, mapped_attr.bv_val, &mapped_value,
ctrls, NULL, &msgid);
if (ber) {
candidates[ candidate ].sr_msgid = msgid;
rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_COMPARE,
mdn.bv_val, ber, msgid );
if (rc == msgid)
rc = LDAP_SUCCESS;
else
rc = LDAP_SERVER_DOWN;
switch ( rc ) {
case LDAP_SUCCESS:
retcode = META_SEARCH_CANDIDATE;
asyncmeta_set_msc_time(msc);
break;
case LDAP_SERVER_DOWN:
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
asyncmeta_clear_one_msc(NULL, mc, candidate);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
if ( nretries && asyncmeta_retry( op, rs, &mc, candidate, LDAP_BACK_DONTSEND ) ) {
nretries = 0;
/* if the identity changed, there might be need to re-authz */
(void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
goto retry;
}
default:
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
retcode = META_SEARCH_ERR;
}
}
done:
(void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
if ( mdn.bv_val != op->o_req_dn.bv_val ) {
free( mdn.bv_val );
}
if ( op->orc_ava->aa_value.bv_val != mapped_value.bv_val ) {
free( mapped_value.bv_val );
}
doreturn:;
Debug( LDAP_DEBUG_TRACE, "%s <<< asyncmeta_back_compare_start[%p]=%d\n", op->o_log_prefix, msc, candidates[candidate].sr_msgid );
return retcode;
}
int
asyncmeta_back_compare( Operation *op, SlapReply *rs )
{
a_metainfo_t *mi = ( a_metainfo_t * )op->o_bd->be_private;
a_metatarget_t *mt;
a_metaconn_t *mc;
int rc, candidate = -1;
OperationBuffer opbuf;
bm_context_t *bc;
SlapReply *candidates;
slap_callback *cb = op->o_callback;
Debug(LDAP_DEBUG_ARGS, "==> asyncmeta_back_compare: %s\n",
op->o_req_dn.bv_val, 0, 0 );
asyncmeta_new_bm_context(op, rs, &bc, mi->mi_ntargets );
if (bc == NULL) {
rs->sr_err = LDAP_OTHER;
asyncmeta_sender_error(op, rs, cb);
return rs->sr_err;
}
candidates = bc->candidates;
mc = asyncmeta_getconn( op, rs, candidates, &candidate, LDAP_BACK_DONTSEND, 0);
if ( !mc || rs->sr_err != LDAP_SUCCESS) {
asyncmeta_sender_error(op, rs, cb);
asyncmeta_clear_bm_context(bc);
return rs->sr_err;
}
mt = mi->mi_targets[ candidate ];
bc->timeout = mt->mt_timeout[ SLAP_OP_COMPARE ];
bc->retrying = LDAP_BACK_RETRYING;
bc->sendok = ( LDAP_BACK_SENDRESULT | bc->retrying );
bc->stoptime = op->o_time + bc->timeout;
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
rc = asyncmeta_add_message_queue(mc, bc);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
if (rc != LDAP_SUCCESS) {
rs->sr_err = LDAP_BUSY;
rs->sr_text = "Maximum pending ops limit exceeded";
asyncmeta_clear_bm_context(bc);
asyncmeta_sender_error(op, rs, cb);
goto finish;
}
rc = asyncmeta_dobind_init_with_retry(op, rs, bc, mc, candidate);
switch (rc)
{
case META_SEARCH_CANDIDATE:
/* target is already bound, just send the request */
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_compare: "
"cnd=\"%ld\"\n", op->o_log_prefix, candidate , 0);
rc = asyncmeta_back_compare_start( op, rs, mc, bc, candidate);
if (rc == META_SEARCH_ERR) {
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
asyncmeta_drop_bc(mc, bc);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
asyncmeta_sender_error(op, rs, cb);
asyncmeta_clear_bm_context(bc);
goto finish;
}
break;
case META_SEARCH_NOT_CANDIDATE:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_compare: NOT_CANDIDATE "
"cnd=\"%ld\"\n", op->o_log_prefix, candidate , 0);
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
asyncmeta_drop_bc(mc, bc);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
asyncmeta_sender_error(op, rs, cb);
asyncmeta_clear_bm_context(bc);
goto finish;
case META_SEARCH_NEED_BIND:
case META_SEARCH_CONNECTING:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_compare: NEED_BIND "
"cnd=\"%ld\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]);
rc = asyncmeta_dobind_init(op, rs, bc, mc, candidate);
if (rc == META_SEARCH_ERR) {
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
asyncmeta_drop_bc(mc, bc);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
asyncmeta_sender_error(op, rs, cb);
asyncmeta_clear_bm_context(bc);
goto finish;
}
break;
case META_SEARCH_BINDING:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_compare: BINDING "
"cnd=\"%ld\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]);
/* Todo add the context to the message queue but do not send the request
the receiver must send this when we are done binding */
/* question - how would do receiver know to which targets??? */
break;
case META_SEARCH_ERR:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_compare: ERR "
"cnd=\"%ldd\"\n", op->o_log_prefix, candidate , 0);
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
candidates[ candidate ].sr_type = REP_RESULT;
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
asyncmeta_drop_bc(mc, bc);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
asyncmeta_sender_error(op, rs, cb);
asyncmeta_clear_bm_context(bc);
goto finish;
default:
assert( 0 );
break;
}
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
asyncmeta_start_one_listener(mc, candidates, candidate);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
finish:
return rs->sr_err;
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,240 @@
/* delete.c - delete request handler for back-asyncmeta */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2016 The OpenLDAP Foundation.
* Portions Copyright 2016 Symas Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
/* ACKNOWLEDGEMENTS:
+ * This work was developed by Symas Corporation
+ * based on back-meta module for inclusion in OpenLDAP Software.
+ * This work was sponsored by Ericsson. */
#include "portable.h"
#include <stdio.h>
#include <ac/string.h>
#include <ac/socket.h>
#include "slap.h"
#include "../back-ldap/back-ldap.h"
#include "back-asyncmeta.h"
#include "../../../libraries/liblber/lber-int.h"
#include "../../../libraries/libldap/ldap-int.h"
meta_search_candidate_t
asyncmeta_back_delete_start(Operation *op,
SlapReply *rs,
a_metaconn_t *mc,
bm_context_t *bc,
int candidate)
{
a_metainfo_t *mi = mc->mc_info;
a_metatarget_t *mt = mi->mi_targets[ candidate ];
struct berval mdn = BER_BVNULL;
a_dncookie dc;
int rc = 0, nretries = 1;
LDAPControl **ctrls = NULL;
meta_search_candidate_t retcode = META_SEARCH_CANDIDATE;
BerElement *ber = NULL;
a_metasingleconn_t *msc = &mc->mc_conns[ candidate ];
SlapReply *candidates = bc->candidates;
ber_int_t msgid;
dc.target = mt;
dc.conn = op->o_conn;
dc.rs = rs;
dc.ctx = "deleteDN";
if ( asyncmeta_dn_massage( &dc, &op->o_req_dn, &mdn ) ) {
rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
retcode = META_SEARCH_ERR;
goto doreturn;
}
retry:;
ctrls = op->o_ctrls;
if ( asyncmeta_controls_add( op, rs, mc, candidate, &ctrls ) != LDAP_SUCCESS )
{
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
retcode = META_SEARCH_ERR;
goto done;
}
ber = ldap_build_delete_req( msc->msc_ld, mdn.bv_val, ctrls, NULL, &msgid);
if (ber) {
candidates[ candidate ].sr_msgid = msgid;
rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_DELETE,
mdn.bv_val, ber, msgid );
if (rc == msgid)
rc = LDAP_SUCCESS;
else
rc = LDAP_SERVER_DOWN;
switch ( rc ) {
case LDAP_SUCCESS:
retcode = META_SEARCH_CANDIDATE;
asyncmeta_set_msc_time(msc);
break;
case LDAP_SERVER_DOWN:
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
asyncmeta_clear_one_msc(NULL, mc, candidate);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
if ( nretries && asyncmeta_retry( op, rs, &mc, candidate, LDAP_BACK_DONTSEND ) ) {
nretries = 0;
/* if the identity changed, there might be need to re-authz */
(void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
goto retry;
}
default:
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
retcode = META_SEARCH_ERR;
}
}
done:
(void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
if ( mdn.bv_val != op->o_req_dn.bv_val ) {
free( mdn.bv_val );
BER_BVZERO( &mdn );
}
doreturn:;
Debug( LDAP_DEBUG_TRACE, "%s <<< asyncmeta_back_delete_start[%p]=%d\n", op->o_log_prefix, msc, candidates[candidate].sr_msgid );
return retcode;
}
int
asyncmeta_back_delete( Operation *op, SlapReply *rs )
{
a_metainfo_t *mi = ( a_metainfo_t * )op->o_bd->be_private;
a_metatarget_t *mt;
a_metaconn_t *mc;
int rc, candidate = -1;
OperationBuffer opbuf;
bm_context_t *bc;
SlapReply *candidates;
slap_callback *cb = op->o_callback;
Debug(LDAP_DEBUG_ARGS, "==> asyncmeta_back_delete: %s\n",
op->o_req_dn.bv_val, 0, 0 );
asyncmeta_new_bm_context(op, rs, &bc, mi->mi_ntargets );
if (bc == NULL) {
rs->sr_err = LDAP_OTHER;
asyncmeta_sender_error(op, rs, cb);
return rs->sr_err;
}
candidates = bc->candidates;
mc = asyncmeta_getconn( op, rs, candidates, &candidate, LDAP_BACK_DONTSEND, 0);
if ( !mc || rs->sr_err != LDAP_SUCCESS) {
asyncmeta_sender_error(op, rs, cb);
asyncmeta_clear_bm_context(bc);
return rs->sr_err;
}
mt = mi->mi_targets[ candidate ];
bc->timeout = mt->mt_timeout[ SLAP_OP_DELETE ];
bc->retrying = LDAP_BACK_RETRYING;
bc->sendok = ( LDAP_BACK_SENDRESULT | bc->retrying );
bc->stoptime = op->o_time + bc->timeout;
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
rc = asyncmeta_add_message_queue(mc, bc);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
if (rc != LDAP_SUCCESS) {
rs->sr_err = LDAP_BUSY;
rs->sr_text = "Maximum pending ops limit exceeded";
asyncmeta_clear_bm_context(bc);
asyncmeta_sender_error(op, rs, cb);
goto finish;
}
rc = asyncmeta_dobind_init_with_retry(op, rs, bc, mc, candidate);
switch (rc)
{
case META_SEARCH_CANDIDATE:
/* target is already bound, just send the request */
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_delete: "
"cnd=\"%ld\"\n", op->o_log_prefix, candidate , 0);
rc = asyncmeta_back_delete_start( op, rs, mc, bc, candidate);
if (rc == META_SEARCH_ERR) {
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
asyncmeta_drop_bc(mc, bc);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
asyncmeta_sender_error(op, rs, cb);
asyncmeta_clear_bm_context(bc);
goto finish;
}
break;
case META_SEARCH_NOT_CANDIDATE:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_delete: NOT_CANDIDATE "
"cnd=\"%ld\"\n", op->o_log_prefix, candidate , 0);
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
asyncmeta_drop_bc(mc, bc);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
asyncmeta_sender_error(op, rs, cb);
asyncmeta_clear_bm_context(bc);
goto finish;
case META_SEARCH_NEED_BIND:
case META_SEARCH_CONNECTING:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_delete: NEED_BIND "
"cnd=\"%ld\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]);
rc = asyncmeta_dobind_init(op, rs, bc, mc, candidate);
if (rc == META_SEARCH_ERR) {
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
asyncmeta_drop_bc(mc, bc);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
asyncmeta_sender_error(op, rs, cb);
asyncmeta_clear_bm_context(bc);
goto finish;
}
break;
case META_SEARCH_BINDING:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_delete: BINDING "
"cnd=\"%ld\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]);
/* Todo add the context to the message queue but do not send the request
the receiver must send this when we are done binding */
/* question - how would do receiver know to which targets??? */
break;
case META_SEARCH_ERR:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_delete: ERR "
"cnd=\"%ldd\"\n", op->o_log_prefix, candidate , 0);
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
candidates[ candidate ].sr_type = REP_RESULT;
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
asyncmeta_drop_bc(mc, bc);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
asyncmeta_sender_error(op, rs, cb);
asyncmeta_clear_bm_context(bc);
goto finish;
default:
assert( 0 );
break;
}
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
asyncmeta_start_one_listener(mc, candidates, candidate);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
finish:
return rs->sr_err;
}

View file

@ -0,0 +1,228 @@
/* dncache.c - dn caching for back-asyncmeta */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2016 The OpenLDAP Foundation.
* Portions Copyright 2016 Symas Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
/* ACKNOWLEDGEMENTS:
* This work was developed by Symas Corporation
* based on back-meta module for inclusion in OpenLDAP Software.
* This work was sponsored by Ericsson. */
#include "portable.h"
#include <stdio.h>
#include <ac/string.h>
#include "slap.h"
#include "../back-ldap/back-ldap.h"
#include "back-asyncmeta.h"
/*
* The dncache, at present, maps an entry to the target that holds it.
*/
typedef struct metadncacheentry_t {
struct berval dn;
int target;
time_t lastupdated;
} metadncacheentry_t;
/*
* asyncmeta_dncache_cmp
*
* compares two struct metadncacheentry; used by avl stuff
* FIXME: modify avl stuff to delete an entry based on cmp
* (e.g. when ttl expired?)
*/
int
asyncmeta_dncache_cmp(
const void *c1,
const void *c2 )
{
metadncacheentry_t *cc1 = ( metadncacheentry_t * )c1;
metadncacheentry_t *cc2 = ( metadncacheentry_t * )c2;
/*
* case sensitive, because the dn MUST be normalized
*/
return ber_bvcmp( &cc1->dn, &cc2->dn);
}
/*
* asyncmeta_dncache_dup
*
* returns -1 in case a duplicate struct metadncacheentry has been inserted;
* used by avl stuff
*/
int
asyncmeta_dncache_dup(
void *c1,
void *c2 )
{
metadncacheentry_t *cc1 = ( metadncacheentry_t * )c1;
metadncacheentry_t *cc2 = ( metadncacheentry_t * )c2;
/*
* case sensitive, because the dn MUST be normalized
*/
return ( ber_bvcmp( &cc1->dn, &cc2->dn ) == 0 ) ? -1 : 0;
}
/*
* asyncmeta_dncache_get_target
*
* returns the target a dn belongs to, or -1 in case the dn is not
* in the cache
*/
int
asyncmeta_dncache_get_target(
a_metadncache_t *cache,
struct berval *ndn )
{
metadncacheentry_t tmp_entry,
*entry;
int target = META_TARGET_NONE;
assert( cache != NULL );
assert( ndn != NULL );
tmp_entry.dn = *ndn;
ldap_pvt_thread_mutex_lock( &cache->mutex );
entry = ( metadncacheentry_t * )avl_find( cache->tree,
( caddr_t )&tmp_entry, asyncmeta_dncache_cmp );
if ( entry != NULL ) {
/*
* if cache->ttl < 0, cache never expires;
* if cache->ttl = 0 no cache is used; shouldn't get here
* else, cache is used with ttl
*/
if ( cache->ttl < 0 ) {
target = entry->target;
} else {
if ( entry->lastupdated+cache->ttl > slap_get_time() ) {
target = entry->target;
}
}
}
ldap_pvt_thread_mutex_unlock( &cache->mutex );
return target;
}
/*
* asyncmeta_dncache_update_entry
*
* updates target and lastupdated of a struct metadncacheentry if exists,
* otherwise it gets created; returns -1 in case of error
*/
int
asyncmeta_dncache_update_entry(
a_metadncache_t *cache,
struct berval *ndn,
int target )
{
metadncacheentry_t *entry,
tmp_entry;
time_t curr_time = 0L;
int err = 0;
assert( cache != NULL );
assert( ndn != NULL );
/*
* if cache->ttl < 0, cache never expires;
* if cache->ttl = 0 no cache is used; shouldn't get here
* else, cache is used with ttl
*/
if ( cache->ttl > 0 ) {
curr_time = slap_get_time();
}
tmp_entry.dn = *ndn;
ldap_pvt_thread_mutex_lock( &cache->mutex );
entry = ( metadncacheentry_t * )avl_find( cache->tree,
( caddr_t )&tmp_entry, asyncmeta_dncache_cmp );
if ( entry != NULL ) {
entry->target = target;
entry->lastupdated = curr_time;
} else {
entry = ch_malloc( sizeof( metadncacheentry_t ) + ndn->bv_len + 1 );
if ( entry == NULL ) {
err = -1;
goto error_return;
}
entry->dn.bv_len = ndn->bv_len;
entry->dn.bv_val = (char *)&entry[ 1 ];
AC_MEMCPY( entry->dn.bv_val, ndn->bv_val, ndn->bv_len );
entry->dn.bv_val[ ndn->bv_len ] = '\0';
entry->target = target;
entry->lastupdated = curr_time;
err = avl_insert( &cache->tree, ( caddr_t )entry,
asyncmeta_dncache_cmp, asyncmeta_dncache_dup );
}
error_return:;
ldap_pvt_thread_mutex_unlock( &cache->mutex );
return err;
}
int
asyncmeta_dncache_delete_entry(
a_metadncache_t *cache,
struct berval *ndn )
{
metadncacheentry_t *entry,
tmp_entry;
assert( cache != NULL );
assert( ndn != NULL );
tmp_entry.dn = *ndn;
ldap_pvt_thread_mutex_lock( &cache->mutex );
entry = avl_delete( &cache->tree, ( caddr_t )&tmp_entry,
asyncmeta_dncache_cmp );
ldap_pvt_thread_mutex_unlock( &cache->mutex );
if ( entry != NULL ) {
asyncmeta_dncache_free( ( void * )entry );
}
return 0;
}
/*
* meta_dncache_free
*
* frees an entry
*
*/
void
asyncmeta_dncache_free(
void *e )
{
free( e );
}

View file

@ -0,0 +1,509 @@
/* init.c - initialization of a back-asyncmeta database */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2016 The OpenLDAP Foundation.
* Portions Copyright 2016 Symas Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
/* ACKNOWLEDGEMENTS:
* This work was developed by Symas Corporation
* based on back-meta module for inclusion in OpenLDAP Software.
* This work was sponsored by Ericsson. */
#include "portable.h"
#include <stdio.h>
#include <ac/string.h>
#include <ac/socket.h>
#include "slap.h"
#include "config.h"
#include "../back-ldap/back-ldap.h"
#include "back-asyncmeta.h"
int
asyncmeta_back_open(
BackendInfo *bi )
{
/* FIXME: need to remove the pagedResults, and likely more... */
bi->bi_controls = slap_known_controls;
return 0;
}
int
asyncmeta_back_initialize(
BackendInfo *bi )
{
bi->bi_flags =
#if 0
/* this is not (yet) set essentially because back-meta does not
* directly support extended operations... */
#ifdef LDAP_DYNAMIC_OBJECTS
/* this is set because all the support a proxy has to provide
* is the capability to forward the refresh exop, and to
* pass thru entries that contain the dynamicObject class
* and the entryTtl attribute */
SLAP_BFLAG_DYNAMIC |
#endif /* LDAP_DYNAMIC_OBJECTS */
#endif
/* back-meta recognizes RFC4525 increment;
* let the remote server complain, if needed (ITS#5912) */
SLAP_BFLAG_INCREMENT;
bi->bi_open = asyncmeta_back_open;
bi->bi_config = 0;
bi->bi_close = 0;
bi->bi_destroy = 0;
bi->bi_db_init = asyncmeta_back_db_init;
bi->bi_db_config = config_generic_wrapper;
bi->bi_db_open = asyncmeta_back_db_open;
bi->bi_db_close = asyncmeta_back_db_close;
bi->bi_db_destroy = asyncmeta_back_db_destroy;
bi->bi_op_bind = asyncmeta_back_bind;
bi->bi_op_unbind = 0;
bi->bi_op_search = asyncmeta_back_search;
bi->bi_op_compare = asyncmeta_back_compare;
bi->bi_op_modify = asyncmeta_back_modify;
bi->bi_op_modrdn = asyncmeta_back_modrdn;
bi->bi_op_add = asyncmeta_back_add;
bi->bi_op_delete = asyncmeta_back_delete;
bi->bi_op_abandon = 0;
bi->bi_extended = 0;
bi->bi_chk_referrals = 0;
bi->bi_connection_init = 0;
bi->bi_connection_destroy = asyncmeta_back_conn_destroy;
return asyncmeta_back_init_cf( bi );
}
int
asyncmeta_back_db_init(
Backend *be,
ConfigReply *cr)
{
a_metainfo_t *mi;
int i;
BackendInfo *bi;
bi = backend_info( "ldap" );
if ( !bi || !bi->bi_extra ) {
Debug( LDAP_DEBUG_ANY,
"asyncmeta_back_db_init: needs back-ldap\n",
0, 0, 0 );
return 1;
}
mi = ch_calloc( 1, sizeof( a_metainfo_t ) );
if ( mi == NULL ) {
return -1;
}
/* set default flags */
mi->mi_flags =
META_BACK_F_DEFER_ROOTDN_BIND
| META_BACK_F_PROXYAUTHZ_ALWAYS
| META_BACK_F_PROXYAUTHZ_ANON
| META_BACK_F_PROXYAUTHZ_NOANON;
/*
* At present the default is no default target;
* this may change
*/
mi->mi_defaulttarget = META_DEFAULT_TARGET_NONE;
mi->mi_bind_timeout.tv_sec = 0;
mi->mi_bind_timeout.tv_usec = META_BIND_TIMEOUT;
mi->mi_rebind_f = asyncmeta_back_default_rebind;
mi->mi_urllist_f = asyncmeta_back_default_urllist;
ldap_pvt_thread_mutex_init( &mi->mi_cache.mutex );
/* safe default */
mi->mi_nretries = META_RETRY_DEFAULT;
mi->mi_version = LDAP_VERSION3;
for ( i = LDAP_BACK_PCONN_FIRST; i < LDAP_BACK_PCONN_LAST; i++ ) {
mi->mi_conn_priv[ i ].mic_num = 0;
LDAP_TAILQ_INIT( &mi->mi_conn_priv[ i ].mic_priv );
}
mi->mi_conn_priv_max = LDAP_BACK_CONN_PRIV_DEFAULT;
mi->mi_ldap_extra = (ldap_extra_t *)bi->bi_extra;
ldap_pvt_thread_mutex_init( &mi->mi_mc_mutex);
be->be_private = mi;
be->be_cf_ocs = be->bd_info->bi_cf_ocs;
return 0;
}
int
asyncmeta_target_finish(
a_metainfo_t *mi,
a_metatarget_t *mt,
const char *log,
char *msg,
size_t msize
)
{
slap_bindconf sb = { BER_BVNULL };
struct berval mapped;
int rc;
int msc_num, i;
ber_str2bv( mt->mt_uri, 0, 0, &sb.sb_uri );
sb.sb_version = mt->mt_version;
sb.sb_method = LDAP_AUTH_SIMPLE;
BER_BVSTR( &sb.sb_binddn, "" );
if ( META_BACK_TGT_T_F_DISCOVER( mt ) ) {
rc = slap_discover_feature( &sb,
slap_schema.si_ad_supportedFeatures->ad_cname.bv_val,
LDAP_FEATURE_ABSOLUTE_FILTERS );
if ( rc == LDAP_COMPARE_TRUE ) {
mt->mt_flags |= LDAP_BACK_F_T_F;
}
}
if ( META_BACK_TGT_CANCEL_DISCOVER( mt ) ) {
rc = slap_discover_feature( &sb,
slap_schema.si_ad_supportedExtension->ad_cname.bv_val,
LDAP_EXOP_CANCEL );
if ( rc == LDAP_COMPARE_TRUE ) {
mt->mt_flags |= LDAP_BACK_F_CANCEL_EXOP;
}
}
if ( !( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE )
|| mt->mt_idassert_authz != NULL )
{
mi->mi_flags &= ~META_BACK_F_PROXYAUTHZ_ALWAYS;
}
if ( ( mt->mt_idassert_flags & LDAP_BACK_AUTH_AUTHZ_ALL )
&& !( mt->mt_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) )
{
snprintf( msg, msize,
"%s: inconsistent idassert configuration "
"(likely authz=\"*\" used with \"non-prescriptive\" flag)",
log );
Debug( LDAP_DEBUG_ANY, "%s (target %s)\n",
msg, mt->mt_uri, 0 );
return 1;
}
if ( !( mt->mt_idassert_flags & LDAP_BACK_AUTH_AUTHZ_ALL ) )
{
mi->mi_flags &= ~META_BACK_F_PROXYAUTHZ_ANON;
}
if ( ( mt->mt_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) )
{
mi->mi_flags &= ~META_BACK_F_PROXYAUTHZ_NOANON;
}
BER_BVZERO( &mapped );
asyncmeta_map( &mt->mt_rwmap.rwm_at,
&slap_schema.si_ad_entryDN->ad_cname, &mapped,
BACKLDAP_REMAP );
if ( BER_BVISNULL( &mapped ) || mapped.bv_val[0] == '\0' ) {
mt->mt_rep_flags |= REP_NO_ENTRYDN;
}
BER_BVZERO( &mapped );
asyncmeta_map( &mt->mt_rwmap.rwm_at,
&slap_schema.si_ad_subschemaSubentry->ad_cname, &mapped,
BACKLDAP_REMAP );
if ( BER_BVISNULL( &mapped ) || mapped.bv_val[0] == '\0' ) {
mt->mt_rep_flags |= REP_NO_SUBSCHEMA;
}
return 0;
}
int
asyncmeta_back_db_open(
Backend *be,
ConfigReply *cr )
{
a_metainfo_t *mi = (a_metainfo_t *)be->be_private;
char msg[SLAP_TEXT_BUFLEN];
int i, rc;
if ( mi->mi_ntargets == 0 ) {
/* Dynamically added, nothing to check here until
* some targets get added
*/
if ( slapMode & SLAP_SERVER_RUNNING )
return 0;
Debug( LDAP_DEBUG_ANY,
"asyncmeta_back_db_open: no targets defined\n",
0, 0, 0 );
return 1;
}
mi->mi_num_conns = 0;
for ( i = 0; i < mi->mi_ntargets; i++ ) {
a_metatarget_t *mt = mi->mi_targets[ i ];
if ( asyncmeta_target_finish( mi, mt,
"asyncmeta_back_db_open", msg, sizeof( msg )))
return 1;
}
mi->mi_num_conns = (mi->mi_max_target_conns == 0) ? META_BACK_CFG_MAX_TARGET_CONNS : mi->mi_max_target_conns;
assert(mi->mi_num_conns > 0);
mi->mi_conns = ch_calloc( mi->mi_num_conns, sizeof( a_metaconn_t ));
for (i = 0; i < mi->mi_num_conns; i++) {
a_metaconn_t *mc = &mi->mi_conns[i];
ldap_pvt_thread_mutex_init( &mc->mc_om_mutex);
mc->mc_authz_target = META_BOUND_NONE;
mc->mc_conns = ch_calloc( mi->mi_ntargets, sizeof( a_metasingleconn_t ));
mc->mc_info = mi;
}
ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
mi->mi_task = ldap_pvt_runqueue_insert( &slapd_rq, 0,
asyncmeta_timeout_loop, mi, "asyncmeta_timeout_loop", be->be_suffix[0].bv_val );
ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
return 0;
}
/*
* asyncmeta_back_conn_free()
*
* actually frees a connection; the reference count must be 0,
* and it must not (or no longer) be in the cache.
*/
void
asyncmeta_back_conn_free(
void *v_mc )
{
a_metaconn_t *mc = v_mc;
assert( mc != NULL );
ldap_pvt_thread_mutex_destroy( &mc->mc_om_mutex );
free( mc );
}
static void
mapping_free(
void *v_mapping )
{
struct ldapmapping *mapping = v_mapping;
ch_free( mapping->src.bv_val );
ch_free( mapping->dst.bv_val );
ch_free( mapping );
}
static void
mapping_dst_free(
void *v_mapping )
{
struct ldapmapping *mapping = v_mapping;
if ( BER_BVISEMPTY( &mapping->dst ) ) {
mapping_free( &mapping[ -1 ] );
}
}
void
asyncmeta_back_map_free( struct ldapmap *lm )
{
avl_free( lm->remap, mapping_dst_free );
avl_free( lm->map, mapping_free );
lm->remap = NULL;
lm->map = NULL;
}
static void
asyncmeta_back_stop_miconns( a_metainfo_t *mi )
{
/*Todo do any other mc cleanup here if necessary*/
}
static void
asyncmeta_back_clear_miconns( a_metainfo_t *mi )
{
int i, j;
a_metaconn_t *mc;
for (i = 0; i < mi->mi_num_conns; i++) {
mc = &mi->mi_conns[i];
/* todo clear the message queue */
for (j = 0; j < mi->mi_ntargets; j ++) {
asyncmeta_clear_one_msc(NULL, mc, j);
}
free(mc->mc_conns);
ldap_pvt_thread_mutex_destroy( &mc->mc_om_mutex );
}
free(mi->mi_conns);
}
static void
asyncmeta_target_free(
a_metatarget_t *mt )
{
if ( mt->mt_uri ) {
free( mt->mt_uri );
ldap_pvt_thread_mutex_destroy( &mt->mt_uri_mutex );
}
if ( mt->mt_subtree ) {
asyncmeta_subtree_destroy( mt->mt_subtree );
mt->mt_subtree = NULL;
}
if ( mt->mt_filter ) {
asyncmeta_filter_destroy( mt->mt_filter );
mt->mt_filter = NULL;
}
if ( !BER_BVISNULL( &mt->mt_psuffix ) ) {
free( mt->mt_psuffix.bv_val );
}
if ( !BER_BVISNULL( &mt->mt_nsuffix ) ) {
free( mt->mt_nsuffix.bv_val );
}
if ( !BER_BVISNULL( &mt->mt_binddn ) ) {
free( mt->mt_binddn.bv_val );
}
if ( !BER_BVISNULL( &mt->mt_bindpw ) ) {
free( mt->mt_bindpw.bv_val );
}
if ( !BER_BVISNULL( &mt->mt_idassert_authcID ) ) {
ch_free( mt->mt_idassert_authcID.bv_val );
}
if ( !BER_BVISNULL( &mt->mt_idassert_authcDN ) ) {
ch_free( mt->mt_idassert_authcDN.bv_val );
}
if ( !BER_BVISNULL( &mt->mt_idassert_passwd ) ) {
ch_free( mt->mt_idassert_passwd.bv_val );
}
if ( !BER_BVISNULL( &mt->mt_idassert_authzID ) ) {
ch_free( mt->mt_idassert_authzID.bv_val );
}
if ( !BER_BVISNULL( &mt->mt_idassert_sasl_mech ) ) {
ch_free( mt->mt_idassert_sasl_mech.bv_val );
}
if ( !BER_BVISNULL( &mt->mt_idassert_sasl_realm ) ) {
ch_free( mt->mt_idassert_sasl_realm.bv_val );
}
if ( mt->mt_idassert_authz != NULL ) {
ber_bvarray_free( mt->mt_idassert_authz );
}
if ( mt->mt_rwmap.rwm_rw ) {
rewrite_info_delete( &mt->mt_rwmap.rwm_rw );
if ( mt->mt_rwmap.rwm_bva_rewrite )
ber_bvarray_free( mt->mt_rwmap.rwm_bva_rewrite );
}
asyncmeta_back_map_free( &mt->mt_rwmap.rwm_oc );
asyncmeta_back_map_free( &mt->mt_rwmap.rwm_at );
ber_bvarray_free( mt->mt_rwmap.rwm_bva_map );
free( mt );
}
int
asyncmeta_back_db_close(
Backend *be,
ConfigReply *cr )
{
a_metainfo_t *mi;
if ( be->be_private ) {
int i;
mi = ( a_metainfo_t * )be->be_private;
if ( mi->mi_task != NULL ) {
ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
if ( ldap_pvt_runqueue_isrunning( &slapd_rq, mi->mi_task )) {
ldap_pvt_runqueue_stoptask( &slapd_rq, mi->mi_task);
}
ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
mi->mi_task = NULL;
}
ldap_pvt_thread_mutex_lock( &mi->mi_mc_mutex );
asyncmeta_back_stop_miconns( mi );
ldap_pvt_thread_mutex_unlock( &mi->mi_mc_mutex );
}
}
int
asyncmeta_back_db_destroy(
Backend *be,
ConfigReply *cr )
{
a_metainfo_t *mi;
if ( be->be_private ) {
int i;
mi = ( a_metainfo_t * )be->be_private;
/*
* Destroy the per-target stuff (assuming there's at
* least one ...)
*/
if ( mi->mi_targets != NULL ) {
for ( i = 0; i < mi->mi_ntargets; i++ ) {
a_metatarget_t *mt = mi->mi_targets[ i ];
if ( META_BACK_TGT_QUARANTINE( mt ) ) {
if ( mt->mt_quarantine.ri_num != mi->mi_quarantine.ri_num )
{
mi->mi_ldap_extra->retry_info_destroy( &mt->mt_quarantine );
}
ldap_pvt_thread_mutex_destroy( &mt->mt_quarantine_mutex );
}
asyncmeta_target_free( mt );
}
free( mi->mi_targets );
}
ldap_pvt_thread_mutex_lock( &mi->mi_cache.mutex );
if ( mi->mi_cache.tree ) {
avl_free( mi->mi_cache.tree, asyncmeta_dncache_free );
}
ldap_pvt_thread_mutex_unlock( &mi->mi_cache.mutex );
ldap_pvt_thread_mutex_destroy( &mi->mi_cache.mutex );
if ( mi->mi_candidates != NULL ) {
ber_memfree_x( mi->mi_candidates, NULL );
}
if ( META_BACK_QUARANTINE( mi ) ) {
mi->mi_ldap_extra->retry_info_destroy( &mi->mi_quarantine );
}
}
ldap_pvt_thread_mutex_lock( &mi->mi_mc_mutex );
asyncmeta_back_clear_miconns(mi);
ldap_pvt_thread_mutex_unlock( &mi->mi_mc_mutex );
ldap_pvt_thread_mutex_destroy( &mi->mi_mc_mutex );
free( be->be_private );
return 0;
}
#if SLAPD_ASYNCMETA == SLAPD_MOD_DYNAMIC
/* conditionally define the init_module() function */
SLAP_BACKEND_INIT_MODULE( asyncmeta )
#endif /* SLAPD_ASYNCMETA == SLAPD_MOD_DYNAMIC */

View file

@ -0,0 +1,874 @@
/* map.c - ldap backend mapping routines */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2016 The OpenLDAP Foundation.
* Portions Copyright 2016 Symas Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
/* ACKNOWLEDGEMENTS:
* This work was developed by Symas Corporation
* based on back-meta module for inclusion in OpenLDAP Software.
* This work was sponsored by Ericsson. */
/* This is an altered version */
/*
* Copyright 1999, Howard Chu, All rights reserved. <hyc@highlandsun.com>
*
* Permission is granted to anyone to use this software for any purpose
* on any computer system, and to alter it and redistribute it, subject
* to the following restrictions:
*
* 1. The author is not responsible for the consequences of use of this
* software, no matter how awful, even if they arise from flaws in it.
*
* 2. The origin of this software must not be misrepresented, either by
* explicit claim or by omission. Since few users ever read sources,
* credits should appear in the documentation.
*
* 3. Altered versions must be plainly marked as such, and must not be
* misrepresented as being the original software. Since few users
* ever read sources, credits should appear in the documentation.
*
* 4. This notice may not be removed or altered.
*
*
*
* Copyright 2016, Symas Corporation
*
* This is based on the back-meta/map.c version by Pierangelo Masarati.
* The previously reported conditions apply to the modified code as well.
* Changes in the original code are highlighted where required.
* Credits for the original code go to the author, Howard Chu.
*/
#include "portable.h"
#include <stdio.h>
#include <ac/string.h>
#include <ac/socket.h>
#include "slap.h"
#include "lutil.h"
#include "../back-ldap/back-ldap.h"
#include "back-asyncmeta.h"
int
asyncmeta_mapping_cmp ( const void *c1, const void *c2 )
{
struct ldapmapping *map1 = (struct ldapmapping *)c1;
struct ldapmapping *map2 = (struct ldapmapping *)c2;
int rc = map1->src.bv_len - map2->src.bv_len;
if (rc) return rc;
return ( strcasecmp( map1->src.bv_val, map2->src.bv_val ) );
}
int
asyncmeta_mapping_dup ( void *c1, void *c2 )
{
struct ldapmapping *map1 = (struct ldapmapping *)c1;
struct ldapmapping *map2 = (struct ldapmapping *)c2;
return ( ( strcasecmp( map1->src.bv_val, map2->src.bv_val ) == 0 ) ? -1 : 0 );
}
void
asyncmeta_map_init ( struct ldapmap *lm, struct ldapmapping **m )
{
struct ldapmapping *mapping;
assert( m != NULL );
*m = NULL;
mapping = (struct ldapmapping *)ch_calloc( 2,
sizeof( struct ldapmapping ) );
if ( mapping == NULL ) {
return;
}
ber_str2bv( "objectclass", STRLENOF("objectclass"), 1, &mapping[0].src);
ber_dupbv( &mapping[0].dst, &mapping[0].src );
mapping[1].src = mapping[0].src;
mapping[1].dst = mapping[0].dst;
avl_insert( &lm->map, (caddr_t)&mapping[0],
asyncmeta_mapping_cmp, asyncmeta_mapping_dup );
avl_insert( &lm->remap, (caddr_t)&mapping[1],
asyncmeta_mapping_cmp, asyncmeta_mapping_dup );
*m = mapping;
}
int
asyncmeta_mapping ( struct ldapmap *map, struct berval *s, struct ldapmapping **m,
int remap )
{
Avlnode *tree;
struct ldapmapping fmapping;
assert( m != NULL );
/* let special attrnames slip through (ITS#5760) */
if ( bvmatch( s, slap_bv_no_attrs )
|| bvmatch( s, slap_bv_all_user_attrs )
|| bvmatch( s, slap_bv_all_operational_attrs ) )
{
*m = NULL;
return 0;
}
if ( remap == BACKLDAP_REMAP ) {
tree = map->remap;
} else {
tree = map->map;
}
fmapping.src = *s;
*m = (struct ldapmapping *)avl_find( tree, (caddr_t)&fmapping, asyncmeta_mapping_cmp );
if ( *m == NULL ) {
return map->drop_missing;
}
return 0;
}
void
asyncmeta_map ( struct ldapmap *map, struct berval *s, struct berval *bv,
int remap )
{
struct ldapmapping *mapping;
int drop_missing;
/* map->map may be NULL when mapping is configured,
* but map->remap can't */
if ( map->remap == NULL ) {
*bv = *s;
return;
}
BER_BVZERO( bv );
drop_missing = asyncmeta_mapping( map, s, &mapping, remap );
if ( mapping != NULL ) {
if ( !BER_BVISNULL( &mapping->dst ) ) {
*bv = mapping->dst;
}
return;
}
if ( !drop_missing ) {
*bv = *s;
}
}
int
asyncmeta_map_attrs(
Operation *op,
struct ldapmap *at_map,
AttributeName *an,
int remap,
char ***mapped_attrs )
{
int i, x, j;
char **na;
struct berval mapped;
if ( an == NULL && op->o_bd->be_extra_anlist == NULL ) {
*mapped_attrs = NULL;
return LDAP_SUCCESS;
}
i = 0;
if ( an != NULL ) {
for ( ; !BER_BVISNULL( &an[i].an_name ); i++ )
/* */ ;
}
x = 0;
if ( op->o_bd->be_extra_anlist != NULL ) {
for ( ; !BER_BVISNULL( &op->o_bd->be_extra_anlist[x].an_name ); x++ )
/* */ ;
}
assert( i > 0 || x > 0 );
na = (char **)ber_memcalloc_x( i + x + 1, sizeof(char *), op->o_tmpmemctx );
if ( na == NULL ) {
*mapped_attrs = NULL;
return LDAP_NO_MEMORY;
}
j = 0;
if ( i > 0 ) {
for ( i = 0; !BER_BVISNULL( &an[i].an_name ); i++ ) {
asyncmeta_map( at_map, &an[i].an_name, &mapped, remap );
if ( !BER_BVISNULL( &mapped ) && !BER_BVISEMPTY( &mapped ) ) {
na[j++] = mapped.bv_val;
}
}
}
if ( x > 0 ) {
for ( x = 0; !BER_BVISNULL( &op->o_bd->be_extra_anlist[x].an_name ); x++ ) {
if ( op->o_bd->be_extra_anlist[x].an_desc &&
ad_inlist( op->o_bd->be_extra_anlist[x].an_desc, an ) )
{
continue;
}
asyncmeta_map( at_map, &op->o_bd->be_extra_anlist[x].an_name, &mapped, remap );
if ( !BER_BVISNULL( &mapped ) && !BER_BVISEMPTY( &mapped ) ) {
na[j++] = mapped.bv_val;
}
}
}
if ( j == 0 && ( i > 0 || x > 0 ) ) {
na[j++] = LDAP_NO_ATTRS;
}
na[j] = NULL;
*mapped_attrs = na;
return LDAP_SUCCESS;
}
static int
map_attr_value(
a_dncookie *dc,
AttributeDescription *ad,
struct berval *mapped_attr,
struct berval *value,
struct berval *mapped_value,
int remap,
void *memctx )
{
struct berval vtmp;
int freeval = 0;
asyncmeta_map( &dc->target->mt_rwmap.rwm_at, &ad->ad_cname, mapped_attr, remap );
if ( BER_BVISNULL( mapped_attr ) || BER_BVISEMPTY( mapped_attr ) ) {
#if 0
/*
* FIXME: are we sure we need to search oc_map if at_map fails?
*/
asyncmeta_map( &dc->target->mt_rwmap.rwm_oc, &ad->ad_cname, mapped_attr, remap );
if ( BER_BVISNULL( mapped_attr ) || BER_BVISEMPTY( mapped_attr ) ) {
*mapped_attr = ad->ad_cname;
}
#endif
if ( dc->target->mt_rwmap.rwm_at.drop_missing ) {
return -1;
}
*mapped_attr = ad->ad_cname;
}
if ( value == NULL ) {
return 0;
}
if ( ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName )
{
a_dncookie fdc = *dc;
fdc.ctx = "searchFilterAttrDN";
switch ( asyncmeta_dn_massage( &fdc, value, &vtmp ) ) {
case LDAP_SUCCESS:
if ( vtmp.bv_val != value->bv_val ) {
freeval = 1;
}
break;
case LDAP_UNWILLING_TO_PERFORM:
return -1;
case LDAP_OTHER:
return -1;
}
} else if ( ad->ad_type->sat_equality &&
ad->ad_type->sat_equality->smr_usage & SLAP_MR_MUTATION_NORMALIZER )
{
if ( ad->ad_type->sat_equality->smr_normalize(
(SLAP_MR_DENORMALIZE|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX),
NULL, NULL, value, &vtmp, memctx ) )
{
return -1;
}
freeval = 2;
} else if ( ad == slap_schema.si_ad_objectClass || ad == slap_schema.si_ad_structuralObjectClass ) {
asyncmeta_map( &dc->target->mt_rwmap.rwm_oc, value, &vtmp, remap );
if ( BER_BVISNULL( &vtmp ) || BER_BVISEMPTY( &vtmp ) ) {
vtmp = *value;
}
} else {
vtmp = *value;
}
filter_escape_value_x( &vtmp, mapped_value, memctx );
switch ( freeval ) {
case 1:
ber_memfree( vtmp.bv_val );
break;
case 2:
ber_memfree_x( vtmp.bv_val, memctx );
break;
}
return 0;
}
static int
asyncmeta_int_filter_map_rewrite(
a_dncookie *dc,
Filter *f,
struct berval *fstr,
int remap,
void *memctx )
{
int i;
Filter *p;
struct berval atmp,
vtmp,
*tmp;
static struct berval
/* better than nothing... */
ber_bvfalse = BER_BVC( "(!(objectClass=*))" ),
ber_bvtf_false = BER_BVC( "(|)" ),
/* better than nothing... */
ber_bvtrue = BER_BVC( "(objectClass=*)" ),
ber_bvtf_true = BER_BVC( "(&)" ),
#if 0
/* no longer needed; preserved for completeness */
ber_bvundefined = BER_BVC( "(?=undefined)" ),
#endif
ber_bverror = BER_BVC( "(?=error)" ),
ber_bvunknown = BER_BVC( "(?=unknown)" ),
ber_bvnone = BER_BVC( "(?=none)" );
ber_len_t len;
assert( fstr != NULL );
BER_BVZERO( fstr );
if ( f == NULL ) {
ber_dupbv_x( fstr, &ber_bvnone, memctx );
return LDAP_OTHER;
}
switch ( ( f->f_choice & SLAPD_FILTER_MASK ) ) {
case LDAP_FILTER_EQUALITY:
if ( map_attr_value( dc, f->f_av_desc, &atmp,
&f->f_av_value, &vtmp, remap, memctx ) )
{
goto computed;
}
fstr->bv_len = atmp.bv_len + vtmp.bv_len
+ ( sizeof("(=)") - 1 );
fstr->bv_val = ber_memalloc_x( fstr->bv_len + 1, memctx );
snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=%s)",
atmp.bv_val, vtmp.bv_len ? vtmp.bv_val : "" );
ber_memfree_x( vtmp.bv_val, memctx );
break;
case LDAP_FILTER_GE:
if ( map_attr_value( dc, f->f_av_desc, &atmp,
&f->f_av_value, &vtmp, remap, memctx ) )
{
goto computed;
}
fstr->bv_len = atmp.bv_len + vtmp.bv_len
+ ( sizeof("(>=)") - 1 );
fstr->bv_val = ber_memalloc_x( fstr->bv_len + 1, memctx );
snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s>=%s)",
atmp.bv_val, vtmp.bv_len ? vtmp.bv_val : "" );
ber_memfree_x( vtmp.bv_val, memctx );
break;
case LDAP_FILTER_LE:
if ( map_attr_value( dc, f->f_av_desc, &atmp,
&f->f_av_value, &vtmp, remap, memctx ) )
{
goto computed;
}
fstr->bv_len = atmp.bv_len + vtmp.bv_len
+ ( sizeof("(<=)") - 1 );
fstr->bv_val = ber_memalloc_x( fstr->bv_len + 1, memctx );
snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s<=%s)",
atmp.bv_val, vtmp.bv_len ? vtmp.bv_val : "" );
ber_memfree_x( vtmp.bv_val, memctx );
break;
case LDAP_FILTER_APPROX:
if ( map_attr_value( dc, f->f_av_desc, &atmp,
&f->f_av_value, &vtmp, remap, memctx ) )
{
goto computed;
}
fstr->bv_len = atmp.bv_len + vtmp.bv_len
+ ( sizeof("(~=)") - 1 );
fstr->bv_val = ber_memalloc_x( fstr->bv_len + 1, memctx );
snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s~=%s)",
atmp.bv_val, vtmp.bv_len ? vtmp.bv_val : "" );
ber_memfree_x( vtmp.bv_val, memctx );
break;
case LDAP_FILTER_SUBSTRINGS:
if ( map_attr_value( dc, f->f_sub_desc, &atmp,
NULL, NULL, remap, memctx ) )
{
goto computed;
}
/* cannot be a DN ... */
fstr->bv_len = atmp.bv_len + ( STRLENOF( "(=*)" ) );
fstr->bv_val = ber_memalloc_x( fstr->bv_len + 128, memctx ); /* FIXME: why 128 ? */
snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=*)",
atmp.bv_val );
if ( !BER_BVISNULL( &f->f_sub_initial ) ) {
len = fstr->bv_len;
filter_escape_value_x( &f->f_sub_initial, &vtmp, memctx );
fstr->bv_len += vtmp.bv_len;
fstr->bv_val = ber_memrealloc_x( fstr->bv_val, fstr->bv_len + 1, memctx );
snprintf( &fstr->bv_val[len - 2], vtmp.bv_len + 3,
/* "(attr=" */ "%s*)",
vtmp.bv_len ? vtmp.bv_val : "" );
ber_memfree_x( vtmp.bv_val, memctx );
}
if ( f->f_sub_any != NULL ) {
for ( i = 0; !BER_BVISNULL( &f->f_sub_any[i] ); i++ ) {
len = fstr->bv_len;
filter_escape_value_x( &f->f_sub_any[i], &vtmp, memctx );
fstr->bv_len += vtmp.bv_len + 1;
fstr->bv_val = ber_memrealloc_x( fstr->bv_val, fstr->bv_len + 1, memctx );
snprintf( &fstr->bv_val[len - 1], vtmp.bv_len + 3,
/* "(attr=[init]*[any*]" */ "%s*)",
vtmp.bv_len ? vtmp.bv_val : "" );
ber_memfree_x( vtmp.bv_val, memctx );
}
}
if ( !BER_BVISNULL( &f->f_sub_final ) ) {
len = fstr->bv_len;
filter_escape_value_x( &f->f_sub_final, &vtmp, memctx );
fstr->bv_len += vtmp.bv_len;
fstr->bv_val = ber_memrealloc_x( fstr->bv_val, fstr->bv_len + 1, memctx );
snprintf( &fstr->bv_val[len - 1], vtmp.bv_len + 3,
/* "(attr=[init*][any*]" */ "%s)",
vtmp.bv_len ? vtmp.bv_val : "" );
ber_memfree_x( vtmp.bv_val, memctx );
}
break;
case LDAP_FILTER_PRESENT:
if ( map_attr_value( dc, f->f_desc, &atmp,
NULL, NULL, remap, memctx ) )
{
goto computed;
}
fstr->bv_len = atmp.bv_len + ( STRLENOF( "(=*)" ) );
fstr->bv_val = ber_memalloc_x( fstr->bv_len + 1, memctx );
snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=*)",
atmp.bv_val );
break;
case LDAP_FILTER_AND:
case LDAP_FILTER_OR:
case LDAP_FILTER_NOT:
fstr->bv_len = STRLENOF( "(%)" );
fstr->bv_val = ber_memalloc_x( fstr->bv_len + 128, memctx ); /* FIXME: why 128? */
snprintf( fstr->bv_val, fstr->bv_len + 1, "(%c)",
f->f_choice == LDAP_FILTER_AND ? '&' :
f->f_choice == LDAP_FILTER_OR ? '|' : '!' );
for ( p = f->f_list; p != NULL; p = p->f_next ) {
int rc;
len = fstr->bv_len;
rc = asyncmeta_int_filter_map_rewrite( dc, p, &vtmp, remap, memctx );
if ( rc != LDAP_SUCCESS ) {
return rc;
}
fstr->bv_len += vtmp.bv_len;
fstr->bv_val = ber_memrealloc_x( fstr->bv_val, fstr->bv_len + 1, memctx );
snprintf( &fstr->bv_val[len-1], vtmp.bv_len + 2,
/*"("*/ "%s)", vtmp.bv_len ? vtmp.bv_val : "" );
ber_memfree_x( vtmp.bv_val, memctx );
}
break;
case LDAP_FILTER_EXT:
if ( f->f_mr_desc ) {
if ( map_attr_value( dc, f->f_mr_desc, &atmp,
&f->f_mr_value, &vtmp, remap, memctx ) )
{
goto computed;
}
} else {
BER_BVSTR( &atmp, "" );
filter_escape_value_x( &f->f_mr_value, &vtmp, memctx );
}
/* FIXME: cleanup (less ?: operators...) */
fstr->bv_len = atmp.bv_len +
( f->f_mr_dnattrs ? STRLENOF( ":dn" ) : 0 ) +
( !BER_BVISEMPTY( &f->f_mr_rule_text ) ? f->f_mr_rule_text.bv_len + 1 : 0 ) +
vtmp.bv_len + ( STRLENOF( "(:=)" ) );
fstr->bv_val = ber_memalloc_x( fstr->bv_len + 1, memctx );
snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s%s%s%s:=%s)",
atmp.bv_val,
f->f_mr_dnattrs ? ":dn" : "",
!BER_BVISEMPTY( &f->f_mr_rule_text ) ? ":" : "",
!BER_BVISEMPTY( &f->f_mr_rule_text ) ? f->f_mr_rule_text.bv_val : "",
vtmp.bv_len ? vtmp.bv_val : "" );
ber_memfree_x( vtmp.bv_val, memctx );
break;
case SLAPD_FILTER_COMPUTED:
switch ( f->f_result ) {
/* FIXME: treat UNDEFINED as FALSE */
case SLAPD_COMPARE_UNDEFINED:
computed:;
if ( META_BACK_TGT_NOUNDEFFILTER( dc->target ) ) {
return LDAP_COMPARE_FALSE;
}
/* fallthru */
case LDAP_COMPARE_FALSE:
if ( META_BACK_TGT_T_F( dc->target ) ) {
tmp = &ber_bvtf_false;
break;
}
tmp = &ber_bvfalse;
break;
case LDAP_COMPARE_TRUE:
if ( META_BACK_TGT_T_F( dc->target ) ) {
tmp = &ber_bvtf_true;
break;
}
tmp = &ber_bvtrue;
break;
default:
tmp = &ber_bverror;
break;
}
ber_dupbv_x( fstr, tmp, memctx );
break;
default:
ber_dupbv_x( fstr, &ber_bvunknown, memctx );
break;
}
return 0;
}
int
asyncmeta_filter_map_rewrite(
a_dncookie *dc,
Filter *f,
struct berval *fstr,
int remap,
void *memctx )
{
int rc;
a_dncookie fdc;
struct berval ftmp;
static char *dmy = "";
rc = asyncmeta_int_filter_map_rewrite( dc, f, fstr, remap, memctx );
if ( rc != LDAP_SUCCESS ) {
return rc;
}
fdc = *dc;
ftmp = *fstr;
fdc.ctx = "searchFilter";
switch ( rewrite_session( fdc.target->mt_rwmap.rwm_rw, fdc.ctx,
( !BER_BVISEMPTY( &ftmp ) ? ftmp.bv_val : dmy ),
fdc.conn, &fstr->bv_val ) )
{
case REWRITE_REGEXEC_OK:
if ( !BER_BVISNULL( fstr ) ) {
fstr->bv_len = strlen( fstr->bv_val );
} else {
*fstr = ftmp;
}
Debug( LDAP_DEBUG_ARGS,
"[rw] %s: \"%s\" -> \"%s\"\n",
fdc.ctx, BER_BVISNULL( &ftmp ) ? "" : ftmp.bv_val,
BER_BVISNULL( fstr ) ? "" : fstr->bv_val );
rc = LDAP_SUCCESS;
break;
case REWRITE_REGEXEC_UNWILLING:
if ( fdc.rs ) {
fdc.rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
fdc.rs->sr_text = "Operation not allowed";
}
rc = LDAP_UNWILLING_TO_PERFORM;
break;
case REWRITE_REGEXEC_ERR:
if ( fdc.rs ) {
fdc.rs->sr_err = LDAP_OTHER;
fdc.rs->sr_text = "Rewrite error";
}
rc = LDAP_OTHER;
break;
}
if ( fstr->bv_val == dmy ) {
BER_BVZERO( fstr );
} else if ( fstr->bv_val != ftmp.bv_val ) {
/* NOTE: need to realloc mapped filter on slab
* and free the original one, until librewrite
* becomes slab-aware
*/
ber_dupbv_x( &ftmp, fstr, memctx );
ch_free( fstr->bv_val );
*fstr = ftmp;
}
return rc;
}
int
asyncmeta_referral_result_rewrite(
a_dncookie *dc,
BerVarray a_vals,
void *memctx
)
{
int i, last;
assert( dc != NULL );
assert( a_vals != NULL );
for ( last = 0; !BER_BVISNULL( &a_vals[ last ] ); last++ )
;
last--;
for ( i = 0; !BER_BVISNULL( &a_vals[ i ] ); i++ ) {
struct berval dn,
olddn = BER_BVNULL;
int rc;
LDAPURLDesc *ludp;
rc = ldap_url_parse( a_vals[ i ].bv_val, &ludp );
if ( rc != LDAP_URL_SUCCESS ) {
/* leave attr untouched if massage failed */
continue;
}
/* FIXME: URLs like "ldap:///dc=suffix" if passed
* thru ldap_url_parse() and ldap_url_desc2str()
* get rewritten as "ldap:///dc=suffix??base";
* we don't want this to occur... */
if ( ludp->lud_scope == LDAP_SCOPE_BASE ) {
ludp->lud_scope = LDAP_SCOPE_DEFAULT;
}
ber_str2bv( ludp->lud_dn, 0, 0, &olddn );
rc = asyncmeta_dn_massage( dc, &olddn, &dn );
switch ( rc ) {
case LDAP_UNWILLING_TO_PERFORM:
/*
* FIXME: need to check if it may be considered
* legal to trim values when adding/modifying;
* it should be when searching (e.g. ACLs).
*/
ber_memfree( a_vals[ i ].bv_val );
if ( last > i ) {
a_vals[ i ] = a_vals[ last ];
}
BER_BVZERO( &a_vals[ last ] );
last--;
i--;
break;
default:
/* leave attr untouched if massage failed */
if ( !BER_BVISNULL( &dn ) && olddn.bv_val != dn.bv_val )
{
char *newurl;
ludp->lud_dn = dn.bv_val;
newurl = ldap_url_desc2str( ludp );
free( dn.bv_val );
if ( newurl == NULL ) {
/* FIXME: leave attr untouched
* even if ldap_url_desc2str failed...
*/
break;
}
ber_memfree_x( a_vals[ i ].bv_val, memctx );
ber_str2bv_x( newurl, 0, 1, &a_vals[ i ], memctx );
ber_memfree( newurl );
ludp->lud_dn = olddn.bv_val;
}
break;
}
ldap_free_urldesc( ludp );
}
return 0;
}
/*
* I don't like this much, but we need two different
* functions because different heap managers may be
* in use in back-ldap/meta to reduce the amount of
* calls to malloc routines, and some of the free()
* routines may be macros with args
*/
int
asyncmeta_dnattr_rewrite(
a_dncookie *dc,
BerVarray a_vals
)
{
struct berval bv;
int i, last;
assert( a_vals != NULL );
for ( last = 0; !BER_BVISNULL( &a_vals[last] ); last++ )
;
last--;
for ( i = 0; !BER_BVISNULL( &a_vals[i] ); i++ ) {
switch ( asyncmeta_dn_massage( dc, &a_vals[i], &bv ) ) {
case LDAP_UNWILLING_TO_PERFORM:
/*
* FIXME: need to check if it may be considered
* legal to trim values when adding/modifying;
* it should be when searching (e.g. ACLs).
*/
ch_free( a_vals[i].bv_val );
if ( last > i ) {
a_vals[i] = a_vals[last];
}
BER_BVZERO( &a_vals[last] );
last--;
break;
default:
/* leave attr untouched if massage failed */
if ( !BER_BVISNULL( &bv ) && bv.bv_val != a_vals[i].bv_val ) {
ch_free( a_vals[i].bv_val );
a_vals[i] = bv;
}
break;
}
}
return 0;
}
int
asyncmeta_dnattr_result_rewrite(
a_dncookie *dc,
BerVarray a_vals
)
{
struct berval bv;
int i, last;
assert( a_vals != NULL );
for ( last = 0; !BER_BVISNULL( &a_vals[last] ); last++ )
;
last--;
for ( i = 0; !BER_BVISNULL( &a_vals[i] ); i++ ) {
switch ( asyncmeta_dn_massage( dc, &a_vals[i], &bv ) ) {
case LDAP_UNWILLING_TO_PERFORM:
/*
* FIXME: need to check if it may be considered
* legal to trim values when adding/modifying;
* it should be when searching (e.g. ACLs).
*/
ber_memfree( a_vals[i].bv_val );
if ( last > i ) {
a_vals[i] = a_vals[last];
}
BER_BVZERO( &a_vals[last] );
last--;
break;
default:
/* leave attr untouched if massage failed */
if ( !BER_BVISNULL( &bv ) && a_vals[i].bv_val != bv.bv_val ) {
ber_memfree( a_vals[i].bv_val );
a_vals[i] = bv;
}
break;
}
}
return 0;
}

View file

@ -0,0 +1,545 @@
/* message_queue.c - routines to maintain the per-connection lists
* of pending operations */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2016 The OpenLDAP Foundation.
* Portions Copyright 2016 Symas Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
/* ACKNOWLEDGEMENTS:
* This work was developed by Symas Corporation
* based on back-meta module for inclusion in OpenLDAP Software.
* This work was sponsored by Ericsson. */
#include "portable.h"
#include <stdio.h>
#include <ac/socket.h>
#include <ac/string.h>
#include <ac/time.h>
#include "lutil.h"
#include "slap.h"
#include "../back-ldap/back-ldap.h"
#include "back-asyncmeta.h"
#include "../../../libraries/liblber/lber-int.h"
#include "lutil.h"
LDAPControl **asyncmeta_copy_controls(Operation *op)
{
LDAPControl **new_controls = NULL;
LDAPControl **c;
LDAPControl *tmp_ctl = NULL;
int i, length = 1;
if (op->o_ctrls == NULL) {
return NULL;
}
for (c = op->o_ctrls; *c != NULL; c++) {
length++;
}
new_controls = op->o_tmpalloc( sizeof(LDAPControl*)*length, op->o_tmpmemctx );
for (i = 0; i < length-1; i ++) {
new_controls[i] = op->o_tmpalloc( sizeof(LDAPControl), op->o_tmpmemctx );
if (op->o_ctrls[i]->ldctl_value.bv_len > 0) {
ber_dupbv_x( &new_controls[i]->ldctl_value, &op->o_ctrls[i]->ldctl_value, op->o_tmpmemctx);
}
if (op->o_ctrls[i]->ldctl_oid) {
new_controls[i]->ldctl_oid = ber_strdup_x(op->o_ctrls[i]->ldctl_oid, op->o_tmpmemctx);
}
new_controls[i]->ldctl_iscritical = op->o_ctrls[i]->ldctl_iscritical;
}
new_controls[length-1] = NULL;
return new_controls;
}
static
void asyncmeta_free_op_controls(Operation *op)
{
LDAPControl **c;
for (c = op->o_ctrls; *c != NULL; c++) {
if ((*c)->ldctl_value.bv_len > 0) {
free((*c)->ldctl_value.bv_val);
}
if ((*c)->ldctl_oid) {
free((*c)->ldctl_oid);
}
free(*c);
}
free(op->o_ctrls);
}
static
Modifications* asyncmeta_copy_modlist(Operation *op, Modifications *modlist)
{
Modifications *ml;
Modifications *new_mods = NULL;
for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
Modifications *mod = op->o_tmpalloc( sizeof( Modifications ), op->o_tmpmemctx );
*mod = *ml;
if ( ml->sml_values ) {
ber_bvarray_dup_x( &mod->sml_values, ml->sml_values, op->o_tmpmemctx );
if ( ml->sml_nvalues ) {
ber_bvarray_dup_x( &mod->sml_nvalues, ml->sml_nvalues, op->o_tmpmemctx );
}
}
mod->sml_next = NULL;
if (new_mods == NULL) {
new_mods = mod;
} else {
new_mods->sml_next = mod;
}
}
return new_mods;
}
Operation *asyncmeta_copy_op(Operation *op)
{
const char *text;
int rc;
char txtbuf[SLAP_TEXT_BUFLEN];
size_t textlen = sizeof txtbuf;
Entry *e;
Operation *new_op = op->o_tmpcalloc( 1, sizeof(OperationBuffer), op->o_tmpmemctx );
*new_op = *op;
new_op->o_hdr = &((OperationBuffer *) new_op)->ob_hdr;
*(new_op->o_hdr) = *(op->o_hdr);
new_op->o_controls = ((OperationBuffer *) new_op)->ob_controls;
new_op->o_callback = op->o_callback;
new_op->o_ber = NULL;
new_op->o_bd = op->o_bd->bd_self;
ber_dupbv_x( &new_op->o_req_dn, &op->o_req_dn, op->o_tmpmemctx );
ber_dupbv_x( &new_op->o_req_ndn, &op->o_req_ndn, op->o_tmpmemctx );
op->o_callback = NULL;
if (op->o_ndn.bv_len > 0) {
ber_dupbv_x( &new_op->o_ndn, &op->o_ndn, op->o_tmpmemctx );
}
if (op->o_dn.bv_len > 0) {
ber_dupbv_x( &new_op->o_dn, &op->o_dn, op->o_tmpmemctx );
}
new_op->o_ctrls = asyncmeta_copy_controls(op);
switch (op->o_tag) {
case LDAP_REQ_SEARCH:
{
AttributeName *at_names;
int i;
for (i=0; op->ors_attrs && !BER_BVISNULL( &op->ors_attrs[i].an_name ); i++);
if (i > 0) {
at_names = op->o_tmpcalloc( i+1, sizeof( AttributeName ), op->o_tmpmemctx );
at_names[i].an_name.bv_len = 0;
i--;
for (i; i >= 0; i--) {
at_names[i] = op->ors_attrs[i];
ber_dupbv_x( &at_names[i].an_name, &op->ors_attrs[i].an_name, op->o_tmpmemctx );
}
} else {
at_names = NULL;
}
ber_dupbv_x( &new_op->ors_filterstr, &op->ors_filterstr, op->o_tmpmemctx );
new_op->ors_filter = filter_dup( op->ors_filter, op->o_tmpmemctx );
new_op->ors_attrs = at_names;
}
break;
case LDAP_REQ_ADD:
{
slap_entry2mods(op->ora_e, &new_op->ora_modlist, &text, txtbuf, textlen);
e = entry_alloc();
new_op->ora_e = e;
ber_dupbv_x( &e->e_name, &op->o_req_dn, op->o_tmpmemctx );
ber_dupbv_x( &e->e_nname, &op->o_req_ndn, op->o_tmpmemctx );
rc = slap_mods2entry( new_op->ora_modlist, &new_op->ora_e, 1, 0, &text, txtbuf, textlen);
}
break;
case LDAP_REQ_MODIFY:
{
new_op->orm_modlist = asyncmeta_copy_modlist(op, op->orm_modlist);
}
break;
case LDAP_REQ_COMPARE:
new_op->orc_ava = (AttributeAssertion *)ch_calloc( 1, sizeof( AttributeAssertion ));
*new_op->orc_ava = *op->orc_ava;
if ( !BER_BVISNULL( &op->orc_ava->aa_value ) ) {
ber_dupbv_x( &new_op->orc_ava->aa_value, &op->orc_ava->aa_value, op->o_tmpmemctx);
}
break;
case LDAP_REQ_MODRDN:
if (op->orr_newrdn.bv_len > 0) {
ber_dupbv_x( &new_op->orr_newrdn, &op->orr_newrdn, op->o_tmpmemctx );
}
if (op->orr_nnewrdn.bv_len > 0) {
ber_dupbv_x( &new_op->orr_nnewrdn, &op->orr_nnewrdn, op->o_tmpmemctx );
}
if (op->orr_newSup != NULL) {
new_op->orr_newSup = op->o_tmpalloc( sizeof( struct berval ), op->o_tmpmemctx );
new_op->orr_newSup->bv_len = 0;
if (op->orr_newSup->bv_len > 0) {
ber_dupbv_x( new_op->orr_newSup, op->orr_newSup, op->o_tmpmemctx );
}
}
if (op->orr_nnewSup != NULL) {
new_op->orr_nnewSup = op->o_tmpalloc( sizeof( struct berval ), op->o_tmpmemctx );
new_op->orr_nnewSup->bv_len = 0;
if (op->orr_nnewSup->bv_len > 0) {
ber_dupbv_x( new_op->orr_nnewSup, op->orr_nnewSup, op->o_tmpmemctx );
}
}
new_op->orr_modlist = asyncmeta_copy_modlist(op, op->orr_modlist);
break;
case LDAP_REQ_DELETE:
default:
break;
}
return new_op;
}
typedef struct listptr {
void *reserved;
struct listptr *next;
} listptr;
typedef struct listhead {
struct listptr *list;
int cnt;
} listhead;
static void *asyncmeta_memctx_destroy(void *key, void *data)
{
listhead *lh = data;
listptr *lp;
while (lp = lh->list) {
lh->list = lp->next;
slap_sl_mem_destroy((void *)1, lp);
}
ch_free(lh);
}
#ifndef LH_MAX
#define LH_MAX 16
#endif
static void *asyncmeta_memctx_get(void *threadctx)
{
listhead *lh = NULL;
listptr *lp = NULL;
ldap_pvt_thread_pool_getkey(threadctx, asyncmeta_memctx_get, &lh, NULL);
if (!lh) {
lh = ch_malloc(sizeof(listhead));
lh->cnt = 0;
lh->list = NULL;
ldap_pvt_thread_pool_setkey(threadctx, asyncmeta_memctx_get, lh, asyncmeta_memctx_destroy, NULL, NULL);
}
if (lh->list) {
lp = lh->list;
lh->list = lp->next;
lh->cnt--;
slap_sl_mem_setctx(threadctx, lp);
}
return slap_sl_mem_create(SLAP_SLAB_SIZE, SLAP_SLAB_STACK, threadctx, 1);
}
static void asyncmeta_memctx_put(void *threadctx, void *memctx)
{
listhead *lh = NULL;
ldap_pvt_thread_pool_getkey(threadctx, asyncmeta_memctx_get, &lh, NULL);
if (!lh) {
lh = ch_malloc(sizeof(listhead));
lh->cnt = 0;
lh->list = NULL;
ldap_pvt_thread_pool_setkey(threadctx, asyncmeta_memctx_get, lh, asyncmeta_memctx_destroy, NULL, NULL);
}
if (lh->cnt < LH_MAX) {
listptr *lp = memctx;
lp->next = lh->list;
lh->list = lp;
lh->cnt++;
} else {
slap_sl_mem_destroy((void *)1, memctx);
}
}
int asyncmeta_new_bm_context(Operation *op, SlapReply *rs, bm_context_t **new_bc, int ntargets)
{
void *oldctx = op->o_tmpmemctx;
/* prevent old memctx from being destroyed */
slap_sl_mem_setctx(op->o_threadctx, NULL);
/* create new memctx */
op->o_tmpmemctx = asyncmeta_memctx_get( op->o_threadctx );
*new_bc = op->o_tmpcalloc( 1, sizeof( bm_context_t ), op->o_tmpmemctx );
(*new_bc)->op = asyncmeta_copy_op(op);
(*new_bc)->candidates = op->o_tmpcalloc(ntargets, sizeof(SlapReply),op->o_tmpmemctx);
/* restore original memctx */
slap_sl_mem_setctx(op->o_threadctx, oldctx);
op->o_tmpmemctx = oldctx;
return LDAP_SUCCESS;
}
void asyncmeta_free_op(Operation *op)
{
assert (op != NULL);
switch (op->o_tag) {
case LDAP_REQ_SEARCH:
if (op->ors_filterstr.bv_len != 0) {
free(op->ors_filterstr.bv_val);
}
if (op->ors_filter) {
filter_free(op->ors_filter);
}
if (op->ors_attrs) {
free(op->ors_attrs);
}
break;
case LDAP_REQ_ADD:
if ( op->ora_modlist != NULL ) {
slap_mods_free(op->ora_modlist, 0 );
}
if ( op->ora_e != NULL ) {
entry_free( op->ora_e );
}
break;
case LDAP_REQ_MODIFY:
if ( op->orm_modlist != NULL ) {
slap_mods_free(op->orm_modlist, 1 );
}
break;
case LDAP_REQ_MODRDN:
if (op->orr_newrdn.bv_len > 0) {
free(op->orr_newrdn.bv_val);
}
if (op->orr_nnewrdn.bv_len > 0) {
free(op->orr_nnewrdn.bv_val);
}
if (op->orr_nnewSup != NULL ) {
if (op->orr_nnewSup->bv_len > 0) {
free(op->orr_nnewSup->bv_val);
}
free (op->orr_nnewSup);
}
if (op->orr_newSup != NULL ) {
if (op->orr_newSup->bv_len > 0) {
free(op->orr_newSup->bv_val);
}
free (op->orr_newSup);
}
if ( op->orr_modlist != NULL ) {
slap_mods_free(op->orr_modlist, 1 );
}
break;
case LDAP_REQ_COMPARE:
if ( !BER_BVISNULL( &op->orc_ava->aa_value ) ) {
free(op->orc_ava->aa_value.bv_val);
}
free(op->orc_ava);
break;
case LDAP_REQ_DELETE:
break;
default:
Debug( LDAP_DEBUG_TRACE, "==> asyncmeta_free_op : other message type",
0, 0, 0 );
}
if (op->o_ctrls != NULL) {
asyncmeta_free_op_controls(op);
}
if (op->o_ndn.bv_len > 0) {
free(op->o_ndn.bv_val);
}
if (op->o_dn.bv_len > 0) {
free( op->o_dn.bv_val );
}
if (op->o_req_dn.bv_len > 0) {
free(op->o_req_dn.bv_val);
}
if (op->o_req_dn.bv_len > 0) {
free(op->o_req_ndn.bv_val);
}
free(op);
}
void asyncmeta_clear_bm_context(bm_context_t *bc)
{
Operation *op = bc->op;
#if 0
bm_candidates_t *cl;
a_metainfo_t *mi;
int i = 0;
if (bmc == NULL) {
return;
} else if (bmc->cl == NULL) {
free(bmc);
return;
}
cl = bmc->cl;
op = cl->op;
switch (op->o_tag) {
case LDAP_REQ_SEARCH:
break;
case LDAP_REQ_ADD:
if ( (bmc->mdn.bv_len != 0) &&
(bmc->mdn.bv_val != op->o_req_dn.bv_val) ) {
free( bmc->mdn.bv_val );
}
if (bmc->data.add_d.attrs != NULL ) {
while (bmc->data.add_d.attrs[i] != NULL) {
free( bmc->data.add_d.attrs[i]->mod_bvalues );
free( bmc->data.add_d.attrs[i] );
i++;
}
free( bmc->data.add_d.attrs );
}
break;
case LDAP_REQ_MODIFY:
if ( bmc->mdn.bv_val != op->o_req_dn.bv_val ) {
free( bmc->mdn.bv_val );
}
if ( bmc->data.mod_d.modv != NULL ) {
for ( i = 0; bmc->data.mod_d.modv[ i ]; i++ ) {
free( bmc->data.mod_d.modv[ i ]->mod_bvalues );
}
}
free( bmc->data.mod_d.mods );
free( bmc->data.mod_d.modv );
break;
case LDAP_REQ_MODRDN:
if ( bmc->mdn.bv_val != op->o_req_dn.bv_val ) {
free( bmc->mdn.bv_val );
}
if ( bmc->data.modrdn_d.newSuperior.bv_len != 0 &&
bmc->data.modrdn_d.newSuperior.bv_val != op->orr_newSup->bv_val )
{
free( bmc->data.modrdn_d.newSuperior.bv_val );
}
if ( bmc->data.modrdn_d.newrdn.bv_len != 0 &&
bmc->data.modrdn_d.newrdn.bv_val != op->orr_newrdn.bv_val )
{
free( bmc->data.modrdn_d.newrdn.bv_val );
}
break;
case LDAP_REQ_COMPARE:
if ( bmc->mdn.bv_val != op->o_req_dn.bv_val ) {
free( bmc->mdn.bv_val );
}
if ( op->orc_ava->aa_value.bv_val != bmc->data.comp_d.mapped_value.bv_val ) {
free( bmc->data.comp_d.mapped_value.bv_val );
}
break;
case LDAP_REQ_DELETE:
if ( bmc->mdn.bv_val != op->o_req_dn.bv_val ) {
free( bmc->mdn.bv_val );
}
break;
default:
Debug( LDAP_DEBUG_TRACE, "==> asyncmeta_clear_bm_context: other message type",
0, 0, 0 );
}
if (bmc->dc != NULL) {
free (bmc->dc);
}
free(bmc);
if (clear_cl > 0) {
asyncmeta_free_candidate_list(cl, lock);
Debug( LDAP_DEBUG_TRACE, "==> asyncmeta_clear_bm_context: free_cl_list\n",
0, 0, 0 );
}
#else
asyncmeta_memctx_put(op->o_threadctx, op->o_tmpmemctx);
#endif
}
int asyncmeta_add_message_queue(a_metaconn_t *mc, bm_context_t *bc)
{
a_metainfo_t *mi = mc->mc_info;
int max_pending_ops = (mi->mi_max_pending_ops == 0) ? META_BACK_CFG_MAX_PENDING_OPS : mi->mi_max_pending_ops;
Debug( LDAP_DEBUG_TRACE, "add_message_queue: mc %p, pending_ops %d, max_pending %d\n",
mc, mc->pending_ops, max_pending_ops );
if (mc->pending_ops >= max_pending_ops) {
return LDAP_BUSY;
}
LDAP_SLIST_INSERT_HEAD( &mc->mc_om_list, bc, bc_next);
mc->pending_ops++;
return LDAP_SUCCESS;
}
void
asyncmeta_drop_bc(a_metaconn_t *mc, bm_context_t *bc)
{
bm_context_t *om;
LDAP_SLIST_FOREACH( om, &mc->mc_om_list, bc_next ) {
if (om == bc) {
LDAP_SLIST_REMOVE(&mc->mc_om_list, om, bm_context_t, bc_next);
mc->pending_ops--;
break;
}
}
}
bm_context_t *
asyncmeta_find_message(ber_int_t msgid, a_metaconn_t *mc, int candidate)
{
bm_context_t *om;
LDAP_SLIST_FOREACH( om, &mc->mc_om_list, bc_next ) {
if (om->candidates[candidate].sr_msgid == msgid) {
break;
}
}
return om;
}
bm_context_t *
asyncmeta_find_message_by_opmsguid (ber_int_t msgid, a_metaconn_t *mc, int remove)
{
bm_context_t *om;
LDAP_SLIST_FOREACH( om, &mc->mc_om_list, bc_next ) {
if (om->op->o_msgid == msgid) {
break;
}
}
if (remove && om) {
LDAP_SLIST_REMOVE(&mc->mc_om_list, om, bm_context_t, bc_next);
mc->pending_ops--;
}
return om;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,369 @@
/* modify.c - modify request handler for back-asyncmeta */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2016 The OpenLDAP Foundation.
* Portions Copyright 2016 Symas Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
/* ACKNOWLEDGEMENTS:
* This work was developed by Symas Corporation
* based on back-meta module for inclusion in OpenLDAP Software.
* This work was sponsored by Ericsson. */
#include "portable.h"
#include <stdio.h>
#include <ac/string.h>
#include <ac/socket.h>
#include "slap.h"
#include "../back-ldap/back-ldap.h"
#include "back-asyncmeta.h"
#include "../../../libraries/liblber/lber-int.h"
#include "../../../libraries/libldap/ldap-int.h"
meta_search_candidate_t
asyncmeta_back_modify_start(Operation *op,
SlapReply *rs,
a_metaconn_t *mc,
bm_context_t *bc,
int candidate)
{
int i, isupdate, rc = 0, nretries = 1;
a_dncookie dc;
a_metainfo_t *mi = mc->mc_info;
a_metatarget_t *mt = mi->mi_targets[ candidate ];
LDAPMod **modv = NULL;
LDAPMod *mods = NULL;
struct berval mdn;
Modifications *ml;
struct berval mapped;
meta_search_candidate_t retcode = META_SEARCH_CANDIDATE;
BerElement *ber = NULL;
a_metasingleconn_t *msc = &mc->mc_conns[ candidate ];
SlapReply *candidates = bc->candidates;
ber_int_t msgid;
LDAPControl **ctrls = NULL;
/*
* Rewrite the modify dn, if needed
*/
dc.target = mt;
dc.conn = op->o_conn;
dc.rs = rs;
dc.ctx = "modifyDN";
switch ( asyncmeta_dn_massage( &dc, &op->o_req_dn, &mdn ) )
{
case LDAP_SUCCESS:
break;
case LDAP_UNWILLING_TO_PERFORM:
rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
rs->sr_text = "Operation not allowed";
retcode = META_SEARCH_ERR;
goto doreturn;
default:
rs->sr_err = LDAP_NO_SUCH_OBJECT;
retcode = META_SEARCH_NOT_CANDIDATE;
goto doreturn;
}
for ( i = 0, ml = op->orm_modlist; ml; i++ ,ml = ml->sml_next )
;
mods = ch_malloc( sizeof( LDAPMod )*i );
if ( mods == NULL ) {
rs->sr_err = LDAP_OTHER;
retcode = META_SEARCH_ERR;
goto doreturn;
}
modv = ( LDAPMod ** )ch_malloc( ( i + 1 )*sizeof( LDAPMod * ) );
if ( modv == NULL ) {
rs->sr_err = LDAP_OTHER;
retcode = META_SEARCH_ERR;
goto doreturn;
}
dc.ctx = "modifyAttrDN";
isupdate = be_shadow_update( op );
for ( i = 0, ml = op->orm_modlist; ml; ml = ml->sml_next ) {
int j, is_oc = 0;
if ( !isupdate && !get_relax( op ) && ml->sml_desc->ad_type->sat_no_user_mod )
{
continue;
}
if ( ml->sml_desc == slap_schema.si_ad_objectClass
|| ml->sml_desc == slap_schema.si_ad_structuralObjectClass )
{
is_oc = 1;
mapped = ml->sml_desc->ad_cname;
} else {
asyncmeta_map( &mt->mt_rwmap.rwm_at,
&ml->sml_desc->ad_cname, &mapped,
BACKLDAP_MAP );
if ( BER_BVISNULL( &mapped ) || BER_BVISEMPTY( &mapped ) ) {
continue;
}
}
modv[ i ] = &mods[ i ];
mods[ i ].mod_op = ml->sml_op | LDAP_MOD_BVALUES;
mods[ i ].mod_type = mapped.bv_val;
/*
* FIXME: dn-valued attrs should be rewritten
* to allow their use in ACLs at the back-ldap
* level.
*/
if ( ml->sml_values != NULL ) {
if ( is_oc ) {
for ( j = 0; !BER_BVISNULL( &ml->sml_values[ j ] ); j++ )
;
mods[ i ].mod_bvalues =
(struct berval **)ch_malloc( ( j + 1 ) *
sizeof( struct berval * ) );
for ( j = 0; !BER_BVISNULL( &ml->sml_values[ j ] ); ) {
struct ldapmapping *mapping;
asyncmeta_mapping( &mt->mt_rwmap.rwm_oc,
&ml->sml_values[ j ], &mapping, BACKLDAP_MAP );
if ( mapping == NULL ) {
if ( mt->mt_rwmap.rwm_oc.drop_missing ) {
continue;
}
mods[ i ].mod_bvalues[ j ] = &ml->sml_values[ j ];
} else {
mods[ i ].mod_bvalues[ j ] = &mapping->dst;
}
j++;
}
mods[ i ].mod_bvalues[ j ] = NULL;
} else {
if ( ml->sml_desc->ad_type->sat_syntax ==
slap_schema.si_syn_distinguishedName )
{
( void )asyncmeta_dnattr_rewrite( &dc, ml->sml_values );
if ( ml->sml_values == NULL ) {
continue;
}
}
for ( j = 0; !BER_BVISNULL( &ml->sml_values[ j ] ); j++ )
;
mods[ i ].mod_bvalues =
(struct berval **)ch_malloc( ( j + 1 ) *
sizeof( struct berval * ) );
for ( j = 0; !BER_BVISNULL( &ml->sml_values[ j ] ); j++ ) {
mods[ i ].mod_bvalues[ j ] = &ml->sml_values[ j ];
}
mods[ i ].mod_bvalues[ j ] = NULL;
}
} else {
mods[ i ].mod_bvalues = NULL;
}
i++;
}
modv[ i ] = 0;
retry:;
ctrls = op->o_ctrls;
if ( asyncmeta_controls_add( op, rs, mc, candidate, &ctrls ) != LDAP_SUCCESS )
{
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
retcode = META_SEARCH_ERR;
goto done;
}
ber = ldap_build_modify_req( msc->msc_ld, mdn.bv_val, modv, ctrls, NULL, &msgid);
if (ber) {
candidates[ candidate ].sr_msgid = msgid;
rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_MODIFY,
mdn.bv_val, ber, msgid );
if (rc == msgid)
rc = LDAP_SUCCESS;
else
rc = LDAP_SERVER_DOWN;
switch ( rc ) {
case LDAP_SUCCESS:
retcode = META_SEARCH_CANDIDATE;
asyncmeta_set_msc_time(msc);
break;
case LDAP_SERVER_DOWN:
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
asyncmeta_clear_one_msc(NULL, mc, candidate);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
if ( nretries && asyncmeta_retry( op, rs, &mc, candidate, LDAP_BACK_DONTSEND ) ) {
nretries = 0;
/* if the identity changed, there might be need to re-authz */
(void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
goto retry;
}
default:
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
retcode = META_SEARCH_ERR;
}
}
done:
(void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
if ( mdn.bv_val != op->o_req_dn.bv_val ) {
free( mdn.bv_val );
BER_BVZERO( &mdn );
}
if ( modv != NULL ) {
for ( i = 0; modv[ i ]; i++ ) {
free( modv[ i ]->mod_bvalues );
}
}
free( mods );
free( modv );
doreturn:;
Debug( LDAP_DEBUG_TRACE, "%s <<< asyncmeta_back_modify_start[%p]=%d\n", op->o_log_prefix, msc, candidates[candidate].sr_msgid );
return retcode;
}
int
asyncmeta_back_modify( Operation *op, SlapReply *rs )
{
a_metainfo_t *mi = ( a_metainfo_t * )op->o_bd->be_private;
a_metatarget_t *mt;
a_metaconn_t *mc;
int rc, candidate = -1;
OperationBuffer opbuf;
bm_context_t *bc;
SlapReply *candidates;
slap_callback *cb = op->o_callback;
Debug(LDAP_DEBUG_ARGS, "==> asyncmeta_back_modify: %s\n",
op->o_req_dn.bv_val, 0, 0 );
asyncmeta_new_bm_context(op, rs, &bc, mi->mi_ntargets );
if (bc == NULL) {
rs->sr_err = LDAP_OTHER;
asyncmeta_sender_error(op, rs, cb);
return rs->sr_err;
}
candidates = bc->candidates;
mc = asyncmeta_getconn( op, rs, candidates, &candidate, LDAP_BACK_DONTSEND, 0);
if ( !mc || rs->sr_err != LDAP_SUCCESS) {
asyncmeta_sender_error(op, rs, cb);
asyncmeta_clear_bm_context(bc);
return rs->sr_err;
}
mt = mi->mi_targets[ candidate ];
bc->timeout = mt->mt_timeout[ SLAP_OP_MODIFY ];
bc->retrying = LDAP_BACK_RETRYING;
bc->sendok = ( LDAP_BACK_SENDRESULT | bc->retrying );
bc->stoptime = op->o_time + bc->timeout;
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
rc = asyncmeta_add_message_queue(mc, bc);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
if (rc != LDAP_SUCCESS) {
rs->sr_err = LDAP_BUSY;
rs->sr_text = "Maximum pending ops limit exceeded";
asyncmeta_clear_bm_context(bc);
asyncmeta_sender_error(op, rs, cb);
goto finish;
}
rc = asyncmeta_dobind_init_with_retry(op, rs, bc, mc, candidate);
switch (rc)
{
case META_SEARCH_CANDIDATE:
/* target is already bound, just send the request */
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modify: "
"cnd=\"%ld\"\n", op->o_log_prefix, candidate , 0);
rc = asyncmeta_back_modify_start( op, rs, mc, bc, candidate);
if (rc == META_SEARCH_ERR) {
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
asyncmeta_drop_bc(mc, bc);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
asyncmeta_sender_error(op, rs, cb);
asyncmeta_clear_bm_context(bc);
goto finish;
}
break;
case META_SEARCH_NOT_CANDIDATE:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modify: NOT_CANDIDATE "
"cnd=\"%ld\"\n", op->o_log_prefix, candidate , 0);
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
asyncmeta_drop_bc(mc, bc);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
asyncmeta_sender_error(op, rs, cb);
asyncmeta_clear_bm_context(bc);
goto finish;
case META_SEARCH_NEED_BIND:
case META_SEARCH_CONNECTING:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modify: NEED_BIND "
"cnd=\"%ld\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]);
rc = asyncmeta_dobind_init(op, rs, bc, mc, candidate);
if (rc == META_SEARCH_ERR) {
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
asyncmeta_drop_bc(mc, bc);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
asyncmeta_sender_error(op, rs, cb);
asyncmeta_clear_bm_context(bc);
goto finish;
}
break;
case META_SEARCH_BINDING:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modify: BINDING "
"cnd=\"%ld\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]);
/* Todo add the context to the message queue but do not send the request
the receiver must send this when we are done binding */
/* question - how would do receiver know to which targets??? */
break;
case META_SEARCH_ERR:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modify: ERR "
"cnd=\"%ldd\"\n", op->o_log_prefix, candidate , 0);
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
candidates[ candidate ].sr_type = REP_RESULT;
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
asyncmeta_drop_bc(mc, bc);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
asyncmeta_sender_error(op, rs, cb);
asyncmeta_clear_bm_context(bc);
goto finish;
default:
assert( 0 );
break;
}
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
asyncmeta_start_one_listener(mc, candidates, candidate);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
finish:
return rs->sr_err;
}

View file

@ -0,0 +1,315 @@
/* modrdn.c - modrdn request handler for back-syncmeta */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2016 The OpenLDAP Foundation.
* Portions Copyright 2016 Symas Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
/* ACKNOWLEDGEMENTS:
* This work was developed by Symas Corporation
* based on back-meta module for inclusion in OpenLDAP Software.
* This work was sponsored by Ericsson. */
#include "portable.h"
#include <stdio.h>
#include <ac/socket.h>
#include <ac/string.h>
#include "slap.h"
#include "../back-ldap/back-ldap.h"
#include "back-asyncmeta.h"
#include "../../../libraries/liblber/lber-int.h"
#include "../../../libraries/libldap/ldap-int.h"
meta_search_candidate_t
asyncmeta_back_modrdn_start(Operation *op,
SlapReply *rs,
a_metaconn_t *mc,
bm_context_t *bc,
int candidate)
{
a_dncookie dc;
a_metainfo_t *mi = mc->mc_info;
a_metatarget_t *mt = mi->mi_targets[ candidate ];
struct berval mdn = BER_BVNULL,
mnewSuperior = BER_BVNULL,
newrdn = BER_BVNULL;
int rc = 0, nretries = 1;
LDAPControl **ctrls = NULL;
meta_search_candidate_t retcode = META_SEARCH_CANDIDATE;
BerElement *ber = NULL;
a_metasingleconn_t *msc = &mc->mc_conns[ candidate ];
SlapReply *candidates = bc->candidates;
ber_int_t msgid;
dc.target = mt;
dc.conn = op->o_conn;
dc.rs = rs;
if ( op->orr_newSup ) {
/*
* NOTE: the newParent, if defined, must be on the
* same target as the entry to be renamed. This check
* has been anticipated in meta_back_getconn()
*/
/*
* FIXME: one possibility is to delete the entry
* from one target and add it to the other;
* unfortunately we'd need write access to both,
* which is nearly impossible; for administration
* needs, the rootdn of the metadirectory could
* be mapped to an administrative account on each
* target (the binddn?); we'll see.
*/
/*
* NOTE: we need to port the identity assertion
* feature from back-ldap
*/
/* needs LDAPv3 */
switch ( mt->mt_version ) {
case LDAP_VERSION3:
break;
case 0:
if ( op->o_protocol == 0 || op->o_protocol == LDAP_VERSION3 ) {
break;
}
/* fall thru */
default:
/* op->o_protocol cannot be anything but LDAPv3,
* otherwise wouldn't be here */
rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
retcode = META_SEARCH_ERR;
goto done;
}
/*
* Rewrite the new superior, if defined and required
*/
dc.ctx = "newSuperiorDN";
if ( asyncmeta_dn_massage( &dc, op->orr_newSup, &mnewSuperior ) ) {
rs->sr_err = LDAP_OTHER;
retcode = META_SEARCH_ERR;
goto done;
}
}
/*
* Rewrite the modrdn dn, if required
*/
dc.ctx = "modrDN";
if ( asyncmeta_dn_massage( &dc, &op->o_req_dn, &mdn ) ) {
rs->sr_err = LDAP_OTHER;
retcode = META_SEARCH_ERR;
goto done;
}
/* NOTE: we need to copy the newRDN in case it was formed
* from a DN by simply changing the length (ITS#5397) */
newrdn = op->orr_newrdn;
if ( newrdn.bv_val[ newrdn.bv_len ] != '\0' ) {
ber_dupbv_x( &newrdn, &op->orr_newrdn, op->o_tmpmemctx );
}
retry:;
ctrls = op->o_ctrls;
if ( asyncmeta_controls_add( op, rs, mc, candidate, &ctrls ) != LDAP_SUCCESS )
{
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
retcode = META_SEARCH_ERR;
goto done;
}
ber = ldap_build_moddn_req( msc->msc_ld, mdn.bv_val, newrdn.bv_val,
mnewSuperior.bv_val, op->orr_deleteoldrdn, ctrls, NULL, &msgid);
if (ber) {
candidates[ candidate ].sr_msgid = msgid;
rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_MODRDN,
mdn.bv_val, ber, msgid );
if (rc == msgid)
rc = LDAP_SUCCESS;
else
rc = LDAP_SERVER_DOWN;
switch ( rc ) {
case LDAP_SUCCESS:
retcode = META_SEARCH_CANDIDATE;
asyncmeta_set_msc_time(msc);
break;
case LDAP_SERVER_DOWN:
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
asyncmeta_clear_one_msc(NULL, mc, candidate);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
if ( nretries && asyncmeta_retry( op, rs, &mc, candidate, LDAP_BACK_DONTSEND ) ) {
nretries = 0;
/* if the identity changed, there might be need to re-authz */
(void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
goto retry;
}
default:
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
retcode = META_SEARCH_ERR;
}
}
done:
(void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
if ( mdn.bv_val != op->o_req_dn.bv_val ) {
free( mdn.bv_val );
BER_BVZERO( &mdn );
}
if ( !BER_BVISNULL( &mnewSuperior )
&& mnewSuperior.bv_val != op->orr_newSup->bv_val )
{
free( mnewSuperior.bv_val );
BER_BVZERO( &mnewSuperior );
}
if ( newrdn.bv_val != op->orr_newrdn.bv_val ) {
op->o_tmpfree( newrdn.bv_val, op->o_tmpmemctx );
}
doreturn:;
Debug( LDAP_DEBUG_TRACE, "%s <<< asyncmeta_back_modrdn_start[%p]=%d\n", op->o_log_prefix, msc, candidates[candidate].sr_msgid );
return retcode;
}
int
asyncmeta_back_modrdn( Operation *op, SlapReply *rs )
{
a_metainfo_t *mi = ( a_metainfo_t * )op->o_bd->be_private;
a_metatarget_t *mt;
a_metaconn_t *mc;
int rc, candidate = -1;
OperationBuffer opbuf;
bm_context_t *bc;
SlapReply *candidates;
slap_callback *cb = op->o_callback;
Debug(LDAP_DEBUG_ARGS, "==> asyncmeta_back_modrdn: %s\n",
op->o_req_dn.bv_val, 0, 0 );
asyncmeta_new_bm_context(op, rs, &bc, mi->mi_ntargets );
if (bc == NULL) {
rs->sr_err = LDAP_OTHER;
asyncmeta_sender_error(op, rs, cb);
return rs->sr_err;
}
candidates = bc->candidates;
mc = asyncmeta_getconn( op, rs, candidates, &candidate, LDAP_BACK_DONTSEND, 0);
if ( !mc || rs->sr_err != LDAP_SUCCESS) {
asyncmeta_sender_error(op, rs, cb);
asyncmeta_clear_bm_context(bc);
return rs->sr_err;
}
mt = mi->mi_targets[ candidate ];
bc->timeout = mt->mt_timeout[ SLAP_OP_MODRDN ];
bc->retrying = LDAP_BACK_RETRYING;
bc->sendok = ( LDAP_BACK_SENDRESULT | bc->retrying );
bc->stoptime = op->o_time + bc->timeout;
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
rc = asyncmeta_add_message_queue(mc, bc);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
if (rc != LDAP_SUCCESS) {
rs->sr_err = LDAP_BUSY;
rs->sr_text = "Maximum pending ops limit exceeded";
asyncmeta_clear_bm_context(bc);
asyncmeta_sender_error(op, rs, cb);
goto finish;
}
rc = asyncmeta_dobind_init_with_retry(op, rs, bc, mc, candidate);
switch (rc)
{
case META_SEARCH_CANDIDATE:
/* target is already bound, just send the request */
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modrdn: "
"cnd=\"%ld\"\n", op->o_log_prefix, candidate , 0);
rc = asyncmeta_back_modrdn_start( op, rs, mc, bc, candidate);
if (rc == META_SEARCH_ERR) {
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
asyncmeta_drop_bc(mc, bc);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
asyncmeta_sender_error(op, rs, cb);
asyncmeta_clear_bm_context(bc);
goto finish;
}
break;
case META_SEARCH_NOT_CANDIDATE:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modrdn: NOT_CANDIDATE "
"cnd=\"%ld\"\n", op->o_log_prefix, candidate , 0);
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
asyncmeta_drop_bc(mc, bc);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
asyncmeta_sender_error(op, rs, cb);
asyncmeta_clear_bm_context(bc);
goto finish;
case META_SEARCH_NEED_BIND:
case META_SEARCH_CONNECTING:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modrdn: NEED_BIND "
"cnd=\"%ld\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]);
rc = asyncmeta_dobind_init(op, rs, bc, mc, candidate);
if (rc == META_SEARCH_ERR) {
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
asyncmeta_drop_bc(mc, bc);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
asyncmeta_sender_error(op, rs, cb);
asyncmeta_clear_bm_context(bc);
goto finish;
}
break;
case META_SEARCH_BINDING:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modrdn: BINDING "
"cnd=\"%ld\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]);
/* Todo add the context to the message queue but do not send the request
the receiver must send this when we are done binding */
/* question - how would do receiver know to which targets??? */
break;
case META_SEARCH_ERR:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modrdn: ERR "
"cnd=\"%ldd\"\n", op->o_log_prefix, candidate , 0);
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
candidates[ candidate ].sr_type = REP_RESULT;
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
asyncmeta_drop_bc(mc, bc);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
asyncmeta_sender_error(op, rs, cb);
asyncmeta_clear_bm_context(bc);
goto finish;
default:
assert( 0 );
break;
}
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
asyncmeta_start_one_listener(mc, candidates, candidate);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
finish:
return rs->sr_err;
}

View file

@ -0,0 +1,54 @@
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2016 The OpenLDAP Foundation.
* Portions Copyright 2016 Symas Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
/* ACKNOWLEDGEMENTS:
* This work was developed by Symas Corporation
* based on back-meta module for inclusion in OpenLDAP Software.
* This work was sponsored by Ericsson. */
#ifndef PROTO_ASYNCMETA_H
#define PROTO_ASYNCMETA_H
LDAP_BEGIN_DECL
extern BI_init asyncmeta_back_initialize;
extern BI_open asyncmeta_back_open;
extern BI_close asyncmeta_back_close;
extern BI_destroy asyncmeta_back_destroy;
extern BI_db_init asyncmeta_back_db_init;
extern BI_db_open asyncmeta_back_db_open;
extern BI_db_destroy asyncmeta_back_db_destroy;
extern BI_db_close asyncmeta_back_db_close;
extern BI_db_config asyncmeta_back_db_config;
extern BI_op_bind asyncmeta_back_bind;
extern BI_op_search asyncmeta_back_search;
extern BI_op_compare asyncmeta_back_compare;
extern BI_op_modify asyncmeta_back_modify;
extern BI_op_modrdn asyncmeta_back_modrdn;
extern BI_op_add asyncmeta_back_add;
extern BI_op_delete asyncmeta_back_delete;
extern BI_op_abandon asyncmeta_back_abandon;
extern BI_connection_destroy asyncmeta_back_conn_destroy;
int asyncmeta_back_init_cf( BackendInfo *bi );
LDAP_END_DECL
#endif /* PROTO_ASYNCMETA_H */

View file

@ -0,0 +1,680 @@
/* search.c - search request handler for back-asyncmeta */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2016 The OpenLDAP Foundation.
* Portions Copyright 2016 Symas Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
/* ACKNOWLEDGEMENTS:
* This work was developed by Symas Corporation
* based on back-meta module for inclusion in OpenLDAP Software.
* This work was sponsored by Ericsson. */
#include "portable.h"
#include <stdio.h>
#include <ac/socket.h>
#include <ac/string.h>
#include <ac/time.h>
#include "lutil.h"
#include "slap.h"
#include "../back-ldap/back-ldap.h"
#include "back-asyncmeta.h"
#include "../../../libraries/liblber/lber-int.h"
#include "../../../libraries/libldap/ldap-int.h"
#undef ldap_debug
#define ldap_debug slap_debug
static void
asyncmeta_handle_onerr_stop(Operation *op,
SlapReply *rs,
a_metaconn_t *mc,
bm_context_t *bc,
int candidate,
slap_callback *cb)
{
a_metainfo_t *mi = mc->mc_info;
int j;
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
if (bc->bc_active > 0) {
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
return;
}
bc->bc_active = 1;
asyncmeta_drop_bc(mc, bc);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
for (j=0; j<mi->mi_ntargets; j++) {
if (j != candidate && bc->candidates[j].sr_msgid >= 0
&& mc->mc_conns[j].msc_ld != NULL) {
asyncmeta_back_abandon_candidate( mc, op,
bc->candidates[ j ].sr_msgid, j );
}
}
if (cb != NULL) {
op->o_callback = cb;
}
send_ldap_result(op, rs);
asyncmeta_clear_bm_context(bc);
}
meta_search_candidate_t
asyncmeta_back_search_start(
Operation *op,
SlapReply *rs,
a_metaconn_t *mc,
bm_context_t *bc,
int candidate,
struct berval *prcookie,
ber_int_t prsize )
{
SlapReply *candidates = bc->candidates;
a_metainfo_t *mi = ( a_metainfo_t * )mc->mc_info;
a_metatarget_t *mt = mi->mi_targets[ candidate ];
a_metasingleconn_t *msc = &mc->mc_conns[ candidate ];
a_dncookie dc;
struct berval realbase = op->o_req_dn;
int realscope = op->ors_scope;
struct berval mbase = BER_BVNULL;
struct berval mfilter = BER_BVNULL;
char **mapped_attrs = NULL;
int rc;
meta_search_candidate_t retcode;
int timelimit;
int nretries = 1;
LDAPControl **ctrls = NULL;
BerElement *ber;
ber_int_t msgid;
#ifdef SLAPD_META_CLIENT_PR
LDAPControl **save_ctrls = NULL;
#endif /* SLAPD_META_CLIENT_PR */
/* this should not happen; just in case... */
if ( msc->msc_ld == NULL ) {
Debug( LDAP_DEBUG_ANY,
"%s: asyncmeta_back_search_start candidate=%d ld=NULL%s.\n",
op->o_log_prefix, candidate,
META_BACK_ONERR_STOP( mi ) ? "" : " (ignored)" );
candidates[ candidate ].sr_err = LDAP_OTHER;
if ( META_BACK_ONERR_STOP( mi ) ) {
return META_SEARCH_ERR;
}
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
return META_SEARCH_NOT_CANDIDATE;
}
Debug( LDAP_DEBUG_TRACE, "%s >>> asyncmeta_back_search_start[%d]\n", op->o_log_prefix, candidate, 0 );
/*
* modifies the base according to the scope, if required
*/
if ( mt->mt_nsuffix.bv_len > op->o_req_ndn.bv_len ) {
switch ( op->ors_scope ) {
case LDAP_SCOPE_SUBTREE:
/*
* make the target suffix the new base
* FIXME: this is very forgiving, because
* "illegal" searchBases may be turned
* into the suffix of the target; however,
* the requested searchBase already passed
* thru the candidate analyzer...
*/
if ( dnIsSuffix( &mt->mt_nsuffix, &op->o_req_ndn ) ) {
realbase = mt->mt_nsuffix;
if ( mt->mt_scope == LDAP_SCOPE_SUBORDINATE ) {
realscope = LDAP_SCOPE_SUBORDINATE;
}
} else {
/*
* this target is no longer candidate
*/
retcode = META_SEARCH_NOT_CANDIDATE;
goto doreturn;
}
break;
case LDAP_SCOPE_SUBORDINATE:
case LDAP_SCOPE_ONELEVEL:
{
struct berval rdn = mt->mt_nsuffix;
rdn.bv_len -= op->o_req_ndn.bv_len + STRLENOF( "," );
if ( dnIsOneLevelRDN( &rdn )
&& dnIsSuffix( &mt->mt_nsuffix, &op->o_req_ndn ) )
{
/*
* if there is exactly one level,
* make the target suffix the new
* base, and make scope "base"
*/
realbase = mt->mt_nsuffix;
if ( op->ors_scope == LDAP_SCOPE_SUBORDINATE ) {
if ( mt->mt_scope == LDAP_SCOPE_SUBORDINATE ) {
realscope = LDAP_SCOPE_SUBORDINATE;
} else {
realscope = LDAP_SCOPE_SUBTREE;
}
} else {
realscope = LDAP_SCOPE_BASE;
}
break;
} /* else continue with the next case */
}
case LDAP_SCOPE_BASE:
/*
* this target is no longer candidate
*/
retcode = META_SEARCH_NOT_CANDIDATE;
goto doreturn;
}
}
/* check filter expression */
if ( mt->mt_filter ) {
metafilter_t *mf;
for ( mf = mt->mt_filter; mf; mf = mf->mf_next ) {
if ( regexec( &mf->mf_regex, op->ors_filterstr.bv_val, 0, NULL, 0 ) == 0 )
break;
}
/* nothing matched, this target is no longer a candidate */
if ( !mf ) {
retcode = META_SEARCH_NOT_CANDIDATE;
goto doreturn;
}
}
/*
* Rewrite the search base, if required
*/
dc.target = mt;
dc.ctx = "searchBase";
dc.conn = op->o_conn;
dc.rs = rs;
switch ( asyncmeta_dn_massage( &dc, &realbase, &mbase ) ) {
case LDAP_SUCCESS:
break;
case LDAP_UNWILLING_TO_PERFORM:
rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
rs->sr_text = "Operation not allowed";
retcode = META_SEARCH_ERR;
goto doreturn;
default:
/*
* this target is no longer candidate
*/
retcode = META_SEARCH_NOT_CANDIDATE;
goto doreturn;
}
/*
* Maps filter
*/
rc = asyncmeta_filter_map_rewrite( &dc, op->ors_filter,
&mfilter, BACKLDAP_MAP, NULL );
switch ( rc ) {
case LDAP_SUCCESS:
break;
case LDAP_COMPARE_FALSE:
default:
/*
* this target is no longer candidate
*/
retcode = META_SEARCH_NOT_CANDIDATE;
goto done;
}
/*
* Maps required attributes
*/
rc = asyncmeta_map_attrs( op, &mt->mt_rwmap.rwm_at,
op->ors_attrs, BACKLDAP_MAP, &mapped_attrs );
if ( rc != LDAP_SUCCESS ) {
/*
* this target is no longer candidate
*/
retcode = META_SEARCH_NOT_CANDIDATE;
goto done;
}
if ( op->ors_tlimit != SLAP_NO_LIMIT ) {
timelimit = op->ors_tlimit > 0 ? op->ors_tlimit : 1;
} else {
timelimit = -1; /* no limit */
}
#ifdef SLAPD_META_CLIENT_PR
save_ctrls = op->o_ctrls;
{
LDAPControl *pr_c = NULL;
int i = 0, nc = 0;
if ( save_ctrls ) {
for ( ; save_ctrls[i] != NULL; i++ );
nc = i;
pr_c = ldap_control_find( LDAP_CONTROL_PAGEDRESULTS, save_ctrls, NULL );
}
if ( pr_c != NULL ) nc--;
if ( mt->mt_ps > 0 || prcookie != NULL ) nc++;
if ( mt->mt_ps > 0 || prcookie != NULL || pr_c != NULL ) {
int src = 0, dst = 0;
BerElementBuffer berbuf;
BerElement *ber = (BerElement *)&berbuf;
struct berval val = BER_BVNULL;
ber_len_t len;
len = sizeof( LDAPControl * )*( nc + 1 ) + sizeof( LDAPControl );
if ( mt->mt_ps > 0 || prcookie != NULL ) {
struct berval nullcookie = BER_BVNULL;
ber_tag_t tag;
if ( prsize == 0 && mt->mt_ps > 0 ) prsize = mt->mt_ps;
if ( prcookie == NULL ) prcookie = &nullcookie;
ber_init2( ber, NULL, LBER_USE_DER );
tag = ber_printf( ber, "{iO}", prsize, prcookie );
if ( tag == LBER_ERROR ) {
/* error */
(void) ber_free_buf( ber );
goto done_pr;
}
tag = ber_flatten2( ber, &val, 0 );
if ( tag == LBER_ERROR ) {
/* error */
(void) ber_free_buf( ber );
goto done_pr;
}
len += val.bv_len + 1;
}
op->o_ctrls = op->o_tmpalloc( len, op->o_tmpmemctx );
if ( save_ctrls ) {
for ( ; save_ctrls[ src ] != NULL; src++ ) {
if ( save_ctrls[ src ] != pr_c ) {
op->o_ctrls[ dst ] = save_ctrls[ src ];
dst++;
}
}
}
if ( mt->mt_ps > 0 || prcookie != NULL ) {
op->o_ctrls[ dst ] = (LDAPControl *)&op->o_ctrls[ nc + 1 ];
op->o_ctrls[ dst ]->ldctl_oid = LDAP_CONTROL_PAGEDRESULTS;
op->o_ctrls[ dst ]->ldctl_iscritical = 1;
op->o_ctrls[ dst ]->ldctl_value.bv_val = (char *)&op->o_ctrls[ dst ][ 1 ];
AC_MEMCPY( op->o_ctrls[ dst ]->ldctl_value.bv_val, val.bv_val, val.bv_len + 1 );
op->o_ctrls[ dst ]->ldctl_value.bv_len = val.bv_len;
dst++;
(void)ber_free_buf( ber );
}
op->o_ctrls[ dst ] = NULL;
}
done_pr:;
}
#endif /* SLAPD_META_CLIENT_PR */
retry:;
asyncmeta_set_msc_time(msc);
ctrls = op->o_ctrls;
if (nretries == 0)
{
if (rc != LDAP_SUCCESS)
{
rs->sr_err = LDAP_BUSY;
retcode = META_SEARCH_ERR;
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
goto done;
}
}
if ( asyncmeta_controls_add( op, rs, mc, candidate, &ctrls )
!= LDAP_SUCCESS )
{
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
retcode = META_SEARCH_NOT_CANDIDATE;
goto done;
}
/*
* Starts the search
*/
ber = ldap_build_search_req( msc->msc_ld,
mbase.bv_val, realscope, mfilter.bv_val,
mapped_attrs, op->ors_attrsonly,
ctrls, NULL, timelimit, op->ors_slimit, op->ors_deref,
&msgid );
if (ber) {
candidates[ candidate ].sr_msgid = msgid;
rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_SEARCH,
mbase.bv_val, ber, msgid );
if (rc == msgid)
rc = LDAP_SUCCESS;
else
rc = LDAP_SERVER_DOWN;
switch ( rc ) {
case LDAP_SUCCESS:
retcode = META_SEARCH_CANDIDATE;
asyncmeta_set_msc_time(msc);
break;
case LDAP_SERVER_DOWN:
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
if (mc->mc_active < 1) {
asyncmeta_clear_one_msc(NULL, mc, candidate);
}
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
if ( nretries && asyncmeta_retry( op, rs, &mc, candidate, LDAP_BACK_DONTSEND ) ) {
nretries = 0;
/* if the identity changed, there might be need to re-authz */
(void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
goto retry;
}
rs->sr_err = LDAP_UNAVAILABLE;
retcode = META_SEARCH_ERR;
break;
default:
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
retcode = META_SEARCH_NOT_CANDIDATE;
}
}
done:;
(void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
#ifdef SLAPD_META_CLIENT_PR
if ( save_ctrls != op->o_ctrls ) {
op->o_tmpfree( op->o_ctrls, op->o_tmpmemctx );
op->o_ctrls = save_ctrls;
}
#endif /* SLAPD_META_CLIENT_PR */
if ( mapped_attrs ) {
ber_memfree_x( mapped_attrs, op->o_tmpmemctx );
}
if ( mfilter.bv_val != op->ors_filterstr.bv_val ) {
ber_memfree_x( mfilter.bv_val, NULL );
}
if ( mbase.bv_val != realbase.bv_val ) {
free( mbase.bv_val );
}
doreturn:;
Debug( LDAP_DEBUG_TRACE, "%s <<< asyncmeta_back_search_start[%p]=%d\n", op->o_log_prefix, msc, candidates[candidate].sr_msgid );
return retcode;
}
int
asyncmeta_back_search( Operation *op, SlapReply *rs )
{
a_metainfo_t *mi = ( a_metainfo_t * )op->o_bd->be_private;
struct timeval save_tv = { 0, 0 },
tv;
time_t stoptime = (time_t)(-1),
lastres_time = slap_get_time(),
timeout = 0;
int rc = 0, sres = LDAP_SUCCESS;
char *matched = NULL;
int last = 0, ncandidates = 0,
initial_candidates = 0, candidate_match = 0,
needbind = 0;
ldap_back_send_t sendok = LDAP_BACK_SENDERR;
long i;
int is_ok = 0;
void *savepriv;
SlapReply *candidates = NULL;
int do_taint = 0;
bm_context_t *bc;
a_metaconn_t *mc;
slap_callback *cb = op->o_callback;
rs_assert_ready( rs );
rs->sr_flags &= ~REP_ENTRY_MASK; /* paranoia, we can set rs = non-entry */
/*
* controls are set in ldap_back_dobind()
*
* FIXME: in case of values return filter, we might want
* to map attrs and maybe rewrite value
*/
asyncmeta_new_bm_context(op, rs, &bc, mi->mi_ntargets );
if (bc == NULL) {
rs->sr_err = LDAP_OTHER;
send_ldap_result(op, rs);
return rs->sr_err;
}
candidates = bc->candidates;
mc = asyncmeta_getconn( op, rs, candidates, NULL, LDAP_BACK_DONTSEND, 0);
if ( !mc || rs->sr_err != LDAP_SUCCESS) {
op->o_callback = cb;
send_ldap_result(op, rs);
asyncmeta_clear_bm_context(bc);
return rs->sr_err;
}
/*
* Inits searches
*/
for ( i = 0; i < mi->mi_ntargets; i++ ) {
/* reset sr_msgid; it is used in most loops
* to check if that target is still to be considered */
candidates[ i ].sr_msgid = META_MSGID_UNDEFINED;
/* a target is marked as candidate by asyncmeta_getconn();
* if for any reason (an error, it's over or so) it is
* no longer active, sr_msgid is set to META_MSGID_IGNORE
* but it remains candidate, which means it has been active
* at some point during the operation. This allows to
* use its response code and more to compute the final
* response */
if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
continue;
}
candidates[ i ].sr_matched = NULL;
candidates[ i ].sr_text = NULL;
candidates[ i ].sr_ref = NULL;
candidates[ i ].sr_ctrls = NULL;
candidates[ i ].sr_nentries = 0;
candidates[ i ].sr_type = -1;
/* get largest timeout among candidates */
if ( mi->mi_targets[ i ]->mt_timeout[ SLAP_OP_SEARCH ]
&& mi->mi_targets[ i ]->mt_timeout[ SLAP_OP_SEARCH ] > timeout )
{
timeout = mi->mi_targets[ i ]->mt_timeout[ SLAP_OP_SEARCH ];
}
}
bc->timeout = timeout;
bc->stoptime = op->o_time + bc->timeout;
if ( op->ors_tlimit != SLAP_NO_LIMIT ) {
stoptime = op->o_time + op->ors_tlimit;
if (stoptime < bc->stoptime) {
bc->stoptime = stoptime;
bc->searchtime = 1;
bc->timeout = op->ors_tlimit;
}
}
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
rc = asyncmeta_add_message_queue(mc, bc);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
if (rc != LDAP_SUCCESS) {
rs->sr_err = LDAP_BUSY;
rs->sr_text = "Maximum pending ops limit exceeded";
asyncmeta_clear_bm_context(bc);
op->o_callback = cb;
send_ldap_result(op, rs);
goto finish;
}
for ( i = 0; i < mi->mi_ntargets; i++ ) {
if ( !META_IS_CANDIDATE( &candidates[ i ] )
|| candidates[ i ].sr_err != LDAP_SUCCESS )
{
continue;
}
rc = asyncmeta_dobind_init_with_retry(op, rs, bc, mc, i);
switch (rc)
{
case META_SEARCH_CANDIDATE:
/* target is already bound, just send the search request */
ncandidates++;
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_search: IS_CANDIDATE "
"cnd=\"%ld\"\n", op->o_log_prefix, i , 0);
rc = asyncmeta_back_search_start( op, rs, mc, bc, i, NULL, 0 );
if (rc == META_SEARCH_ERR) {
META_CANDIDATE_CLEAR(&candidates[i]);
candidates[ i ].sr_msgid = META_MSGID_IGNORE;
if ( META_BACK_ONERR_STOP( mi ) ) {
asyncmeta_handle_onerr_stop(op,rs,mc,bc,i,cb);
goto finish;
}
else {
continue;
}
}
break;
case META_SEARCH_NOT_CANDIDATE:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_search: NOT_CANDIDATE "
"cnd=\"%ld\"\n", op->o_log_prefix, i , 0);
candidates[ i ].sr_msgid = META_MSGID_IGNORE;
break;
case META_SEARCH_NEED_BIND:
case META_SEARCH_CONNECTING:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_search: NEED_BIND "
"cnd=\"%ld\" %p\n", op->o_log_prefix, i , &mc->mc_conns[i]);
ncandidates++;
rc = asyncmeta_dobind_init(op, rs, bc, mc, i);
if (rc == META_SEARCH_ERR) {
candidates[ i ].sr_msgid = META_MSGID_IGNORE;
if ( META_BACK_ONERR_STOP( mi ) ) {
asyncmeta_handle_onerr_stop(op,rs,mc,bc,i,cb);
goto finish;
}
else {
continue;
}
}
break;
case META_SEARCH_BINDING:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_search: BINDING "
"cnd=\"%ld\" %p\n", op->o_log_prefix, i , &mc->mc_conns[i]);
ncandidates++;
/* Todo add the context to the message queue but do not send the request
the receiver must send this when we are done binding */
/* question - how would do receiver know to which targets??? */
break;
case META_SEARCH_ERR:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_search: SEARCH_ERR "
"cnd=\"%ldd\"\n", op->o_log_prefix, i , 0);
candidates[ i ].sr_msgid = META_MSGID_IGNORE;
candidates[ i ].sr_type = REP_RESULT;
if ( META_BACK_ONERR_STOP( mi ) ) {
asyncmeta_handle_onerr_stop(op,rs,mc,bc,i,cb);
goto finish;
}
else {
continue;
}
break;
default:
assert( 0 );
break;
}
}
initial_candidates = ncandidates;
if ( LogTest( LDAP_DEBUG_TRACE ) ) {
char cnd[ SLAP_TEXT_BUFLEN ];
int c;
for ( c = 0; c < mi->mi_ntargets; c++ ) {
if ( META_IS_CANDIDATE( &candidates[ c ] ) ) {
cnd[ c ] = '*';
} else {
cnd[ c ] = ' ';
}
}
cnd[ c ] = '\0';
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_search: ncandidates=%d "
"cnd=\"%s\"\n", op->o_log_prefix, ncandidates, cnd );
}
if ( initial_candidates == 0 ) {
/* NOTE: here we are not sending any matchedDN;
* this is intended, because if the back-meta
* is serving this search request, but no valid
* candidate could be looked up, it means that
* there is a hole in the mapping of the targets
* and thus no knowledge of any remote superior
* is available */
Debug( LDAP_DEBUG_ANY, "%s asyncmeta_back_search: "
"base=\"%s\" scope=%d: "
"no candidate could be selected\n",
op->o_log_prefix, op->o_req_dn.bv_val,
op->ors_scope );
/* FIXME: we're sending the first error we encounter;
* maybe we should pick the worst... */
rc = LDAP_NO_SUCH_OBJECT;
for ( i = 0; i < mi->mi_ntargets; i++ ) {
if ( META_IS_CANDIDATE( &candidates[ i ] )
&& candidates[ i ].sr_err != LDAP_SUCCESS )
{
rc = candidates[ i ].sr_err;
break;
}
}
rs->sr_err = rc;
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
asyncmeta_drop_bc(mc, bc);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
op->o_callback = cb;
send_ldap_result(op, rs);
asyncmeta_clear_bm_context(bc);
goto finish;
}
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
asyncmeta_start_listeners(mc, candidates);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
finish:
return rs->sr_err;
}

View file

@ -0,0 +1,112 @@
/* suffixmassage.c - massages ldap backend dns */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2016 The OpenLDAP Foundation.
* Portions Copyright 2016 Symas Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
/* ACKNOWLEDGEMENTS:
* This work was developed by Symas Corporation
* based on back-meta module for inclusion in OpenLDAP Software.
* This work was sponsored by Ericsson. */
/* This is an altered version */
/*
* Copyright 1999, Howard Chu, All rights reserved. <hyc@highlandsun.com>
* Copyright 2000, Pierangelo Masarati, All rights reserved. <ando@sys-net.it>
*
* Module back-ldap, originally developed by Howard Chu
*
* has been modified by Pierangelo Masarati. The original copyright
* notice has been maintained.
*
* Permission is granted to anyone to use this software for any purpose
* on any computer system, and to alter it and redistribute it, subject
* to the following restrictions:
*
* 1. The author is not responsible for the consequences of use of this
* software, no matter how awful, even if they arise from flaws in it.
*
* 2. The origin of this software must not be misrepresented, either by
* explicit claim or by omission. Since few users ever read sources,
* credits should appear in the documentation.
*
* 3. Altered versions must be plainly marked as such, and must not be
* misrepresented as being the original software. Since few users
* ever read sources, credits should appear in the documentation.
*
* 4. This notice may not be removed or altered.
*/
#include "portable.h"
#include <stdio.h>
#include <ac/string.h>
#include <ac/socket.h>
#include "slap.h"
#include "../back-ldap/back-ldap.h"
#include "back-asyncmeta.h"
int
asyncmeta_dn_massage(
a_dncookie *dc,
struct berval *dn,
struct berval *res )
{
int rc = 0;
static char *dmy = "";
switch ( rewrite_session( dc->target->mt_rwmap.rwm_rw, dc->ctx,
( dn->bv_val ? dn->bv_val : dmy ),
dc->conn, &res->bv_val ) )
{
case REWRITE_REGEXEC_OK:
if ( res->bv_val != NULL ) {
res->bv_len = strlen( res->bv_val );
} else {
*res = *dn;
}
Debug( LDAP_DEBUG_ARGS,
"[rw] %s: \"%s\" -> \"%s\"\n",
dc->ctx,
BER_BVISNULL( dn ) ? "" : dn->bv_val,
BER_BVISNULL( res ) ? "" : res->bv_val );
rc = LDAP_SUCCESS;
break;
case REWRITE_REGEXEC_UNWILLING:
if ( dc->rs ) {
dc->rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
dc->rs->sr_text = "Operation not allowed";
}
rc = LDAP_UNWILLING_TO_PERFORM;
break;
case REWRITE_REGEXEC_ERR:
if ( dc->rs ) {
dc->rs->sr_err = LDAP_OTHER;
dc->rs->sr_text = "Rewrite error";
}
rc = LDAP_OTHER;
break;
}
if ( res->bv_val == dmy ) {
BER_BVZERO( res );
}
return rc;
}

View file

@ -0,0 +1,55 @@
/* unbind.c - unbind handler for back-asyncmeta */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2016 The OpenLDAP Foundation.
* Portions Copyright 2016 Symas Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
/* ACKNOWLEDGEMENTS:
* This work was developed by Symas Corporation
* based on back-meta module for inclusion in OpenLDAP Software.
* This work was sponsored by Ericsson. */
#include "portable.h"
#include <stdio.h>
#include <ac/errno.h>
#include <ac/socket.h>
#include <ac/string.h>
#include "slap.h"
#include "../back-ldap/back-ldap.h"
#include "back-asyncmeta.h"
int
asyncmeta_back_conn_destroy(
Backend *be,
Connection *conn )
{
a_metainfo_t *mi = ( a_metainfo_t * )be->be_private;
int i;
Debug( LDAP_DEBUG_TRACE,
"=>asyncmeta_back_conn_destroy: fetching conn=%ld DN=\"%s\"\n",
conn->c_connid,
BER_BVISNULL( &conn->c_ndn ) ? "" : conn->c_ndn.bv_val, 0 );
/*
* Cleanup rewrite session
*/
for ( i = 0; i < mi->mi_ntargets; ++i ) {
rewrite_session_delete( mi->mi_targets[ i ]->mt_rwmap.rwm_rw, conn );
}
return 0;
}

View file

@ -255,6 +255,21 @@ over_back_response ( Operation *op, SlapReply *rs )
return rc; return rc;
} }
static int
over_back_response_cleanup(Operation *op, SlapReply *rs)
{
if (rs->sr_type == REP_RESULT) {
if (op->o_callback != NULL) {
slap_callback *sc = op->o_callback;
op->o_callback = sc->sc_next;
free( sc );
}
}
return 0;
}
static int static int
over_access_allowed( over_access_allowed(
Operation *op, Operation *op,
@ -727,7 +742,8 @@ over_op_func(
slap_overinfo *oi; slap_overinfo *oi;
slap_overinst *on; slap_overinst *on;
BackendDB *be = op->o_bd, db; BackendDB *be = op->o_bd, db;
slap_callback cb = {NULL, over_back_response, NULL, NULL}, **sc; slap_callback **sc;
slap_callback *cb = (slap_callback *) ch_malloc( sizeof( slap_callback ));
int rc = SLAP_CB_CONTINUE; int rc = SLAP_CB_CONTINUE;
/* FIXME: used to happen for instance during abandon /* FIXME: used to happen for instance during abandon
@ -742,14 +758,18 @@ over_op_func(
db.be_flags |= SLAP_DBFLAG_OVERLAY; db.be_flags |= SLAP_DBFLAG_OVERLAY;
op->o_bd = &db; op->o_bd = &db;
} }
cb.sc_next = op->o_callback; cb->sc_cleanup = over_back_response_cleanup;
cb.sc_private = oi; cb->sc_response = over_back_response;
op->o_callback = &cb; cb->sc_writewait = NULL;
cb->sc_next = op->o_callback;
cb->sc_private = oi;
op->o_callback = cb;
rc = overlay_op_walk( op, rs, which, oi, on ); rc = overlay_op_walk( op, rs, which, oi, on );
for ( sc = &op->o_callback; *sc; sc = &(*sc)->sc_next ) { for ( sc = &op->o_callback; *sc; sc = &(*sc)->sc_next ) {
if ( *sc == &cb ) { if ( *sc == cb ) {
*sc = cb.sc_next; *sc = cb->sc_next;
ch_free( cb );
break; break;
} }
} }

View file

@ -185,7 +185,7 @@ main( int argc, char **argv )
/* by default, tolerate referrals and no such object */ /* by default, tolerate referrals and no such object */
tester_ignore_str2errlist( "REFERRAL,NO_SUCH_OBJECT" ); tester_ignore_str2errlist( "REFERRAL,NO_SUCH_OBJECT" );
while ( (i = getopt( argc, argv, "ACc:D:e:Ff:H:h:i:L:l:M:m:p:r:t:T:w:v" )) != EOF ) { while ( (i = getopt( argc, argv, "ACc:D:e:Ff:H:h:i:L:l:M:m:Np:r:t:T:w:v" )) != EOF ) {
switch ( i ) { switch ( i ) {
case 'A': case 'A':
noattrs++; noattrs++;