slapd-meta

title: slapd-meta(5)

summary: metadirectory backend to slapd

text:
# slapd-meta(5)

## NAME
slapd-meta - metadirectory backend to slapd

## SYNOPSIS
/etc/openldap/slapd.conf

## DESCRIPTION
The meta backend to 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).

A basic knowledge of the functionality of the slapd-ldap(5) backend is recommended. This backend has been designed as an enhancement of the ldap backend. The two backends share many features (actually they also share portions of code). While the ldap backend is intended to proxy operations directed to a single server, the meta backend is mainly intended for proxying of multiple servers and possibly naming context masquerading. These features, although useful in many scenarios, may result in excessive overhead for some applications, so its use should be carefully considered. In the examples section, some typical scenarios will be discussed.

The proxy instance of slapd(8) must contain schema information for the attributes and objectClasses used in filters, request DN and request-related data in general. It should also contain schema information for the data returned by the proxied server. It is the responsibility of the proxy administrator to keep the schema of the proxy lined up with that of the proxied server.

Note: When looping back to the same instance of slapd(8), each connection requires a new thread; as a consequence, slapd(8) must be compiled with thread support, and the threads parameter may need some tuning; in those cases, unless the multiple target feature is required, one may consider using slapd-relay(5) instead, which performs the relayed operation internally and thus reuses the same connection.

## EXAMPLES
There are examples in various places in this document, as well as in the slapd/back-meta/data/ directory in the OpenLDAP source tree.

## CONFIGURATION
These slapd.conf options apply to the META backend database. That is, they must follow a "database meta" line and come before any subsequent "backend" or "database" lines. Other database options are described in the slapd.conf(5) manual page.

Note: In early versions of back-ldap and back-meta it was recommended to always set

```
lastmod  off
```

for ldap and meta databases. This was required because operational attributes related to entry creation and modification should not be proxied, as they could be mistakenly written to the target server(s), generating an error. The current implementation automatically sets lastmod to off, so its use is redundant and should be omitted.

## 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:

conn-ttl <time>

This directive causes a cached connection to be dropped an recreated after a given ttl, regardless of being idle or not.

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.

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 idle-timeout directive.

onerr {CONTINUE|report|stop}

This directive allows one to select the behavior in case an error is returned by one target during a search. The default, continue, consists in continuing the operation, trying to return as much data as possible. If the value is set to stop, 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 report, 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.

norefs <NO|yes>

If 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.

noundeffilter <NO|yes>

If 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 (!(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.

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 unwillingToPerform 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.

pseudoroot-bind-defer {YES|no}

This directive, when set to yes, causes the authentication to the remote servers with the pseudo-root identity (the identity defined in each idassert-bind directive) to be deferred until actually needed by subsequent operations. Otherwise, all binds as the rootdn are propagated to the targets.

quarantine <interval>,<num>[;<interval>,<num>[...]]

Turns on quarantine of URIs that returned 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 interval seconds elapsed since last attempt, for exactly num times; then use the next pattern. If num for the last pattern is "+", it retries forever; otherwise, no more retries occur. This directive must appear before any target specification; it affects all targets with the same pattern.

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 chase-referrals is set to yes.

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 protocol-version to 2. If set before any target specification, it affects all targets, unless overridden by any per-target directive.

single-conn {NO|yes}

Discards current cached connection when the client rebinds.

use-temporary-conn {NO|yes}

when set to yes, create a temporary connection whenever competing with other threads for a shared one; otherwise, wait until the shared connection is available.

## TARGET SPECIFICATION
Target specification starts with a "uri" directive:

uri <protocol>://[<host>]/<naming context> [...]

The <protocol> part can be anything ldap_initialize(3) accepts ({ldap|ldaps|ldapi} and variants); the <host> may be omitted, defaulting to whatever is set in ldap.conf(5). The <naming context> part is mandatory for the first URI, but it must be omitted for subsequent ones, if any. The naming context part must be within the naming context defined for the backend, e.g.:

```
suffix "dc=foo,dc=com"
uri    "ldap://x.foo.com/dc=x,dc=foo,dc=com"
```

The <naming context> part doesn't need to be unique across the targets; it may also match one of the values of the "suffix" directive. Multiple URIs may be defined in a single URI statement. The additional URIs must be separate arguments and must not have any <naming context> part. This causes the underlying library to contact the first server of the list that responds. For example, if l1.foo.com and l2.foo.com are shadows of the same server, the directive

```
suffix "dc=foo,dc=com"
uri    "ldap://l1.foo.com/dc=foo,dc=com" "ldap://l2.foo.com/"
```

causes l2.foo.com to be contacted whenever l1.foo.com does not respond. In that case, the URI list is internally rearranged, by moving unavailable URIs to the end, so that further connection attempts occur with respect to the last URI that succeeded.

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. The acl-authcDN identity is by no means implicitly used by the proxy when the client connects anonymously.

acl-passwd <password>

Password used with the acl-authcDN above.

bind-timeout <microseconds>

This directive defines the timeout, in microseconds, used when polling for response after an asynchronous bind connection. The initial call to ldap_result(3) is performed with a trade-off timeout of 100000 us; if that results in a timeout exceeded, subsequent calls use the value provided with bind-timeout. The default value is used also for subsequent calls if bind-timeout is not specified. If set before any target specification, it affects all targets, unless overridden by any per-target directive.

chase-referrals {YES|no}

enable/disable automatic referral chasing, which is delegated to the underlying libldap, with rebinding eventually performed if the rebind-as-user 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.

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.

filter <pattern>

This directive allows specifying a 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 pattern the target is considered while fulfilling the request; otherwise the target is ignored. There may be multiple occurrences of the filter directive for each target.

idassert-authzFrom <authz-regexp>

if defined, selects what local identities are authorized to exploit the identity assertion feature. The string <authz-regexp> follows the rules defined for the authzFrom attribute. See slapd.conf(5), section related to authz-policy, for details on the syntax of this field.

idassert-bind bindmethod=none|simple|sasl [binddn=<simple DN>] [credentials=<simple password>] [saslmech=<SASL mech>] [secprops=<properties>] [realm=<realm>] [authcId=<authentication ID>] [authzId=<authorization ID>] [authz={native|proxyauthz}] [mode=<mode>] [flags=<flags>] [starttls=no|yes|critical] [tls_cert=<file>] [tls_key=<file>] [tls_cacert=<file>] [tls_cacertdir=<path>] [tls_reqcert=never|allow|try|demand] [tls_reqsan=never|allow|try|demand] [tls_cipher_suite=<ciphers>] [tls_ecname=<ciphers>] [tls_protocol_min=<major>[.<minor>]] [tls_crlcheck=none|peer|all]

Allows one to define the parameters of the authentication method that is internally used by the proxy to authorize connections that are authenticated by other databases. The identity defined by this directive, according to the properties associated to the authentication method, is supposed to have auth access on the target server to attributes used on the proxy for authentication and authorization, and to be allowed to authorize the users. This requires to have proxyAuthz privileges on a wide set of DNs, e.g. authzTo=dn.subtree:"", and the remote server to have authz-policy set to to or both. See slapd.conf(5) for details on these statements and for remarks and drawbacks about their usage. The supported bindmethods are none|simple|sasl

where none is the default, i.e. no identity assertion is performed.

The authz parameter is used to instruct the SASL bind to exploit native SASL authorization, if available; since connections are cached, this should only be used when authorizing with a fixed identity (e.g. by means of the authzDN or authzID parameters). Otherwise, the default proxyauthz is used, i.e. the proxyAuthz control (Proxied Authorization, RFC 4370) is added to all operations.

The supported modes are:

<mode> := {legacy|anonymous|none|self}

If <mode> is not present, and authzId is given, the proxy always authorizes that identity. <authorization ID> can be

u:<user>

[dn:]<DN>

The former is supposed to be expanded by the remote server according to the authz rules; see slapd.conf(5) for details. In the latter case, whether or not the dn: prefix is present, the string must pass DN validation and normalization.

The default mode is legacy, which implies that the proxy will either perform a simple bind as the authcDN or a SASL bind as the authcID and assert the client's identity when it is not anonymous. Direct binds are always proxied. The other modes imply that the proxy will always either perform a simple bind as the authcDN or a SASL bind as the authcID, unless restricted by idassert-authzFrom rules (see below), in which case the operation will fail; eventually, it will assert some other identity according to <mode>. Other identity assertion modes are anonymous and self, which respectively mean that the empty or the client's identity will be asserted; none, which means that no proxyAuthz control will be used, so the authcDN or the authcID identity will be asserted. For all modes that require the use of the proxyAuthz control, on the remote server the proxy identity must have appropriate authzTo permissions, or the asserted identities must have appropriate authzFrom permissions. Note, however, that the ID assertion feature is mostly useful when the asserted identities do not exist on the remote server.

Flags can be

override,[non-]prescriptive,proxy-authz-[non-]critical

When the override flag is used, identity assertion takes place even when the database is authorizing for the identity of the client, i.e. after binding with the provided identity, and thus authenticating it, the proxy performs the identity assertion using the configured identity and authentication method.

When the prescriptive flag is used (the default), operations fail with inappropriateAuthentication for those identities whose assertion is not allowed by the idassert-authzFrom patterns. If the non-prescriptive flag is used, operations are performed anonymously for those identities whose assertion is not allowed by the idassert-authzFrom patterns.

When the proxy-authz-non-critical flag is used (the default), the proxyAuthz control is not marked as critical, in violation of RFC 4370. Use of proxy-authz-critical is recommended.

The TLS settings default to the same as the main slapd TLS settings, except for tls_reqcert which defaults to "demand", and tls_reqsan which defaults to "allow"..

The identity associated to this directive is also used for privileged operations whenever idassert-bind is defined and acl-bind is not. See acl-bind for details.

idle-timeout <time>

This directive causes a cached connection to be dropped an recreated after it has been idle for the specified time. The value can be specified as [<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.

keepalive <idle>:<probes>:<interval>

The keepalive parameter sets the values of idle, probes, and interval used to check whether a socket is alive; idle is the number of seconds a connection needs to remain idle before TCP starts sending keepalive probes; probes is the maximum number of keepalive probes TCP should send before dropping the connection; interval is interval in seconds between individual keepalive probes. Only some systems support the customization of these values; the keepalive parameter is ignored otherwise, and system-wide settings are used.

map {attribute|objectclass} [<local name>|*] {<foreign name>|*}

This maps object classes and attributes as in the LDAP backend. See slapd-ldap(5).

network-timeout <time>

Sets the network timeout value after which poll(2)/select(2) following a connect(2) returns in case of no activity. The value is in seconds, and it can be specified as for idle-timeout. If set before any target specification, it affects all targets, unless overridden by any per-target directive.

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, 3 times); the global value can be overridden by redefinitions inside each target specification.

rewrite* ...

The rewrite options are described in the "REWRITING" section.

subtree-{exclude|include} <rule>

This directive allows one to indicate what subtrees are actually served by a target. The syntax of the supported rules is <rule>: [dn[.<style>]:]<pattern>

<style>: subtree|children|regex

When <style> is either subtree or children the <pattern> is a DN that must be within the naming context served by the target. When <style> is regex the <pattern> is a regex(5) pattern. If the dn.<style>: prefix is omitted, dn.subtree: is implicitly assumed for backward compatibility.

In the subtree-exclude form if the request DN matches at least one rule, the target is not considered while fulfilling the request; otherwise, the target is considered based on the value of the request DN. When the request is a search, also the scope is considered.

In the subtree-include form if the request DN matches at least one rule, the target is considered while fulfilling the request; otherwise the target is ignored.

```
    |  match  | exclude |

    +---------+---------+-------------------+

    |    T    |    T    | not candidate     |

    |    F    |    T    | continue checking |

    +---------+---------+-------------------+

    |    T    |    F    | candidate         |

    |    F    |    F    | not candidate     |

    +---------+---------+-------------------+
```

There may be multiple occurrences of the subtree-exclude or subtree-include directive for each of the targets, but they are mutually exclusive.

suffixmassage <virtual naming context> <real naming context>

All the directives starting with "rewrite" refer to the rewrite engine that has been added to slapd. The "suffixmassage" directive was introduced in the LDAP backend to allow suffix massaging while proxying. It has been obsoleted by the rewriting tools. However, both for backward compatibility and for ease of configuration when simple suffix massage is required, it has been preserved. It wraps the basic rewriting instructions that perform suffix massaging. See the "REWRITING" section for a detailed list of the rewrite rules it implies.

t-f-support {NO|yes|discover}

enable if the remote server supports absolute filters (see RFC 4526 for details). If set to 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.

timeout [<op>=]<val> [...]

This directive allows one to set per-operation timeouts. Operations can be <op> ::= bind, add, delete, modrdn, modify, compare, search

The overall duration of the search operation is controlled either by the timelimit parameter or by server-side enforced time limits (see timelimit and limits in slapd.conf(5) for details). This timeout parameter controls how long the target can be irresponsive before the operation is aborted. Timeout is meaningless for the remaining operations, unbind and abandon, which do not imply any response, while it is not yet implemented in currently supported extended operations. If no operation is specified, the timeout val affects all supported operations. If specified before any target definition, it affects all targets unless overridden by per-target directives.

Note: if the timeout is exceeded, the operation is cancelled (according to the cancel directive); the protocol does not provide any means to rollback operations, so the client will not be notified about the result of the operation, which may eventually succeeded or not. In case the timeout is exceeded during a bind operation, the connection is destroyed, according to RFC4511.

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 ldaps://. propagate issues the StartTLS operation only if the original connection did. The try- 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.

## SCENARIOS
A powerful (and in some sense dangerous) rewrite engine has been added to both the LDAP and Meta backends. While the former can gain limited beneficial effects from rewriting stuff, the latter can become an amazingly powerful tool.

Consider a couple of scenarios first.

1) Two directory servers share two levels of naming context; say "dc=a,dc=foo,dc=com" and "dc=b,dc=foo,dc=com". Then, an unambiguous Meta database can be configured as:

```
database meta
suffix   "dc=foo,dc=com"
uri      "ldap://a.foo.com/dc=a,dc=foo,dc=com"
uri      "ldap://b.foo.com/dc=b,dc=foo,dc=com"
```

Operations directed to a specific target can be easily resolved because there are no ambiguities. The only operation that may resolve to multiple targets is a search with base "dc=foo,dc=com" and scope at least "one", which results in spawning two searches to the targets.

2a) Two directory servers don't share any portion of naming context, but they'd present as a single DIT [Caveat: uniqueness of (massaged) entries among the two servers is assumed; integrity checks risk to incur in excessive overhead and have not been implemented]. Say we have "dc=bar,dc=org" and "o=Foo,c=US", and we'd like them to appear as branches of "dc=foo,dc=com", say "dc=a,dc=foo,dc=com" and "dc=b,dc=foo,dc=com". Then we need to configure our Meta backend as:

