Back to index

openldap  2.4.31
backend.c
Go to the documentation of this file.
00001 /* backend.c - routines for dealing with back-end databases */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 1998-2012 The OpenLDAP Foundation.
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted only as authorized by the OpenLDAP
00010  * Public License.
00011  *
00012  * A copy of this license is available in the file LICENSE in the
00013  * top-level directory of the distribution or, alternatively, at
00014  * <http://www.OpenLDAP.org/license.html>.
00015  */
00016 /* Portions Copyright (c) 1995 Regents of the University of Michigan.
00017  * All rights reserved.
00018  *
00019  * Redistribution and use in source and binary forms are permitted
00020  * provided that this notice is preserved and that due credit is given
00021  * to the University of Michigan at Ann Arbor. The name of the University
00022  * may not be used to endorse or promote products derived from this
00023  * software without specific prior written permission. This software
00024  * is provided ``as is'' without express or implied warranty.
00025  */
00026 
00027 
00028 #include "portable.h"
00029 
00030 #include <stdio.h>
00031 
00032 #include <ac/string.h>
00033 #include <ac/socket.h>
00034 #include <sys/stat.h>
00035 
00036 #include "slap.h"
00037 #include "config.h"
00038 #include "lutil.h"
00039 #include "lber_pvt.h"
00040 
00041 /*
00042  * If a module is configured as dynamic, its header should not
00043  * get included into slapd. While this is a general rule and does
00044  * not have much of an effect in UNIX, this rule should be adhered
00045  * to for Windows, where dynamic object code should not be implicitly
00046  * imported into slapd without appropriate __declspec(dllimport) directives.
00047  */
00048 
00049 int                  nBackendInfo = 0;
00050 slap_bi_head backendInfo = LDAP_STAILQ_HEAD_INITIALIZER(backendInfo);
00051 
00052 int                  nBackendDB = 0; 
00053 slap_be_head backendDB = LDAP_STAILQ_HEAD_INITIALIZER(backendDB);
00054 
00055 static int
00056 backend_init_controls( BackendInfo *bi )
00057 {
00058        if ( bi->bi_controls ) {
00059               int    i;
00060 
00061               for ( i = 0; bi->bi_controls[ i ]; i++ ) {
00062                      int    cid;
00063 
00064                      if ( slap_find_control_id( bi->bi_controls[ i ], &cid )
00065                                    == LDAP_CONTROL_NOT_FOUND )
00066                      {
00067                             if ( !( slapMode & SLAP_TOOL_MODE ) ) {
00068                                    assert( 0 );
00069                             }
00070 
00071                             return -1;
00072                      }
00073 
00074                      bi->bi_ctrls[ cid ] = 1;
00075               }
00076        }
00077 
00078        return 0;
00079 }
00080 
00081 int backend_init(void)
00082 {
00083        int rc = -1;
00084        BackendInfo *bi;
00085 
00086        if((nBackendInfo != 0) || !LDAP_STAILQ_EMPTY(&backendInfo)) {
00087               /* already initialized */
00088               Debug( LDAP_DEBUG_ANY,
00089                      "backend_init: already initialized\n", 0, 0, 0 );
00090               return -1;
00091        }
00092 
00093        for( bi=slap_binfo; bi->bi_type != NULL; bi++,nBackendInfo++ ) {
00094               assert( bi->bi_init != 0 );
00095 
00096               rc = bi->bi_init( bi );
00097 
00098               if(rc != 0) {
00099                      Debug( LDAP_DEBUG_ANY,
00100                             "backend_init: initialized for type \"%s\"\n",
00101                             bi->bi_type, 0, 0 );
00102                      /* destroy those we've already inited */
00103                      for( nBackendInfo--;
00104                             nBackendInfo >= 0 ;
00105                             nBackendInfo-- )
00106                      { 
00107                             if ( slap_binfo[nBackendInfo].bi_destroy ) {
00108                                    slap_binfo[nBackendInfo].bi_destroy(
00109                                           &slap_binfo[nBackendInfo] );
00110                             }
00111                      }
00112                      return rc;
00113               }
00114 
00115               LDAP_STAILQ_INSERT_TAIL(&backendInfo, bi, bi_next);
00116        }
00117 
00118        if ( nBackendInfo > 0) {
00119               return 0;
00120        }
00121 
00122 #ifdef SLAPD_MODULES 
00123        return 0;
00124 #else
00125 
00126        Debug( LDAP_DEBUG_ANY,
00127               "backend_init: failed\n",
00128               0, 0, 0 );
00129 
00130        return rc;
00131 #endif /* SLAPD_MODULES */
00132 }
00133 
00134 int backend_add(BackendInfo *aBackendInfo)
00135 {
00136        int rc = 0;
00137 
00138        if ( aBackendInfo->bi_init == NULL ) {
00139               Debug( LDAP_DEBUG_ANY, "backend_add: "
00140                      "backend type \"%s\" does not have the (mandatory)init function\n",
00141                      aBackendInfo->bi_type, 0, 0 );
00142               return -1;
00143        }
00144 
00145        rc = aBackendInfo->bi_init(aBackendInfo);
00146        if ( rc != 0) {
00147               Debug( LDAP_DEBUG_ANY,
00148                      "backend_add:  initialization for type \"%s\" failed\n",
00149                      aBackendInfo->bi_type, 0, 0 );
00150               return rc;
00151        }
00152 
00153        (void)backend_init_controls( aBackendInfo );
00154 
00155        /* now add the backend type to the Backend Info List */
00156        LDAP_STAILQ_INSERT_TAIL( &backendInfo, aBackendInfo, bi_next );
00157        nBackendInfo++;
00158        return 0;
00159 }
00160 
00161 static int
00162 backend_set_controls( BackendDB *be )
00163 {
00164        BackendInfo   *bi = be->bd_info;
00165 
00166        /* back-relay takes care of itself; so may do other */
00167        if ( overlay_is_over( be ) ) {
00168               bi = ((slap_overinfo *)be->bd_info->bi_private)->oi_orig;
00169        }
00170 
00171        if ( bi->bi_controls ) {
00172               if ( be->be_ctrls[ SLAP_MAX_CIDS ] == 0 ) {
00173                      AC_MEMCPY( be->be_ctrls, bi->bi_ctrls,
00174                                    sizeof( be->be_ctrls ) );
00175                      be->be_ctrls[ SLAP_MAX_CIDS ] = 1;
00176                      
00177               } else {
00178                      int    i;
00179                      
00180                      for ( i = 0; i < SLAP_MAX_CIDS; i++ ) {
00181                             if ( bi->bi_ctrls[ i ] ) {
00182                                    be->be_ctrls[ i ] = bi->bi_ctrls[ i ];
00183                             }
00184                      }
00185               }
00186 
00187        }
00188 
00189        return 0;
00190 }
00191 
00192 /* startup a specific backend database */
00193 int backend_startup_one(Backend *be, ConfigReply *cr)
00194 {
00195        int           rc = 0;
00196 
00197        assert( be != NULL );
00198 
00199        be->be_pending_csn_list = (struct be_pcl *)
00200               ch_calloc( 1, sizeof( struct be_pcl ) );
00201 
00202        LDAP_TAILQ_INIT( be->be_pending_csn_list );
00203 
00204        Debug( LDAP_DEBUG_TRACE,
00205               "backend_startup_one: starting \"%s\"\n",
00206               be->be_suffix ? be->be_suffix[0].bv_val : "(unknown)",
00207               0, 0 );
00208 
00209        /* set database controls */
00210        (void)backend_set_controls( be );
00211 
00212 #if 0
00213        if ( !BER_BVISEMPTY( &be->be_rootndn )
00214               && select_backend( &be->be_rootndn, 0 ) == be
00215               && BER_BVISNULL( &be->be_rootpw ) )
00216        {
00217               /* warning: if rootdn entry is created,
00218                * it can take rootdn privileges;
00219                * set empty rootpw to prevent */
00220        }
00221 #endif
00222 
00223        if ( be->bd_info->bi_db_open ) {
00224               rc = be->bd_info->bi_db_open( be, cr );
00225               if ( rc == 0 ) {
00226                      (void)backend_set_controls( be );
00227 
00228               } else {
00229                      char *type = be->bd_info->bi_type;
00230                      char *suffix = "(null)";
00231 
00232                      if ( overlay_is_over( be ) ) {
00233                             slap_overinfo *oi = (slap_overinfo *)be->bd_info->bi_private;
00234                             type = oi->oi_orig->bi_type;
00235                      }
00236 
00237                      if ( be->be_suffix != NULL && !BER_BVISNULL( &be->be_suffix[0] ) ) {
00238                             suffix = be->be_suffix[0].bv_val;
00239                      }
00240 
00241                      Debug( LDAP_DEBUG_ANY,
00242                             "backend_startup_one (type=%s, suffix=\"%s\"): "
00243                             "bi_db_open failed! (%d)\n",
00244                             type, suffix, rc );
00245               }
00246        }
00247 
00248        return rc;
00249 }
00250 
00251 int backend_startup(Backend *be)
00252 {
00253        int i;
00254        int rc = 0;
00255        BackendInfo *bi;
00256        ConfigReply cr={0, ""};
00257 
00258        if( ! ( nBackendDB > 0 ) ) {
00259               /* no databases */
00260               Debug( LDAP_DEBUG_ANY,
00261                      "backend_startup: %d databases to startup.\n",
00262                      nBackendDB, 0, 0 );
00263               return 1;
00264        }
00265 
00266        if(be != NULL) {
00267               if ( be->bd_info->bi_open ) {
00268                      rc = be->bd_info->bi_open( be->bd_info );
00269                      if ( rc != 0 ) {
00270                             Debug( LDAP_DEBUG_ANY,
00271                                    "backend_startup: bi_open failed!\n",
00272                                    0, 0, 0 );
00273 
00274                             return rc;
00275                      }
00276               }
00277 
00278               return backend_startup_one( be, &cr );
00279        }
00280 
00281        /* open frontend, if required */
00282        if ( frontendDB->bd_info->bi_db_open ) {
00283               rc = frontendDB->bd_info->bi_db_open( frontendDB, &cr );
00284               if ( rc != 0 ) {
00285                      Debug( LDAP_DEBUG_ANY,
00286                             "backend_startup: bi_db_open(frontend) failed! (%d)\n",
00287                             rc, 0, 0 );
00288                      return rc;
00289               }
00290        }
00291 
00292        /* open each backend type */
00293        i = -1;
00294        LDAP_STAILQ_FOREACH(bi, &backendInfo, bi_next) {
00295               i++;
00296               if( bi->bi_nDB == 0) {
00297                      /* no database of this type, don't open */
00298                      continue;
00299               }
00300 
00301               if( bi->bi_open ) {
00302                      rc = bi->bi_open( bi );
00303                      if ( rc != 0 ) {
00304                             Debug( LDAP_DEBUG_ANY,
00305                                    "backend_startup: bi_open %d (%s) failed!\n",
00306                                    i, bi->bi_type, 0 );
00307                             return rc;
00308                      }
00309               }
00310 
00311               (void)backend_init_controls( bi );
00312        }
00313 
00314        /* open each backend database */
00315        i = -1;
00316        LDAP_STAILQ_FOREACH(be, &backendDB, be_next) {
00317               i++;
00318               if ( be->be_suffix == NULL ) {
00319                      Debug( LDAP_DEBUG_ANY,
00320                             "backend_startup: warning, database %d (%s) "
00321                             "has no suffix\n",
00322                             i, be->bd_info->bi_type, 0 );
00323               }
00324 
00325               rc = backend_startup_one( be, &cr );
00326 
00327               if ( rc ) return rc;
00328        }
00329 
00330        return rc;
00331 }
00332 
00333 int backend_num( Backend *be )
00334 {
00335        int i = 0;
00336        BackendDB *b2;
00337 
00338        if( be == NULL ) return -1;
00339 
00340        LDAP_STAILQ_FOREACH( b2, &backendDB, be_next ) {
00341               if( be == b2 ) return i;
00342               i++;
00343        }
00344        return -1;
00345 }
00346 
00347 int backend_shutdown( Backend *be )
00348 {
00349        int rc = 0;
00350        BackendInfo *bi;
00351 
00352        if( be != NULL ) {
00353               /* shutdown a specific backend database */
00354 
00355               if ( be->bd_info->bi_nDB == 0 ) {
00356                      /* no database of this type, we never opened it */
00357                      return 0;
00358               }
00359 
00360               if ( be->bd_info->bi_db_close ) {
00361                      rc = be->bd_info->bi_db_close( be, NULL );
00362                      if ( rc ) return rc;
00363               }
00364 
00365               if( be->bd_info->bi_close ) {
00366                      rc = be->bd_info->bi_close( be->bd_info );
00367                      if ( rc ) return rc;
00368               }
00369 
00370               return 0;
00371        }
00372 
00373        /* close each backend database */
00374        LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) {
00375               if ( be->bd_info->bi_db_close ) {
00376                      be->bd_info->bi_db_close( be, NULL );
00377               }
00378 
00379               if(rc != 0) {
00380                      Debug( LDAP_DEBUG_ANY,
00381                             "backend_close: bi_db_close %s failed!\n",
00382                             be->be_type, 0, 0 );
00383               }
00384        }
00385 
00386        /* close each backend type */
00387        LDAP_STAILQ_FOREACH( bi, &backendInfo, bi_next ) {
00388               if( bi->bi_nDB == 0 ) {
00389                      /* no database of this type */
00390                      continue;
00391               }
00392 
00393               if( bi->bi_close ) {
00394                      bi->bi_close( bi );
00395               }
00396        }
00397 
00398        /* close frontend, if required */
00399        if ( frontendDB->bd_info->bi_db_close ) {
00400               rc = frontendDB->bd_info->bi_db_close ( frontendDB, NULL );
00401               if ( rc != 0 ) {
00402                      Debug( LDAP_DEBUG_ANY,
00403                             "backend_startup: bi_db_close(frontend) failed! (%d)\n",
00404                             rc, 0, 0 );
00405               }
00406        }
00407 
00408        return 0;
00409 }
00410 
00411 /*
00412  * This function is supposed to be the exact counterpart
00413  * of backend_startup_one(), although this one calls bi_db_destroy()
00414  * while backend_startup_one() calls bi_db_open().
00415  *
00416  * Make sure backend_stopdown_one() destroys resources allocated
00417  * by backend_startup_one(); only call backend_destroy_one() when
00418  * all stuff in a BackendDB needs to be destroyed
00419  */
00420 void
00421 backend_stopdown_one( BackendDB *bd )
00422 {
00423        if ( bd->be_pending_csn_list ) {
00424               struct slap_csn_entry *csne;
00425               csne = LDAP_TAILQ_FIRST( bd->be_pending_csn_list );
00426               while ( csne ) {
00427                      struct slap_csn_entry *tmp_csne = csne;
00428 
00429                      LDAP_TAILQ_REMOVE( bd->be_pending_csn_list, csne, ce_csn_link );
00430                      ch_free( csne->ce_csn.bv_val );
00431                      csne = LDAP_TAILQ_NEXT( csne, ce_csn_link );
00432                      ch_free( tmp_csne );
00433               }
00434               ch_free( bd->be_pending_csn_list );
00435        }
00436 
00437        if ( bd->bd_info->bi_db_destroy ) {
00438               bd->bd_info->bi_db_destroy( bd, NULL );
00439        }
00440 }
00441 
00442 void backend_destroy_one( BackendDB *bd, int dynamic )
00443 {
00444        if ( dynamic ) {
00445               LDAP_STAILQ_REMOVE(&backendDB, bd, BackendDB, be_next );
00446        }
00447 
00448        if ( bd->be_syncinfo ) {
00449               syncinfo_free( bd->be_syncinfo, 1 );
00450        }
00451 
00452        backend_stopdown_one( bd );
00453 
00454        ber_bvarray_free( bd->be_suffix );
00455        ber_bvarray_free( bd->be_nsuffix );
00456        if ( !BER_BVISNULL( &bd->be_rootdn ) ) {
00457               free( bd->be_rootdn.bv_val );
00458        }
00459        if ( !BER_BVISNULL( &bd->be_rootndn ) ) {
00460               free( bd->be_rootndn.bv_val );
00461        }
00462        if ( !BER_BVISNULL( &bd->be_rootpw ) ) {
00463               free( bd->be_rootpw.bv_val );
00464        }
00465        acl_destroy( bd->be_acl );
00466        limits_destroy( bd->be_limits );
00467        if ( bd->be_extra_anlist ) {
00468               anlist_free( bd->be_extra_anlist, 1, NULL );
00469        }
00470        if ( !BER_BVISNULL( &bd->be_update_ndn ) ) {
00471               ch_free( bd->be_update_ndn.bv_val );
00472        }
00473        if ( bd->be_update_refs ) {
00474               ber_bvarray_free( bd->be_update_refs );
00475        }
00476 
00477        ldap_pvt_thread_mutex_destroy( &bd->be_pcl_mutex );
00478 
00479        if ( dynamic ) {
00480               free( bd );
00481        }
00482 }
00483 
00484 int backend_destroy(void)
00485 {
00486        BackendDB *bd;
00487        BackendInfo *bi;
00488 
00489        /* destroy each backend database */
00490        while (( bd = LDAP_STAILQ_FIRST(&backendDB))) {
00491               backend_destroy_one( bd, 1 );
00492        }
00493 
00494        /* destroy each backend type */
00495        LDAP_STAILQ_FOREACH( bi, &backendInfo, bi_next ) {
00496               if( bi->bi_destroy ) {
00497                      bi->bi_destroy( bi );
00498               }
00499        }
00500 
00501        nBackendInfo = 0;
00502        LDAP_STAILQ_INIT(&backendInfo);
00503 
00504        /* destroy frontend database */
00505        bd = frontendDB;
00506        if ( bd ) {
00507               if ( bd->bd_info->bi_db_destroy ) {
00508                      bd->bd_info->bi_db_destroy( bd, NULL );
00509               }
00510               ber_bvarray_free( bd->be_suffix );
00511               ber_bvarray_free( bd->be_nsuffix );
00512               if ( !BER_BVISNULL( &bd->be_rootdn ) ) {
00513                      free( bd->be_rootdn.bv_val );
00514               }
00515               if ( !BER_BVISNULL( &bd->be_rootndn ) ) {
00516                      free( bd->be_rootndn.bv_val );
00517               }
00518               if ( !BER_BVISNULL( &bd->be_rootpw ) ) {
00519                      free( bd->be_rootpw.bv_val );
00520               }
00521               acl_destroy( bd->be_acl );
00522               frontendDB = NULL;
00523        }
00524 
00525        return 0;
00526 }
00527 
00528 BackendInfo* backend_info(const char *type)
00529 {
00530        BackendInfo *bi;
00531 
00532        /* search for the backend type */
00533        LDAP_STAILQ_FOREACH(bi,&backendInfo,bi_next) {
00534               if( strcasecmp(bi->bi_type, type) == 0 ) {
00535                      return bi;
00536               }
00537        }
00538 
00539        return NULL;
00540 }
00541 
00542 void
00543 backend_db_insert(
00544        BackendDB *be,
00545        int idx
00546 )
00547 {
00548        /* If idx < 0, just add to end of list */
00549        if ( idx < 0 ) {
00550               LDAP_STAILQ_INSERT_TAIL(&backendDB, be, be_next);
00551        } else if ( idx == 0 ) {
00552               LDAP_STAILQ_INSERT_HEAD(&backendDB, be, be_next);
00553        } else {
00554               int i;
00555               BackendDB *b2;
00556 
00557               b2 = LDAP_STAILQ_FIRST(&backendDB);
00558               idx--;
00559               for (i=0; i<idx; i++) {
00560                      b2 = LDAP_STAILQ_NEXT(b2, be_next);
00561               }
00562               LDAP_STAILQ_INSERT_AFTER(&backendDB, b2, be, be_next);
00563        }
00564 }
00565 
00566 void
00567 backend_db_move(
00568        BackendDB *be,
00569        int idx
00570 )
00571 {
00572        LDAP_STAILQ_REMOVE(&backendDB, be, BackendDB, be_next);
00573        backend_db_insert(be, idx);
00574 }
00575 
00576 BackendDB *
00577 backend_db_init(
00578     const char       *type,
00579        BackendDB *b0,
00580        int idx,
00581        ConfigReply *cr)
00582 {
00583        BackendInfo *bi = backend_info(type);
00584        BackendDB *be = b0;
00585        int    rc = 0;
00586 
00587        if( bi == NULL ) {
00588               fprintf( stderr, "Unrecognized database type (%s)\n", type );
00589               return NULL;
00590        }
00591 
00592        /* If be is provided, treat it as private. Otherwise allocate
00593         * one and add it to the global list.
00594         */
00595        if ( !be ) {
00596               be = ch_calloc( 1, sizeof(Backend) );
00597               /* Just append */
00598               if ( idx >= nbackends )
00599                      idx = -1;
00600               nbackends++;
00601               backend_db_insert( be, idx );
00602        }
00603 
00604        be->bd_info = bi;
00605        be->bd_self = be;
00606 
00607        be->be_def_limit = frontendDB->be_def_limit;
00608        be->be_dfltaccess = frontendDB->be_dfltaccess;
00609 
00610        be->be_restrictops = frontendDB->be_restrictops;
00611        be->be_requires = frontendDB->be_requires;
00612        be->be_ssf_set = frontendDB->be_ssf_set;
00613 
00614        ldap_pvt_thread_mutex_init( &be->be_pcl_mutex );
00615 
00616        /* assign a default depth limit for alias deref */
00617        be->be_max_deref_depth = SLAPD_DEFAULT_MAXDEREFDEPTH; 
00618 
00619        if ( bi->bi_db_init ) {
00620               rc = bi->bi_db_init( be, cr );
00621        }
00622 
00623        if ( rc != 0 ) {
00624               fprintf( stderr, "database init failed (%s)\n", type );
00625               /* If we created and linked this be, remove it and free it */
00626               if ( !b0 ) {
00627                      LDAP_STAILQ_REMOVE(&backendDB, be, BackendDB, be_next);
00628                      ldap_pvt_thread_mutex_destroy( &be->be_pcl_mutex );
00629                      ch_free( be );
00630                      be = NULL;
00631                      nbackends--;
00632               }
00633        } else {
00634               if ( !bi->bi_nDB ) {
00635                      backend_init_controls( bi );
00636               }
00637               bi->bi_nDB++;
00638        }
00639        return( be );
00640 }
00641 
00642 void
00643 be_db_close( void )
00644 {
00645        BackendDB *be;
00646 
00647        LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) {
00648               if ( be->bd_info->bi_db_close ) {
00649                      be->bd_info->bi_db_close( be, NULL );
00650               }
00651        }
00652 
00653        if ( frontendDB->bd_info->bi_db_close ) {
00654               frontendDB->bd_info->bi_db_close( frontendDB, NULL );
00655        }
00656 
00657 }
00658 
00659 Backend *
00660 select_backend(
00661        struct berval * dn,
00662        int noSubs )
00663 {
00664        int           j;
00665        ber_len_t     len, dnlen = dn->bv_len;
00666        Backend              *be;
00667 
00668        LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) {
00669               if ( be->be_nsuffix == NULL || SLAP_DBHIDDEN( be )) {
00670                      continue;
00671               }
00672 
00673               for ( j = 0; !BER_BVISNULL( &be->be_nsuffix[j] ); j++ )
00674               {
00675                      if ( ( SLAP_GLUE_SUBORDINATE( be ) ) && noSubs )
00676                      {
00677                             continue;
00678                      }
00679 
00680                      len = be->be_nsuffix[j].bv_len;
00681 
00682                      if ( len > dnlen ) {
00683                             /* suffix is longer than DN */
00684                             continue;
00685                      }
00686                      
00687                      /*
00688                       * input DN is normalized, so the separator check
00689                       * need not look at escaping
00690                       */
00691                      if ( len && len < dnlen &&
00692                             !DN_SEPARATOR( dn->bv_val[(dnlen-len)-1] ))
00693                      {
00694                             continue;
00695                      }
00696 
00697                      if ( strcmp( be->be_nsuffix[j].bv_val,
00698                             &dn->bv_val[dnlen-len] ) == 0 )
00699                      {
00700                             return be;
00701                      }
00702               }
00703        }
00704 
00705        return be;
00706 }
00707 
00708 int
00709 be_issuffix(
00710     Backend *be,
00711     struct berval *bvsuffix )
00712 {
00713        int    i;
00714 
00715        if ( be->be_nsuffix == NULL ) {
00716               return 0;
00717        }
00718 
00719        for ( i = 0; !BER_BVISNULL( &be->be_nsuffix[i] ); i++ ) {
00720               if ( bvmatch( &be->be_nsuffix[i], bvsuffix ) ) {
00721                      return 1;
00722               }
00723        }
00724 
00725        return 0;
00726 }
00727 
00728 int
00729 be_issubordinate(
00730     Backend *be,
00731     struct berval *bvsubordinate )
00732 {
00733        int    i;
00734 
00735        if ( be->be_nsuffix == NULL ) {
00736               return 0;
00737        }
00738 
00739        for ( i = 0; !BER_BVISNULL( &be->be_nsuffix[i] ); i++ ) {
00740               if ( dnIsSuffix( bvsubordinate, &be->be_nsuffix[i] ) ) {
00741                      return 1;
00742               }
00743        }
00744 
00745        return 0;
00746 }
00747 
00748 int
00749 be_isroot_dn( Backend *be, struct berval *ndn )
00750 {
00751        if ( BER_BVISEMPTY( ndn ) || BER_BVISEMPTY( &be->be_rootndn ) ) {
00752               return 0;
00753        }
00754 
00755        return dn_match( &be->be_rootndn, ndn );
00756 }
00757 
00758 int
00759 be_slurp_update( Operation *op )
00760 {
00761        return ( SLAP_SLURP_SHADOW( op->o_bd ) &&
00762               be_isupdate_dn( op->o_bd, &op->o_ndn ) );
00763 }
00764 
00765 int
00766 be_shadow_update( Operation *op )
00767 {
00768        /* This assumes that all internal ops (connid <= -1000) on a syncrepl
00769         * database are syncrepl operations.
00770         */
00771        return ( ( SLAP_SYNC_SHADOW( op->o_bd ) && SLAPD_SYNC_IS_SYNCCONN( op->o_connid ) ) ||
00772               ( SLAP_SHADOW( op->o_bd ) && be_isupdate_dn( op->o_bd, &op->o_ndn ) ) );
00773 }
00774 
00775 int
00776 be_isupdate_dn( Backend *be, struct berval *ndn )
00777 {
00778        if ( BER_BVISEMPTY( ndn ) || BER_BVISEMPTY( &be->be_update_ndn ) ) {
00779               return 0;
00780        }
00781 
00782        return dn_match( &be->be_update_ndn, ndn );
00783 }
00784 
00785 struct berval *
00786 be_root_dn( Backend *be )
00787 {
00788        return &be->be_rootdn;
00789 }
00790 
00791 int
00792 be_isroot( Operation *op )
00793 {
00794        return be_isroot_dn( op->o_bd, &op->o_ndn );
00795 }
00796 
00797 int
00798 be_isroot_pw( Operation *op )
00799 {
00800        return be_rootdn_bind( op, NULL ) == LDAP_SUCCESS;
00801 }
00802 
00803 /*
00804  * checks if binding as rootdn
00805  *
00806  * return value:
00807  *     SLAP_CB_CONTINUE            if not the rootdn, or if rootpw is null
00808  *     LDAP_SUCCESS                if rootdn & rootpw
00809  *     LDAP_INVALID_CREDENTIALS    if rootdn & !rootpw
00810  *
00811  * if rs != NULL
00812  *     if LDAP_SUCCESS, op->orb_edn is set
00813  *     if LDAP_INVALID_CREDENTIALS, response is sent to client
00814  */
00815 int
00816 be_rootdn_bind( Operation *op, SlapReply *rs )
00817 {
00818        int           rc;
00819 #ifdef SLAPD_SPASSWD
00820        void   *old_authctx = NULL;
00821 #endif
00822 
00823        assert( op->o_tag == LDAP_REQ_BIND );
00824        assert( op->orb_method == LDAP_AUTH_SIMPLE );
00825 
00826        if ( !be_isroot_dn( op->o_bd, &op->o_req_ndn ) ) {
00827               return SLAP_CB_CONTINUE;
00828        }
00829 
00830        if ( BER_BVISNULL( &op->o_bd->be_rootpw ) ) {
00831               /* give the database a chance */
00832               return SLAP_CB_CONTINUE;
00833        }
00834 
00835        if ( BER_BVISEMPTY( &op->o_bd->be_rootpw ) ) {
00836               /* rootdn bind explicitly disallowed */
00837               rc = LDAP_INVALID_CREDENTIALS;
00838               if ( rs ) {
00839                      goto send_result;
00840               }
00841 
00842               return rc;
00843        }
00844 
00845 #ifdef SLAPD_SPASSWD
00846        ldap_pvt_thread_pool_setkey( op->o_threadctx, (void *)slap_sasl_bind,
00847               op->o_conn->c_sasl_authctx, 0, &old_authctx, NULL );
00848 #endif
00849 
00850        rc = lutil_passwd( &op->o_bd->be_rootpw, &op->orb_cred, NULL, NULL );
00851 
00852 #ifdef SLAPD_SPASSWD
00853        ldap_pvt_thread_pool_setkey( op->o_threadctx, (void *)slap_sasl_bind,
00854               old_authctx, 0, NULL, NULL );
00855 #endif
00856 
00857        rc = ( rc == 0 ? LDAP_SUCCESS : LDAP_INVALID_CREDENTIALS );
00858        if ( rs ) {
00859 send_result:;
00860               rs->sr_err = rc;
00861 
00862               Debug( LDAP_DEBUG_TRACE, "%s: rootdn=\"%s\" bind%s\n", 
00863                      op->o_log_prefix, op->o_bd->be_rootdn.bv_val,
00864                      rc == LDAP_SUCCESS ? " succeeded" : " failed" );
00865 
00866               if ( rc == LDAP_SUCCESS ) {
00867                      /* Set to the pretty rootdn */
00868                      ber_dupbv( &op->orb_edn, &op->o_bd->be_rootdn );
00869 
00870               } else {
00871                      send_ldap_result( op, rs );
00872               }
00873        }
00874 
00875        return rc;
00876 }
00877 
00878 int
00879 be_entry_release_rw(
00880        Operation *op,
00881        Entry *e,
00882        int rw )
00883 {
00884        if ( op->o_bd->be_release ) {
00885               /* free and release entry from backend */
00886               return op->o_bd->be_release( op, e, rw );
00887        } else {
00888               /* free entry */
00889               entry_free( e );
00890               return 0;
00891        }
00892 }
00893 
00894 int
00895 backend_unbind( Operation *op, SlapReply *rs )
00896 {
00897        BackendDB *be;
00898 
00899        LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) {
00900               if ( be->be_unbind ) {
00901                      op->o_bd = be;
00902                      be->be_unbind( op, rs );
00903               }
00904        }
00905 
00906        return 0;
00907 }
00908 
00909 int
00910 backend_connection_init(
00911        Connection   *conn )
00912 {
00913        BackendDB *be;
00914 
00915        LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) {
00916               if ( be->be_connection_init ) {
00917                      be->be_connection_init( be, conn );
00918               }
00919        }
00920 
00921        return 0;
00922 }
00923 
00924 int
00925 backend_connection_destroy(
00926        Connection   *conn )
00927 {
00928        BackendDB *be;
00929 
00930        LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) {
00931               if ( be->be_connection_destroy ) {
00932                      be->be_connection_destroy( be, conn);
00933               }
00934        }
00935 
00936        return 0;
00937 }
00938 
00939 int
00940 backend_check_controls(
00941        Operation *op,
00942        SlapReply *rs )
00943 {
00944        LDAPControl **ctrls = op->o_ctrls;
00945        rs->sr_err = LDAP_SUCCESS;
00946 
00947        if( ctrls ) {
00948               for( ; *ctrls != NULL ; ctrls++ ) {
00949                      int cid;
00950 
00951                      switch ( slap_global_control( op, (*ctrls)->ldctl_oid, &cid ) ) {
00952                      case LDAP_CONTROL_NOT_FOUND:
00953                             /* unrecognized control */ 
00954                             if ( (*ctrls)->ldctl_iscritical ) {
00955                                    /* should not be reachable */ 
00956                                    Debug( LDAP_DEBUG_ANY, "backend_check_controls: "
00957                                           "unrecognized critical control: %s\n",
00958                                           (*ctrls)->ldctl_oid, 0, 0 );
00959                                    assert( 0 );
00960                             } else {
00961                                    Debug( LDAP_DEBUG_TRACE, "backend_check_controls: "
00962                                           "unrecognized non-critical control: %s\n",
00963                                           (*ctrls)->ldctl_oid, 0, 0 );
00964                             }
00965                             break;
00966 
00967                      case LDAP_COMPARE_FALSE:
00968                             if ( !op->o_bd->be_ctrls[cid] && (*ctrls)->ldctl_iscritical ) {
00969 #ifdef SLAP_CONTROL_X_WHATFAILED
00970                                    if ( get_whatFailed( op ) ) {
00971                                           char *oids[ 2 ];
00972                                           oids[ 0 ] = (*ctrls)->ldctl_oid;
00973                                           oids[ 1 ] = NULL;
00974                                           slap_ctrl_whatFailed_add( op, rs, oids );
00975                                    }
00976 #endif
00977                                    /* RFC 4511 allows unavailableCriticalExtension to be
00978                                     * returned when the server is unwilling to perform
00979                                     * an operation extended by a recognized critical
00980                                     * control.
00981                                     */
00982                                    rs->sr_text = "critical control unavailable in context";
00983                                    rs->sr_err = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
00984                                    goto done;
00985                             }
00986                             break;
00987 
00988                      case LDAP_COMPARE_TRUE:
00989                             break;
00990 
00991                      default:
00992                             /* unreachable */
00993                             Debug( LDAP_DEBUG_ANY,
00994                                    "backend_check_controls: unable to check control: %s\n",
00995                                    (*ctrls)->ldctl_oid, 0, 0 );
00996                             assert( 0 );
00997 
00998                             rs->sr_text = "unable to check control";
00999                             rs->sr_err = LDAP_OTHER;
01000                             goto done;
01001                      }
01002               }
01003        }
01004 
01005 #if 0 /* temporarily removed */
01006        /* check should be generalized */
01007        if( get_relax(op) && !be_isroot(op)) {
01008               rs->sr_text = "requires manager authorization";
01009               rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
01010        }
01011 #endif
01012 
01013 done:;
01014        return rs->sr_err;
01015 }
01016 
01017 int
01018 backend_check_restrictions(
01019        Operation *op,
01020        SlapReply *rs,
01021        struct berval *opdata )
01022 {
01023        slap_mask_t restrictops;
01024        slap_mask_t requires;
01025        slap_mask_t opflag;
01026        slap_mask_t exopflag = 0;
01027        slap_ssf_set_t ssfs, *ssf;
01028        int updateop = 0;
01029        int starttls = 0;
01030        int session = 0;
01031 
01032        restrictops = frontendDB->be_restrictops;
01033        requires = frontendDB->be_requires;
01034        ssfs = frontendDB->be_ssf_set;
01035        ssf = &ssfs;
01036 
01037        if ( op->o_bd ) {
01038               slap_ssf_t *fssf, *bssf;
01039               int    rc = SLAP_CB_CONTINUE, i;
01040 
01041               if ( op->o_bd->be_chk_controls ) {
01042                      rc = ( *op->o_bd->be_chk_controls )( op, rs );
01043               }
01044 
01045               if ( rc == SLAP_CB_CONTINUE ) {
01046                      rc = backend_check_controls( op, rs );
01047               }
01048 
01049               if ( rc != LDAP_SUCCESS ) {
01050                      return rs->sr_err;
01051               }
01052 
01053               restrictops |= op->o_bd->be_restrictops;
01054               requires |= op->o_bd->be_requires;
01055               bssf = &op->o_bd->be_ssf_set.sss_ssf;
01056               fssf = &ssfs.sss_ssf;
01057               for ( i=0; i < (int)(sizeof(ssfs)/sizeof(slap_ssf_t)); i++ ) {
01058                      if ( bssf[i] ) fssf[i] = bssf[i];
01059               }
01060        }
01061 
01062        switch( op->o_tag ) {
01063        case LDAP_REQ_ADD:
01064               opflag = SLAP_RESTRICT_OP_ADD;
01065               updateop++;
01066               break;
01067        case LDAP_REQ_BIND:
01068               opflag = SLAP_RESTRICT_OP_BIND;
01069               session++;
01070               break;
01071        case LDAP_REQ_COMPARE:
01072               opflag = SLAP_RESTRICT_OP_COMPARE;
01073               break;
01074        case LDAP_REQ_DELETE:
01075               updateop++;
01076               opflag = SLAP_RESTRICT_OP_DELETE;
01077               break;
01078        case LDAP_REQ_EXTENDED:
01079               opflag = SLAP_RESTRICT_OP_EXTENDED;
01080 
01081               if( !opdata ) {
01082                      /* treat unspecified as a modify */
01083                      opflag = SLAP_RESTRICT_OP_MODIFY;
01084                      updateop++;
01085                      break;
01086               }
01087 
01088               if( bvmatch( opdata, &slap_EXOP_START_TLS ) ) {
01089                      session++;
01090                      starttls++;
01091                      exopflag = SLAP_RESTRICT_EXOP_START_TLS;
01092                      break;
01093               }
01094 
01095               if( bvmatch( opdata, &slap_EXOP_WHOAMI ) ) {
01096                      exopflag = SLAP_RESTRICT_EXOP_WHOAMI;
01097                      break;
01098               }
01099 
01100               if ( bvmatch( opdata, &slap_EXOP_CANCEL ) ) {
01101                      exopflag = SLAP_RESTRICT_EXOP_CANCEL;
01102                      break;
01103               }
01104 
01105               if ( bvmatch( opdata, &slap_EXOP_MODIFY_PASSWD ) ) {
01106                      exopflag = SLAP_RESTRICT_EXOP_MODIFY_PASSWD;
01107                      updateop++;
01108                      break;
01109               }
01110 
01111               /* treat everything else as a modify */
01112               opflag = SLAP_RESTRICT_OP_MODIFY;
01113               updateop++;
01114               break;
01115 
01116        case LDAP_REQ_MODIFY:
01117               updateop++;
01118               opflag = SLAP_RESTRICT_OP_MODIFY;
01119               break;
01120        case LDAP_REQ_RENAME:
01121               updateop++;
01122               opflag = SLAP_RESTRICT_OP_RENAME;
01123               break;
01124        case LDAP_REQ_SEARCH:
01125               opflag = SLAP_RESTRICT_OP_SEARCH;
01126               break;
01127        case LDAP_REQ_UNBIND:
01128               session++;
01129               opflag = 0;
01130               break;
01131        default:
01132               rs->sr_text = "restrict operations internal error";
01133               rs->sr_err = LDAP_OTHER;
01134               return rs->sr_err;
01135        }
01136 
01137        if ( !starttls ) {
01138               /* these checks don't apply to StartTLS */
01139 
01140               rs->sr_err = LDAP_CONFIDENTIALITY_REQUIRED;
01141               if( op->o_transport_ssf < ssf->sss_transport ) {
01142                      rs->sr_text = op->o_transport_ssf
01143                             ? "stronger transport confidentiality required"
01144                             : "transport confidentiality required";
01145                      return rs->sr_err;
01146               }
01147 
01148               if( op->o_tls_ssf < ssf->sss_tls ) {
01149                      rs->sr_text = op->o_tls_ssf
01150                             ? "stronger TLS confidentiality required"
01151                             : "TLS confidentiality required";
01152                      return rs->sr_err;
01153               }
01154 
01155 
01156               if( op->o_tag == LDAP_REQ_BIND && opdata == NULL ) {
01157                      /* simple bind specific check */
01158                      if( op->o_ssf < ssf->sss_simple_bind ) {
01159                             rs->sr_text = op->o_ssf
01160                                    ? "stronger confidentiality required"
01161                                    : "confidentiality required";
01162                             return rs->sr_err;
01163                      }
01164               }
01165 
01166               if( op->o_tag != LDAP_REQ_BIND || opdata == NULL ) {
01167                      /* these checks don't apply to SASL bind */
01168 
01169                      if( op->o_sasl_ssf < ssf->sss_sasl ) {
01170                             rs->sr_text = op->o_sasl_ssf
01171                                    ? "stronger SASL confidentiality required"
01172                                    : "SASL confidentiality required";
01173                             return rs->sr_err;
01174                      }
01175 
01176                      if( op->o_ssf < ssf->sss_ssf ) {
01177                             rs->sr_text = op->o_ssf
01178                                    ? "stronger confidentiality required"
01179                                    : "confidentiality required";
01180                             return rs->sr_err;
01181                      }
01182               }
01183 
01184               if( updateop ) {
01185                      if( op->o_transport_ssf < ssf->sss_update_transport ) {
01186                             rs->sr_text = op->o_transport_ssf
01187                                    ? "stronger transport confidentiality required for update"
01188                                    : "transport confidentiality required for update";
01189                             return rs->sr_err;
01190                      }
01191 
01192                      if( op->o_tls_ssf < ssf->sss_update_tls ) {
01193                             rs->sr_text = op->o_tls_ssf
01194                                    ? "stronger TLS confidentiality required for update"
01195                                    : "TLS confidentiality required for update";
01196                             return rs->sr_err;
01197                      }
01198 
01199                      if( op->o_sasl_ssf < ssf->sss_update_sasl ) {
01200                             rs->sr_text = op->o_sasl_ssf
01201                                    ? "stronger SASL confidentiality required for update"
01202                                    : "SASL confidentiality required for update";
01203                             return rs->sr_err;
01204                      }
01205 
01206                      if( op->o_ssf < ssf->sss_update_ssf ) {
01207                             rs->sr_text = op->o_ssf
01208                                    ? "stronger confidentiality required for update"
01209                                    : "confidentiality required for update";
01210                             return rs->sr_err;
01211                      }
01212 
01213                      if( !( global_allows & SLAP_ALLOW_UPDATE_ANON ) &&
01214                             BER_BVISEMPTY( &op->o_ndn ) )
01215                      {
01216                             rs->sr_text = "modifications require authentication";
01217                             rs->sr_err = LDAP_STRONG_AUTH_REQUIRED;
01218                             return rs->sr_err;
01219                      }
01220 
01221 #ifdef SLAP_X_LISTENER_MOD
01222                      if ( op->o_conn->c_listener &&
01223                             ! ( op->o_conn->c_listener->sl_perms & ( !BER_BVISEMPTY( &op->o_ndn )
01224                                    ? (S_IWUSR|S_IWOTH) : S_IWOTH ) ) )
01225                      {
01226                             /* no "w" mode means readonly */
01227                             rs->sr_text = "modifications not allowed on this listener";
01228                             rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
01229                             return rs->sr_err;
01230                      }
01231 #endif /* SLAP_X_LISTENER_MOD */
01232               }
01233        }
01234 
01235        if ( !session ) {
01236               /* these checks don't apply to Bind, StartTLS, or Unbind */
01237 
01238               if( requires & SLAP_REQUIRE_STRONG ) {
01239                      /* should check mechanism */
01240                      if( ( op->o_transport_ssf < ssf->sss_transport
01241                             && op->o_authtype == LDAP_AUTH_SIMPLE )
01242                             || BER_BVISEMPTY( &op->o_dn ) )
01243                      {
01244                             rs->sr_text = "strong(er) authentication required";
01245                             rs->sr_err = LDAP_STRONG_AUTH_REQUIRED;
01246                             return rs->sr_err;
01247                      }
01248               }
01249 
01250               if( requires & SLAP_REQUIRE_SASL ) {
01251                      if( op->o_authtype != LDAP_AUTH_SASL || BER_BVISEMPTY( &op->o_dn ) ) {
01252                             rs->sr_text = "SASL authentication required";
01253                             rs->sr_err = LDAP_STRONG_AUTH_REQUIRED;
01254                             return rs->sr_err;
01255                      }
01256               }
01257                      
01258               if( requires & SLAP_REQUIRE_AUTHC ) {
01259                      if( BER_BVISEMPTY( &op->o_dn ) ) {
01260                             rs->sr_text = "authentication required";
01261                             rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
01262                             return rs->sr_err;
01263                      }
01264               }
01265 
01266               if( requires & SLAP_REQUIRE_BIND ) {
01267                      int version;
01268                      ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
01269                      version = op->o_conn->c_protocol;
01270                      ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
01271 
01272                      if( !version ) {
01273                             /* no bind has occurred */
01274                             rs->sr_text = "BIND required";
01275                             rs->sr_err = LDAP_OPERATIONS_ERROR;
01276                             return rs->sr_err;
01277                      }
01278               }
01279 
01280               if( requires & SLAP_REQUIRE_LDAP_V3 ) {
01281                      if( op->o_protocol < LDAP_VERSION3 ) {
01282                             /* no bind has occurred */
01283                             rs->sr_text = "operation restricted to LDAPv3 clients";
01284                             rs->sr_err = LDAP_OPERATIONS_ERROR;
01285                             return rs->sr_err;
01286                      }
01287               }
01288 
01289 #ifdef SLAP_X_LISTENER_MOD
01290               if ( !starttls && BER_BVISEMPTY( &op->o_dn ) ) {
01291                      if ( op->o_conn->c_listener &&
01292                             !( op->o_conn->c_listener->sl_perms & S_IXOTH ))
01293               {
01294                             /* no "x" mode means bind required */
01295                             rs->sr_text = "bind required on this listener";
01296                             rs->sr_err = LDAP_STRONG_AUTH_REQUIRED;
01297                             return rs->sr_err;
01298                      }
01299               }
01300 
01301               if ( !starttls && !updateop ) {
01302                      if ( op->o_conn->c_listener &&
01303                             !( op->o_conn->c_listener->sl_perms &
01304                                    ( !BER_BVISEMPTY( &op->o_dn )
01305                                           ? (S_IRUSR|S_IROTH) : S_IROTH )))
01306                      {
01307                             /* no "r" mode means no read */
01308                             rs->sr_text = "read not allowed on this listener";
01309                             rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
01310                             return rs->sr_err;
01311                      }
01312               }
01313 #endif /* SLAP_X_LISTENER_MOD */
01314 
01315        }
01316 
01317        if( ( restrictops & opflag )
01318                      || ( exopflag && ( restrictops & exopflag ) )
01319                      || (( restrictops & SLAP_RESTRICT_READONLY ) && updateop )) {
01320               if( ( restrictops & SLAP_RESTRICT_OP_MASK) == SLAP_RESTRICT_OP_READS ) {
01321                      rs->sr_text = "read operations restricted";
01322               } else if ( restrictops & exopflag ) {
01323                      rs->sr_text = "extended operation restricted";
01324               } else {
01325                      rs->sr_text = "operation restricted";
01326               }
01327               rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
01328               return rs->sr_err;
01329        }
01330 
01331        rs->sr_err = LDAP_SUCCESS;
01332        return rs->sr_err;
01333 }
01334 
01335 int backend_check_referrals( Operation *op, SlapReply *rs )
01336 {
01337        rs->sr_err = LDAP_SUCCESS;
01338 
01339        if( op->o_bd->be_chk_referrals ) {
01340               rs->sr_err = op->o_bd->be_chk_referrals( op, rs );
01341 
01342               if( rs->sr_err != LDAP_SUCCESS && rs->sr_err != LDAP_REFERRAL ) {
01343                      send_ldap_result( op, rs );
01344               }
01345        }
01346 
01347        return rs->sr_err;
01348 }
01349 
01350 int
01351 be_entry_get_rw(
01352        Operation *op,
01353        struct berval *ndn,
01354        ObjectClass *oc,
01355        AttributeDescription *at,
01356        int rw,
01357        Entry **e )
01358 {
01359        *e = NULL;
01360 
01361        if ( op->o_bd == NULL ) {
01362               return LDAP_NO_SUCH_OBJECT;
01363        }
01364 
01365        if ( op->o_bd->be_fetch ) {
01366               return op->o_bd->be_fetch( op, ndn, oc, at, rw, e );
01367        }
01368 
01369        return LDAP_UNWILLING_TO_PERFORM;
01370 }
01371 
01372 int 
01373 fe_acl_group(
01374        Operation *op,
01375        Entry  *target,
01376        struct berval *gr_ndn,
01377        struct berval *op_ndn,
01378        ObjectClass *group_oc,
01379        AttributeDescription *group_at )
01380 {
01381        Entry *e;
01382        void *o_priv = op->o_private, *e_priv = NULL;
01383        Attribute *a;
01384        int rc;
01385        GroupAssertion *g;
01386        Backend *be = op->o_bd;
01387        OpExtra              *oex;
01388 
01389        LDAP_SLIST_FOREACH(oex, &op->o_extra, oe_next) {
01390               if ( oex->oe_key == (void *)backend_group )
01391                      break;
01392        }
01393 
01394        if ( oex && ((OpExtraDB *)oex)->oe_db )
01395               op->o_bd = ((OpExtraDB *)oex)->oe_db;
01396 
01397        if ( !op->o_bd || !SLAP_DBHIDDEN( op->o_bd ))
01398               op->o_bd = select_backend( gr_ndn, 0 );
01399 
01400        for ( g = op->o_groups; g; g = g->ga_next ) {
01401               if ( g->ga_be != op->o_bd || g->ga_oc != group_oc ||
01402                      g->ga_at != group_at || g->ga_len != gr_ndn->bv_len )
01403               {
01404                      continue;
01405               }
01406               if ( strcmp( g->ga_ndn, gr_ndn->bv_val ) == 0 ) {
01407                      break;
01408               }
01409        }
01410 
01411        if ( g ) {
01412               rc = g->ga_res;
01413               goto done;
01414        }
01415 
01416        if ( target && dn_match( &target->e_nname, gr_ndn ) ) {
01417               e = target;
01418               rc = 0;
01419 
01420        } else {
01421               op->o_private = NULL;
01422               rc = be_entry_get_rw( op, gr_ndn, group_oc, group_at, 0, &e );
01423               e_priv = op->o_private;
01424               op->o_private = o_priv;
01425        }
01426 
01427        if ( e ) {
01428               a = attr_find( e->e_attrs, group_at );
01429               if ( a ) {
01430                      /* If the attribute is a subtype of labeledURI,
01431                       * treat this as a dynamic group ala groupOfURLs
01432                       */
01433                      if ( is_at_subtype( group_at->ad_type,
01434                             slap_schema.si_ad_labeledURI->ad_type ) )
01435                      {
01436                             int i;
01437                             LDAPURLDesc *ludp;
01438                             struct berval bv, nbase;
01439                             Filter *filter;
01440                             Entry *user = NULL;
01441                             void *user_priv = NULL;
01442                             Backend *b2 = op->o_bd;
01443 
01444                             if ( target && dn_match( &target->e_nname, op_ndn ) ) {
01445                                    user = target;
01446                             }
01447                             
01448                             rc = LDAP_COMPARE_FALSE;
01449                             for ( i = 0; !BER_BVISNULL( &a->a_vals[i] ); i++ ) {
01450                                    if ( ldap_url_parse( a->a_vals[i].bv_val, &ludp ) !=
01451                                           LDAP_URL_SUCCESS )
01452                                    {
01453                                           continue;
01454                                    }
01455 
01456                                    BER_BVZERO( &nbase );
01457 
01458                                    /* host, attrs and extensions parts must be empty */
01459                                    if ( ( ludp->lud_host && *ludp->lud_host )
01460                                           || ludp->lud_attrs
01461                                           || ludp->lud_exts )
01462                                    {
01463                                           goto loopit;
01464                                    }
01465 
01466                                    ber_str2bv( ludp->lud_dn, 0, 0, &bv );
01467                                    if ( dnNormalize( 0, NULL, NULL, &bv, &nbase,
01468                                           op->o_tmpmemctx ) != LDAP_SUCCESS )
01469                                    {
01470                                           goto loopit;
01471                                    }
01472 
01473                                    switch ( ludp->lud_scope ) {
01474                                    case LDAP_SCOPE_BASE:
01475                                           if ( !dn_match( &nbase, op_ndn ) ) {
01476                                                  goto loopit;
01477                                           }
01478                                           break;
01479                                    case LDAP_SCOPE_ONELEVEL:
01480                                           dnParent( op_ndn, &bv );
01481                                           if ( !dn_match( &nbase, &bv ) ) {
01482                                                  goto loopit;
01483                                           }
01484                                           break;
01485                                    case LDAP_SCOPE_SUBTREE:
01486                                           if ( !dnIsSuffix( op_ndn, &nbase ) ) {
01487                                                  goto loopit;
01488                                           }
01489                                           break;
01490                                    case LDAP_SCOPE_SUBORDINATE:
01491                                           if ( dn_match( &nbase, op_ndn ) ||
01492                                                  !dnIsSuffix( op_ndn, &nbase ) )
01493                                           {
01494                                                  goto loopit;
01495                                           }
01496                                    }
01497 
01498                                    /* NOTE: this could be NULL
01499                                     * if no filter is provided,
01500                                     * or if filter parsing fails.
01501                                     * In the latter case,
01502                                     * we should give up. */
01503                                    if ( ludp->lud_filter != NULL && ludp->lud_filter != '\0') {
01504                                           filter = str2filter_x( op, ludp->lud_filter );
01505                                           if ( filter == NULL ) {
01506                                                  /* give up... */
01507                                                  rc = LDAP_OTHER;
01508                                                  goto loopit;
01509                                           }
01510 
01511                                           /* only get user if required
01512                                            * and not available yet */
01513                                           if ( user == NULL ) {       
01514                                                  int rc2;
01515 
01516                                                  op->o_bd = select_backend( op_ndn, 0 );
01517                                                  op->o_private = NULL;
01518                                                  rc2 = be_entry_get_rw( op, op_ndn, NULL, NULL, 0, &user );
01519                                                  user_priv = op->o_private;
01520                                                  op->o_private = o_priv;
01521                                                  if ( rc2 != 0 ) {
01522                                                         /* give up... */
01523                                                         rc = LDAP_OTHER;
01524                                                         goto loopit;
01525                                                  }
01526                                           }
01527 
01528                                           if ( test_filter( NULL, user, filter ) ==
01529                                                  LDAP_COMPARE_TRUE )
01530                                           {
01531                                                  rc = 0;
01532                                           }
01533                                           filter_free_x( op, filter, 1 );
01534                                    }
01535 loopit:
01536                                    ldap_free_urldesc( ludp );
01537                                    if ( !BER_BVISNULL( &nbase ) ) {
01538                                           op->o_tmpfree( nbase.bv_val, op->o_tmpmemctx );
01539                                    }
01540                                    if ( rc != LDAP_COMPARE_FALSE ) {
01541                                           break;
01542                                    }
01543                             }
01544 
01545                             if ( user != NULL && user != target ) {
01546                                    op->o_private = user_priv;
01547                                    be_entry_release_r( op, user );
01548                                    op->o_private = o_priv;
01549                             }
01550                             op->o_bd = b2;
01551 
01552                      } else {
01553                             rc = attr_valfind( a,
01554                                    SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
01555                                    SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
01556                                    op_ndn, NULL, op->o_tmpmemctx );
01557                             if ( rc == LDAP_NO_SUCH_ATTRIBUTE ) {
01558                                    rc = LDAP_COMPARE_FALSE;
01559                             }
01560                      }
01561 
01562               } else {
01563                      rc = LDAP_NO_SUCH_ATTRIBUTE;
01564               }
01565 
01566               if ( e != target ) {
01567                      op->o_private = e_priv;
01568                      be_entry_release_r( op, e );
01569                      op->o_private = o_priv;
01570               }
01571 
01572        } else {
01573               rc = LDAP_NO_SUCH_OBJECT;
01574        }
01575 
01576        if ( op->o_tag != LDAP_REQ_BIND && !op->o_do_not_cache ) {
01577               g = op->o_tmpalloc( sizeof( GroupAssertion ) + gr_ndn->bv_len,
01578                      op->o_tmpmemctx );
01579               g->ga_be = op->o_bd;
01580               g->ga_oc = group_oc;
01581               g->ga_at = group_at;
01582               g->ga_res = rc;
01583               g->ga_len = gr_ndn->bv_len;
01584               strcpy( g->ga_ndn, gr_ndn->bv_val );
01585               g->ga_next = op->o_groups;
01586               op->o_groups = g;
01587        }
01588 
01589 done:
01590        op->o_bd = be;
01591        return rc;
01592 }
01593 
01594 int 
01595 backend_group(
01596        Operation *op,
01597        Entry  *target,
01598        struct berval *gr_ndn,
01599        struct berval *op_ndn,
01600        ObjectClass *group_oc,
01601        AttributeDescription *group_at )
01602 {
01603        int                  rc;
01604        BackendDB *be_orig;
01605        OpExtraDB     oex;
01606 
01607        if ( op->o_abandon ) {
01608               return SLAPD_ABANDON;
01609        }
01610 
01611        oex.oe_db = op->o_bd;
01612        oex.oe.oe_key = (void *)backend_group;
01613        LDAP_SLIST_INSERT_HEAD(&op->o_extra, &oex.oe, oe_next);
01614 
01615        be_orig = op->o_bd;
01616        op->o_bd = frontendDB;
01617        rc = frontendDB->be_group( op, target, gr_ndn,
01618               op_ndn, group_oc, group_at );
01619        op->o_bd = be_orig;
01620        LDAP_SLIST_REMOVE(&op->o_extra, &oex.oe, OpExtra, oe_next);
01621 
01622        return rc;
01623 }
01624 
01625 int 
01626 fe_acl_attribute(
01627        Operation *op,
01628        Entry  *target,
01629        struct berval *edn,
01630        AttributeDescription *entry_at,
01631        BerVarray *vals,
01632        slap_access_t access )
01633 {
01634        Entry                *e = NULL;
01635        void                 *o_priv = op->o_private, *e_priv = NULL;
01636        Attribute            *a = NULL;
01637        int                  freeattr = 0, i, j, rc = LDAP_SUCCESS;
01638        AccessControlState   acl_state = ACL_STATE_INIT;
01639        Backend                     *be = op->o_bd;
01640        OpExtra              *oex;
01641 
01642        LDAP_SLIST_FOREACH(oex, &op->o_extra, oe_next) {
01643               if ( oex->oe_key == (void *)backend_attribute )
01644                      break;
01645        }
01646 
01647        if ( oex && ((OpExtraDB *)oex)->oe_db )
01648               op->o_bd = ((OpExtraDB *)oex)->oe_db;
01649 
01650        if ( !op->o_bd || !SLAP_DBHIDDEN( op->o_bd ))
01651               op->o_bd = select_backend( edn, 0 );
01652 
01653        if ( target && dn_match( &target->e_nname, edn ) ) {
01654               e = target;
01655 
01656        } else {
01657               op->o_private = NULL;
01658               rc = be_entry_get_rw( op, edn, NULL, entry_at, 0, &e );
01659               e_priv = op->o_private;
01660               op->o_private = o_priv;
01661        } 
01662 
01663        if ( e ) {
01664               if ( entry_at == slap_schema.si_ad_entry || entry_at == slap_schema.si_ad_children ) {
01665                      assert( vals == NULL );
01666 
01667                      rc = LDAP_SUCCESS;
01668                      if ( op->o_conn && access > ACL_NONE &&
01669                             access_allowed( op, e, entry_at, NULL,
01670                                           access, &acl_state ) == 0 )
01671                      {
01672                             rc = LDAP_INSUFFICIENT_ACCESS;
01673                      }
01674                      goto freeit;
01675               }
01676 
01677               a = attr_find( e->e_attrs, entry_at );
01678               if ( a == NULL ) {
01679                      SlapReply     rs = { REP_SEARCH };
01680                      AttributeName anlist[ 2 ];
01681 
01682                      anlist[ 0 ].an_name = entry_at->ad_cname;
01683                      anlist[ 0 ].an_desc = entry_at;
01684                      BER_BVZERO( &anlist[ 1 ].an_name );
01685                      rs.sr_attrs = anlist;
01686                      
01687                      /* NOTE: backend_operational() is also called
01688                       * when returning results, so it's supposed
01689                       * to do no harm to entries */
01690                      rs.sr_entry = e;
01691                      rc = backend_operational( op, &rs );
01692 
01693                      if ( rc == LDAP_SUCCESS ) {
01694                             if ( rs.sr_operational_attrs ) {
01695                                    freeattr = 1;
01696                                    a = rs.sr_operational_attrs;
01697 
01698                             } else {
01699                                    rc = LDAP_NO_SUCH_ATTRIBUTE;
01700                             }
01701                      }
01702               }
01703 
01704               if ( a ) {
01705                      BerVarray v;
01706 
01707                      if ( op->o_conn && access > ACL_NONE &&
01708                             access_allowed( op, e, entry_at, NULL,
01709                                           access, &acl_state ) == 0 )
01710                      {
01711                             rc = LDAP_INSUFFICIENT_ACCESS;
01712                             goto freeit;
01713                      }
01714 
01715                      i = a->a_numvals;
01716                      v = op->o_tmpalloc( sizeof(struct berval) * ( i + 1 ),
01717                             op->o_tmpmemctx );
01718                      for ( i = 0, j = 0; !BER_BVISNULL( &a->a_vals[i] ); i++ )
01719                      {
01720                             if ( op->o_conn && access > ACL_NONE && 
01721                                    access_allowed( op, e, entry_at,
01722                                                  &a->a_nvals[i],
01723                                                  access,
01724                                                  &acl_state ) == 0 )
01725                             {
01726                                    continue;
01727                             }
01728                             ber_dupbv_x( &v[j], &a->a_nvals[i],
01729                                           op->o_tmpmemctx );
01730                             if ( !BER_BVISNULL( &v[j] ) ) {
01731                                    j++;
01732                             }
01733                      }
01734                      if ( j == 0 ) {
01735                             op->o_tmpfree( v, op->o_tmpmemctx );
01736                             *vals = NULL;
01737                             rc = LDAP_INSUFFICIENT_ACCESS;
01738 
01739                      } else {
01740                             BER_BVZERO( &v[j] );
01741                             *vals = v;
01742                             rc = LDAP_SUCCESS;
01743                      }
01744               }
01745 freeit:              if ( e != target ) {
01746                      op->o_private = e_priv;
01747                      be_entry_release_r( op, e );
01748                      op->o_private = o_priv;
01749               }
01750               if ( freeattr ) {
01751                      attr_free( a );
01752               }
01753        }
01754 
01755        op->o_bd = be;
01756        return rc;
01757 }
01758 
01759 int 
01760 backend_attribute(
01761        Operation *op,
01762        Entry  *target,
01763        struct berval *edn,
01764        AttributeDescription *entry_at,
01765        BerVarray *vals,
01766        slap_access_t access )
01767 {
01768        int                  rc;
01769        BackendDB *be_orig;
01770        OpExtraDB     oex;
01771 
01772        oex.oe_db = op->o_bd;
01773        oex.oe.oe_key = (void *)backend_attribute;
01774        LDAP_SLIST_INSERT_HEAD(&op->o_extra, &oex.oe, oe_next);
01775 
01776        be_orig = op->o_bd;
01777        op->o_bd = frontendDB;
01778        rc = frontendDB->be_attribute( op, target, edn,
01779               entry_at, vals, access );
01780        op->o_bd = be_orig;
01781        LDAP_SLIST_REMOVE(&op->o_extra, &oex.oe, OpExtra, oe_next);
01782 
01783        return rc;
01784 }
01785 
01786 int 
01787 backend_access(
01788        Operation            *op,
01789        Entry                *target,
01790        struct berval        *edn,
01791        AttributeDescription *entry_at,
01792        struct berval        *nval,
01793        slap_access_t        access,
01794        slap_mask_t          *mask )
01795 {
01796        Entry         *e = NULL;
01797        void          *o_priv, *e_priv = NULL;
01798        int           rc = LDAP_INSUFFICIENT_ACCESS;
01799        Backend              *be;
01800 
01801        /* pedantic */
01802        assert( op != NULL );
01803        assert( op->o_conn != NULL );
01804        assert( edn != NULL );
01805        assert( access > ACL_NONE );
01806 
01807        be = op->o_bd;
01808        o_priv = op->o_private;
01809 
01810        if ( !op->o_bd ) {
01811               op->o_bd = select_backend( edn, 0 );
01812        }
01813 
01814        if ( target && dn_match( &target->e_nname, edn ) ) {
01815               e = target;
01816 
01817        } else {
01818               op->o_private = NULL;
01819               rc = be_entry_get_rw( op, edn, NULL, entry_at, 0, &e );
01820               e_priv = op->o_private;
01821               op->o_private = o_priv;
01822        } 
01823 
01824        if ( e ) {
01825               Attribute     *a = NULL;
01826               int           freeattr = 0;
01827 
01828               if ( entry_at == NULL ) {
01829                      entry_at = slap_schema.si_ad_entry;
01830               }
01831 
01832               if ( entry_at == slap_schema.si_ad_entry || entry_at == slap_schema.si_ad_children )
01833               {
01834                      if ( access_allowed_mask( op, e, entry_at,
01835                                    NULL, access, NULL, mask ) == 0 )
01836                      {
01837                             rc = LDAP_INSUFFICIENT_ACCESS;
01838 
01839                      } else {
01840                             rc = LDAP_SUCCESS;
01841                      }
01842 
01843               } else {
01844                      a = attr_find( e->e_attrs, entry_at );
01845                      if ( a == NULL ) {
01846                             SlapReply     rs = { REP_SEARCH };
01847                             AttributeName anlist[ 2 ];
01848 
01849                             anlist[ 0 ].an_name = entry_at->ad_cname;
01850                             anlist[ 0 ].an_desc = entry_at;
01851                             BER_BVZERO( &anlist[ 1 ].an_name );
01852                             rs.sr_attrs = anlist;
01853                      
01854                             rs.sr_attr_flags = slap_attr_flags( rs.sr_attrs );
01855 
01856                             /* NOTE: backend_operational() is also called
01857                              * when returning results, so it's supposed
01858                              * to do no harm to entries */
01859                             rs.sr_entry = e;
01860                             rc = backend_operational( op, &rs );
01861 
01862                             if ( rc == LDAP_SUCCESS ) {
01863                                    if ( rs.sr_operational_attrs ) {
01864                                           freeattr = 1;
01865                                           a = rs.sr_operational_attrs;
01866 
01867                                    } else {
01868                                           rc = LDAP_NO_SUCH_OBJECT;
01869                                    }
01870                             }
01871                      }
01872 
01873                      if ( a ) {
01874                             if ( access_allowed_mask( op, e, entry_at,
01875                                           nval, access, NULL, mask ) == 0 )
01876                             {
01877                                    rc = LDAP_INSUFFICIENT_ACCESS;
01878                                    goto freeit;
01879                             }
01880                             rc = LDAP_SUCCESS;
01881                      }
01882               }
01883 freeit:              if ( e != target ) {
01884                      op->o_private = e_priv;
01885                      be_entry_release_r( op, e );
01886                      op->o_private = o_priv;
01887               }
01888               if ( freeattr ) {
01889                      attr_free( a );
01890               }
01891        }
01892 
01893        op->o_bd = be;
01894        return rc;
01895 }
01896 
01897 int
01898 fe_aux_operational(
01899        Operation *op,
01900        SlapReply *rs )
01901 {
01902        Attribute            **ap;
01903        int                  rc = LDAP_SUCCESS;
01904        BackendDB            *be_orig = op->o_bd;
01905        OpExtra              *oex;
01906 
01907        LDAP_SLIST_FOREACH(oex, &op->o_extra, oe_next) {
01908               if ( oex->oe_key == (void *)backend_operational )
01909                      break;
01910        }
01911 
01912        for ( ap = &rs->sr_operational_attrs; *ap; ap = &(*ap)->a_next )
01913               /* just count them */ ;
01914 
01915        /*
01916         * If operational attributes (allegedly) are required, 
01917         * and the backend supports specific operational attributes, 
01918         * add them to the attribute list
01919         */
01920        if ( !( rs->sr_flags & REP_NO_ENTRYDN )
01921               && ( SLAP_OPATTRS( rs->sr_attr_flags ) || ( rs->sr_attrs &&
01922               ad_inlist( slap_schema.si_ad_entryDN, rs->sr_attrs ) ) ) )
01923        {
01924               *ap = slap_operational_entryDN( rs->sr_entry );
01925               ap = &(*ap)->a_next;
01926        }
01927 
01928        if ( !( rs->sr_flags & REP_NO_SUBSCHEMA)
01929               && ( SLAP_OPATTRS( rs->sr_attr_flags ) || ( rs->sr_attrs &&
01930               ad_inlist( slap_schema.si_ad_subschemaSubentry, rs->sr_attrs ) ) ) )
01931        {
01932               *ap = slap_operational_subschemaSubentry( op->o_bd );
01933               ap = &(*ap)->a_next;
01934        }
01935 
01936        /* Let the overlays have a chance at this */
01937        if ( oex && ((OpExtraDB *)oex)->oe_db )
01938               op->o_bd = ((OpExtraDB *)oex)->oe_db;
01939 
01940        if ( !op->o_bd || !SLAP_DBHIDDEN( op->o_bd ))
01941               op->o_bd = select_backend( &op->o_req_ndn, 0 );
01942 
01943        if ( op->o_bd != NULL && !be_match( op->o_bd, frontendDB ) &&
01944               ( SLAP_OPATTRS( rs->sr_attr_flags ) || rs->sr_attrs ) &&
01945               op->o_bd->be_operational != NULL )
01946        {
01947               rc = op->o_bd->be_operational( op, rs );
01948        }
01949        op->o_bd = be_orig;
01950 
01951        return rc;
01952 }
01953 
01954 int backend_operational( Operation *op, SlapReply *rs )
01955 {
01956        int rc;
01957        BackendDB *be_orig;
01958        OpExtraDB     oex;
01959 
01960        oex.oe_db = op->o_bd;
01961        oex.oe.oe_key = (void *)backend_operational;
01962        LDAP_SLIST_INSERT_HEAD(&op->o_extra, &oex.oe, oe_next);
01963 
01964        /* Moved this into the frontend so global overlays are called */
01965 
01966        be_orig = op->o_bd;
01967        op->o_bd = frontendDB;
01968        rc = frontendDB->be_operational( op, rs );
01969        op->o_bd = be_orig;
01970        LDAP_SLIST_REMOVE(&op->o_extra, &oex.oe, OpExtra, oe_next);
01971 
01972        return rc;
01973 }
01974 
01975 /* helper that calls the bi_tool_entry_first_x() variant with default args;
01976  * use to initialize a backend's bi_tool_entry_first() when appropriate
01977  */
01978 ID
01979 backend_tool_entry_first( BackendDB *be )
01980 {
01981        return be->bd_info->bi_tool_entry_first_x( be,
01982               NULL, LDAP_SCOPE_DEFAULT, NULL );
01983 }