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