Home | History | Annotate | Line # | Download | only in back-ldap
      1  1.3  christos /*	$NetBSD: distproc.c,v 1.4 2025/09/05 21:16:27 christos Exp $	*/
      2  1.2  christos 
      3  1.1     lukem /* distproc.c - implement distributed procedures */
      4  1.2  christos /* $OpenLDAP$ */
      5  1.1     lukem /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      6  1.1     lukem  *
      7  1.4  christos  * Copyright 2005-2024 The OpenLDAP Foundation.
      8  1.1     lukem  * Portions Copyright 2003 Howard Chu.
      9  1.1     lukem  * All rights reserved.
     10  1.1     lukem  *
     11  1.1     lukem  * Redistribution and use in source and binary forms, with or without
     12  1.1     lukem  * modification, are permitted only as authorized by the OpenLDAP
     13  1.1     lukem  * Public License.
     14  1.1     lukem  *
     15  1.1     lukem  * A copy of this license is available in the file LICENSE in the
     16  1.1     lukem  * top-level directory of the distribution or, alternatively, at
     17  1.1     lukem  * <http://www.OpenLDAP.org/license.html>.
     18  1.1     lukem  */
     19  1.1     lukem /* ACKNOWLEDGEMENTS:
     20  1.1     lukem  * This work was initially developed by Pierangelo Masarati for inclusion
     21  1.1     lukem  * in OpenLDAP Software.
     22  1.1     lukem  * Based on back-ldap and slapo-chain, developed by Howard Chu
     23  1.1     lukem  */
     24  1.1     lukem 
     25  1.2  christos #include <sys/cdefs.h>
     26  1.3  christos __RCSID("$NetBSD: distproc.c,v 1.4 2025/09/05 21:16:27 christos Exp $");
     27  1.2  christos 
     28  1.1     lukem #include "portable.h"
     29  1.1     lukem 
     30  1.1     lukem #include <stdio.h>
     31  1.1     lukem 
     32  1.1     lukem #include <ac/string.h>
     33  1.1     lukem #include <ac/socket.h>
     34  1.1     lukem 
     35  1.1     lukem #include "slap.h"
     36  1.1     lukem 
     37  1.1     lukem #ifdef SLAP_DISTPROC
     38  1.1     lukem 
     39  1.1     lukem #include "back-ldap.h"
     40  1.1     lukem 
     41  1.3  christos #include "slap-config.h"
     42  1.1     lukem 
     43  1.1     lukem /*
     44  1.1     lukem  * From <draft-sermersheim-ldap-distproc>
     45  1.1     lukem  *
     46  1.1     lukem 
     47  1.1     lukem       ContinuationReference ::= SET {
     48  1.1     lukem          referralURI      [0] SET SIZE (1..MAX) OF URI,
     49  1.1     lukem          localReference   [2] LDAPDN,
     50  1.1     lukem          referenceType    [3] ReferenceType,
     51  1.1     lukem          remainingName    [4] RelativeLDAPDN OPTIONAL,
     52  1.1     lukem          searchScope      [5] SearchScope OPTIONAL,
     53  1.1     lukem          searchedSubtrees [6] SearchedSubtrees OPTIONAL,
     54  1.1     lukem          failedName       [7] LDAPDN OPTIONAL,
     55  1.1     lukem          ...  }
     56  1.1     lukem 
     57  1.1     lukem       ReferenceType ::= ENUMERATED {
     58  1.1     lukem          superior               (0),
     59  1.1     lukem          subordinate            (1),
     60  1.1     lukem          cross                  (2),
     61  1.1     lukem          nonSpecificSubordinate (3),
     62  1.1     lukem          supplier               (4),
     63  1.1     lukem          master                 (5),
     64  1.1     lukem          immediateSuperior      (6),
     65  1.1     lukem          self                   (7),
     66  1.1     lukem          ...  }
     67  1.1     lukem 
     68  1.1     lukem       SearchScope ::= ENUMERATED {
     69  1.1     lukem          baseObject         (0),
     70  1.1     lukem          singleLevel        (1),
     71  1.1     lukem          wholeSubtree       (2),
     72  1.1     lukem          subordinateSubtree (3),
     73  1.1     lukem          ...  }
     74  1.1     lukem 
     75  1.1     lukem    SearchedSubtrees ::= SET OF RelativeLDAPDN
     76  1.1     lukem 
     77  1.1     lukem    LDAPDN, RelativeLDAPDN, and LDAPString, are defined in [RFC2251].
     78  1.1     lukem 
     79  1.1     lukem  */
     80  1.1     lukem 
     81  1.1     lukem typedef enum ReferenceType_t {
     82  1.1     lukem 	LDAP_DP_RT_UNKNOWN			= -1,
     83  1.1     lukem 	LDAP_DP_RT_SUPERIOR			= 0,
     84  1.1     lukem 	LDAP_DP_RT_SUBORDINATE			= 1,
     85  1.1     lukem 	LDAP_DP_RT_CROSS			= 2,
     86  1.1     lukem 	LDAP_DP_RT_NONSPECIFICSUBORDINATE	= 3,
     87  1.1     lukem 	LDAP_DP_RT_SUPPLIER			= 4,
     88  1.1     lukem 	LDAP_DP_RT_MASTER			= 5,
     89  1.1     lukem 	LDAP_DP_RT_IMMEDIATESUPERIOR		= 6,
     90  1.1     lukem 	LDAP_DP_RT_SELF				= 7,
     91  1.1     lukem 	LDAP_DP_RT_LAST
     92  1.1     lukem } ReferenceType_t;
     93  1.1     lukem 
     94  1.1     lukem typedef enum SearchScope_t {
     95  1.1     lukem 	LDAP_DP_SS_UNKNOWN			= -1,
     96  1.1     lukem 	LDAP_DP_SS_BASEOBJECT			= 0,
     97  1.1     lukem 	LDAP_DP_SS_SINGLELEVEL			= 1,
     98  1.1     lukem 	LDAP_DP_SS_WHOLESUBTREE			= 2,
     99  1.1     lukem 	LDAP_DP_SS_SUBORDINATESUBTREE		= 3,
    100  1.1     lukem 	LDAP_DP_SS_LAST
    101  1.1     lukem } SearchScope_t;
    102  1.1     lukem 
    103  1.1     lukem typedef struct ContinuationReference_t {
    104  1.1     lukem 	BerVarray		cr_referralURI;
    105  1.1     lukem 	/* ?			[1] ? */
    106  1.1     lukem 	struct berval		cr_localReference;
    107  1.1     lukem 	ReferenceType_t		cr_referenceType;
    108  1.1     lukem 	struct berval		cr_remainingName;
    109  1.1     lukem 	SearchScope_t		cr_searchScope;
    110  1.1     lukem 	BerVarray		cr_searchedSubtrees;
    111  1.1     lukem 	struct berval		cr_failedName;
    112  1.1     lukem } ContinuationReference_t;
    113  1.1     lukem #define	CR_INIT		{ NULL, BER_BVNULL, LDAP_DP_RT_UNKNOWN, BER_BVNULL, LDAP_DP_SS_UNKNOWN, NULL, BER_BVNULL }
    114  1.1     lukem 
    115  1.2  christos #ifdef unused
    116  1.1     lukem static struct berval	bv2rt[] = {
    117  1.1     lukem 	BER_BVC( "superior" ),
    118  1.1     lukem 	BER_BVC( "subordinate" ),
    119  1.1     lukem 	BER_BVC( "cross" ),
    120  1.1     lukem 	BER_BVC( "nonSpecificSubordinate" ),
    121  1.1     lukem 	BER_BVC( "supplier" ),
    122  1.1     lukem 	BER_BVC( "master" ),
    123  1.1     lukem 	BER_BVC( "immediateSuperior" ),
    124  1.1     lukem 	BER_BVC( "self" ),
    125  1.1     lukem 	BER_BVNULL
    126  1.1     lukem };
    127  1.1     lukem 
    128  1.1     lukem static struct berval	bv2ss[] = {
    129  1.1     lukem 	BER_BVC( "baseObject" ),
    130  1.1     lukem 	BER_BVC( "singleLevel" ),
    131  1.1     lukem 	BER_BVC( "wholeSubtree" ),
    132  1.1     lukem 	BER_BVC( "subordinateSubtree" ),
    133  1.1     lukem 	BER_BVNULL
    134  1.1     lukem };
    135  1.1     lukem 
    136  1.1     lukem static struct berval *
    137  1.1     lukem ldap_distproc_rt2bv( ReferenceType_t rt )
    138  1.1     lukem {
    139  1.1     lukem 	return &bv2rt[ rt ];
    140  1.1     lukem }
    141  1.1     lukem 
    142  1.1     lukem static const char *
    143  1.1     lukem ldap_distproc_rt2str( ReferenceType_t rt )
    144  1.1     lukem {
    145  1.1     lukem 	return bv2rt[ rt ].bv_val;
    146  1.1     lukem }
    147  1.1     lukem 
    148  1.1     lukem static ReferenceType_t
    149  1.1     lukem ldap_distproc_bv2rt( struct berval *bv )
    150  1.1     lukem {
    151  1.1     lukem 	ReferenceType_t		rt;
    152  1.1     lukem 
    153  1.1     lukem 	for ( rt = 0; !BER_BVISNULL( &bv2rt[ rt ] ); rt++ ) {
    154  1.1     lukem 		if ( ber_bvstrcasecmp( bv, &bv2rt[ rt ] ) == 0 ) {
    155  1.1     lukem 			return rt;
    156  1.1     lukem 		}
    157  1.1     lukem 	}
    158  1.1     lukem 
    159  1.1     lukem 	return LDAP_DP_RT_UNKNOWN;
    160  1.1     lukem }
    161  1.1     lukem 
    162  1.1     lukem static ReferenceType_t
    163  1.1     lukem ldap_distproc_str2rt( const char *s )
    164  1.1     lukem {
    165  1.1     lukem 	struct berval	bv;
    166  1.1     lukem 
    167  1.1     lukem 	ber_str2bv( s, 0, 0, &bv );
    168  1.1     lukem 	return ldap_distproc_bv2rt( &bv );
    169  1.1     lukem }
    170  1.1     lukem 
    171  1.1     lukem static struct berval *
    172  1.1     lukem ldap_distproc_ss2bv( SearchScope_t ss )
    173  1.1     lukem {
    174  1.1     lukem 	return &bv2ss[ ss ];
    175  1.1     lukem }
    176  1.1     lukem 
    177  1.1     lukem static const char *
    178  1.1     lukem ldap_distproc_ss2str( SearchScope_t ss )
    179  1.1     lukem {
    180  1.1     lukem 	return bv2ss[ ss ].bv_val;
    181  1.1     lukem }
    182  1.1     lukem 
    183  1.1     lukem static SearchScope_t
    184  1.1     lukem ldap_distproc_bv2ss( struct berval *bv )
    185  1.1     lukem {
    186  1.1     lukem 	ReferenceType_t		ss;
    187  1.1     lukem 
    188  1.1     lukem 	for ( ss = 0; !BER_BVISNULL( &bv2ss[ ss ] ); ss++ ) {
    189  1.1     lukem 		if ( ber_bvstrcasecmp( bv, &bv2ss[ ss ] ) == 0 ) {
    190  1.1     lukem 			return ss;
    191  1.1     lukem 		}
    192  1.1     lukem 	}
    193  1.1     lukem 
    194  1.1     lukem 	return LDAP_DP_SS_UNKNOWN;
    195  1.1     lukem }
    196  1.1     lukem 
    197  1.1     lukem static SearchScope_t
    198  1.1     lukem ldap_distproc_str2ss( const char *s )
    199  1.1     lukem {
    200  1.1     lukem 	struct berval	bv;
    201  1.1     lukem 
    202  1.1     lukem 	ber_str2bv( s, 0, 0, &bv );
    203  1.1     lukem 	return ldap_distproc_bv2ss( &bv );
    204  1.1     lukem }
    205  1.2  christos #endif /* unused */
    206  1.1     lukem 
    207  1.1     lukem /*
    208  1.1     lukem  * NOTE: this overlay assumes that the chainingBehavior control
    209  1.1     lukem  * is registered by the chain overlay; it may move here some time.
    210  1.1     lukem  * This overlay provides support for that control as well.
    211  1.1     lukem  */
    212  1.1     lukem 
    213  1.1     lukem 
    214  1.1     lukem static int		sc_returnContRef;
    215  1.1     lukem #define o_returnContRef			o_ctrlflag[sc_returnContRef]
    216  1.1     lukem #define get_returnContRef(op)		((op)->o_returnContRef & SLAP_CONTROL_MASK)
    217  1.1     lukem 
    218  1.1     lukem static struct berval	slap_EXOP_CHAINEDREQUEST = BER_BVC( LDAP_EXOP_X_CHAINEDREQUEST );
    219  1.1     lukem static struct berval	slap_FEATURE_CANCHAINOPS = BER_BVC( LDAP_FEATURE_X_CANCHAINOPS );
    220  1.1     lukem 
    221  1.1     lukem static BackendInfo	*lback;
    222  1.1     lukem 
    223  1.1     lukem typedef struct ldap_distproc_t {
    224  1.1     lukem 	/* "common" configuration info (anything occurring before an "uri") */
    225  1.1     lukem 	ldapinfo_t		*lc_common_li;
    226  1.1     lukem 
    227  1.1     lukem 	/* current configuration info */
    228  1.1     lukem 	ldapinfo_t		*lc_cfg_li;
    229  1.1     lukem 
    230  1.1     lukem 	/* tree of configured[/generated?] "uri" info */
    231  1.1     lukem 	ldap_avl_info_t		lc_lai;
    232  1.1     lukem 
    233  1.1     lukem 	unsigned		lc_flags;
    234  1.1     lukem #define LDAP_DISTPROC_F_NONE		(0x00U)
    235  1.1     lukem #define	LDAP_DISTPROC_F_CHAINING	(0x01U)
    236  1.1     lukem #define	LDAP_DISTPROC_F_CACHE_URI	(0x10U)
    237  1.1     lukem 
    238  1.1     lukem #define	LDAP_DISTPROC_CHAINING( lc )	( ( (lc)->lc_flags & LDAP_DISTPROC_F_CHAINING ) == LDAP_DISTPROC_F_CHAINING )
    239  1.1     lukem #define	LDAP_DISTPROC_CACHE_URI( lc )	( ( (lc)->lc_flags & LDAP_DISTPROC_F_CACHE_URI ) == LDAP_DISTPROC_F_CACHE_URI )
    240  1.1     lukem 
    241  1.1     lukem } ldap_distproc_t;
    242  1.1     lukem 
    243  1.1     lukem static int ldap_distproc_db_init_common( BackendDB	*be );
    244  1.1     lukem static int ldap_distproc_db_init_one( BackendDB *be );
    245  1.1     lukem #define	ldap_distproc_db_open_one(be)		(lback)->bi_db_open( (be) )
    246  1.1     lukem #define	ldap_distproc_db_close_one(be)		(0)
    247  1.1     lukem #define	ldap_distproc_db_destroy_one(be, ca)	(lback)->bi_db_destroy( (be), (ca) )
    248  1.1     lukem 
    249  1.1     lukem static int
    250  1.1     lukem ldap_distproc_uri_cmp( const void *c1, const void *c2 )
    251  1.1     lukem {
    252  1.1     lukem 	const ldapinfo_t	*li1 = (const ldapinfo_t *)c1;
    253  1.1     lukem 	const ldapinfo_t	*li2 = (const ldapinfo_t *)c2;
    254  1.1     lukem 
    255  1.1     lukem 	assert( li1->li_bvuri != NULL );
    256  1.1     lukem 	assert( !BER_BVISNULL( &li1->li_bvuri[ 0 ] ) );
    257  1.1     lukem 	assert( BER_BVISNULL( &li1->li_bvuri[ 1 ] ) );
    258  1.1     lukem 
    259  1.1     lukem 	assert( li2->li_bvuri != NULL );
    260  1.1     lukem 	assert( !BER_BVISNULL( &li2->li_bvuri[ 0 ] ) );
    261  1.1     lukem 	assert( BER_BVISNULL( &li2->li_bvuri[ 1 ] ) );
    262  1.1     lukem 
    263  1.1     lukem 	/* If local DNs don't match, it is definitely not a match */
    264  1.1     lukem 	return ber_bvcmp( &li1->li_bvuri[ 0 ], &li2->li_bvuri[ 0 ] );
    265  1.1     lukem }
    266  1.1     lukem 
    267  1.1     lukem static int
    268  1.1     lukem ldap_distproc_uri_dup( void *c1, void *c2 )
    269  1.1     lukem {
    270  1.1     lukem 	ldapinfo_t	*li1 = (ldapinfo_t *)c1;
    271  1.1     lukem 	ldapinfo_t	*li2 = (ldapinfo_t *)c2;
    272  1.1     lukem 
    273  1.1     lukem 	assert( li1->li_bvuri != NULL );
    274  1.1     lukem 	assert( !BER_BVISNULL( &li1->li_bvuri[ 0 ] ) );
    275  1.1     lukem 	assert( BER_BVISNULL( &li1->li_bvuri[ 1 ] ) );
    276  1.1     lukem 
    277  1.1     lukem 	assert( li2->li_bvuri != NULL );
    278  1.1     lukem 	assert( !BER_BVISNULL( &li2->li_bvuri[ 0 ] ) );
    279  1.1     lukem 	assert( BER_BVISNULL( &li2->li_bvuri[ 1 ] ) );
    280  1.1     lukem 
    281  1.1     lukem 	/* Cannot have more than one shared session with same DN */
    282  1.1     lukem 	if ( ber_bvcmp( &li1->li_bvuri[ 0 ], &li2->li_bvuri[ 0 ] ) == 0 ) {
    283  1.1     lukem 		return -1;
    284  1.1     lukem 	}
    285  1.1     lukem 
    286  1.1     lukem 	return 0;
    287  1.1     lukem }
    288  1.1     lukem 
    289  1.1     lukem static int
    290  1.1     lukem ldap_distproc_operational( Operation *op, SlapReply *rs )
    291  1.1     lukem {
    292  1.1     lukem 	/* Trap entries generated by back-ldap.
    293  1.1     lukem 	 *
    294  1.1     lukem 	 * FIXME: we need a better way to recognize them; a cleaner
    295  1.1     lukem 	 * solution would be to be able to intercept the response
    296  1.1     lukem 	 * of be_operational(), so that we can divert only those
    297  1.1     lukem 	 * calls that fail because operational attributes were
    298  1.1     lukem 	 * requested for entries that do not belong to the underlying
    299  1.1     lukem 	 * database.  This fix is likely to intercept also entries
    300  1.1     lukem 	 * generated by back-perl and so. */
    301  1.1     lukem 	if ( rs->sr_entry->e_private == NULL ) {
    302  1.1     lukem 		return LDAP_SUCCESS;
    303  1.1     lukem 	}
    304  1.1     lukem 
    305  1.1     lukem 	return SLAP_CB_CONTINUE;
    306  1.1     lukem }
    307  1.1     lukem 
    308  1.1     lukem static int
    309  1.1     lukem ldap_distproc_response( Operation *op, SlapReply *rs )
    310  1.1     lukem {
    311  1.1     lukem 	return SLAP_CB_CONTINUE;
    312  1.1     lukem }
    313  1.1     lukem 
    314  1.1     lukem /*
    315  1.1     lukem  * configuration...
    316  1.1     lukem  */
    317  1.1     lukem 
    318  1.1     lukem enum {
    319  1.1     lukem 	/* NOTE: the chaining behavior control is registered
    320  1.1     lukem 	 * by the chain overlay; it may move here some time */
    321  1.1     lukem 	DP_CHAINING = 1,
    322  1.1     lukem 	DP_CACHE_URI,
    323  1.1     lukem 
    324  1.1     lukem 	DP_LAST
    325  1.1     lukem };
    326  1.1     lukem 
    327  1.1     lukem static ConfigDriver distproc_cfgen;
    328  1.1     lukem static ConfigCfAdd distproc_cfadd;
    329  1.1     lukem static ConfigLDAPadd distproc_ldadd;
    330  1.1     lukem 
    331  1.1     lukem static ConfigTable distproc_cfg[] = {
    332  1.1     lukem 	{ "distproc-chaining", "args",
    333  1.1     lukem 		2, 4, 0, ARG_MAGIC|ARG_BERVAL|DP_CHAINING, distproc_cfgen,
    334  1.1     lukem 		/* NOTE: using the same attributeTypes defined
    335  1.1     lukem 		 * for the "chain" overlay */
    336  1.1     lukem 		"( OLcfgOvAt:3.1 NAME 'olcChainingBehavior' "
    337  1.1     lukem 			"DESC 'Chaining behavior control parameters (draft-sermersheim-ldap-chaining)' "
    338  1.1     lukem 			"SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
    339  1.1     lukem 	{ "distproc-cache-uri", "TRUE/FALSE",
    340  1.1     lukem 		2, 2, 0, ARG_MAGIC|ARG_ON_OFF|DP_CACHE_URI, distproc_cfgen,
    341  1.1     lukem 		"( OLcfgOvAt:3.2 NAME 'olcChainCacheURI' "
    342  1.1     lukem 			"DESC 'Enables caching of URIs not present in configuration' "
    343  1.1     lukem 			"SYNTAX OMsBoolean "
    344  1.1     lukem 			"SINGLE-VALUE )", NULL, NULL },
    345  1.1     lukem 	{ NULL, NULL, 0, 0, 0, ARG_IGNORED }
    346  1.1     lukem };
    347  1.1     lukem 
    348  1.1     lukem static ConfigOCs distproc_ocs[] = {
    349  1.1     lukem 	{ "( OLcfgOvOc:7.1 "
    350  1.1     lukem 		"NAME 'olcDistProcConfig' "
    351  1.1     lukem 		"DESC 'Distributed procedures <draft-sermersheim-ldap-distproc> configuration' "
    352  1.1     lukem 		"SUP olcOverlayConfig "
    353  1.1     lukem 		"MAY ( "
    354  1.1     lukem 			"olcChainingBehavior $ "
    355  1.1     lukem 			"olcChainCacheURI "
    356  1.1     lukem 			") )",
    357  1.1     lukem 		Cft_Overlay, distproc_cfg, NULL, distproc_cfadd },
    358  1.1     lukem 	{ "( OLcfgOvOc:7.2 "
    359  1.1     lukem 		"NAME 'olcDistProcDatabase' "
    360  1.1     lukem 		"DESC 'Distributed procedure remote server configuration' "
    361  1.1     lukem 		"AUXILIARY )",
    362  1.1     lukem 		Cft_Misc, distproc_cfg, distproc_ldadd },
    363  1.1     lukem 	{ NULL, 0, NULL }
    364  1.1     lukem };
    365  1.1     lukem 
    366  1.1     lukem static int
    367  1.1     lukem distproc_ldadd( CfEntryInfo *p, Entry *e, ConfigArgs *ca )
    368  1.1     lukem {
    369  1.1     lukem 	slap_overinst		*on;
    370  1.1     lukem 	ldap_distproc_t		*lc;
    371  1.1     lukem 
    372  1.1     lukem 	ldapinfo_t		*li;
    373  1.1     lukem 
    374  1.1     lukem 	AttributeDescription	*ad = NULL;
    375  1.1     lukem 	Attribute		*at;
    376  1.1     lukem 	const char		*text;
    377  1.1     lukem 
    378  1.1     lukem 	int			rc;
    379  1.1     lukem 
    380  1.1     lukem 	if ( p->ce_type != Cft_Overlay
    381  1.1     lukem 		|| !p->ce_bi
    382  1.1     lukem 		|| p->ce_bi->bi_cf_ocs != distproc_ocs )
    383  1.1     lukem 	{
    384  1.1     lukem 		return LDAP_CONSTRAINT_VIOLATION;
    385  1.1     lukem 	}
    386  1.1     lukem 
    387  1.1     lukem 	on = (slap_overinst *)p->ce_bi;
    388  1.1     lukem 	lc = (ldap_distproc_t *)on->on_bi.bi_private;
    389  1.1     lukem 
    390  1.1     lukem 	assert( ca->be == NULL );
    391  1.1     lukem 	ca->be = (BackendDB *)ch_calloc( 1, sizeof( BackendDB ) );
    392  1.1     lukem 
    393  1.1     lukem 	ca->be->bd_info = (BackendInfo *)on;
    394  1.1     lukem 
    395  1.1     lukem 	rc = slap_str2ad( "olcDbURI", &ad, &text );
    396  1.1     lukem 	assert( rc == LDAP_SUCCESS );
    397  1.1     lukem 
    398  1.1     lukem 	at = attr_find( e->e_attrs, ad );
    399  1.1     lukem 	if ( lc->lc_common_li == NULL && at != NULL ) {
    400  1.1     lukem 		/* FIXME: we should generate an empty default entry
    401  1.1     lukem 		 * if none is supplied */
    402  1.1     lukem 		Debug( LDAP_DEBUG_ANY, "slapd-distproc: "
    403  1.1     lukem 			"first underlying database \"%s\" "
    404  1.1     lukem 			"cannot contain attribute \"%s\".\n",
    405  1.3  christos 			e->e_name.bv_val, ad->ad_cname.bv_val );
    406  1.1     lukem 		rc = LDAP_CONSTRAINT_VIOLATION;
    407  1.1     lukem 		goto done;
    408  1.1     lukem 
    409  1.1     lukem 	} else if ( lc->lc_common_li != NULL && at == NULL ) {
    410  1.1     lukem 		/* FIXME: we should generate an empty default entry
    411  1.1     lukem 		 * if none is supplied */
    412  1.1     lukem 		Debug( LDAP_DEBUG_ANY, "slapd-distproc: "
    413  1.1     lukem 			"subsequent underlying database \"%s\" "
    414  1.1     lukem 			"must contain attribute \"%s\".\n",
    415  1.3  christos 			e->e_name.bv_val, ad->ad_cname.bv_val );
    416  1.1     lukem 		rc = LDAP_CONSTRAINT_VIOLATION;
    417  1.1     lukem 		goto done;
    418  1.1     lukem 	}
    419  1.1     lukem 
    420  1.1     lukem 	if ( lc->lc_common_li == NULL ) {
    421  1.1     lukem 		rc = ldap_distproc_db_init_common( ca->be );
    422  1.1     lukem 
    423  1.1     lukem 	} else {
    424  1.1     lukem 		rc = ldap_distproc_db_init_one( ca->be );
    425  1.1     lukem 	}
    426  1.1     lukem 
    427  1.1     lukem 	if ( rc != 0 ) {
    428  1.1     lukem 		Debug( LDAP_DEBUG_ANY, "slapd-distproc: "
    429  1.1     lukem 			"unable to init %sunderlying database \"%s\".\n",
    430  1.3  christos 			lc->lc_common_li == NULL ? "common " : "", e->e_name.bv_val );
    431  1.2  christos 		rc = LDAP_CONSTRAINT_VIOLATION;
    432  1.2  christos 		goto done;
    433  1.1     lukem 	}
    434  1.1     lukem 
    435  1.1     lukem 	li = ca->be->be_private;
    436  1.1     lukem 
    437  1.1     lukem 	if ( lc->lc_common_li == NULL ) {
    438  1.1     lukem 		lc->lc_common_li = li;
    439  1.1     lukem 
    440  1.3  christos 	} else if ( ldap_tavl_insert( &lc->lc_lai.lai_tree, (caddr_t)li,
    441  1.1     lukem 		ldap_distproc_uri_cmp, ldap_distproc_uri_dup ) )
    442  1.1     lukem 	{
    443  1.1     lukem 		Debug( LDAP_DEBUG_ANY, "slapd-distproc: "
    444  1.1     lukem 			"database \"%s\" insert failed.\n",
    445  1.3  christos 			e->e_name.bv_val );
    446  1.1     lukem 		rc = LDAP_CONSTRAINT_VIOLATION;
    447  1.1     lukem 		goto done;
    448  1.1     lukem 	}
    449  1.1     lukem 
    450  1.1     lukem done:;
    451  1.1     lukem 	if ( rc != LDAP_SUCCESS ) {
    452  1.1     lukem 		(void)ldap_distproc_db_destroy_one( ca->be, NULL );
    453  1.1     lukem 		ch_free( ca->be );
    454  1.1     lukem 		ca->be = NULL;
    455  1.1     lukem 	}
    456  1.1     lukem 
    457  1.1     lukem 	return rc;
    458  1.1     lukem }
    459  1.1     lukem 
    460  1.1     lukem typedef struct ldap_distproc_cfadd_apply_t {
    461  1.1     lukem 	Operation	*op;
    462  1.1     lukem 	SlapReply	*rs;
    463  1.1     lukem 	Entry		*p;
    464  1.1     lukem 	ConfigArgs	*ca;
    465  1.1     lukem 	int		count;
    466  1.1     lukem } ldap_distproc_cfadd_apply_t;
    467  1.1     lukem 
    468  1.3  christos static void
    469  1.3  christos ldap_distproc_cfadd_apply(
    470  1.3  christos 	ldapinfo_t *li,
    471  1.3  christos 	Operation *op,
    472  1.3  christos 	SlapReply *rs,
    473  1.3  christos 	Entry *p,
    474  1.3  christos 	ConfigArgs *ca,
    475  1.3  christos 	int count )
    476  1.1     lukem {
    477  1.1     lukem 	struct berval			bv;
    478  1.1     lukem 
    479  1.1     lukem 	/* FIXME: should not hardcode "olcDatabase" here */
    480  1.3  christos 	bv.bv_len = snprintf( ca->cr_msg, sizeof( ca->cr_msg ),
    481  1.3  christos 		"olcDatabase={%d}%s", count, lback->bi_type );
    482  1.3  christos 	bv.bv_val = ca->cr_msg;
    483  1.1     lukem 
    484  1.3  christos 	ca->be->be_private = (void *)li;
    485  1.3  christos 	config_build_entry( op, rs, p->e_private, ca,
    486  1.1     lukem 		&bv, lback->bi_cf_ocs, &distproc_ocs[ 1 ] );
    487  1.1     lukem 
    488  1.3  christos 	return;
    489  1.1     lukem }
    490  1.1     lukem 
    491  1.1     lukem static int
    492  1.1     lukem distproc_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *ca )
    493  1.1     lukem {
    494  1.1     lukem 	CfEntryInfo	*pe = p->e_private;
    495  1.1     lukem 	slap_overinst	*on = (slap_overinst *)pe->ce_bi;
    496  1.1     lukem 	ldap_distproc_t	*lc = (ldap_distproc_t *)on->on_bi.bi_private;
    497  1.1     lukem 	void		*priv = (void *)ca->be->be_private;
    498  1.3  christos 	TAvlnode	*edge;
    499  1.3  christos 	int		count = 0;
    500  1.1     lukem 
    501  1.1     lukem 	if ( lback->bi_cf_ocs ) {
    502  1.1     lukem 		ldap_distproc_cfadd_apply_t	lca = { 0 };
    503  1.1     lukem 
    504  1.1     lukem 		lca.op = op;
    505  1.1     lukem 		lca.rs = rs;
    506  1.1     lukem 		lca.p = p;
    507  1.1     lukem 		lca.ca = ca;
    508  1.1     lukem 		lca.count = 0;
    509  1.1     lukem 
    510  1.3  christos 		ldap_distproc_cfadd_apply( lc->lc_common_li, op, rs, p, ca, count++ );
    511  1.1     lukem 
    512  1.3  christos 		edge = ldap_tavl_end( lc->lc_lai.lai_tree, TAVL_DIR_LEFT );
    513  1.3  christos 		while ( edge ) {
    514  1.3  christos 			TAvlnode *next = ldap_tavl_next( edge, TAVL_DIR_RIGHT );
    515  1.3  christos 			ldapinfo_t *li = (ldapinfo_t *)edge->avl_data;
    516  1.3  christos 			ldap_distproc_cfadd_apply( li, op, rs, p, ca, count++ );
    517  1.3  christos 			edge = next;
    518  1.3  christos 		}
    519  1.1     lukem 
    520  1.1     lukem 		ca->be->be_private = priv;
    521  1.1     lukem 	}
    522  1.1     lukem 
    523  1.1     lukem 	return 0;
    524  1.1     lukem }
    525  1.1     lukem 
    526  1.1     lukem static int
    527  1.1     lukem distproc_cfgen( ConfigArgs *c )
    528  1.1     lukem {
    529  1.1     lukem 	slap_overinst	*on = (slap_overinst *)c->bi;
    530  1.1     lukem 	ldap_distproc_t	*lc = (ldap_distproc_t *)on->on_bi.bi_private;
    531  1.1     lukem 
    532  1.1     lukem 	int		rc = 0;
    533  1.1     lukem 
    534  1.1     lukem 	if ( c->op == SLAP_CONFIG_EMIT ) {
    535  1.1     lukem 		switch( c->type ) {
    536  1.1     lukem 		case DP_CACHE_URI:
    537  1.1     lukem 			c->value_int = LDAP_DISTPROC_CACHE_URI( lc );
    538  1.1     lukem 			break;
    539  1.1     lukem 
    540  1.1     lukem 		default:
    541  1.1     lukem 			assert( 0 );
    542  1.1     lukem 			rc = 1;
    543  1.1     lukem 		}
    544  1.1     lukem 		return rc;
    545  1.1     lukem 
    546  1.1     lukem 	} else if ( c->op == LDAP_MOD_DELETE ) {
    547  1.1     lukem 		switch( c->type ) {
    548  1.1     lukem 		case DP_CHAINING:
    549  1.1     lukem 			return 1;
    550  1.1     lukem 
    551  1.1     lukem 		case DP_CACHE_URI:
    552  1.1     lukem 			lc->lc_flags &= ~LDAP_DISTPROC_F_CACHE_URI;
    553  1.1     lukem 			break;
    554  1.1     lukem 
    555  1.1     lukem 		default:
    556  1.1     lukem 			return 1;
    557  1.1     lukem 		}
    558  1.1     lukem 		return rc;
    559  1.1     lukem 	}
    560  1.1     lukem 
    561  1.1     lukem 	switch( c->type ) {
    562  1.1     lukem 	case DP_CACHE_URI:
    563  1.1     lukem 		if ( c->value_int ) {
    564  1.1     lukem 			lc->lc_flags |= LDAP_DISTPROC_F_CACHE_URI;
    565  1.1     lukem 		} else {
    566  1.1     lukem 			lc->lc_flags &= ~LDAP_DISTPROC_F_CACHE_URI;
    567  1.1     lukem 		}
    568  1.1     lukem 		break;
    569  1.1     lukem 
    570  1.1     lukem 	default:
    571  1.1     lukem 		assert( 0 );
    572  1.1     lukem 		return 1;
    573  1.1     lukem 	}
    574  1.1     lukem 
    575  1.1     lukem 	return rc;
    576  1.1     lukem }
    577  1.1     lukem 
    578  1.1     lukem static int
    579  1.1     lukem ldap_distproc_db_init(
    580  1.1     lukem 	BackendDB *be,
    581  1.1     lukem 	ConfigReply *cr )
    582  1.1     lukem {
    583  1.1     lukem 	slap_overinst	*on = (slap_overinst *)be->bd_info;
    584  1.1     lukem 	ldap_distproc_t	*lc = NULL;
    585  1.1     lukem 
    586  1.1     lukem 	if ( lback == NULL ) {
    587  1.1     lukem 		lback = backend_info( "ldap" );
    588  1.1     lukem 
    589  1.1     lukem 		if ( lback == NULL ) {
    590  1.1     lukem 			return 1;
    591  1.1     lukem 		}
    592  1.1     lukem 	}
    593  1.1     lukem 
    594  1.1     lukem 	lc = ch_malloc( sizeof( ldap_distproc_t ) );
    595  1.1     lukem 	if ( lc == NULL ) {
    596  1.1     lukem 		return 1;
    597  1.1     lukem 	}
    598  1.1     lukem 	memset( lc, 0, sizeof( ldap_distproc_t ) );
    599  1.1     lukem 	ldap_pvt_thread_mutex_init( &lc->lc_lai.lai_mutex );
    600  1.1     lukem 
    601  1.1     lukem 	on->on_bi.bi_private = (void *)lc;
    602  1.1     lukem 
    603  1.1     lukem 	return 0;
    604  1.1     lukem }
    605  1.1     lukem 
    606  1.1     lukem static int
    607  1.1     lukem ldap_distproc_db_config(
    608  1.1     lukem 	BackendDB	*be,
    609  1.1     lukem 	const char	*fname,
    610  1.1     lukem 	int		lineno,
    611  1.1     lukem 	int		argc,
    612  1.1     lukem 	char		**argv )
    613  1.1     lukem {
    614  1.1     lukem 	slap_overinst	*on = (slap_overinst *)be->bd_info;
    615  1.1     lukem 	ldap_distproc_t	*lc = (ldap_distproc_t *)on->on_bi.bi_private;
    616  1.1     lukem 
    617  1.1     lukem 	int		rc = SLAP_CONF_UNKNOWN;
    618  1.1     lukem 
    619  1.1     lukem 	if ( lc->lc_common_li == NULL ) {
    620  1.1     lukem 		void	*be_private = be->be_private;
    621  1.1     lukem 		ldap_distproc_db_init_common( be );
    622  1.1     lukem 		lc->lc_common_li = lc->lc_cfg_li = (ldapinfo_t *)be->be_private;
    623  1.1     lukem 		be->be_private = be_private;
    624  1.1     lukem 	}
    625  1.1     lukem 
    626  1.1     lukem 	/* Something for the distproc database? */
    627  1.1     lukem 	if ( strncasecmp( argv[ 0 ], "distproc-", STRLENOF( "distproc-" ) ) == 0 ) {
    628  1.1     lukem 		char		*save_argv0 = argv[ 0 ];
    629  1.1     lukem 		BackendInfo	*bd_info = be->bd_info;
    630  1.1     lukem 		void		*be_private = be->be_private;
    631  1.1     lukem 		ConfigOCs	*be_cf_ocs = be->be_cf_ocs;
    632  1.1     lukem 		int		is_uri = 0;
    633  1.1     lukem 
    634  1.1     lukem 		argv[ 0 ] += STRLENOF( "distproc-" );
    635  1.1     lukem 
    636  1.1     lukem 		if ( strcasecmp( argv[ 0 ], "uri" ) == 0 ) {
    637  1.1     lukem 			rc = ldap_distproc_db_init_one( be );
    638  1.1     lukem 			if ( rc != 0 ) {
    639  1.1     lukem 				Debug( LDAP_DEBUG_ANY, "%s: line %d: "
    640  1.1     lukem 					"underlying slapd-ldap initialization failed.\n.",
    641  1.3  christos 					fname, lineno );
    642  1.1     lukem 				return 1;
    643  1.1     lukem 			}
    644  1.1     lukem 			lc->lc_cfg_li = be->be_private;
    645  1.1     lukem 			is_uri = 1;
    646  1.1     lukem 		}
    647  1.1     lukem 
    648  1.1     lukem 		/* TODO: add checks on what other slapd-ldap(5) args
    649  1.1     lukem 		 * should be put in the template; this is not quite
    650  1.1     lukem 		 * harmful, because attributes that shouldn't don't
    651  1.1     lukem 		 * get actually used, but the user should at least
    652  1.1     lukem 		 * be warned.
    653  1.1     lukem 		 */
    654  1.1     lukem 
    655  1.1     lukem 		be->bd_info = lback;
    656  1.1     lukem 		be->be_private = (void *)lc->lc_cfg_li;
    657  1.1     lukem 		be->be_cf_ocs = lback->bi_cf_ocs;
    658  1.1     lukem 
    659  1.1     lukem 		rc = config_generic_wrapper( be, fname, lineno, argc, argv );
    660  1.1     lukem 
    661  1.1     lukem 		argv[ 0 ] = save_argv0;
    662  1.1     lukem 		be->be_cf_ocs = be_cf_ocs;
    663  1.1     lukem 		be->be_private = be_private;
    664  1.1     lukem 		be->bd_info = bd_info;
    665  1.1     lukem 
    666  1.1     lukem 		if ( is_uri ) {
    667  1.1     lukem private_destroy:;
    668  1.1     lukem 			if ( rc != 0 ) {
    669  1.1     lukem 				BackendDB		db = *be;
    670  1.1     lukem 
    671  1.1     lukem 				db.bd_info = lback;
    672  1.1     lukem 				db.be_private = (void *)lc->lc_cfg_li;
    673  1.1     lukem 				ldap_distproc_db_destroy_one( &db, NULL );
    674  1.1     lukem 				lc->lc_cfg_li = NULL;
    675  1.1     lukem 
    676  1.1     lukem 			} else {
    677  1.1     lukem 				if ( lc->lc_cfg_li->li_bvuri == NULL
    678  1.1     lukem 					|| BER_BVISNULL( &lc->lc_cfg_li->li_bvuri[ 0 ] )
    679  1.1     lukem 					|| !BER_BVISNULL( &lc->lc_cfg_li->li_bvuri[ 1 ] ) )
    680  1.1     lukem 				{
    681  1.1     lukem 					Debug( LDAP_DEBUG_ANY, "%s: line %d: "
    682  1.1     lukem 						"no URI list allowed in slapo-distproc.\n",
    683  1.3  christos 						fname, lineno );
    684  1.1     lukem 					rc = 1;
    685  1.1     lukem 					goto private_destroy;
    686  1.1     lukem 				}
    687  1.1     lukem 
    688  1.3  christos 				if ( ldap_tavl_insert( &lc->lc_lai.lai_tree,
    689  1.1     lukem 					(caddr_t)lc->lc_cfg_li,
    690  1.1     lukem 					ldap_distproc_uri_cmp, ldap_distproc_uri_dup ) )
    691  1.1     lukem 				{
    692  1.1     lukem 					Debug( LDAP_DEBUG_ANY, "%s: line %d: "
    693  1.1     lukem 						"duplicate URI in slapo-distproc.\n",
    694  1.3  christos 						fname, lineno );
    695  1.1     lukem 					rc = 1;
    696  1.1     lukem 					goto private_destroy;
    697  1.1     lukem 				}
    698  1.1     lukem 			}
    699  1.1     lukem 		}
    700  1.1     lukem 	}
    701  1.1     lukem 
    702  1.1     lukem 	return rc;
    703  1.1     lukem }
    704  1.1     lukem 
    705  1.1     lukem enum db_which {
    706  1.1     lukem 	db_open = 0,
    707  1.1     lukem 	db_close,
    708  1.1     lukem 	db_destroy,
    709  1.1     lukem 
    710  1.1     lukem 	db_last
    711  1.1     lukem };
    712  1.1     lukem 
    713  1.1     lukem static int
    714  1.1     lukem ldap_distproc_db_func(
    715  1.1     lukem 	BackendDB *be,
    716  1.1     lukem 	enum db_which which
    717  1.1     lukem )
    718  1.1     lukem {
    719  1.1     lukem 	slap_overinst	*on = (slap_overinst *)be->bd_info;
    720  1.1     lukem 	ldap_distproc_t	*lc = (ldap_distproc_t *)on->on_bi.bi_private;
    721  1.1     lukem 
    722  1.1     lukem 	int		rc = 0;
    723  1.1     lukem 
    724  1.1     lukem 	if ( lc ) {
    725  1.1     lukem 		BI_db_func	*func = (&lback->bi_db_open)[ which ];
    726  1.1     lukem 
    727  1.1     lukem 		if ( func != NULL && lc->lc_common_li != NULL ) {
    728  1.1     lukem 			BackendDB		db = *be;
    729  1.1     lukem 
    730  1.1     lukem 			db.bd_info = lback;
    731  1.1     lukem 			db.be_private = lc->lc_common_li;
    732  1.1     lukem 
    733  1.1     lukem 			rc = func( &db, NULL );
    734  1.1     lukem 
    735  1.1     lukem 			if ( rc != 0 ) {
    736  1.1     lukem 				return rc;
    737  1.1     lukem 			}
    738  1.1     lukem 
    739  1.1     lukem 			if ( lc->lc_lai.lai_tree != NULL ) {
    740  1.3  christos 				TAvlnode *edge = ldap_tavl_end( lc->lc_lai.lai_tree, TAVL_DIR_LEFT );
    741  1.3  christos 				while ( edge ) {
    742  1.3  christos 					TAvlnode *next = ldap_tavl_next( edge, TAVL_DIR_RIGHT );
    743  1.3  christos 					ldapinfo_t *li = (ldapinfo_t *)edge->avl_data;
    744  1.3  christos 					be->be_private = (void *)li;
    745  1.3  christos 					rc = func( &db, NULL );
    746  1.3  christos 					if ( rc == 1 ) {
    747  1.3  christos 						break;
    748  1.3  christos 					}
    749  1.3  christos 					edge = next;
    750  1.3  christos 				}
    751  1.1     lukem 			}
    752  1.1     lukem 		}
    753  1.1     lukem 	}
    754  1.1     lukem 
    755  1.1     lukem 	return rc;
    756  1.1     lukem }
    757  1.1     lukem 
    758  1.1     lukem static int
    759  1.1     lukem ldap_distproc_db_open(
    760  1.1     lukem 	BackendDB	*be,
    761  1.1     lukem 	ConfigReply	*cr )
    762  1.1     lukem {
    763  1.1     lukem 	return ldap_distproc_db_func( be, db_open );
    764  1.1     lukem }
    765  1.1     lukem 
    766  1.1     lukem static int
    767  1.1     lukem ldap_distproc_db_close(
    768  1.1     lukem 	BackendDB	*be,
    769  1.1     lukem 	ConfigReply	*cr )
    770  1.1     lukem {
    771  1.1     lukem 	return ldap_distproc_db_func( be, db_close );
    772  1.1     lukem }
    773  1.1     lukem 
    774  1.1     lukem static int
    775  1.1     lukem ldap_distproc_db_destroy(
    776  1.1     lukem 	BackendDB	*be,
    777  1.1     lukem 	ConfigReply	*cr )
    778  1.1     lukem {
    779  1.1     lukem 	slap_overinst	*on = (slap_overinst *) be->bd_info;
    780  1.1     lukem 	ldap_distproc_t	*lc = (ldap_distproc_t *)on->on_bi.bi_private;
    781  1.1     lukem 
    782  1.1     lukem 	int		rc;
    783  1.1     lukem 
    784  1.1     lukem 	rc = ldap_distproc_db_func( be, db_destroy );
    785  1.1     lukem 
    786  1.1     lukem 	if ( lc ) {
    787  1.3  christos 		ldap_tavl_free( lc->lc_lai.lai_tree, NULL );
    788  1.1     lukem 		ldap_pvt_thread_mutex_destroy( &lc->lc_lai.lai_mutex );
    789  1.1     lukem 		ch_free( lc );
    790  1.1     lukem 	}
    791  1.1     lukem 
    792  1.1     lukem 	return rc;
    793  1.1     lukem }
    794  1.1     lukem 
    795  1.1     lukem /*
    796  1.1     lukem  * inits one instance of the slapd-ldap backend, and stores
    797  1.1     lukem  * the private info in be_private of the arg
    798  1.1     lukem  */
    799  1.1     lukem static int
    800  1.1     lukem ldap_distproc_db_init_common(
    801  1.1     lukem 	BackendDB	*be )
    802  1.1     lukem {
    803  1.1     lukem 	BackendInfo	*bi = be->bd_info;
    804  1.1     lukem 	int		t;
    805  1.1     lukem 
    806  1.1     lukem 	be->bd_info = lback;
    807  1.1     lukem 	be->be_private = NULL;
    808  1.1     lukem 	t = lback->bi_db_init( be, NULL );
    809  1.1     lukem 	if ( t != 0 ) {
    810  1.1     lukem 		return t;
    811  1.1     lukem 	}
    812  1.1     lukem 	be->bd_info = bi;
    813  1.1     lukem 
    814  1.1     lukem 	return 0;
    815  1.1     lukem }
    816  1.1     lukem 
    817  1.1     lukem /*
    818  1.1     lukem  * inits one instance of the slapd-ldap backend, stores
    819  1.1     lukem  * the private info in be_private of the arg and fills
    820  1.1     lukem  * selected fields with data from the template.
    821  1.1     lukem  *
    822  1.1     lukem  * NOTE: add checks about the other fields of the template,
    823  1.1     lukem  * which are ignored and SHOULD NOT be configured by the user.
    824  1.1     lukem  */
    825  1.1     lukem static int
    826  1.1     lukem ldap_distproc_db_init_one(
    827  1.1     lukem 	BackendDB	*be )
    828  1.1     lukem {
    829  1.1     lukem 	slap_overinst	*on = (slap_overinst *)be->bd_info;
    830  1.1     lukem 	ldap_distproc_t	*lc = (ldap_distproc_t *)on->on_bi.bi_private;
    831  1.1     lukem 
    832  1.1     lukem 	BackendInfo	*bi = be->bd_info;
    833  1.1     lukem 	ldapinfo_t	*li;
    834  1.1     lukem 
    835  1.1     lukem 	slap_op_t	t;
    836  1.1     lukem 
    837  1.1     lukem 	be->bd_info = lback;
    838  1.1     lukem 	be->be_private = NULL;
    839  1.1     lukem 	t = lback->bi_db_init( be, NULL );
    840  1.1     lukem 	if ( t != 0 ) {
    841  1.1     lukem 		return t;
    842  1.1     lukem 	}
    843  1.1     lukem 	li = (ldapinfo_t *)be->be_private;
    844  1.1     lukem 
    845  1.1     lukem 	/* copy common data */
    846  1.1     lukem 	li->li_nretries = lc->lc_common_li->li_nretries;
    847  1.1     lukem 	li->li_flags = lc->lc_common_li->li_flags;
    848  1.1     lukem 	li->li_version = lc->lc_common_li->li_version;
    849  1.1     lukem 	for ( t = 0; t < SLAP_OP_LAST; t++ ) {
    850  1.1     lukem 		li->li_timeout[ t ] = lc->lc_common_li->li_timeout[ t ];
    851  1.1     lukem 	}
    852  1.1     lukem 	be->bd_info = bi;
    853  1.1     lukem 
    854  1.1     lukem 	return 0;
    855  1.1     lukem }
    856  1.1     lukem 
    857  1.1     lukem static int
    858  1.1     lukem ldap_distproc_connection_destroy(
    859  1.1     lukem 	BackendDB *be,
    860  1.1     lukem 	Connection *conn
    861  1.1     lukem )
    862  1.1     lukem {
    863  1.1     lukem 	slap_overinst		*on = (slap_overinst *) be->bd_info;
    864  1.1     lukem 	ldap_distproc_t		*lc = (ldap_distproc_t *)on->on_bi.bi_private;
    865  1.1     lukem 	void			*private = be->be_private;
    866  1.1     lukem 	int			rc;
    867  1.3  christos 	TAvlnode		*edge;
    868  1.1     lukem 
    869  1.1     lukem 	be->be_private = NULL;
    870  1.1     lukem 	ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
    871  1.3  christos 	edge = ldap_tavl_end( lc->lc_lai.lai_tree, TAVL_DIR_LEFT );
    872  1.3  christos 	while ( edge ) {
    873  1.3  christos 		TAvlnode *next = ldap_tavl_next( edge, TAVL_DIR_RIGHT );
    874  1.3  christos 		ldapinfo_t *li = (ldapinfo_t *)edge->avl_data;
    875  1.3  christos 		be->be_private = (void *)li;
    876  1.3  christos 		rc = lback->bi_connection_destroy( be, conn );
    877  1.3  christos 		if ( rc == 1 ) {
    878  1.3  christos 			break;
    879  1.3  christos 		}
    880  1.3  christos 		edge = next;
    881  1.3  christos 	}
    882  1.1     lukem 	ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
    883  1.1     lukem 	be->be_private = private;
    884  1.1     lukem 
    885  1.1     lukem 	return rc;
    886  1.1     lukem }
    887  1.1     lukem 
    888  1.1     lukem static int
    889  1.1     lukem ldap_distproc_parse_returnContRef_ctrl(
    890  1.1     lukem 	Operation	*op,
    891  1.1     lukem 	SlapReply	*rs,
    892  1.1     lukem 	LDAPControl	*ctrl )
    893  1.1     lukem {
    894  1.1     lukem 	if ( get_returnContRef( op ) != SLAP_CONTROL_NONE ) {
    895  1.1     lukem 		rs->sr_text = "returnContinuationReference control specified multiple times";
    896  1.1     lukem 		return LDAP_PROTOCOL_ERROR;
    897  1.1     lukem 	}
    898  1.1     lukem 
    899  1.1     lukem 	if ( op->o_pagedresults != SLAP_CONTROL_NONE ) {
    900  1.1     lukem 		rs->sr_text = "returnContinuationReference control specified with pagedResults control";
    901  1.1     lukem 		return LDAP_PROTOCOL_ERROR;
    902  1.1     lukem 	}
    903  1.1     lukem 
    904  1.1     lukem 	if ( !BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
    905  1.1     lukem 		rs->sr_text = "returnContinuationReference control: value must be NULL";
    906  1.1     lukem 		return LDAP_PROTOCOL_ERROR;
    907  1.1     lukem 	}
    908  1.1     lukem 
    909  1.1     lukem 	op->o_returnContRef = ctrl->ldctl_iscritical ? SLAP_CONTROL_CRITICAL : SLAP_CONTROL_NONCRITICAL;
    910  1.1     lukem 
    911  1.1     lukem 	return LDAP_SUCCESS;
    912  1.1     lukem }
    913  1.1     lukem 
    914  1.1     lukem static int
    915  1.1     lukem ldap_exop_chained_request(
    916  1.1     lukem 		Operation	*op,
    917  1.1     lukem 		SlapReply	*rs )
    918  1.1     lukem {
    919  1.3  christos 	Debug( LDAP_DEBUG_STATS, "%s CHAINED REQUEST\n",
    920  1.3  christos 	    op->o_log_prefix );
    921  1.1     lukem 
    922  1.1     lukem 	rs->sr_err = backend_check_restrictions( op, rs,
    923  1.1     lukem 			(struct berval *)&slap_EXOP_CHAINEDREQUEST );
    924  1.1     lukem 	if ( rs->sr_err != LDAP_SUCCESS ) {
    925  1.1     lukem 		return rs->sr_err;
    926  1.1     lukem 	}
    927  1.1     lukem 
    928  1.1     lukem 	/* by now, just reject requests */
    929  1.1     lukem 	rs->sr_text = "under development";
    930  1.1     lukem 	return LDAP_UNWILLING_TO_PERFORM;
    931  1.1     lukem }
    932  1.1     lukem 
    933  1.1     lukem 
    934  1.1     lukem static slap_overinst distproc;
    935  1.1     lukem 
    936  1.1     lukem int
    937  1.1     lukem distproc_initialize( void )
    938  1.1     lukem {
    939  1.1     lukem 	int	rc;
    940  1.1     lukem 
    941  1.1     lukem 	/* Make sure we don't exceed the bits reserved for userland */
    942  1.1     lukem 	config_check_userland( DP_LAST );
    943  1.1     lukem 
    944  1.1     lukem 	rc = load_extop( (struct berval *)&slap_EXOP_CHAINEDREQUEST,
    945  1.1     lukem 		SLAP_EXOP_HIDE, ldap_exop_chained_request );
    946  1.1     lukem 	if ( rc != LDAP_SUCCESS ) {
    947  1.1     lukem 		Debug( LDAP_DEBUG_ANY, "slapd-distproc: "
    948  1.1     lukem 			"unable to register chainedRequest exop: %d.\n",
    949  1.3  christos 			rc );
    950  1.1     lukem 		return rc;
    951  1.1     lukem 	}
    952  1.1     lukem 
    953  1.1     lukem 	rc = supported_feature_load( &slap_FEATURE_CANCHAINOPS );
    954  1.1     lukem 	if ( rc != LDAP_SUCCESS ) {
    955  1.1     lukem 		Debug( LDAP_DEBUG_ANY, "slapd-distproc: "
    956  1.1     lukem 			"unable to register canChainOperations supported feature: %d.\n",
    957  1.3  christos 			rc );
    958  1.1     lukem 		return rc;
    959  1.1     lukem 	}
    960  1.1     lukem 
    961  1.1     lukem 	rc = register_supported_control( LDAP_CONTROL_X_RETURNCONTREF,
    962  1.1     lukem 			SLAP_CTRL_GLOBAL|SLAP_CTRL_ACCESS|SLAP_CTRL_HIDE, NULL,
    963  1.1     lukem 			ldap_distproc_parse_returnContRef_ctrl, &sc_returnContRef );
    964  1.1     lukem 	if ( rc != LDAP_SUCCESS ) {
    965  1.1     lukem 		Debug( LDAP_DEBUG_ANY, "slapd-distproc: "
    966  1.1     lukem 			"unable to register returnContinuationReference control: %d.\n",
    967  1.3  christos 			rc );
    968  1.1     lukem 		return rc;
    969  1.1     lukem 	}
    970  1.1     lukem 
    971  1.1     lukem 	distproc.on_bi.bi_type = "distproc";
    972  1.1     lukem 	distproc.on_bi.bi_db_init = ldap_distproc_db_init;
    973  1.1     lukem 	distproc.on_bi.bi_db_config = ldap_distproc_db_config;
    974  1.1     lukem 	distproc.on_bi.bi_db_open = ldap_distproc_db_open;
    975  1.1     lukem 	distproc.on_bi.bi_db_close = ldap_distproc_db_close;
    976  1.1     lukem 	distproc.on_bi.bi_db_destroy = ldap_distproc_db_destroy;
    977  1.1     lukem 
    978  1.1     lukem 	/* ... otherwise the underlying backend's function would be called,
    979  1.1     lukem 	 * likely passing an invalid entry; on the contrary, the requested
    980  1.1     lukem 	 * operational attributes should have been returned while chasing
    981  1.1     lukem 	 * the referrals.  This all in all is a bit messy, because part
    982  1.1     lukem 	 * of the operational attributes are generated by the backend;
    983  1.1     lukem 	 * part by the frontend; back-ldap should receive all the available
    984  1.1     lukem 	 * ones from the remote server, but then, on its own, it strips those
    985  1.1     lukem 	 * it assumes will be (re)generated by the frontend (e.g.
    986  1.1     lukem 	 * subschemaSubentry, entryDN, ...) */
    987  1.1     lukem 	distproc.on_bi.bi_operational = ldap_distproc_operational;
    988  1.1     lukem 
    989  1.1     lukem 	distproc.on_bi.bi_connection_destroy = ldap_distproc_connection_destroy;
    990  1.1     lukem 
    991  1.1     lukem 	distproc.on_response = ldap_distproc_response;
    992  1.1     lukem 
    993  1.1     lukem 	distproc.on_bi.bi_cf_ocs = distproc_ocs;
    994  1.1     lukem 
    995  1.1     lukem 	rc = config_register_schema( distproc_cfg, distproc_ocs );
    996  1.1     lukem 	if ( rc ) {
    997  1.1     lukem 		return rc;
    998  1.1     lukem 	}
    999  1.1     lukem 
   1000  1.1     lukem 	return overlay_register( &distproc );
   1001  1.1     lukem }
   1002  1.1     lukem 
   1003  1.1     lukem #endif /* SLAP_DISTPROC */
   1004