```
database      meta
suffix        "dc=foo,dc=com"
uri           "ldap://a.bar.com/dc=a,dc=foo,dc=com"
suffixmassage "dc=a,dc=foo,dc=com" "dc=bar,dc=org"
uri           "ldap://b.foo.com/dc=b,dc=foo,dc=com"
suffixmassage "dc=b,dc=foo,dc=com" "o=Foo,c=US"
```

Again, operations can be resolved without ambiguity, although some rewriting is required. Notice that the virtual naming context of each target is a branch of the database's naming context; it is rewritten back and forth when operations are performed towards the target servers. What "back and forth" means will be clarified later.

When a search with base "dc=foo,dc=com" is attempted, if the scope is "base" it fails with "no such object"; in fact, the common root of the two targets (prior to massaging) does not exist. If the scope is "one", both targets are contacted with the base replaced by each target's base; the scope is derated to "base". In general, a scope "one" search is honored, and the scope is derated, only when the incoming base is at most one level lower of a target's naming context (prior to massaging).

Finally, if the scope is "sub" the incoming base is replaced by each target's unmassaged naming context, and the scope is not altered.

2b) Consider the above reported scenario with the two servers sharing the same naming context:

```
database      meta
suffix        "dc=foo,dc=com"
uri           "ldap://a.bar.com/dc=foo,dc=com"
suffixmassage "dc=foo,dc=com" "dc=bar,dc=org"
uri           "ldap://b.foo.com/dc=foo,dc=com"
suffixmassage "dc=foo,dc=com" "o=Foo,c=US"
```

All the previous considerations hold, except that now there is no way to unambiguously resolve a DN. In this case, all the operations that require an unambiguous target selection will fail unless the DN is already cached or a default target has been set. Practical configurations may result as a combination of all the above scenarios.

## ACLs
Note on ACLs: at present you may add whatever ACL rule you desire to the Meta (and LDAP) backends. However, the meaning of an ACL on a proxy may require some considerations. Two philosophies may be considered:

a) the remote server dictates the permissions; the proxy simply passes back what it gets from the remote server.

b) the remote server unveils "everything"; the proxy is responsible for protecting data from unauthorized access.

