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