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