~ttx/openldap/lucid-gssapi-495418

« back to all changes in this revision

Viewing changes to servers/slapd/backglue.c

  • Committer: Bazaar Package Importer
  • Author(s): Mathias Gug
  • Date: 2008-07-10 14:45:49 UTC
  • Revision ID: james.westby@ubuntu.com-20080710144549-wck73med0e72gfyo
Tags: upstream-2.4.10
ImportĀ upstreamĀ versionĀ 2.4.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* backglue.c - backend glue */
 
2
/* $OpenLDAP: pkg/ldap/servers/slapd/backglue.c,v 1.112.2.12 2008/06/02 18:00:53 quanah Exp $ */
 
3
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 
4
 *
 
5
 * Copyright 2001-2008 The OpenLDAP Foundation.
 
6
 * All rights reserved.
 
7
 *
 
8
 * Redistribution and use in source and binary forms, with or without
 
9
 * modification, are permitted only as authorized by the OpenLDAP
 
10
 * Public License.
 
11
 *
 
12
 * A copy of this license is available in the file LICENSE in the
 
13
 * top-level directory of the distribution or, alternatively, at
 
14
 * <http://www.OpenLDAP.org/license.html>.
 
15
 */
 
16
 
 
17
/*
 
18
 * Functions to glue a bunch of other backends into a single tree.
 
19
 * All of the glued backends must share a common suffix. E.g., you
 
20
 * can glue o=foo and ou=bar,o=foo but you can't glue o=foo and o=bar.
 
21
 *
 
22
 * The purpose of these functions is to allow you to split a single database
 
23
 * into pieces (for load balancing purposes, whatever) but still be able
 
24
 * to treat it as a single database after it's been split. As such, each
 
25
 * of the glued backends should have identical rootdn.
 
26
 *  -- Howard Chu
 
27
 */
 
28
 
 
29
#include "portable.h"
 
30
 
 
31
#include <stdio.h>
 
32
 
 
33
#include <ac/string.h>
 
34
#include <ac/socket.h>
 
35
 
 
36
#define SLAPD_TOOLS
 
37
#include "slap.h"
 
38
#include "config.h"
 
39
 
 
40
typedef struct gluenode {
 
41
        BackendDB *gn_be;
 
42
        struct berval gn_pdn;
 
43
} gluenode;
 
44
 
 
45
typedef struct glueinfo {
 
46
        int gi_nodes;
 
47
        struct berval gi_pdn;
 
48
        gluenode gi_n[1];
 
49
} glueinfo;
 
50
 
 
51
static slap_overinst    glue;
 
52
 
 
53
static int glueMode;
 
54
static BackendDB *glueBack;
 
55
 
 
56
static slap_response glue_op_response;
 
57
 
 
58
/* Just like select_backend, but only for our backends */
 
59
static BackendDB *
 
60
glue_back_select (
 
61
        BackendDB *be,
 
62
        struct berval *dn
 
63
)
 
64
{
 
65
        slap_overinst   *on = (slap_overinst *)be->bd_info;
 
66
        glueinfo                *gi = (glueinfo *)on->on_bi.bi_private;
 
67
        int i;
 
68
 
 
69
        for (i = gi->gi_nodes-1; i >= 0; i--) {
 
70
                assert( gi->gi_n[i].gn_be->be_nsuffix != NULL );
 
71
 
 
72
                if (dnIsSuffix(dn, &gi->gi_n[i].gn_be->be_nsuffix[0])) {
 
73
                        return gi->gi_n[i].gn_be;
 
74
                }
 
75
        }
 
76
        be->bd_info = on->on_info->oi_orig;
 
77
        return be;
 
78
}
 
79
 
 
80
 
 
81
typedef struct glue_state {
 
82
        char *matched;
 
83
        BerVarray refs;
 
84
        LDAPControl **ctrls;
 
85
        int err;
 
86
        int matchlen;
 
87
        int nrefs;
 
88
        int nctrls;
 
89
} glue_state;
 
90
 
 
91
static int
 
92
glue_op_cleanup( Operation *op, SlapReply *rs )
 
93
{
 
94
        /* This is not a final result */
 
95
        if (rs->sr_type == REP_RESULT )
 
96
                rs->sr_type = REP_GLUE_RESULT;
 
97
        return SLAP_CB_CONTINUE;
 
98
}
 
99
 
 
100
static int
 
101
glue_op_response ( Operation *op, SlapReply *rs )
 