Of course the latter sounds unreasonable, but it is not. It is possible to imagine scenarios in which a remote host discloses data that can be considered "public" inside an intranet, and a proxy that connects it to the internet may impose additional constraints. To this purpose, the proxy should be able to comply with all the ACL matching criteria that the server supports. This has been achieved with regard to all the criteria supported by slapd except a special subtle case (please file an ITS if you can find other exceptions: <http://www.openldap.org/its/>). The rule

```
access to dn="<dn>" attrs=<attr>

       by dnattr=<dnattr> read

       by * none
```

cannot be matched iff the attribute that is being requested, <attr>, is NOT <dnattr>, and the attribute that determines membership, <dnattr>, has not been requested (e.g. in a search)

In fact this ACL is resolved by slapd using the portion of entry it retrieved from the remote server without requiring any further intervention of the backend, so, if the <dnattr> attribute has not been fetched, the match cannot be assessed because the attribute is not present, not because no value matches the requirement!

Note on ACLs and attribute mapping: ACLs are applied to the mapped attributes; for instance, if the attribute locally known as "foo" is mapped to "bar" on a remote server, then local ACLs apply to attribute "foo" and are totally unaware of its remote name. The remote server will check permissions for "bar", and the local server will possibly enforce additional restrictions to "foo".

## REWRITING
A string is rewritten according to a set of rules, called a `rewrite context'. The rules are based on POSIX (''extended'') regular expressions (regex) with substring matching; basic variable substitution and map resolution of substrings is allowed by specific mechanisms detailed in the following. The behavior of pattern matching/substitution can be altered by a set of flags.

The underlying concept is to build a lightweight rewrite module for the slapd server (initially dedicated to the LDAP backend).

## Passes
An incoming string is matched against a set of rules. Rules are made of a regex match pattern, a substitution pattern and a set of actions, described by a set of flags. In case of match a string rewriting is performed according to the substitution pattern that allows one to refer to substrings matched in the incoming string. The actions, if any, are finally performed. The substitution pattern allows map resolution of substrings. A map is a generic object that maps a substitution pattern to a value. The flags are divided in "Pattern matching Flags" and "Action Flags"; the former alter the regex match pattern behavior while the latter alter the action that is taken after substitution.

## Pattern Matching Flags
`C'

honors case in matching (default is case insensitive)

`R'

use POSIX ''basic'' regular expressions (default is ''extended'')

`M{n}'

allow no more than n recursive passes for a specific rule; does not alter the max total count of passes, so it can only enforce a stricter limit for a specific rule.

## Action Flags
`:'

apply the rule once only (default is recursive)

`@'

stop applying rules in case of match; the current rule is still applied recursively; combine with `:' to apply the current rule only once and then stop.

`#'

stop current operation if the rule matches, and issue an `unwilling to perform' error.

`G{n}'

jump n rules back and forth (watch for loops!). Note that `G{1}' is implicit in every rule.

`I'

ignores errors in rule; this means, in case of error, e.g. issued by a map, the error is treated as a missed match. The `unwilling to perform' is not overridden.

`U{n}'

uses n as return code if the rule matches; the flag does not alter the recursive behavior of the rule, so, to have it performed only once, it must be used in combination with `:', e.g. `:U{16}' returns the value `16' after exactly one execution of the rule, if the pattern matches. As a consequence, its behavior is equivalent to `@', with the return code set to n; or, in other words, `@' is equivalent to `U{0}'. By convention, the freely available codes are above 16 included; the others are reserved.

The ordering of the flags can be significant. For instance: `IG{2}' means ignore errors and jump two lines ahead both in case of match and in case of error, while `G{2}I' means ignore errors, but jump two lines ahead only in case of match.

More flags (mainly Action Flags) will be added as needed.

## Pattern matching:
See regex(7) and/or re_format(7).

## Substitution Pattern Syntax:
Everything starting with `%' requires substitution;

the only obvious exception is `%%', which is left as is;

the basic substitution is `%d', where `d' is a digit; 0 means the whole string, while 1-9 is a submatch;

a `%' followed by a `{' invokes an advanced substitution. The pattern is:

`%' `{' [ <op> ] <name> `(' <substitution> `)' `}'

where <name> must be a legal name for the map, i.e.

```
<name> ::= [a-z][a-z0-9]* (case insensitive)
<op> ::= `>' `|' `&' `&&' `*' `**' `$'
```

and <substitution> must be a legal substitution pattern, with no limits on the nesting level.

The operators are:

>

sub context invocation; <name> must be a legal, already defined rewrite context name

|

external command invocation; <name> must refer to a legal, already defined command name (NOT IMPL.)

&

variable assignment; <name> defines a variable in the running operation structure which can be dereferenced later; operator & assigns a variable in the rewrite context scope; operator && assigns a variable that scopes the entire session, e.g. its value can be dereferenced later by other rewrite contexts

*

variable dereferencing; <name> must refer to a variable that is defined and assigned for the running operation; operator * dereferences a variable scoping the rewrite context; operator ** dereferences a variable scoping the whole session, e.g. the value is passed across rewrite contexts

$

parameter dereferencing; <name> must refer to an existing parameter; the idea is to make some run-time parameters set by the system available to the rewrite engine, as the client host name, the bind DN if any, constant parameters initialized at config time, and so on; no parameter is currently set by either back-ldap or back-meta, but constant parameters can be defined in the configuration file by using the rewriteParam directive.

Substitution escaping has been delegated to the `%' symbol, which is used instead of `\' in string substitution patterns because `\' is already escaped by slapd's low level parsing routines; as a consequence, regex escaping requires two `\' symbols, e.g. `.*\.foo\.bar' must be written as `.*\\.foo\\.bar'.

## Rewrite context:
A rewrite context is a set of rules which are applied in sequence. The basic idea is to have an application initialize a rewrite engine (think of Apache's mod_rewrite ...) with a set of rewrite contexts; when string rewriting is required, one invokes the appropriate rewrite context with the input string and obtains the newly rewritten one if no errors occur.

Each basic server operation is associated to a rewrite context; they are divided in two main groups: client -> server and server -> client rewriting.

client -> server:

```
(default)            if defined and no specific context

                     is available
bindDN               bind
searchBase           search
searchFilter         search
searchFilterAttrDN   search
compareDN            compare
compareAttrDN        compare AVA
addDN                add
addAttrDN            add AVA
modifyDN             modify
modifyAttrDN         modify AVA
modrDN               modrdn
newSuperiorDN        modrdn
deleteDN             delete
exopPasswdDN         password modify extended operation DN if proxy
```

server -> client:

```
searchResult         search (only if defined; no default;

                     acts on DN and DN-syntax attributes

                     of search results)
searchAttrDN         search AVA
matchedDN            all ops (only if applicable)
```

## Basic configuration syntax
rewriteEngine { on | off }

If `on', the requested rewriting is performed; if `off', no rewriting takes place (an easy way to stop rewriting without altering too much the configuration file).

rewriteContext <context name> [ alias <aliased context name> ]

<Context name> is the name that identifies the context, i.e. the name used by the application to refer to the set of rules it contains. It is used also to reference sub contexts in string rewriting. A context may alias another one. In this case the alias context contains no rule, and any reference to it will result in accessing the aliased one.

rewriteRule <regex match pattern> <substitution pattern> [ <flags> ]

Determines how a string can be rewritten if a pattern is matched. Examples are reported below.

## Additional configuration syntax:
rewriteMap <map type> <map name> [ <map attrs> ]

Allows one to define a map that transforms substring rewriting into something else. The map is referenced inside the substitution pattern of a rule.

rewriteParam <param name> <param value>

Sets a value with global scope, that can be dereferenced by the command `%{$paramName}'.

rewriteMaxPasses <number of passes> [<number of passes per rule>]

Sets the maximum number of total rewriting passes that can be performed in a single rewrite operation (to avoid loops). A safe default is set to 100; note that reaching this limit is still treated as a success; recursive invocation of rules is simply interrupted. The count applies to the rewriting operation as a whole, not to any single rule; an optional per-rule limit can be set. This limit is overridden by setting specific per-rule limits with the `M{n}' flag.

## Configuration examples:

```
# set to `off' to disable rewriting
rewriteEngine on
# the rules the "suffixmassage" directive implies
rewriteEngine on
# all dataflow from client to server referring to DNs
rewriteContext default
rewriteRule "(.*)<virtualnamingcontext>$" "%1<realnamingcontext>" ":"
# empty filter rule
rewriteContext searchFilter
# all dataflow from server to client
rewriteContext searchResult
rewriteRule "(.*)<realnamingcontext>$" "%1<virtualnamingcontext>" ":"
rewriteContext searchAttrDN alias searchResult
rewriteContext matchedDN alias searchResult
# Everything defined here goes into the `default' context.
# This rule changes the naming context of anything sent
# to `dc=home,dc=net' to `dc=OpenLDAP, dc=org'
rewriteRule "(.*)dc=home,[ ]?dc=net"

            "%1dc=OpenLDAP, dc=org"  ":"
# since a pretty/normalized DN does not include spaces
# after rdn separators, e.g. `,', this rule suffices:
rewriteRule "(.*)dc=home,dc=net"

            "%1dc=OpenLDAP,dc=org"  ":"
# Start a new context (ends input of the previous one).
# This rule adds blanks between DN parts if not present.
rewriteContext  addBlanks
rewriteRule     "(.*),([^ ].*)" "%1, %2"
# This one eats blanks
rewriteContext  eatBlanks
rewriteRule     "(.*),[ ](.*)" "%1,%2"
# Here control goes back to the default rewrite
# context; rules are appended to the existing ones.
# anything that gets here is piped into rule `addBlanks'
rewriteContext  default
rewriteRule     ".*" "%{>addBlanks(%0)}" ":"
# Rewrite the search base according to `default' rules.
rewriteContext  searchBase alias default
# Search results with OpenLDAP DN are rewritten back with
# `dc=home,dc=net' naming context, with spaces eaten.
rewriteContext  searchResult
rewriteRule     "(.*[^ ]?)[ ]?dc=OpenLDAP,[ ]?dc=org"

                "%{>eatBlanks(%1)}dc=home,dc=net"    ":"
# Bind with email instead of full DN: we first need
# an ldap map that turns attributes into a DN (the
# argument used when invoking the map is appended to
# the URI and acts as the filter portion)
rewriteMap ldap attr2dn "ldap://host/dc=my,dc=org?dn?sub"
# Then we need to detect DN made up of a single email,
# e.g. `mail=someone@example.com'; note that the rule
# in case of match stops rewriting; in case of error,
# it is ignored.  In case we are mapping virtual
# to real naming contexts, we also need to rewrite
# regular DNs, because the definition of a bindDn
# rewrite context overrides the default definition.
rewriteContext bindDN
rewriteRule "^mail=[^,]+@[^,]+$" "%{attr2dn(%0)}" ":@I"
# This is a rather sophisticated example. It massages a
# search filter in case who performs the search has
# administrative privileges.  First we need to keep
# track of the bind DN of the incoming request, which is
# stored in a variable called `binddn' with session scope,
# and left in place to allow regular binding:
rewriteContext  bindDN
rewriteRule     ".+" "%{&&binddn(%0)}%0" ":"
# A search filter containing `uid=' is rewritten only
# if an appropriate DN is bound.
# To do this, in the first rule the bound DN is
# dereferenced, while the filter is decomposed in a
# prefix, in the value of the `uid=<arg>' AVA, and
# in a suffix. A tag `<>' is appended to the DN.
# If the DN refers to an entry in the `ou=admin' subtree,
# the filter is rewritten OR-ing the `uid=<arg>' with
# `cn=<arg>'; otherwise it is left as is. This could be
# useful, for instance, to allow apache's auth_ldap-1.4
# module to authenticate users with both `uid' and
# `cn', but only if the request comes from a possible
# `cn=Web auth,ou=admin,dc=home,dc=net' user.
rewriteContext searchFilter
rewriteRule "(.*\\()uid=([a-z0-9_]+)(\\).*)"

  "%{**binddn}<>%{&prefix(%1)}%{&arg(%2)}%{&suffix(%3)}"

  ":I"
rewriteRule "[^,]+,ou=admin,dc=home,dc=net"

  "%{*prefix}|(uid=%{*arg})(cn=%{*arg})%{*suffix}" ":@I"
rewriteRule ".*<>" "%{*prefix}uid=%{*arg}%{*suffix}" ":"
# This example shows how to strip unwanted DN-valued
# attribute values from a search result; the first rule
# matches DN values below "ou=People,dc=example,dc=com";
# in case of match the rewriting exits successfully.
# The second rule matches everything else and causes
# the value to be rejected.
rewriteContext searchResult
rewriteRule ".*,ou=People,dc=example,dc=com" "%0" ":@"
rewriteRule ".*" "" "#"
```

## LDAP Proxy resolution (a possible evolution of slapd-ldap(5)):
In case the rewritten DN is an LDAP URI, the operation is initiated towards the host[:port] indicated in the uri, if it does not refer to the local server. E.g.:

```
  rewriteRule '^cn=root,.*' '%0'                     'G{3}'

  rewriteRule '^cn=[a-l].*' 'ldap://ldap1.my.org/%0' ':@'

  rewriteRule '^cn=[m-z].*' 'ldap://ldap2.my.org/%0' ':@'

  rewriteRule '.*'          'ldap://ldap3.my.org/%0' ':@'
```

(Rule 1 is simply there to illustrate the `G{n}' action; it could have been written:

```
  rewriteRule '^cn=root,.*' 'ldap://ldap3.my.org/%0' ':@'
```

with the advantage of saving one rewrite pass ...)

## ACCESS CONTROL
The meta backend does not honor all ACL semantics as described in slapd.access(5). In general, access checking is delegated to the remote server(s). Only read (=r) access to the entry pseudo-attribute and to the other attribute values of the entries returned by the search operation is honored, which is performed by the frontend.

## PROXY CACHE OVERLAY
The proxy cache overlay allows caching of LDAP search requests (queries) in a local database. See slapo-pcache(5) for details.

## DEPRECATED STATEMENTS
The following statements have been deprecated and should no longer be used.

pseudorootdn <substitute DN in case of rootdn bind>

Use idassert-bind instead.

pseudorootpw <substitute password in case of rootdn bind>

Use idassert-bind instead.

## FILES
/etc/openldap/slapd.conf

default slapd configuration file

## SEE ALSO
slapd.conf(5), slapd-ldap(5), slapo-pcache(5), slapd(8), regex(7), re_format(7).

## AUTHOR
Pierangelo Masarati, based on back-ldap by Howard Chu


slapd-monitor

package: openldap-servers

title: slapd-monitor(5)

summary: Monitor backend to slapd

text:
# slapd-monitor(5)

## NAME
slapd-monitor - Monitor backend to slapd

## SYNOPSIS
/etc/openldap/slapd.conf

## DESCRIPTION
The monitor backend to slapd(8) is not an actual database; if enabled, it is automatically generated and dynamically maintained by slapd with information about the running status of the daemon.

To inspect all monitor information, issue a subtree search with base cn=Monitor, requesting that attributes "+" and "*" are returned. The monitor backend produces mostly operational attributes, and LDAP only returns operational attributes that are explicitly requested. Requesting attribute "+" is an extension which requests all operational attributes.

## CONFIGURATION
These slapd.conf options apply to the monitor backend database. That is, they must follow a "database monitor" line and come before any subsequent "backend" or "database" lines.

As opposed to most databases, the monitor database can be instantiated only once, i.e. only one occurrence of "database monitor" can occur in the slapd.conf(5) file. Moreover, the suffix of the database cannot be explicitly set by means of the suffix directive. The suffix is automatically set to "cn=Monitor".

The monitor database honors the rootdn and the rootpw directives, and the usual ACL directives, e.g. the access directive.

Other database options are described in the slapd.conf(5) manual page.

## USAGE
The usage is:

1) enable the monitor backend at configure:

```
configure --enable-monitor
```

2) activate the monitor database in the slapd.conf(5) file:

