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