102
{
 
103
        glue_state *gs = op->o_callback->sc_private;
 
104
 
 
105
        switch(rs->sr_type) {
 
106
        case REP_SEARCH:
 
107
        case REP_SEARCHREF:
 
108
        case REP_INTERMEDIATE:
 
109
                return SLAP_CB_CONTINUE;
 
110
 
 
111
        default:
 
112
                if (rs->sr_err == LDAP_SUCCESS ||
 
113
                        rs->sr_err == LDAP_SIZELIMIT_EXCEEDED ||
 
114
                        rs->sr_err == LDAP_TIMELIMIT_EXCEEDED ||
 
115
                        rs->sr_err == LDAP_ADMINLIMIT_EXCEEDED ||
 
116
                        rs->sr_err == LDAP_NO_SUCH_OBJECT ||
 
117
                        gs->err != LDAP_SUCCESS)
 
118
                        gs->err = rs->sr_err;
 
119
                if (gs->err == LDAP_SUCCESS && gs->matched) {
 
120
                        ch_free (gs->matched);
 
121
                        gs->matched = NULL;
 
122
                        gs->matchlen = 0;
 
123
                }
 
124
                if (gs->err != LDAP_SUCCESS && rs->sr_matched) {
 
125
                        int len;
 
126
                        len = strlen (rs->sr_matched);
 
127
                        if (len > gs->matchlen) {
 
128
                                if (gs->matched)
 
129
                                        ch_free (gs->matched);
 
130
                                gs->matched = ch_strdup (rs->sr_matched);
 
131
                                gs->matchlen = len;
 
132
                        }
 
133
                }
 
134
                if (rs->sr_ref) {
 
135
                        int i, j, k;
 
136
                        BerVarray new;
 
137
 
 
138
                        for (i=0; rs->sr_ref[i].bv_val; i++);
 
139
 
 
140
                        j = gs->nrefs;
 
141
                        if (!j) {
 
142
                                new = ch_malloc ((i+1)*sizeof(struct berval));
 
143
                        } else {
 
144
                                new = ch_realloc(gs->refs,
 
145
                                        (j+i+1)*sizeof(struct berval));
 
146
                        }
 
147
                        for (k=0; k<i; j++,k++) {
 
148
                                ber_dupbv( &new[j], &rs->sr_ref[k] );
 
149
                        }
 
150
                        new[j].bv_val = NULL;
 
151
                        gs->nrefs = j;
 
152
                        gs->refs = new;
 
153
                }
 
154
                if (rs->sr_ctrls) {
 
155
                        int i, j, k;
 
156
                        LDAPControl **newctrls;
 
157
 
 
158
                        for (i=0; rs->sr_ctrls[i]; i++);
 
159
 
 
160
                        j = gs->nctrls;
 
161
                        if (!j) {
 
162
                                newctrls = ch_malloc((i+1)*sizeof(LDAPControl *));
 
163
                        } else {
 
164
                                /* Forget old pagedResults response if we're sending
 
165
                                 * a new one now
 
166
                                 */
 
167
                                if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED ) {
 
168
                                        int newpage = 0;
 
169
                                        for ( k=0; k<i; k++ ) {
 
170
                                                if ( !strcmp(rs->sr_ctrls[k]->ldctl_oid,
 
171
                                                        LDAP_CONTROL_PAGEDRESULTS )) {
 
172
                                                        newpage = 1;
 
173
                                                        break;
 
174
                                                }
 
175
                                        }
 
176
                                        if ( newpage ) {
 
177
                                                for ( k=0; k<j; k++ ) {
 
178
                                                        if ( !strcmp(gs->ctrls[k]->ldctl_oid,
 
179
                                                                LDAP_CONTROL_PAGEDRESULTS )) {
 
180
                                                                        gs->ctrls[k]->ldctl_oid = NULL;
 
181
                                                                        ldap_control_free( gs->ctrls[k] );
 
182
                                                                        gs->ctrls[k] = gs->ctrls[--j];
 
183
                                                                        gs->ctrls[j] = NULL;
 
184
                                                                        break;
 
185
                                                        }
 
186
                                                }
 
187
                                        }
 
188
                                }
 
189
                                newctrls = ch_realloc(gs->ctrls,
 
190
                                        (j+i+1)*sizeof(LDAPControl *));
 
191
                        }
 
192
                        for (k=0; k<i; j++,k++) {
 
193
                                newctrls[j] = ch_malloc(sizeof(LDAPControl));
 
194
                                *newctrls[j] = *rs->sr_ctrls[k];
 
195
                                if ( !BER_BVISNULL( &rs->sr_ctrls[k]->ldctl_value ))
 
196
                                        ber_dupbv( &newctrls[j]->ldctl_value,
 
197
                                                &rs->sr_ctrls[k]->ldctl_value );
 
198
                        }
 
199
                        newctrls[j] = NULL;
 
200
                        gs->nctrls = j;
 
201
                        gs->ctrls = newctrls;
 
202
                }
 
203
        }
 
204
        return 0;
 
205
}
 
206
 
 
207
static int
 
208
glue_op_func ( Operation *op, SlapReply *rs )
 
209
{
 
210
        slap_overinst   *on = (slap_overinst *)op->o_bd->bd_info;
 
211
        BackendDB *b0 = op->o_bd;
 
212
        BackendInfo *bi0 = op->o_bd->bd_info;
 
213
        BI_op_modify **func;
 
214
        slap_operation_t which = op_bind;
 
215
        int rc;
 
216
 
 
217
        op->o_bd = glue_back_select (b0, &op->o_req_ndn);
 
218
 
 
219
        /* If we're on the master backend, let overlay framework handle it */
 
220
        if ( op->o_bd == b0 )
 
221
                return SLAP_CB_CONTINUE;
 
222
 
 
223
        b0->bd_info = on->on_info->oi_orig;
 
224
 
 
225
        switch(op->o_tag) {
 
226
        case LDAP_REQ_ADD: which = op_add; break;
 
227
        case LDAP_REQ_DELETE: which = op_delete; break;
 
228
        case LDAP_REQ_MODIFY: which = op_modify; break;
 
229
        case LDAP_REQ_MODRDN: which = op_modrdn; break;
 
230
        case LDAP_REQ_EXTENDED: which = op_extended; break;
 
231
        default: assert( 0 ); break;
 
232
        }
 
233
 
 
234
        func = &op->o_bd->bd_info->bi_op_bind;
 
235
        if ( func[which] )
 
236
                rc = func[which]( op, rs );
 
237
        else
 
238
                rc = SLAP_CB_BYPASS;
 
239
 
 
240
        op->o_bd = b0;
 
241
        op->o_bd->bd_info = bi0;
 
242
        return rc;
 
243
}
 
244
 
 
245
static int
 
246
glue_response ( Operation *op, SlapReply *rs )
 
247
{
 
248
        BackendDB *be = op->o_bd;
 
249
        be = glue_back_select (op->o_bd, &op->o_req_ndn);
 
250
 
 
251
        /* If we're on the master backend, let overlay framework handle it.
 
252
         * Otherwise, bail out.
 
253
         */
 
254
        return ( op->o_bd == be ) ? SLAP_CB_CONTINUE : SLAP_CB_BYPASS;
 
255
}
 
256
 
 
257
static int
 
258
glue_chk_referrals ( Operation *op, SlapReply *rs )
 
259
{
 
260
        slap_overinst   *on = (slap_overinst *)op->o_bd->bd_info;
 
261
        BackendDB *b0 = op->o_bd;
 
262
        BackendInfo *bi0 = op->o_bd->bd_info;
 
263
        int rc;
 
264
 
 
265
        op->o_bd = glue_back_select (b0, &op->o_req_ndn);
 
266
        if ( op->o_bd == b0 )
 
267
                return SLAP_CB_CONTINUE;
 
268
 
 
269
        b0->bd_info = on->on_info->oi_orig;
 
270
 
 
271
        if ( op->o_bd->bd_info->bi_chk_referrals )
 
272
                rc = ( *op->o_bd->bd_info->bi_chk_referrals )( op, rs );
 
273
        else
 
274
                rc = SLAP_CB_CONTINUE;
 
275
 
 
276
        op->o_bd = b0;
 
277
        op->o_bd->bd_info = bi0;
 
278
        return rc;
 
279
}
 
280
 
 
281
static int
 
282
glue_chk_controls ( Operation *op, SlapReply *rs )
 
