]> git.sur5r.net Git - openldap/blob - servers/slapd/backend.c
67f45256abd92e9ebd885465d3e54ed342218dd5
[openldap] / servers / slapd / backend.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6 /* backend.c - routines for dealing with back-end databases */
7
8
9 #include "portable.h"
10
11 #include <stdio.h>
12
13 #include <ac/string.h>
14 #include <ac/socket.h>
15
16 #include <sys/stat.h>
17
18 #include "slap.h"
19 #include "lutil.h"
20
21 #ifdef SLAPD_BDB
22 #include "back-bdb/external.h"
23 #endif
24 #ifdef SLAPD_DNSSRV
25 #include "back-dnssrv/external.h"
26 #endif
27 #ifdef SLAPD_LDAP
28 #include "back-ldap/external.h"
29 #endif
30 #ifdef SLAPD_LDBM
31 #include "back-ldbm/external.h"
32 #endif
33 #ifdef SLAPD_PASSWD
34 #include "back-passwd/external.h"
35 #endif
36 #ifdef SLAPD_PERL
37 #include "back-perl/external.h"
38 #endif
39 #ifdef SLAPD_SHELL
40 #include "back-shell/external.h"
41 #endif
42 #ifdef SLAPD_TCL
43 #include "back-tcl/external.h"
44 #endif
45 #ifdef SLAPD_SQL
46 #include "back-sql/external.h"
47 #endif
48 #ifdef SLAPD_PRIVATE
49 #include "private/external.h"
50 #endif
51
52 static BackendInfo binfo[] = {
53 #if defined(SLAPD_BDB) && !defined(SLAPD_BDB_DYNAMIC)
54         {"bdb", bdb_back_initialize},
55 #endif
56 #if defined(SLAPD_DNSSRV) && !defined(SLAPD_DNSSRV_DYNAMIC)
57         {"dnssrv",      dnssrv_back_initialize},
58 #endif
59 #if defined(SLAPD_LDAP) && !defined(SLAPD_LDAP_DYNAMIC)
60         {"ldap",        ldap_back_initialize},
61 #endif
62 #if defined(SLAPD_LDBM) && !defined(SLAPD_LDBM_DYNAMIC)
63         {"ldbm",        ldbm_back_initialize},
64 #endif
65 #if defined(SLAPD_PASSWD) && !defined(SLAPD_PASSWD_DYNAMIC)
66         {"passwd",      passwd_back_initialize},
67 #endif
68 #if defined(SLAPD_PERL) && !defined(SLAPD_PERL_DYNAMIC)
69         {"perl",        perl_back_initialize},
70 #endif
71 #if defined(SLAPD_SHELL) && !defined(SLAPD_SHELL_DYNAMIC)
72         {"shell",       shell_back_initialize},
73 #endif
74 #if defined(SLAPD_TCL) && !defined(SLAPD_TCL_DYNAMIC)
75         {"tcl",         tcl_back_initialize},
76 #endif
77 #if defined(SLAPD_SQL) && !defined(SLAPD_SQL_DYNAMIC)
78         {"sql",         sql_back_initialize},
79 #endif
80         /* for any private backend */
81 #if defined(SLAPD_PRIVATE) && !defined(SLAPD_PRIVATE_DYNAMIC)
82         {"private",     private_back_initialize},
83 #endif
84         {NULL}
85 };
86
87 int                     nBackendInfo = 0;
88 BackendInfo     *backendInfo = NULL;
89
90 int                     nBackendDB = 0; 
91 BackendDB       *backendDB = NULL;
92
93 int backend_init(void)
94 {
95         int rc = -1;
96
97         if((nBackendInfo != 0) || (backendInfo != NULL)) {
98                 /* already initialized */
99                 Debug( LDAP_DEBUG_ANY,
100                         "backend_init: already initialized.\n", 0, 0, 0 );
101                 return -1;
102         }
103
104         for( ;
105                 binfo[nBackendInfo].bi_type != NULL;
106                 nBackendInfo++ )
107         {
108                 rc = binfo[nBackendInfo].bi_init( &binfo[nBackendInfo] );
109
110                 if(rc != 0) {
111                         Debug( LDAP_DEBUG_ANY,
112                                 "backend_init: initialized for type \"%s\"\n",
113                                         binfo[nBackendInfo].bi_type, 0, 0 );
114
115                         /* destroy those we've already inited */
116                         for( nBackendInfo--;
117                                 nBackendInfo >= 0 ;
118                                 nBackendInfo-- )
119                         { 
120                                 if ( binfo[nBackendInfo].bi_destroy ) {
121                                         binfo[nBackendInfo].bi_destroy(
122                                                 &binfo[nBackendInfo] );
123                                 }
124                         }
125                         return rc;
126                 }
127         }
128
129         if ( nBackendInfo > 0) {
130                 backendInfo = binfo;
131                 return 0;
132         }
133
134 #ifdef SLAPD_MODULES    
135         return 0;
136 #else
137         Debug( LDAP_DEBUG_ANY,
138                 "backend_init: failed\n",
139                 0, 0, 0 );
140
141         return rc;
142 #endif /* SLAPD_MODULES */
143 }
144
145 int backend_add(BackendInfo *aBackendInfo)
146 {
147    int rc = 0;
148
149    if ((rc = aBackendInfo->bi_init(aBackendInfo)) != 0) {
150       Debug( LDAP_DEBUG_ANY,
151              "backend_add: initialization for type \"%s\" failed\n",
152              aBackendInfo->bi_type, 0, 0 );
153       return rc;
154    }
155
156    /* now add the backend type to the Backend Info List */
157    {
158       BackendInfo *newBackendInfo = 0;
159
160       /* if backendInfo == binfo no deallocation of old backendInfo */
161       if (backendInfo == binfo) {
162          newBackendInfo = ch_calloc(nBackendInfo + 1, sizeof(BackendInfo));
163          AC_MEMCPY(newBackendInfo, backendInfo, sizeof(BackendInfo) * 
164                 nBackendInfo);
165       } else {
166          newBackendInfo = ch_realloc(backendInfo, sizeof(BackendInfo) * 
167                                      (nBackendInfo + 1));
168       }
169       AC_MEMCPY(&newBackendInfo[nBackendInfo], aBackendInfo, 
170              sizeof(BackendInfo));
171       backendInfo = newBackendInfo;
172       nBackendInfo++;
173
174       return 0;
175    }        
176 }
177
178 int backend_startup(Backend *be)
179 {
180         int i;
181         int rc = 0;
182
183         if( ! ( nBackendDB > 0 ) ) {
184                 /* no databases */
185                 Debug( LDAP_DEBUG_ANY,
186                         "backend_startup: %d databases to startup.\n",
187                         nBackendDB, 0, 0 );
188                 return 1;
189         }
190
191         if(be != NULL) {
192                 /* startup a specific backend database */
193                 Debug( LDAP_DEBUG_TRACE,
194                         "backend_startup: starting database\n",
195                         0, 0, 0 );
196
197                 if ( be->bd_info->bi_open ) {
198                         rc = be->bd_info->bi_open( be->bd_info );
199                 }
200
201                 if(rc != 0) {
202                         Debug( LDAP_DEBUG_ANY,
203                                 "backend_startup: bi_open failed!\n",
204                                 0, 0, 0 );
205                         return rc;
206                 }
207
208                 if ( be->bd_info->bi_db_open ) {
209                         rc = be->bd_info->bi_db_open( be );
210                 }
211
212                 if(rc != 0) {
213                         Debug( LDAP_DEBUG_ANY,
214                                 "backend_startup: bi_db_open failed!\n",
215                                 0, 0, 0 );
216                         return rc;
217                 }
218
219                 return rc;
220         }
221
222         /* open each backend type */
223         for( i = 0; i < nBackendInfo; i++ ) {
224                 if( backendInfo[i].bi_nDB == 0) {
225                         /* no database of this type, don't open */
226                         continue;
227                 }
228
229                 if( backendInfo[i].bi_open ) {
230                         rc = backendInfo[i].bi_open(
231                                 &backendInfo[i] );
232                 }
233
234                 if(rc != 0) {
235                         Debug( LDAP_DEBUG_ANY,
236                                 "backend_startup: bi_open %d failed!\n",
237                                 i, 0, 0 );
238                         return rc;
239                 }
240         }
241
242         /* open each backend database */
243         for( i = 0; i < nBackendDB; i++ ) {
244                 /* append global access controls */
245                 acl_append( &backendDB[i].be_acl, global_acl );
246
247                 if ( backendDB[i].bd_info->bi_db_open ) {
248                         rc = backendDB[i].bd_info->bi_db_open(
249                                 &backendDB[i] );
250                 }
251
252                 if(rc != 0) {
253                         Debug( LDAP_DEBUG_ANY,
254                                 "backend_startup: bi_db_open %d failed!\n",
255                                 i, 0, 0 );
256                         return rc;
257                 }
258         }
259
260         return rc;
261 }
262
263 int backend_num( Backend *be )
264 {
265         int i;
266
267         if( be == NULL ) return -1;
268
269         for( i = 0; i < nBackendDB; i++ ) {
270                 if( be == &backendDB[i] ) return i;
271         }
272         return -1;
273 }
274
275 int backend_shutdown( Backend *be )
276 {
277         int i;
278         int rc = 0;
279
280         if( be != NULL ) {
281                 /* shutdown a specific backend database */
282
283                 if ( be->bd_info->bi_nDB == 0 ) {
284                         /* no database of this type, we never opened it */
285                         return 0;
286                 }
287
288                 if ( be->bd_info->bi_db_close ) {
289                         be->bd_info->bi_db_close( be );
290                 }
291
292                 if( be->bd_info->bi_close ) {
293                         be->bd_info->bi_close( be->bd_info );
294                 }
295
296                 return 0;
297         }
298
299         /* close each backend database */
300         for( i = 0; i < nBackendDB; i++ ) {
301                 if ( backendDB[i].bd_info->bi_db_close ) {
302                         backendDB[i].bd_info->bi_db_close(
303                                 &backendDB[i] );
304                 }
305
306                 if(rc != 0) {
307                         Debug( LDAP_DEBUG_ANY,
308                                 "backend_close: bi_close %s failed!\n",
309                                 backendDB[i].be_type, 0, 0 );
310                 }
311         }
312
313         /* close each backend type */
314         for( i = 0; i < nBackendInfo; i++ ) {
315                 if( backendInfo[i].bi_nDB == 0 ) {
316                         /* no database of this type */
317                         continue;
318                 }
319
320                 if( backendInfo[i].bi_close ) {
321                         backendInfo[i].bi_close(
322                                 &backendInfo[i] );
323                 }
324         }
325
326         return 0;
327 }
328
329 int backend_destroy(void)
330 {
331         int i;
332
333         /* destroy each backend database */
334         for( i = 0; i < nBackendDB; i++ ) {
335                 if ( backendDB[i].bd_info->bi_db_destroy ) {
336                         backendDB[i].bd_info->bi_db_destroy(
337                                 &backendDB[i] );
338                 }
339         }
340
341         /* destroy each backend type */
342         for( i = 0; i < nBackendInfo; i++ ) {
343                 if( backendInfo[i].bi_destroy ) {
344                         backendInfo[i].bi_destroy(
345                                 &backendInfo[i] );
346                 }
347         }
348
349 #ifdef SLAPD_MODULES
350         if (backendInfo != binfo) {
351            free(backendInfo);
352         }
353 #endif /* SLAPD_MODULES */
354
355         nBackendInfo = 0;
356         backendInfo = NULL;
357
358         return 0;
359 }
360
361 BackendInfo* backend_info(const char *type)
362 {
363         int i;
364
365         /* search for the backend type */
366         for( i = 0; i < nBackendInfo; i++ ) {
367                 if( strcasecmp(backendInfo[i].bi_type, type) == 0 ) {
368                         return &backendInfo[i];
369                 }
370         }
371
372         return NULL;
373 }
374
375
376 BackendDB *
377 backend_db_init(
378     const char  *type
379 )
380 {
381         Backend *be;
382         BackendInfo *bi = backend_info(type);
383         int     rc = 0;
384
385         if( bi == NULL ) {
386                 fprintf( stderr, "Unrecognized database type (%s)\n", type );
387                 return NULL;
388         }
389
390         backendDB = (BackendDB *) ch_realloc(
391                         (char *) backendDB,
392                     (nBackendDB + 1) * sizeof(Backend) );
393
394         memset( &backendDB[nbackends], '\0', sizeof(Backend) );
395
396         be = &backends[nbackends++];
397
398         be->bd_info = bi;
399         be->be_sizelimit = defsize;
400         be->be_timelimit = deftime;
401         be->be_dfltaccess = global_default_access;
402
403         be->be_restrictops = global_restrictops;
404         be->be_requires = global_requires;
405
406         /* assign a default depth limit for alias deref */
407         be->be_max_deref_depth = SLAPD_DEFAULT_MAXDEREFDEPTH; 
408
409         if(bi->bi_db_init) {
410                 rc = bi->bi_db_init( be );
411         }
412
413         if(rc != 0) {
414                 fprintf( stderr, "database init failed (%s)\n", type );
415                 nbackends--;
416                 return NULL;
417         }
418
419         bi->bi_nDB++;
420         return( be );
421 }
422
423 void
424 be_db_close( void )
425 {
426         int     i;
427
428         for ( i = 0; i < nbackends; i++ ) {
429                 if ( backends[i].bd_info->bi_db_close ) {
430                         (*backends[i].bd_info->bi_db_close)( &backends[i] );
431                 }
432         }
433 }
434
435 Backend *
436 select_backend( const char * dn )
437 {
438         int     i, j, len, dnlen;
439
440         dnlen = strlen( dn );
441         for ( i = 0; i < nbackends; i++ ) {
442                 for ( j = 0; backends[i].be_nsuffix != NULL &&
443                     backends[i].be_nsuffix[j] != NULL; j++ )
444                 {
445                         len = strlen( backends[i].be_nsuffix[j] );
446
447                         if ( len > dnlen ) {
448                                 continue;
449                         }
450
451                         if ( strcmp( backends[i].be_nsuffix[j],
452                             dn + (dnlen - len) ) == 0 ) {
453                                 return( &backends[i] );
454                         }
455                 }
456         }
457
458         return( NULL );
459 }
460
461 int
462 be_issuffix(
463     Backend     *be,
464     const char  *suffix
465 )
466 {
467         int     i;
468
469         for ( i = 0; be->be_nsuffix != NULL && be->be_nsuffix[i] != NULL; i++ ) {
470                 if ( strcmp( be->be_nsuffix[i], suffix ) == 0 ) {
471                         return( 1 );
472                 }
473         }
474
475         return( 0 );
476 }
477
478 int
479 be_isroot( Backend *be, const char *ndn )
480 {
481         int rc;
482
483         if ( ndn == NULL || *ndn == '\0' ) {
484                 return( 0 );
485         }
486
487         if ( be->be_root_ndn == NULL || *be->be_root_ndn == '\0' ) {
488                 return( 0 );
489         }
490
491         rc = strcmp( be->be_root_ndn, ndn ) ? 0 : 1;
492
493         return(rc);
494 }
495
496 char *
497 be_root_dn( Backend *be )
498 {
499         if ( be->be_root_dn == NULL ) {
500                 return( "" );
501         }
502
503         return be->be_root_dn;
504 }
505
506 int
507 be_isroot_pw( Backend *be, const char *ndn, struct berval *cred )
508 {
509         int result;
510
511         if ( ! be_isroot( be, ndn ) ) {
512                 return 0;
513         }
514
515         if( be->be_root_pw.bv_len == 0 ) {
516                 return 0;
517         }
518
519 #ifdef SLAPD_CRYPT
520         ldap_pvt_thread_mutex_lock( &crypt_mutex );
521 #endif
522
523         result = lutil_passwd( &be->be_root_pw, cred, NULL );
524
525 #ifdef SLAPD_CRYPT
526         ldap_pvt_thread_mutex_unlock( &crypt_mutex );
527 #endif
528
529         return result == 0;
530 }
531
532 int
533 be_entry_release_rw( Backend *be, Entry *e, int rw )
534 {
535         if ( be->be_release ) {
536                 /* free and release entry from backend */
537                 return be->be_release( be, e, rw );
538         } else {
539                 /* free entry */
540                 entry_free( e );
541                 return 0;
542         }
543 }
544
545 int
546 backend_unbind(
547         Connection   *conn,
548         Operation    *op
549 )
550 {
551         int     i;
552
553         for ( i = 0; i < nbackends; i++ ) {
554                 if ( backends[i].be_unbind ) {
555                         (*backends[i].be_unbind)( &backends[i], conn, op );
556                 }
557         }
558
559         return 0;
560 }
561
562 int
563 backend_connection_init(
564         Connection   *conn
565 )
566 {
567         int     i;
568
569         for ( i = 0; i < nbackends; i++ ) {
570                 if ( backends[i].be_connection_init ) {
571                         (*backends[i].be_connection_init)( &backends[i], conn);
572                 }
573         }
574
575         return 0;
576 }
577
578 int
579 backend_connection_destroy(
580         Connection   *conn
581 )
582 {
583         int     i;
584
585         for ( i = 0; i < nbackends; i++ ) {
586                 if ( backends[i].be_connection_destroy ) {
587                         (*backends[i].be_connection_destroy)( &backends[i], conn);
588                 }
589         }
590
591         return 0;
592 }
593
594 static int
595 backend_check_controls(
596         Backend *be,
597         Connection *conn,
598         Operation *op,
599         const char **text )
600 {
601         LDAPControl **ctrls;
602         ctrls = op->o_ctrls;
603         if( ctrls == NULL ) {
604                 return LDAP_SUCCESS;
605         }
606
607         for( ; *ctrls != NULL ; ctrls++ ) {
608                 if( (*ctrls)->ldctl_iscritical &&
609                         !charray_inlist( be->be_controls, (*ctrls)->ldctl_oid ) )
610                 {
611                         *text = "control unavailable in NamingContext";
612                         return LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
613                 }
614         }
615
616         return LDAP_SUCCESS;
617 }
618
619 int
620 backend_check_restrictions(
621         Backend *be,
622         Connection *conn,
623         Operation *op,
624         const char *extoid,
625         const char **text )
626 {
627         int rc;
628         slap_mask_t restrictops;
629         slap_mask_t requires;
630         slap_mask_t opflag;
631         slap_ssf_set_t *ssf;
632         int updateop = 0;
633
634         if( be ) {
635                 rc = backend_check_controls( be, conn, op, text );
636
637                 if( rc != LDAP_SUCCESS ) {
638                         return rc;
639                 }
640
641                 restrictops = be->be_restrictops;
642                 requires = be->be_requires;
643                 ssf = &be->be_ssf_set;
644
645         } else {
646                 restrictops = global_restrictops;
647                 requires = global_requires;
648                 ssf = &global_ssf_set;
649         }
650
651         switch( op->o_tag ) {
652         case LDAP_REQ_ADD:
653                 opflag = SLAP_RESTRICT_OP_ADD;
654                 updateop++;
655                 break;
656         case LDAP_REQ_BIND:
657                 opflag = SLAP_RESTRICT_OP_BIND;
658                 break;
659         case LDAP_REQ_COMPARE:
660                 opflag = SLAP_RESTRICT_OP_COMPARE;
661                 break;
662         case LDAP_REQ_DELETE:
663                 updateop++;
664                 opflag = SLAP_RESTRICT_OP_DELETE;
665                 break;
666         case LDAP_REQ_EXTENDED:
667                 opflag = SLAP_RESTRICT_OP_EXTENDED;
668                 break;
669         case LDAP_REQ_MODIFY:
670                 updateop++;
671                 opflag = SLAP_RESTRICT_OP_MODIFY;
672                 break;
673         case LDAP_REQ_RENAME:
674                 updateop++;
675                 opflag = SLAP_RESTRICT_OP_RENAME;
676                 break;
677         case LDAP_REQ_SEARCH:
678                 opflag = SLAP_RESTRICT_OP_SEARCH;
679                 break;
680         case LDAP_REQ_UNBIND:
681                 opflag = 0;
682                 break;
683         default:
684                 *text = "restrict operations internal error";
685                 return LDAP_OTHER;
686         }
687
688         if (( extoid == NULL || strcmp( extoid, LDAP_EXOP_START_TLS ) ) ) {
689                 /* these checks don't apply to StartTLS */
690
691                 if( op->o_tag == LDAP_REQ_EXTENDED ) {
692                         /* threat other extended operations as update ops */
693                         updateop++;
694                 }
695
696                 if( op->o_ssf < ssf->sss_ssf ) {
697                         *text = "confidentiality required";
698                         return LDAP_CONFIDENTIALITY_REQUIRED;
699                 }
700                 if( op->o_transport_ssf < ssf->sss_transport ) {
701                         *text = "transport confidentiality required";
702                         return LDAP_CONFIDENTIALITY_REQUIRED;
703                 }
704                 if( op->o_tls_ssf < ssf->sss_tls ) {
705                         *text = "TLS confidentiality required";
706                         return LDAP_CONFIDENTIALITY_REQUIRED;
707                 }
708                 if( op->o_sasl_ssf < ssf->sss_sasl ) {
709                         *text = "SASL confidentiality required";
710                         return LDAP_CONFIDENTIALITY_REQUIRED;
711                 }
712
713                 if( updateop ) {
714                         if( op->o_ssf < ssf->sss_update_ssf ) {
715                                 *text = "update confidentiality required";
716                                 return LDAP_CONFIDENTIALITY_REQUIRED;
717                         }
718                         if( op->o_transport_ssf < ssf->sss_update_transport ) {
719                                 *text = "transport update confidentiality required";
720                                 return LDAP_CONFIDENTIALITY_REQUIRED;
721                         }
722                         if( op->o_tls_ssf < ssf->sss_update_tls ) {
723                                 *text = "TLS update confidentiality required";
724                                 return LDAP_CONFIDENTIALITY_REQUIRED;
725                         }
726                         if( op->o_sasl_ssf < ssf->sss_update_sasl ) {
727                                 *text = "SASL update confidentiality required";
728                                 return LDAP_CONFIDENTIALITY_REQUIRED;
729                         }
730                 }
731         }
732
733         if (( extoid == NULL || strcmp( extoid, LDAP_EXOP_START_TLS ) )
734                 || op->o_tag == LDAP_REQ_BIND )
735         {
736                 /* these checks don't apply to StartTLS or Bind */
737
738                 if( requires & SLAP_REQUIRE_STRONG ) {
739                         /* should check mechanism */
740                         if( op->o_authmech == NULL ||
741                                 op->o_dn == NULL || *op->o_dn == '\0' )
742                         {
743                                 *text = "strong authentication required";
744                                 return LDAP_STRONG_AUTH_REQUIRED;
745                         }
746                 }
747
748                 if( requires & SLAP_REQUIRE_SASL ) {
749                         if( op->o_authmech == NULL ||
750                                 op->o_dn == NULL || *op->o_dn == '\0' )
751                         {
752                                 *text = "SASL authentication required";
753                                 return LDAP_STRONG_AUTH_REQUIRED;
754                         }
755                 }
756                         
757                 if( requires & SLAP_REQUIRE_AUTHC ) {
758                         if( op->o_dn == NULL || *op->o_dn == '\0' ) {
759                                 *text = "authentication required";
760                                 return LDAP_UNWILLING_TO_PERFORM;
761                         }
762                 }
763
764                 if( requires & SLAP_REQUIRE_BIND ) {
765                         int version;
766                         ldap_pvt_thread_mutex_lock( &conn->c_mutex );
767                         version = conn->c_protocol;
768                         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
769
770                         if( !version ) {
771                                 /* no bind has occurred */
772                                 *text = "BIND required";
773                                 return LDAP_OPERATIONS_ERROR;
774                         }
775                 }
776
777                 if( requires & SLAP_REQUIRE_LDAP_V3 ) {
778                         if( op->o_protocol < LDAP_VERSION3 ) {
779                                 /* no bind has occurred */
780                                 *text = "operation restricted to LDAPv3 clients";
781                                 return LDAP_OPERATIONS_ERROR;
782                         }
783                 }
784         }
785
786         if( restrictops & opflag ) {
787                 if( restrictops == SLAP_RESTRICT_OP_READS ) {
788                         *text = "read operations restricted";
789                 } else {
790                         *text = "operation restricted";
791                 }
792                 return LDAP_UNWILLING_TO_PERFORM;
793         }
794
795         return LDAP_SUCCESS;
796 }
797
798 int backend_check_referrals(
799         Backend *be,
800         Connection *conn,
801         Operation *op,
802         const char *dn,
803         const char *ndn )
804 {
805         int rc = LDAP_SUCCESS;
806
807         if( be->be_chk_referrals ) {
808                 const char *text;
809
810                 rc = be->be_chk_referrals( be,
811                         conn, op, dn, ndn, &text );
812
813                 if( rc != LDAP_SUCCESS && rc != LDAP_REFERRAL ) {
814                         send_ldap_result( conn, op, rc,
815                                 NULL, text, NULL, NULL );
816                 }
817         }
818
819         return rc;
820 }
821
822 int 
823 backend_group(
824         Backend *be,
825         Entry   *target,
826         const char      *gr_ndn,
827         const char      *op_ndn,
828         ObjectClass *group_oc,
829         AttributeDescription *group_at
830 )
831 {
832         if( strcmp( target->e_ndn, gr_ndn ) != 0 ) {
833                 /* we won't attempt to send it to a different backend */
834                 
835                 be = select_backend(gr_ndn);
836
837                 if (be == NULL) {
838                         return LDAP_NO_SUCH_OBJECT;
839                 }
840         } 
841
842         if( be->be_group ) {
843                 return be->be_group( be, target, gr_ndn, op_ndn,
844                         group_oc, group_at );
845         }
846
847         return LDAP_UNWILLING_TO_PERFORM;
848 }
849
850 int 
851 backend_attribute(
852         Backend *be,
853         Connection *conn,
854         Operation *op,
855         Entry   *target,
856         const char      *e_ndn,
857         AttributeDescription *entry_at,
858         struct berval ***vals
859 )
860 {
861         if( target == NULL || strcmp( target->e_ndn, e_ndn ) != 0 ) {
862                 /* we won't attempt to send it to a different backend */
863                 
864                 be = select_backend(e_ndn);
865
866                 if (be == NULL) {
867                         return LDAP_NO_SUCH_OBJECT;
868                 }
869         } 
870
871         if( be->be_attribute ) {
872                 return be->be_attribute( be, conn, op, target, e_ndn,
873                         entry_at, vals );
874         }
875
876         return LDAP_UNWILLING_TO_PERFORM;
877 }
878
879 Attribute *backend_operational(
880         Backend *be,
881         Entry *e )
882 {
883         Attribute *a = NULL;
884
885 #ifdef SLAPD_SCHEMA_DN
886         a = ch_malloc( sizeof( Attribute ) );
887         a->a_desc = ad_dup( slap_schema.si_ad_subschemaSubentry );
888
889         /* Should be backend specific */
890         a->a_vals = ch_malloc( 2 * sizeof( struct berval * ) );
891         a->a_vals[0] = ber_bvstrdup( SLAPD_SCHEMA_DN );
892         a->a_vals[1] = NULL;
893
894         a->a_next = NULL;
895 #endif
896
897         return a;
898 }