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