283
{
 
284
        slap_overinst   *on = (slap_overinst *)op->o_bd->bd_info;
 
285
        BackendDB *b0 = op->o_bd;
 
286
        BackendInfo *bi0 = op->o_bd->bd_info;
 
287
        int rc = SLAP_CB_CONTINUE;
 
288
 
 
289
        op->o_bd = glue_back_select (b0, &op->o_req_ndn);
 
290
        if ( op->o_bd == b0 )
 
291
                return SLAP_CB_CONTINUE;
 
292
 
 
293
        b0->bd_info = on->on_info->oi_orig;
 
294
 
 
295
        /* if the subordinate database has overlays, the bi_chk_controls()
 
296
         * hook is actually over_aux_chk_controls(); in case it actually
 
297
         * wraps a missing hok, we need to mimic the behavior
 
298
         * of the frontend applied to that database */
 
299
        if ( op->o_bd->bd_info->bi_chk_controls ) {
 
300
                rc = ( *op->o_bd->bd_info->bi_chk_controls )( op, rs );
 
301
        }
 
302
 
 
303
        
 
304
        if ( rc == SLAP_CB_CONTINUE ) {
 
305
                rc = backend_check_controls( op, rs );
 
306
        }
 
307
 
 
308
        op->o_bd = b0;
 
309
        op->o_bd->bd_info = bi0;
 
310
        return rc;
 
311
}
 
312
 
 
313
/* ITS#4615 - overlays configured above the glue overlay should be
 
314
 * invoked for the entire glued tree. Overlays configured below the
 
315
 * glue overlay should only be invoked on the master backend.
 
316
 * So, if we're searching on any subordinates, we need to force the
 
317
 * current overlay chain to stop processing, without stopping the
 
318
 * overall callback flow.
 
319
 */
 
320
static int
 
321
glue_sub_search( Operation *op, SlapReply *rs, BackendDB *b0,
 
322
        slap_overinst *on )
 
323
{
 
324
        /* Process any overlays on the master backend */
 
325
        if ( op->o_bd == b0 && on->on_next ) {
 
326
                BackendInfo *bi = op->o_bd->bd_info;
 
327
                int rc = SLAP_CB_CONTINUE;
 
328
                for ( on=on->on_next; on; on=on->on_next ) {
 
329
                        op->o_bd->bd_info = (BackendInfo *)on;
 
330
                        if ( on->on_bi.bi_op_search ) {
 
331
                                rc = on->on_bi.bi_op_search( op, rs );
 
332
                                if ( rc != SLAP_CB_CONTINUE )
 
333
                                        break;
 
334
                        }
 
335
                }
 
336
                op->o_bd->bd_info = bi;
 
337
                if ( rc != SLAP_CB_CONTINUE )
 
338
                        return rc;
 
339
        }
 
340
        return op->o_bd->be_search( op, rs );
 
341
}
 
342
 
 
343
static int
 
344
glue_op_search ( Operation *op, SlapReply *rs )
 
345
{
 
346
        slap_overinst   *on = (slap_overinst *)op->o_bd->bd_info;
 
347
        glueinfo                *gi = (glueinfo *)on->on_bi.bi_private;
 
348
        BackendDB *b0 = op->o_bd;
 
349
        BackendDB *b1 = NULL, *btmp;
 
350
        BackendInfo *bi0 = op->o_bd->bd_info;
 
351
        int i;
 
352
        long stoptime = 0, starttime;
 
353
        glue_state gs = {NULL, NULL, NULL, 0, 0, 0, 0};
 
354
        slap_callback cb = { NULL, glue_op_response, glue_op_cleanup, NULL };
 
355
        int scope0, tlimit0;
 
356
        struct berval dn, ndn, *pdn;
 
357
 
 
358
        cb.sc_private = &gs;
 
359
 
 
360
        cb.sc_next = op->o_callback;
 
361
 
 
362
        starttime = op->o_time;
 
363
        stoptime = slap_get_time () + op->ors_tlimit;
 
364
 
 
365
        op->o_bd = glue_back_select (b0, &op->o_req_ndn);
 
366
        b0->bd_info = on->on_info->oi_orig;
 
367
 
 
368
        switch (op->ors_scope) {
 
369
        case LDAP_SCOPE_BASE:
 
370
                if ( op->o_bd == b0 )
 
371
                        return SLAP_CB_CONTINUE;
 
372
 
 
373
                rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
 
374
                if (op->o_bd && op->o_bd->be_search) {
 
375
                        rs->sr_err = op->o_bd->be_search( op, rs );
 
376
                }
 
377
                return rs->sr_err;
 
378
 
 
379
        case LDAP_SCOPE_ONELEVEL:
 
380
        case LDAP_SCOPE_SUBTREE:
 
381
        case LDAP_SCOPE_SUBORDINATE: /* FIXME */
 
382
                op->o_callback = &cb;
 
383
                rs->sr_err = gs.err = LDAP_UNWILLING_TO_PERFORM;
 
384
                scope0 = op->ors_scope;
 
385
                tlimit0 = op->ors_tlimit;
 
386
                dn = op->o_req_dn;
 
387
                ndn = op->o_req_ndn;
 
388
                b1 = op->o_bd;
 
389
 
 
390
                /*
 
391
                 * Execute in reverse order, most specific first 
 
392
                 */
 
393
                for (i = gi->gi_nodes; i >= 0; i--) {
 
394
                        if ( i == gi->gi_nodes ) {
 
395
                                btmp = b0;
 
396
                                pdn = &gi->gi_pdn;
 
397
                        } else {
 
398
                                btmp = gi->gi_n[i].gn_be;
 
399
                                pdn = &gi->gi_n[i].gn_pdn;
 
400
                        }
 
401
                        if (!btmp || !btmp->be_search)
 
402
                                continue;
 
403
                        if (!dnIsSuffix(&btmp->be_nsuffix[0], &b1->be_nsuffix[0]))
 
404
                                continue;
 
405
                        if (get_no_subordinate_glue(op) && btmp != b1)
 
406
                                continue;
 
407
                        /* If we remembered which backend we were on before,
 
408
                         * skip down to it now
 
409
                         */
 
410
                        if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED &&
 
411
                                op->o_conn->c_pagedresults_state.ps_be &&
 
412
                                op->o_conn->c_pagedresults_state.ps_be != btmp )
 
413
                                continue;
 
414
 
 
415
                        if (tlimit0 != SLAP_NO_LIMIT) {
 
416
                                op->o_time = slap_get_time();
 
417
                                op->ors_tlimit = stoptime - op->o_time;
 
418
                                if (op->ors_tlimit <= 0) {
 
419
                                        rs->sr_err = gs.err = LDAP_TIMELIMIT_EXCEEDED;
 
420
                                        break;
 
421
                                }
 
422
                        }
 
423
                        rs->sr_err = 0;
 
424
                        /*
 
425
                         * check for abandon 
 
426
                         */
 
427
                        if (op->o_abandon) {
 
428
                                goto end_of_loop;
 
429
                        }
 
430
                        op->o_bd = btmp;
 
431
 
 
432
                        assert( op->o_bd->be_suffix != NULL );
 
433
                        assert( op->o_bd->be_nsuffix != NULL );
 
434
                        
 
435
                        if (scope0 == LDAP_SCOPE_ONELEVEL && 
 
436
                                dn_match(pdn, &ndn))
 
437
                        {
 
438
                                op->ors_scope = LDAP_SCOPE_BASE;
 
439
                                op->o_req_dn = op->o_bd->be_suffix[0];
 
440
                                op->o_req_ndn = op->o_bd->be_nsuffix[0];
 
441
                                rs->sr_err = op->o_bd->be_search(op, rs);
 
442
                                if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) {
 
443
                                        gs.err = LDAP_SUCCESS;
 
444
                                }
 
445
                                op->ors_scope = LDAP_SCOPE_ONELEVEL;
 
446
                                op->o_req_dn = dn;
 
447
                                op->o_req_ndn = ndn;
 
448
 
 
449
                        } else if (scope0 == LDAP_SCOPE_SUBTREE &&
 
450
                                dn_match(&op->o_bd->be_nsuffix[0], &ndn))
 
451
                        {
 
452
                                rs->sr_err = glue_sub_search( op, rs, b0, on );
 
453
 
 
454
                        } else if (scope0 == LDAP_SCOPE_SUBTREE &&
 
455
                                dnIsSuffix(&op->o_bd->be_nsuffix[0], &ndn))
 
456
                        {
 
457
                                op->o_req_dn = op->o_bd->be_suffix[0];
 
458
                                op->o_req_ndn = op->o_bd->be_nsuffix[0];
 
459
                                rs->sr_err = glue_sub_search( op, rs, b0, on );
 
460
                                if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) {
 
461
                                        gs.err = LDAP_SUCCESS;
 
462
                                }
 
463
                                op->o_req_dn = dn;
 
464
                                op->o_req_ndn = ndn;
 
465
 
 
466
                        } else if (dnIsSuffix(&ndn, &op->o_bd->be_nsuffix[0])) {
 
467
                                rs->sr_err = glue_sub_search( op, rs, b0, on );
 
468
                        }
 
