Home | History | Annotate | Line # | Download | only in back-ldap
distproc.c revision 1.2
      1  1.2  christos /*	$NetBSD: distproc.c,v 1.2 2020/08/11 13:15:40 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.2  christos  * Copyright 2005-2020 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.2  christos __RCSID("$NetBSD: distproc.c,v 1.2 2020/08/11 13:15:40 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.1     lukem #include "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.2  christos #ifdef LDAP_DEVEL
    220  1.1     lukem static struct berval	slap_FEATURE_CANCHAINOPS = BER_BVC( LDAP_FEATURE_X_CANCHAINOPS );
    221  1.2  christos #endif
    222  1.2  christos 
    223  1.1     lukem 
    224  1.1     lukem static BackendInfo	*lback;
    225  1.1     lukem 
    226  1.1     lukem typedef struct ldap_distproc_t {
    227  1.1     lukem 	/* "common" configuration info (anything occurring before an "uri") */
    228  1.1     lukem 	ldapinfo_t		*lc_common_li;
    229  1.1     lukem 
    230  1.1     lukem 	/* current configuration info */
    231  1.1     lukem 	ldapinfo_t		*lc_cfg_li;
    232  1.1     lukem 
    233  1.1     lukem 	/* tree of configured[/generated?] "uri" info */
    234  1.1     lukem 	ldap_avl_info_t		lc_lai;
    235  1.1     lukem 
    236  1.1     lukem 	unsigned		lc_flags;
    237  1.1     lukem #define LDAP_DISTPROC_F_NONE		(0x00U)
    238  1.1     lukem #define	LDAP_DISTPROC_F_CHAINING	(0x01U)
    239  1.1     lukem #define	LDAP_DISTPROC_F_CACHE_URI	(0x10U)
    240  1.1     lukem 
    241  1.1     lukem #define	LDAP_DISTPROC_CHAINING( lc )	( ( (lc)->lc_flags & LDAP_DISTPROC_F_CHAINING ) == LDAP_DISTPROC_F_CHAINING )
    242  1.1     lukem #define	LDAP_DISTPROC_CACHE_URI( lc )	( ( (lc)->lc_flags & LDAP_DISTPROC_F_CACHE_URI ) == LDAP_DISTPROC_F_CACHE_URI )
    243  1.1     lukem 
    244  1.1     lukem } ldap_distproc_t;
    245  1.1     lukem 
    246  1.1     lukem static int ldap_distproc_db_init_common( BackendDB	*be );
    247  1.1     lukem static int ldap_distproc_db_init_one( BackendDB *be );
    248  1.1     lukem #define	ldap_distproc_db_open_one(be)		(lback)->bi_db_open( (be) )
    249  1.1     lukem #define	ldap_distproc_db_close_one(be)		(0)
    250  1.1     lukem #define	ldap_distproc_db_destroy_one(be, ca)	(lback)->bi_db_destroy( (be), (ca) )
    251  1.1     lukem 
    252  1.1     lukem static int
    253  1.1     lukem ldap_distproc_uri_cmp( const void *c1, const void *c2 )
    254  1.1     lukem {
    255  1.1     lukem 	const ldapinfo_t	*li1 = (const ldapinfo_t *)c1;
    256  1.1     lukem 	const ldapinfo_t	*li2 = (const ldapinfo_t *)c2;
    257  1.1     lukem 
    258  1.1     lukem 	assert( li1->li_bvuri != NULL );
    259  1.1     lukem 	assert( !BER_BVISNULL( &li1->li_bvuri[ 0 ] ) );
    260  1.1     lukem 	assert( BER_BVISNULL( &li1->li_bvuri[ 1 ] ) );
    261  1.1     lukem 
    262  1.1     lukem 	assert( li2->li_bvuri != NULL );
    263  1.1     lukem 	assert( !BER_BVISNULL( &li2->li_bvuri[ 0 ] ) );
    264  1.1     lukem 	assert( BER_BVISNULL( &li2->li_bvuri[ 1 ] ) );
    265  1.1     lukem 
    266  1.1     lukem 	/* If local DNs don't match, it is definitely not a match */
    267  1.1     lukem 	return ber_bvcmp( &li1->li_bvuri[ 0 ], &li2->li_bvuri[ 0 ] );
    268  1.1     lukem }
    269  1.1     lukem 
    270  1.1     lukem static int
    271  1.1     lukem ldap_distproc_uri_dup( void *c1, void *c2 )
    272  1.1     lukem {
    273  1.1     lukem 	ldapinfo_t	*li1 = (ldapinfo_t *)c1;
    274  1.1     lukem 	ldapinfo_t	*li2 = (ldapinfo_t *)c2;
    275  1.1     lukem 
    276  1.1     lukem 	assert( li1->li_bvuri != NULL );
    277  1.1     lukem 	assert( !BER_BVISNULL( &li1->li_bvuri[ 0 ] ) );
    278  1.1     lukem 	assert( BER_BVISNULL( &li1->li_bvuri[ 1 ] ) );
    279  1.1     lukem 
    280  1.1     lukem 	assert( li2->li_bvuri != NULL );
    281  1.1     lukem 	assert( !BER_BVISNULL( &li2->li_bvuri[ 0 ] ) );
    282  1.1     lukem 	assert( BER_BVISNULL( &li2->li_bvuri[ 1 ] ) );
    283  1.1     lukem 
    284  1.1     lukem 	/* Cannot have more than one shared session with same DN */
    285  1.1     lukem 	if ( ber_bvcmp( &li1->li_bvuri[ 0 ], &li2->li_bvuri[ 0 ] ) == 0 ) {
    286  1.1     lukem 		return -1;
    287  1.1     lukem 	}
    288  1.1     lukem 
    289  1.1     lukem 	return 0;
    290  1.1     lukem }
    291  1.1     lukem 
    292  1.1     lukem static int
    293  1.1     lukem ldap_distproc_operational( Operation *op, SlapReply *rs )
    294  1.1     lukem {
    295  1.1     lukem 	/* Trap entries generated by back-ldap.
    296  1.1     lukem 	 *
    297  1.1     lukem 	 * FIXME: we need a better way to recognize them; a cleaner
    298  1.1     lukem 	 * solution would be to be able to intercept the response
    299  1.1     lukem 	 * of be_operational(), so that we can divert only those
    300  1.1     lukem 	 * calls that fail because operational attributes were
    301  1.1     lukem 	 * requested for entries that do not belong to the underlying
    302  1.1     lukem 	 * database.  This fix is likely to intercept also entries
    303  1.1     lukem 	 * generated by back-perl and so. */
    304  1.1     lukem 	if ( rs->sr_entry->e_private == NULL ) {
    305  1.1     lukem 		return LDAP_SUCCESS;
    306  1.1     lukem 	}
    307  1.1     lukem 
    308  1.1     lukem 	return SLAP_CB_CONTINUE;
    309  1.1     lukem }
    310  1.1     lukem 
    311  1.1     lukem static int
    312  1.1     lukem ldap_distproc_response( Operation *op, SlapReply *rs )
    313  1.1     lukem {
    314  1.1     lukem 	return SLAP_CB_CONTINUE;
    315  1.1     lukem }
    316  1.1     lukem 
    317  1.1     lukem /*
    318  1.1     lukem  * configuration...
    319  1.1     lukem  */
    320  1.1     lukem 
    321  1.1     lukem enum {
    322  1.1     lukem 	/* NOTE: the chaining behavior control is registered
    323  1.1     lukem 	 * by the chain overlay; it may move here some time */
    324  1.1     lukem 	DP_CHAINING = 1,
    325  1.1     lukem 	DP_CACHE_URI,
    326  1.1     lukem 
    327  1.1     lukem 	DP_LAST
    328  1.1     lukem };
    329  1.1     lukem 
    330  1.1     lukem static ConfigDriver distproc_cfgen;
    331  1.1     lukem static ConfigCfAdd distproc_cfadd;
    332  1.1     lukem static ConfigLDAPadd distproc_ldadd;
    333  1.1     lukem 
    334  1.1     lukem static ConfigTable distproc_cfg[] = {
    335  1.1     lukem 	{ "distproc-chaining", "args",
    336  1.1     lukem 		2, 4, 0, ARG_MAGIC|ARG_BERVAL|DP_CHAINING, distproc_cfgen,
    337  1.1     lukem 		/* NOTE: using the same attributeTypes defined
    338  1.1     lukem 		 * for the "chain" overlay */
    339  1.1     lukem 		"( OLcfgOvAt:3.1 NAME 'olcChainingBehavior' "
    340  1.1     lukem 			"DESC 'Chaining behavior control parameters (draft-sermersheim-ldap-chaining)' "
    341  1.1     lukem 			"SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
    342  1.1     lukem 	{ "distproc-cache-uri", "TRUE/FALSE",
    343  1.1     lukem 		2, 2, 0, ARG_MAGIC|ARG_ON_OFF|DP_CACHE_URI, distproc_cfgen,
    344  1.1     lukem 		"( OLcfgOvAt:3.2 NAME 'olcChainCacheURI' "
    345  1.1     lukem 			"DESC 'Enables caching of URIs not present in configuration' "
    346  1.1     lukem 			"SYNTAX OMsBoolean "
    347  1.1     lukem 			"SINGLE-VALUE )", NULL, NULL },
    348  1.1     lukem 	{ NULL, NULL, 0, 0, 0, ARG_IGNORED }
    349  1.1     lukem };
    350  1.1     lukem 
    351  1.1     lukem static ConfigOCs distproc_ocs[] = {
    352  1.1     lukem 	{ "( OLcfgOvOc:7.1 "
    353  1.1     lukem 		"NAME 'olcDistProcConfig' "
    354  1.1     lukem 		"DESC 'Distributed procedures <draft-sermersheim-ldap-distproc> configuration' "
    355  1.1     lukem 		"SUP olcOverlayConfig "
    356  1.1     lukem 		"MAY ( "
    357  1.1     lukem 			"olcChainingBehavior $ "
    358  1.1     lukem 			"olcChainCacheURI "
    359  1.1     lukem 			") )",
    360  1.1     lukem 		Cft_Overlay, distproc_cfg, NULL, distproc_cfadd },
    361  1.1     lukem 	{ "( OLcfgOvOc:7.2 "
    362  1.1     lukem 		"NAME 'olcDistProcDatabase' "
    363  1.1     lukem 		"DESC 'Distributed procedure remote server configuration' "
    364  1.1     lukem 		"AUXILIARY )",
    365  1.1     lukem 		Cft_Misc, distproc_cfg, distproc_ldadd },
    366  1.1     lukem 	{ NULL, 0, NULL }
    367  1.1     lukem };
    368  1.1     lukem 
    369  1.1     lukem static int
    370  1.1     lukem distproc_ldadd( CfEntryInfo *p, Entry *e, ConfigArgs *ca )
    371  1.1     lukem {
    372  1.1     lukem 	slap_overinst		*on;
    373  1.1     lukem 	ldap_distproc_t		*lc;
    374  1.1     lukem 
    375  1.1     lukem 	ldapinfo_t		*li;
    376  1.1     lukem 
    377  1.1     lukem 	AttributeDescription	*ad = NULL;
    378  1.1     lukem 	Attribute		*at;
    379  1.1     lukem 	const char		*text;
    380  1.1     lukem 
    381  1.1     lukem 	int			rc;
    382  1.1     lukem 
    383  1.1     lukem 	if ( p->ce_type != Cft_Overlay
    384  1.1     lukem 		|| !p->ce_bi
    385  1.1     lukem 		|| p->ce_bi->bi_cf_ocs != distproc_ocs )
    386  1.1     lukem 	{
    387  1.1     lukem 		return LDAP_CONSTRAINT_VIOLATION;
    388  1.1     lukem 	}
    389  1.1     lukem 
    390  1.1     lukem 	on = (slap_overinst *)p->ce_bi;
    391  1.1     lukem 	lc = (ldap_distproc_t *)on->on_bi.bi_private;
    392  1.1     lukem 
    393  1.1     lukem 	assert( ca->be == NULL );
    394  1.1     lukem 	ca->be = (BackendDB *)ch_calloc( 1, sizeof( BackendDB ) );
    395  1.1     lukem 
    396  1.1     lukem 	ca->be->bd_info = (BackendInfo *)on;
    397  1.1     lukem 
    398  1.1     lukem 	rc = slap_str2ad( "olcDbURI", &ad, &text );
    399  1.1     lukem 	assert( rc == LDAP_SUCCESS );
    400  1.1     lukem 
    401  1.1     lukem 	at = attr_find( e->e_attrs, ad );
    402  1.1     lukem 	if ( lc->lc_common_li == NULL && at != NULL ) {
    403  1.1     lukem 		/* FIXME: we should generate an empty default entry
    404  1.1     lukem 		 * if none is supplied */
    405  1.1     lukem 		Debug( LDAP_DEBUG_ANY, "slapd-distproc: "
    406  1.1     lukem 			"first underlying database \"%s\" "
    407  1.1     lukem 			"cannot contain attribute \"%s\".\n",
    408  1.1     lukem 			e->e_name.bv_val, ad->ad_cname.bv_val, 0 );
    409  1.1     lukem 		rc = LDAP_CONSTRAINT_VIOLATION;
    410  1.1     lukem 		goto done;
    411  1.1     lukem 
    412  1.1     lukem 	} else if ( lc->lc_common_li != NULL && at == NULL ) {
    413  1.1     lukem 		/* FIXME: we should generate an empty default entry
    414  1.1     lukem 		 * if none is supplied */
    415  1.1     lukem 		Debug( LDAP_DEBUG_ANY, "slapd-distproc: "
    416  1.1     lukem 			"subsequent underlying database \"%s\" "
    417  1.1     lukem 			"must contain attribute \"%s\".\n",
    418  1.1     lukem 			e->e_name.bv_val, ad->ad_cname.bv_val, 0 );
    419  1.1     lukem 		rc = LDAP_CONSTRAINT_VIOLATION;
    420  1.1     lukem 		goto done;
    421  1.1     lukem 	}
    422  1.1     lukem 
    423  1.1     lukem 	if ( lc->lc_common_li == NULL ) {
    424  1.1     lukem 		rc = ldap_distproc_db_init_common( ca->be );
    425  1.1     lukem 
    426  1.1     lukem 	} else {
    427  1.1     lukem 		rc = ldap_distproc_db_init_one( ca->be );
    428  1.1     lukem 	}
    429  1.1     lukem 
    430  1.1     lukem 	if ( rc != 0 ) {
    431  1.1     lukem 		Debug( LDAP_DEBUG_ANY, "slapd-distproc: "
    432  1.1     lukem 			"unable to init %sunderlying database \"%s\".\n",
    433  1.1     lukem 			lc->lc_common_li == NULL ? "common " : "", e->e_name.bv_val, 0 );
    434  1.2  christos 		rc = LDAP_CONSTRAINT_VIOLATION;
    435  1.2  christos 		goto done;
    436  1.1     lukem 	}
    437  1.1     lukem 
    438  1.1     lukem 	li = ca->be->be_private;
    439  1.1     lukem 
    440  1.1     lukem 	if ( lc->lc_common_li == NULL ) {
    441  1.1     lukem 		lc->lc_common_li = li;
    442  1.1     lukem 
    443  1.1     lukem 	} else if ( avl_insert( &lc->lc_lai.lai_tree, (caddr_t)li,
    444  1.1     lukem 		ldap_distproc_uri_cmp, ldap_distproc_uri_dup ) )
    445  1.1     lukem 	{
    446  1.1     lukem 		Debug( LDAP_DEBUG_ANY, "slapd-distproc: "
    447  1.1     lukem 			"database \"%s\" insert failed.\n",
    448  1.1     lukem 			e->e_name.bv_val, 0, 0 );
    449  1.1     lukem 		rc = LDAP_CONSTRAINT_VIOLATION;
    450  1.1     lukem 		goto done;
    451  1.1     lukem 	}
    452  1.1     lukem 
    453  1.1     lukem done:;
    454  1.1     lukem 	if ( rc != LDAP_SUCCESS ) {
    455  1.1     lukem 		(void)ldap_distproc_db_destroy_one( ca->be, NULL );
    456  1.1     lukem 		ch_free( ca->be );
    457  1.1     lukem 		ca->be = NULL;
    458  1.1     lukem 	}
    459  1.1     lukem 
    460  1.1     lukem 	return rc;
    461  1.1     lukem }
    462  1.1     lukem 
    463  1.1     lukem typedef struct ldap_distproc_cfadd_apply_t {
    464  1.1     lukem 	Operation	*op;
    465  1.1     lukem 	SlapReply	*rs;
    466  1.1     lukem 	Entry		*p;
    467  1.1     lukem 	ConfigArgs	*ca;
    468  1.1     lukem 	int		count;
    469  1.1     lukem } ldap_distproc_cfadd_apply_t;
    470  1.1     lukem 
    471  1.1     lukem static int
    472  1.1     lukem ldap_distproc_cfadd_apply( void *datum, void *arg )
    473  1.1     lukem {
    474  1.1     lukem 	ldapinfo_t			*li = (ldapinfo_t *)datum;
    475  1.1     lukem 	ldap_distproc_cfadd_apply_t	*lca = (ldap_distproc_cfadd_apply_t *)arg;
    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.1     lukem 	bv.bv_len = snprintf( lca->ca->cr_msg, sizeof( lca->ca->cr_msg ),
    481  1.1     lukem 		"olcDatabase={%d}%s", lca->count, lback->bi_type );
    482  1.1     lukem 	bv.bv_val = lca->ca->cr_msg;
    483  1.1     lukem 
    484  1.1     lukem 	lca->ca->be->be_private = (void *)li;
    485  1.1     lukem 	config_build_entry( lca->op, lca->rs, lca->p->e_private, lca->ca,
    486  1.1     lukem 		&bv, lback->bi_cf_ocs, &distproc_ocs[ 1 ] );
    487  1.1     lukem 
    488  1.1     lukem 	lca->count++;
    489  1.1     lukem 
    490  1.1     lukem 	return 0;
    491  1.1     lukem }
    492  1.1     lukem 
    493  1.1     lukem static int
    494  1.1     lukem distproc_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *ca )
    495  1.1     lukem {
    496  1.1     lukem 	CfEntryInfo	*pe = p->e_private;
    497  1.1     lukem 	slap_overinst	*on = (slap_overinst *)pe->ce_bi;
    498  1.1     lukem 	ldap_distproc_t	*lc = (ldap_distproc_t *)on->on_bi.bi_private;
    499  1.1     lukem 	void		*priv = (void *)ca->be->be_private;
    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.1     lukem 		(void)ldap_distproc_cfadd_apply( (void *)lc->lc_common_li, (void *)&lca );
    511  1.1     lukem 
    512  1.1     lukem 		(void)avl_apply( lc->lc_lai.lai_tree, ldap_distproc_cfadd_apply,
    513  1.1     lukem 			&lca, 1, AVL_INORDER );
    514  1.1     lukem 
    515  1.1     lukem 		ca->be->be_private = priv;
    516  1.1     lukem 	}
    517  1.1     lukem 
    518  1.1     lukem 	return 0;
    519  1.1     lukem }
    520  1.1     lukem 
    521  1.1     lukem static int
    522  1.1     lukem distproc_cfgen( ConfigArgs *c )
    523  1.1     lukem {
    524  1.1     lukem 	slap_overinst	*on = (slap_overinst *)c->bi;
    525  1.1     lukem 	ldap_distproc_t	*lc = (ldap_distproc_t *)on->on_bi.bi_private;
    526  1.1     lukem 
    527  1.1     lukem 	int		rc = 0;
    528  1.1     lukem 
    529  1.1     lukem 	if ( c->op == SLAP_CONFIG_EMIT ) {
    530  1.1     lukem 		switch( c->type ) {
    531  1.1     lukem 		case DP_CACHE_URI:
    532  1.1     lukem 			c->value_int = LDAP_DISTPROC_CACHE_URI( lc );
    533  1.1     lukem 			break;
    534  1.1     lukem 
    535  1.1     lukem 		default:
    536  1.1     lukem 			assert( 0 );
    537  1.1     lukem 			rc = 1;
    538  1.1     lukem 		}
    539  1.1     lukem 		return rc;
    540  1.1     lukem 
    541  1.1     lukem 	} else if ( c->op == LDAP_MOD_DELETE ) {
    542  1.1     lukem 		switch( c->type ) {
    543  1.1     lukem 		case DP_CHAINING:
    544  1.1     lukem 			return 1;
    545  1.1     lukem 
    546  1.1     lukem 		case DP_CACHE_URI:
    547  1.1     lukem 			lc->lc_flags &= ~LDAP_DISTPROC_F_CACHE_URI;
    548  1.1     lukem 			break;
    549  1.1     lukem 
    550  1.1     lukem 		default:
    551  1.1     lukem 			return 1;
    552  1.1     lukem 		}
    553  1.1     lukem 		return rc;
    554  1.1     lukem 	}
    555  1.1     lukem 
    556  1.1     lukem 	switch( c->type ) {
    557  1.1     lukem 	case DP_CACHE_URI:
    558  1.1     lukem 		if ( c->value_int ) {
    559  1.1     lukem 			lc->lc_flags |= LDAP_DISTPROC_F_CACHE_URI;
    560  1.1     lukem 		} else {
    561  1.1     lukem 			lc->lc_flags &= ~LDAP_DISTPROC_F_CACHE_URI;
    562  1.1     lukem 		}
    563  1.1     lukem 		break;
    564  1.1     lukem 
    565  1.1     lukem 	default:
    566  1.1     lukem 		assert( 0 );
    567  1.1     lukem 		return 1;
    568  1.1     lukem 	}
    569  1.1     lukem 
    570  1.1     lukem 	return rc;
    571  1.1     lukem }
    572  1.1     lukem 
    573  1.1     lukem static int
    574  1.1     lukem ldap_distproc_db_init(
    575  1.1     lukem 	BackendDB *be,
    576  1.1     lukem 	ConfigReply *cr )
    577  1.1     lukem {
    578  1.1     lukem 	slap_overinst	*on = (slap_overinst *)be->bd_info;
    579  1.1     lukem 	ldap_distproc_t	*lc = NULL;
    580  1.1     lukem 
    581  1.1     lukem 	if ( lback == NULL ) {
    582  1.1     lukem 		lback = backend_info( "ldap" );
    583  1.1     lukem 
    584  1.1     lukem 		if ( lback == NULL ) {
    585  1.1     lukem 			return 1;
    586  1.1     lukem 		}
    587  1.1     lukem 	}
    588  1.1     lukem 
    589  1.1     lukem 	lc = ch_malloc( sizeof( ldap_distproc_t ) );
    590  1.1     lukem 	if ( lc == NULL ) {
    591  1.1     lukem 		return 1;
    592  1.1     lukem 	}
    593  1.1     lukem 	memset( lc, 0, sizeof( ldap_distproc_t ) );
    594  1.1     lukem 	ldap_pvt_thread_mutex_init( &lc->lc_lai.lai_mutex );
    595  1.1     lukem 
    596  1.1     lukem 	on->on_bi.bi_private = (void *)lc;
    597  1.1     lukem 
    598  1.1     lukem 	return 0;
    599  1.1     lukem }
    600  1.1     lukem 
    601  1.1     lukem static int
    602  1.1     lukem ldap_distproc_db_config(
    603  1.1     lukem 	BackendDB	*be,
    604  1.1     lukem 	const char	*fname,
    605  1.1     lukem 	int		lineno,
    606  1.1     lukem 	int		argc,
    607  1.1     lukem 	char		**argv )
    608  1.1     lukem {
    609  1.1     lukem 	slap_overinst	*on = (slap_overinst *)be->bd_info;
    610  1.1     lukem 	ldap_distproc_t	*lc = (ldap_distproc_t *)on->on_bi.bi_private;
    611  1.1     lukem 
    612  1.1     lukem 	int		rc = SLAP_CONF_UNKNOWN;
    613  1.1     lukem 
    614  1.1     lukem 	if ( lc->lc_common_li == NULL ) {
    615  1.1     lukem 		void	*be_private = be->be_private;
    616  1.1     lukem 		ldap_distproc_db_init_common( be );
    617  1.1     lukem 		lc->lc_common_li = lc->lc_cfg_li = (ldapinfo_t *)be->be_private;
    618  1.1     lukem 		be->be_private = be_private;
    619  1.1     lukem 	}
    620  1.1     lukem 
    621  1.1     lukem 	/* Something for the distproc database? */
    622  1.1     lukem 	if ( strncasecmp( argv[ 0 ], "distproc-", STRLENOF( "distproc-" ) ) == 0 ) {
    623  1.1     lukem 		char		*save_argv0 = argv[ 0 ];
    624  1.1     lukem 		BackendInfo	*bd_info = be->bd_info;
    625  1.1     lukem 		void		*be_private = be->be_private;
    626  1.1     lukem 		ConfigOCs	*be_cf_ocs = be->be_cf_ocs;
    627  1.1     lukem 		int		is_uri = 0;
    628  1.1     lukem 
    629  1.1     lukem 		argv[ 0 ] += STRLENOF( "distproc-" );
    630  1.1     lukem 
    631  1.1     lukem 		if ( strcasecmp( argv[ 0 ], "uri" ) == 0 ) {
    632  1.1     lukem 			rc = ldap_distproc_db_init_one( be );
    633  1.1     lukem 			if ( rc != 0 ) {
    634  1.1     lukem 				Debug( LDAP_DEBUG_ANY, "%s: line %d: "
    635  1.1     lukem 					"underlying slapd-ldap initialization failed.\n.",
    636  1.1     lukem 					fname, lineno, 0 );
    637  1.1     lukem 				return 1;
    638  1.1     lukem 			}
    639  1.1     lukem 			lc->lc_cfg_li = be->be_private;
    640  1.1     lukem 			is_uri = 1;
    641  1.1     lukem 		}
    642  1.1     lukem 
    643  1.1     lukem 		/* TODO: add checks on what other slapd-ldap(5) args
    644  1.1     lukem 		 * should be put in the template; this is not quite
    645  1.1     lukem 		 * harmful, because attributes that shouldn't don't
    646  1.1     lukem 		 * get actually used, but the user should at least
    647  1.1     lukem 		 * be warned.
    648  1.1     lukem 		 */
    649  1.1     lukem 
    650  1.1     lukem 		be->bd_info = lback;
    651  1.1     lukem 		be->be_private = (void *)lc->lc_cfg_li;
    652  1.1     lukem 		be->be_cf_ocs = lback->bi_cf_ocs;
    653  1.1     lukem 
    654  1.1     lukem 		rc = config_generic_wrapper( be, fname, lineno, argc, argv );
    655  1.1     lukem 
    656  1.1     lukem 		argv[ 0 ] = save_argv0;
    657  1.1     lukem 		be->be_cf_ocs = be_cf_ocs;
    658  1.1     lukem 		be->be_private = be_private;
    659  1.1     lukem 		be->bd_info = bd_info;
    660  1.1     lukem 
    661  1.1     lukem 		if ( is_uri ) {
    662  1.1     lukem private_destroy:;
    663  1.1     lukem 			if ( rc != 0 ) {
    664  1.1     lukem 				BackendDB		db = *be;
    665  1.1     lukem 
    666  1.1     lukem 				db.bd_info = lback;
    667  1.1     lukem 				db.be_private = (void *)lc->lc_cfg_li;
    668  1.1     lukem 				ldap_distproc_db_destroy_one( &db, NULL );
    669  1.1     lukem 				lc->lc_cfg_li = NULL;
    670  1.1     lukem 
    671  1.1     lukem 			} else {
    672  1.1     lukem 				if ( lc->lc_cfg_li->li_bvuri == NULL
    673  1.1     lukem 					|| BER_BVISNULL( &lc->lc_cfg_li->li_bvuri[ 0 ] )
    674  1.1     lukem 					|| !BER_BVISNULL( &lc->lc_cfg_li->li_bvuri[ 1 ] ) )
    675  1.1     lukem 				{
    676  1.1     lukem 					Debug( LDAP_DEBUG_ANY, "%s: line %d: "
    677  1.1     lukem 						"no URI list allowed in slapo-distproc.\n",
    678  1.1     lukem 						fname, lineno, 0 );
    679  1.1     lukem 					rc = 1;
    680  1.1     lukem 					goto private_destroy;
    681  1.1     lukem 				}
    682  1.1     lukem 
    683  1.1     lukem 				if ( avl_insert( &lc->lc_lai.lai_tree,
    684  1.1     lukem 					(caddr_t)lc->lc_cfg_li,
    685  1.1     lukem 					ldap_distproc_uri_cmp, ldap_distproc_uri_dup ) )
    686  1.1     lukem 				{
    687  1.1     lukem 					Debug( LDAP_DEBUG_ANY, "%s: line %d: "
    688  1.1     lukem 						"duplicate URI in slapo-distproc.\n",
    689  1.1     lukem 						fname, lineno, 0 );
    690  1.1     lukem 					rc = 1;
    691  1.1     lukem 					goto private_destroy;
    692  1.1     lukem 				}
    693  1.1     lukem 			}
    694  1.1     lukem 		}
    695  1.1     lukem 	}
    696  1.1     lukem 
    697  1.1     lukem 	return rc;
    698  1.1     lukem }
    699  1.1     lukem 
    700  1.1     lukem enum db_which {
    701  1.1     lukem 	db_open = 0,
    702  1.1     lukem 	db_close,
    703  1.1     lukem 	db_destroy,
    704  1.1     lukem 
    705  1.1     lukem 	db_last
    706  1.1     lukem };
    707  1.1     lukem 
    708  1.1     lukem typedef struct ldap_distproc_db_apply_t {
    709  1.1     lukem 	BackendDB	*be;
    710  1.1     lukem 	BI_db_func	*func;
    711  1.1     lukem } ldap_distproc_db_apply_t;
    712  1.1     lukem 
    713  1.1     lukem static int
    714  1.1     lukem ldap_distproc_db_apply( void *datum, void *arg )
    715  1.1     lukem {
    716  1.1     lukem 	ldapinfo_t		*li = (ldapinfo_t *)datum;
    717  1.1     lukem 	ldap_distproc_db_apply_t	*lca = (ldap_distproc_db_apply_t *)arg;
    718  1.1     lukem 
    719  1.1     lukem 	lca->be->be_private = (void *)li;
    720  1.1     lukem 
    721  1.1     lukem 	return lca->func( lca->be, NULL );
    722  1.1     lukem }
    723  1.1     lukem 
    724  1.1     lukem static int
    725  1.1     lukem ldap_distproc_db_func(
    726  1.1     lukem 	BackendDB *be,
    727  1.1     lukem 	enum db_which which
    728  1.1     lukem )
    729  1.1     lukem {
    730  1.1     lukem 	slap_overinst	*on = (slap_overinst *)be->bd_info;
    731  1.1     lukem 	ldap_distproc_t	*lc = (ldap_distproc_t *)on->on_bi.bi_private;
    732  1.1     lukem 
    733  1.1     lukem 	int		rc = 0;
    734  1.1     lukem 
    735  1.1     lukem 	if ( lc ) {
    736  1.1     lukem 		BI_db_func	*func = (&lback->bi_db_open)[ which ];
    737  1.1     lukem 
    738  1.1     lukem 		if ( func != NULL && lc->lc_common_li != NULL ) {
    739  1.1     lukem 			BackendDB		db = *be;
    740  1.1     lukem 
    741  1.1     lukem 			db.bd_info = lback;
    742  1.1     lukem 			db.be_private = lc->lc_common_li;
    743  1.1     lukem 
    744  1.1     lukem 			rc = func( &db, NULL );
    745  1.1     lukem 
    746  1.1     lukem 			if ( rc != 0 ) {
    747  1.1     lukem 				return rc;
    748  1.1     lukem 			}
    749  1.1     lukem 
    750  1.1     lukem 			if ( lc->lc_lai.lai_tree != NULL ) {
    751  1.1     lukem 				ldap_distproc_db_apply_t	lca;
    752  1.1     lukem 
    753  1.1     lukem 				lca.be = &db;
    754  1.1     lukem 				lca.func = func;
    755  1.1     lukem 
    756  1.1     lukem 				rc = avl_apply( lc->lc_lai.lai_tree,
    757  1.1     lukem 					ldap_distproc_db_apply, (void *)&lca,
    758  1.1     lukem 					1, AVL_INORDER ) != AVL_NOMORE;
    759  1.1     lukem 			}
    760  1.1     lukem 		}
    761  1.1     lukem 	}
    762  1.1     lukem 
    763  1.1     lukem 	return rc;
    764  1.1     lukem }
    765  1.1     lukem 
    766  1.1     lukem static int
    767  1.1     lukem ldap_distproc_db_open(
    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_open );
    772  1.1     lukem }
    773  1.1     lukem 
    774  1.1     lukem static int
    775  1.1     lukem ldap_distproc_db_close(
    776  1.1     lukem 	BackendDB	*be,
    777  1.1     lukem 	ConfigReply	*cr )
    778  1.1     lukem {
    779  1.1     lukem 	return ldap_distproc_db_func( be, db_close );
    780  1.1     lukem }
    781  1.1     lukem 
    782  1.1     lukem static int
    783  1.1     lukem ldap_distproc_db_destroy(
    784  1.1     lukem 	BackendDB	*be,
    785  1.1     lukem 	ConfigReply	*cr )
    786  1.1     lukem {
    787  1.1     lukem 	slap_overinst	*on = (slap_overinst *) be->bd_info;
    788  1.1     lukem 	ldap_distproc_t	*lc = (ldap_distproc_t *)on->on_bi.bi_private;
    789  1.1     lukem 
    790  1.1     lukem 	int		rc;
    791  1.1     lukem 
    792  1.1     lukem 	rc = ldap_distproc_db_func( be, db_destroy );
    793  1.1     lukem 
    794  1.1     lukem 	if ( lc ) {
    795  1.1     lukem 		avl_free( lc->lc_lai.lai_tree, NULL );
    796  1.1     lukem 		ldap_pvt_thread_mutex_destroy( &lc->lc_lai.lai_mutex );
    797  1.1     lukem 		ch_free( lc );
    798  1.1     lukem 	}
    799  1.1     lukem 
    800  1.1     lukem 	return rc;
    801  1.1     lukem }
    802  1.1     lukem 
    803  1.1     lukem /*
    804  1.1     lukem  * inits one instance of the slapd-ldap backend, and stores
    805  1.1     lukem  * the private info in be_private of the arg
    806  1.1     lukem  */
    807  1.1     lukem static int
    808  1.1     lukem ldap_distproc_db_init_common(
    809  1.1     lukem 	BackendDB	*be )
    810  1.1     lukem {
    811  1.1     lukem 	BackendInfo	*bi = be->bd_info;
    812  1.1     lukem 	int		t;
    813  1.1     lukem 
    814  1.1     lukem 	be->bd_info = lback;
    815  1.1     lukem 	be->be_private = NULL;
    816  1.1     lukem 	t = lback->bi_db_init( be, NULL );
    817  1.1     lukem 	if ( t != 0 ) {
    818  1.1     lukem 		return t;
    819  1.1     lukem 	}
    820  1.1     lukem 	be->bd_info = bi;
    821  1.1     lukem 
    822  1.1     lukem 	return 0;
    823  1.1     lukem }
    824  1.1     lukem 
    825  1.1     lukem /*
    826  1.1     lukem  * inits one instance of the slapd-ldap backend, stores
    827  1.1     lukem  * the private info in be_private of the arg and fills
    828  1.1     lukem  * selected fields with data from the template.
    829  1.1     lukem  *
    830  1.1     lukem  * NOTE: add checks about the other fields of the template,
    831  1.1     lukem  * which are ignored and SHOULD NOT be configured by the user.
    832  1.1     lukem  */
    833  1.1     lukem static int
    834  1.1     lukem ldap_distproc_db_init_one(
    835  1.1     lukem 	BackendDB	*be )
    836  1.1     lukem {
    837  1.1     lukem 	slap_overinst	*on = (slap_overinst *)be->bd_info;
    838  1.1     lukem 	ldap_distproc_t	*lc = (ldap_distproc_t *)on->on_bi.bi_private;
    839  1.1     lukem 
    840  1.1     lukem 	BackendInfo	*bi = be->bd_info;
    841  1.1     lukem 	ldapinfo_t	*li;
    842  1.1     lukem 
    843  1.1     lukem 	slap_op_t	t;
    844  1.1     lukem 
    845  1.1     lukem 	be->bd_info = lback;
    846  1.1     lukem 	be->be_private = NULL;
    847  1.1     lukem 	t = lback->bi_db_init( be, NULL );
    848  1.1     lukem 	if ( t != 0 ) {
    849  1.1     lukem 		return t;
    850  1.1     lukem 	}
    851  1.1     lukem 	li = (ldapinfo_t *)be->be_private;
    852  1.1     lukem 
    853  1.1     lukem 	/* copy common data */
    854  1.1     lukem 	li->li_nretries = lc->lc_common_li->li_nretries;
    855  1.1     lukem 	li->li_flags = lc->lc_common_li->li_flags;
    856  1.1     lukem 	li->li_version = lc->lc_common_li->li_version;
    857  1.1     lukem 	for ( t = 0; t < SLAP_OP_LAST; t++ ) {
    858  1.1     lukem 		li->li_timeout[ t ] = lc->lc_common_li->li_timeout[ t ];
    859  1.1     lukem 	}
    860  1.1     lukem 	be->bd_info = bi;
    861  1.1     lukem 
    862  1.1     lukem 	return 0;
    863  1.1     lukem }
    864  1.1     lukem 
    865  1.1     lukem typedef struct ldap_distproc_conn_apply_t {
    866  1.1     lukem 	BackendDB	*be;
    867  1.1     lukem 	Connection	*conn;
    868  1.1     lukem } ldap_distproc_conn_apply_t;
    869  1.1     lukem 
    870  1.1     lukem static int
    871  1.1     lukem ldap_distproc_conn_apply( void *datum, void *arg )
    872  1.1     lukem {
    873  1.1     lukem 	ldapinfo_t		*li = (ldapinfo_t *)datum;
    874  1.1     lukem 	ldap_distproc_conn_apply_t	*lca = (ldap_distproc_conn_apply_t *)arg;
    875  1.1     lukem 
    876  1.1     lukem 	lca->be->be_private = (void *)li;
    877  1.1     lukem 
    878  1.1     lukem 	return lback->bi_connection_destroy( lca->be, lca->conn );
    879  1.1     lukem }
    880  1.1     lukem 
    881  1.1     lukem static int
    882  1.1     lukem ldap_distproc_connection_destroy(
    883  1.1     lukem 	BackendDB *be,
    884  1.1     lukem 	Connection *conn
    885  1.1     lukem )
    886  1.1     lukem {
    887  1.1     lukem 	slap_overinst		*on = (slap_overinst *) be->bd_info;
    888  1.1     lukem 	ldap_distproc_t		*lc = (ldap_distproc_t *)on->on_bi.bi_private;
    889  1.1     lukem 	void			*private = be->be_private;
    890  1.1     lukem 	ldap_distproc_conn_apply_t	lca;
    891  1.1     lukem 	int			rc;
    892  1.1     lukem 
    893  1.1     lukem 	be->be_private = NULL;
    894  1.1     lukem 	lca.be = be;
    895  1.1     lukem 	lca.conn = conn;
    896  1.1     lukem 	ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
    897  1.1     lukem 	rc = avl_apply( lc->lc_lai.lai_tree, ldap_distproc_conn_apply,
    898  1.1     lukem 		(void *)&lca, 1, AVL_INORDER ) != AVL_NOMORE;
    899  1.1     lukem 	ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
    900  1.1     lukem 	be->be_private = private;
    901  1.1     lukem 
    902  1.1     lukem 	return rc;
    903  1.1     lukem }
    904  1.1     lukem 
    905  1.1     lukem static int
    906  1.1     lukem ldap_distproc_parse_returnContRef_ctrl(
    907  1.1     lukem 	Operation	*op,
    908  1.1     lukem 	SlapReply	*rs,
    909  1.1     lukem 	LDAPControl	*ctrl )
    910  1.1     lukem {
    911  1.1     lukem 	if ( get_returnContRef( op ) != SLAP_CONTROL_NONE ) {
    912  1.1     lukem 		rs->sr_text = "returnContinuationReference control specified multiple times";
    913  1.1     lukem 		return LDAP_PROTOCOL_ERROR;
    914  1.1     lukem 	}
    915  1.1     lukem 
    916  1.1     lukem 	if ( op->o_pagedresults != SLAP_CONTROL_NONE ) {
    917  1.1     lukem 		rs->sr_text = "returnContinuationReference control specified with pagedResults control";
    918  1.1     lukem 		return LDAP_PROTOCOL_ERROR;
    919  1.1     lukem 	}
    920  1.1     lukem 
    921  1.1     lukem 	if ( !BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
    922  1.1     lukem 		rs->sr_text = "returnContinuationReference control: value must be NULL";
    923  1.1     lukem 		return LDAP_PROTOCOL_ERROR;
    924  1.1     lukem 	}
    925  1.1     lukem 
    926  1.1     lukem 	op->o_returnContRef = ctrl->ldctl_iscritical ? SLAP_CONTROL_CRITICAL : SLAP_CONTROL_NONCRITICAL;
    927  1.1     lukem 
    928  1.1     lukem 	return LDAP_SUCCESS;
    929  1.1     lukem }
    930  1.1     lukem 
    931  1.1     lukem static int
    932  1.1     lukem ldap_exop_chained_request(
    933  1.1     lukem 		Operation	*op,
    934  1.1     lukem 		SlapReply	*rs )
    935  1.1     lukem {
    936  1.1     lukem 	Statslog( LDAP_DEBUG_STATS, "%s CHAINED REQUEST\n",
    937  1.1     lukem 	    op->o_log_prefix, 0, 0, 0, 0 );
    938  1.1     lukem 
    939  1.1     lukem 	rs->sr_err = backend_check_restrictions( op, rs,
    940  1.1     lukem 			(struct berval *)&slap_EXOP_CHAINEDREQUEST );
    941  1.1     lukem 	if ( rs->sr_err != LDAP_SUCCESS ) {
    942  1.1     lukem 		return rs->sr_err;
    943  1.1     lukem 	}
    944  1.1     lukem 
    945  1.1     lukem 	/* by now, just reject requests */
    946  1.1     lukem 	rs->sr_text = "under development";
    947  1.1     lukem 	return LDAP_UNWILLING_TO_PERFORM;
    948  1.1     lukem }
    949  1.1     lukem 
    950  1.1     lukem 
    951  1.1     lukem static slap_overinst distproc;
    952  1.1     lukem 
    953  1.1     lukem int
    954  1.1     lukem distproc_initialize( void )
    955  1.1     lukem {
    956  1.1     lukem 	int	rc;
    957  1.1     lukem 
    958  1.1     lukem 	/* Make sure we don't exceed the bits reserved for userland */
    959  1.1     lukem 	config_check_userland( DP_LAST );
    960  1.1     lukem 
    961  1.1     lukem 	rc = load_extop( (struct berval *)&slap_EXOP_CHAINEDREQUEST,
    962  1.1     lukem 		SLAP_EXOP_HIDE, ldap_exop_chained_request );
    963  1.1     lukem 	if ( rc != LDAP_SUCCESS ) {
    964  1.1     lukem 		Debug( LDAP_DEBUG_ANY, "slapd-distproc: "
    965  1.1     lukem 			"unable to register chainedRequest exop: %d.\n",
    966  1.1     lukem 			rc, 0, 0 );
    967  1.1     lukem 		return rc;
    968  1.1     lukem 	}
    969  1.1     lukem 
    970  1.1     lukem #ifdef LDAP_DEVEL
    971  1.1     lukem 	rc = supported_feature_load( &slap_FEATURE_CANCHAINOPS );
    972  1.1     lukem 	if ( rc != LDAP_SUCCESS ) {
    973  1.1     lukem 		Debug( LDAP_DEBUG_ANY, "slapd-distproc: "
    974  1.1     lukem 			"unable to register canChainOperations supported feature: %d.\n",
    975  1.1     lukem 			rc, 0, 0 );
    976  1.1     lukem 		return rc;
    977  1.1     lukem 	}
    978  1.1     lukem #endif
    979  1.1     lukem 
    980  1.1     lukem 	rc = register_supported_control( LDAP_CONTROL_X_RETURNCONTREF,
    981  1.1     lukem 			SLAP_CTRL_GLOBAL|SLAP_CTRL_ACCESS|SLAP_CTRL_HIDE, NULL,
    982  1.1     lukem 			ldap_distproc_parse_returnContRef_ctrl, &sc_returnContRef );
    983  1.1     lukem 	if ( rc != LDAP_SUCCESS ) {
    984  1.1     lukem 		Debug( LDAP_DEBUG_ANY, "slapd-distproc: "
    985  1.1     lukem 			"unable to register returnContinuationReference control: %d.\n",
    986  1.1     lukem 			rc, 0, 0 );
    987  1.1     lukem 		return rc;
    988  1.1     lukem 	}
    989  1.1     lukem 
    990  1.1     lukem 	distproc.on_bi.bi_type = "distproc";
    991  1.1     lukem 	distproc.on_bi.bi_db_init = ldap_distproc_db_init;
    992  1.1     lukem 	distproc.on_bi.bi_db_config = ldap_distproc_db_config;
    993  1.1     lukem 	distproc.on_bi.bi_db_open = ldap_distproc_db_open;
    994  1.1     lukem 	distproc.on_bi.bi_db_close = ldap_distproc_db_close;
    995  1.1     lukem 	distproc.on_bi.bi_db_destroy = ldap_distproc_db_destroy;
    996  1.1     lukem 
    997  1.1     lukem 	/* ... otherwise the underlying backend's function would be called,
    998  1.1     lukem 	 * likely passing an invalid entry; on the contrary, the requested
    999  1.1     lukem 	 * operational attributes should have been returned while chasing
   1000  1.1     lukem 	 * the referrals.  This all in all is a bit messy, because part
   1001  1.1     lukem 	 * of the operational attributes are generated by the backend;
   1002  1.1     lukem 	 * part by the frontend; back-ldap should receive all the available
   1003  1.1     lukem 	 * ones from the remote server, but then, on its own, it strips those
   1004  1.1     lukem 	 * it assumes will be (re)generated by the frontend (e.g.
   1005  1.1     lukem 	 * subschemaSubentry, entryDN, ...) */
   1006  1.1     lukem 	distproc.on_bi.bi_operational = ldap_distproc_operational;
   1007  1.1     lukem 
   1008  1.1     lukem 	distproc.on_bi.bi_connection_destroy = ldap_distproc_connection_destroy;
   1009  1.1     lukem 
   1010  1.1     lukem 	distproc.on_response = ldap_distproc_response;
   1011  1.1     lukem 
   1012  1.1     lukem 	distproc.on_bi.bi_cf_ocs = distproc_ocs;
   1013  1.1     lukem 
   1014  1.1     lukem 	rc = config_register_schema( distproc_cfg, distproc_ocs );
   1015  1.1     lukem 	if ( rc ) {
   1016  1.1     lukem 		return rc;
   1017  1.1     lukem 	}
   1018  1.1     lukem 
   1019  1.1     lukem 	return overlay_register( &distproc );
   1020  1.1     lukem }
   1021  1.1     lukem 
   1022  1.1     lukem #endif /* SLAP_DISTPROC */
   1023