]> git.sur5r.net Git - openldap/blob - servers/slapd/overlays/translucent.c
38ff0039f66102fcf1bb5f19eb90dd2458bd2e25
[openldap] / servers / slapd / overlays / translucent.c
1 /* Copyright 2004, Symas Corporation.
2  * All Rights Reserved.
3  */
4
5 #include "portable.h"
6
7 #ifdef SLAPD_OVER_TRANSLUCENT
8
9 #include <stdio.h>
10
11 #include <ac/string.h>
12 #include <ac/socket.h>
13
14 #include "slap.h"
15
16 /* config block */
17
18 typedef struct translucent_configuration {
19         int debug;
20         int strict;
21         int no_add;
22         int glue;
23 } translucent_configuration;
24
25 /* stack of captive backends */
26
27 typedef struct overlay_stack {
28         BackendInfo *info;                      /* captive backend */
29         void *private;                          /* local backend_private */
30         translucent_configuration *config;      /* our_private: configuration */
31 } overlay_stack;
32
33 /* for translucent_init() */
34
35 static slap_overinst translucent;
36
37 /*
38 ** glue_parent()
39 **      call syncrepl_add_glue() with the parent suffix;
40 **
41 */
42
43 static struct berval glue[] = { BER_BVC("top"), BER_BVC("glue"), BER_BVNULL };
44
45 void glue_parent(Operation *op) {
46         Operation nop = *op;
47         slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
48         struct berval dn = { 0, NULL };
49         char *odn = op->o_req_ndn.bv_val;
50         Attribute *a;
51         Entry *e;
52         int idn, ldn;
53
54         /* tis more work to use strchr() for a berval... */
55         for(idn = 0; odn[idn] && odn[idn] != ','; idn++);
56         if(!idn || !odn[idn]) return;   /* because you never know */
57         idn++;
58         ldn = dn.bv_len = op->o_req_ndn.bv_len - idn;
59         dn.bv_val = ch_malloc(ldn + 1);
60         strcpy(dn.bv_val, odn + idn);
61
62         Debug(LDAP_DEBUG_TRACE, "=> glue_parent: fabricating glue for <%s>\n", dn.bv_val, 0, 0);
63
64         e = ch_calloc(1, sizeof(Entry));
65         e->e_id = NOID;
66         ber_dupbv(&e->e_name, &dn);
67         ber_dupbv(&e->e_nname, &dn);
68
69         a = ch_calloc(1, sizeof(Attribute));
70         a->a_desc = slap_schema.si_ad_objectClass;
71         a->a_vals = ch_malloc(sizeof(struct berval) * 3);
72         ber_dupbv(&a->a_vals[0], &glue[0]);
73         ber_dupbv(&a->a_vals[1], &glue[1]);
74         ber_dupbv(&a->a_vals[2], &glue[2]);
75         a->a_nvals = a->a_vals;
76         a->a_next = e->e_attrs;
77         e->e_attrs = a;
78
79         a = ch_calloc(1, sizeof(Attribute));
80         a->a_desc = slap_schema.si_ad_structuralObjectClass;
81         a->a_vals = ch_malloc(sizeof(struct berval) * 2);
82         ber_dupbv(&a->a_vals[0], &glue[1]);
83         ber_dupbv(&a->a_vals[1], &glue[2]);
84         a->a_nvals = a->a_vals;
85         a->a_next = e->e_attrs;
86         e->e_attrs = a;
87
88         nop.o_req_dn = dn;
89         nop.o_req_ndn = dn;
90         nop.ora_e = e;
91         nop.o_bd->bd_info = (BackendInfo *) on->on_info->oi_orig;
92
93         syncrepl_add_glue(&nop, e);
94         return;
95 }
96
97 /*
98 ** dup_bervarray()
99 **      copy a BerVarray;
100 */
101
102 BerVarray dup_bervarray(BerVarray b) {
103         int i, len;
104         BerVarray nb;
105         for(len = 0; b[len].bv_val; len++);
106         nb = ch_malloc((len+1) * sizeof(BerValue));
107         for(i = 0; i < len; i++) ber_dupbv(&nb[i], &b[i]);
108         nb[len].bv_val = NULL;
109         nb[len].bv_len = 0;
110         return(nb);
111 }
112
113 /*
114 ** free_attr_chain()
115 **      free only the Attribute*, not the contents;
116 **
117 */
118 void free_attr_chain(Attribute *a) {
119         Attribute *ax;
120         for(ax = NULL; a; a = a->a_next) {
121                 if(ax) ch_free(ax);
122                 ax = a;
123         }
124         return;
125 }
126
127 /*
128 ** translucent_add()
129 **      if not bound as root, send ACCESS error;
130 **      if config.glue, glue_parent();
131 **      return CONTINUE;
132 **
133 */
134
135 static int translucent_add(Operation *op, SlapReply *rs) {
136         slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
137         overlay_stack *ov = on->on_bi.bi_private;
138         Debug(LDAP_DEBUG_TRACE, "==> translucent_add: %s\n",
139                 op->o_req_dn.bv_val, 0, 0);
140         if(!be_isroot(op)) {
141                 op->o_bd->bd_info = (BackendInfo *) on->on_info;
142                 send_ldap_error(op, rs, LDAP_INSUFFICIENT_ACCESS,
143                         "user modification of overlay database not permitted");
144                 return(rs->sr_err);
145         }
146         if(!ov->config->glue) glue_parent(op);
147         return(SLAP_CB_CONTINUE);
148 }
149
150 /*
151 ** translucent_modrdn()
152 **      if not bound as root, send ACCESS error;
153 **      if !config.glue, glue_parent();
154 **      else return CONTINUE;
155 **
156 */
157
158 static int translucent_modrdn(Operation *op, SlapReply *rs) {
159         slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
160         overlay_stack *ov = on->on_bi.bi_private;
161         Debug(LDAP_DEBUG_TRACE, "==> translucent_modrdn: %s -> %s\n",
162                 op->o_req_dn.bv_val, op->orr_newrdn.bv_val, 0);
163         if(!be_isroot(op)) {
164                 op->o_bd->bd_info = (BackendInfo *) on->on_info;
165                 send_ldap_error(op, rs, LDAP_INSUFFICIENT_ACCESS,
166                         "user modification of overlay database not permitted");
167                 return(rs->sr_err);
168         }
169         if(!ov->config->glue) glue_parent(op);
170         return(SLAP_CB_CONTINUE);
171 }
172
173 /*
174 ** translucent_delete()
175 **      if not bound as root, send ACCESS error;
176 **      else return CONTINUE;
177 **
178 */
179
180 static int translucent_delete(Operation *op, SlapReply *rs) {
181         slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
182         Debug(LDAP_DEBUG_TRACE, "==> translucent_delete: %s\n",
183                 op->o_req_dn.bv_val, 0, 0);
184         if(!be_isroot(op)) {
185                 op->o_bd->bd_info = (BackendInfo *) on->on_info;
186                 send_ldap_error(op, rs, LDAP_INSUFFICIENT_ACCESS,
187                         "user modification of overlay database not permitted");
188                 return(rs->sr_err);
189         }
190         return(SLAP_CB_CONTINUE);
191 }
192
193 /*
194 ** translucent_modify()
195 **      modify in local backend if exists in both;
196 **      otherwise, add to local backend;
197 **      fail if not defined in captive backend;
198 **
199 */
200
201 static int translucent_modify(Operation *op, SlapReply *rs) {
202         SlapReply nrs = { REP_RESULT };
203         Operation nop = *op;
204
205         slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
206         overlay_stack *ov = on->on_bi.bi_private;
207         translucent_configuration *cf = ov->config;
208         void *private = op->o_bd->be_private;
209         Entry ne, *e, *re = NULL;
210         Attribute *a, *ax;
211         Modifications *m, *mm;
212         int del, rc, erc = 0;
213
214         Debug(LDAP_DEBUG_TRACE, "==> translucent_modify: %s\n",
215                 op->o_req_dn.bv_val, 0, 0);
216
217 /*
218 ** fetch entry from the captive backend;
219 ** if it did not exist, fail;
220 ** release it, if captive backend supports this;
221 **
222 */
223
224         op->o_bd->bd_info = (BackendInfo *) on->on_info;
225         op->o_bd->be_private = ov->private;
226         rc = ov->info->bi_entry_get_rw(op, &op->o_req_ndn, NULL, NULL, 0, &re);
227         op->o_bd->be_private = private;
228
229         /* if(ov->config->no_add && (!re || rc != LDAP_SUCCESS)) */
230         if(!re || rc != LDAP_SUCCESS) {
231                 send_ldap_error(op, rs, LDAP_NO_SUCH_OBJECT,
232                         "attempt to modify nonexistent local record");
233                 return(rs->sr_err);
234         }
235
236 /*
237 ** fetch entry from local backend;
238 ** if it exists:
239 **      foreach Modification:
240 **          if attr not present in local:
241 **              if Mod == LDAP_MOD_DELETE:
242 **                  if remote attr not present, return NO_SUCH;
243 **                  if remote attr present, drop this Mod;
244 **              else force this Mod to LDAP_MOD_ADD;
245 **      return CONTINUE;
246 **
247 */
248
249         rc = be_entry_get_rw(op, &op->o_req_ndn, NULL, NULL, 0, &e);
250
251         if(e && rc == LDAP_SUCCESS) {
252                 Debug(LDAP_DEBUG_TRACE, "=> translucent_modify: found local entry\n", 0, 0, 0);
253                 for(m = op->orm_modlist; m; m = m->sml_next) {
254                         for(a = e->e_attrs; a; a = a->a_next)
255                                 if(a->a_desc == m->sml_desc) break;
256                         if(a) continue;         /* found local attr */
257                         if(m->sml_op == LDAP_MOD_DELETE) {
258                                 for(a = re->e_attrs; a; a = a->a_next)
259                                         if(a->a_desc == m->sml_desc) break;
260                                 /* not found remote attr */
261                                 if(!a) {
262                                         erc = LDAP_NO_SUCH_ATTRIBUTE;
263                                         goto release;
264                                 }
265                                 if(ov->config->strict) {
266                                         erc = LDAP_CONSTRAINT_VIOLATION;
267                                         goto release;
268                                 }
269                                 Debug(LDAP_DEBUG_TRACE,
270                                         "=> translucent_modify: silently dropping delete: %s\n",
271                                         m->sml_desc->ad_cname.bv_val, 0, 0);
272                                 for(mm = op->orm_modlist; mm->sml_next != m; mm = mm->sml_next);
273                                 mm->sml_next = m->sml_next;
274                                 mm = m;
275                                 m = m->sml_next;
276                                 mm->sml_next = NULL;            /* hack */
277                                 slap_mods_free(mm);
278                                 if(m) continue;
279                         }
280                         m->sml_op = LDAP_MOD_ADD;
281                 }
282                 erc = SLAP_CB_CONTINUE;
283 release:
284                 if(re) {
285                         op->o_bd->be_private = ov->private;
286                         if(ov->info->bi_entry_release_rw)
287                                 ov->info->bi_entry_release_rw(op, re, 0);
288                         else
289                                 entry_free(re);
290                         op->o_bd->be_private = private;
291                 }
292                 be_entry_release_r(op, e);
293                 if(erc == SLAP_CB_CONTINUE) {
294                         op->o_bd->bd_info = (BackendInfo *) on;
295                         return(erc);
296                 } else if(erc) {
297                         send_ldap_error(op, rs, erc,
298                                 "attempt to delete nonexistent attribute");
299                         return(erc);
300                 }
301         }
302
303 /*
304 ** foreach Modification:
305 **      if MOD_ADD or MOD_REPLACE, add Attribute;
306 ** if no Modifications were suitable:
307 **      if config.strict, throw CONSTRAINT_VIOLATION;
308 **      else, return early SUCCESS;
309 ** fabricate Entry with new Attribute chain;
310 ** glue_parent() for this Entry;
311 ** call bi_op_add() in local backend;
312 **
313 */
314
315         Debug(LDAP_DEBUG_TRACE, "=> translucent_modify: fabricating local add\n", 0, 0, 0);
316         a = NULL;
317         for(del = 0, ax = NULL, m = op->orm_modlist; m; m = m->sml_next) {
318                 if(((m->sml_op & LDAP_MOD_OP) != LDAP_MOD_ADD) &&
319                    ((m->sml_op & LDAP_MOD_OP) != LDAP_MOD_REPLACE)) {
320                         Debug(LDAP_DEBUG_ANY,
321                                 "=> translucent_modify: silently dropped modification(%d): %s\n",
322                                 m->sml_op, m->sml_desc->ad_cname.bv_val, 0);
323                         if((m->sml_op & LDAP_MOD_OP) == LDAP_MOD_DELETE) del++;
324                         continue;
325                 }
326                 a = ch_calloc(1, sizeof(Attribute));
327                 a->a_desc  = m->sml_desc;
328                 a->a_vals  = m->sml_values;
329                 a->a_nvals = m->sml_nvalues;
330                 a->a_next  = ax;
331                 ax = a;
332         }
333
334         if(del && ov->config->strict) {
335                 free_attr_chain(a);
336                 send_ldap_error(op, rs, LDAP_CONSTRAINT_VIOLATION,
337                         "attempt to delete attributes from local database");
338                 return(rs->sr_err);
339         }
340
341         if(!ax) {
342                 if(ov->config->strict) {
343                         send_ldap_error(op, rs, LDAP_CONSTRAINT_VIOLATION,
344                                 "modification contained other than ADD or REPLACE");
345                         return(rs->sr_err);
346                 }
347                 op->o_bd->bd_info = (BackendInfo *) on;
348                 /* rs->sr_text = "no valid modification found"; */
349                 rs->sr_err = LDAP_SUCCESS;
350                 send_ldap_result(op, rs);
351                 return(rs->sr_err);
352         }
353
354         ne.e_id         = NOID;
355         ne.e_name       = op->o_req_dn;
356         ne.e_nname      = op->o_req_ndn;
357         ne.e_attrs      = a;
358         ne.e_ocflags    = 0;
359         ne.e_bv.bv_len  = 0;
360         ne.e_bv.bv_val  = NULL;
361         ne.e_private    = NULL;
362
363         nop.o_tag       = LDAP_REQ_ADD;
364         nop.oq_add.rs_e = &ne;
365
366         op->o_bd->bd_info = (BackendInfo *) on;
367         glue_parent(&nop);
368
369         rc = on->on_info->oi_orig->bi_op_add(&nop, &nrs);
370         free_attr_chain(a);
371
372         return(rc);
373 }
374
375 static int translucent_compare(Operation *op, SlapReply *rs) {
376         slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
377         overlay_stack *ov = on->on_bi.bi_private;
378         void *private = op->o_bd->be_private;
379         translucent_configuration *cf = ov->config;
380
381         AttributeAssertion *ava = op->orc_ava;
382         Attribute *a, *an, *ra, *as = NULL;
383         Entry *e, *ee, *re;
384         int rc;
385
386         Debug(LDAP_DEBUG_TRACE, "==> translucent_compare: <%s> %s:%s\n",
387                 op->o_req_dn.bv_val, ava->aa_desc->ad_cname.bv_val, ava->aa_value.bv_val);
388
389 /*
390 ** if the local backend has an entry for this attribute:
391 **      CONTINUE and let it do the compare;
392 **
393 */
394
395         op->o_bd->bd_info = (BackendInfo *) on->on_info;
396         rc = be_entry_get_rw(op, &op->o_req_ndn, NULL, ava->aa_desc, 0, &e);
397         if(e && rc == LDAP_SUCCESS) {
398                 be_entry_release_r(op, e);
399                 op->o_bd->bd_info = (BackendInfo *) on;
400                 return(SLAP_CB_CONTINUE);
401         }
402
403 /*
404 ** call compare() in the captive backend;
405 ** return the result;
406 **
407 */
408
409         op->o_bd->be_private = ov->private;
410         rc = ov->info->bi_op_compare(op, rs);
411         op->o_bd->be_private = private;
412         op->o_bd->bd_info = (BackendInfo *) on;
413         return(rc);
414 }
415
416 /*
417 ** translucent_search_cb()
418 **      merge local data with the search result
419 **
420 */
421
422 static int translucent_search_cb(Operation *op, SlapReply *rs) {
423         slap_overinst *on;
424         Entry *e, *re = NULL;
425         Attribute *a, *ax, *an, *as = NULL;
426         BerVarray b, bx;
427         void *private;
428         int i, rc, size;
429
430         if(!op || !rs || rs->sr_type != REP_SEARCH || !rs->sr_entry)
431                 return(SLAP_CB_CONTINUE);
432
433         Debug(LDAP_DEBUG_TRACE, "==> tranclucent_search_cb: %s\n",
434                 rs->sr_entry->e_name.bv_val, 0, 0);
435
436         on = (slap_overinst *) op->o_bd->bd_info;
437         op->o_bd->bd_info = (BackendInfo *) on->on_info;
438
439         private = op->o_bd->be_private;
440         op->o_bd->be_private = op->o_callback->sc_private;
441
442         rc = be_entry_get_rw(op, &rs->sr_entry->e_nname, NULL, NULL, 0, &e);
443
444 /*
445 ** if we got an entry from local backend:
446 **      make a copy of this search result;
447 **      foreach local attr:
448 **              foreach search result attr:
449 **                      if match, result attr with local attr;
450 **                      if new local, add to list;
451 **      append new local attrs to search result;
452 **
453 */
454
455         if(e && rc == LDAP_SUCCESS) {
456                 re = entry_dup(rs->sr_entry);
457                 for(ax = e->e_attrs; ax; ax = ax->a_next) {
458 #if 0
459                         if(is_at_operational(ax->a_desc->ad_type)) continue;
460 #endif
461                         for(a = re->e_attrs; a; a = a->a_next) {
462                                 if(a->a_desc == ax->a_desc) {
463                                         if(a->a_vals != a->a_nvals)
464                                                 ber_bvarray_free(a->a_nvals);
465                                         ber_bvarray_free(a->a_vals);
466                                         a->a_vals = dup_bervarray(ax->a_vals);
467                                         a->a_nvals = (ax->a_vals == ax->a_nvals) ?
468                                                 a->a_vals : dup_bervarray(ax->a_nvals);
469                                         break;
470                                 }
471                         }
472                         if(a) continue;
473                         an = attr_dup(ax);
474                         an->a_next = as;
475                         as = an;
476                 }
477                 be_entry_release_r(op, e);
478
479                 /* literally append, so locals are always last */
480                 if(as) {
481                         if(re->e_attrs) {
482                                 for(ax = re->e_attrs; ax->a_next; ax = ax->a_next);
483                                 ax->a_next = as;
484                         } else {
485                                 re->e_attrs = as;
486                         }
487                 }
488                 rs->sr_entry = re;
489                 rs->sr_flags |= REP_ENTRY_MUSTBEFREED;
490         }
491
492         op->o_bd->be_private = private;
493         op->o_bd->bd_info = (BackendInfo *) on;
494
495         return(SLAP_CB_CONTINUE);
496 }
497
498 /*
499 ** translucent_search()
500 **      search via captive backend;
501 **      override results with any local data;
502 **
503 */
504
505 static int translucent_search(Operation *op, SlapReply *rs) {
506         Operation nop = *op;
507
508         slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
509         slap_callback cb = { NULL, NULL, NULL, NULL };
510         overlay_stack *ov = on->on_bi.bi_private;
511         translucent_configuration *cf = ov->config;
512         void *private = op->o_bd->be_private;
513         int rc;
514
515         Debug(LDAP_DEBUG_TRACE, "==> translucent_search: <%s> %s\n",
516                 op->o_req_dn.bv_val, op->ors_filterstr.bv_val, 0);
517         cb.sc_response = (slap_response *) translucent_search_cb;
518         cb.sc_private = private;
519
520         cb.sc_next = nop.o_callback;
521         nop.o_callback = &cb;
522
523         op->o_bd->be_private = ov->private;
524         rc = ov->info->bi_op_search(&nop, rs);
525         op->o_bd->be_private = private;
526
527         return(rs->sr_err);
528 }
529
530
531 /*
532 ** translucent_bind()
533 **      pass bind request to captive backend;
534 **
535 */
536
537 static int translucent_bind(Operation *op, SlapReply *rs) {
538         slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
539         overlay_stack *ov = on->on_bi.bi_private;
540         void *private = op->o_bd->be_private;
541         int rc = 0;
542
543         Debug(LDAP_DEBUG_TRACE, "translucent_bind: <%s> method %d\n",
544                 op->o_req_dn.bv_val, op->orb_method, 0);
545
546         op->o_bd->be_private = ov->private;
547         rc = ov->info->bi_op_bind(op, rs);
548         op->o_bd->be_private = private;
549
550         return(rc);
551 }
552
553 /*
554 ** translucent_config()
555 **      pass config directives to captive backend;
556 **      parse unrecognized directives ourselves;
557 **
558 */
559
560 static int translucent_config(
561         BackendDB       *be,
562         const char      *fname,
563         int             lineno,
564         int             argc,
565         char            **argv
566 )
567 {
568         slap_overinst *on = (slap_overinst *) be->bd_info;
569         overlay_stack *ov = on->on_bi.bi_private;
570         void *private = be->be_private;
571         int rc;
572
573         /* "this should never happen" */
574         if(!ov->info) {
575                 fprintf(stderr, "fatal: captive backend not initialized");
576                 return(1);
577         }
578
579         be->be_private = ov->private;
580         rc = ov->info->bi_db_config ? ov->info->bi_db_config(be, fname, lineno, argc, argv) : 0;
581         be->be_private = private;
582
583         /* pass okay or error up, SLAP_CONF_UNKNOWN might be ours */
584         if(rc == 0 || rc == 1) return(rc);
585
586         rc = 0;
587         if(!strcasecmp(*argv, "translucent_strict")) {
588                 ov->config->strict++;
589         } else if(!strcasecmp(*argv, "translucent_no_add")) {
590                 ov->config->no_add++;
591         } else if(!strcasecmp(*argv, "translucent_no_glue")) {
592                 ov->config->glue++;
593         } else if(!strcasecmp(*argv, "translucent_debug")) {
594                 if(argc == 1) {
595                         ov->config->debug = 0xFFFF;
596                         rc = 0;
597                 } else if(argc == 2) {
598                         ov->config->debug = atoi(argv[1]);
599                         rc = 0;
600                 } else {
601                         fprintf(stderr, "%s: line %d: too many arguments (%d) to debug\n",
602                                 fname, lineno, argc);
603                         rc = 1;
604                 }
605         } else {
606                 fprintf(stderr, "%s: line %d: unknown keyword %s\n",
607                         fname, lineno, *argv);
608                 rc = SLAP_CONF_UNKNOWN;
609         }
610         return(rc);
611 }
612
613 /*
614 ** translucent_db_init()
615 **      initialize the captive backend;
616 **
617 */
618
619 static int translucent_db_init(BackendDB *be) {
620         slap_overinst *on = (slap_overinst *) be->bd_info;
621         void *private = be->be_private;
622         overlay_stack *ov;
623         int rc;
624
625         Debug(LDAP_DEBUG_TRACE, "==> translucent_init\n", 0, 0, 0);
626
627         ov = ch_calloc(1, sizeof(overlay_stack));
628         ov->config = ch_calloc(1, sizeof(translucent_configuration));
629         ov->info = backend_info("ldap");
630
631         if(!ov->info) {
632                 Debug(LDAP_DEBUG_ANY, "translucent: backend_info failed!\n", 0, 0, 0);
633                 return(1);
634         }
635
636         /* forcibly disable schema checking on the local backend */
637         SLAP_DBFLAGS(be) |= SLAP_DBFLAG_NO_SCHEMA_CHECK;
638
639         be->be_private = NULL;
640         rc = ov->info->bi_db_init ? ov->info->bi_db_init(be) : 0;
641
642         if(rc) Debug(LDAP_DEBUG_TRACE,
643                 "translucent: bi_db_init() returned error %d\n", rc, 0, 0);
644
645         ov->private = be->be_private;
646         be->be_private = private;
647         on->on_bi.bi_private = ov;
648         return(rc);
649 }
650
651 /*
652 ** translucent_open()
653 **      if the captive backend has an open() method, call it;
654 **
655 */
656
657 static int translucent_open(BackendDB *be) {
658         slap_overinst *on = (slap_overinst *) be->bd_info;
659         overlay_stack *ov = on->on_bi.bi_private;
660         void *private = be->be_private;
661         int rc;
662
663         /* "should never happen" */
664         if(!ov->info) {
665                 Debug(LDAP_DEBUG_ANY, "translucent_open() called with bad ov->info\n", 0, 0, 0);
666                 return(LDAP_OTHER);
667         }
668
669         Debug(LDAP_DEBUG_TRACE, "translucent_open\n", 0, 0, 0);
670
671         be->be_private = ov->private;
672         rc = ov->info->bi_db_open ? ov->info->bi_db_open(be) : 0;
673         be->be_private = private;
674
675         if(rc) Debug(LDAP_DEBUG_TRACE,
676                 "translucent: bi_db_open() returned error %d\n", rc, 0, 0);
677
678         return(rc);
679 }
680
681 /*
682 ** translucent_close()
683 **      if the captive backend has a close() method, call it;
684 **      free any config data;
685 **
686 */
687
688 static int translucent_close(BackendDB *be) {
689         slap_overinst *on = (slap_overinst *) be->bd_info;
690         overlay_stack *ov = on->on_bi.bi_private;
691         translucent_configuration *cf = ov->config;
692         void *private = be->be_private;
693         int rc;
694
695         be->be_private = ov->private;
696         rc = (ov->info && ov->info->bi_db_close) ? ov->info->bi_db_close(be) : 0;
697         be->be_private = private;
698         if(ov->config) ch_free(ov->config);
699         ch_free(ov);
700         return(rc);
701 }
702
703 /*
704 ** translucent_init()
705 **      initialize the slap_overinst with our entry points;
706 **
707 */
708
709 int translucent_init() {
710
711         translucent.on_bi.bi_type       = "translucent";
712         translucent.on_bi.bi_db_init    = translucent_db_init;
713         translucent.on_bi.bi_db_config  = translucent_config;
714         translucent.on_bi.bi_db_open    = translucent_open;
715         translucent.on_bi.bi_db_close   = translucent_close;
716         translucent.on_bi.bi_op_bind    = translucent_bind;
717         translucent.on_bi.bi_op_add     = translucent_add;
718         translucent.on_bi.bi_op_modify  = translucent_modify;
719         translucent.on_bi.bi_op_modrdn  = translucent_modrdn;
720         translucent.on_bi.bi_op_delete  = translucent_delete;
721         translucent.on_bi.bi_op_search  = translucent_search;
722         translucent.on_bi.bi_op_compare = translucent_compare;
723
724         return(overlay_register(&translucent));
725 }
726
727 #if SLAPD_OVER_TRANSLUCENT == SLAPD_MOD_DYNAMIC && defined(PIC)
728 int init_module(int argc, char *argv[]) {
729         return translucent_init();
730 }
731 #endif
732
733 #endif /* SLAPD_OVER_TRANSLUCENT */
734