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