Back to index

openldap  2.4.31
distproc.c
Go to the documentation of this file.
00001 /* distproc.c - implement distributed procedures */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 2005-2012 The OpenLDAP Foundation.
00006  * Portions Copyright 2003 Howard Chu.
00007  * All rights reserved.
00008  *
00009  * Redistribution and use in source and binary forms, with or without
00010  * modification, are permitted only as authorized by the OpenLDAP
00011  * Public License.
00012  *
00013  * A copy of this license is available in the file LICENSE in the
00014  * top-level directory of the distribution or, alternatively, at
00015  * <http://www.OpenLDAP.org/license.html>.
00016  */
00017 /* ACKNOWLEDGEMENTS:
00018  * This work was initially developed by Pierangelo Masarati for inclusion
00019  * in OpenLDAP Software.
00020  * Based on back-ldap and slapo-chain, developed by Howard Chu
00021  */
00022 
00023 #include "portable.h"
00024 
00025 #include <stdio.h>
00026 
00027 #include <ac/string.h>
00028 #include <ac/socket.h>
00029 
00030 #include "slap.h"
00031 
00032 #ifdef SLAP_DISTPROC
00033 
00034 #include "back-ldap.h"
00035 
00036 #include "config.h"
00037 
00038 /*
00039  * From <draft-sermersheim-ldap-distproc>
00040  *
00041 
00042       ContinuationReference ::= SET {
00043          referralURI      [0] SET SIZE (1..MAX) OF URI,
00044          localReference   [2] LDAPDN,
00045          referenceType    [3] ReferenceType,
00046          remainingName    [4] RelativeLDAPDN OPTIONAL,
00047          searchScope      [5] SearchScope OPTIONAL,
00048          searchedSubtrees [6] SearchedSubtrees OPTIONAL,
00049          failedName       [7] LDAPDN OPTIONAL,
00050          ...  }
00051 
00052       ReferenceType ::= ENUMERATED {
00053          superior               (0),
00054          subordinate            (1),
00055          cross                  (2),
00056          nonSpecificSubordinate (3),
00057          supplier               (4),
00058          master                 (5),
00059          immediateSuperior      (6),
00060          self                   (7),
00061          ...  }
00062 
00063       SearchScope ::= ENUMERATED {
00064          baseObject         (0),
00065          singleLevel        (1),
00066          wholeSubtree       (2),
00067          subordinateSubtree (3),
00068          ...  }
00069 
00070    SearchedSubtrees ::= SET OF RelativeLDAPDN
00071 
00072    LDAPDN, RelativeLDAPDN, and LDAPString, are defined in [RFC2251].
00073 
00074  */
00075 
00076 typedef enum ReferenceType_t {
00077        LDAP_DP_RT_UNKNOWN                 = -1,
00078        LDAP_DP_RT_SUPERIOR                = 0,
00079        LDAP_DP_RT_SUBORDINATE                    = 1,
00080        LDAP_DP_RT_CROSS                   = 2,
00081        LDAP_DP_RT_NONSPECIFICSUBORDINATE  = 3,
00082        LDAP_DP_RT_SUPPLIER                = 4,
00083        LDAP_DP_RT_MASTER                  = 5,
00084        LDAP_DP_RT_IMMEDIATESUPERIOR              = 6,
00085        LDAP_DP_RT_SELF                           = 7,
00086        LDAP_DP_RT_LAST
00087 } ReferenceType_t;
00088 
00089 typedef enum SearchScope_t {
00090        LDAP_DP_SS_UNKNOWN                 = -1,
00091        LDAP_DP_SS_BASEOBJECT                     = 0,
00092        LDAP_DP_SS_SINGLELEVEL                    = 1,
00093        LDAP_DP_SS_WHOLESUBTREE                   = 2,
00094        LDAP_DP_SS_SUBORDINATESUBTREE             = 3,
00095        LDAP_DP_SS_LAST
00096 } SearchScope_t;
00097 
00098 typedef struct ContinuationReference_t {
00099        BerVarray            cr_referralURI;
00100        /* ?                 [1] ? */
00101        struct berval        cr_localReference;
00102        ReferenceType_t             cr_referenceType;
00103        struct berval        cr_remainingName;
00104        SearchScope_t        cr_searchScope;
00105        BerVarray            cr_searchedSubtrees;
00106        struct berval        cr_failedName;
00107 } ContinuationReference_t;
00108 #define       CR_INIT              { NULL, BER_BVNULL, LDAP_DP_RT_UNKNOWN, BER_BVNULL, LDAP_DP_SS_UNKNOWN, NULL, BER_BVNULL }
00109 
00110 #ifdef unused
00111 static struct berval bv2rt[] = {
00112        BER_BVC( "superior" ),
00113        BER_BVC( "subordinate" ),
00114        BER_BVC( "cross" ),
00115        BER_BVC( "nonSpecificSubordinate" ),
00116        BER_BVC( "supplier" ),
00117        BER_BVC( "master" ),
00118        BER_BVC( "immediateSuperior" ),
00119        BER_BVC( "self" ),
00120        BER_BVNULL
00121 };
00122 
00123 static struct berval bv2ss[] = {
00124        BER_BVC( "baseObject" ),
00125        BER_BVC( "singleLevel" ),
00126        BER_BVC( "wholeSubtree" ),
00127        BER_BVC( "subordinateSubtree" ),
00128        BER_BVNULL
00129 };
00130 
00131 static struct berval *
00132 ldap_distproc_rt2bv( ReferenceType_t rt )
00133 {
00134        return &bv2rt[ rt ];
00135 }
00136 
00137 static const char *
00138 ldap_distproc_rt2str( ReferenceType_t rt )
00139 {
00140        return bv2rt[ rt ].bv_val;
00141 }
00142 
00143 static ReferenceType_t
00144 ldap_distproc_bv2rt( struct berval *bv )
00145 {
00146        ReferenceType_t             rt;
00147 
00148        for ( rt = 0; !BER_BVISNULL( &bv2rt[ rt ] ); rt++ ) {
00149               if ( ber_bvstrcasecmp( bv, &bv2rt[ rt ] ) == 0 ) {
00150                      return rt;
00151               }
00152        }
00153 
00154        return LDAP_DP_RT_UNKNOWN;
00155 }
00156 
00157 static ReferenceType_t
00158 ldap_distproc_str2rt( const char *s )
00159 {
00160        struct berval bv;
00161 
00162        ber_str2bv( s, 0, 0, &bv );
00163        return ldap_distproc_bv2rt( &bv );
00164 }
00165 
00166 static struct berval *
00167 ldap_distproc_ss2bv( SearchScope_t ss )
00168 {
00169        return &bv2ss[ ss ];
00170 }
00171 
00172 static const char *
00173 ldap_distproc_ss2str( SearchScope_t ss )
00174 {
00175        return bv2ss[ ss ].bv_val;
00176 }
00177 
00178 static SearchScope_t
00179 ldap_distproc_bv2ss( struct berval *bv )
00180 {
00181        ReferenceType_t             ss;
00182 
00183        for ( ss = 0; !BER_BVISNULL( &bv2ss[ ss ] ); ss++ ) {
00184               if ( ber_bvstrcasecmp( bv, &bv2ss[ ss ] ) == 0 ) {
00185                      return ss;
00186               }
00187        }
00188 
00189        return LDAP_DP_SS_UNKNOWN;
00190 }
00191 
00192 static SearchScope_t
00193 ldap_distproc_str2ss( const char *s )
00194 {
00195        struct berval bv;
00196 
00197        ber_str2bv( s, 0, 0, &bv );
00198        return ldap_distproc_bv2ss( &bv );
00199 }
00200 #endif /* unused */
00201 
00202 /*
00203  * NOTE: this overlay assumes that the chainingBehavior control
00204  * is registered by the chain overlay; it may move here some time.
00205  * This overlay provides support for that control as well.
00206  */
00207 
00208 
00209 static int           sc_returnContRef;
00210 #define o_returnContRef                   o_ctrlflag[sc_returnContRef]
00211 #define get_returnContRef(op)             ((op)->o_returnContRef & SLAP_CONTROL_MASK)
00212 
00213 static struct berval slap_EXOP_CHAINEDREQUEST = BER_BVC( LDAP_EXOP_X_CHAINEDREQUEST );
00214 static struct berval slap_FEATURE_CANCHAINOPS = BER_BVC( LDAP_FEATURE_X_CANCHAINOPS );
00215 
00216 static BackendInfo   *lback;
00217 
00218 typedef struct ldap_distproc_t {
00219        /* "common" configuration info (anything occurring before an "uri") */
00220        ldapinfo_t           *lc_common_li;
00221 
00222        /* current configuration info */
00223        ldapinfo_t           *lc_cfg_li;
00224 
00225        /* tree of configured[/generated?] "uri" info */
00226        ldap_avl_info_t             lc_lai;
00227 
00228        unsigned             lc_flags;
00229 #define LDAP_DISTPROC_F_NONE              (0x00U)
00230 #define       LDAP_DISTPROC_F_CHAINING    (0x01U)
00231 #define       LDAP_DISTPROC_F_CACHE_URI   (0x10U)
00232 
00233 #define       LDAP_DISTPROC_CHAINING( lc )       ( ( (lc)->lc_flags & LDAP_DISTPROC_F_CHAINING ) == LDAP_DISTPROC_F_CHAINING )
00234 #define       LDAP_DISTPROC_CACHE_URI( lc )      ( ( (lc)->lc_flags & LDAP_DISTPROC_F_CACHE_URI ) == LDAP_DISTPROC_F_CACHE_URI )
00235 
00236 } ldap_distproc_t;
00237 
00238 static int ldap_distproc_db_init_common( BackendDB      *be );
00239 static int ldap_distproc_db_init_one( BackendDB *be );
00240 #define       ldap_distproc_db_open_one(be)             (lback)->bi_db_open( (be) )
00241 #define       ldap_distproc_db_close_one(be)            (0)
00242 #define       ldap_distproc_db_destroy_one(be, ca)      (lback)->bi_db_destroy( (be), (ca) )
00243 
00244 static int
00245 ldap_distproc_uri_cmp( const void *c1, const void *c2 )
00246 {
00247        const ldapinfo_t     *li1 = (const ldapinfo_t *)c1;
00248        const ldapinfo_t     *li2 = (const ldapinfo_t *)c2;
00249 
00250        assert( li1->li_bvuri != NULL );
00251        assert( !BER_BVISNULL( &li1->li_bvuri[ 0 ] ) );
00252        assert( BER_BVISNULL( &li1->li_bvuri[ 1 ] ) );
00253 
00254        assert( li2->li_bvuri != NULL );
00255        assert( !BER_BVISNULL( &li2->li_bvuri[ 0 ] ) );
00256        assert( BER_BVISNULL( &li2->li_bvuri[ 1 ] ) );
00257 
00258        /* If local DNs don't match, it is definitely not a match */
00259        return ber_bvcmp( &li1->li_bvuri[ 0 ], &li2->li_bvuri[ 0 ] );
00260 }
00261 
00262 static int
00263 ldap_distproc_uri_dup( void *c1, void *c2 )
00264 {
00265        ldapinfo_t    *li1 = (ldapinfo_t *)c1;
00266        ldapinfo_t    *li2 = (ldapinfo_t *)c2;
00267 
00268        assert( li1->li_bvuri != NULL );
00269        assert( !BER_BVISNULL( &li1->li_bvuri[ 0 ] ) );
00270        assert( BER_BVISNULL( &li1->li_bvuri[ 1 ] ) );
00271 
00272        assert( li2->li_bvuri != NULL );
00273        assert( !BER_BVISNULL( &li2->li_bvuri[ 0 ] ) );
00274        assert( BER_BVISNULL( &li2->li_bvuri[ 1 ] ) );
00275 
00276        /* Cannot have more than one shared session with same DN */
00277        if ( ber_bvcmp( &li1->li_bvuri[ 0 ], &li2->li_bvuri[ 0 ] ) == 0 ) {
00278               return -1;
00279        }
00280               
00281        return 0;
00282 }
00283 
00284 static int
00285 ldap_distproc_operational( Operation *op, SlapReply *rs )
00286 {
00287        /* Trap entries generated by back-ldap.
00288         * 
00289         * FIXME: we need a better way to recognize them; a cleaner
00290         * solution would be to be able to intercept the response
00291         * of be_operational(), so that we can divert only those
00292         * calls that fail because operational attributes were
00293         * requested for entries that do not belong to the underlying
00294         * database.  This fix is likely to intercept also entries
00295         * generated by back-perl and so. */
00296        if ( rs->sr_entry->e_private == NULL ) {
00297               return LDAP_SUCCESS;
00298        }
00299 
00300        return SLAP_CB_CONTINUE;
00301 }
00302 
00303 static int
00304 ldap_distproc_response( Operation *op, SlapReply *rs )
00305 {
00306        return SLAP_CB_CONTINUE;
00307 }
00308 
00309 /*
00310  * configuration...
00311  */
00312 
00313 enum {
00314        /* NOTE: the chaining behavior control is registered
00315         * by the chain overlay; it may move here some time */
00316        DP_CHAINING = 1,
00317        DP_CACHE_URI,
00318 
00319        DP_LAST
00320 };
00321 
00322 static ConfigDriver distproc_cfgen;
00323 static ConfigCfAdd distproc_cfadd;
00324 static ConfigLDAPadd distproc_ldadd;
00325 
00326 static ConfigTable distproc_cfg[] = {
00327        { "distproc-chaining", "args",
00328               2, 4, 0, ARG_MAGIC|ARG_BERVAL|DP_CHAINING, distproc_cfgen,
00329               /* NOTE: using the same attributeTypes defined
00330                * for the "chain" overlay */
00331               "( OLcfgOvAt:3.1 NAME 'olcChainingBehavior' "
00332                      "DESC 'Chaining behavior control parameters (draft-sermersheim-ldap-chaining)' "
00333                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00334        { "distproc-cache-uri", "TRUE/FALSE",
00335               2, 2, 0, ARG_MAGIC|ARG_ON_OFF|DP_CACHE_URI, distproc_cfgen,
00336               "( OLcfgOvAt:3.2 NAME 'olcChainCacheURI' "
00337                      "DESC 'Enables caching of URIs not present in configuration' "
00338                      "SYNTAX OMsBoolean "
00339                      "SINGLE-VALUE )", NULL, NULL },
00340        { NULL, NULL, 0, 0, 0, ARG_IGNORED }
00341 };
00342 
00343 static ConfigOCs distproc_ocs[] = {
00344        { "( OLcfgOvOc:7.1 "
00345               "NAME 'olcDistProcConfig' "
00346               "DESC 'Distributed procedures <draft-sermersheim-ldap-distproc> configuration' "
00347               "SUP olcOverlayConfig "
00348               "MAY ( "
00349                      "olcChainingBehavior $ "
00350                      "olcChainCacheURI "
00351                      ") )",
00352               Cft_Overlay, distproc_cfg, NULL, distproc_cfadd },
00353        { "( OLcfgOvOc:7.2 "
00354               "NAME 'olcDistProcDatabase' "
00355               "DESC 'Distributed procedure remote server configuration' "
00356               "AUXILIARY )",
00357               Cft_Misc, distproc_cfg, distproc_ldadd },
00358        { NULL, 0, NULL }
00359 };
00360 
00361 static int
00362 distproc_ldadd( CfEntryInfo *p, Entry *e, ConfigArgs *ca )
00363 {
00364        slap_overinst        *on;
00365        ldap_distproc_t             *lc;
00366 
00367        ldapinfo_t           *li;
00368 
00369        AttributeDescription *ad = NULL;
00370        Attribute            *at;
00371        const char           *text;
00372 
00373        int                  rc;
00374 
00375        if ( p->ce_type != Cft_Overlay
00376               || !p->ce_bi
00377               || p->ce_bi->bi_cf_ocs != distproc_ocs )
00378        {
00379               return LDAP_CONSTRAINT_VIOLATION;
00380        }
00381 
00382        on = (slap_overinst *)p->ce_bi;
00383        lc = (ldap_distproc_t *)on->on_bi.bi_private;
00384 
00385        assert( ca->be == NULL );
00386        ca->be = (BackendDB *)ch_calloc( 1, sizeof( BackendDB ) );
00387 
00388        ca->be->bd_info = (BackendInfo *)on;
00389 
00390        rc = slap_str2ad( "olcDbURI", &ad, &text );
00391        assert( rc == LDAP_SUCCESS );
00392 
00393        at = attr_find( e->e_attrs, ad );
00394        if ( lc->lc_common_li == NULL && at != NULL ) {
00395               /* FIXME: we should generate an empty default entry
00396                * if none is supplied */
00397               Debug( LDAP_DEBUG_ANY, "slapd-distproc: "
00398                      "first underlying database \"%s\" "
00399                      "cannot contain attribute \"%s\".\n",
00400                      e->e_name.bv_val, ad->ad_cname.bv_val, 0 );
00401               rc = LDAP_CONSTRAINT_VIOLATION;
00402               goto done;
00403 
00404        } else if ( lc->lc_common_li != NULL && at == NULL ) {
00405               /* FIXME: we should generate an empty default entry
00406                * if none is supplied */
00407               Debug( LDAP_DEBUG_ANY, "slapd-distproc: "
00408                      "subsequent underlying database \"%s\" "
00409                      "must contain attribute \"%s\".\n",
00410                      e->e_name.bv_val, ad->ad_cname.bv_val, 0 );
00411               rc = LDAP_CONSTRAINT_VIOLATION;
00412               goto done;
00413        }
00414 
00415        if ( lc->lc_common_li == NULL ) {
00416               rc = ldap_distproc_db_init_common( ca->be );
00417 
00418        } else {
00419               rc = ldap_distproc_db_init_one( ca->be );
00420        }
00421 
00422        if ( rc != 0 ) {
00423               Debug( LDAP_DEBUG_ANY, "slapd-distproc: "
00424                      "unable to init %sunderlying database \"%s\".\n",
00425                      lc->lc_common_li == NULL ? "common " : "", e->e_name.bv_val, 0 );
00426               return LDAP_CONSTRAINT_VIOLATION;
00427        }
00428 
00429        li = ca->be->be_private;
00430 
00431        if ( lc->lc_common_li == NULL ) {
00432               lc->lc_common_li = li;
00433 
00434        } else if ( avl_insert( &lc->lc_lai.lai_tree, (caddr_t)li,
00435               ldap_distproc_uri_cmp, ldap_distproc_uri_dup ) )
00436        {
00437               Debug( LDAP_DEBUG_ANY, "slapd-distproc: "
00438                      "database \"%s\" insert failed.\n",
00439                      e->e_name.bv_val, 0, 0 );
00440               rc = LDAP_CONSTRAINT_VIOLATION;
00441               goto done;
00442        }
00443 
00444 done:;
00445        if ( rc != LDAP_SUCCESS ) {
00446               (void)ldap_distproc_db_destroy_one( ca->be, NULL );
00447               ch_free( ca->be );
00448               ca->be = NULL;
00449        }
00450 
00451        return rc;
00452 }
00453 
00454 typedef struct ldap_distproc_cfadd_apply_t {
00455        Operation     *op;
00456        SlapReply     *rs;
00457        Entry         *p;
00458        ConfigArgs    *ca;
00459        int           count;
00460 } ldap_distproc_cfadd_apply_t;
00461 
00462 static int
00463 ldap_distproc_cfadd_apply( void *datum, void *arg )
00464 {
00465        ldapinfo_t                  *li = (ldapinfo_t *)datum;
00466        ldap_distproc_cfadd_apply_t *lca = (ldap_distproc_cfadd_apply_t *)arg;
00467 
00468        struct berval               bv;
00469 
00470        /* FIXME: should not hardcode "olcDatabase" here */
00471        bv.bv_len = snprintf( lca->ca->cr_msg, sizeof( lca->ca->cr_msg ),
00472               "olcDatabase={%d}%s", lca->count, lback->bi_type );
00473        bv.bv_val = lca->ca->cr_msg;
00474 
00475        lca->ca->be->be_private = (void *)li;
00476        config_build_entry( lca->op, lca->rs, lca->p->e_private, lca->ca,
00477               &bv, lback->bi_cf_ocs, &distproc_ocs[ 1 ] );
00478 
00479        lca->count++;
00480 
00481        return 0;
00482 }
00483 
00484 static int
00485 distproc_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *ca )
00486 {
00487        CfEntryInfo   *pe = p->e_private;
00488        slap_overinst *on = (slap_overinst *)pe->ce_bi;
00489        ldap_distproc_t      *lc = (ldap_distproc_t *)on->on_bi.bi_private;
00490        void          *priv = (void *)ca->be->be_private;
00491 
00492        if ( lback->bi_cf_ocs ) {
00493               ldap_distproc_cfadd_apply_t lca = { 0 };
00494 
00495               lca.op = op;
00496               lca.rs = rs;
00497               lca.p = p;
00498               lca.ca = ca;
00499               lca.count = 0;
00500 
00501               (void)ldap_distproc_cfadd_apply( (void *)lc->lc_common_li, (void *)&lca );
00502 
00503               (void)avl_apply( lc->lc_lai.lai_tree, ldap_distproc_cfadd_apply,
00504                      &lca, 1, AVL_INORDER );
00505 
00506               ca->be->be_private = priv;
00507        }
00508 
00509        return 0;
00510 }
00511 
00512 static int
00513 distproc_cfgen( ConfigArgs *c )
00514 {
00515        slap_overinst *on = (slap_overinst *)c->bi;
00516        ldap_distproc_t      *lc = (ldap_distproc_t *)on->on_bi.bi_private;
00517 
00518        int           rc = 0;
00519 
00520        if ( c->op == SLAP_CONFIG_EMIT ) {
00521               switch( c->type ) {
00522               case DP_CACHE_URI:
00523                      c->value_int = LDAP_DISTPROC_CACHE_URI( lc );
00524                      break;
00525 
00526               default:
00527                      assert( 0 );
00528                      rc = 1;
00529               }
00530               return rc;
00531 
00532        } else if ( c->op == LDAP_MOD_DELETE ) {
00533               switch( c->type ) {
00534               case DP_CHAINING:
00535                      return 1;
00536 
00537               case DP_CACHE_URI:
00538                      lc->lc_flags &= ~LDAP_DISTPROC_F_CACHE_URI;
00539                      break;
00540 
00541               default:
00542                      return 1;
00543               }
00544               return rc;
00545        }
00546 
00547        switch( c->type ) {
00548        case DP_CACHE_URI:
00549               if ( c->value_int ) {
00550                      lc->lc_flags |= LDAP_DISTPROC_F_CACHE_URI;
00551               } else {
00552                      lc->lc_flags &= ~LDAP_DISTPROC_F_CACHE_URI;
00553               }
00554               break;
00555 
00556        default:
00557               assert( 0 );
00558               return 1;
00559        }
00560 
00561        return rc;
00562 }
00563 
00564 static int
00565 ldap_distproc_db_init(
00566        BackendDB *be,
00567        ConfigReply *cr )
00568 {
00569        slap_overinst *on = (slap_overinst *)be->bd_info;
00570        ldap_distproc_t      *lc = NULL;
00571 
00572        if ( lback == NULL ) {
00573               lback = backend_info( "ldap" );
00574 
00575               if ( lback == NULL ) {
00576                      return 1;
00577               }
00578        }
00579 
00580        lc = ch_malloc( sizeof( ldap_distproc_t ) );
00581        if ( lc == NULL ) {
00582               return 1;
00583        }
00584        memset( lc, 0, sizeof( ldap_distproc_t ) );
00585        ldap_pvt_thread_mutex_init( &lc->lc_lai.lai_mutex );
00586 
00587        on->on_bi.bi_private = (void *)lc;
00588 
00589        return 0;
00590 }
00591 
00592 static int
00593 ldap_distproc_db_config(
00594        BackendDB     *be,
00595        const char    *fname,
00596        int           lineno,
00597        int           argc,
00598        char          **argv )
00599 {
00600        slap_overinst *on = (slap_overinst *)be->bd_info;
00601        ldap_distproc_t      *lc = (ldap_distproc_t *)on->on_bi.bi_private;
00602 
00603        int           rc = SLAP_CONF_UNKNOWN;
00604               
00605        if ( lc->lc_common_li == NULL ) {
00606               void   *be_private = be->be_private;
00607               ldap_distproc_db_init_common( be );
00608               lc->lc_common_li = lc->lc_cfg_li = (ldapinfo_t *)be->be_private;
00609               be->be_private = be_private;
00610        }
00611 
00612        /* Something for the distproc database? */
00613        if ( strncasecmp( argv[ 0 ], "distproc-", STRLENOF( "distproc-" ) ) == 0 ) {
00614               char          *save_argv0 = argv[ 0 ];
00615               BackendInfo   *bd_info = be->bd_info;
00616               void          *be_private = be->be_private;
00617               ConfigOCs     *be_cf_ocs = be->be_cf_ocs;
00618               int           is_uri = 0;
00619 
00620               argv[ 0 ] += STRLENOF( "distproc-" );
00621 
00622               if ( strcasecmp( argv[ 0 ], "uri" ) == 0 ) {
00623                      rc = ldap_distproc_db_init_one( be );
00624                      if ( rc != 0 ) {
00625                             Debug( LDAP_DEBUG_ANY, "%s: line %d: "
00626                                    "underlying slapd-ldap initialization failed.\n.",
00627                                    fname, lineno, 0 );
00628                             return 1;
00629                      }
00630                      lc->lc_cfg_li = be->be_private;
00631                      is_uri = 1;
00632               }
00633 
00634               /* TODO: add checks on what other slapd-ldap(5) args
00635                * should be put in the template; this is not quite
00636                * harmful, because attributes that shouldn't don't
00637                * get actually used, but the user should at least
00638                * be warned.
00639                */
00640 
00641               be->bd_info = lback;
00642               be->be_private = (void *)lc->lc_cfg_li;
00643               be->be_cf_ocs = lback->bi_cf_ocs;
00644 
00645               rc = config_generic_wrapper( be, fname, lineno, argc, argv );
00646 
00647               argv[ 0 ] = save_argv0;
00648               be->be_cf_ocs = be_cf_ocs;
00649               be->be_private = be_private;
00650               be->bd_info = bd_info;
00651 
00652               if ( is_uri ) {
00653 private_destroy:;
00654                      if ( rc != 0 ) {
00655                             BackendDB            db = *be;
00656 
00657                             db.bd_info = lback;
00658                             db.be_private = (void *)lc->lc_cfg_li;
00659                             ldap_distproc_db_destroy_one( &db, NULL );
00660                             lc->lc_cfg_li = NULL;
00661 
00662                      } else {
00663                             if ( lc->lc_cfg_li->li_bvuri == NULL
00664                                    || BER_BVISNULL( &lc->lc_cfg_li->li_bvuri[ 0 ] )
00665                                    || !BER_BVISNULL( &lc->lc_cfg_li->li_bvuri[ 1 ] ) )
00666                             {
00667                                    Debug( LDAP_DEBUG_ANY, "%s: line %d: "
00668                                           "no URI list allowed in slapo-distproc.\n",
00669                                           fname, lineno, 0 );
00670                                    rc = 1;
00671                                    goto private_destroy;
00672                             }
00673 
00674                             if ( avl_insert( &lc->lc_lai.lai_tree,
00675                                    (caddr_t)lc->lc_cfg_li,
00676                                    ldap_distproc_uri_cmp, ldap_distproc_uri_dup ) )
00677                             {
00678                                    Debug( LDAP_DEBUG_ANY, "%s: line %d: "
00679                                           "duplicate URI in slapo-distproc.\n",
00680                                           fname, lineno, 0 );
00681                                    rc = 1;
00682                                    goto private_destroy;
00683                             }
00684                      }
00685               }
00686        }
00687        
00688        return rc;
00689 }
00690 
00691 enum db_which {
00692        db_open = 0,
00693        db_close,
00694        db_destroy,
00695 
00696        db_last
00697 };
00698 
00699 typedef struct ldap_distproc_db_apply_t {
00700        BackendDB     *be;
00701        BI_db_func    *func;
00702 } ldap_distproc_db_apply_t;
00703 
00704 static int
00705 ldap_distproc_db_apply( void *datum, void *arg )
00706 {
00707        ldapinfo_t           *li = (ldapinfo_t *)datum;
00708        ldap_distproc_db_apply_t    *lca = (ldap_distproc_db_apply_t *)arg;
00709 
00710        lca->be->be_private = (void *)li;
00711 
00712        return lca->func( lca->be, NULL );
00713 }
00714 
00715 static int
00716 ldap_distproc_db_func(
00717        BackendDB *be,
00718        enum db_which which
00719 )
00720 {
00721        slap_overinst *on = (slap_overinst *)be->bd_info;
00722        ldap_distproc_t      *lc = (ldap_distproc_t *)on->on_bi.bi_private;
00723 
00724        int           rc = 0;
00725 
00726        if ( lc ) {
00727               BI_db_func    *func = (&lback->bi_db_open)[ which ];
00728 
00729               if ( func != NULL && lc->lc_common_li != NULL ) {
00730                      BackendDB            db = *be;
00731 
00732                      db.bd_info = lback;
00733                      db.be_private = lc->lc_common_li;
00734 
00735                      rc = func( &db, NULL );
00736 
00737                      if ( rc != 0 ) {
00738                             return rc;
00739                      }
00740 
00741                      if ( lc->lc_lai.lai_tree != NULL ) {
00742                             ldap_distproc_db_apply_t    lca;
00743 
00744                             lca.be = &db;
00745                             lca.func = func;
00746 
00747                             rc = avl_apply( lc->lc_lai.lai_tree,
00748                                    ldap_distproc_db_apply, (void *)&lca,
00749                                    1, AVL_INORDER ) != AVL_NOMORE;
00750                      }
00751               }
00752        }
00753 
00754        return rc;
00755 }
00756 
00757 static int
00758 ldap_distproc_db_open(
00759        BackendDB     *be,
00760        ConfigReply   *cr )
00761 {
00762        return ldap_distproc_db_func( be, db_open );
00763 }
00764 
00765 static int
00766 ldap_distproc_db_close(
00767        BackendDB     *be,
00768        ConfigReply   *cr )
00769 {
00770        return ldap_distproc_db_func( be, db_close );
00771 }
00772 
00773 static int
00774 ldap_distproc_db_destroy(
00775        BackendDB     *be,
00776        ConfigReply   *cr )
00777 {
00778        slap_overinst *on = (slap_overinst *) be->bd_info;
00779        ldap_distproc_t      *lc = (ldap_distproc_t *)on->on_bi.bi_private;
00780 
00781        int           rc;
00782 
00783        rc = ldap_distproc_db_func( be, db_destroy );
00784 
00785        if ( lc ) {
00786               avl_free( lc->lc_lai.lai_tree, NULL );
00787               ldap_pvt_thread_mutex_destroy( &lc->lc_lai.lai_mutex );
00788               ch_free( lc );
00789        }
00790 
00791        return rc;
00792 }
00793 
00794 /*
00795  * inits one instance of the slapd-ldap backend, and stores
00796  * the private info in be_private of the arg
00797  */
00798 static int
00799 ldap_distproc_db_init_common(
00800        BackendDB     *be )
00801 {
00802        BackendInfo   *bi = be->bd_info;
00803        int           t;
00804 
00805        be->bd_info = lback;
00806        be->be_private = NULL;
00807        t = lback->bi_db_init( be, NULL );
00808        if ( t != 0 ) {
00809               return t;
00810        }
00811        be->bd_info = bi;
00812 
00813        return 0;
00814 }
00815 
00816 /*
00817  * inits one instance of the slapd-ldap backend, stores
00818  * the private info in be_private of the arg and fills
00819  * selected fields with data from the template.
00820  *
00821  * NOTE: add checks about the other fields of the template,
00822  * which are ignored and SHOULD NOT be configured by the user.
00823  */
00824 static int
00825 ldap_distproc_db_init_one(
00826        BackendDB     *be )
00827 {
00828        slap_overinst *on = (slap_overinst *)be->bd_info;
00829        ldap_distproc_t      *lc = (ldap_distproc_t *)on->on_bi.bi_private;
00830 
00831        BackendInfo   *bi = be->bd_info;
00832        ldapinfo_t    *li;
00833 
00834        slap_op_t     t;
00835 
00836        be->bd_info = lback;
00837        be->be_private = NULL;
00838        t = lback->bi_db_init( be, NULL );
00839        if ( t != 0 ) {
00840               return t;
00841        }
00842        li = (ldapinfo_t *)be->be_private;
00843 
00844        /* copy common data */
00845        li->li_nretries = lc->lc_common_li->li_nretries;
00846        li->li_flags = lc->lc_common_li->li_flags;
00847        li->li_version = lc->lc_common_li->li_version;
00848        for ( t = 0; t < SLAP_OP_LAST; t++ ) {
00849               li->li_timeout[ t ] = lc->lc_common_li->li_timeout[ t ];
00850        }
00851        be->bd_info = bi;
00852 
00853        return 0;
00854 }
00855 
00856 typedef struct ldap_distproc_conn_apply_t {
00857        BackendDB     *be;
00858        Connection    *conn;
00859 } ldap_distproc_conn_apply_t;
00860 
00861 static int
00862 ldap_distproc_conn_apply( void *datum, void *arg )
00863 {
00864        ldapinfo_t           *li = (ldapinfo_t *)datum;
00865        ldap_distproc_conn_apply_t  *lca = (ldap_distproc_conn_apply_t *)arg;
00866 
00867        lca->be->be_private = (void *)li;
00868 
00869        return lback->bi_connection_destroy( lca->be, lca->conn );
00870 }
00871 
00872 static int
00873 ldap_distproc_connection_destroy(
00874        BackendDB *be,
00875        Connection *conn
00876 )
00877 {
00878        slap_overinst        *on = (slap_overinst *) be->bd_info;
00879        ldap_distproc_t             *lc = (ldap_distproc_t *)on->on_bi.bi_private;
00880        void                 *private = be->be_private;
00881        ldap_distproc_conn_apply_t  lca;
00882        int                  rc;
00883 
00884        be->be_private = NULL;
00885        lca.be = be;
00886        lca.conn = conn;
00887        ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
00888        rc = avl_apply( lc->lc_lai.lai_tree, ldap_distproc_conn_apply,
00889               (void *)&lca, 1, AVL_INORDER ) != AVL_NOMORE;
00890        ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
00891        be->be_private = private;
00892 
00893        return rc;
00894 }
00895 
00896 static int
00897 ldap_distproc_parse_returnContRef_ctrl(
00898        Operation     *op,
00899        SlapReply     *rs,
00900        LDAPControl   *ctrl )
00901 {
00902        if ( get_returnContRef( op ) != SLAP_CONTROL_NONE ) {
00903               rs->sr_text = "returnContinuationReference control specified multiple times";
00904               return LDAP_PROTOCOL_ERROR;
00905        }
00906 
00907        if ( op->o_pagedresults != SLAP_CONTROL_NONE ) {
00908               rs->sr_text = "returnContinuationReference control specified with pagedResults control";
00909               return LDAP_PROTOCOL_ERROR;
00910        }
00911 
00912        if ( !BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
00913               rs->sr_text = "returnContinuationReference control: value must be NULL";
00914               return LDAP_PROTOCOL_ERROR;
00915        }
00916 
00917        op->o_returnContRef = ctrl->ldctl_iscritical ? SLAP_CONTROL_CRITICAL : SLAP_CONTROL_NONCRITICAL;
00918 
00919        return LDAP_SUCCESS;
00920 }
00921 
00922 static int
00923 ldap_exop_chained_request(
00924               Operation     *op,
00925               SlapReply     *rs )
00926 {
00927        Statslog( LDAP_DEBUG_STATS, "%s CHAINED REQUEST\n",
00928            op->o_log_prefix, 0, 0, 0, 0 );
00929 
00930        rs->sr_err = backend_check_restrictions( op, rs, 
00931                      (struct berval *)&slap_EXOP_CHAINEDREQUEST );
00932        if ( rs->sr_err != LDAP_SUCCESS ) {
00933               return rs->sr_err;
00934        }
00935 
00936        /* by now, just reject requests */
00937        rs->sr_text = "under development";
00938        return LDAP_UNWILLING_TO_PERFORM;
00939 }
00940 
00941 
00942 static slap_overinst distproc;
00943 
00944 int
00945 distproc_initialize( void )
00946 {
00947        int    rc;
00948 
00949        /* Make sure we don't exceed the bits reserved for userland */
00950        config_check_userland( DP_LAST );
00951 
00952        rc = load_extop( (struct berval *)&slap_EXOP_CHAINEDREQUEST,
00953               SLAP_EXOP_HIDE, ldap_exop_chained_request );
00954        if ( rc != LDAP_SUCCESS ) {
00955               Debug( LDAP_DEBUG_ANY, "slapd-distproc: "
00956                      "unable to register chainedRequest exop: %d.\n",
00957                      rc, 0, 0 );
00958               return rc;
00959        }
00960 
00961 #ifdef LDAP_DEVEL
00962        rc = supported_feature_load( &slap_FEATURE_CANCHAINOPS );
00963        if ( rc != LDAP_SUCCESS ) {
00964               Debug( LDAP_DEBUG_ANY, "slapd-distproc: "
00965                      "unable to register canChainOperations supported feature: %d.\n",
00966                      rc, 0, 0 );
00967               return rc;
00968        }
00969 #endif
00970 
00971        rc = register_supported_control( LDAP_CONTROL_X_RETURNCONTREF,
00972                      SLAP_CTRL_GLOBAL|SLAP_CTRL_ACCESS|SLAP_CTRL_HIDE, NULL,
00973                      ldap_distproc_parse_returnContRef_ctrl, &sc_returnContRef );
00974        if ( rc != LDAP_SUCCESS ) {
00975               Debug( LDAP_DEBUG_ANY, "slapd-distproc: "
00976                      "unable to register returnContinuationReference control: %d.\n",
00977                      rc, 0, 0 );
00978               return rc;
00979        }
00980 
00981        distproc.on_bi.bi_type = "distproc";
00982        distproc.on_bi.bi_db_init = ldap_distproc_db_init;
00983        distproc.on_bi.bi_db_config = ldap_distproc_db_config;
00984        distproc.on_bi.bi_db_open = ldap_distproc_db_open;
00985        distproc.on_bi.bi_db_close = ldap_distproc_db_close;
00986        distproc.on_bi.bi_db_destroy = ldap_distproc_db_destroy;
00987 
00988        /* ... otherwise the underlying backend's function would be called,
00989         * likely passing an invalid entry; on the contrary, the requested
00990         * operational attributes should have been returned while chasing
00991         * the referrals.  This all in all is a bit messy, because part
00992         * of the operational attributes are generated by the backend;
00993         * part by the frontend; back-ldap should receive all the available
00994         * ones from the remote server, but then, on its own, it strips those
00995         * it assumes will be (re)generated by the frontend (e.g.
00996         * subschemaSubentry, entryDN, ...) */
00997        distproc.on_bi.bi_operational = ldap_distproc_operational;
00998        
00999        distproc.on_bi.bi_connection_destroy = ldap_distproc_connection_destroy;
01000 
01001        distproc.on_response = ldap_distproc_response;
01002 
01003        distproc.on_bi.bi_cf_ocs = distproc_ocs;
01004 
01005        rc = config_register_schema( distproc_cfg, distproc_ocs );
01006        if ( rc ) {
01007               return rc;
01008        }
01009 
01010        return overlay_register( &distproc );
01011 }
01012 
01013 #endif /* SLAP_DISTPROC */