]> git.sur5r.net Git - openldap/blob - servers/slapd/backend.c
0dad539936c0a9919776ef56456ac850e44f4551
[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 #if defined( SLAPD_CRYPT ) || defined( SLAPD_PASSWD )
520         ldap_pvt_thread_mutex_lock( &passwd_mutex );
521 #ifdef SLAPD_SPASSWD
522         lutil_passwd_sasl_conn = conn->c_sasl_context;
523 #endif
524 #endif
525
526         result = lutil_passwd( &be->be_root_pw, cred, NULL );
527
528 #if defined( SLAPD_CRYPT ) || defined( SLAPD_PASSWD )
529         ldap_pvt_thread_mutex_unlock( &passwd_mutex );
530 #endif
531
532         return result == 0;
533 }
534
535 int
536 be_entry_release_rw( Backend *be, Entry *e, int rw )
537 {
538         if ( be->be_release ) {
539                 /* free and release entry from backend */
540                 return be->be_release( be, e, rw );
541         } else {
542                 /* free entry */
543                 entry_free( e );
544                 return 0;
545         }
546 }
547
548 int
549 backend_unbind(
550         Connection   *conn,
551         Operation    *op
552 )
553 {
554         int     i;
555
556         for ( i = 0; i < nbackends; i++ ) {
557                 if ( backends[i].be_unbind ) {
558                         (*backends[i].be_unbind)( &backends[i], conn, op );
559                 }
560         }
561
562         return 0;
563 }
564
565 int
566 backend_connection_init(
567         Connection   *conn
568 )
569 {
570         int     i;
571
572         for ( i = 0; i < nbackends; i++ ) {
573                 if ( backends[i].be_connection_init ) {
574                         (*backends[i].be_connection_init)( &backends[i], conn);
575                 }
576         }
577
578         return 0;
579 }
580
581 int
582 backend_connection_destroy(
583         Connection   *conn
584 )
585 {
586         int     i;
587
588         for ( i = 0; i < nbackends; i++ ) {
589                 if ( backends[i].be_connection_destroy ) {
590                         (*backends[i].be_connection_destroy)( &backends[i], conn);
591                 }
592         }
593
594         return 0;
595 }
596
597 static int
598 backend_check_controls(
599         Backend *be,
600         Connection *conn,
601         Operation *op,
602         const char **text )
603 {
604         LDAPControl **ctrls;
605         ctrls = op->o_ctrls;
606         if( ctrls == NULL ) {
607                 return LDAP_SUCCESS;
608         }
609
610         for( ; *ctrls != NULL ; ctrls++ ) {
611                 if( (*ctrls)->ldctl_iscritical &&
612                         !charray_inlist( be->be_controls, (*ctrls)->ldctl_oid ) )
613                 {
614                         *text = "control unavailable in NamingContext";
615                         return LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
616                 }
617         }
618
619         return LDAP_SUCCESS;
620 }
621
622 int
623 backend_check_restrictions(
624         Backend *be,
625         Connection *conn,
626         Operation *op,
627         const char *extoid,
628         const char **text )
629 {
630         int rc;
631         slap_mask_t restrictops;
632         slap_mask_t requires;
633         slap_mask_t opflag;
634         slap_ssf_set_t *ssf;
635         int updateop = 0;
636
637         if( be ) {
638                 rc = backend_check_controls( be, conn, op, text );
639
640                 if( rc != LDAP_SUCCESS ) {
641                         return rc;
642                 }
643
644                 restrictops = be->be_restrictops;
645                 requires = be->be_requires;
646                 ssf = &be->be_ssf_set;
647
648         } else {
649                 restrictops = global_restrictops;
650                 requires = global_requires;
651                 ssf = &global_ssf_set;
652         }
653
654         switch( op->o_tag ) {
655         case LDAP_REQ_ADD:
656                 opflag = SLAP_RESTRICT_OP_ADD;
657                 updateop++;
658                 break;
659         case LDAP_REQ_BIND:
660                 opflag = SLAP_RESTRICT_OP_BIND;
661                 break;
662         case LDAP_REQ_COMPARE:
663                 opflag = SLAP_RESTRICT_OP_COMPARE;
664                 break;
665         case LDAP_REQ_DELETE:
666                 updateop++;
667                 opflag = SLAP_RESTRICT_OP_DELETE;
668                 break;
669         case LDAP_REQ_EXTENDED:
670                 opflag = SLAP_RESTRICT_OP_EXTENDED;
671                 break;
672         case LDAP_REQ_MODIFY:
673                 updateop++;
674                 opflag = SLAP_RESTRICT_OP_MODIFY;
675                 break;
676         case LDAP_REQ_RENAME:
677                 updateop++;
678                 opflag = SLAP_RESTRICT_OP_RENAME;
679                 break;
680         case LDAP_REQ_SEARCH:
681                 opflag = SLAP_RESTRICT_OP_SEARCH;
682                 break;
683         case LDAP_REQ_UNBIND:
684                 opflag = 0;
685                 break;
686         default:
687                 *text = "restrict operations internal error";
688                 return LDAP_OTHER;
689         }
690
691         if (( extoid == NULL || strcmp( extoid, LDAP_EXOP_START_TLS ) ) ) {
692                 /* these checks don't apply to StartTLS */
693
694                 if( op->o_tag == LDAP_REQ_EXTENDED ) {
695                         /* threat other extended operations as update ops */
696                         updateop++;
697                 }
698
699                 if( op->o_ssf < ssf->sss_ssf ) {
700                         *text = "confidentiality required";
701                         return LDAP_CONFIDENTIALITY_REQUIRED;
702                 }
703                 if( op->o_transport_ssf < ssf->sss_transport ) {
704                         *text = "transport confidentiality required";
705                         return LDAP_CONFIDENTIALITY_REQUIRED;
706                 }
707                 if( op->o_tls_ssf < ssf->sss_tls ) {
708                         *text = "TLS confidentiality required";
709                         return LDAP_CONFIDENTIALITY_REQUIRED;
710                 }
711                 if( op->o_sasl_ssf < ssf->sss_sasl ) {
712                         *text = "SASL confidentiality required";
713                         return LDAP_CONFIDENTIALITY_REQUIRED;
714                 }
715
716                 if( updateop ) {
717                         if( op->o_ssf < ssf->sss_update_ssf ) {
718                                 *text = "update confidentiality required";
719                                 return LDAP_CONFIDENTIALITY_REQUIRED;
720                         }
721                         if( op->o_transport_ssf < ssf->sss_update_transport ) {
722                                 *text = "transport update confidentiality required";
723                                 return LDAP_CONFIDENTIALITY_REQUIRED;
724                         }
725                         if( op->o_tls_ssf < ssf->sss_update_tls ) {
726                                 *text = "TLS update confidentiality required";
727                                 return LDAP_CONFIDENTIALITY_REQUIRED;
728                         }
729                         if( op->o_sasl_ssf < ssf->sss_update_sasl ) {
730                                 *text = "SASL update confidentiality required";
731                                 return LDAP_CONFIDENTIALITY_REQUIRED;
732                         }
733                 }
734         }
735
736         if (( extoid == NULL || strcmp( extoid, LDAP_EXOP_START_TLS ) )
737                 || op->o_tag == LDAP_REQ_BIND )
738         {
739                 /* these checks don't apply to StartTLS or Bind */
740
741                 if( requires & SLAP_REQUIRE_STRONG ) {
742                         /* should check mechanism */
743                         if( op->o_authmech == NULL ||
744                                 op->o_dn == NULL || *op->o_dn == '\0' )
745                         {
746                                 *text = "strong authentication required";
747                                 return LDAP_STRONG_AUTH_REQUIRED;
748                         }
749                 }
750
751                 if( requires & SLAP_REQUIRE_SASL ) {
752                         if( op->o_authmech == NULL ||
753                                 op->o_dn == NULL || *op->o_dn == '\0' )
754                         {
755                                 *text = "SASL authentication required";
756                                 return LDAP_STRONG_AUTH_REQUIRED;
757                         }
758                 }
759                         
760                 if( requires & SLAP_REQUIRE_AUTHC ) {
761                         if( op->o_dn == NULL || *op->o_dn == '\0' ) {
762                                 *text = "authentication required";
763                                 return LDAP_UNWILLING_TO_PERFORM;
764                         }
765                 }
766
767                 if( requires & SLAP_REQUIRE_BIND ) {
768                         int version;
769                         ldap_pvt_thread_mutex_lock( &conn->c_mutex );
770                         version = conn->c_protocol;
771                         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
772
773                         if( !version ) {
774                                 /* no bind has occurred */
775                                 *text = "BIND required";
776                                 return LDAP_OPERATIONS_ERROR;
777                         }
778                 }
779
780                 if( requires & SLAP_REQUIRE_LDAP_V3 ) {
781                         if( op->o_protocol < LDAP_VERSION3 ) {
782                                 /* no bind has occurred */
783                                 *text = "operation restricted to LDAPv3 clients";
784                                 return LDAP_OPERATIONS_ERROR;
785                         }
786                 }
787         }
788
789         if( restrictops & opflag ) {
790                 if( restrictops == SLAP_RESTRICT_OP_READS ) {
791                         *text = "read operations restricted";
792                 } else {
793                         *text = "operation restricted";
794                 }
795                 return LDAP_UNWILLING_TO_PERFORM;
796         }
797
798         return LDAP_SUCCESS;
799 }
800
801 int backend_check_referrals(
802         Backend *be,
803         Connection *conn,
804         Operation *op,
805         const char *dn,
806         const char *ndn )
807 {
808         int rc = LDAP_SUCCESS;
809
810         if( be->be_chk_referrals ) {
811                 const char *text;
812
813                 rc = be->be_chk_referrals( be,
814                         conn, op, dn, ndn, &text );
815
816                 if( rc != LDAP_SUCCESS && rc != LDAP_REFERRAL ) {
817                         send_ldap_result( conn, op, rc,
818                                 NULL, text, NULL, NULL );
819                 }
820         }
821
822         return rc;
823 }
824
825 int 
826 backend_group(
827         Backend *be,
828         Entry   *target,
829         const char      *gr_ndn,
830         const char      *op_ndn,
831         ObjectClass *group_oc,
832         AttributeDescription *group_at
833 )
834 {
835         if( strcmp( target->e_ndn, gr_ndn ) != 0 ) {
836                 /* we won't attempt to send it to a different backend */
837                 
838                 be = select_backend(gr_ndn);
839
840                 if (be == NULL) {
841                         return LDAP_NO_SUCH_OBJECT;
842                 }
843         } 
844
845         if( be->be_group ) {
846                 return be->be_group( be, target, gr_ndn, op_ndn,
847                         group_oc, group_at );
848         }
849
850         return LDAP_UNWILLING_TO_PERFORM;
851 }
852
853 int 
854 backend_attribute(
855         Backend *be,
856         Connection *conn,
857         Operation *op,
858         Entry   *target,
859         const char      *e_ndn,
860         AttributeDescription *entry_at,
861         struct berval ***vals
862 )
863 {
864         if( target == NULL || strcmp( target->e_ndn, e_ndn ) != 0 ) {
865                 /* we won't attempt to send it to a different backend */
866                 
867                 be = select_backend(e_ndn);
868
869                 if (be == NULL) {
870                         return LDAP_NO_SUCH_OBJECT;
871                 }
872         } 
873
874         if( be->be_attribute ) {
875                 return be->be_attribute( be, conn, op, target, e_ndn,
876                         entry_at, vals );
877         }
878
879         return LDAP_UNWILLING_TO_PERFORM;
880 }
881
882 Attribute *backend_operational(
883         Backend *be,
884         Entry *e )
885 {
886         Attribute *a = NULL;
887
888 #ifdef SLAPD_SCHEMA_DN
889         a = ch_malloc( sizeof( Attribute ) );
890         a->a_desc = ad_dup( slap_schema.si_ad_subschemaSubentry );
891
892         /* Should be backend specific */
893         a->a_vals = ch_malloc( 2 * sizeof( struct berval * ) );
894         a->a_vals[0] = ber_bvstrdup( SLAPD_SCHEMA_DN );
895         a->a_vals[1] = NULL;
896
897         a->a_next = NULL;
898 #endif
899
900         return a;
901 }