```
database monitor
```

3) add ACLs as detailed in slapd.access(5) to control access to the database, e.g.:

```
access to dn.subtree="cn=Monitor"
	by dn.exact="uid=Admin,dc=my,dc=org" write
	by users read
	by * none
```

4) ensure that the core.schema file is loaded.

The monitor backend relies on some standard track attributeTypes that must be already defined when the backend is started.

## ACCESS CONTROL
The monitor backend honors access control semantics as indicated in slapd.access(5), including the disclose access privilege, on all currently implemented operations.

## KNOWN LIMITATIONS
The monitor backend does not honor size/time limits in search operations.

## FILES
/etc/openldap/slapd.conf

default slapd configuration file

## SEE ALSO
slapd.conf(5), slapd-config(5), slapd.access(5), slapd(8), ldap(3).

## ACKNOWLEDGEMENTS
OpenLDAP Software is developed and maintained by The OpenLDAP Project <http://www.openldap.org/>. OpenLDAP Software is derived from the University of Michigan LDAP 3.3 Release.


slapd-ndb

title: slapd-ndb(5)

summary: MySQL NDB backend to slapd

text:
# slapd-ndb(5)

## NAME
slapd-ndb - MySQL NDB backend to slapd

## SYNOPSIS
/etc/openldap/slapd.conf

## DESCRIPTION
The ndb backend to slapd(8) uses the MySQL Cluster package to store data, through its NDB API. It provides fault tolerance with extreme scalability, along with a degree of SQL compatibility.

This backend is designed to store LDAP information using tables that are also visible from SQL. It uses a higher level SQL API for creating these tables, while using the low level NDB API for storing and retrieving the data within these tables. The NDB Cluster engine allows data to be partitioned across multiple data nodes, and this backend allows multiple slapd instances to operate against a given database concurrently.

The general approach is to use distinct tables for each LDAP object class. Entries comprised of multiple object classes will have their data spread across multiple tables. The data tables use a 64 bit entryID as their primary key. The DIT hierarchy is maintained in a separate table, which maps DNs to entryIDs.

This backend is experimental. While intended to be a general-purpose backend, it is currently missing a number of common LDAP features. See the TODO file in the source directory for details.

## CONFIGURATION
These slapd.conf options apply to the ndb backend database. That is, they must follow a "database ndb" line and come before any subsequent "backend" or "database" lines. Other database options are described in the slapd.conf(5) manual page.

## DATA SOURCE CONFIGURATION
dbhost <hostname>

The name or IP address of the host running the MySQL server. The default is "localhost". On Unix systems, the connection to a local server is made using a Unix Domain socket, whose path is specified using the dbsocket directive.

dbuser <username>

The MySQL login ID to use when connecting to the MySQL server. The chosen user must have sufficient privileges to manipulate the SQL tables in the target database.

dbpasswd <password>

The password for the dbuser.

dbname <database name>

The name of the MySQL database to use.

dbport <port>

The port number to use for the TCP connection to the MySQL server.

dbsocket <path>

The socket to be used for connecting to a local MySQL server.

dbflag <integer>

Client flags for the MySQL session. See the MySQL documentation for details.

dbconnect <connectstring>

The name or IP address of the host running the cluster manager. The default is "localhost".

dbconnections <integer>

The number of cluster connections to establish. Using up to 4 may improve performance under heavier load. The default is 1.

## SCHEMA CONFIGURATION
attrlen <attribute> <length>

Specify the column length to use for a particular attribute. LDAP attributes are stored in individual columns of the SQL tables. The maximum column lengths for each column must be specified when creating these tables. If a length constraint was specified in the attribute's LDAP schema definition, that value will be used by default. If the schema didn't specify a constraint, the default is 128 bytes. Currently the maximum is 1024.

index <attr[,attr...]>

Specify a list of attributes for which indexing should be maintained. Currently there is no support for substring indexing; a single index structure provides presence, equality, and inequality indexing for the specified attributes.

attrset <set> <attrs>

Specify a list of attributes to be treated as an attribute set. This directive creates a table named set which will contain all of the listed attributes. Ordinarily an attribute resides in a table named by an object class that uses the attribute. However, attributes are only allowed to appear in a single table. For attributes that are derived from an inherited object class definition, the attribute will only be stored in the superior class's table. Attribute sets should be defined for any attributes that are used in multiple unrelated object classes, i.e., classes that are not connected by a simple inheritance chain.

## ACCESS CONTROL
The ndb backend honors most access control semantics as indicated in slapd.access(5).

## FILES
/etc/openldap/slapd.conf

default slapd configuration file

## SEE ALSO
slapd.conf(5), slapd-config(5), slapd(8), slapadd(8), slapcat(8), slapindex(8), MySQL Cluster documentation.

## AUTHOR
Howard Chu, with assistance from Johan Andersson et al @ MySQL.


slapd-null

title: slapd-null(5)

summary: Null backend to slapd

text:
# slapd-null(5)

## NAME
slapd-null - Null backend to slapd

## SYNOPSIS
/etc/openldap/slapd.conf

## DESCRIPTION
The Null backend to slapd(8) is surely the most useful part of slapd:

- Searches return success but no entries.

- Compares return compareFalse.

- Updates return success (unless readonly is on) but do nothing.

- Binds other than as the rootdn fail unless the database option "bind on" is given.

- The slapadd(8) and slapcat(8) tools are equally exciting.

Inspired by the /dev/null device.

## CONFIGURATION
This slapd.conf option applies to the NULL backend database. That is, it must follow a "database null" line and come before any subsequent "database" lines. Other database options are described in the slapd.conf(5) manual page.

bind <on/off>

Allow binds as any DN in this backend's suffix, with any password. The default is "off".

dosearch <on/off>

If enabled, a single entry will be returned on all search requests. The entry's DN will be the same as the database suffix. The default is "off".

## EXAMPLE
Here is a possible slapd.conf extract using the Null backend:

```
database null
suffix   "cn=Nothing"
bind     on
```

## ACCESS CONTROL
The null backend does not honor any of the access control semantics described in slapd.access(5).

## FILES
/etc/openldap/slapd.conf

default slapd configuration file

## SEE ALSO
slapd.conf(5), slapd(8), slapadd(8), slapcat(8).


slapd-passwd

title: slapd-passwd(5)

summary: /etc/passwd backend to slapd

text:
# slapd-passwd(5)

## NAME
slapd-passwd - /etc/passwd backend to slapd

## SYNOPSIS
/etc/openldap/slapd.conf

## DESCRIPTION
The PASSWD backend to slapd(8) serves up the user account information listed in the system passwd(5) file. This backend is provided for demonstration purposes only. The DN of each entry is "uid=<username>,<suffix>". Note that non-base searches scan the entire passwd file, and are best suited for hosts with small passwd files.

## CONFIGURATION
This slapd.conf option applies to the PASSWD backend database. That is, it must follow a "database passwd" line and come before any subsequent "backend" or "database" lines. Other database options are described in the slapd.conf(5) manual page.

file <filename>

Specifies an alternate passwd file to use. The default is /etc/passwd.

## ACCESS CONTROL
The passwd backend does not honor any of the access control semantics described in slapd.access(5). Only read (=r) access to the entry pseudo-attribute and to the other attribute values of the entries returned by the search operation is honored, which is performed by the frontend.

## FILES
/etc/openldap/slapd.conf

default slapd configuration file

/etc/passwd

user account information

## SEE ALSO
slapd.conf(5), slapd(8), passwd(5).


slapd-perl

title: slapd-perl(5)

summary: Perl backend to slapd

text:
# slapd-perl(5)

## NAME
slapd-perl - Perl backend to slapd

## SYNOPSIS
/etc/openldap/slapd.conf

## DESCRIPTION
The Perl backend to slapd(8) works by embedding a perl(1) interpreter into slapd(8). Any perl database section of the configuration file slapd.conf(5) must then specify what Perl module to use. Slapd then creates a new Perl object that handles all the requests for that particular instance of the backend.

You will need to create a method for each one of the following actions:

```
  * new        # creates a new object,

  * search     # performs the ldap search,

  * compare    # does a compare,

  * modify     # modifies an entry,

  * add        # adds an entry to backend,

  * modrdn     # modifies an entry's rdn,

  * delete     # deletes an ldap entry,

  * config     # module-specific config directives,

  * init       # called after backend is initialized.
```

