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