469
 
 
470
                        switch ( gs.err ) {
 
471
 
 
472
                        /*
 
473
                         * Add errors that should result in dropping
 
474
                         * the search
 
475
                         */
 
476
                        case LDAP_SIZELIMIT_EXCEEDED:
 
477
                        case LDAP_TIMELIMIT_EXCEEDED:
 
478
                        case LDAP_ADMINLIMIT_EXCEEDED:
 
479
                        case LDAP_NO_SUCH_OBJECT:
 
480
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
 
481
                        case LDAP_X_CANNOT_CHAIN:
 
482
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
 
483
                                goto end_of_loop;
 
484
 
 
485
                        case LDAP_SUCCESS:
 
486
                                if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED ) {
 
487
                                        PagedResultsState *ps = op->o_pagedresults_state;
 
488
 
 
489
                                        /* Assume this backend can be forgotten now */
 
490
                                        op->o_conn->c_pagedresults_state.ps_be = NULL;
 
491
 
 
492
                                        /* If we have a full page, exit the loop. We may
 
493
                                         * need to remember this backend so we can continue
 
494
                                         * from here on a subsequent request.
 
495
                                         */
 
496
                                        if ( rs->sr_nentries >= ps->ps_size ) {
 
497
                                                /* Don't bother to remember the first backend.
 
498
                                                 * Only remember the last one if there's more state left.
 
499
                                                 */
 
500
                                                if ( op->o_bd != b0 &&
 
501
                                                        ( op->o_conn->c_pagedresults_state.ps_cookie ||
 
502
                                                        op->o_bd != gi->gi_n[0].gn_be ))
 
503
                                                        op->o_conn->c_pagedresults_state.ps_be = op->o_bd;
 
504
                                                goto end_of_loop;
 
505
                                        }
 
506
 
 
507
                                        /* This backend has run out of entries, but more responses
 
508
                                         * can fit in the page. Fake a reset of the state so the
 
509
                                         * next backend will start up properly. Only back-[bh]db
 
510
                                         * and back-sql look at this state info.
 
511
                                         */
 
512
                                        if ( ps->ps_cookieval.bv_len == sizeof( PagedResultsCookie )) {
 
513
                                                ps->ps_cookie = 0;
 
514
                                                memset( ps->ps_cookieval.bv_val, 0,
 
515
                                                        sizeof( PagedResultsCookie ));
 
516
                                        }
 
517
                                }
 
518
                                
 
519
                        default:
 
520
                                break;
 
521
                        }
 
522
                }
 
523
end_of_loop:;
 
524
                op->ors_scope = scope0;
 
525
                op->ors_tlimit = tlimit0;
 
526
                op->o_time = starttime;
 
527
                op->o_req_dn = dn;
 
528
                op->o_req_ndn = ndn;
 
529
 
 
530
                break;
 
531
        }
 
532
        if ( op->o_abandon ) {
 
533
                rs->sr_err = SLAPD_ABANDON;
 
534
        } else {
 
535
                op->o_callback = cb.sc_next;
 
536
                rs->sr_err = gs.err;
 
537
                rs->sr_matched = gs.matched;
 
538
                rs->sr_ref = gs.refs;
 
539
                rs->sr_ctrls = gs.ctrls;
 
540
 
 
541
                send_ldap_result( op, rs );
 
542
        }
 
543
 
 
544
        op->o_bd = b0;
 
545
        op->o_bd->bd_info = bi0;
 
546
        if (gs.matched)
 
547
                free (gs.matched);
 
548
        if (gs.refs)
 
549
                ber_bvarray_free(gs.refs);
 
550
        if (gs.ctrls) {
 
551
                for (i = gs.nctrls; --i >= 0; ) {
 
552
                        if (!BER_BVISNULL( &gs.ctrls[i]->ldctl_value ))
 
553
                                free(gs.ctrls[i]->ldctl_value.bv_val);
 
554
                        free(gs.ctrls[i]);
 
555
                }
 
556
                free(gs.ctrls);
 
557
        }
 
