]> git.sur5r.net Git - openldap/blob - servers/slapd/backover.c
allow backends to automatically install overlays; issue warnings in case of duplicate...
[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-2004 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         return over_db_func( be, db_close );
152 }
153
154 static int
155 over_db_destroy(
156         BackendDB *be
157 )
158 {
159         slap_overinfo *oi = be->bd_info->bi_private;
160         slap_overinst *on = oi->oi_list, *next;
161         int rc;
162
163         rc = over_db_func( be, db_destroy );
164
165         for (next = on->on_next; on; on=next) {
166                 next = on->on_next;
167                 free( on );
168         }
169         free( oi );
170         return rc;
171 }
172
173 static int
174 over_back_response ( Operation *op, SlapReply *rs )
175 {
176         slap_overinfo *oi = op->o_callback->sc_private;
177         slap_overinst *on = oi->oi_list;
178         int rc = SLAP_CB_CONTINUE;
179         BackendDB *be = op->o_bd, db = *op->o_bd;
180
181         op->o_bd = &db;
182         for (; on; on=on->on_next ) {
183                 if ( on->on_response ) {
184                         db.bd_info = (BackendInfo *)on;
185                         rc = on->on_response( op, rs );
186                         if ( rc != SLAP_CB_CONTINUE ) break;
187                 }
188         }
189         op->o_bd = be;
190         return rc;
191 }
192
193 enum op_which {
194         op_bind = 0,
195         op_unbind,
196         op_search,
197         op_compare,
198         op_modify,
199         op_modrdn,
200         op_add,
201         op_delete,
202         op_abandon,
203         op_cancel,
204         op_extended,
205         op_aux_operational,
206         op_aux_chk_referrals,
207         op_last
208 };
209
210 /*
211  * default return code in case of missing backend function
212  * and overlay stack returning SLAP_CB_CONTINUE
213  */
214 static int op_rc[] = {
215         LDAP_UNWILLING_TO_PERFORM,      /* bind */
216         LDAP_UNWILLING_TO_PERFORM,      /* unbind */
217         LDAP_UNWILLING_TO_PERFORM,      /* search */
218         LDAP_UNWILLING_TO_PERFORM,      /* compare */
219         LDAP_UNWILLING_TO_PERFORM,      /* modify */
220         LDAP_UNWILLING_TO_PERFORM,      /* modrdn */
221         LDAP_UNWILLING_TO_PERFORM,      /* add */
222         LDAP_UNWILLING_TO_PERFORM,      /* delete */
223         LDAP_UNWILLING_TO_PERFORM,      /* abandon */
224         LDAP_UNWILLING_TO_PERFORM,      /* cancel */
225         LDAP_UNWILLING_TO_PERFORM,      /* extended */
226         LDAP_SUCCESS,                   /* aux_operational */
227         LDAP_SUCCESS                    /* aux_chk_referrals */
228 };
229
230 static int
231 over_op_func(
232         Operation *op,
233         SlapReply *rs,
234         enum op_which which
235 )
236 {
237         slap_overinfo *oi = op->o_bd->bd_info->bi_private;
238         slap_overinst *on = oi->oi_list;
239         BI_op_bind **func;
240         BackendDB *be = op->o_bd, db = *op->o_bd;
241         slap_callback cb = {NULL, over_back_response, NULL, NULL};
242         int rc = SLAP_CB_CONTINUE;
243
244         op->o_bd = &db;
245         cb.sc_next = op->o_callback;
246         cb.sc_private = oi;
247         op->o_callback = &cb;
248
249         for (; on; on=on->on_next ) {
250                 func = &on->on_bi.bi_op_bind;
251                 if ( func[which] ) {
252                         db.bd_info = (BackendInfo *)on;
253                         rc = func[which]( op, rs );
254                         if ( rc != SLAP_CB_CONTINUE ) break;
255                 }
256         }
257
258         func = &oi->oi_orig->bi_op_bind;
259         if ( func[which] && rc == SLAP_CB_CONTINUE ) {
260                 db.bd_info = oi->oi_orig;
261                 rc = func[which]( op, rs );
262         }
263         /* should not fall thru this far without anything happening... */
264         if ( rc == SLAP_CB_CONTINUE ) {
265                 rc = op_rc[ which ];
266         }
267         op->o_bd = be;
268         op->o_callback = cb.sc_next;
269         return rc;
270 }
271
272 static int
273 over_op_bind( Operation *op, SlapReply *rs )
274 {
275         return over_op_func( op, rs, op_bind );
276 }
277
278 static int
279 over_op_unbind( Operation *op, SlapReply *rs )
280 {
281         return over_op_func( op, rs, op_unbind );
282 }
283
284 static int
285 over_op_search( Operation *op, SlapReply *rs )
286 {
287         return over_op_func( op, rs, op_search );
288 }
289
290 static int
291 over_op_compare( Operation *op, SlapReply *rs )
292 {
293         return over_op_func( op, rs, op_compare );
294 }
295
296 static int
297 over_op_modify( Operation *op, SlapReply *rs )
298 {
299         return over_op_func( op, rs, op_modify );
300 }
301
302 static int
303 over_op_modrdn( Operation *op, SlapReply *rs )
304 {
305         return over_op_func( op, rs, op_modrdn );
306 }
307
308 static int
309 over_op_add( Operation *op, SlapReply *rs )
310 {
311         return over_op_func( op, rs, op_add );
312 }
313
314 static int
315 over_op_delete( Operation *op, SlapReply *rs )
316 {
317         return over_op_func( op, rs, op_delete );
318 }
319
320 static int
321 over_op_abandon( Operation *op, SlapReply *rs )
322 {
323         return over_op_func( op, rs, op_abandon );
324 }
325
326 static int
327 over_op_cancel( Operation *op, SlapReply *rs )
328 {
329         return over_op_func( op, rs, op_cancel );
330 }
331
332 static int
333 over_op_extended( Operation *op, SlapReply *rs )
334 {
335         return over_op_func( op, rs, op_extended );
336 }
337
338 static int
339 over_aux_operational( Operation *op, SlapReply *rs )
340 {
341         return over_op_func( op, rs, op_aux_operational );
342 }
343
344 static int
345 over_aux_chk_referrals( Operation *op, SlapReply *rs )
346 {
347         return over_op_func( op, rs, op_aux_chk_referrals );
348 }
349
350 int
351 overlay_register(
352         slap_overinst *on
353 )
354 {
355         on->on_next = overlays;
356         overlays = on;
357         return 0;
358 }
359
360 /*
361  * iterator on registered overlays; overlay_next( NULL ) returns the first
362  * overlay; * subsequent calls with the previously returned value allow to 
363  * iterate * over the entire list; returns NULL when no more overlays are 
364  * registered.
365  */
366
367 slap_overinst *
368 overlay_next(
369         slap_overinst *on
370 )
371 {
372         if ( on == NULL ) {
373                 return overlays;
374         }
375
376         return on->on_next;
377 }
378
379 /*
380  * returns a specific registered overlay based on the type; NULL if not
381  * registered.
382  */
383
384 slap_overinst *
385 overlay_find( const char *over_type )
386 {
387         slap_overinst *on = overlays;
388
389         assert( over_type );
390
391         for ( ; on; on = on->on_next ) {
392                 if ( strcmp( on->on_bi.bi_type, over_type ) == 0 ) {
393                         break;
394                 }
395         }
396
397         return on;
398 }
399
400 static const char overtype[] = "over";
401
402 /*
403  * returns TRUE (1) if the database is actually an overlay instance;
404  * FALSE (0) otherwise.
405  */
406
407 int
408 overlay_is_over( BackendDB *be )
409 {
410         return be->bd_info->bi_type == overtype;
411 }
412
413 /*
414  * returns TRUE (1) if the given database is actually an overlay
415  * instance and, somewhere in the list, contains the requested overlay;
416  * FALSE (0) otherwise.
417  */
418
419 int
420 overlay_is_inst( BackendDB *be, const char *over_type )
421 {
422         slap_overinst   *on;
423
424         assert( be );
425
426         if ( !overlay_is_over( be ) ) {
427                 return 0;
428         }
429         
430         on = ((slap_overinfo *)be->bd_info->bi_private)->oi_list;
431         for ( ; on; on = on->on_next ) {
432                 if ( strcmp( on->on_bi.bi_type, over_type ) == 0 ) {
433                         return 1;
434                 }
435         }
436
437         return 0;
438 }
439
440 /* add an overlay to a particular backend. */
441 int
442 overlay_config( BackendDB *be, const char *ov )
443 {
444         slap_overinst *on = NULL, *on2 = NULL;
445         slap_overinfo *oi = NULL;
446         BackendInfo *bi = NULL;
447
448         on = overlay_find( ov );
449         if ( !on ) {
450                 Debug( LDAP_DEBUG_ANY, "overlay \"%s\" not found\n", ov, 0, 0 );
451                 return 1;
452         }
453
454         /* If this is the first overlay on this backend, set up the
455          * overlay info structure
456          */
457         if ( !overlay_is_over( be ) ) {
458                 oi = ch_malloc( sizeof( slap_overinfo ) );
459                 oi->oi_orig = be->bd_info;
460                 oi->oi_bi = *be->bd_info;
461
462                 /* Save a pointer to ourself in bi_private.
463                  * This allows us to keep working in conjunction
464                  * with backglue...
465                  */
466                 oi->oi_bi.bi_private = oi;
467                 oi->oi_list = NULL;
468                 bi = (BackendInfo *)oi;
469
470                 bi->bi_type = (char *)overtype;
471
472                 bi->bi_db_config = over_db_config;
473                 bi->bi_db_open = over_db_open;
474                 bi->bi_db_close = over_db_close;
475                 bi->bi_db_destroy = over_db_destroy;
476
477                 bi->bi_op_bind = over_op_bind;
478                 bi->bi_op_unbind = over_op_unbind;
479                 bi->bi_op_search = over_op_search;
480                 bi->bi_op_compare = over_op_compare;
481                 bi->bi_op_modify = over_op_modify;
482                 bi->bi_op_modrdn = over_op_modrdn;
483                 bi->bi_op_add = over_op_add;
484                 bi->bi_op_delete = over_op_delete;
485                 bi->bi_op_abandon = over_op_abandon;
486                 bi->bi_op_cancel = over_op_cancel;
487
488                 bi->bi_extended = over_op_extended;
489
490                 /*
491                  * this is fine because it has the same
492                  * args of the operations; we need to rework
493                  * all the hooks to share the same args
494                  * of the operations...
495                  */
496                 bi->bi_operational = over_aux_operational;
497                 bi->bi_chk_referrals = over_aux_chk_referrals;
498
499                 be->bd_info = bi;
500
501         } else {
502                 if ( overlay_is_inst( be, ov ) ) {
503                         Debug( LDAP_DEBUG_ANY, "overlay_config(): "
504                                         "warning, overlay \"%s\" "
505                                         "already in list\n", ov, 0, 0 );
506                 }
507
508                 oi = be->bd_info->bi_private;
509         }
510
511         /* Insert new overlay on head of list. Overlays are executed
512          * in reverse of config order...
513          */
514         on2 = ch_calloc( 1, sizeof(slap_overinst) );
515         *on2 = *on;
516         on2->on_info = oi;
517         on2->on_next = oi->oi_list;
518         oi->oi_list = on2;
519
520         /* Any initialization needed? */
521         if ( on->on_bi.bi_db_init ) {
522                 be->bd_info = (BackendInfo *)on2;
523                 on2->on_bi.bi_db_init( be );
524                 be->bd_info = (BackendInfo *)oi;
525         }
526
527         return 0;
528 }
529