Home | History | Annotate | Line # | Download | only in back-meta
candidates.c revision 1.3
      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