558
        return rs->sr_err;
 
559
}
 
560
 
 
561
static BackendDB toolDB;
 
562
 
 
563
static int
 
564
glue_tool_entry_open (
 
565
        BackendDB *b0,
 
566
        int mode
 
567
)
 
568
{
 
569
        slap_overinfo   *oi = (slap_overinfo *)b0->bd_info;
 
570
 
 
571
        /* We don't know which backend to talk to yet, so just
 
572
         * remember the mode and move on...
 
573
         */
 
574
 
 
575
        glueMode = mode;
 
576
        glueBack = NULL;
 
577
        toolDB = *b0;
 
578
        toolDB.bd_info = oi->oi_orig;
 
579
 
 
580
        return 0;
 
581
}
 
582
 
 
583
static int
 
584
glue_tool_entry_close (
 
585
        BackendDB *b0
 
586
)
 
587
{
 
588
        int rc = 0;
 
589
 
 
590
        if (glueBack) {
 
591
                if (!glueBack->be_entry_close)
 
592
                        return 0;
 
593
                rc = glueBack->be_entry_close (glueBack);
 
594
        }
 
595
        return rc;
 
596
}
 
597
 
 
598
static slap_overinst *
 
599
glue_tool_inst(
 
600
        BackendInfo *bi
 
601
)
 
602
{
 
603
        slap_overinfo   *oi = (slap_overinfo *)bi;
 
604
        slap_overinst   *on;
 
605
 
 
606
        for ( on = oi->oi_list; on; on=on->on_next ) {
 
607
                if ( !strcmp( on->on_bi.bi_type, glue.on_bi.bi_type ))
 
608
                        return on;
 
609
        }
 
610
        return NULL;
 
611
}
 
612
 
 
613
/* This function will only be called in tool mode */
 
614
static int
 
615
glue_open (
 
616
        BackendInfo *bi
 
617
)
 
618
{
 
619
        slap_overinst *on = glue_tool_inst( bi );
 
620
        glueinfo                *gi = on->on_bi.bi_private;
 
621
        static int glueOpened = 0;
 
622
        int i, j, same, bsame = 0, rc = 0;
 
623
        ConfigReply cr = {0};
 
624
 
 
625
        if (glueOpened) return 0;
 
626
 
 
627
        glueOpened = 1;
 
628
 
 
629
        /* If we were invoked in tool mode, open all the underlying backends */
 
630
        if (slapMode & SLAP_TOOL_MODE) {
 
631
                for (i = 0; i<gi->gi_nodes; i++) {
 
632
                        same = 0;
 
633
                        /* Same bi_open as our main backend? */
 
634
                        if ( gi->gi_n[i].gn_be->bd_info->bi_open ==
 
635
                                on->on_info->oi_orig->bi_open )
 
636
                                bsame = 1;
 
637
 
 
638
                        /* Loop thru the bd_info's and make sure we only
 
639
                         * invoke their bi_open functions once each.
 
640
                         */
 
641
                        for ( j = 0; j<i; j++ ) {
 
642
                                if ( gi->gi_n[i].gn_be->bd_info->bi_open ==
 
643
                                        gi->gi_n[j].gn_be->bd_info->bi_open ) {
 
644
                                        same = 1;
 
645
                                        break;
 
646
                                }
 
647
                        }
 
648
                        /* OK, it's unique and non-NULL, call it. */
 
649
                        if ( !same && gi->gi_n[i].gn_be->bd_info->bi_open )
 
650
                                rc = gi->gi_n[i].gn_be->bd_info->bi_open(
 
651
                                        gi->gi_n[i].gn_be->bd_info );
 
652
                        /* Let backend.c take care of the rest of startup */
 
653
                        if ( !rc )
 
654
                                rc = backend_startup_one( gi->gi_n[i].gn_be, &cr );
 
655
                        if ( rc ) break;
 
656
                }
 
657
                if ( !rc && !bsame && on->on_info->oi_orig->bi_open )
 
658
                        rc = on->on_info->oi_orig->bi_open( on->on_info->oi_orig );
 
659
 
 
660
        } /* other case is impossible */
 
661
        return rc;
 
662
}
 
663
 
 
664
/* This function will only be called in tool mode */
 
665
static int
 
666
glue_close (
 
667
        BackendInfo *bi
 
668
)
 
669
{
 
670
        static int glueClosed = 0;
 
671
        int rc = 0;
 
672
 
 
673
        if (glueClosed) return 0;
 
674
 
 
675
        glueClosed = 1;
 
676
 
 
677
        if (slapMode & SLAP_TOOL_MODE) {
 
678
                rc = backend_shutdown( NULL );
 
679
        }
 
680
        return rc;
 
681
}
 
682
 
 
683
static int
 
684
glue_entry_get_rw (
 
685
        Operation               *op,
 
686
        struct berval   *dn,
 
687
        ObjectClass             *oc,
 
688
        AttributeDescription    *ad,
 
689
        int     rw,
 
690
        Entry   **e )
 
691
{
 
692
        int rc;
 
693
        BackendDB *b0 = op->o_bd;
 
694
        op->o_bd = glue_back_select( b0, dn );
 
695
 
 
696
        if ( op->o_bd->be_fetch ) {
 
697
                rc = op->o_bd->be_fetch( op, dn, oc, ad, rw, e );
 
698
        } else {
 
699
                rc = LDAP_UNWILLING_TO_PERFORM;
 
700
        }
 
701
        op->o_bd =b0;
 
702
        return rc;
 
703
}
 
704
 
 
705
static int
 
706
glue_entry_release_rw (
 
707
        Operation *op,
 
708
        Entry *e,
 
709
        int rw
 
710
)
 
711
{
 
712
        BackendDB *b0 = op->o_bd;
 
713
        int rc = -1;
 
714
 
 
715
        op->o_bd = glue_back_select (b0, &e->e_nname);
 
716
 
 
717
        if ( op->o_bd->be_release ) {
 
718
                rc = op->o_bd->be_release( op, e, rw );
 
719
 
 
720
        } else {
 
721
                /* FIXME: mimic be_entry_release_rw
 
722
                 * when no be_release() available */
 
723
                /* free entry */
 
724
                entry_free( e );
 
725
                rc = 0;
 
726
        }
 
727
        op->o_bd = b0;
 
728
        return rc;
 
729
}
 
730
 
 
731
static ID
 
732
glue_tool_entry_first (
 
733
        BackendDB *b0
 
734
)
 
