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