]> git.sur5r.net Git - openldap/blob - servers/slapd/backglue.c
2651283154cff6b9ebe81c0418deeb44c4a23e5e
[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_group (
529         BackendDB *b0,
530         Connection *conn,
531         Operation *op,
532         Entry *target,
533         const char *ndn,
534         const char *ondn,
535         ObjectClass *oc,
536         AttributeDescription * ad
537 )
538 {
539         BackendDB *be;
540         int rc;
541
542         be = glue_back_select (b0, ndn);
543
544         if (be && be->be_group) {
545                 rc = be->be_group (be, conn, op, target, ndn, ondn, oc, ad);
546         } else {
547                 rc = LDAP_UNWILLING_TO_PERFORM;
548         }
549         return rc;
550 }
551
552 int
553 glue_back_attribute (
554         BackendDB *b0,
555         Connection *conn,
556         Operation *op,
557         Entry *target,
558         const char *ndn,
559         AttributeDescription *ad,
560         struct berval ***vals
561 )
562 {
563         BackendDB *be;
564         int rc;
565
566         be = glue_back_select (b0, ndn);
567
568         if (be && be->be_attribute) {
569                 rc = be->be_attribute (be, conn, op, target, ndn, ad, vals);
570         } else {
571                 rc = LDAP_UNWILLING_TO_PERFORM;
572         }
573         return rc;
574 }
575
576 int
577 glue_back_referrals (
578         BackendDB *b0,
579         Connection *conn,
580         Operation *op,
581         const char *dn,
582         const char *ndn,
583         const char **text
584 )
585 {
586         BackendDB *be;
587         int rc;
588
589         be = glue_back_select (b0, ndn);
590
591         if (be && be->be_chk_referrals) {
592                 rc = be->be_chk_referrals (be, conn, op, dn, ndn, text);
593         } else {
594                 rc = LDAP_SUCCESS;;
595         }
596         return rc;
597 }
598
599 static int glueMode;
600 static int glueBack;
601
602 int
603 glue_tool_entry_open (
604         BackendDB *b0,
605         int mode
606 )
607 {
608         int i, rc;
609
610         /* We don't know which backend to talk to yet, so just
611          * remember the mode and move on...
612          */
613
614         glueMode = mode;
615         glueBack = -1;
616
617         return 0;
618 }
619
620 int
621 glue_tool_entry_close (
622         BackendDB *b0
623 )
624 {
625         struct glueinfo *gi = (struct glueinfo *) b0->be_private;
626         int i, rc = 0;
627
628         i = glueBack;
629         if (i >= 0) {
630                 if (!gi[i].be->be_entry_close)
631                         return 0;
632                 rc = gi[i].be->be_entry_close (gi[i].be);
633                 glueBack = -1;
634         }
635         return rc;
636 }
637
638 ID
639 glue_tool_entry_first (
640         BackendDB *b0
641 )
642 {
643         struct glueinfo *gi = (struct glueinfo *) b0->be_private;
644         int i;
645
646         /* If we're starting from scratch, start at the most general */
647         if (glueBack == -1) {
648                 for (i = 0; b0->be_nsuffix[i]; i++);
649                 for (--i; i >= 0; i--) {
650                         if (gi[i].be->be_entry_open &&
651                             gi[i].be->be_entry_first)
652                                 break;
653                 }
654         } else {
655                 i = glueBack;
656         }
657         if (gi[i].be->be_entry_open (gi[i].be, glueMode) != 0)
658                 return NOID;
659         glueBack = i;
660
661         return gi[i].be->be_entry_first (gi[i].be);
662 }
663
664 ID
665 glue_tool_entry_next (
666         BackendDB *b0
667 )
668 {
669         struct glueinfo *gi = (struct glueinfo *) b0->be_private;
670         int i, rc;
671
672         i = glueBack;
673         rc = gi[i].be->be_entry_next (gi[i].be);
674
675         /* If we ran out of entries in one database, move on to the next */
676         if (rc == NOID) {
677                 gi[i].be->be_entry_close (gi[i].be);
678                 i--;
679                 if (i < 0)
680                         rc = NOID;
681                 else
682                         rc = glue_tool_entry_first (b0);
683         }
684         return rc;
685 }
686
687 Entry *
688 glue_tool_entry_get (
689         BackendDB *b0,
690         ID id
691 )
692 {
693         struct glueinfo *gi = (struct glueinfo *) b0->be_private;
694
695         return gi[glueBack].be->be_entry_get (gi[glueBack].be, id);
696 }
697
698 ID
699 glue_tool_entry_put (
700         BackendDB *b0,
701         Entry *e
702 )
703 {
704         struct glueinfo *gi = (struct glueinfo *) b0->be_private;
705         BackendDB *be;
706         int i, rc;
707
708         be = glue_back_select (b0, e->e_ndn);
709         if (!be->be_entry_put)
710                 return NOID;
711
712         i = glueBack;
713         if (i < 0) {
714                 rc = be->be_entry_open (be, glueMode);
715                 if (rc != 0)
716                         return NOID;
717                 glueBack = i;
718         } else if (be != gi[i].be) {
719                 /* If this entry belongs in a different branch than the
720                  * previous one, close the current database and open the
721                  * new one.
722                  */
723                 gi[i].be->be_entry_close (gi[i].be);
724                 glueBack = -1;
725                 for (i = 0; b0->be_nsuffix[i]; i++)
726                         if (gi[i].be == be)
727                                 break;
728                 rc = be->be_entry_open (be, glueMode);
729                 if (rc != 0)
730                         return NOID;
731                 glueBack = i;
732         }
733         return be->be_entry_put (be, e);
734 }
735
736 int
737 glue_tool_entry_reindex (
738         BackendDB *b0,
739         ID id
740 )
741 {
742         struct glueinfo *gi = (struct glueinfo *) b0->be_private;
743         int i = glueBack;
744
745         if (!gi[i].be->be_entry_reindex)
746                 return -1;
747
748         return gi[i].be->be_entry_reindex (gi[i].be, id);
749 }
750
751 int
752 glue_tool_sync (
753         BackendDB *b0
754 )
755 {
756         struct glueinfo *gi = (struct glueinfo *) b0->be_private;
757         int i;
758
759         /* just sync everyone */
760         for (i = 0; b0->be_nsuffix[i]; i++)
761                 if (gi[i].be->be_sync)
762                         gi[i].be->be_sync (gi[i].be);
763         return 0;
764 }
765
766 int
767 glue_back_initialize (
768         BackendInfo *bi
769 )
770 {
771         bi->bi_open = glue_back_open;
772         bi->bi_config = 0;
773         bi->bi_close = glue_back_close;
774         bi->bi_destroy = 0;
775
776         bi->bi_db_init = 0;
777         bi->bi_db_config = 0;
778         bi->bi_db_open = glue_back_db_open;
779         bi->bi_db_close = 0;
780         bi->bi_db_destroy = glue_back_db_destroy;
781
782         bi->bi_op_bind = glue_back_bind;
783         bi->bi_op_unbind = 0;
784         bi->bi_op_search = glue_back_search;
785         bi->bi_op_compare = glue_back_compare;
786         bi->bi_op_modify = glue_back_modify;
787         bi->bi_op_modrdn = glue_back_modrdn;
788         bi->bi_op_add = glue_back_add;
789         bi->bi_op_delete = glue_back_delete;
790         bi->bi_op_abandon = 0;
791
792         bi->bi_extended = 0;
793
794         bi->bi_acl_group = glue_back_group;
795         bi->bi_acl_attribute = glue_back_attribute;
796         bi->bi_chk_referrals = glue_back_referrals;
797
798         /*
799          * hooks for slap tools
800          */
801         bi->bi_tool_entry_open = glue_tool_entry_open;
802         bi->bi_tool_entry_close = glue_tool_entry_close;
803         bi->bi_tool_entry_first = glue_tool_entry_first;
804         bi->bi_tool_entry_next = glue_tool_entry_next;
805         bi->bi_tool_entry_get = glue_tool_entry_get;
806         bi->bi_tool_entry_put = glue_tool_entry_put;
807         bi->bi_tool_entry_reindex = glue_tool_entry_reindex;
808         bi->bi_tool_sync = glue_tool_sync;
809
810         bi->bi_connection_init = 0;
811         bi->bi_connection_destroy = 0;
812
813         return 0;
814 }