]> git.sur5r.net Git - openldap/blob - servers/slapd/backover.c
bda4c6cb03c6538ff8c21522780a0a9774666976
[openldap] / servers / slapd / backover.c
1 /* backover.c - backend overlay routines */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2003-2005 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 /* Functions to overlay other modules over a backend. */
18
19 #include "portable.h"
20
21 #include <stdio.h>
22
23 #include <ac/string.h>
24 #include <ac/socket.h>
25
26 #define SLAPD_TOOLS
27 #include "slap.h"
28 #include "config.h"
29
30 static slap_overinst *overlays;
31
32 enum db_which { db_open = 0, db_close, db_destroy };
33
34 static int
35 over_db_func(
36         BackendDB *be,
37         enum db_which which
38 )
39 {
40         slap_overinfo *oi = be->bd_info->bi_private;
41         slap_overinst *on = oi->oi_list;
42         BackendInfo *bi_orig = be->bd_info;
43         BI_db_open **func;
44         int rc = 0;
45
46         func = &oi->oi_orig->bi_db_open;
47         if ( func[which] ) {
48                 be->bd_info = oi->oi_orig;
49                 rc = func[which]( be );
50         }
51
52         for (; on && rc == 0; on=on->on_next) {
53                 be->bd_info = &on->on_bi;
54                 func = &on->on_bi.bi_db_open;
55                 if (func[which]) {
56                         rc = func[which]( be );
57                 }
58         }
59         be->bd_info = bi_orig;
60         return rc;
61 }
62
63 static int
64 over_db_config(
65         BackendDB *be,
66         const char *fname,
67         int lineno,
68         int argc,
69         char **argv
70 )
71 {
72         slap_overinfo *oi = be->bd_info->bi_private;
73         slap_overinst *on = oi->oi_list;
74         BackendInfo *bi_orig = be->bd_info;
75         ConfigArgs ca;
76         ConfigTable *ct;
77         int rc = 0;
78
79         if ( oi->oi_orig->bi_db_config ) {
80                 be->bd_info = oi->oi_orig;
81                 rc = oi->oi_orig->bi_db_config( be, fname, lineno,
82                         argc, argv );
83
84                 if ( be->bd_info != oi->oi_orig ) {
85                         slap_overinfo   *oi2;
86                         slap_overinst   *on2, **onp;
87                         BackendDB       be2 = *be;
88                         int             i;
89
90                         /* a database added an overlay;
91                          * work it around... */
92                         assert( overlay_is_over( be ) );
93                         
94                         oi2 = ( slap_overinfo * )be->bd_info->bi_private;
95                         on2 = oi2->oi_list;
96
97                         /* need to put a uniqueness check here as well;
98                          * note that in principle there could be more than
99                          * one overlay as a result of multiple calls to
100                          * overlay_config() */
101                         be2.bd_info = (BackendInfo *)oi;
102
103                         for ( i = 0, onp = &on2; *onp; i++, onp = &(*onp)->on_next ) {
104                                 if ( overlay_is_inst( &be2, (*onp)->on_bi.bi_type ) ) {
105                                         Debug( LDAP_DEBUG_ANY, "over_db_config(): "
106                                                         "warning, freshly added "
107                                                         "overlay #%d \"%s\" is already in list\n",
108                                                         i, (*onp)->on_bi.bi_type, 0 );
109
110                                         /* NOTE: if the overlay already exists,
111                                          * there is no way to merge the results
112                                          * of the configuration that may have 
113                                          * occurred during bi_db_config(); we
114                                          * just issue a warning, and the 
115                                          * administrator should deal with this */
116                                 }
117                         }
118                         *onp = oi->oi_list;
119
120                         oi->oi_list = on2;
121
122                         ch_free( be->bd_info );
123                 }
124
125                 be->bd_info = (BackendInfo *)oi;
126                 if ( rc != SLAP_CONF_UNKNOWN ) return rc;
127         }
128
129         ca.argv = argv;
130         ca.argc = argc;
131         ca.fname = fname;
132         ca.lineno = lineno;
133         ca.be = be;
134         for (; on; on=on->on_next) {
135                 rc = SLAP_CONF_UNKNOWN;
136                 if (on->on_bi.bi_cf_ocs) {
137                         ConfigTable *ct;
138                         ca.bi = &on->on_bi;
139                         ct = config_find_keyword( on->on_bi.bi_cf_ocs->co_table, &ca );
140                         if ( ct ) {
141                                 rc = config_add_vals( ct, &ca );
142                         }
143                 }
144                 if (on->on_bi.bi_db_config && rc == SLAP_CONF_UNKNOWN) {
145                         be->bd_info = &on->on_bi;
146                         rc = on->on_bi.bi_db_config( be, fname, lineno,
147                                 argc, argv );
148                         if ( rc != SLAP_CONF_UNKNOWN ) break;
149                 }
150         }
151         be->bd_info = bi_orig;
152         return rc;
153 }
154
155 static int
156 over_db_open(
157         BackendDB *be
158 )
159 {
160         return over_db_func( be, db_open );
161 }
162
163 static int
164 over_db_close(
165         BackendDB *be
166 )
167 {
168         slap_overinfo *oi = be->bd_info->bi_private;
169         slap_overinst *on = oi->oi_list;
170         BackendInfo *bi_orig = be->bd_info;
171         int rc = 0;
172
173         for (; on && rc == 0; on=on->on_next) {
174                 be->bd_info = &on->on_bi;
175                 if ( be->bd_info->bi_db_close ) {
176                         rc = be->bd_info->bi_db_close( be );
177                 }
178         }
179
180         if ( oi->oi_orig->bi_db_close ) {
181                 be->bd_info = oi->oi_orig;
182                 rc = be->bd_info->bi_db_close( be );
183         }
184
185         be->bd_info = bi_orig;
186         return rc;
187 }
188
189 static int
190 over_db_destroy(
191         BackendDB *be
192 )
193 {
194         slap_overinfo *oi = be->bd_info->bi_private;
195         slap_overinst *on = oi->oi_list, *next;
196         int rc;
197
198         rc = over_db_func( be, db_destroy );
199
200         for (next = on->on_next; on; on=next) {
201                 next = on->on_next;
202                 free( on );
203         }
204         free( oi );
205         return rc;
206 }
207
208 static int
209 over_back_response ( Operation *op, SlapReply *rs )
210 {
211         slap_overinfo *oi = op->o_callback->sc_private;
212         slap_overinst *on = oi->oi_list;
213         int rc = SLAP_CB_CONTINUE;
214         BackendDB *be = op->o_bd, db = *op->o_bd;
215
216         db.be_flags |= SLAP_DBFLAG_OVERLAY;
217         op->o_bd = &db;
218         for (; on; on=on->on_next ) {
219                 if ( on->on_response ) {
220                         db.bd_info = (BackendInfo *)on;
221                         rc = on->on_response( op, rs );
222                         if ( rc != SLAP_CB_CONTINUE ) break;
223                 }
224         }
225         op->o_bd = be;
226         return rc;
227 }
228
229 enum op_which {
230         op_bind = 0,
231         op_unbind,
232         op_search,
233         op_compare,
234         op_modify,
235         op_modrdn,
236         op_add,
237         op_delete,
238         op_abandon,
239         op_cancel,
240         op_extended,
241         op_aux_operational,
242         op_aux_chk_referrals,
243         op_aux_chk_controls,
244         op_last
245 };
246
247 /*
248  * default return code in case of missing backend function
249  * and overlay stack returning SLAP_CB_CONTINUE
250  */
251 static int op_rc[] = {
252         LDAP_UNWILLING_TO_PERFORM,      /* bind */
253         LDAP_UNWILLING_TO_PERFORM,      /* unbind */
254         LDAP_UNWILLING_TO_PERFORM,      /* search */
255         SLAP_CB_CONTINUE,               /* compare; pass to frontend */
256         LDAP_UNWILLING_TO_PERFORM,      /* modify */
257         LDAP_UNWILLING_TO_PERFORM,      /* modrdn */
258         LDAP_UNWILLING_TO_PERFORM,      /* add */
259         LDAP_UNWILLING_TO_PERFORM,      /* delete */
260         LDAP_UNWILLING_TO_PERFORM,      /* abandon */
261         LDAP_UNWILLING_TO_PERFORM,      /* cancel */
262         LDAP_UNWILLING_TO_PERFORM,      /* extended */
263         LDAP_SUCCESS,                   /* aux_operational */
264         LDAP_SUCCESS,                   /* aux_chk_referrals */
265         SLAP_CB_CONTINUE                /* aux_chk_controls; pass to frontend */
266 };
267
268 #ifdef SLAP_OVERLAY_ACCESS
269 static int
270 over_access_allowed(
271         Operation               *op,
272         Entry                   *e,
273         AttributeDescription    *desc,
274         struct berval           *val,
275         slap_access_t           access,
276         AccessControlState      *state,
277         slap_mask_t             *maskp )
278 {
279         slap_overinfo *oi;
280         slap_overinst *on;
281         BackendInfo *bi = op->o_bd->bd_info;
282         BackendDB *be = op->o_bd, db;
283         int rc = SLAP_CB_CONTINUE;
284
285         /* FIXME: used to happen for instance during abandon
286          * when global overlays are used... */
287         assert( op->o_bd != NULL );
288
289         oi = op->o_bd->bd_info->bi_private;
290         on = oi->oi_list;
291
292         for ( ; on; on = on->on_next ) {
293                 if ( on->on_bi.bi_access_allowed ) {
294                         /* NOTE: do not copy the structure until required */
295                         if ( !SLAP_ISOVERLAY( op->o_bd ) ) {
296                                 db = *op->o_bd;
297                                 db.be_flags |= SLAP_DBFLAG_OVERLAY;
298                                 op->o_bd = &db;
299                         }
300
301                         op->o_bd->bd_info = (BackendInfo *)on;
302                         rc = on->on_bi.bi_access_allowed( op, e,
303                                 desc, val, access, state, maskp );
304                         if ( rc != SLAP_CB_CONTINUE ) break;
305                 }
306         }
307
308         if ( rc == SLAP_CB_CONTINUE ) {
309                 BI_access_allowed       *bi_access_allowed;
310
311                 /* if the database structure was changed, o_bd points to a
312                  * copy of the structure; put the original bd_info in place */
313                 if ( SLAP_ISOVERLAY( op->o_bd ) ) {
314                         op->o_bd->bd_info = oi->oi_orig;
315                 }
316
317                 if ( oi->oi_orig->bi_access_allowed ) {
318                         bi_access_allowed = oi->oi_orig->bi_access_allowed;
319                 } else {
320                         bi_access_allowed = slap_access_allowed;
321                 }
322
323                 rc = bi_access_allowed( op, e,
324                         desc, val, access, state, maskp );
325         }
326         /* should not fall thru this far without anything happening... */
327         if ( rc == SLAP_CB_CONTINUE ) {
328                 /* access not allowed */
329                 rc = 0;
330         }
331
332         op->o_bd = be;
333         op->o_bd->bd_info = bi;
334
335         return rc;
336 }
337 #endif /* SLAP_OVERLAY_ACCESS */
338
339 static int
340 over_op_func(
341         Operation *op,
342         SlapReply *rs,
343         enum op_which which
344 )
345 {
346         slap_overinfo *oi;
347         slap_overinst *on;
348         BI_op_bind **func;
349         BackendDB *be = op->o_bd, db;
350         slap_callback cb = {NULL, over_back_response, NULL, NULL};
351         int rc = SLAP_CB_CONTINUE;
352
353         /* FIXME: used to happen for instance during abandon
354          * when global overlays are used... */
355         assert( op->o_bd != NULL );
356
357         oi = op->o_bd->bd_info->bi_private;
358         on = oi->oi_list;
359
360         if ( !SLAP_ISOVERLAY( op->o_bd )) {
361                 db = *op->o_bd;
362                 db.be_flags |= SLAP_DBFLAG_OVERLAY;
363                 op->o_bd = &db;
364         }
365         cb.sc_next = op->o_callback;
366         cb.sc_private = oi;
367         op->o_callback = &cb;
368
369         for (; on; on=on->on_next ) {
370                 func = &on->on_bi.bi_op_bind;
371                 if ( func[which] ) {
372                         op->o_bd->bd_info = (BackendInfo *)on;
373                         rc = func[which]( op, rs );
374                         if ( rc != SLAP_CB_CONTINUE ) break;
375                 }
376         }
377
378         func = &oi->oi_orig->bi_op_bind;
379         if ( func[which] && rc == SLAP_CB_CONTINUE ) {
380                 op->o_bd->bd_info = oi->oi_orig;
381                 rc = func[which]( op, rs );
382         }
383         /* should not fall thru this far without anything happening... */
384         if ( rc == SLAP_CB_CONTINUE ) {
385                 rc = op_rc[ which ];
386         }
387
388         /* The underlying backend didn't handle the request, make sure
389          * overlay cleanup is processed.
390          */
391         if ( rc == LDAP_UNWILLING_TO_PERFORM ) {
392                 slap_callback *sc_next;
393                 for ( ; op->o_callback && op->o_callback != cb.sc_next; 
394                         op->o_callback = sc_next ) {
395                         sc_next = op->o_callback->sc_next;
396                         if ( op->o_callback->sc_cleanup ) {
397                                 op->o_callback->sc_cleanup( op, rs );
398                         }
399                 }
400         }
401         op->o_bd = be;
402         op->o_callback = cb.sc_next;
403         return rc;
404 }
405
406 static int
407 over_op_bind( Operation *op, SlapReply *rs )
408 {
409         return over_op_func( op, rs, op_bind );
410 }
411
412 static int
413 over_op_unbind( Operation *op, SlapReply *rs )
414 {
415         return over_op_func( op, rs, op_unbind );
416 }
417
418 static int
419 over_op_search( Operation *op, SlapReply *rs )
420 {
421         return over_op_func( op, rs, op_search );
422 }
423
424 static int
425 over_op_compare( Operation *op, SlapReply *rs )
426 {
427         return over_op_func( op, rs, op_compare );
428 }
429
430 static int
431 over_op_modify( Operation *op, SlapReply *rs )
432 {
433         return over_op_func( op, rs, op_modify );
434 }
435
436 static int
437 over_op_modrdn( Operation *op, SlapReply *rs )
438 {
439         return over_op_func( op, rs, op_modrdn );
440 }
441
442 static int
443 over_op_add( Operation *op, SlapReply *rs )
444 {
445         return over_op_func( op, rs, op_add );
446 }
447
448 static int
449 over_op_delete( Operation *op, SlapReply *rs )
450 {
451         return over_op_func( op, rs, op_delete );
452 }
453
454 static int
455 over_op_abandon( Operation *op, SlapReply *rs )
456 {
457         return over_op_func( op, rs, op_abandon );
458 }
459
460 static int
461 over_op_cancel( Operation *op, SlapReply *rs )
462 {
463         return over_op_func( op, rs, op_cancel );
464 }
465
466 static int
467 over_op_extended( Operation *op, SlapReply *rs )
468 {
469         return over_op_func( op, rs, op_extended );
470 }
471
472 static int
473 over_aux_operational( Operation *op, SlapReply *rs )
474 {
475         return over_op_func( op, rs, op_aux_operational );
476 }
477
478 static int
479 over_aux_chk_referrals( Operation *op, SlapReply *rs )
480 {
481         return over_op_func( op, rs, op_aux_chk_referrals );
482 }
483
484 static int
485 over_aux_chk_controls( Operation *op, SlapReply *rs )
486 {
487         return over_op_func( op, rs, op_aux_chk_controls );
488 }
489
490 static int
491 over_connection_destroy(
492         BackendDB       *bd,
493         Connection      *conn
494 )
495 {
496         slap_overinfo *oi;
497         slap_overinst *on;
498         BackendDB db;
499         int rc = SLAP_CB_CONTINUE;
500
501         /* FIXME: used to happen for instance during abandon
502          * when global overlays are used... */
503         assert( bd != NULL );
504
505         oi = bd->bd_info->bi_private;
506         on = oi->oi_list;
507
508         if ( !SLAP_ISOVERLAY( bd )) {
509                 db = *bd;
510                 db.be_flags |= SLAP_DBFLAG_OVERLAY;
511                 bd = &db;
512         }
513
514         for (; on; on=on->on_next ) {
515                 if ( on->on_bi.bi_connection_destroy ) {
516                         bd->bd_info = (BackendInfo *)on;
517                         rc = on->on_bi.bi_connection_destroy( bd, conn );
518                         if ( rc != SLAP_CB_CONTINUE ) break;
519                 }
520         }
521
522         if ( oi->oi_orig->bi_connection_destroy && rc == SLAP_CB_CONTINUE ) {
523                 bd->bd_info = oi->oi_orig;
524                 rc = oi->oi_orig->bi_connection_destroy( bd, conn );
525         }
526         /* should not fall thru this far without anything happening... */
527         if ( rc == SLAP_CB_CONTINUE ) {
528                 rc = LDAP_UNWILLING_TO_PERFORM;
529         }
530
531         return rc;
532 }
533
534 int
535 overlay_register(
536         slap_overinst *on
537 )
538 {
539         on->on_next = overlays;
540         overlays = on;
541         return 0;
542 }
543
544 /*
545  * iterator on registered overlays; overlay_next( NULL ) returns the first
546  * overlay; * subsequent calls with the previously returned value allow to 
547  * iterate * over the entire list; returns NULL when no more overlays are 
548  * registered.
549  */
550
551 slap_overinst *
552 overlay_next(
553         slap_overinst *on
554 )
555 {
556         if ( on == NULL ) {
557                 return overlays;
558         }
559
560         return on->on_next;
561 }
562
563 /*
564  * returns a specific registered overlay based on the type; NULL if not
565  * registered.
566  */
567
568 slap_overinst *
569 overlay_find( const char *over_type )
570 {
571         slap_overinst *on = overlays;
572
573         assert( over_type );
574
575         for ( ; on; on = on->on_next ) {
576                 if ( strcmp( on->on_bi.bi_type, over_type ) == 0 ) {
577                         break;
578                 }
579         }
580
581         return on;
582 }
583
584 static const char overtype[] = "over";
585
586 /*
587  * returns TRUE (1) if the database is actually an overlay instance;
588  * FALSE (0) otherwise.
589  */
590
591 int
592 overlay_is_over( BackendDB *be )
593 {
594         return be->bd_info->bi_type == overtype;
595 }
596
597 /*
598  * returns TRUE (1) if the given database is actually an overlay
599  * instance and, somewhere in the list, contains the requested overlay;
600  * FALSE (0) otherwise.
601  */
602
603 int
604 overlay_is_inst( BackendDB *be, const char *over_type )
605 {
606         slap_overinst   *on;
607
608         assert( be );
609
610         if ( !overlay_is_over( be ) ) {
611                 return 0;
612         }
613         
614         on = ((slap_overinfo *)be->bd_info->bi_private)->oi_list;
615         for ( ; on; on = on->on_next ) {
616                 if ( strcmp( on->on_bi.bi_type, over_type ) == 0 ) {
617                         return 1;
618                 }
619         }
620
621         return 0;
622 }
623
624 int
625 overlay_register_control( BackendDB *be, const char *oid )
626 {
627         int             rc = 0;
628         int             gotit = 0;
629         int             cid;
630
631         if ( slap_find_control_id( oid, &cid ) == LDAP_CONTROL_NOT_FOUND ) {
632                 return -1;
633         }
634
635         if ( SLAP_DBFLAGS( be ) & SLAP_DBFLAG_GLOBAL_OVERLAY ) {
636                 BackendDB *bd;
637                 
638                 /* add to all backends... */
639                 LDAP_STAILQ_FOREACH( bd, &backendDB, be_next ) {
640                         if ( be == bd ) {
641                                 gotit = 1;
642                         }
643
644                         bd->be_ctrls[ cid ] = 1;
645                         bd->be_ctrls[ SLAP_MAX_CIDS ] = 1;
646                 }
647
648         }
649         
650         if ( rc == 0 && !gotit ) {
651                 be->be_ctrls[ cid ] = 1;
652                 be->be_ctrls[ SLAP_MAX_CIDS ] = 1;
653         }
654
655         return rc;
656 }
657
658 /* add an overlay to a particular backend. */
659 int
660 overlay_config( BackendDB *be, const char *ov )
661 {
662         slap_overinst *on = NULL, *on2 = NULL;
663         slap_overinfo *oi = NULL;
664         BackendInfo *bi = NULL;
665
666         on = overlay_find( ov );
667         if ( !on ) {
668                 Debug( LDAP_DEBUG_ANY, "overlay \"%s\" not found\n", ov, 0, 0 );
669                 return 1;
670         }
671
672         /* If this is the first overlay on this backend, set up the
673          * overlay info structure
674          */
675         if ( !overlay_is_over( be ) ) {
676                 oi = ch_malloc( sizeof( slap_overinfo ) );
677                 oi->oi_orig = be->bd_info;
678                 oi->oi_bi = *be->bd_info;
679
680                 /* NOTE: the first time a global overlay is configured,
681                  * frontendDB gets this flag; it is used later by overlays
682                  * to determine if they're stacked on top of the frontendDB */
683                 if ( oi->oi_orig == frontendDB->bd_info ) {
684                         SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_GLOBAL_OVERLAY;
685                 }
686
687                 /* Save a pointer to ourself in bi_private.
688                  */
689                 oi->oi_bi.bi_private = oi;
690                 oi->oi_list = NULL;
691                 bi = (BackendInfo *)oi;
692
693                 bi->bi_type = (char *)overtype;
694
695                 bi->bi_db_config = over_db_config;
696                 bi->bi_db_open = over_db_open;
697                 bi->bi_db_close = over_db_close;
698                 bi->bi_db_destroy = over_db_destroy;
699
700                 bi->bi_op_bind = over_op_bind;
701                 bi->bi_op_unbind = over_op_unbind;
702                 bi->bi_op_search = over_op_search;
703                 bi->bi_op_compare = over_op_compare;
704                 bi->bi_op_modify = over_op_modify;
705                 bi->bi_op_modrdn = over_op_modrdn;
706                 bi->bi_op_add = over_op_add;
707                 bi->bi_op_delete = over_op_delete;
708                 bi->bi_op_abandon = over_op_abandon;
709                 bi->bi_op_cancel = over_op_cancel;
710
711                 bi->bi_extended = over_op_extended;
712
713                 /*
714                  * this is fine because it has the same
715                  * args of the operations; we need to rework
716                  * all the hooks to share the same args
717                  * of the operations...
718                  */
719                 bi->bi_operational = over_aux_operational;
720                 bi->bi_chk_referrals = over_aux_chk_referrals;
721                 bi->bi_chk_controls = over_aux_chk_controls;
722
723 #ifdef SLAP_OVERLAY_ACCESS
724                 /* this has a specific arglist */
725                 bi->bi_access_allowed = over_access_allowed;
726 #endif /* SLAP_OVERLAY_ACCESS */
727                 
728                 bi->bi_connection_destroy = over_connection_destroy;
729
730                 be->bd_info = bi;
731
732         } else {
733                 if ( overlay_is_inst( be, ov ) ) {
734                         Debug( LDAP_DEBUG_ANY, "overlay_config(): "
735                                         "warning, overlay \"%s\" "
736                                         "already in list\n", ov, 0, 0 );
737                 }
738
739                 oi = be->bd_info->bi_private;
740         }
741
742         /* Insert new overlay on head of list. Overlays are executed
743          * in reverse of config order...
744          */
745         on2 = ch_calloc( 1, sizeof(slap_overinst) );
746         *on2 = *on;
747         on2->on_info = oi;
748         on2->on_next = oi->oi_list;
749         oi->oi_list = on2;
750
751         /* Any initialization needed? */
752         if ( on->on_bi.bi_db_init ) {
753                 int rc;
754                 be->bd_info = (BackendInfo *)on2;
755                 rc = on2->on_bi.bi_db_init( be );
756                 be->bd_info = (BackendInfo *)oi;
757                 if ( rc ) return rc;
758         }
759
760         return 0;
761 }
762