]> git.sur5r.net Git - openldap/blob - servers/slapd/back-asyncmeta/candidates.c
Merge remote-tracking branch 'origin/mdb.RE/0.9'
[openldap] / servers / slapd / back-asyncmeta / candidates.c
1 /* candidates.c - candidate targets selection and processing for
2  * back-asyncmeta */
3 /* $OpenLDAP$ */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5  *
6  * Copyright 2016-2017 The OpenLDAP Foundation.
7  * Portions Copyright 2016 Symas Corporation.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted only as authorized by the OpenLDAP
12  * Public License.
13  *
14  * A copy of this license is available in the file LICENSE in the
15  * top-level directory of the distribution or, alternatively, at
16  * <http://www.OpenLDAP.org/license.html>.
17  */
18
19 /* ACKNOWLEDGEMENTS:
20 + * This work was developed by Symas Corporation
21 + * based on back-meta module for inclusion in OpenLDAP Software.
22 + * This work was sponsored by Ericsson. */
23
24 #include "portable.h"
25
26 #include <stdio.h>
27 #include "ac/string.h"
28
29 #include "slap.h"
30 #include "../back-ldap/back-ldap.h"
31 #include "back-asyncmeta.h"
32
33 /*
34  * The meta-directory has one suffix, called <suffix>.
35  * It handles a pool of target servers, each with a branch suffix
36  * of the form <branch X>,<suffix>, where <branch X> may be empty.
37  *
38  * When the meta-directory receives a request with a request DN that belongs
39  * to a branch, the corresponding target is invoked. When the request DN
40  * does not belong to a specific branch, all the targets that
41  * are compatible with the request DN are selected as candidates, and
42  * the request is spawned to all the candidate targets
43  *
44  * A request is characterized by a request DN. The following cases are
45  * handled:
46  *      - the request DN is the suffix: <dn> == <suffix>,
47  *              all the targets are candidates (search ...)
48  *      - the request DN is a branch suffix: <dn> == <branch X>,<suffix>, or
49  *      - the request DN is a subtree of a branch suffix:
50  *              <dn> == <rdn>,<branch X>,<suffix>,
51  *              the target is the only candidate.
52  *
53  * A possible extension will include the handling of multiple suffixes
54  */
55
56 static a_metasubtree_t *
57 asyncmeta_subtree_match( a_metatarget_t *mt, struct berval *ndn, int scope )
58 {
59         a_metasubtree_t *ms = mt->mt_subtree;
60
61         for ( ms = mt->mt_subtree; ms; ms = ms->ms_next ) {
62                 switch ( ms->ms_type ) {
63                 case META_ST_SUBTREE:
64                         if ( dnIsSuffix( ndn, &ms->ms_dn ) ) {
65                                 return ms;
66                         }
67                         break;
68
69                 case META_ST_SUBORDINATE:
70                         if ( dnIsSuffix( ndn, &ms->ms_dn ) &&
71                                 ( ndn->bv_len > ms->ms_dn.bv_len || scope != LDAP_SCOPE_BASE ) )
72                         {
73                                 return ms;
74                         }
75                         break;
76
77                 case META_ST_REGEX:
78                         /* NOTE: cannot handle scope */
79                         if ( regexec( &ms->ms_regex, ndn->bv_val, 0, NULL, 0 ) == 0 ) {
80                                 return ms;
81                         }
82                         break;
83                 }
84         }
85
86         return NULL;
87 }
88
89 /*
90  * returns 1 if suffix is candidate for dn, otherwise 0
91  *
92  * Note: this function should never be called if dn is the <suffix>.
93  */
94 int
95 asyncmeta_is_candidate(
96         a_metatarget_t  *mt,
97         struct berval   *ndn,
98         int             scope )
99 {
100         struct berval rdn;
101         int d = ndn->bv_len - mt->mt_nsuffix.bv_len;
102
103         if ( d >= 0 ) {
104                 if ( !dnIsSuffix( ndn, &mt->mt_nsuffix ) ) {
105                         return META_NOT_CANDIDATE;
106                 }
107
108                 /*
109                  * |  match  | exclude |
110                  * +---------+---------+-------------------+
111                  * |    T    |    T    | not candidate     |
112                  * |    F    |    T    | continue checking |
113                  * +---------+---------+-------------------+
114                  * |    T    |    F    | candidate         |
115                  * |    F    |    F    | not candidate     |
116                  * +---------+---------+-------------------+
117                  */
118
119                 if ( mt->mt_subtree ) {
120                         int match = ( asyncmeta_subtree_match( mt, ndn, scope ) != NULL );
121
122                         if ( !mt->mt_subtree_exclude ) {
123                                 return match ? META_CANDIDATE : META_NOT_CANDIDATE;
124                         }
125
126                         if ( match /* && mt->mt_subtree_exclude */ ) {
127                                 return META_NOT_CANDIDATE;
128                         }
129                 }
130
131                 switch ( mt->mt_scope ) {
132                 case LDAP_SCOPE_SUBTREE:
133                 default:
134                         return META_CANDIDATE;
135
136                 case LDAP_SCOPE_SUBORDINATE:
137                         if ( d > 0 ) {
138                                 return META_CANDIDATE;
139                         }
140                         break;
141
142                 /* nearly useless; not allowed by config */
143                 case LDAP_SCOPE_ONELEVEL:
144                         if ( d > 0 ) {
145                                 rdn.bv_val = ndn->bv_val;
146                                 rdn.bv_len = (ber_len_t)d - STRLENOF( "," );
147                                 if ( dnIsOneLevelRDN( &rdn ) ) {
148                                         return META_CANDIDATE;
149                                 }
150                         }
151                         break;
152
153                 /* nearly useless; not allowed by config */
154                 case LDAP_SCOPE_BASE:
155                         if ( d == 0 ) {
156                                 return META_CANDIDATE;
157                         }
158                         break;
159                 }
160
161         } else /* if ( d < 0 ) */ {
162                 if ( !dnIsSuffix( &mt->mt_nsuffix, ndn ) ) {
163                         return META_NOT_CANDIDATE;
164                 }
165
166                 switch ( scope ) {
167                 case LDAP_SCOPE_SUBTREE:
168                 case LDAP_SCOPE_SUBORDINATE:
169                         /*
170                          * suffix longer than dn, but common part matches
171                          */
172                         return META_CANDIDATE;
173
174                 case LDAP_SCOPE_ONELEVEL:
175                         rdn.bv_val = mt->mt_nsuffix.bv_val;
176                         rdn.bv_len = (ber_len_t)(-d) - STRLENOF( "," );
177                         if ( dnIsOneLevelRDN( &rdn ) ) {
178                                 return META_CANDIDATE;
179                         }
180                         break;
181                 }
182         }
183
184         return META_NOT_CANDIDATE;
185 }
186
187 /*
188  * meta_back_select_unique_candidate
189  *
190  * returns the index of the candidate in case it is unique, otherwise
191  * META_TARGET_NONE if none matches, or
192  * META_TARGET_MULTIPLE if more than one matches
193  * Note: ndn MUST be normalized.
194  */
195 int
196 asyncmeta_select_unique_candidate(
197         a_metainfo_t    *mi,
198         struct berval   *ndn )
199 {
200         int     i, candidate = META_TARGET_NONE;
201
202         for ( i = 0; i < mi->mi_ntargets; i++ ) {
203                 a_metatarget_t  *mt = mi->mi_targets[ i ];
204
205                 if ( asyncmeta_is_candidate( mt, ndn, LDAP_SCOPE_BASE ) ) {
206                         if ( candidate == META_TARGET_NONE ) {
207                                 candidate = i;
208
209                         } else {
210                                 return META_TARGET_MULTIPLE;
211                         }
212                 }
213         }
214
215         return candidate;
216 }
217
218 /*
219  * asyncmeta_clear_unused_candidates
220  *
221  * clears all candidates except candidate
222  */
223 int
224 asyncmeta_clear_unused_candidates(
225         Operation       *op,
226         int             candidate,
227         a_metaconn_t    *mc,
228         SlapReply       *candidates)
229 {
230         a_metainfo_t    *mi = mc->mc_info;
231         int             i;
232
233         for ( i = 0; i < mi->mi_ntargets; ++i ) {
234                 if ( i == candidate ) {
235                         continue;
236                 }
237                 META_CANDIDATE_RESET( &candidates[ i ] );
238         }
239
240         return 0;
241 }
242
243 int
244 asyncmeta_clear_one_msc(
245         Operation       *op,
246         a_metaconn_t    *mc,
247         int             candidate )
248 {
249         a_metasingleconn_t *msc;
250         if (mc == NULL) {
251                 return 0;
252         }
253         msc = &mc->mc_conns[candidate];
254         if (msc->conn) {
255                 connection_client_stop( msc->conn );
256                 msc->conn = NULL;
257         }
258         if ( msc->msc_ld != NULL ) {
259
260 #ifdef DEBUG_205
261                 char    buf[ BUFSIZ ];
262
263                 snprintf( buf, sizeof( buf ), "asyncmeta_clear_one_msc ldap_unbind_ext[%d] ld=%p",
264                         candidate, (void *)msc->msc_ld );
265                 Debug( LDAP_DEBUG_ANY, "### %s %s\n",
266                        op ? op->o_log_prefix : "", buf, 0 );
267 #endif /* DEBUG_205 */
268
269                 ldap_unbind_ext( msc->msc_ld, NULL, NULL );
270                 msc->msc_ld = NULL;
271                 ldap_ld_free( msc->msc_ldr, 0, NULL, NULL );
272                 msc->msc_ldr = NULL;
273         }
274
275         if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) {
276                 ber_memfree_x( msc->msc_bound_ndn.bv_val, NULL );
277                 BER_BVZERO( &msc->msc_bound_ndn );
278         }
279
280         if ( !BER_BVISNULL( &msc->msc_cred ) ) {
281                 memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len );
282                 ber_memfree_x( msc->msc_cred.bv_val, NULL );
283                 BER_BVZERO( &msc->msc_cred );
284         }
285         msc->msc_time = 0;
286         msc->msc_mscflags = 0;
287         msc->msc_timeout_ops = 0;
288         msc->msc_pending_ops = 0;
289         return 0;
290 }