735
{
 
736
        slap_overinst   *on = glue_tool_inst( b0->bd_info );
 
737
        glueinfo                *gi = on->on_bi.bi_private;
 
738
        int i;
 
739
 
 
740
        /* If we're starting from scratch, start at the most general */
 
741
        if (!glueBack) {
 
742
                if ( toolDB.be_entry_open && toolDB.be_entry_first ) {
 
743
                        glueBack = &toolDB;
 
744
                } else {
 
745
                        for (i = gi->gi_nodes-1; i >= 0; i--) {
 
746
                                if (gi->gi_n[i].gn_be->be_entry_open &&
 
747
                                        gi->gi_n[i].gn_be->be_entry_first) {
 
748
                                                glueBack = gi->gi_n[i].gn_be;
 
749
                                        break;
 
750
                                }
 
751
                        }
 
752
                }
 
753
        }
 
754
        if (!glueBack || !glueBack->be_entry_open || !glueBack->be_entry_first ||
 
755
                glueBack->be_entry_open (glueBack, glueMode) != 0)
 
756
                return NOID;
 
757
 
 
758
        return glueBack->be_entry_first (glueBack);
 
759
}
 
760
 
 
761
static ID
 
762
glue_tool_entry_next (
 
763
        BackendDB *b0
 
764
)
 
765
{
 
766
        slap_overinst   *on = glue_tool_inst( b0->bd_info );
 
767
        glueinfo                *gi = on->on_bi.bi_private;
 
768
        int i;
 
769
        ID rc;
 
770
 
 
771
        if (!glueBack || !glueBack->be_entry_next)
 
772
                return NOID;
 
773
 
 
774
        rc = glueBack->be_entry_next (glueBack);
 
775
 
 
776
        /* If we ran out of entries in one database, move on to the next */
 
777
        while (rc == NOID) {
 
778
                if ( glueBack && glueBack->be_entry_close )
 
779
                        glueBack->be_entry_close (glueBack);
 
780
                for (i=0; i<gi->gi_nodes; i++) {
 
781
                        if (gi->gi_n[i].gn_be == glueBack)
 
782
                                break;
 
783
                }
 
784
                if (i == 0) {
 
785
                        glueBack = NULL;
 
786
                        break;
 
787
                } else {
 
788
                        glueBack = gi->gi_n[i-1].gn_be;
 
789
                        rc = glue_tool_entry_first (b0);
 
790
                }
 
791
        }
 
792
        return rc;
 
793
}
 
794
 
 
795
static ID
 
796
glue_tool_dn2id_get (
 
797
        BackendDB *b0,
 
798
        struct berval *dn
 
799
)
 
800
{
 
801
        BackendDB *be, b2;
 
802
        int rc = -1;
 
803
 
 
804
        b2 = *b0;
 
805
        b2.bd_info = (BackendInfo *)glue_tool_inst( b0->bd_info );
 
806
        be = glue_back_select (&b2, dn);
 
807
        if ( be == &b2 ) be = &toolDB;
 
808
 
 
809
        if (!be->be_dn2id_get)
 
810
                return NOID;
 
811
 
 
812
        if (!glueBack) {
 
813
                if ( be->be_entry_open ) {
 
814
                        rc = be->be_entry_open (be, glueMode);
 
815
                }
 
816
                if (rc != 0) {
 
817
                        return NOID;
 
818
                }
 
819
        } else if (be != glueBack) {
 
820
                /* If this entry belongs in a different branch than the
 
821
                 * previous one, close the current database and open the
 
822
                 * new one.
 
823
                 */
 
824
                if ( glueBack->be_entry_close ) {
 
825
                        glueBack->be_entry_close (glueBack);
 
826
                }
 
827
                if ( be->be_entry_open ) {
 
828
                        rc = be->be_entry_open (be, glueMode);
 
829
                }
 
830
                if (rc != 0) {
 
831
                        return NOID;
 
832
                }
 
833
        }
 
834
        glueBack = be;
 
835
        return be->be_dn2id_get (be, dn);
 
836
}
 
837
 
 
838
static Entry *
 
839
glue_tool_entry_get (
 
840
        BackendDB *b0,
 
841
        ID id
 
842
)
 
843
{
 
844
        if (!glueBack || !glueBack->be_entry_get)
 
845
                return NULL;
 
846
 
 
847
        return glueBack->be_entry_get (glueBack, id);
 
848
}
 
849
 
 
850
static ID
 
851
glue_tool_entry_put (
 
852
        BackendDB *b0,
 
853
        Entry *e,
 
854
        struct berval *text
 
855
)
 
856
{
 
857
        BackendDB *be, b2;
 
858
        int rc = -1;
 
859
 
 
860
        b2 = *b0;
 
861
        b2.bd_info = (BackendInfo *)glue_tool_inst( b0->bd_info );
 
862
        be = glue_back_select (&b2, &e->e_nname);
 
863
        if ( be == &b2 ) be = &toolDB;
 
864
 
 
865
        if (!be->be_entry_put)
 
866
                return NOID;
 
867
 
 
868
        if (!glueBack) {
 
869
                if ( be->be_entry_open ) {
 
870
                        rc = be->be_entry_open (be, glueMode);
 
871
                }
 
872
                if (rc != 0) {
 
873
                        return NOID;
 
874
                }
 
875
        } else if (be != glueBack) {
 
876
                /* If this entry belongs in a different branch than the
 
877
                 * previous one, close the current database and open the
 
878
                 * new one.
 
879
                 */
 
880
                if ( glueBack->be_entry_close ) {
 
881
                        glueBack->be_entry_close (glueBack);
 
882
                }
 
883
                if ( be->be_entry_open ) {
 
884
                        rc = be->be_entry_open (be, glueMode);
 
885
                }
 
886
                if (rc != 0) {
 
887
                        return NOID;
 
888
                }
 
889
        }
 
890
        glueBack = be;
 
891
        return be->be_entry_put (be, e, text);
 
892
}
 
893
 
 
894
static ID
 
895
glue_tool_entry_modify (
 
896
        BackendDB *b0,
 
897
        Entry *e,
 
898
        struct berval *text
 
899
)
 
900
{
 
901
        if (!glueBack || !glueBack->be_entry_modify)
 
902
                return NOID;
 
903
 
 
904
        return glueBack->be_entry_modify (glueBack, e, text);
 
905
}
 
906
 
 
907
static int
 
