1 /*        $NetBSD: backover.c,v 1.3 2021/08/14 16:14:58 christos Exp $          */
2 
3 /* backover.c - backend overlay routines */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6  *
7  * Copyright 2003-2021 The OpenLDAP Foundation.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted only as authorized by the OpenLDAP
12  * Public License.
13  *
14  * A copy of this license is available in the file LICENSE in the
15  * top-level directory of the distribution or, alternatively, at
16  * <http://www.OpenLDAP.org/license.html>.
17  */
18 
19 /* Functions to overlay other modules over a backend. */
20 
21 #include <sys/cdefs.h>
22 __RCSID("$NetBSD: backover.c,v 1.3 2021/08/14 16:14:58 christos Exp $");
23 
24 #include "portable.h"
25 
26 #include <stdio.h>
27 
28 #include <ac/string.h>
29 #include <ac/socket.h>
30 
31 #define SLAPD_TOOLS
32 #include "slap.h"
33 #include "slap-config.h"
34 
35 static slap_overinst *overlays;
36 
37 static int
over_db_config(BackendDB * be,const char * fname,int lineno,int argc,char ** argv)38 over_db_config(
39           BackendDB *be,
40           const char *fname,
41           int lineno,
42           int argc,
43           char **argv
44 )
45 {
46           slap_overinfo *oi = be->bd_info->bi_private;
47           slap_overinst *on = oi->oi_list;
48           BackendInfo *bi_orig = be->bd_info;
49           struct ConfigOCs *be_cf_ocs = be->be_cf_ocs;
50           ConfigArgs ca = {0};
51           int rc = 0;
52 
53           if ( oi->oi_orig->bi_db_config ) {
54                     be->bd_info = oi->oi_orig;
55                     be->be_cf_ocs = oi->oi_orig->bi_cf_ocs;
56                     rc = oi->oi_orig->bi_db_config( be, fname, lineno,
57                               argc, argv );
58 
59                     if ( be->bd_info != oi->oi_orig ) {
60                               slap_overinfo       *oi2;
61                               slap_overinst       *on2, **onp;
62                               BackendDB be2 = *be;
63                               int                 i;
64 
65                               /* a database added an overlay;
66                                * work it around... */
67                               assert( overlay_is_over( be ) );
68 
69                               oi2 = ( slap_overinfo * )be->bd_info->bi_private;
70                               on2 = oi2->oi_list;
71 
72                               /* need to put a uniqueness check here as well;
73                                * note that in principle there could be more than
74                                * one overlay as a result of multiple calls to
75                                * overlay_config() */
76                               be2.bd_info = (BackendInfo *)oi;
77 
78                               for ( i = 0, onp = &on2; *onp; i++, onp = &(*onp)->on_next ) {
79                                         if ( overlay_is_inst( &be2, (*onp)->on_bi.bi_type ) ) {
80                                                   Debug( LDAP_DEBUG_ANY, "over_db_config(): "
81                                                                       "warning, freshly added "
82                                                                       "overlay #%d \"%s\" is already in list\n",
83                                                                       i, (*onp)->on_bi.bi_type );
84 
85                                                   /* NOTE: if the overlay already exists,
86                                                    * there is no way to merge the results
87                                                    * of the configuration that may have
88                                                    * occurred during bi_db_config(); we
89                                                    * just issue a warning, and the
90                                                    * administrator should deal with this */
91                                         }
92                               }
93                               *onp = oi->oi_list;
94 
95                               oi->oi_list = on2;
96 
97                               ch_free( be->bd_info );
98                     }
99 
100                     be->bd_info = (BackendInfo *)oi;
101                     if ( rc != SLAP_CONF_UNKNOWN ) return rc;
102           }
103 
104           ca.argv = argv;
105           ca.argc = argc;
106           ca.fname = fname;
107           ca.lineno = lineno;
108           ca.be = be;
109           snprintf( ca.log, sizeof( ca.log ), "%s: line %d",
110                               ca.fname, ca.lineno );
111           ca.op = SLAP_CONFIG_ADD;
112           ca.valx = -1;
113 
114           for (; on; on=on->on_next) {
115                     rc = SLAP_CONF_UNKNOWN;
116                     if (on->on_bi.bi_cf_ocs) {
117                               ConfigTable *ct;
118                               ca.bi = &on->on_bi;
119                               ct = config_find_keyword( on->on_bi.bi_cf_ocs->co_table, &ca );
120                               if ( ct ) {
121                                         ca.table = on->on_bi.bi_cf_ocs->co_type;
122                                         rc = config_add_vals( ct, &ca );
123                                         if ( rc != SLAP_CONF_UNKNOWN )
124                                                   break;
125                               }
126                     }
127                     if (on->on_bi.bi_db_config && rc == SLAP_CONF_UNKNOWN) {
128                               be->bd_info = &on->on_bi;
129                               rc = on->on_bi.bi_db_config( be, fname, lineno,
130                                         argc, argv );
131                               if ( rc != SLAP_CONF_UNKNOWN ) break;
132                     }
133           }
134           be->bd_info = bi_orig;
135           be->be_cf_ocs = be_cf_ocs;
136 
137           return rc;
138 }
139 
140 static int
over_db_open(BackendDB * be,ConfigReply * cr)141 over_db_open(
142           BackendDB *be,
143           ConfigReply *cr
144 )
145 {
146           slap_overinfo *oi = be->bd_info->bi_private;
147           slap_overinst *on = oi->oi_list;
148           BackendDB db = *be;
149           int rc = 0;
150 
151           db.be_flags |= SLAP_DBFLAG_OVERLAY;
152           db.bd_info = oi->oi_orig;
153           if ( db.bd_info->bi_db_open ) {
154                     rc = db.bd_info->bi_db_open( &db, cr );
155           }
156 
157           for (; on && rc == 0; on=on->on_next) {
158                     if ( on->on_bi.bi_flags & SLAPO_BFLAG_DISABLED )
159                               continue;
160                     db.bd_info = &on->on_bi;
161                     if ( db.bd_info->bi_db_open ) {
162                               rc = db.bd_info->bi_db_open( &db, cr );
163                     }
164           }
165 
166           return rc;
167 }
168 
169 static int
over_db_close(BackendDB * be,ConfigReply * cr)170 over_db_close(
171           BackendDB *be,
172           ConfigReply *cr
173 )
174 {
175           slap_overinfo *oi = be->bd_info->bi_private;
176           slap_overinst *on = oi->oi_list;
177           BackendInfo *bi_orig = be->bd_info;
178           int rc = 0;
179 
180           for (; on && rc == 0; on=on->on_next) {
181                     if ( on->on_bi.bi_flags & SLAPO_BFLAG_DISABLED )
182                               continue;
183                     be->bd_info = &on->on_bi;
184                     if ( be->bd_info->bi_db_close ) {
185                               rc = be->bd_info->bi_db_close( be, cr );
186                     }
187           }
188 
189           if ( oi->oi_orig->bi_db_close ) {
190                     be->bd_info = oi->oi_orig;
191                     rc = be->bd_info->bi_db_close( be, cr );
192           }
193 
194           be->bd_info = bi_orig;
195           return rc;
196 }
197 
198 static int
over_db_destroy(BackendDB * be,ConfigReply * cr)199 over_db_destroy(
200           BackendDB *be,
201           ConfigReply *cr
202 )
203 {
204           slap_overinfo *oi = be->bd_info->bi_private;
205           slap_overinst *on = oi->oi_list, *next;
206           BackendInfo *bi_orig = be->bd_info;
207           int rc = 0;
208 
209           be->bd_info = oi->oi_orig;
210           if ( be->bd_info->bi_db_destroy ) {
211                     rc = be->bd_info->bi_db_destroy( be, cr );
212           }
213 
214           for (; on && rc == 0; on=on->on_next) {
215                     if ( on->on_bi.bi_flags & SLAPO_BFLAG_DISABLED )
216                               continue;
217                     be->bd_info = &on->on_bi;
218                     if ( be->bd_info->bi_db_destroy ) {
219                               rc = be->bd_info->bi_db_destroy( be, cr );
220                     }
221           }
222 
223           on = oi->oi_list;
224           if ( on ) {
225                     for (next = on->on_next; on; on=next) {
226                               next = on->on_next;
227                               free( on );
228                     }
229           }
230           be->bd_info = bi_orig;
231           free( oi );
232           return rc;
233 }
234 
235 static int
over_back_response(Operation * op,SlapReply * rs)236 over_back_response ( Operation *op, SlapReply *rs )
237 {
238           slap_overinfo *oi = op->o_callback->sc_private;
239           slap_overinst *on = oi->oi_list;
240           int rc = SLAP_CB_CONTINUE;
241           BackendDB *be = op->o_bd, db = *op->o_bd;
242 
243           db.be_flags |= SLAP_DBFLAG_OVERLAY;
244           op->o_bd = &db;
245           for (; on; on=on->on_next ) {
246                     if ( on->on_bi.bi_flags & SLAPO_BFLAG_DISABLED )
247                               continue;
248                     if ( on->on_response ) {
249                               db.bd_info = (BackendInfo *)on;
250                               rc = on->on_response( op, rs );
251                               if ( rc != SLAP_CB_CONTINUE ) break;
252                     }
253           }
254           /* Bypass the remaining on_response layers, but allow
255            * normal execution to continue.
256            */
257           if ( rc == SLAP_CB_BYPASS )
258                     rc = SLAP_CB_CONTINUE;
259           op->o_bd = be;
260           return rc;
261 }
262 
263 static int
over_access_allowed(Operation * op,Entry * e,AttributeDescription * desc,struct berval * val,slap_access_t access,AccessControlState * state,slap_mask_t * maskp)264 over_access_allowed(
265           Operation           *op,
266           Entry                         *e,
267           AttributeDescription          *desc,
268           struct berval                 *val,
269           slap_access_t                 access,
270           AccessControlState  *state,
271           slap_mask_t                   *maskp )
272 {
273           slap_overinfo *oi;
274           slap_overinst *on;
275           BackendInfo *bi;
276           BackendDB *be = op->o_bd, db;
277           int rc = SLAP_CB_CONTINUE;
278 
279           /* FIXME: used to happen for instance during abandon
280            * when global overlays are used... */
281           assert( op->o_bd != NULL );
282 
283           bi = op->o_bd->bd_info;
284           /* Were we invoked on the frontend? */
285           if ( !bi->bi_access_allowed ) {
286                     oi = frontendDB->bd_info->bi_private;
287           } else {
288                     oi = op->o_bd->bd_info->bi_private;
289           }
290           on = oi->oi_list;
291 
292           for ( ; on; on = on->on_next ) {
293                     if ( on->on_bi.bi_flags & SLAPO_BFLAG_DISABLED )
294                               continue;
295                     if ( on->on_bi.bi_access_allowed ) {
296                               /* NOTE: do not copy the structure until required */
297                               if ( !SLAP_ISOVERLAY( op->o_bd ) ) {
298                                         db = *op->o_bd;
299                                         db.be_flags |= SLAP_DBFLAG_OVERLAY;
300                                         op->o_bd = &db;
301                               }
302 
303                               op->o_bd->bd_info = (BackendInfo *)on;
304                               rc = on->on_bi.bi_access_allowed( op, e,
305                                         desc, val, access, state, maskp );
306                               if ( rc != SLAP_CB_CONTINUE ) break;
307                     }
308           }
309 
310           if ( rc == SLAP_CB_CONTINUE ) {
311                     BI_access_allowed   *bi_access_allowed;
312 
313                     /* if the database structure was changed, o_bd points to a
314                      * copy of the structure; put the original bd_info in place */
315                     if ( SLAP_ISOVERLAY( op->o_bd ) ) {
316                               op->o_bd->bd_info = oi->oi_orig;
317                     }
318 
319                     if ( oi->oi_orig->bi_access_allowed ) {
320                               bi_access_allowed = oi->oi_orig->bi_access_allowed;
321                     } else {
322                               bi_access_allowed = slap_access_allowed;
323                     }
324 
325                     rc = bi_access_allowed( op, e,
326                               desc, val, access, state, maskp );
327           }
328           /* should not fall thru this far without anything happening... */
329           if ( rc == SLAP_CB_CONTINUE ) {
330                     /* access not allowed */
331                     rc = 0;
332           }
333 
334           op->o_bd = be;
335           if ( SLAP_ISOVERLAY( op->o_bd ) ) {
336                     op->o_bd->bd_info = bi;
337           }
338 
339           return rc;
340 }
341 
342 int
overlay_entry_get_ov(Operation * op,struct berval * dn,ObjectClass * oc,AttributeDescription * ad,int rw,Entry ** e,slap_overinst * on)343 overlay_entry_get_ov(
344           Operation           *op,
345           struct berval       *dn,
346           ObjectClass                   *oc,
347           AttributeDescription          *ad,
348           int       rw,
349           Entry     **e,
350           slap_overinst *on )
351 {
352           slap_overinfo *oi = on->on_info;
353           BackendDB *be = op->o_bd, db;
354           BackendInfo *bi = op->o_bd->bd_info;
355           int rc = SLAP_CB_CONTINUE;
356 
357           for ( ; on; on = on->on_next ) {
358                     if ( on->on_bi.bi_flags & SLAPO_BFLAG_DISABLED )
359                               continue;
360                     if ( on->on_bi.bi_entry_get_rw ) {
361                               /* NOTE: do not copy the structure until required */
362                               if ( !SLAP_ISOVERLAY( op->o_bd ) ) {
363                                         db = *op->o_bd;
364                                         db.be_flags |= SLAP_DBFLAG_OVERLAY;
365                                         op->o_bd = &db;
366                               }
367 
368                               op->o_bd->bd_info = (BackendInfo *)on;
369                               rc = on->on_bi.bi_entry_get_rw( op, dn,
370                                         oc, ad, rw, e );
371                               if ( rc != SLAP_CB_CONTINUE ) break;
372                     }
373           }
374 
375           if ( rc == SLAP_CB_CONTINUE ) {
376                     /* if the database structure was changed, o_bd points to a
377                      * copy of the structure; put the original bd_info in place */
378                     if ( SLAP_ISOVERLAY( op->o_bd ) ) {
379                               op->o_bd->bd_info = oi->oi_orig;
380                     }
381 
382                     if ( oi->oi_orig->bi_entry_get_rw ) {
383                               rc = oi->oi_orig->bi_entry_get_rw( op, dn,
384                                         oc, ad, rw, e );
385                     }
386           }
387           /* should not fall thru this far without anything happening... */
388           if ( rc == SLAP_CB_CONTINUE ) {
389                     rc = LDAP_UNWILLING_TO_PERFORM;
390           }
391 
392           op->o_bd = be;
393           if ( SLAP_ISOVERLAY( op->o_bd ) ) {
394                     op->o_bd->bd_info = bi;
395           }
396 
397           return rc;
398 }
399 
400 static int
over_entry_get_rw(Operation * op,struct berval * dn,ObjectClass * oc,AttributeDescription * ad,int rw,Entry ** e)401 over_entry_get_rw(
402           Operation           *op,
403           struct berval       *dn,
404           ObjectClass                   *oc,
405           AttributeDescription          *ad,
406           int       rw,
407           Entry     **e )
408 {
409           slap_overinfo *oi;
410           slap_overinst *on;
411 
412           assert( op->o_bd != NULL );
413 
414           oi = op->o_bd->bd_info->bi_private;
415           on = oi->oi_list;
416 
417           return overlay_entry_get_ov( op, dn, oc, ad, rw, e, on );
418 }
419 
420 int
overlay_entry_release_ov(Operation * op,Entry * e,int rw,slap_overinst * on)421 overlay_entry_release_ov(
422           Operation *op,
423           Entry     *e,
424           int rw,
425           slap_overinst *on )
426 {
427           slap_overinfo *oi = on->on_info;
428           BackendDB *be = op->o_bd, db;
429           BackendInfo *bi = op->o_bd->bd_info;
430           int rc = SLAP_CB_CONTINUE;
431 
432           for ( ; on; on = on->on_next ) {
433                     if ( on->on_bi.bi_flags & SLAPO_BFLAG_DISABLED )
434                               continue;
435                     if ( on->on_bi.bi_entry_release_rw ) {
436                               /* NOTE: do not copy the structure until required */
437                               if ( !SLAP_ISOVERLAY( op->o_bd ) ) {
438                                         db = *op->o_bd;
439                                         db.be_flags |= SLAP_DBFLAG_OVERLAY;
440                                         op->o_bd = &db;
441                               }
442 
443                               op->o_bd->bd_info = (BackendInfo *)on;
444                               rc = on->on_bi.bi_entry_release_rw( op, e, rw );
445                               if ( rc != SLAP_CB_CONTINUE ) break;
446                     }
447           }
448 
449           if ( rc == SLAP_CB_CONTINUE ) {
450                     /* if the database structure was changed, o_bd points to a
451                      * copy of the structure; put the original bd_info in place */
452                     if ( SLAP_ISOVERLAY( op->o_bd ) ) {
453                               op->o_bd->bd_info = oi->oi_orig;
454                     }
455 
456                     if ( oi->oi_orig->bi_entry_release_rw ) {
457                               rc = oi->oi_orig->bi_entry_release_rw( op, e, rw );
458                     }
459           }
460           /* should not fall thru this far without anything happening... */
461           if ( rc == SLAP_CB_CONTINUE ) {
462                     entry_free( e );
463                     rc = 0;
464           }
465 
466           op->o_bd = be;
467           if ( SLAP_ISOVERLAY( op->o_bd ) ) {
468                     op->o_bd->bd_info = bi;
469           }
470 
471           return rc;
472 }
473 
474 static int
over_entry_release_rw(Operation * op,Entry * e,int rw)475 over_entry_release_rw(
476           Operation *op,
477           Entry     *e,
478           int rw )
479 {
480           slap_overinfo *oi;
481           slap_overinst *on;
482 
483           assert( op->o_bd != NULL );
484 
485           oi = op->o_bd->bd_info->bi_private;
486           on = oi->oi_list;
487 
488           return overlay_entry_release_ov( op, e, rw, on );
489 }
490 
491 static int
over_acl_group(Operation * op,Entry * e,struct berval * gr_ndn,struct berval * op_ndn,ObjectClass * group_oc,AttributeDescription * group_at)492 over_acl_group(
493           Operation           *op,
494           Entry                         *e,
495           struct berval                 *gr_ndn,
496           struct berval                 *op_ndn,
497           ObjectClass                   *group_oc,
498           AttributeDescription          *group_at )
499 {
500           slap_overinfo *oi;
501           slap_overinst *on;
502           BackendInfo *bi;
503           BackendDB *be = op->o_bd, db;
504           int rc = SLAP_CB_CONTINUE;
505 
506           /* FIXME: used to happen for instance during abandon
507            * when global overlays are used... */
508           assert( be != NULL );
509 
510           bi = be->bd_info;
511           oi = bi->bi_private;
512           on = oi->oi_list;
513 
514           for ( ; on; on = on->on_next ) {
515                     if ( on->on_bi.bi_flags & SLAPO_BFLAG_DISABLED )
516                               continue;
517                     if ( on->on_bi.bi_acl_group ) {
518                               /* NOTE: do not copy the structure until required */
519                               if ( !SLAP_ISOVERLAY( op->o_bd ) ) {
520                                         db = *op->o_bd;
521                                         db.be_flags |= SLAP_DBFLAG_OVERLAY;
522                                         op->o_bd = &db;
523                               }
524 
525                               op->o_bd->bd_info = (BackendInfo *)on;
526                               rc = on->on_bi.bi_acl_group( op, e,
527                                         gr_ndn, op_ndn, group_oc, group_at );
528                               if ( rc != SLAP_CB_CONTINUE ) break;
529                     }
530           }
531 
532           if ( rc == SLAP_CB_CONTINUE ) {
533                     BI_acl_group                  *bi_acl_group;
534 
535                     /* if the database structure was changed, o_bd points to a
536                      * copy of the structure; put the original bd_info in place */
537                     if ( SLAP_ISOVERLAY( op->o_bd ) ) {
538                               op->o_bd->bd_info = oi->oi_orig;
539                     }
540 
541                     if ( oi->oi_orig->bi_acl_group ) {
542                               bi_acl_group = oi->oi_orig->bi_acl_group;
543                     } else {
544                               bi_acl_group = backend_group;
545                     }
546 
547                     rc = bi_acl_group( op, e,
548                               gr_ndn, op_ndn, group_oc, group_at );
549           }
550           /* should not fall thru this far without anything happening... */
551           if ( rc == SLAP_CB_CONTINUE ) {
552                     /* access not allowed */
553                     rc = 0;
554           }
555 
556           op->o_bd = be;
557           if ( SLAP_ISOVERLAY( op->o_bd ) ) {
558                     op->o_bd->bd_info = bi;
559           }
560 
561           return rc;
562 }
563 
564 static int
over_acl_attribute(Operation * op,Entry * target,struct berval * entry_ndn,AttributeDescription * entry_at,BerVarray * vals,slap_access_t access)565 over_acl_attribute(
566           Operation           *op,
567           Entry                         *target,
568           struct berval                 *entry_ndn,
569           AttributeDescription          *entry_at,
570           BerVarray           *vals,
571           slap_access_t                 access )
572 {
573           slap_overinfo *oi;
574           slap_overinst *on;
575           BackendInfo *bi;
576           BackendDB *be = op->o_bd, db;
577           int rc = SLAP_CB_CONTINUE;
578 
579           /* FIXME: used to happen for instance during abandon
580            * when global overlays are used... */
581           assert( be != NULL );
582 
583           bi = be->bd_info;
584           oi = bi->bi_private;
585           on = oi->oi_list;
586 
587           for ( ; on; on = on->on_next ) {
588                     if ( on->on_bi.bi_flags & SLAPO_BFLAG_DISABLED )
589                               continue;
590                     if ( on->on_bi.bi_acl_attribute ) {
591                               /* NOTE: do not copy the structure until required */
592                               if ( !SLAP_ISOVERLAY( op->o_bd ) ) {
593                                         db = *op->o_bd;
594                                         db.be_flags |= SLAP_DBFLAG_OVERLAY;
595                                         op->o_bd = &db;
596                               }
597 
598                               op->o_bd->bd_info = (BackendInfo *)on;
599                               rc = on->on_bi.bi_acl_attribute( op, target,
600                                         entry_ndn, entry_at, vals, access );
601                               if ( rc != SLAP_CB_CONTINUE ) break;
602                     }
603           }
604 
605           if ( rc == SLAP_CB_CONTINUE ) {
606                     BI_acl_attribute              *bi_acl_attribute;
607 
608                     /* if the database structure was changed, o_bd points to a
609                      * copy of the structure; put the original bd_info in place */
610                     if ( SLAP_ISOVERLAY( op->o_bd ) ) {
611                               op->o_bd->bd_info = oi->oi_orig;
612                     }
613 
614                     if ( oi->oi_orig->bi_acl_attribute ) {
615                               bi_acl_attribute = oi->oi_orig->bi_acl_attribute;
616                     } else {
617                               bi_acl_attribute = backend_attribute;
618                     }
619 
620                     rc = bi_acl_attribute( op, target,
621                               entry_ndn, entry_at, vals, access );
622           }
623           /* should not fall thru this far without anything happening... */
624           if ( rc == SLAP_CB_CONTINUE ) {
625                     /* access not allowed */
626                     rc = 0;
627           }
628 
629           op->o_bd = be;
630           if ( SLAP_ISOVERLAY( op->o_bd ) ) {
631                     op->o_bd->bd_info = bi;
632           }
633 
634           return rc;
635 }
636 
637 int
overlay_callback_after_backover(Operation * op,slap_callback * sc,int append)638 overlay_callback_after_backover( Operation *op, slap_callback *sc, int append )
639 {
640           slap_callback **scp;
641 
642           for ( scp = &op->o_callback; *scp != NULL; scp = &(*scp)->sc_next ) {
643                     if ( (*scp)->sc_response == over_back_response ) {
644                               sc->sc_next = (*scp)->sc_next;
645                               (*scp)->sc_next = sc;
646                               return 0;
647                     }
648           }
649 
650           if ( append ) {
651                     *scp = sc;
652                     return 0;
653           }
654 
655           return 1;
656 }
657 
658 /*
659  * default return code in case of missing backend function
660  * and overlay stack returning SLAP_CB_CONTINUE
661  */
662 static int op_rc[ op_last ] = {
663           LDAP_UNWILLING_TO_PERFORM,    /* bind */
664           LDAP_UNWILLING_TO_PERFORM,    /* unbind */
665           LDAP_UNWILLING_TO_PERFORM,    /* search */
666           SLAP_CB_CONTINUE,             /* compare; pass to frontend */
667           LDAP_UNWILLING_TO_PERFORM,    /* modify */
668           LDAP_UNWILLING_TO_PERFORM,    /* modrdn */
669           LDAP_UNWILLING_TO_PERFORM,    /* add */
670           LDAP_UNWILLING_TO_PERFORM,    /* delete */
671           LDAP_UNWILLING_TO_PERFORM,    /* abandon */
672           LDAP_UNWILLING_TO_PERFORM,    /* cancel */
673           LDAP_UNWILLING_TO_PERFORM,    /* extended */
674           LDAP_SUCCESS,                           /* aux_operational */
675           LDAP_SUCCESS,                           /* aux_chk_referrals */
676           SLAP_CB_CONTINUE              /* aux_chk_controls; pass to frontend */
677 };
678 
overlay_op_walk(Operation * op,SlapReply * rs,slap_operation_t which,slap_overinfo * oi,slap_overinst * on)679 int overlay_op_walk(
680           Operation *op,
681           SlapReply *rs,
682           slap_operation_t which,
683           slap_overinfo *oi,
684           slap_overinst *on
685 )
686 {
687           BackendInfo *bi;
688           int rc = SLAP_CB_CONTINUE;
689 
690           for (; on; on=on->on_next ) {
691                     if ( on->on_bi.bi_flags & SLAPO_BFLAG_DISABLED )
692                               continue;
693                     bi = &on->on_bi;
694                     if ( (&bi->bi_op_bind)[ which ] ) {
695                               op->o_bd->bd_info = (BackendInfo *)on;
696                               rc = (&bi->bi_op_bind)[ which ]( op, rs );
697                               if ( rc != SLAP_CB_CONTINUE ) break;
698                     }
699           }
700           if ( rc == SLAP_CB_BYPASS )
701                     rc = SLAP_CB_CONTINUE;
702           /* if an overlay halted processing, make sure
703            * any previously set cleanup handlers are run
704            */
705           if ( rc != SLAP_CB_CONTINUE )
706                     goto cleanup;
707 
708           bi = oi->oi_orig;
709           if ( (&bi->bi_op_bind)[ which ] ) {
710                     op->o_bd->bd_info = bi;
711                     rc = (&bi->bi_op_bind)[ which ]( op, rs );
712           }
713           /* should not fall thru this far without anything happening... */
714           if ( rc == SLAP_CB_CONTINUE ) {
715                     rc = op_rc[ which ];
716           }
717 
718           /* The underlying backend didn't handle the request, make sure
719            * overlay cleanup is processed.
720            */
721           if ( rc == LDAP_UNWILLING_TO_PERFORM ) {
722                     slap_callback *sc_next;
723 cleanup:
724                     for ( ; op->o_callback && op->o_callback->sc_response !=
725                               over_back_response; op->o_callback = sc_next ) {
726                               sc_next = op->o_callback->sc_next;
727                               if ( op->o_callback->sc_cleanup ) {
728                                         op->o_callback->sc_cleanup( op, rs );
729                               }
730                     }
731           }
732           return rc;
733 }
734 
735 static int
over_op_func(Operation * op,SlapReply * rs,slap_operation_t which)736 over_op_func(
737           Operation *op,
738           SlapReply *rs,
739           slap_operation_t which
740 )
741 {
742           slap_overinfo *oi;
743           slap_overinst *on;
744           BackendDB *be = op->o_bd, db;
745           slap_callback **sc;
746           slap_callback *cb;
747           int rc = SLAP_CB_CONTINUE;
748 
749           /* FIXME: used to happen for instance during abandon
750            * when global overlays are used... */
751           assert( op->o_bd != NULL );
752 
753           oi = op->o_bd->bd_info->bi_private;
754           on = oi->oi_list;
755 
756           if ( !SLAP_ISOVERLAY( op->o_bd )) {
757                     db = *op->o_bd;
758                     db.be_flags |= SLAP_DBFLAG_OVERLAY;
759                     op->o_bd = &db;
760           }
761           if ( op->o_tag != LDAP_REQ_ABANDON && op->o_tag != LDAP_REQ_UNBIND ) {
762                     cb = (slap_callback *)op->o_tmpcalloc( 1, sizeof(slap_callback), op->o_tmpmemctx );
763                     cb->sc_cleanup = NULL;
764                     cb->sc_response = over_back_response;
765                     cb->sc_writewait = NULL;
766                     cb->sc_next = op->o_callback;
767                     cb->sc_private = oi;
768                     op->o_callback = cb;
769           }
770 
771           rc = overlay_op_walk( op, rs, which, oi, on );
772           if ( rc != SLAPD_ASYNCOP && op->o_tag != LDAP_REQ_ABANDON && op->o_tag != LDAP_REQ_UNBIND ) {
773                     for ( sc = &op->o_callback; *sc; sc = &(*sc)->sc_next ) {
774                               if ( *sc == cb ) {
775                                         *sc = cb->sc_next;
776                                         op->o_tmpfree( cb, op->o_tmpmemctx );
777                                         break;
778                               }
779                     }
780           }
781 
782           op->o_bd = be;
783           return rc;
784 }
785 
786 static int
over_op_bind(Operation * op,SlapReply * rs)787 over_op_bind( Operation *op, SlapReply *rs )
788 {
789           return over_op_func( op, rs, op_bind );
790 }
791 
792 static int
over_op_unbind(Operation * op,SlapReply * rs)793 over_op_unbind( Operation *op, SlapReply *rs )
794 {
795           return over_op_func( op, rs, op_unbind );
796 }
797 
798 static int
over_op_search(Operation * op,SlapReply * rs)799 over_op_search( Operation *op, SlapReply *rs )
800 {
801           return over_op_func( op, rs, op_search );
802 }
803 
804 static int
over_op_compare(Operation * op,SlapReply * rs)805 over_op_compare( Operation *op, SlapReply *rs )
806 {
807           return over_op_func( op, rs, op_compare );
808 }
809 
810 static int
over_op_modify(Operation * op,SlapReply * rs)811 over_op_modify( Operation *op, SlapReply *rs )
812 {
813           return over_op_func( op, rs, op_modify );
814 }
815 
816 static int
over_op_modrdn(Operation * op,SlapReply * rs)817 over_op_modrdn( Operation *op, SlapReply *rs )
818 {
819           return over_op_func( op, rs, op_modrdn );
820 }
821 
822 static int
over_op_add(Operation * op,SlapReply * rs)823 over_op_add( Operation *op, SlapReply *rs )
824 {
825           return over_op_func( op, rs, op_add );
826 }
827 
828 static int
over_op_delete(Operation * op,SlapReply * rs)829 over_op_delete( Operation *op, SlapReply *rs )
830 {
831           return over_op_func( op, rs, op_delete );
832 }
833 
834 static int
over_op_abandon(Operation * op,SlapReply * rs)835 over_op_abandon( Operation *op, SlapReply *rs )
836 {
837           return over_op_func( op, rs, op_abandon );
838 }
839 
840 static int
over_op_cancel(Operation * op,SlapReply * rs)841 over_op_cancel( Operation *op, SlapReply *rs )
842 {
843           return over_op_func( op, rs, op_cancel );
844 }
845 
846 static int
over_op_extended(Operation * op,SlapReply * rs)847 over_op_extended( Operation *op, SlapReply *rs )
848 {
849           return over_op_func( op, rs, op_extended );
850 }
851 
852 static int
over_aux_operational(Operation * op,SlapReply * rs)853 over_aux_operational( Operation *op, SlapReply *rs )
854 {
855           return over_op_func( op, rs, op_aux_operational );
856 }
857 
858 static int
over_aux_chk_referrals(Operation * op,SlapReply * rs)859 over_aux_chk_referrals( Operation *op, SlapReply *rs )
860 {
861           return over_op_func( op, rs, op_aux_chk_referrals );
862 }
863 
864 static int
over_aux_chk_controls(Operation * op,SlapReply * rs)865 over_aux_chk_controls( Operation *op, SlapReply *rs )
866 {
867           return over_op_func( op, rs, op_aux_chk_controls );
868 }
869 
870 enum conn_which {
871           conn_init = 0,
872           conn_destroy,
873           conn_last
874 };
875 
876 static int
over_connection_func(BackendDB * bd,Connection * conn,enum conn_which which)877 over_connection_func(
878           BackendDB *bd,
879           Connection          *conn,
880           enum conn_which     which
881 )
882 {
883           slap_overinfo                 *oi;
884           slap_overinst                 *on;
885           BackendDB           db;
886           int                           rc = SLAP_CB_CONTINUE;
887           BI_connection_init  **func;
888 
889           /* FIXME: used to happen for instance during abandon
890            * when global overlays are used... */
891           assert( bd != NULL );
892 
893           oi = bd->bd_info->bi_private;
894           on = oi->oi_list;
895 
896           if ( !SLAP_ISOVERLAY( bd ) ) {
897                     db = *bd;
898                     db.be_flags |= SLAP_DBFLAG_OVERLAY;
899                     bd = &db;
900           }
901 
902           for ( ; on; on = on->on_next ) {
903                     if ( on->on_bi.bi_flags & SLAPO_BFLAG_DISABLED )
904                               continue;
905                     func = &on->on_bi.bi_connection_init;
906                     if ( func[ which ] ) {
907                               bd->bd_info = (BackendInfo *)on;
908                               rc = func[ which ]( bd, conn );
909                               if ( rc != SLAP_CB_CONTINUE ) break;
910                     }
911           }
912 
913           func = &oi->oi_orig->bi_connection_init;
914           if ( func[ which ] && rc == SLAP_CB_CONTINUE ) {
915                     bd->bd_info = oi->oi_orig;
916                     rc = func[ which ]( bd, conn );
917           }
918           /* should not fall thru this far without anything happening... */
919           if ( rc == SLAP_CB_CONTINUE ) {
920                     rc = LDAP_UNWILLING_TO_PERFORM;
921           }
922 
923           return rc;
924 }
925 
926 static int
over_connection_init(BackendDB * bd,Connection * conn)927 over_connection_init(
928           BackendDB *bd,
929           Connection          *conn
930 )
931 {
932           return over_connection_func( bd, conn, conn_init );
933 }
934 
935 static int
over_connection_destroy(BackendDB * bd,Connection * conn)936 over_connection_destroy(
937           BackendDB *bd,
938           Connection          *conn
939 )
940 {
941           return over_connection_func( bd, conn, conn_destroy );
942 }
943 
944 int
overlay_register(slap_overinst * on)945 overlay_register(
946           slap_overinst *on
947 )
948 {
949           slap_overinst       *tmp;
950 
951           /* FIXME: check for duplicates? */
952           for ( tmp = overlays; tmp != NULL; tmp = tmp->on_next ) {
953                     if ( strcmp( on->on_bi.bi_type, tmp->on_bi.bi_type ) == 0 ) {
954                               Debug( LDAP_DEBUG_ANY,
955                                         "overlay_register(\"%s\"): "
956                                         "name already in use.\n",
957                                         on->on_bi.bi_type );
958                               return -1;
959                     }
960 
961                     if ( on->on_bi.bi_obsolete_names != NULL ) {
962                               int       i;
963 
964                               for ( i = 0; on->on_bi.bi_obsolete_names[ i ] != NULL; i++ ) {
965                                         if ( strcmp( on->on_bi.bi_obsolete_names[ i ], tmp->on_bi.bi_type ) == 0 ) {
966                                                   Debug( LDAP_DEBUG_ANY,
967                                                             "overlay_register(\"%s\"): "
968                                                             "obsolete name \"%s\" already in use "
969                                                             "by overlay \"%s\".\n",
970                                                             on->on_bi.bi_type,
971                                                             on->on_bi.bi_obsolete_names[ i ],
972                                                             tmp->on_bi.bi_type );
973                                                   return -1;
974                                         }
975                               }
976                     }
977 
978                     if ( tmp->on_bi.bi_obsolete_names != NULL ) {
979                               int       i;
980 
981                               for ( i = 0; tmp->on_bi.bi_obsolete_names[ i ] != NULL; i++ ) {
982                                         int       j;
983 
984                                         if ( strcmp( on->on_bi.bi_type, tmp->on_bi.bi_obsolete_names[ i ] ) == 0 ) {
985                                                   Debug( LDAP_DEBUG_ANY,
986                                                             "overlay_register(\"%s\"): "
987                                                             "name already in use "
988                                                             "as obsolete by overlay \"%s\".\n",
989                                                             on->on_bi.bi_type,
990                                                             tmp->on_bi.bi_obsolete_names[ i ] );
991                                                   return -1;
992                                         }
993 
994                                         if ( on->on_bi.bi_obsolete_names != NULL ) {
995                                                   for ( j = 0; on->on_bi.bi_obsolete_names[ j ] != NULL; j++ ) {
996                                                             if ( strcmp( on->on_bi.bi_obsolete_names[ j ], tmp->on_bi.bi_obsolete_names[ i ] ) == 0 ) {
997                                                                       Debug( LDAP_DEBUG_ANY,
998                                                                                 "overlay_register(\"%s\"): "
999                                                                                 "obsolete name \"%s\" already in use "
1000                                                                                 "as obsolete by overlay \"%s\".\n",
1001                                                                                 on->on_bi.bi_type,
1002                                                                                 on->on_bi.bi_obsolete_names[ j ],
1003                                                                                 tmp->on_bi.bi_type );
1004                                                                       return -1;
1005                                                             }
1006                                                   }
1007                                         }
1008                               }
1009                     }
1010           }
1011 
1012           on->on_next = overlays;
1013           overlays = on;
1014           return 0;
1015 }
1016 
1017 /*
1018  * iterator on registered overlays; overlay_next( NULL ) returns the first
1019  * overlay; subsequent calls with the previously returned value allow to
1020  * iterate over the entire list; returns NULL when no more overlays are
1021  * registered.
1022  */
1023 
1024 slap_overinst *
overlay_next(slap_overinst * on)1025 overlay_next(
1026           slap_overinst *on
1027 )
1028 {
1029           if ( on == NULL ) {
1030                     return overlays;
1031           }
1032 
1033           return on->on_next;
1034 }
1035 
1036 /*
1037  * returns a specific registered overlay based on the type; NULL if not
1038  * registered.
1039  */
1040 
1041 slap_overinst *
overlay_find(const char * over_type)1042 overlay_find( const char *over_type )
1043 {
1044           slap_overinst *on = overlays;
1045 
1046           assert( over_type != NULL );
1047 
1048           for ( ; on; on = on->on_next ) {
1049                     if ( strcmp( on->on_bi.bi_type, over_type ) == 0 ) {
1050                               goto foundit;
1051                     }
1052 
1053                     if ( on->on_bi.bi_obsolete_names != NULL ) {
1054                               int       i;
1055 
1056                               for ( i = 0; on->on_bi.bi_obsolete_names[ i ] != NULL; i++ ) {
1057                                         if ( strcmp( on->on_bi.bi_obsolete_names[ i ], over_type ) == 0 ) {
1058                                                   Debug( LDAP_DEBUG_ANY,
1059                                                             "overlay_find(\"%s\"): "
1060                                                             "obsolete name for \"%s\".\n",
1061                                                             on->on_bi.bi_obsolete_names[ i ],
1062                                                             on->on_bi.bi_type );
1063                                                   goto foundit;
1064                                         }
1065                               }
1066                     }
1067           }
1068 
1069 foundit:;
1070           return on;
1071 }
1072 
1073 static const char overtype[] = "over";
1074 
1075 /*
1076  * returns TRUE (1) if the database is actually an overlay instance;
1077  * FALSE (0) otherwise.
1078  */
1079 
1080 int
overlay_is_over(BackendDB * be)1081 overlay_is_over( BackendDB *be )
1082 {
1083           return be->bd_info->bi_type == overtype;
1084 }
1085 
1086 /*
1087  * returns TRUE (1) if the given database is actually an overlay
1088  * instance and, somewhere in the list, contains the requested overlay;
1089  * FALSE (0) otherwise.
1090  */
1091 
1092 int
overlay_is_inst(BackendDB * be,const char * over_type)1093 overlay_is_inst( BackendDB *be, const char *over_type )
1094 {
1095           slap_overinst       *on;
1096 
1097           assert( be != NULL );
1098 
1099           if ( !overlay_is_over( be ) ) {
1100                     return 0;
1101           }
1102 
1103           on = ((slap_overinfo *)be->bd_info->bi_private)->oi_list;
1104           for ( ; on; on = on->on_next ) {
1105                     if ( strcmp( on->on_bi.bi_type, over_type ) == 0 ) {
1106                               return 1;
1107                     }
1108           }
1109 
1110           return 0;
1111 }
1112 
1113 int
overlay_register_control(BackendDB * be,const char * oid)1114 overlay_register_control( BackendDB *be, const char *oid )
1115 {
1116           int                 gotit = 0;
1117           int                 cid;
1118 
1119           if ( slap_find_control_id( oid, &cid ) == LDAP_CONTROL_NOT_FOUND ) {
1120                     return -1;
1121           }
1122 
1123           if ( SLAP_ISGLOBALOVERLAY( be ) ) {
1124                     BackendDB *bd;
1125 
1126                     /* add to all backends... */
1127                     LDAP_STAILQ_FOREACH( bd, &backendDB, be_next ) {
1128                               if ( bd == be->bd_self ) {
1129                                         gotit = 1;
1130                               }
1131 
1132                               /* overlays can be instantiated multiple times, use
1133                                * be_ctrls[ cid ] as an instance counter, so that the
1134                                * overlay's controls are only really disabled after the
1135                                * last instance called overlay_register_control() */
1136                               bd->be_ctrls[ cid ]++;
1137                               bd->be_ctrls[ SLAP_MAX_CIDS ] = 1;
1138                     }
1139 
1140           }
1141 
1142           if ( !gotit ) {
1143                     /* overlays can be instantiated multiple times, use
1144                      * be_ctrls[ cid ] as an instance counter, so that the
1145                      * overlay's controls are only really unregistered after the
1146                      * last instance called overlay_register_control() */
1147                     be->bd_self->be_ctrls[ cid ]++;
1148                     be->bd_self->be_ctrls[ SLAP_MAX_CIDS ] = 1;
1149           }
1150 
1151           return 0;
1152 }
1153 
1154 #ifdef SLAP_CONFIG_DELETE
1155 void
overlay_unregister_control(BackendDB * be,const char * oid)1156 overlay_unregister_control( BackendDB *be, const char *oid )
1157 {
1158           int                 gotit = 0;
1159           int                 cid;
1160 
1161           if ( slap_find_control_id( oid, &cid ) == LDAP_CONTROL_NOT_FOUND ) {
1162                     return;
1163           }
1164 
1165           if ( SLAP_ISGLOBALOVERLAY( be ) ) {
1166                     BackendDB *bd;
1167 
1168                     /* remove from all backends... */
1169                     LDAP_STAILQ_FOREACH( bd, &backendDB, be_next ) {
1170                               if ( bd == be->bd_self ) {
1171                                         gotit = 1;
1172                               }
1173 
1174                               bd->be_ctrls[ cid ]--;
1175                     }
1176           }
1177 
1178           if ( !gotit ) {
1179                     be->bd_self->be_ctrls[ cid ]--;
1180           }
1181 }
1182 #endif /* SLAP_CONFIG_DELETE */
1183 
1184 void
overlay_destroy_one(BackendDB * be,slap_overinst * on)1185 overlay_destroy_one( BackendDB *be, slap_overinst *on )
1186 {
1187           slap_overinfo *oi = on->on_info;
1188           slap_overinst **oidx;
1189 
1190           for ( oidx = &oi->oi_list; *oidx; oidx = &(*oidx)->on_next ) {
1191                     if ( *oidx == on ) {
1192                               *oidx = on->on_next;
1193                               if ( on->on_bi.bi_db_destroy ) {
1194                                         BackendInfo *bi_orig = be->bd_info;
1195                                         be->bd_info = (BackendInfo *)on;
1196                                         on->on_bi.bi_db_destroy( be, NULL );
1197                                         be->bd_info = bi_orig;
1198                               }
1199                               free( on );
1200                               break;
1201                     }
1202           }
1203 }
1204 
1205 #ifdef SLAP_CONFIG_DELETE
1206 typedef struct ov_remove_ctx {
1207           BackendDB be;
1208           slap_overinst *on;
1209 } ov_remove_ctx;
1210 
1211 int
overlay_remove_cb(Operation * op,SlapReply * rs)1212 overlay_remove_cb( Operation *op, SlapReply *rs )
1213 {
1214           slap_callback *sc = op->o_callback;
1215           ov_remove_ctx *rm_ctx = (ov_remove_ctx*) op->o_callback->sc_private;
1216 
1217           op->o_callback = sc->sc_next;
1218           rm_ctx->be.bd_info = (BackendInfo*) rm_ctx->on;
1219 
1220           if ( rm_ctx->on->on_bi.bi_db_close ) {
1221                     rm_ctx->on->on_bi.bi_db_close( &rm_ctx->be, NULL );
1222           }
1223           if ( rm_ctx->on->on_bi.bi_db_destroy ) {
1224                     rm_ctx->on->on_bi.bi_db_destroy( &rm_ctx->be, NULL );
1225           }
1226 
1227           /* clean up after removing last overlay */
1228           if ( ! rm_ctx->on->on_info->oi_list ) {
1229                     ch_free(rm_ctx->on->on_info);
1230           }
1231           ch_free( rm_ctx->on );
1232           op->o_tmpfree( sc, op->o_tmpmemctx );
1233           return SLAP_CB_CONTINUE;
1234 }
1235 
1236 void
overlay_remove(BackendDB * be,slap_overinst * on,Operation * op)1237 overlay_remove( BackendDB *be, slap_overinst *on, Operation *op )
1238 {
1239           slap_overinfo *oi = on->on_info;
1240           slap_overinst **oidx;
1241           ov_remove_ctx *rm_ctx;
1242           slap_callback *rm_cb, *cb;
1243 
1244           /* remove overlay from oi_list */
1245           for ( oidx = &oi->oi_list; *oidx; oidx = &(*oidx)->on_next ) {
1246                     if ( *oidx == on ) {
1247                               *oidx = on->on_next;
1248                               break;
1249                     }
1250           }
1251 
1252           /* The db_close and db_destroy handlers to cleanup a release
1253            * the overlay's resources are called from the cleanup callback
1254            */
1255 
1256           rm_cb = op->o_tmpalloc( sizeof( slap_callback ) + sizeof( ov_remove_ctx ), op->o_tmpmemctx );
1257           rm_cb->sc_next = NULL;
1258           rm_cb->sc_cleanup = overlay_remove_cb;
1259           rm_cb->sc_response = NULL;
1260           rm_cb->sc_private = (void*) ( rm_cb + 1 );
1261           rm_cb->sc_writewait = NULL;
1262 
1263           rm_ctx = rm_cb->sc_private;
1264           rm_ctx->be = *be;
1265           rm_ctx->on = on;
1266 
1267           /* Append callback to the end of the list */
1268           if ( !op->o_callback ) {
1269                     op->o_callback = rm_cb;
1270           } else {
1271                     for ( cb = op->o_callback; cb->sc_next; cb = cb->sc_next );
1272                     cb->sc_next = rm_cb;
1273           }
1274 
1275           /* if this is the last overlay */
1276           if ( ! on->on_info->oi_list ) {
1277                     /* reset db flags and bd_info to orig */
1278                     SLAP_DBFLAGS( be ) &= ~SLAP_DBFLAG_GLOBAL_OVERLAY;
1279                     be->bd_info = on->on_info->oi_orig;
1280           }
1281 }
1282 #endif /* SLAP_CONFIG_DELETE */
1283 
1284 void
overlay_insert(BackendDB * be,slap_overinst * on2,slap_overinst *** prev,int idx)1285 overlay_insert( BackendDB *be, slap_overinst *on2, slap_overinst ***prev,
1286           int idx )
1287 {
1288           slap_overinfo *oi = (slap_overinfo *)be->bd_info;
1289 
1290           if ( idx == -1 ) {
1291                     on2->on_next = oi->oi_list;
1292                     oi->oi_list = on2;
1293           } else {
1294                     int i, novs;
1295                     slap_overinst *on, **prev;
1296 
1297                     /* Since the list is in reverse order and is singly linked,
1298                      * we have to count the overlays and then insert backwards.
1299                      * Adding on overlay at a specific point should be a pretty
1300                      * infrequent occurrence.
1301                      */
1302                     novs = 0;
1303                     for ( on = oi->oi_list; on; on=on->on_next )
1304                               novs++;
1305 
1306                     if (idx > novs)
1307                               idx = 0;
1308                     else
1309                               idx = novs - idx;
1310 
1311                     /* advance to insertion point */
1312                     prev = &oi->oi_list;
1313                     for ( i=0; i<idx; i++ ) {
1314                               on = *prev;
1315                               prev = &on->on_next;
1316                     }
1317                     /* insert */
1318                     on2->on_next = *prev;
1319                     *prev = on2;
1320           }
1321 }
1322 
1323 void
overlay_move(BackendDB * be,slap_overinst * on,int idx)1324 overlay_move( BackendDB *be, slap_overinst *on, int idx )
1325 {
1326           slap_overinfo *oi = (slap_overinfo *)be->bd_info;
1327           slap_overinst **onp;
1328 
1329           for (onp = &oi->oi_list; *onp; onp= &(*onp)->on_next) {
1330                     if ( *onp == on ) {
1331                               *onp = on->on_next;
1332                               break;
1333                     }
1334           }
1335           overlay_insert( be, on, &onp, idx );
1336 }
1337 
1338 /* add an overlay to a particular backend. */
1339 int
overlay_config(BackendDB * be,const char * ov,int idx,BackendInfo ** res,ConfigReply * cr)1340 overlay_config( BackendDB *be, const char *ov, int idx, BackendInfo **res, ConfigReply *cr )
1341 {
1342           slap_overinst *on = NULL, *on2 = NULL, **prev;
1343           slap_overinfo *oi = NULL;
1344           BackendInfo *bi = NULL;
1345 
1346           if ( res )
1347                     *res = NULL;
1348 
1349           on = overlay_find( ov );
1350           if ( !on ) {
1351                     Debug( LDAP_DEBUG_ANY, "overlay \"%s\" not found\n", ov );
1352                     return 1;
1353           }
1354 
1355           /* If this is the first overlay on this backend, set up the
1356            * overlay info structure
1357            */
1358           if ( !overlay_is_over( be ) ) {
1359                     int       isglobal = 0;
1360 
1361                     /* NOTE: the first time a global overlay is configured,
1362                      * frontendDB gets this flag; it is used later by overlays
1363                      * to determine if they're stacked on top of the frontendDB */
1364                     if ( be->bd_info == frontendDB->bd_info || SLAP_ISGLOBALOVERLAY( be ) ) {
1365                               isglobal = 1;
1366                               if ( on->on_bi.bi_flags & SLAPO_BFLAG_DBONLY ) {
1367                                         snprintf( cr->msg, sizeof( cr->msg ), "overlay_config(): "
1368                                                   "overlay \"%s\" cannot be global.", ov );
1369                                         Debug( LDAP_DEBUG_ANY, "%s\n", cr->msg );
1370                                         return 1;
1371                               }
1372 
1373                     } else if ( on->on_bi.bi_flags & SLAPO_BFLAG_GLOBONLY ) {
1374                               snprintf( cr->msg, sizeof( cr->msg ), "overlay_config(): "
1375                                         "overlay \"%s\" can only be global.", ov );
1376                               Debug( LDAP_DEBUG_ANY, "%s\n", cr->msg );
1377                               return 1;
1378                     }
1379 
1380                     oi = ch_malloc( sizeof( slap_overinfo ) );
1381                     oi->oi_orig = be->bd_info;
1382                     oi->oi_bi = *be->bd_info;
1383                     oi->oi_origdb = be;
1384 
1385                     if ( isglobal ) {
1386                               SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_GLOBAL_OVERLAY;
1387                     }
1388 
1389                     /* Save a pointer to ourself in bi_private.
1390                      */
1391                     oi->oi_bi.bi_private = oi;
1392                     oi->oi_list = NULL;
1393                     bi = (BackendInfo *)oi;
1394 
1395                     bi->bi_type = (char *)overtype;
1396 
1397                     bi->bi_db_config = over_db_config;
1398                     bi->bi_db_open = over_db_open;
1399                     bi->bi_db_close = over_db_close;
1400                     bi->bi_db_destroy = over_db_destroy;
1401 
1402                     bi->bi_op_bind = over_op_bind;
1403                     bi->bi_op_unbind = over_op_unbind;
1404                     bi->bi_op_search = over_op_search;
1405                     bi->bi_op_compare = over_op_compare;
1406                     bi->bi_op_modify = over_op_modify;
1407                     bi->bi_op_modrdn = over_op_modrdn;
1408                     bi->bi_op_add = over_op_add;
1409                     bi->bi_op_delete = over_op_delete;
1410                     bi->bi_op_abandon = over_op_abandon;
1411                     bi->bi_op_cancel = over_op_cancel;
1412 
1413                     bi->bi_extended = over_op_extended;
1414 
1415                     /*
1416                      * this is fine because it has the same
1417                      * args of the operations; we need to rework
1418                      * all the hooks to share the same args
1419                      * of the operations...
1420                      */
1421                     bi->bi_operational = over_aux_operational;
1422                     bi->bi_chk_referrals = over_aux_chk_referrals;
1423                     bi->bi_chk_controls = over_aux_chk_controls;
1424 
1425                     /* these have specific arglists */
1426                     bi->bi_entry_get_rw = over_entry_get_rw;
1427                     bi->bi_entry_release_rw = over_entry_release_rw;
1428                     bi->bi_access_allowed = over_access_allowed;
1429                     bi->bi_acl_group = over_acl_group;
1430                     bi->bi_acl_attribute = over_acl_attribute;
1431 
1432                     bi->bi_connection_init = over_connection_init;
1433                     bi->bi_connection_destroy = over_connection_destroy;
1434 
1435                     be->bd_info = bi;
1436 
1437           } else {
1438                     if ( overlay_is_inst( be, ov ) ) {
1439                               if ( on->on_bi.bi_flags & SLAPO_BFLAG_SINGLE ) {
1440                                         snprintf( cr->msg, sizeof( cr->msg ), "overlay_config(): "
1441                                                   "overlay \"%s\" already in list", ov );
1442                                         Debug( LDAP_DEBUG_ANY, "%s\n", cr->msg );
1443                                         return 1;
1444                               }
1445                     }
1446 
1447                     oi = be->bd_info->bi_private;
1448           }
1449 
1450           /* Insert new overlay into list. By default overlays are
1451            * added to head of list and executed in LIFO order.
1452            */
1453           on2 = ch_calloc( 1, sizeof(slap_overinst) );
1454           *on2 = *on;
1455           on2->on_info = oi;
1456 
1457           prev = &oi->oi_list;
1458           /* Do we need to find the insertion point? */
1459           if ( idx >= 0 ) {
1460                     int i;
1461 
1462                     /* count current overlays */
1463                     for ( i=0, on=oi->oi_list; on; on=on->on_next, i++ );
1464 
1465                     /* are we just appending a new one? */
1466                     if ( idx >= i )
1467                               idx = -1;
1468           }
1469           overlay_insert( be, on2, &prev, idx );
1470 
1471           /* Any initialization needed? */
1472           if ( on2->on_bi.bi_db_init ) {
1473                     int rc;
1474                     be->bd_info = (BackendInfo *)on2;
1475                     rc = on2->on_bi.bi_db_init( be, cr);
1476                     be->bd_info = (BackendInfo *)oi;
1477                     if ( rc ) {
1478                               *prev = on2->on_next;
1479                               ch_free( on2 );
1480                               on2 = NULL;
1481                               return rc;
1482                     }
1483           }
1484 
1485           if ( res )
1486                     *res = &on2->on_bi;
1487 
1488           return 0;
1489 }
1490