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