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