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