mirror of
https://git.openldap.org/openldap/openldap.git
synced 2025-12-20 22:59:34 -05:00
ITS#8303 Asynchronous meta back-end for OpenLDAP
This commit is contained in:
parent
a4c7943d39
commit
6cafdfa8d8
25 changed files with 14692 additions and 7 deletions
23
configure.in
23
configure.in
|
|
@ -316,6 +316,8 @@ OL_ARG_ENABLE(mdb,[ --enable-mdb enable mdb database backend],
|
|||
yes, [no yes mod], ol_enable_backends)dnl
|
||||
OL_ARG_ENABLE(meta,[ --enable-meta enable metadirectory backend],
|
||||
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],
|
||||
yes, [no yes mod], ol_enable_backends)dnl
|
||||
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])
|
||||
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_with_tls = no ; then
|
||||
AC_MSG_ERROR([LAN Manager passwords require OpenSSL])
|
||||
|
|
@ -543,6 +549,7 @@ BUILD_HDB=no
|
|||
BUILD_LDAP=no
|
||||
BUILD_MDB=no
|
||||
BUILD_META=no
|
||||
BUILD_ASYNCMETA=no
|
||||
BUILD_MONITOR=no
|
||||
BUILD_NDB=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])
|
||||
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
|
||||
BUILD_SLAPD=yes
|
||||
BUILD_NDB=$ol_enable_ndb
|
||||
|
|
@ -3142,6 +3163,7 @@ dnl backends
|
|||
AC_SUBST(BUILD_LDAP)
|
||||
AC_SUBST(BUILD_MDB)
|
||||
AC_SUBST(BUILD_META)
|
||||
AC_SUBST(BUILD_ASYNCMETA)
|
||||
AC_SUBST(BUILD_MONITOR)
|
||||
AC_SUBST(BUILD_NDB)
|
||||
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-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-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-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]
|
||||
|
|
|
|||
487
doc/man/man5/slapd-asyncmeta.5
Normal file
487
doc/man/man5/slapd-asyncmeta.5
Normal 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.
|
||||
50
servers/slapd/back-asyncmeta/Makefile.in
Normal file
50
servers/slapd/back-asyncmeta/Makefile.in
Normal 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 $@
|
||||
52
servers/slapd/back-asyncmeta/abandon.c
Normal file
52
servers/slapd/back-asyncmeta/abandon.c
Normal 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;
|
||||
}
|
||||
368
servers/slapd/back-asyncmeta/add.c
Normal file
368
servers/slapd/back-asyncmeta/add.c
Normal 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;
|
||||
}
|
||||
847
servers/slapd/back-asyncmeta/back-asyncmeta.h
Normal file
847
servers/slapd/back-asyncmeta/back-asyncmeta.h
Normal 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 */
|
||||
1978
servers/slapd/back-asyncmeta/bind.c
Normal file
1978
servers/slapd/back-asyncmeta/bind.c
Normal file
File diff suppressed because it is too large
Load diff
289
servers/slapd/back-asyncmeta/candidates.c
Normal file
289
servers/slapd/back-asyncmeta/candidates.c
Normal 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;
|
||||
}
|
||||
293
servers/slapd/back-asyncmeta/compare.c
Normal file
293
servers/slapd/back-asyncmeta/compare.c
Normal 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;
|
||||
|
||||
}
|
||||
3191
servers/slapd/back-asyncmeta/config.c
Normal file
3191
servers/slapd/back-asyncmeta/config.c
Normal file
File diff suppressed because it is too large
Load diff
1327
servers/slapd/back-asyncmeta/conn.c
Normal file
1327
servers/slapd/back-asyncmeta/conn.c
Normal file
File diff suppressed because it is too large
Load diff
240
servers/slapd/back-asyncmeta/delete.c
Normal file
240
servers/slapd/back-asyncmeta/delete.c
Normal 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;
|
||||
}
|
||||
228
servers/slapd/back-asyncmeta/dncache.c
Normal file
228
servers/slapd/back-asyncmeta/dncache.c
Normal 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 );
|
||||
}
|
||||
509
servers/slapd/back-asyncmeta/init.c
Normal file
509
servers/slapd/back-asyncmeta/init.c
Normal 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 */
|
||||
874
servers/slapd/back-asyncmeta/map.c
Normal file
874
servers/slapd/back-asyncmeta/map.c
Normal 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;
|
||||
}
|
||||
545
servers/slapd/back-asyncmeta/message_queue.c
Normal file
545
servers/slapd/back-asyncmeta/message_queue.c
Normal 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;
|
||||
}
|
||||
1779
servers/slapd/back-asyncmeta/meta_result.c
Normal file
1779
servers/slapd/back-asyncmeta/meta_result.c
Normal file
File diff suppressed because it is too large
Load diff
369
servers/slapd/back-asyncmeta/modify.c
Normal file
369
servers/slapd/back-asyncmeta/modify.c
Normal 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;
|
||||
}
|
||||
315
servers/slapd/back-asyncmeta/modrdn.c
Normal file
315
servers/slapd/back-asyncmeta/modrdn.c
Normal 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;
|
||||
}
|
||||
54
servers/slapd/back-asyncmeta/proto-asyncmeta.h
Normal file
54
servers/slapd/back-asyncmeta/proto-asyncmeta.h
Normal 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 */
|
||||
680
servers/slapd/back-asyncmeta/search.c
Normal file
680
servers/slapd/back-asyncmeta/search.c
Normal 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;
|
||||
}
|
||||
112
servers/slapd/back-asyncmeta/suffixmassage.c
Normal file
112
servers/slapd/back-asyncmeta/suffixmassage.c
Normal 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;
|
||||
}
|
||||
55
servers/slapd/back-asyncmeta/unbind.c
Normal file
55
servers/slapd/back-asyncmeta/unbind.c
Normal 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;
|
||||
}
|
||||
|
|
@ -255,6 +255,21 @@ over_back_response ( Operation *op, SlapReply *rs )
|
|||
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
|
||||
over_access_allowed(
|
||||
Operation *op,
|
||||
|
|
@ -727,7 +742,8 @@ over_op_func(
|
|||
slap_overinfo *oi;
|
||||
slap_overinst *on;
|
||||
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;
|
||||
|
||||
/* FIXME: used to happen for instance during abandon
|
||||
|
|
@ -742,14 +758,18 @@ over_op_func(
|
|||
db.be_flags |= SLAP_DBFLAG_OVERLAY;
|
||||
op->o_bd = &db;
|
||||
}
|
||||
cb.sc_next = op->o_callback;
|
||||
cb.sc_private = oi;
|
||||
op->o_callback = &cb;
|
||||
cb->sc_cleanup = over_back_response_cleanup;
|
||||
cb->sc_response = over_back_response;
|
||||
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 );
|
||||
for ( sc = &op->o_callback; *sc; sc = &(*sc)->sc_next ) {
|
||||
if ( *sc == &cb ) {
|
||||
*sc = cb.sc_next;
|
||||
if ( *sc == cb ) {
|
||||
*sc = cb->sc_next;
|
||||
ch_free( cb );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -185,7 +185,7 @@ main( int argc, char **argv )
|
|||
/* by default, tolerate referrals and 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 ) {
|
||||
case 'A':
|
||||
noattrs++;
|
||||
|
|
|
|||
Loading…
Reference in a new issue