1/*	$NetBSD: candidates.c,v 1.1.1.3 2010/12/12 15:23:09 adam Exp $	*/
2
3/* OpenLDAP: pkg/ldap/servers/slapd/back-meta/candidates.c,v 1.28.2.7 2010/04/13 20:23:30 kurt Exp */
4/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 *
6 * Copyright 1999-2010 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>
38 *
39 * When the meta-directory receives a request with a dn that belongs
40 * to a branch, the corresponding target is invoked. When the dn
41 * does not belong to a specific branch, all the targets that
42 * are compatible with the dn are selected as candidates, and
43 * the request is spawned to all the candidate targets
44 *
45 * A request is characterized by a dn. The following cases are handled:
46 * 	- the dn is the suffix: <dn> == <suffix>,
47 * 		all the targets are candidates (search ...)
48 * 	- the dn is a branch suffix: <dn> == <branch X>,<suffix>, or
49 * 	- the 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
57/*
58 * returns 1 if suffix is candidate for dn, otherwise 0
59 *
60 * Note: this function should never be called if dn is the <suffix>.
61 */
62int
63meta_back_is_candidate(
64	metatarget_t	*mt,
65	struct berval	*ndn,
66	int		scope )
67{
68	if ( dnIsSuffix( ndn, &mt->mt_nsuffix ) ) {
69		if ( mt->mt_subtree_exclude ) {
70			int	i;
71
72			for ( i = 0; !BER_BVISNULL( &mt->mt_subtree_exclude[ i ] ); i++ ) {
73				if ( dnIsSuffix( ndn, &mt->mt_subtree_exclude[ i ] ) ) {
74					return META_NOT_CANDIDATE;
75				}
76			}
77		}
78
79		switch ( mt->mt_scope ) {
80		case LDAP_SCOPE_SUBTREE:
81		default:
82			return META_CANDIDATE;
83
84		case LDAP_SCOPE_SUBORDINATE:
85			if ( ndn->bv_len > mt->mt_nsuffix.bv_len ) {
86				return META_CANDIDATE;
87			}
88			break;
89
90		/* nearly useless; not allowed by config */
91		case LDAP_SCOPE_ONELEVEL:
92			if ( ndn->bv_len > mt->mt_nsuffix.bv_len ) {
93				struct berval	rdn = *ndn;
94
95				rdn.bv_len -= mt->mt_nsuffix.bv_len
96					+ STRLENOF( "," );
97				if ( dnIsOneLevelRDN( &rdn ) ) {
98					return META_CANDIDATE;
99				}
100			}
101			break;
102
103		/* nearly useless; not allowed by config */
104		case LDAP_SCOPE_BASE:
105			if ( ndn->bv_len == mt->mt_nsuffix.bv_len ) {
106				return META_CANDIDATE;
107			}
108			break;
109		}
110
111		return META_NOT_CANDIDATE;
112	}
113
114	if ( scope == LDAP_SCOPE_SUBTREE && dnIsSuffix( &mt->mt_nsuffix, ndn ) ) {
115		/*
116		 * suffix longer than dn, but common part matches
117		 */
118		return META_CANDIDATE;
119	}
120
121	return META_NOT_CANDIDATE;
122}
123
124/*
125 * meta_back_select_unique_candidate
126 *
127 * returns the index of the candidate in case it is unique, otherwise
128 * META_TARGET_NONE if none matches, or
129 * META_TARGET_MULTIPLE if more than one matches
130 * Note: ndn MUST be normalized.
131 */
132int
133meta_back_select_unique_candidate(
134	metainfo_t	*mi,
135	struct berval	*ndn )
136{
137	int	i, candidate = META_TARGET_NONE;
138
139	for ( i = 0; i < mi->mi_ntargets; i++ ) {
140		metatarget_t	*mt = mi->mi_targets[ i ];
141
142		if ( meta_back_is_candidate( mt, ndn, LDAP_SCOPE_BASE ) ) {
143			if ( candidate == META_TARGET_NONE ) {
144				candidate = i;
145
146			} else {
147				return META_TARGET_MULTIPLE;
148			}
149		}
150	}
151
152	return candidate;
153}
154
155/*
156 * meta_clear_unused_candidates
157 *
158 * clears all candidates except candidate
159 */
160int
161meta_clear_unused_candidates(
162	Operation	*op,
163	int		candidate )
164{
165	metainfo_t	*mi = ( metainfo_t * )op->o_bd->be_private;
166	int		i;
167	SlapReply	*candidates = meta_back_candidates_get( op );
168
169	for ( i = 0; i < mi->mi_ntargets; ++i ) {
170		if ( i == candidate ) {
171			continue;
172		}
173		META_CANDIDATE_RESET( &candidates[ i ] );
174	}
175
176	return 0;
177}
178
179/*
180 * meta_clear_one_candidate
181 *
182 * clears the selected candidate
183 */
184int
185meta_clear_one_candidate(
186	Operation	*op,
187	metaconn_t	*mc,
188	int		candidate )
189{
190	metasingleconn_t	*msc = &mc->mc_conns[ candidate ];
191
192	if ( msc->msc_ld != NULL ) {
193
194#ifdef DEBUG_205
195		char	buf[ BUFSIZ ];
196
197		snprintf( buf, sizeof( buf ), "meta_clear_one_candidate ldap_unbind_ext[%d] mc=%p ld=%p",
198			candidate, (void *)mc, (void *)msc->msc_ld );
199		Debug( LDAP_DEBUG_ANY, "### %s %s\n",
200			op ? op->o_log_prefix : "", buf, 0 );
201#endif /* DEBUG_205 */
202
203		ldap_unbind_ext( msc->msc_ld, NULL, NULL );
204		msc->msc_ld = NULL;
205	}
206
207	if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) {
208		ber_memfree_x( msc->msc_bound_ndn.bv_val, NULL );
209		BER_BVZERO( &msc->msc_bound_ndn );
210	}
211
212	if ( !BER_BVISNULL( &msc->msc_cred ) ) {
213		memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len );
214		ber_memfree_x( msc->msc_cred.bv_val, NULL );
215		BER_BVZERO( &msc->msc_cred );
216	}
217
218	msc->msc_mscflags = 0;
219
220	return 0;
221}
222
223