1/* $OpenLDAP$ */ 2/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 3 * 4 * Copyright 1999-2011 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 55static metasubtree_t * 56meta_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 */ 93int 94meta_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 */ 194int 195meta_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 */ 222int 223meta_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 */ 246int 247meta_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 285