Unless otherwise specified, the methods return the result code which will be returned to the client. Unimplemented actions can just return unwillingToPerform (53).

new

This method is called when the configuration file encounters a perlmod line. The module in that line is then effectively `use'd into the perl interpreter, then the new method is called to create a new object. Note that multiple instances of that object may be instantiated, as with any perl object. The new method receives the class name as argument.

search

This method is called when a search request comes from a client. It arguments are as follows:

```
  * object reference

  * base DN

  * scope

  * alias dereferencing policy

  * size limit

  * time limit

  * filter string

  * attributes only flag (1 for yes)

  * list of attributes to return (may be empty)
```

Return value: (resultcode, ldif-entry, ldif-entry, ...)

compare

This method is called when a compare request comes from a client. Its arguments are as follows.

```
  * object reference

  * dn

  * attribute assertion string
```

modify

This method is called when a modify request comes from a client. Its arguments are as follows.

```
  * object reference

  * dn

  * a list formatted as follows

    ({ "ADD" | "DELETE" | "REPLACE" },

     attributetype, value...)...
```

add

This method is called when a add request comes from a client. Its arguments are as follows.

```
  * object reference

  * entry in string format
```

modrdn

This method is called when a modrdn request comes from a client. Its arguments are as follows.

```
  * object reference

  * dn

  * new rdn

  * delete old dn flag (1 means yes)
```

delete

This method is called when a delete request comes from a client. Its arguments are as follows.

```
  * object reference

  * dn
```

config

This method is called once for each perlModuleConfig line in the slapd.conf(5) configuration file. Its arguments are as follows.

```
  * object reference

  * array of arguments on line
```

Return value: nonzero if this is not a valid option.

init

This method is called after backend is initialized. Its argument is as follows.

```
  * object reference
```

Return value: nonzero if initialization failed.

## CONFIGURATION
These slapd.conf options apply to the PERL backend database. That is, they must follow a "database perl" line and come before any subsequent "backend" or "database" lines. Other database options are described in the slapd.conf(5) manual page.

perlModulePath /path/to/libs

Add the path to the @INC variable.

perlModule ModName

`Use' the module name ModName from ModName.pm

filterSearchResults

Search results are candidates that need to be filtered (with the filter in the search request), rather than search results to be returned directly to the client.

perlModuleConfig <arguments>

Invoke the module's config method with the given arguments.

## EXAMPLE
There is an example Perl module `SampleLDAP' in the slapd/back-perl/ directory in the OpenLDAP source tree.

## ACCESS CONTROL
The perl backend does not honor any of the access control semantics described in slapd.access(5); all access control is delegated to the underlying PERL scripting. Only read (=r) access to the entry pseudo-attribute and to the other attribute values of the entries returned by the search operation is honored, which is performed by the frontend.

## WARNING
The interface of this backend to the perl module MAY change. Any suggestions would greatly be appreciated.

Note: in previous versions, any unrecognized lines in the slapd.conf file were passed to the perl module's config method. This behavior is deprecated (but still allowed for backward compatibility), and the perlModuleConfig directive should instead be used to invoke the module's config method. This compatibility feature will be removed at some future date.

## FILES
/etc/openldap/slapd.conf

default slapd configuration file

## SEE ALSO
slapd.conf(5), slapd(8), perl(1).


slapd-relay

title: slapd-relay(5)

summary: relay backend to slapd

text:
# slapd-relay(5)

## NAME
slapd-relay - relay backend to slapd

## SYNOPSIS
/etc/openldap/slapd.conf

## DESCRIPTION
The primary purpose of this slapd(8) backend is to map a naming context defined in a database running in the same slapd(8) instance into a virtual naming context, with attributeType and objectClass manipulation, if required. It requires the slapo-rwm(5) overlay.

This backend and the above mentioned overlay are experimental.

## CONFIGURATION
The following slapd.conf directives apply to the relay backend database. That is, they must follow a "database relay" line and come before any subsequent "backend" or "database" lines. Other database options are described in the slapd.conf(5) manual page; only the suffix directive is allowed by the relay backend.

relay <real naming context>

The naming context of the database that is presented under a virtual naming context. The presence of this directive implies that one specific database, i.e. the one serving the real naming context, will be presented under a virtual naming context.

## MASSAGING
The relay database does not automatically rewrite the naming context of requests and responses. For this purpose, the slapo-rwm(5) overlay must be explicitly instantiated, and configured as appropriate. Usually, the rwm-suffixmassage directive suffices if only naming context rewriting is required.

## ACCESS RULES
One important issue is that access rules are based on the identity that issued the operation. After massaging from the virtual to the real naming context, the frontend sees the operation as performed by the identity in the real naming context. Moreover, since back-relay bypasses the real database frontend operations by short-circuiting operations through the internal backend API, the original database access rules do not apply but in selected cases, i.e. when the backend itself applies access control. As a consequence, the instances of the relay database must provide own access rules that are consistent with those of the original database, possibly adding further specific restrictions. So, access rules in the relay database must refer to identities in the real naming context. Examples are reported in the EXAMPLES section.

## SCENARIOS
If no relay directive is given, the relay database does not refer to any specific database, but the most appropriate one is looked-up after rewriting the request DN for the operation that is being handled.

This allows one to write carefully crafted rewrite rules that cause some of the requests to be directed to one database, and some to another; e.g., authentication can be mapped to one database, and searches to another, or different target databases can be selected based on the DN of the request, and so.

Another possibility is to map the same operation to different databases based on details of the virtual naming context, e.g. groups on one database and persons on another.

## EXAMPLES
To implement a plain virtual naming context mapping that refers to a single database, use

```
  database                relay

  suffix                  "dc=virtual,dc=naming,dc=context"

  relay                   "dc=real,dc=naming,dc=context"

  overlay                 rwm

  rwm-suffixmassage       "dc=real,dc=naming,dc=context"
```

To implement a plain virtual naming context mapping that looks up the real naming context for each operation, use

```
  database                relay

  suffix                  "dc=virtual,dc=naming,dc=context"

  overlay                 rwm

  rwm-suffixmassage       "dc=real,dc=naming,dc=context"
```

This is useful, for instance, to relay different databases that share the terminal portion of the naming context (the one that is rewritten).

To implement the old-fashioned suffixalias, e.g. mapping the virtual to the real naming context, but not the results back from the real to the virtual naming context, use

```
  database                relay

  suffix                  "dc=virtual,dc=naming,dc=context"

  relay                   "dc=real,dc=naming,dc=context"

  overlay                 rwm

  rwm-rewriteEngine       on

  rwm-rewriteContext      default

  rwm-rewriteRule         "dc=virtual,dc=naming,dc=context"

                          "dc=real,dc=naming,dc=context" ":@"

  rwm-rewriteContext      searchFilter

  rwm-rewriteContext      searchEntryDN

  rwm-rewriteContext      searchAttrDN

  rwm-rewriteContext      matchedDN
```

Note that the slapo-rwm(5) overlay is instantiated, but the rewrite rules are written explicitly, rather than automatically as with the rwm-suffixmassage statement, to map all the virtual to real naming context data flow, but none of the real to virtual.

Access rules:

```
  database                bdb

  suffix                  "dc=example,dc=com"

  # skip...

  access to dn.subtree="dc=example,dc=com"

          by dn.exact="cn=Supervisor,dc=example,dc=com" write

          by * read

  database                relay

  suffix                  "o=Example,c=US"

  relay                   "dc=example,dc=com"

  overlay                 rwm

  rwm-suffixmassage       "dc=example,dc=com"

  # skip ...

  access to dn.subtree="o=Example,c=US"

          by dn.exact="cn=Supervisor,dc=example,dc=com" write

          by dn.exact="cn=Relay Supervisor,dc=example,dc=com" write

          by * read
```

Note that, in both databases, the identities (the <who> clause) are in the real naming context, i.e. `dc=example,dc=com', while the targets (the <what> clause) are in the real and in the virtual naming context, respectively.

## ACCESS CONTROL
The relay backend does not honor any of the access control semantics described in slapd.access(5); all access control is delegated to the relayed database(s). Only read (=r) access to the entry pseudo-attribute and to the other attribute values of the entries returned by the search operation is honored, which is performed by the frontend.

## FILES
/etc/openldap/slapd.conf

default slapd configuration file

## SEE ALSO
slapd.conf(5), slapd-config(5), slapo-rwm(5), slapd(8).


slapd-shell

title: slapd-shell(5)

summary: Shell backend to slapd

text:
# slapd-shell(5)

## NAME
slapd-shell - Shell backend to slapd

## SYNOPSIS
/etc/openldap/slapd.conf

## DESCRIPTION
The Shell backend to slapd(8) executes external programs to implement operations, and is designed to make it easy to tie an existing database to the slapd front-end.

This backend is primarily intended to be used in prototypes.

## WARNING
The abandon shell command has been removed since OpenLDAP 2.1.

## CONFIGURATION
These slapd.conf options apply to the SHELL backend database. That is, they must follow a "database shell" line and come before any subsequent "backend" or "database" lines. Other database options are described in the slapd.conf(5) manual page.

These options specify the pathname and arguments of the program to execute in response to the given LDAP operation. Each option is followed by the input lines that the program receives:

add <pathname> <argument>...

```
ADD
msgid: <message id>
<repeat { "suffix:" <database suffix DN> }>
<entry in LDIF format>
```

bind <pathname> <argument>...

```
BIND
msgid: <message id>
<repeat { "suffix:" <database suffix DN> }>
dn: <DN>
method: <method number>
credlen: <length of <credentials>>
cred: <credentials>
```

compare <pathname> <argument>...

```
COMPARE
msgid: <message id>
<repeat { "suffix:" <database suffix DN> }>
dn: <DN>
<attribute>: <value>
```

delete <pathname> <argument>...

```
DELETE
msgid: <message id>
<repeat { "suffix:" <database suffix DN> }>
dn: <DN>
```

modify <pathname> <argument>...

```
MODIFY
msgid: <message id>
<repeat { "suffix:" <database suffix DN> }>
dn: <DN>
<repeat {

    <"add"/"delete"/"replace">: <attribute>

    <repeat { <attribute>: <value> }>

    -
}>
```

modrdn <pathname> <argument>...