908
glue_tool_entry_reindex (
 
909
        BackendDB *b0,
 
910
        ID id,
 
911
        AttributeDescription **adv
 
912
)
 
913
{
 
914
        if (!glueBack || !glueBack->be_entry_reindex)
 
915
                return -1;
 
916
 
 
917
        return glueBack->be_entry_reindex (glueBack, id, adv);
 
918
}
 
919
 
 
920
static int
 
921
glue_tool_sync (
 
922
        BackendDB *b0
 
923
)
 
924
{
 
925
        slap_overinst   *on = glue_tool_inst( b0->bd_info );
 
926
        glueinfo                *gi = on->on_bi.bi_private;
 
927
        BackendInfo             *bi = b0->bd_info;
 
928
        int i;
 
929
 
 
930
        /* just sync everyone */
 
931
        for (i = 0; i<gi->gi_nodes; i++)
 
932
                if (gi->gi_n[i].gn_be->be_sync)
 
933
                        gi->gi_n[i].gn_be->be_sync (gi->gi_n[i].gn_be);
 
934
        b0->bd_info = on->on_info->oi_orig;
 
935
        if ( b0->be_sync )
 
936
                b0->be_sync( b0 );
 
937
        b0->bd_info = bi;
 
938
        return 0;
 
939
}
 
940
 
 
941
static int
 
942
glue_db_init(
 
943
        BackendDB *be,
 
944
        ConfigReply *cr
 
945
)
 
946
{
 
947
        slap_overinst   *on = (slap_overinst *)be->bd_info;
 
948
        slap_overinfo   *oi = on->on_info;
 
949
        BackendInfo     *bi = oi->oi_orig;
 
950
        glueinfo *gi;
 
951
 
 
952
        if ( SLAP_GLUE_SUBORDINATE( be )) {
 
953
                Debug( LDAP_DEBUG_ANY, "glue: backend %s is already subordinate, "
 
954
                        "cannot have glue overlay!\n",
 
955
                        be->be_suffix[0].bv_val, 0, 0 );
 
956
                return LDAP_OTHER;
 
957
        }
 
958
 
 
959
        gi = ch_calloc( 1, sizeof(glueinfo));
 
960
        on->on_bi.bi_private = gi;
 
961
        dnParent( be->be_nsuffix, &gi->gi_pdn );
 
962
 
 
963
        /* Currently the overlay framework doesn't handle these entry points
 
964
         * but we need them....
 
965
         */
 
966
        oi->oi_bi.bi_open = glue_open;
 
967
        oi->oi_bi.bi_close = glue_close;
 
968
 
 
969
        /* Only advertise these if the root DB supports them */
 
970
        if ( bi->bi_tool_entry_open )
 
971
                oi->oi_bi.bi_tool_entry_open = glue_tool_entry_open;
 
972
        if ( bi->bi_tool_entry_close )
 
973
                oi->oi_bi.bi_tool_entry_close = glue_tool_entry_close;
 
974
        if ( bi->bi_tool_entry_first )
 
975
                oi->oi_bi.bi_tool_entry_first = glue_tool_entry_first;
 
976
        if ( bi->bi_tool_entry_next )
 
977
                oi->oi_bi.bi_tool_entry_next = glue_tool_entry_next;
 
978
        if ( bi->bi_tool_entry_get )
 
979
                oi->oi_bi.bi_tool_entry_get = glue_tool_entry_get;
 
980
        if ( bi->bi_tool_dn2id_get )
 
981
                oi->oi_bi.bi_tool_dn2id_get = glue_tool_dn2id_get;
 
982
        if ( bi->bi_tool_entry_put )
 
983
                oi->oi_bi.bi_tool_entry_put = glue_tool_entry_put;
 
984
        if ( bi->bi_tool_entry_reindex )
 
985
                oi->oi_bi.bi_tool_entry_reindex = glue_tool_entry_reindex;
 
986
        if ( bi->bi_tool_entry_modify )
 
987
                oi->oi_bi.bi_tool_entry_modify = glue_tool_entry_modify;
 
988
        if ( bi->bi_tool_sync )
 
989
                oi->oi_bi.bi_tool_sync = glue_tool_sync;
 
990
 
 
991
        SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_GLUE_INSTANCE;
 
992
 
 
993
        return 0;
 
994
}
 
995
 
 
996
static int
 
997
glue_db_destroy (
 
998
        BackendDB *be,
 
999
        ConfigReply *cr
 
1000
)
 
1001
{
 
1002
        slap_overinst   *on = (slap_overinst *)be->bd_info;
 
1003
        glueinfo                *gi = (glueinfo *)on->on_bi.bi_private;
 
1004
 
 
1005
        free (gi);
 
1006
        return SLAP_CB_CONTINUE;
 
1007
}
 
1008
 
 
1009
static int
 
1010
glue_db_close( 
 
1011
        BackendDB *be,
 
1012
        ConfigReply *cr
 
1013
)
 
1014
{
 
1015
        slap_overinst   *on = (slap_overinst *)be->bd_info;
 
1016
 
 
1017
        on->on_info->oi_bi.bi_db_close = 0;
 
1018
        return 0;
 
1019
}
 
1020
 
 
1021
int
 
1022
glue_sub_del( BackendDB *b0 )
 
1023
{
 
1024
        BackendDB *be;
 
1025
        int rc = 0;
 
1026
 
 
1027
        /* Find the top backend for this subordinate */
 
1028
        be = b0;
 
1029
        while ( (be=LDAP_STAILQ_NEXT( be, be_next )) != NULL ) {
 
1030
                slap_overinfo *oi;
 
1031
                slap_overinst *on;
 
1032
                glueinfo *gi;
 
1033
                int i;
 
1034
 
 
1035
                if ( SLAP_GLUE_SUBORDINATE( be ))
 
1036
                        continue;
 
1037
                if ( !SLAP_GLUE_INSTANCE( be ))
 
1038
                        continue;
 
1039
                if ( !dnIsSuffix( &b0->be_nsuffix[0], &be->be_nsuffix[0] ))
 
1040
                        continue;
 
1041
 
 
1042
                /* OK, got the right backend, find the overlay */
 
1043
                oi = (slap_overinfo *)be->bd_info;
 
1044
                for ( on=oi->oi_list; on; on=on->on_next ) {
 
1045
                        if ( on->on_bi.bi_type == glue.on_bi.bi_type )
 
1046
                                break;
 
1047
                }
 
1048
                assert( on != NULL );
 
1049
                gi = on->on_bi.bi_private;
 
1050
                for ( i=0; i < gi->gi_nodes; i++ ) {
 
1051
                        if ( gi->gi_n[i].gn_be == b0 ) {
 
1052
                                int j;
 
1053
 
 
1054
                                for (j=i+1; j < gi->gi_nodes; j++)
 
1055
                                        gi->gi_n[j-1] = gi->gi_n[j];
 
1056
 
 
1057
                                gi->gi_nodes--;
 
1058
                        }
 
1059
                }
 
1060
        }
 
1061
        if ( be == NULL )
 
1062
                rc = LDAP_NO_SUCH_OBJECT;
 
1063
 
 
1064
        return rc;
 
1065
}
 
