]> git.sur5r.net Git - openldap/blob - servers/slapd/backglue.c
05f7c2633cbb637507579fbdee6455b1d13f1798
[openldap] / servers / slapd / backglue.c
1 /* backglue.c - backend glue routines */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 2001 The OpenLDAP Foundation, All Rights Reserved.
5  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6  */
7
8 /*
9  * Functions to glue a bunch of other backends into a single tree.
10  * All of the glued backends must share a common suffix. E.g., you
11  * can glue o=foo and ou=bar,o=foo but you can't glue o=foo and o=bar.
12  *
13  * The only configuration items that are needed for this backend are
14  * the suffixes, and they should be identical to suffixes of other
15  * backends that are being configured. The suffixes must be listed
16  * in order from longest to shortest, (most-specific to least-specific)
17  * in order for the selection to work. Every backend that is being glued
18  * must be fully configured as usual.
19  *
20  * The purpose of this backend is to allow you to split a single database
21  * into pieces (for load balancing purposes, whatever) but still be able
22  * to treat it as a single database after it's been split. As such, each
23  * of the glued backends should have identical rootdn and rootpw.
24  *
25  * If you need more elaborate configuration, you probably should be using
26  * back-meta instead.
27  *  -- Howard Chu
28  */
29
30 #include "portable.h"
31
32 #include <stdio.h>
33
34 #include <ac/socket.h>
35
36 #define SLAPD_TOOLS
37 #include "slap.h"
38
39 typedef struct glueinfo {
40         BackendDB *be;
41         char *pdn;
42 } glueinfo;
43
44 /* Just like select_backend, but only for our backends */
45 static BackendDB *
46 glue_back_select (
47         BackendDB *be,
48         const char *dn
49 )
50 {
51         struct glueinfo *gi = (struct glueinfo *) be->be_private;
52         int i;
53
54         for (i = 0; be->be_nsuffix[i]; i++) {
55                 if (dn_issuffix (dn, be->be_nsuffix[i]->bv_val))
56                         return gi[i].be;
57         }
58         return NULL;
59 }
60
61 static int
62 glue_back_open (
63         BackendInfo *bi
64 )
65 {
66         static int glueOpened = 0;
67
68         if (glueOpened)
69                 return 0;
70         glueOpened = 1;
71         /* Make sure all backends get started when we got selected
72          * by a tool
73          */
74         if (slapMode == SLAP_TOOL_MODE)
75                 backend_startup (NULL);
76         return 0;
77 }
78
79 static int
80 glue_back_close (
81         BackendInfo *bi
82 )
83 {
84         static int glueClosed = 0;
85
86         if (glueClosed)
87                 return 0;
88         glueClosed = 1;
89         if (slapMode == SLAP_TOOL_MODE)
90                 backend_shutdown (NULL);
91         return 0;
92 }
93
94 static int
95 glue_back_db_open (
96         BackendDB *be
97 )
98 {
99         struct glueinfo *gi;
100         int i, j, k;
101         int ok;
102
103         /*
104          * Done already? 
105          */
106         if (be->be_private)
107                 return 0;
108
109         for (i = 0; be->be_suffix[i]; i++);
110
111         gi = (struct glueinfo *) ch_calloc (i, sizeof (struct glueinfo));
112
113         be->be_private = gi;
114
115         if (!gi)
116                 return 1;
117
118         /*
119          * For each of our suffixes, find the real backend that handles this 
120          * suffix. 
121          */
122         for (i = 0; be->be_nsuffix[i]; i++) {
123                 for (j = 0; j < nbackends; j++) {
124                         if (be == &backends[j])
125                                 continue;
126                         ok = 0;
127                         for (k = 0; backends[j].be_nsuffix &&
128                              backends[j].be_nsuffix[k]; k++) {
129                                 if (be->be_nsuffix[i]->bv_len !=
130                                     backends[j].be_nsuffix[k]->bv_len)
131                                         continue;
132                                 if (!strcmp (backends[j].be_nsuffix[k]->bv_val,
133                                              be->be_nsuffix[i]->bv_val)) {
134                                         ok = 1;
135                                         break;
136                                 }
137                         }
138                         if (ok) {
139                                 gi[i].be = &backends[j];
140                                 gi[i].pdn = dn_parent (NULL,
141                                                  be->be_nsuffix[i]->bv_val);
142                                 break;
143                         }
144                 }
145         }
146         return 0;
147 }
148
149 int
150 glue_back_db_destroy (
151         BackendDB *be
152 )
153 {
154         free (be->be_private);
155         return 0;
156 }
157
158 int
159 glue_back_bind (
160         BackendDB *b0,
161         Connection *conn,
162         Operation *op,
163         const char *dn,
164         const char *ndn,
165         int method,
166         struct berval *cred,
167         char **edn
168 )
169 {
170         BackendDB *be;
171         int rc;
172
173         be = glue_back_select (b0, ndn);
174
175         if (be && be->be_bind) {
176                 conn->c_authz_backend = be;
177                 rc = be->be_bind (be, conn, op, dn, ndn, method, cred, edn);
178         } else {
179                 rc = LDAP_UNWILLING_TO_PERFORM;
180                 send_ldap_result (conn, op, rc, NULL, "No bind target found",
181                                   NULL, NULL);
182         }
183         return rc;
184 }
185
186 typedef struct glue_state {
187         int err;
188         int nentries;
189         int matchlen;
190         char *matched;
191 } glue_state;
192
193 void
194 glue_back_response (
195         Connection *conn,
196         Operation *op,
197         ber_tag_t tag,
198         ber_int_t msgid,
199         ber_int_t err,
200         const char *matched,
201         const char *text,
202         struct berval **ref,
203         const char *resoid,
204         struct berval *resdata,
205         struct berval *sasldata,
206         LDAPControl **ctrls
207 )
208 {
209         glue_state *gs = op->o_glue;
210
211         if (err == LDAP_SUCCESS || gs->err != LDAP_SUCCESS)
212                 gs->err = err;
213         if (gs->err == LDAP_SUCCESS && gs->matched) {
214                 free (gs->matched);
215                 gs->matchlen = 0;
216         }
217         if (gs->err != LDAP_SUCCESS && matched) {
218                 int len;
219                 len = strlen (matched);
220                 if (len > gs->matchlen) {
221                         if (gs->matched)
222                                 free (gs->matched);
223                         gs->matched = ch_strdup (matched);
224                         gs->matchlen = len;
225                 }
226         }
227 }
228
229 void
230 glue_back_sresult (
231         Connection *c,
232         Operation *op,
233         ber_int_t err,
234         const char *matched,
235         const char *text,
236         struct berval **refs,
237         LDAPControl **ctrls,
238         int nentries
239 )
240 {
241         glue_state *gs = op->o_glue;
242
243         gs->nentries += nentries;
244         glue_back_response (c, op, 0, 0, err, matched, text, refs,
245                             NULL, NULL, NULL, ctrls);
246 }
247
248 int
249 glue_back_search (
250         BackendDB *b0,
251         Connection *conn,
252         Operation *op,
253         const char *dn,
254         const char *ndn,
255         int scope,
256         int deref,
257         int slimit,
258         int tlimit,
259         Filter *filter,
260         const char *filterstr,
261         char **attrs,
262         int attrsonly
263 )
264 {
265         struct glueinfo *gi = (struct glueinfo *) b0->be_private;
266         BackendDB *be;
267         int i, rc, t2limit = 0, s2limit = 0;
268         long stoptime = 0;
269         glue_state gs =
270         {0};
271
272
273         if (tlimit)
274                 stoptime = slap_get_time () + tlimit;
275
276         switch (scope) {
277         case LDAP_SCOPE_BASE:
278                 be = glue_back_select (b0, ndn);
279
280                 if (be && be->be_search) {
281                         rc = be->be_search (be, conn, op, dn, ndn, scope,
282                                    deref, slimit, tlimit, filter, filterstr,
283                                             attrs, attrsonly);
284                 } else {
285                         rc = LDAP_UNWILLING_TO_PERFORM;
286                         send_ldap_result (conn, op, rc, NULL,
287                                       "No search target found", NULL, NULL);
288                 }
289                 return rc;
290
291         case LDAP_SCOPE_ONELEVEL:
292                 op->o_glue = &gs;
293                 op->o_sresult = glue_back_sresult;
294                 op->o_response = glue_back_response;
295
296                 /*
297                  * Execute in reverse order, most general first 
298                  */
299                 for (i = 0; b0->be_nsuffix[i]; i++);
300                 for (--i; i >= 0; i--) {
301                         if (!gi[i].be->be_search)
302                                 continue;
303                         if (tlimit) {
304                                 t2limit = stoptime - slap_get_time ();
305                                 if (t2limit <= 0)
306                                         break;
307                         }
308                         if (slimit) {
309                                 s2limit = slimit - gs.nentries;
310                                 if (s2limit <= 0)
311                                         break;
312                         }
313                         /*
314                          * check for abandon 
315                          */
316                         ldap_pvt_thread_mutex_lock (&op->o_abandonmutex);
317                         rc = op->o_abandon;
318                         ldap_pvt_thread_mutex_unlock (&op->o_abandonmutex);
319                         if (rc) {
320                                 rc = 0;
321                                 goto done;
322                         }
323                         if (!strcmp (gi[i].pdn, ndn)) {
324                                 be = gi[i].be;
325                                 rc = be->be_search (be, conn, op,
326                                                     b0->be_suffix[i],
327                                                   b0->be_nsuffix[i]->bv_val,
328                                                     LDAP_SCOPE_BASE, deref,
329                                         s2limit, t2limit, filter, filterstr,
330                                                     attrs, attrsonly);
331                         } else if (dn_issuffix (ndn, b0->be_nsuffix[i]->bv_val)) {
332                                 be = gi[i].be;
333                                 rc = be->be_search (be, conn, op,
334                                                     dn, ndn, scope, deref,
335                                         s2limit, t2limit, filter, filterstr,
336                                                     attrs, attrsonly);
337                         }
338                 }
339                 break;
340
341         case LDAP_SCOPE_SUBTREE:
342                 op->o_glue = &gs;
343                 op->o_sresult = glue_back_sresult;
344                 op->o_response = glue_back_response;
345
346                 /*
347                  * Execute in reverse order, most general first 
348                  */
349                 for (i = 0; b0->be_nsuffix[i]; i++);
350                 for (--i; i >= 0; i--) {
351                         if (!gi[i].be->be_search)
352                                 continue;
353                         if (tlimit) {
354                                 t2limit = stoptime - slap_get_time ();
355                                 if (t2limit <= 0)
356                                         break;
357                         }
358                         if (slimit) {
359                                 s2limit = slimit - gs.nentries;
360                                 if (s2limit <= 0)
361                                         break;
362                         }
363                         /*
364                          * check for abandon 
365                          */
366                         ldap_pvt_thread_mutex_lock (&op->o_abandonmutex);
367                         rc = op->o_abandon;
368                         ldap_pvt_thread_mutex_unlock (&op->o_abandonmutex);
369                         if (rc) {
370                                 rc = 0;
371                                 goto done;
372                         }
373                         if (dn_issuffix (ndn, b0->be_nsuffix[i]->bv_val)) {
374                                 be = gi[i].be;
375                                 rc = be->be_search (be, conn, op,
376                                                     dn, ndn, scope, deref,
377                                         s2limit, t2limit, filter, filterstr,
378                                                     attrs, attrsonly);
379                         } else if (dn_issuffix (b0->be_nsuffix[i]->bv_val, ndn)) {
380                                 be = gi[i].be;
381                                 rc = be->be_search (be, conn, op,
382                                                     b0->be_suffix[i],
383                                                   b0->be_nsuffix[i]->bv_val,
384                                                     scope, deref,
385                                         s2limit, t2limit, filter, filterstr,
386                                                     attrs, attrsonly);
387                         }
388                 }
389                 break;
390         }
391         op->o_sresult = NULL;
392         op->o_response = NULL;
393         op->o_glue = NULL;
394
395         send_search_result (conn, op, gs.err, gs.matched, NULL, NULL,
396                             NULL, gs.nentries);
397       done:
398         if (gs.matched)
399                 free (gs.matched);
400         return rc;
401 }
402
403 int
404 glue_back_compare (
405         BackendDB *b0,
406         Connection *conn,
407         Operation *op,
408         const char *dn,
409         const char *ndn,
410         AttributeAssertion *ava
411 )
412 {
413         BackendDB *be;
414         int rc;
415
416         be = glue_back_select (b0, ndn);
417
418         if (be && be->be_compare) {
419                 rc = be->be_compare (be, conn, op, dn, ndn, ava);
420         } else {
421                 rc = LDAP_UNWILLING_TO_PERFORM;
422                 send_ldap_result (conn, op, rc, NULL, "No compare target found",
423                                   NULL, NULL);
424         }
425         return rc;
426 }
427
428 int
429 glue_back_modify (
430         BackendDB *b0,
431         Connection *conn,
432         Operation *op,
433         const char *dn,
434         const char *ndn,
435         Modifications *mod
436 )
437 {
438         BackendDB *be;
439         int rc;
440
441         be = glue_back_select (b0, ndn);
442
443         if (be && be->be_modify) {
444                 rc = be->be_modify (be, conn, op, dn, ndn, mod);
445         } else {
446                 rc = LDAP_UNWILLING_TO_PERFORM;
447                 send_ldap_result (conn, op, rc, NULL, "No modify target found",
448                                   NULL, NULL);
449         }
450         return rc;
451 }
452
453 int
454 glue_back_modrdn (
455         BackendDB *b0,
456         Connection *conn,
457         Operation *op,
458         const char *dn,
459         const char *ndn,
460         const char *newrdn,
461         int del,
462         const char *newsup
463 )
464 {
465         BackendDB *be;
466         int rc;
467
468         be = glue_back_select (b0, ndn);
469
470         if (be && be->be_modrdn) {
471                 rc = be->be_modrdn (be, conn, op, dn, ndn, newrdn, del, newsup);
472         } else {
473                 rc = LDAP_UNWILLING_TO_PERFORM;
474                 send_ldap_result (conn, op, rc, NULL, "No modrdn target found",
475                                   NULL, NULL);
476         }
477         return rc;
478 }
479
480 int
481 glue_back_add (
482         BackendDB *b0,
483         Connection *conn,
484         Operation *op,
485         Entry *e
486 )
487 {
488         BackendDB *be;
489         int rc;
490
491         be = glue_back_select (b0, e->e_ndn);
492
493         if (be && be->be_add) {
494                 rc = be->be_add (be, conn, op, e);
495         } else {
496                 rc = LDAP_UNWILLING_TO_PERFORM;
497                 send_ldap_result (conn, op, rc, NULL, "No add target found",
498                                   NULL, NULL);
499         }
500         return rc;
501 }
502
503 int
504 glue_back_delete (
505         BackendDB *b0,
506         Connection *conn,
507         Operation *op,
508         const char *dn,
509         const char *ndn
510 )
511 {
512         BackendDB *be;
513         int rc;
514
515         be = glue_back_select (b0, ndn);
516
517         if (be && be->be_delete) {
518                 rc = be->be_delete (be, conn, op, dn, ndn);
519         } else {
520                 rc = LDAP_UNWILLING_TO_PERFORM;
521                 send_ldap_result (conn, op, rc, NULL, "No delete target found",
522                                   NULL, NULL);
523         }
524         return rc;
525 }
526
527 int
528 glue_back_release_rw (
529         BackendDB *b0,
530         Connection *conn,
531         Operation *op,
532         Entry *e,
533         int rw
534 )
535 {
536         BackendDB *be;
537         int rc;
538
539         be = glue_back_select (b0, e->e_ndn);
540
541         if (be && be->be_release) {
542                 rc = be->be_release (be, conn, op, e, rw);
543         } else {
544                 entry_free (e);
545                 rc = 0;
546         }
547         return rc;
548 }
549
550 int
551 glue_back_group (
552         BackendDB *b0,
553         Connection *conn,
554         Operation *op,
555         Entry *target,
556         const char *ndn,
557         const char *ondn,
558         ObjectClass *oc,
559         AttributeDescription * ad
560 )
561 {
562         BackendDB *be;
563         int rc;
564
565         be = glue_back_select (b0, ndn);
566
567         if (be && be->be_group) {
568                 rc = be->be_group (be, conn, op, target, ndn, ondn, oc, ad);
569         } else {
570                 rc = LDAP_UNWILLING_TO_PERFORM;
571         }
572         return rc;
573 }
574
575 int
576 glue_back_attribute (
577         BackendDB *b0,
578         Connection *conn,
579         Operation *op,
580         Entry *target,
581         const char *ndn,
582         AttributeDescription *ad,
583         struct berval ***vals
584 )
585 {
586         BackendDB *be;
587         int rc;
588
589         be = glue_back_select (b0, ndn);
590
591         if (be && be->be_attribute) {
592                 rc = be->be_attribute (be, conn, op, target, ndn, ad, vals);
593         } else {
594                 rc = LDAP_UNWILLING_TO_PERFORM;
595         }
596         return rc;
597 }
598
599 int
600 glue_back_referrals (
601         BackendDB *b0,
602         Connection *conn,
603         Operation *op,
604         const char *dn,
605         const char *ndn,
606         const char **text
607 )
608 {
609         BackendDB *be;
610         int rc;
611
612         be = glue_back_select (b0, ndn);
613
614         if (be && be->be_chk_referrals) {
615                 rc = be->be_chk_referrals (be, conn, op, dn, ndn, text);
616         } else {
617                 rc = LDAP_SUCCESS;;
618         }
619         return rc;
620 }
621
622 static int glueMode;
623 static int glueBack;
624
625 int
626 glue_tool_entry_open (
627         BackendDB *b0,
628         int mode
629 )
630 {
631         int i, rc;
632
633         /* We don't know which backend to talk to yet, so just
634          * remember the mode and move on...
635          */
636
637         glueMode = mode;
638         glueBack = -1;
639
640         return 0;
641 }
642
643 int
644 glue_tool_entry_close (
645         BackendDB *b0
646 )
647 {
648         struct glueinfo *gi = (struct glueinfo *) b0->be_private;
649         int i, rc = 0;
650
651         i = glueBack;
652         if (i >= 0) {
653                 if (!gi[i].be->be_entry_close)
654                         return 0;
655                 rc = gi[i].be->be_entry_close (gi[i].be);
656                 glueBack = -1;
657         }
658         return rc;
659 }
660
661 ID
662 glue_tool_entry_first (
663         BackendDB *b0
664 )
665 {
666         struct glueinfo *gi = (struct glueinfo *) b0->be_private;
667         int i;
668
669         /* If we're starting from scratch, start at the most general */
670         if (glueBack == -1) {
671                 for (i = 0; b0->be_nsuffix[i]; i++);
672                 for (--i; i >= 0; i--) {
673                         if (gi[i].be->be_entry_open &&
674                             gi[i].be->be_entry_first)
675                                 break;
676                 }
677         } else {
678                 i = glueBack;
679         }
680         if (gi[i].be->be_entry_open (gi[i].be, glueMode) != 0)
681                 return NOID;
682         glueBack = i;
683
684         return gi[i].be->be_entry_first (gi[i].be);
685 }
686
687 ID
688 glue_tool_entry_next (
689         BackendDB *b0
690 )
691 {
692         struct glueinfo *gi = (struct glueinfo *) b0->be_private;
693         int i, rc;
694
695         i = glueBack;
696         rc = gi[i].be->be_entry_next (gi[i].be);
697
698         /* If we ran out of entries in one database, move on to the next */
699         if (rc == NOID) {
700                 gi[i].be->be_entry_close (gi[i].be);
701                 i--;
702                 glueBack = i;
703                 if (i < 0)
704                         rc = NOID;
705                 else
706                         rc = glue_tool_entry_first (b0);
707         }
708         return rc;
709 }
710
711 Entry *
712 glue_tool_entry_get (
713         BackendDB *b0,
714         ID id
715 )
716 {
717         struct glueinfo *gi = (struct glueinfo *) b0->be_private;
718
719         return gi[glueBack].be->be_entry_get (gi[glueBack].be, id);
720 }
721
722 ID
723 glue_tool_entry_put (
724         BackendDB *b0,
725         Entry *e
726 )
727 {
728         struct glueinfo *gi = (struct glueinfo *) b0->be_private;
729         BackendDB *be;
730         int i, rc;
731
732         be = glue_back_select (b0, e->e_ndn);
733         if (!be->be_entry_put)
734                 return NOID;
735
736         i = glueBack;
737         if (i < 0) {
738                 rc = be->be_entry_open (be, glueMode);
739                 if (rc != 0)
740                         return NOID;
741                 glueBack = i;
742         } else if (be != gi[i].be) {
743                 /* If this entry belongs in a different branch than the
744                  * previous one, close the current database and open the
745                  * new one.
746                  */
747                 gi[i].be->be_entry_close (gi[i].be);
748                 glueBack = -1;
749                 for (i = 0; b0->be_nsuffix[i]; i++)
750                         if (gi[i].be == be)
751                                 break;
752                 rc = be->be_entry_open (be, glueMode);
753                 if (rc != 0)
754                         return NOID;
755                 glueBack = i;
756         }
757         return be->be_entry_put (be, e);
758 }
759
760 int
761 glue_tool_entry_reindex (
762         BackendDB *b0,
763         ID id
764 )
765 {
766         struct glueinfo *gi = (struct glueinfo *) b0->be_private;
767         int i = glueBack;
768
769         if (!gi[i].be->be_entry_reindex)
770                 return -1;
771
772         return gi[i].be->be_entry_reindex (gi[i].be, id);
773 }
774
775 int
776 glue_tool_sync (
777         BackendDB *b0
778 )
779 {
780         struct glueinfo *gi = (struct glueinfo *) b0->be_private;
781         int i;
782
783         /* just sync everyone */
784         for (i = 0; b0->be_nsuffix[i]; i++)
785                 if (gi[i].be->be_sync)
786                         gi[i].be->be_sync (gi[i].be);
787         return 0;
788 }
789
790 int
791 glue_back_initialize (
792         BackendInfo *bi
793 )
794 {
795         bi->bi_open = glue_back_open;
796         bi->bi_config = 0;
797         bi->bi_close = glue_back_close;
798         bi->bi_destroy = 0;
799
800         bi->bi_db_init = 0;
801         bi->bi_db_config = 0;
802         bi->bi_db_open = glue_back_db_open;
803         bi->bi_db_close = 0;
804         bi->bi_db_destroy = glue_back_db_destroy;
805
806         bi->bi_op_bind = glue_back_bind;
807         bi->bi_op_unbind = 0;
808         bi->bi_op_search = glue_back_search;
809         bi->bi_op_compare = glue_back_compare;
810         bi->bi_op_modify = glue_back_modify;
811         bi->bi_op_modrdn = glue_back_modrdn;
812         bi->bi_op_add = glue_back_add;
813         bi->bi_op_delete = glue_back_delete;
814         bi->bi_op_abandon = 0;
815
816         bi->bi_extended = 0;
817
818         bi->bi_entry_release_rw = glue_back_release_rw;
819         bi->bi_acl_group = glue_back_group;
820         bi->bi_acl_attribute = glue_back_attribute;
821         bi->bi_chk_referrals = glue_back_referrals;
822
823         /*
824          * hooks for slap tools
825          */
826         bi->bi_tool_entry_open = glue_tool_entry_open;
827         bi->bi_tool_entry_close = glue_tool_entry_close;
828         bi->bi_tool_entry_first = glue_tool_entry_first;
829         bi->bi_tool_entry_next = glue_tool_entry_next;
830         bi->bi_tool_entry_get = glue_tool_entry_get;
831         bi->bi_tool_entry_put = glue_tool_entry_put;
832         bi->bi_tool_entry_reindex = glue_tool_entry_reindex;
833         bi->bi_tool_sync = glue_tool_sync;
834
835         bi->bi_connection_init = 0;
836         bi->bi_connection_destroy = 0;
837
838         return 0;
839 }