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