```
MODRDN
msgid: <message id>
<repeat { "suffix:" <database suffix DN> }>
dn: <DN>
newrdn: <new RDN>
deleteoldrdn: <0 or 1>
<if new superior is specified: "newSuperior: <DN>">
```

search <pathname> <argument>...

```
SEARCH
msgid: <message id>
<repeat { "suffix:" <database suffix DN> }>
base: <base DN>
scope: <0-2, see ldap.h>
deref: <0-3, see ldap.h>
sizelimit: <size limit>
timelimit: <time limit>
filter: <filter>
attrsonly: <0 or 1>
attrs: <"all" or space-separated attribute list>
```

unbind <pathname> <argument>...

```
UNBIND
msgid: <message id>
<repeat { "suffix:" <database suffix DN> }>
dn: <bound DN>
```

Note that you need only supply configuration lines for those commands you want the backend to handle. Operations for which a command is not supplied will be refused with an "unwilling to perform" error.

The search command should output the entries in LDIF format, each entry followed by a blank line, and after these the RESULT below.

All commands except unbind should then output:

```
RESULT
code: <integer>
matched: <matched DN>
info: <text>
```

where only the RESULT line is mandatory. Lines starting with `#' or `DEBUG:' are ignored.

## ACCESS CONTROL
The shell backend does not honor all ACL semantics as described in slapd.access(5). In general, access to objects is checked by using a dummy object that contains only the DN, so access rules that rely on the contents of the object are not honored. In detail:

The add operation does not require write (=w) access to the children pseudo-attribute of the parent entry.

The bind operation requires auth (=x) access to the entry pseudo-attribute of the entry whose identity is being assessed; auth (=x) access to the credentials is not checked, but rather delegated to the underlying shell script.

