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