1066
 
 
1067
typedef struct glue_Addrec {
 
1068
        struct glue_Addrec *ga_next;
 
1069
        BackendDB *ga_be;
 
1070
} glue_Addrec;
 
1071
 
 
1072
/* List of added subordinates */
 
1073
static glue_Addrec *ga_list;
 
1074
 
 
1075
/* Attach all the subordinate backends to their superior */
 
1076
int
 
1077
glue_sub_attach()
 
1078
{
 
1079
        glue_Addrec *ga, *gnext = NULL;
 
1080
        int rc = 0;
 
1081
 
 
1082
        /* For all the subordinate backends */
 
1083
        for ( ga=ga_list; ga != NULL; ga = gnext ) {
 
1084
                BackendDB *be;
 
1085
 
 
1086
                gnext = ga->ga_next;
 
1087
 
 
1088
                /* Find the top backend for this subordinate */
 
1089
                be = ga->ga_be;
 
1090
                while ( (be=LDAP_STAILQ_NEXT( be, be_next )) != NULL ) {
 
1091
                        slap_overinfo *oi;
 
1092
                        slap_overinst *on;
 
1093
                        glueinfo *gi;
 
1094
 
 
1095
                        if ( SLAP_GLUE_SUBORDINATE( be ))
 
1096
                                continue;
 
1097
                        if ( !dnIsSuffix( &ga->ga_be->be_nsuffix[0], &be->be_nsuffix[0] ))
 
1098
                                continue;
 
1099
 
 
1100
                        /* If it's not already configured, set up the overlay */
 
1101
                        if ( !SLAP_GLUE_INSTANCE( be )) {
 
1102
                                rc = overlay_config( be, glue.on_bi.bi_type, -1, NULL, NULL);
 
1103
                                if ( rc )
 
1104
                                        break;
 
1105
                        }
 
1106
                        /* Find the overlay instance */
 
1107
                        oi = (slap_overinfo *)be->bd_info;
 
1108
                        for ( on=oi->oi_list; on; on=on->on_next ) {
 
1109
                                if ( on->on_bi.bi_type == glue.on_bi.bi_type )
 
1110
                                        break;
 
1111
                        }
 
1112
                        assert( on != NULL );
 
1113
                        gi = on->on_bi.bi_private;
 
1114
                        gi = (glueinfo *)ch_realloc( gi, sizeof(glueinfo) +
 
1115
                                gi->gi_nodes * sizeof(gluenode));
 
1116
                        gi->gi_n[gi->gi_nodes].gn_be = ga->ga_be;
 
1117
                        dnParent( &ga->ga_be->be_nsuffix[0],
 
1118
                                &gi->gi_n[gi->gi_nodes].gn_pdn );
 
1119
                        gi->gi_nodes++;
 
1120
                        on->on_bi.bi_private = gi;
 
1121
                        break;
 
1122
                }
 
1123
                if ( !be ) {
 
1124
                        Debug( LDAP_DEBUG_ANY, "glue: no superior found for sub %s!\n",
 
1125
                                ga->ga_be->be_suffix[0].bv_val, 0, 0 );
 
1126
                        rc = LDAP_NO_SUCH_OBJECT;
 
1127
                }
 
1128
                ch_free( ga );
 
1129
                if ( rc ) break;
 
1130
        }
 
1131
 
 
1132
        ga_list = gnext;
 
1133
 
 
1134
        return rc;
 
1135
}
 
1136
 
 
1137
int
 
1138
glue_sub_add( BackendDB *be, int advert, int online )
 
1139
{
 
1140
        glue_Addrec *ga;
 
1141
        int rc = 0;
 
1142
 
 
1143
        if ( overlay_is_inst( be, "glue" )) {
 
1144
                Debug( LDAP_DEBUG_ANY, "glue: backend %s already has glue overlay, "
 
1145
                        "cannot be a subordinate!\n",
 
1146
                        be->be_suffix[0].bv_val, 0, 0 );
 
1147
                return LDAP_OTHER;
 
1148
        }
 
1149
        SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_GLUE_SUBORDINATE;
 
1150
        if ( advert )
 
1151
                SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_GLUE_ADVERTISE;
 
1152
 
 
1153
        ga = ch_malloc( sizeof( glue_Addrec ));
 
1154
        ga->ga_next = ga_list;
 
1155
        ga->ga_be = be;
 
1156
        ga_list = ga;
 
1157
 
 
1158
        if ( online )
 
1159
                rc = glue_sub_attach();
 
1160
 
 
1161
        return rc;
 
1162
}
 
1163
 
 
1164
int
 
1165
glue_sub_init()
 
1166
{
 
1167
        glue.on_bi.bi_type = "glue";
 
1168
 
 
1169
        glue.on_bi.bi_db_init = glue_db_init;
 
1170
        glue.on_bi.bi_db_close = glue_db_close;
 
1171
        glue.on_bi.bi_db_destroy = glue_db_destroy;
 
1172
 
 
1173
        glue.on_bi.bi_op_search = glue_op_search;
 
1174
        glue.on_bi.bi_op_modify = glue_op_func;
 
1175
        glue.on_bi.bi_op_modrdn = glue_op_func;
 
1176
        glue.on_bi.bi_op_add = glue_op_func;
 
1177
        glue.on_bi.bi_op_delete = glue_op_func;
 
1178
        glue.on_bi.bi_extended = glue_op_func;
 
1179
 
 
1180
        glue.on_bi.bi_chk_referrals = glue_chk_referrals;
 
1181
        glue.on_bi.bi_chk_controls = glue_chk_controls;
 
1182
        glue.on_bi.bi_entry_get_rw = glue_entry_get_rw;
 
1183
        glue.on_bi.bi_entry_release_rw = glue_entry_release_rw;
 
1184
 
 
1185
        glue.on_response = glue_response;
 
1186
 
 
1187
        return overlay_register( &glue );
 
1188
}