The compare operation requires read (=r) access (FIXME: wouldn't compare (=c) be a more appropriate choice?) to the entry pseudo-attribute of the object whose value is being asserted; compare (=c) access to the attribute whose value is being asserted is not checked.

The delete operation does not require write (=w) access to the children pseudo-attribute of the parent entry.

The modify operation requires write (=w) access to the entry pseudo-attribute; write (=w) access to the specific attributes that are modified is not checked.

The modrdn operation does not require write (=w) access to the children pseudo-attribute of the parent entry, nor to that of the new parent, if different; write (=w) access to the distinguished values of the naming attributes is not checked.

The search operation does not require search (=s) access to the entry pseudo_attribute of the searchBase; search (=s) access to the attributes and values used in the filter is not checked.

## EXAMPLE
There is an example search script in the slapd/back-shell/ directory in the OpenLDAP source tree.

## LIMITATIONS
The shell backend does not support threaded environments. When using the shell backend, slapd(8) should be built --without-threads.

## FILES
/etc/openldap/slapd.conf

default slapd configuration file

## SEE ALSO
slapd.conf(5), slapd(8), sh(1).


slapd-sock

title: slapd-sock(5)

summary: Socket backend/overlay to slapd

text:
# slapd-sock(5)

## NAME
slapd-sock - Socket backend/overlay to slapd

## SYNOPSIS
/etc/openldap/slapd.conf

## DESCRIPTION
The Socket backend to slapd(8) uses an external program to handle queries, similarly to slapd-shell(5). However, in this case the external program listens on a Unix domain socket. This makes it possible to have a pool of processes, which persist between requests. This allows multithreaded operation and a higher level of efficiency. The external program must have been started independently; slapd(8) itself will not start it.

This module may also be used as an overlay on top of some other database. Use as an overlay allows external actions to be triggered in response to operations on the main database.

## CONFIGURATION
These slapd.conf options apply to the SOCK backend database. That is, they must follow a "database sock" line and come before any subsequent "backend" or "database" lines. Other database options are described in the slapd.conf(5) manual page.

Alternatively, to use this module as an overlay, these directives must follow an "overlay sock" line within an existing database definition.

extensions [ binddn | peername | ssf | connid ]*

Enables the sending of additional meta-attributes with each request.

```
binddn: <bound DN>
peername: IP=<address>:<port>
ssf: <SSF value>
connid: <connection ID>
```

socketpath <pathname>

Gives the path to a Unix domain socket to which the commands will be sent and from which replies are received. When used as an overlay, these additional directives are defined:

sockops [ bind | unbind | search | compare | modify | modrdn | add | delete | extended ]*

Specify which request types to send to the external program. The default is empty (no requests are sent).

sockresps [ result | search ]*

Specify which response types to send to the external program. "result" sends just the results of an operation. "search" sends all entries that the database returned for a search request. The default is empty (no responses are sent).

sockdnpat <regexp>

Specify DN patterns for which the overlay will act. Only operations on DNs matching the specified regular expression will be processed. The default is empty (all DNs are processed).

## PROTOCOL
The protocol is essentially the same as slapd-shell(5) with the addition of a newline to terminate the command parameters. The following commands are sent:

```
ADD
msgid: <message id>
<repeat { "suffix:" <database suffix DN> }>
<entry in LDIF format>
<blank line>
```

```
BIND
msgid: <message id>
<repeat { "suffix:" <database suffix DN> }>
dn: <DN>
method: <method number>
credlen: <length of <credentials>>
cred: <credentials>
<blank line>
```

```
COMPARE
msgid: <message id>
<repeat { "suffix:" <database suffix DN> }>
dn: <DN>
<attribute>: <value>
<blank line>
```

```
DELETE
msgid: <message id>
<repeat { "suffix:" <database suffix DN> }>
dn: <DN>
<blank line>
```

```
EXTENDED
msgid: <message id>
<repeat { "suffix:" <database suffix DN> }>
oid: <OID>
value: <base64-value>
<blank line>
```

```
MODIFY
msgid: <message id>
<repeat { "suffix:" <database suffix DN> }>
dn: <DN>
<repeat {

    <"add"/"delete"/"replace">: <attribute>

    <repeat { <attribute>: <value> }>

    -
}>
<blank line>
```

```
MODRDN
msgid: <message id>
<repeat { "suffix:" <database suffix DN> }>
dn: <DN>
newrdn: <new RDN>
deleteoldrdn: <0 or 1>
<if new superior is specified: "newSuperior: <DN>">
<blank line>
```

```
SEARCH
msgid: <message id>
<repeat { "suffix:" <database suffix DN> }>
base: <base DN>
scope: <0-2, see ldap.h>
deref: <0-3, see ldap.h>
sizelimit: <size limit>
timelimit: <time limit>
filter: <filter>
attrsonly: <0 or 1>
attrs: <"all" or space-separated attribute list>
<blank line>
```

```
UNBIND
msgid: <message id>
<repeat { "suffix:" <database suffix DN> }>
<blank line>
```

The commands - except unbind - should output:

```
RESULT
code: <integer>
matched: <matched DN>
info: <text>
```

where only RESULT is mandatory, and then close the socket. The search RESULT should be preceded by the entries in LDIF format, each entry followed by a blank line. Lines starting with `#' or `DEBUG:' are ignored. When used as an overlay, the external program should return a CONTINUE response if request processing should continue normally, or a regular RESULT response if the external program wishes to bypass the underlying database.

If the overlay is configured to send response messages to the external program, they will appear as an extended RESULT message or as an ENTRY message, defined below. The RESULT message is similar to the one above, but also includes the msgid and any configured extensions:

```
RESULT
msgid: <message id>
code: <integer>
matched: <matched DN>
info: <text>
<blank line>
```

Typically both the msgid and the connid will be needed to match a result message to a request. The ENTRY message has the form

```
ENTRY
msgid: <message id>
<entry in LDIF format>
<blank line>
```

## KNOWN LIMITATIONS
The sock backend does not process extended operation results from an external program.

## ACCESS CONTROL
The sock backend does not honor all ACL semantics as described in slapd.access(5). In general, access to objects is checked by using a dummy object that contains only the DN, so access rules that rely on the contents of the object are not honored. In detail:

The add operation does not require write (=w) access to the children pseudo-attribute of the parent entry.

The bind operation requires auth (=x) access to the entry pseudo-attribute of the entry whose identity is being assessed; auth (=x) access to the credentials is not checked, but rather delegated to the underlying program.

The compare operation requires compare (=c) access to the entry pseudo-attribute of the object whose value is being asserted; compare (=c) access to the attribute whose value is being asserted is not checked.

The delete operation does not require write (=w) access to the children pseudo-attribute of the parent entry.

The modify operation requires write (=w) access to the entry pseudo-attribute; write (=w) access to the specific attributes that are modified is not checked.

The modrdn operation does not require write (=w) access to the children pseudo-attribute of the parent entry, nor to that of the new parent, if different; write (=w) access to the distinguished values of the naming attributes is not checked.

The search operation does not require search (=s) access to the entry pseudo_attribute of the searchBase; search (=s) access to the attributes and values used in the filter is not checked.

The extended operation does not require any access special rights. The external program has to implement any sort of access control.

## EXAMPLE
There is an example script in the slapd/back-sock/ directory in the OpenLDAP source tree.

## FILES
/etc/openldap/slapd.conf

default slapd configuration file

## SEE ALSO
slapd.conf(5), slapd-config(5), slapd(8).

## AUTHOR
Brian Candler, with enhancements by Howard Chu


slapd-sql

title: slapd-sql(5)

summary: SQL backend to slapd

text:
# slapd-sql(5)

## NAME
slapd-sql - SQL backend to slapd

## SYNOPSIS
/etc/openldap/slapd.conf

## DESCRIPTION
The primary purpose of this slapd(8) backend is to PRESENT information stored in some RDBMS as an LDAP subtree without any programming (some SQL and maybe stored procedures can't be considered programming, anyway ;).

That is, for example, when you (some ISP) have account information you use in an RDBMS, and want to use modern solutions that expect such information in LDAP (to authenticate users, make email lookups etc.). Or you want to synchronize or distribute information between different sites/applications that use RDBMSes and/or LDAP. Or whatever else...

It is NOT designed as a general-purpose backend that uses RDBMS instead of BerkeleyDB (as the standard BDB backend does), though it can be used as such with several limitations. You can take a look at http://www.openldap.org/faq/index.cgi?file=378 (OpenLDAP FAQ-O-Matic/General LDAP FAQ/Directories vs. conventional databases) to find out more on this point.

The idea (detailed below) is to use some meta-information to translate LDAP queries to SQL queries, leaving relational schema untouched, so that old applications can continue using it without any modifications. This allows SQL and LDAP applications to inter-operate without replication, and exchange data as needed.

The SQL backend is designed to be tunable to virtually any relational schema without having to change source (through that meta-information mentioned). Also, it uses ODBC to connect to RDBMSes, and is highly configurable for SQL dialects RDBMSes may use, so it may be used for integration and distribution of data on different RDBMSes, OSes, hosts etc., in other words, in highly heterogeneous environment.

This backend is experimental.

## CONFIGURATION
These slapd.conf options apply to the SQL backend database, which means that they must follow a "database sql" line and come before any subsequent "backend" or "database" lines. Other database options not specific to this backend are described in the slapd.conf(5) manual page.

## DATA SOURCE CONFIGURATION
dbname <datasource name>

The name of the ODBC datasource to use.

dbhost <hostname>

dbpasswd <password>

dbuser <username>

The three above options are generally unneeded, because this information is taken from the datasource specified by the dbname directive. They allow to override datasource settings. Also, several RDBMS' drivers tend to require explicit passing of user/password, even if those are given in datasource (Note: dbhost is currently ignored).

## SCOPING CONFIGURATION
These options specify SQL query templates for scoping searches.

subtree_cond <SQL expression>

Specifies a where-clause template used to form a subtree search condition (dn="(.+,)?<dn>$"). It may differ from one SQL dialect to another (see samples). By default, it is constructed based on the knowledge about how to normalize DN values (e.g. "<upper_func>(ldap_entries.dn) LIKE CONCAT('%',?)"); see upper_func, upper_needs_cast, concat_pattern and strcast_func in "HELPER CONFIGURATION" for details.

children_cond <SQL expression>

Specifies a where-clause template used to form a children search condition (dn=".+,<dn>$"). It may differ from one SQL dialect to another (see samples). By default, it is constructed based on the knowledge about how to normalize DN values (e.g. "<upper_func>(ldap_entries.dn) LIKE CONCAT('%,',?)"); see upper_func, upper_needs_cast, concat_pattern and strcast_func in "HELPER CONFIGURATION" for details.

use_subtree_shortcut { YES | no }

Do not use the subtree condition when the searchBase is the database suffix, and the scope is subtree; rather collect all entries.

## STATEMENT CONFIGURATION
These options specify SQL query templates for loading schema mapping meta-information, adding and deleting entries to ldap_entries, etc. All these and subtree_cond should have the given default values. For the current value it is recommended to look at the sources, or in the log output when slapd starts with "-d 5" or greater. Note that the parameter number and order must not be changed.

oc_query <SQL expression>

The query that is used to collect the objectClass mapping data from table ldap_oc_mappings; see "METAINFORMATION USED" for details. The default is "SELECT id, name, keytbl, keycol, create_proc, delete_proc, expect_return FROM ldap_oc_mappings".

at_query <SQL expression>

The query that is used to collect the attributeType mapping data from table ldap_attr_mappings; see "METAINFORMATION USED" for details. The default is "SELECT name, sel_expr, from_tbls, join_where, add_proc, delete_proc, param_order, expect_return FROM ldap_attr_mappings WHERE oc_map_id=?".

id_query <SQL expression>

The query that is used to map a DN to an entry in table ldap_entries; see "METAINFORMATION USED" for details. The default is "SELECT id,keyval,oc_map_id,dn FROM ldap_entries WHERE <DN match expr>", where <DN match expr> is constructed based on the knowledge about how to normalize DN values (e.g. "dn=?" if no means to uppercase strings are available; typically, "<upper_func>(dn)=?" is used); see upper_func, upper_needs_cast, concat_pattern and strcast_func in "HELPER CONFIGURATION" for details.

insentry_stmt <SQL expression>

The statement that is used to insert a new entry in table ldap_entries; see "METAINFORMATION USED" for details. The default is "INSERT INTO ldap_entries (dn, oc_map_id, parent, keyval) VALUES (?, ?, ?, ?)".

delentry_stmt <SQL expression>

The statement that is used to delete an existing entry from table ldap_entries; see "METAINFORMATION USED" for details. The default is "DELETE FROM ldap_entries WHERE id=?".

delobjclasses_stmt <SQL expression>

The statement that is used to delete an existing entry's ID from table ldap_objclasses; see "METAINFORMATION USED" for details. The default is "DELETE FROM ldap_entry_objclasses WHERE entry_id=?".

## HELPER CONFIGURATION
These statements are used to modify the default behavior of the backend according to issues of the dialect of the RDBMS. The first options essentially refer to string and DN normalization when building filters. LDAP normalization is more than upper- (or lower-)casing everything; however, as a reasonable trade-off, for case-sensitive RDBMSes the backend can be instructed to uppercase strings and DNs by providing the upper_func directive. Some RDBMSes, to use functions on arbitrary data types, e.g. string constants, requires a cast, which is triggered by the upper_needs_cast directive. If required, a string cast function can be provided as well, by using the strcast_func directive. Finally, a custom string concatenation pattern may be required; it is provided by the concat_pattern directive.

upper_func <SQL function name>

Specifies the name of a function that converts a given value to uppercase. This is used for case insensitive matching when the RDBMS is case sensitive. It may differ from one SQL dialect to another (e.g. UCASE, UPPER or whatever; see samples). By default, none is used, i.e. strings are not uppercased, so matches may be case sensitive.

upper_needs_cast { NO | yes }

Set this directive to yes if upper_func needs an explicit cast when applied to literal strings. A cast in the form CAST (<arg> AS VARCHAR(<max DN length>)) is used, where <max DN length> is builtin in back-sql; see macro BACKSQL_MAX_DN_LEN (currently 255; note that slapd's builtin limit, in macro SLAP_LDAPDN_MAXLEN, is set to 8192). This is experimental and may change in future releases.

strcast_func <SQL function name>

Specifies the name of a function that converts a given value to a string for appropriate ordering. This is used in "SELECT DISTINCT" statements for strongly typed RDBMSes with little implicit casting (like PostgreSQL), when a literal string is specified. This is experimental and may change in future releases.

concat_pattern <pattern>

This statement defines the pattern that is used to concatenate strings. The pattern MUST contain two question marks, '?', that will be replaced by the two strings that must be concatenated. The default value is CONCAT(?,?); a form that is known to be highly portable (IBM db2, PostgreSQL) is ?||?, but an explicit cast may be required when operating on literal strings: CAST(?||? AS VARCHAR(<length>)). On some RDBMSes (IBM db2, MSSQL) the form ?+? is known to work as well. Carefully check the documentation of your RDBMS or stay with the examples for supported ones. This is experimental and may change in future releases.

aliasing_keyword <string>

Define the aliasing keyword. Some RDBMSes use the word "AS" (the default), others don't use any.

aliasing_quote <string>

Define the quoting char of the aliasing keyword. Some RDBMSes don't require any (the default), others may require single or double quotes.

has_ldapinfo_dn_ru { NO | yes }

Explicitly inform the backend whether the dn_ru column (DN in reverse uppercased form) is present in table ldap_entries. Overrides automatic check (this is required, for instance, by PostgreSQL/unixODBC). This is experimental and may change in future releases.

fail_if_no_mapping { NO | yes }

When set to yes it forces attribute write operations to fail if no appropriate mapping between LDAP attributes and SQL data is available. The default behavior is to ignore those changes that cannot be mapped. It has no impact on objectClass mapping, i.e. if the structuralObjectClass of an entry cannot be mapped to SQL by looking up its name in ldap_oc_mappings, an add operation will fail regardless of the fail_if_no_mapping switch; see section "METAINFORMATION USED" for details. This is experimental and may change in future releases.

allow_orphans { NO | yes }

When set to yes orphaned entries (i.e. without the parent entry in the database) can be added. This option should be used with care, possibly in conjunction with some special rule on the RDBMS side that dynamically creates the missing parent.

baseObject [ <filename> ]

Instructs the database to create and manage an in-memory baseObject entry instead of looking for one in the RDBMS. If the (optional) <filename> argument is given, the entry is read from that file in LDIF(5) format; otherwise, an entry with objectClass extensibleObject is created based on the contents of the RDN of the baseObject. This is particularly useful when ldap_entries information is stored in a view rather than in a table, and union is not supported for views, so that the view can only specify one rule to compute the entry structure for one objectClass. This topic is discussed further in section "METAINFORMATION USED". This is experimental and may change in future releases.

create_needs_select { NO | yes }

Instructs the database whether or not entry creation in table ldap_entries needs a subsequent select to collect the automatically assigned ID, instead of being returned by a stored procedure.

fetch_attrs <attrlist>

fetch_all_attrs { NO | yes }

The first statement allows one to provide a list of attributes that must always be fetched in addition to those requested by any specific operation, because they are required for the proper usage of the backend. For instance, all attributes used in ACLs should be listed here. The second statement is a shortcut to require all attributes to be always loaded. Note that the dynamically generated attributes, e.g. hasSubordinates, entryDN and other implementation dependent attributes are NOT generated at this point, for consistency with the rest of slapd. This may change in the future.

check_schema { YES | no }

Instructs the database to check schema adherence of entries after modifications, and structural objectClass chain when entries are built. By default it is set to yes.

sqllayer <name> [...]

Loads the layer <name> onto a stack of helpers that are used to map DNs from LDAP to SQL representation and vice-versa. Subsequent args are passed to the layer configuration routine. This is highly experimental and should be used with extreme care. The API of the layers is not frozen yet, so it is unpublished.

autocommit { NO | yes }

Activates autocommit; by default, it is off.

## METAINFORMATION USED
Almost everything mentioned later is illustrated in examples located in the servers/slapd/back-sql/rdbms_depend/ directory in the OpenLDAP source tree, and contains scripts for generating sample database for Oracle, MS SQL Server, mySQL and more (including PostgreSQL and IBM db2).

The first thing that one must arrange is what set of LDAP object classes can present your RDBMS information.

The easiest way is to create an objectClass for each entity you had in ER-diagram when designing your relational schema. Any relational schema, no matter how normalized it is, was designed after some model of your application's domain (for instance, accounts, services etc. in ISP), and is used in terms of its entities, not just tables of normalized schema. It means that for every attribute of every such instance there is an effective SQL query that loads its values.

Also you might want your object classes to conform to some of the standard schemas like inetOrgPerson etc.

Nevertheless, when you think it out, we must define a way to translate LDAP operation requests to (a series of) SQL queries. Let us deal with the SEARCH operation.

Example: Let's suppose that we store information about persons working in our organization in two tables:

```
  PERSONS              PHONES

  ----------           -------------

  id integer           id integer

  first_name varchar   pers_id integer references persons(id)

  last_name varchar    phone

  middle_name varchar

  ...
```

(PHONES contains telephone numbers associated with persons). A person can have several numbers, then PHONES contains several records with corresponding pers_id, or no numbers (and no records in PHONES with such pers_id). An LDAP objectclass to present such information could look like this:

```
  person

  -------

  MUST cn

  MAY telephoneNumber $ firstName $ lastName

  ...
```

To fetch all values for cn attribute given person ID, we construct the query:

```
  SELECT CONCAT(persons.first_name,' ',persons.last_name)

      AS cn FROM persons WHERE persons.id=?
```

for telephoneNumber we can use:

```
  SELECT phones.phone AS telephoneNumber FROM persons,phones

      WHERE persons.id=phones.pers_id AND persons.id=?
```

If we wanted to service LDAP requests with filters like (telephoneNumber=123*), we would construct something like:

```
  SELECT ... FROM persons,phones

      WHERE persons.id=phones.pers_id

          AND persons.id=?

          AND phones.phone like '%1%2%3%'
```

(note how the telephoneNumber match is expanded in multiple wildcards to account for interspersed ininfluential chars like spaces, dashes and so; this occurs by design because telephoneNumber is defined after a specially recognized syntax). So, if we had information about what tables contain values for each attribute, how to join these tables and arrange these values, we could try to automatically generate such statements, and translate search filters to SQL WHERE clauses.

To store such information, we add three more tables to our schema and fill it with data (see samples):

```
  ldap_oc_mappings (some columns are not listed for clarity)

  ---------------

  id=1

  name="person"

  keytbl="persons"

  keycol="id"
```

This table defines a mapping between objectclass (its name held in the "name" column), and a table that holds the primary key for corresponding entities. For instance, in our example, the person entity, which we are trying to present as "person" objectclass, resides in two tables (persons and phones), and is identified by the persons.id column (that we will call the primary key for this entity). Keytbl and keycol thus contain "persons" (name of the table), and "id" (name of the column).

```
  ldap_attr_mappings (some columns are not listed for clarity)

  -----------

  id=1

  oc_map_id=1

  name="cn"

  sel_expr="CONCAT(persons.first_name,' ',persons.last_name)"

  from_tbls="persons"

  join_where=NULL

  ************

  id=<n>

  oc_map_id=1

  name="telephoneNumber"

  sel_expr="phones.phone"

  from_tbls="persons,phones"

  join_where="phones.pers_id=persons.id"
```

This table defines mappings between LDAP attributes and SQL queries that load their values. Note that, unlike LDAP schema, these are not attribute types - the attribute "cn" for "person" objectclass can have its values in different tables than "cn" for some other objectclass, so attribute mappings depend on objectclass mappings (unlike attribute types in LDAP schema, which are indifferent to objectclasses). Thus, we have oc_map_id column with link to oc_mappings table.

Now we cut the SQL query that loads values for a given attribute into 3 parts. First goes into sel_expr column - this is the expression we had between SELECT and FROM keywords, which defines WHAT to load. Next is table list - text between FROM and WHERE keywords. It may contain aliases for convenience (see examples). The last is part of the where clause, which (if it exists at all) expresses the condition for joining the table containing values with the table containing the primary key (foreign key equality and such). If values are in the same table as the primary key, then this column is left NULL (as for cn attribute above).

Having this information in parts, we are able to not only construct queries that load attribute values by id of entry (for this we could store SQL query as a whole), but to construct queries that load id's of objects that correspond to a given search filter (or at least part of it). See below for examples.

```
  ldap_entries

  ------------

  id=1

  dn=<dn you choose>

  oc_map_id=...

  parent=<parent record id>

  keyval=<value of primary key>
```

This table defines mappings between DNs of entries in your LDAP tree, and values of primary keys for corresponding relational data. It has recursive structure (parent column references id column of the same table), which allows you to add any tree structure(s) to your flat relational data. Having id of objectclass mapping, we can determine table and column for primary key, and keyval stores value of it, thus defining the exact tuple corresponding to the LDAP entry with this DN.

Note that such design (see exact SQL table creation query) implies one important constraint - the key must be an integer. But all that I know about well-designed schemas makes me think that it's not very narrow ;) If anyone needs support for different types for keys - he may want to write a patch, and submit it to OpenLDAP ITS, then I'll include it.

Also, several users complained that they don't really need very structured trees, and they don't want to update one more table every time they add or delete an instance in the relational schema. Those people can use a view instead of a real table for ldap_entries, something like this (by Robin Elfrink):

```
  CREATE VIEW ldap_entries (id, dn, oc_map_id, parent, keyval)

      AS

          SELECT 0, UPPER('o=MyCompany,c=NL'),

              3, 0, 'baseObject' FROM unixusers WHERE userid='root'

      UNION

          SELECT (1000000000+userid),

              UPPER(CONCAT(CONCAT('cn=',gecos),',o=MyCompany,c=NL')),

              1, 0, userid FROM unixusers

      UNION

          SELECT (2000000000+groupnummer),

              UPPER(CONCAT(CONCAT('cn=',groupnaam),',o=MyCompany,c=NL')),

              2, 0, groupnummer FROM groups;
```

If your RDBMS does not support unions in views, only one objectClass can be mapped in ldap_entries, and the baseObject cannot be created; in this case, see the baseObject directive for a possible workaround.

## TYPICAL SQL BACKEND OPERATION
Having meta-information loaded, the SQL backend uses these tables to determine a set of primary keys of candidates (depending on search scope and filter). It tries to do it for each objectclass registered in ldap_objclasses.

Example: for our query with filter (telephoneNumber=123*) we would get the following query generated (which loads candidate IDs)

```
  SELECT ldap_entries.id,persons.id, 'person' AS objectClass,

         ldap_entries.dn AS dn

    FROM ldap_entries,persons,phones

   WHERE persons.id=ldap_entries.keyval

     AND ldap_entries.objclass=?

     AND ldap_entries.parent=?

     AND phones.pers_id=persons.id

     AND (phones.phone LIKE '%1%2%3%')
```

(for ONELEVEL search) or "... AND dn=?" (for BASE search) or "... AND dn LIKE '%?'" (for SUBTREE)

Then, for each candidate, we load the requested attributes using per-attribute queries like

```
  SELECT phones.phone AS telephoneNumber

    FROM persons,phones

   WHERE persons.id=? AND phones.pers_id=persons.id
```

Then, we use test_filter() from the frontend API to test the entry for a full LDAP search filter match (since we cannot effectively make sense of SYNTAX of corresponding LDAP schema attribute, we translate the filter into the most relaxed SQL condition to filter candidates), and send it to the user.

ADD, DELETE, MODIFY and MODRDN operations are also performed on per-attribute meta-information (add_proc etc.). In those fields one can specify an SQL statement or stored procedure call which can add, or delete given values of a given attribute, using the given entry keyval (see examples -- mostly PostgreSQL, ORACLE and MSSQL - since as of this writing there are no stored procs in MySQL).

We just add more columns to ldap_oc_mappings and ldap_attr_mappings, holding statements to execute (like create_proc, add_proc, del_proc etc.), and flags governing the order of parameters passed to those statements. Please see samples to find out what are the parameters passed, and other information on this matter - they are self-explanatory for those familiar with the concepts expressed above.

## COMMON TECHNIQUES
First of all, let's recall that among other major differences to the complete LDAP data model, the above illustrated concept does not directly support such features as multiple objectclasses per entry, and referrals. Fortunately, they are easy to adopt in this scheme. The SQL backend requires that one more table is added to the schema: ldap_entry_objectclasses(entry_id,oc_name).

That table contains any number of objectclass names that corresponding entries will possess, in addition to that mentioned in mapping. The SQL backend automatically adds attribute mapping for the "objectclass" attribute to each objectclass mapping that loads values from this table. So, you may, for instance, have a mapping for inetOrgPerson, and use it for queries for "person" objectclass...

Referrals used to be implemented in a loose manner by adding an extra table that allowed any entry to host a "ref" attribute, along with a "referral" extra objectClass in table ldap_entry_objclasses. In the current implementation, referrals are treated like any other user-defined schema, since "referral" is a structural objectclass. The suggested practice is to define a "referral" entry in ldap_oc_mappings, holding a naming attribute, e.g. "ou" or "cn", a "ref" attribute, containing the url; in case multiple referrals per entry are needed, a separate table for urls can be created, where urls are mapped to the respective entries. The use of the naming attribute usually requires to add an "extensibleObject" value to ldap_entry_objclasses.

## CAVEATS
As previously stated, this backend should not be considered a replacement of other data storage backends, but rather a gateway to existing RDBMS storages that need to be published in LDAP form.

The hasSubordintes operational attribute is honored by back-sql in search results and in compare operations; it is partially honored also in filtering. Owing to design limitations, a (brain-dead?) filter of the form (!(hasSubordinates=TRUE)) will give no results instead of returning all the leaf entries, because it actually expands into ... AND NOT (1=1). If you need to find all the leaf entries, please use (hasSubordinates=FALSE) instead.

A directoryString value of the form "__First___Last_" (where underscores mean spaces, ASCII 0x20 char) corresponds to its prettified counterpart "First_Last"; this is not currently honored by back-sql if non-prettified data is written via RDBMS; when non-prettified data is written through back-sql, the prettified values are actually used instead.

## BUGS
When the ldap_entry_objclasses table is empty, filters on the objectClass attribute erroneously result in no candidates. A workaround consists in adding at least one row to that table, no matter if valid or not.

## PROXY CACHE OVERLAY
The proxy cache overlay allows caching of LDAP search requests (queries) in a local database. See slapo-pcache(5) for details.

## EXAMPLES
There are example SQL modules in the slapd/back-sql/rdbms_depend/ directory in the OpenLDAP source tree.

## ACCESS CONTROL
The sql backend honors access control semantics as indicated in slapd.access(5) (including the disclose access privilege when enabled at compile time).

## FILES
/etc/openldap/slapd.conf

default slapd configuration file

## SEE ALSO
slapd.conf(5), slapd(8).