From: Kurt Zeilenga Date: Fri, 28 Jan 2005 18:29:47 +0000 (+0000) Subject: Sync with HEAD X-Git-Tag: OPENLDAP_REL_ENG_2_3_1ALPHA~3 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=b008f1e8810440711e311561a17ab5976e106543;p=openldap Sync with HEAD --- diff --git a/clients/tools/common.c b/clients/tools/common.c index 415be46b9d..39c6586d30 100644 --- a/clients/tools/common.c +++ b/clients/tools/common.c @@ -80,6 +80,12 @@ int protocol = -1; int verbose = 0; int version = 0; +#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR +int chaining = 0; +static int chainingResolve = -1; +static int chainingContinuation = -1; +#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ + /* Set in main() */ char *prog = NULL; @@ -107,6 +113,11 @@ N_(" [!]noop\n") #ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST N_(" ppolicy\n") #endif +#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR +N_(" [!]chaining[=[/]]\n") +N_(" one of \"chainingPreferred\", \"chainingRequired\",\n") +N_(" \"referralsPreferred\", \"referralsRequired\"\n") +#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ N_(" [!]postread[=] (a comma-separated attribute list)\n") N_(" [!]preread[=] (a comma-separated attribute list)\n"), N_(" -f file read operations from `file'\n"), @@ -286,6 +297,52 @@ tool_args( int argc, char **argv ) postread = 1 + crit; postread_attrs = cvalue; +#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR + } else if ( strcasecmp( control, "chaining" ) == 0 ) { + chaining = 1 + crit; + + if ( cvalue != NULL ) { + char *continuation; + + continuation = strchr( cvalue, '/' ); + if ( continuation ) { + /* FIXME: this makes sense only in searches */ + *continuation++ = '\0'; + if ( strcasecmp( continuation, "chainingPreferred" ) == 0 ) { + chainingContinuation = LDAP_CHAINING_PREFERRED; + } else if ( strcasecmp( continuation, "chainingRequired" ) == 0 ) { + chainingContinuation = LDAP_CHAINING_REQUIRED; + } else if ( strcasecmp( continuation, "referralsPreferred" ) == 0 ) { + chainingContinuation = LDAP_REFERRALS_PREFERRED; + } else if ( strcasecmp( continuation, "referralsRequired" ) == 0 ) { + chainingContinuation = LDAP_REFERRALS_REQUIRED; + } else { + fprintf( stderr, + "chaining behavior control " + "continuation value \"%s\" invalid\n", + continuation ); + exit( EXIT_FAILURE ); + } + } + + if ( strcasecmp( cvalue, "chainingPreferred" ) == 0 ) { + chainingResolve = LDAP_CHAINING_PREFERRED; + } else if ( strcasecmp( cvalue, "chainingRequired" ) == 0 ) { + chainingResolve = LDAP_CHAINING_REQUIRED; + } else if ( strcasecmp( cvalue, "referralsPreferred" ) == 0 ) { + chainingResolve = LDAP_REFERRALS_PREFERRED; + } else if ( strcasecmp( cvalue, "referralsRequired" ) == 0 ) { + chainingResolve = LDAP_REFERRALS_REQUIRED; + } else { + fprintf( stderr, + "chaining behavior control " + "resolve value \"%s\" invalid\n", + cvalue); + exit( EXIT_FAILURE ); + } + } +#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ + } else { fprintf( stderr, "Invalid general control name: %s\n", control ); @@ -867,7 +924,7 @@ void tool_server_controls( LDAP *ld, LDAPControl *extra_c, int count ) { int i = 0, j, crit = 0, err; - LDAPControl c[8], **ctrls; + LDAPControl c[9], **ctrls; ctrls = (LDAPControl**) malloc(sizeof(c) + (count+1)*sizeof(LDAPControl*)); if ( ctrls == NULL ) { @@ -915,8 +972,7 @@ tool_server_controls( LDAP *ld, LDAPControl *extra_c, int count ) if ( manageDSAit ) { c[i].ldctl_oid = LDAP_CONTROL_MANAGEDSAIT; - c[i].ldctl_value.bv_val = NULL; - c[i].ldctl_value.bv_len = 0; + BER_BVZERO( &c[i].ldctl_value ); c[i].ldctl_iscritical = manageDSAit > 1; ctrls[i] = &c[i]; i++; @@ -924,8 +980,7 @@ tool_server_controls( LDAP *ld, LDAPControl *extra_c, int count ) if ( noop ) { c[i].ldctl_oid = LDAP_CONTROL_NOOP; - c[i].ldctl_value.bv_val = NULL; - c[i].ldctl_value.bv_len = 0; + BER_BVZERO( &c[i].ldctl_value ); c[i].ldctl_iscritical = noop > 1; ctrls[i] = &c[i]; i++; @@ -991,6 +1046,52 @@ tool_server_controls( LDAP *ld, LDAPControl *extra_c, int count ) if( attrs ) ldap_charray_free( attrs ); } +#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR + if ( chaining ) { + if ( chainingResolve > -1 ) { + BerElementBuffer berbuf; + BerElement *ber = (BerElement *)&berbuf; + + ber_init2( ber, NULL, LBER_USE_DER ); + + err = ber_printf( ber, "{e" /* } */, chainingResolve ); + if ( err == -1 ) { + ber_free( ber, 1 ); + fprintf( stderr, _("Chaining behavior control encoding error!\n") ); + exit( EXIT_FAILURE ); + } + + if ( chainingContinuation > -1 ) { + err = ber_printf( ber, "e", chainingContinuation ); + if ( err == -1 ) { + ber_free( ber, 1 ); + fprintf( stderr, _("Chaining behavior control encoding error!\n") ); + exit( EXIT_FAILURE ); + } + } + + err = ber_printf( ber, /* { */ "N}" ); + if ( err == -1 ) { + ber_free( ber, 1 ); + fprintf( stderr, _("Chaining behavior control encoding error!\n") ); + exit( EXIT_FAILURE ); + } + + if ( ber_flatten2( ber, &c[i].ldctl_value, 0 ) == -1 ) { + exit( EXIT_FAILURE ); + } + + } else { + BER_BVZERO( &c[i].ldctl_value ); + } + + c[i].ldctl_oid = LDAP_CONTROL_X_CHAINING_BEHAVIOR; + c[i].ldctl_iscritical = chaining > 1; + ctrls[i] = &c[i]; + i++; + } +#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ + while ( count-- ) { ctrls[i++] = extra_c++; } diff --git a/clients/tools/common.h b/clients/tools/common.h index 3022721d5b..d6903ac9f9 100644 --- a/clients/tools/common.h +++ b/clients/tools/common.h @@ -49,6 +49,9 @@ extern int manageDSAit; extern int noop; extern int ppolicy; extern int preread, postread; +#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR +extern int chaining; +#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ extern int not; extern int want_bindpw; diff --git a/clients/tools/ldapsearch.c b/clients/tools/ldapsearch.c index e2f9944959..c603281d97 100644 --- a/clients/tools/ldapsearch.c +++ b/clients/tools/ldapsearch.c @@ -379,7 +379,7 @@ handle_private_option( int i ) if( crit ) subentries *= -1; #endif - } else if ( strcasecmp( control, "sync" ) == 0 ) { + } else if ( strcasecmp( control, "sync" ) == 0 ) { char *cookiep; char *slimitp; if ( ldapsync ) { @@ -664,31 +664,34 @@ getNextPage: #ifdef LDAP_CONTROL_PAGEDRESULTS || pagedResults #endif +#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR + || chaining +#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ || ldapsync || subentries || valuesReturnFilter ) { int err; int i=0; - LDAPControl c[6]; + LDAPControl c[10]; #ifdef LDAP_CONTROL_X_DOMAIN_SCOPE - if ( domainScope ) { - c[i].ldctl_oid = LDAP_CONTROL_X_DOMAIN_SCOPE; - c[i].ldctl_value.bv_val = NULL; - c[i].ldctl_value.bv_len = 0; - c[i].ldctl_iscritical = domainScope > 1; - i++; - } + if ( domainScope ) { + c[i].ldctl_oid = LDAP_CONTROL_X_DOMAIN_SCOPE; + c[i].ldctl_value.bv_val = NULL; + c[i].ldctl_value.bv_len = 0; + c[i].ldctl_iscritical = domainScope > 1; + i++; + } #endif #ifdef LDAP_CONTROL_SUBENTRIES if ( subentries ) { - if (( seber = ber_alloc_t(LBER_USE_DER)) == NULL ) { + if (( seber = ber_alloc_t(LBER_USE_DER)) == NULL ) { return EXIT_FAILURE; } err = ber_printf( seber, "b", abs(subentries) == 1 ? 0 : 1 ); - if ( err == -1 ) { + if ( err == -1 ) { ber_free( seber, 1 ); fprintf( stderr, _("Subentries control encoding error!\n") ); return EXIT_FAILURE; diff --git a/doc/man/man5/slapd-bdb.5 b/doc/man/man5/slapd-bdb.5 index 50716b7c7e..d43be03ea5 100644 --- a/doc/man/man5/slapd-bdb.5 +++ b/doc/man/man5/slapd-bdb.5 @@ -73,12 +73,6 @@ results if the data comes from a transaction that is later aborted. In this case, the modified data is discarded and a subsequent search will return a different result. .TP -.B fasttool -Disables transaction logging when using the slapadd/slapindex tools, -using the DB_TXN_NOT_DURABLE flag. Does not affect normal slapd operation, -but will improve the performance of slapadd/slapindex. -See the Berkeley DB reference guide for more details. -.TP .B idlcachesize Specify the size of the in-memory index cache, in index slots. The default is zero. A larger value will speed up frequent searches of diff --git a/include/ldap.h b/include/ldap.h index b06dd612c3..dda9db93df 100644 --- a/include/ldap.h +++ b/include/ldap.h @@ -277,6 +277,18 @@ typedef struct ldapcontrol { #define LDAP_SEARCH_FLAG_DOMAIN_SCOPE 1 /* do not generate referrals */ #define LDAP_SEARCH_FLAG_PHANTOM_ROOT 2 /* search all NCs subordinate to base */ +/* LDAP Chaining Behavior Control *//* work in progress */ +/* ; + * see also LDAP_REQUIRES_CHAINING, LDAP_CANNOT_CHAIN */ +#ifdef LDAP_DEVEL +#define LDAP_CONTROL_X_CHAINING_BEHAVIOR "1.3.6.1.4.1.4203.666.11.3" + +#define LDAP_CHAINING_PREFERRED 0 +#define LDAP_CHAINING_REQUIRED 1 +#define LDAP_REFERRALS_PREFERRED 2 +#define LDAP_REFERRALS_REQUIRED 3 +#endif + /* LDAP Unsolicited Notifications */ #define LDAP_NOTICE_OF_DISCONNECTION "1.3.6.1.4.1.1466.20036" /* RFC 2251 */ #define LDAP_NOTICE_DISCONNECT LDAP_NOTICE_OF_DISCONNECTION @@ -550,6 +562,13 @@ typedef struct ldapcontrol { /* for the Assertion control */ #define LDAP_ASSERTION_FAILED 0x410f +/* for the Chaining Behavior control (consecutive result codes requested; + * see ) */ +#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR +#define LDAP_REQUIRES_CHAINING 0x4110 +#define LDAP_CANNOT_CHAIN 0x4111 +#endif + /* API Error Codes * * Based on draft-ietf-ldap-c-api-xx diff --git a/include/slapi-plugin.h b/include/slapi-plugin.h index f8cc9f2150..dcb3a95a63 100644 --- a/include/slapi-plugin.h +++ b/include/slapi-plugin.h @@ -317,6 +317,8 @@ void *slapi_get_object_extension(int objecttype, void *object, void slapi_set_object_extension(int objecttype, void *object, int extensionhandle, void *extension); +int slapi_x_backend_get_flags( const Slapi_Backend *be, unsigned long *flags ); + /* parameters currently supported */ /* @@ -330,6 +332,20 @@ void slapi_set_object_extension(int objecttype, void *object, #define SLAPI_ATTR_FLAG_COLLECTIVE 0x0080 #define SLAPI_ATTR_FLAG_NOUSERMOD 0x0100 +/* + * Backend flags returned by slapi_x_backend_get_flags() + */ +#define SLAPI_BACKEND_FLAG_NOLASTMOD 0x0001U +#define SLAPI_BACKEND_FLAG_NO_SCHEMA_CHECK 0x0002U +#define SLAPI_BACKEND_FLAG_GLUE_INSTANCE 0x0010U /* a glue backend */ +#define SLAPI_BACKEND_FLAG_GLUE_SUBORDINATE 0x0020U /* child of a glue hierarchy */ +#define SLAPI_BACKEND_FLAG_GLUE_LINKED 0x0040U /* child is connected to parent */ +#define SLAPI_BACKEND_FLAG_OVERLAY 0x0080U /* this db struct is an overlay */ +#define SLAPI_BACKEND_FLAG_GLOBAL_OVERLAY 0x0100U /* this db struct is a global overlay */ +#define SLAPI_BACKEND_FLAG_SHADOW 0x8000U /* a shadow */ +#define SLAPI_BACKEND_FLAG_SYNC_SHADOW 0x1000U /* a sync shadow */ +#define SLAPI_BACKEND_FLAG_SLURP_SHADOW 0x2000U /* a slurp shadow */ + /* * ACL levels */ diff --git a/libraries/libldap/request.c b/libraries/libldap/request.c index ed9c6f3e22..41caa7f7b5 100644 --- a/libraries/libldap/request.c +++ b/libraries/libldap/request.c @@ -1125,7 +1125,7 @@ re_encode_request( LDAP *ld, scope = LDAP_SCOPE_BASE; break; case LDAP_SCOPE_SUBTREE: -#ifdef LDAP_FEATURE_SUBORDINATE_SCOPE +#ifdef LDAP_SCOPE_SUBORDINATE case LDAP_SCOPE_SUBORDINATE: #endif scope = LDAP_SCOPE_SUBTREE; diff --git a/libraries/libldap/url.c b/libraries/libldap/url.c index 0f6379f443..b6a669fce9 100644 --- a/libraries/libldap/url.c +++ b/libraries/libldap/url.c @@ -509,7 +509,7 @@ desc2str_len( LDAPURLDesc *u ) case LDAP_SCOPE_BASE: case LDAP_SCOPE_ONELEVEL: case LDAP_SCOPE_SUBTREE: -#ifdef LDAP_FEATURE_SUBORDINATE_SCOPE +#ifdef LDAP_SCOPE_SUBORDINATE case LDAP_SCOPE_SUBORDINATE: #endif switch ( u->lud_scope ) { @@ -525,7 +525,7 @@ desc2str_len( LDAPURLDesc *u ) len += STRLENOF( "sub" ); break; -#ifdef LDAP_FEATURE_SUBORDINATE_SCOPE +#ifdef LDAP_SCOPE_SUBORDINATE case LDAP_SCOPE_SUBORDINATE: len += STRLENOF( "subordinate" ); break; @@ -597,7 +597,7 @@ desc2str( LDAPURLDesc *u, char *s, int len ) case LDAP_SCOPE_BASE: case LDAP_SCOPE_ONELEVEL: case LDAP_SCOPE_SUBTREE: -#ifdef LDAP_FEATURE_SUBORDINATE_SCOPE +#ifdef LDAP_SCOPE_SUBORDINATE case LDAP_SCOPE_SUBORDINATE: #endif gotscope = 1; @@ -690,7 +690,7 @@ desc2str( LDAPURLDesc *u, char *s, int len ) len -= STRLENOF("sub"); break; -#ifdef LDAP_FEATURE_SUBORDINATE_SCOPE +#ifdef LDAP_SCOPE_SUBORDINATE case LDAP_SCOPE_SUBORDINATE: strcpy( &s[sofar], "children" ); sofar += STRLENOF("children"); diff --git a/servers/slapd/back-bdb/config.c b/servers/slapd/back-bdb/config.c index ec70bf0095..76d1c63adc 100644 --- a/servers/slapd/back-bdb/config.c +++ b/servers/slapd/back-bdb/config.c @@ -63,15 +63,6 @@ bdb_db_config( } else if ( strcasecmp( argv[0], "dbnosync" ) == 0 ) { bdb->bi_dbenv_xflags |= DB_TXN_NOSYNC; - /* slapadd/slapindex logging configuration */ - } else if ( strcasecmp( argv[0], "fasttool" ) == 0 ) { - if ( slapMode & SLAP_TOOL_MODE ) -#if DB_VERSION_FULL >= 0x04030015 - bdb->bi_dbenv_xflags |= DB_LOG_INMEMORY; -#else - bdb->bi_dbenv_xflags |= DB_TXN_NOT_DURABLE; -#endif - /* slapindex algorithm tuning */ } else if ( strcasecmp( argv[0], "linearindex" ) == 0 ) { bdb->bi_linear_index = 1; diff --git a/servers/slapd/back-bdb/init.c b/servers/slapd/back-bdb/init.c index 53e036a6de..32892d6014 100644 --- a/servers/slapd/back-bdb/init.c +++ b/servers/slapd/back-bdb/init.c @@ -41,27 +41,6 @@ struct berval bdb_uuid = BER_BVNULL; typedef void * db_malloc(size_t); typedef void * db_realloc(void *, size_t); -#if 0 -static int -bdb_open( BackendInfo *bi ) -{ - return 0; -} - -static int -bdb_destroy( BackendInfo *bi ) -{ - return 0; -} - -static int -bdb_close( BackendInfo *bi ) -{ - /* terminate the underlying database system */ - return 0; -} -#endif - static int bdb_db_init( BackendDB *be ) { @@ -140,7 +119,7 @@ bdb_db_open( BackendDB *be ) flags = DB_INIT_MPOOL | DB_THREAD | DB_CREATE; -if ( !( slapMode & SLAP_TOOL_QUICK )) + if ( !( slapMode & SLAP_TOOL_QUICK )) flags |= DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_TXN; #if 0 @@ -386,7 +365,6 @@ if ( !( slapMode & SLAP_TOOL_QUICK )) ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); } - /* open (and create) index databases */ return 0; } @@ -583,11 +561,6 @@ bdb_back_initialize( bi->bi_op_unbind = 0; -#if 0 /* DELETE ME */ - bi->bi_op_abandon = bdb_abandon; - bi->bi_op_cancel = bdb_cancel; -#endif - bi->bi_extended = bdb_extended; bi->bi_chk_referrals = bdb_referrals; diff --git a/servers/slapd/back-ldap/bind.c b/servers/slapd/back-ldap/bind.c index 998ce24537..bdf8078e2f 100644 --- a/servers/slapd/back-ldap/bind.c +++ b/servers/slapd/back-ldap/bind.c @@ -404,6 +404,8 @@ ldap_back_dobind_int( ldap_pvt_thread_mutex_lock( &lc->lc_mutex ); if ( !lc->lc_bound ) { + struct ldapinfo *li = (struct ldapinfo *)op->o_bd->be_private; + /* * FIXME: we need to let clients use proxyAuthz * otherwise we cannot do symmetric pools of servers; @@ -419,11 +421,17 @@ ldap_back_dobind_int( /* * if no bind took place yet, but the connection is bound * and the "idassert-authcDN" (or other ID) is set, - * then bind as the asserting ideintity and explicitly + * then bind as the asserting identity and explicitly * add the proxyAuthz control to every operation with the * dn bound to the connection as control value. + * This is done also if this is the authrizing backend, + * but the "override" flag is given to idassert. + * It allows to use SASL bind and yet proxyAuthz users */ - if ( op->o_conn != NULL && BER_BVISNULL( &lc->lc_bound_ndn ) ) { + if ( op->o_conn != NULL && + ( BER_BVISNULL( &lc->lc_bound_ndn ) || + ( li->idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ) ) + { (void)ldap_back_proxy_authz_bind( lc, op, rs ); goto done; } diff --git a/servers/slapd/back-ldap/chain.c b/servers/slapd/back-ldap/chain.c index 67927c40d7..d481abb7a4 100644 --- a/servers/slapd/back-ldap/chain.c +++ b/servers/slapd/back-ldap/chain.c @@ -29,7 +29,35 @@ #include "slap.h" #include "back-ldap.h" -static BackendInfo *lback; +#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR +#define SLAP_CH_RESOLVE_SHIFT SLAP_CONTROL_SHIFT +#define SLAP_CH_RESOLVE_MASK (0x3 << SLAP_CH_RESOLVE_SHIFT) +#define SLAP_CH_RESOLVE_CHAINING_PREFERRED (LDAP_CHAINING_PREFERRED << SLAP_CH_RESOLVE_SHIFT) +#define SLAP_CH_RESOLVE_CHAINING_REQUIRED (LDAP_CHAINING_REQUIRED << SLAP_CH_RESOLVE_SHIFT) +#define SLAP_CH_RESOLVE_REFERRALS_PREFERRED (LDAP_REFERRALS_PREFERRED << SLAP_CH_RESOLVE_SHIFT) +#define SLAP_CH_RESOLVE_REFERRALS_REQUIRED (LDAP_REFERRALS_REQUIRED << SLAP_CH_RESOLVE_SHIFT) +#define SLAP_CH_RESOLVE_DEFAULT SLAP_CH_RESOLVE_CHAINING_PREFERRED +#define SLAP_CH_CONTINUATION_SHIFT (SLAP_CH_RESOLVE_SHIFT + 2) +#define SLAP_CH_CONTINUATION_MASK (0x3 << SLAP_CH_CONTINUATION_SHIFT) +#define SLAP_CH_CONTINUATION_CHAINING_PREFERRED (LDAP_CHAINING_PREFERRED << SLAP_CH_CONTINUATION_SHIFT) +#define SLAP_CH_CONTINUATION_CHAINING_REQUIRED (LDAP_CHAINING_REQUIRED << SLAP_CH_CONTINUATION_SHIFT) +#define SLAP_CH_CONTINUATION_REFERRALS_PREFERRED (LDAP_REFERRALS_PREFERRED << SLAP_CH_CONTINUATION_SHIFT) +#define SLAP_CH_CONTINUATION_REFERRALS_REQUIRED (LDAP_REFERRALS_REQUIRED << SLAP_CH_CONTINUATION_SHIFT) +#define SLAP_CH_CONTINUATION_DEFAULT SLAP_CH_CONTINUATION_CHAINING_PREFERRED + +#define o_chaining o_ctrlflag[sc_chainingBehavior] +#define get_chaining(op) ((op)->o_chaining & SLAP_CONTROL_MASK) +#define get_chainingBehavior(op) ((op)->o_chaining & (SLAP_CH_RESOLVE_MASK|SLAP_CH_CONTINUATION_MASK)) +#define get_resolveBehavior(op) ((op)->o_chaining & SLAP_CH_RESOLVE_MASK) +#define get_continuationBehavior(op) ((op)->o_chaining & SLAP_CH_CONTINUATION_MASK) +#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ + +#define LDAP_CH_NONE ((void *)(0)) +#define LDAP_CH_RES ((void *)(1)) +#define LDAP_CH_ERR ((void *)(2)) + +static int sc_chainingBehavior; +static BackendInfo *lback; static int ldap_chain_operational( Operation *op, SlapReply *rs ) @@ -58,6 +86,11 @@ ldap_chain_cb_search_response( Operation *op, SlapReply *rs ) { assert( op->o_tag == LDAP_REQ_SEARCH ); + /* if in error, don't proceed any further */ + if ( op->o_callback->sc_private == LDAP_CH_ERR ) { + return 0; + } + if ( rs->sr_type == REP_SEARCH ) { Attribute **ap = &rs->sr_entry->e_attrs; @@ -79,9 +112,27 @@ ldap_chain_cb_search_response( Operation *op, SlapReply *rs ) return SLAP_CB_CONTINUE; + } else if ( rs->sr_type == REP_SEARCHREF ) { + /* if we get it here, it means the library was unable + * to chase the referral... */ + +#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR + if ( get_chaining( op ) > SLAP_CONTROL_IGNORED ) { + switch ( get_continuationBehavior( op ) ) { + case SLAP_CH_RESOLVE_CHAINING_REQUIRED: + op->o_callback->sc_private = LDAP_CH_ERR; + return -1; + + default: + break; + } + } +#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ + return SLAP_CB_CONTINUE; + } else if ( rs->sr_type == REP_RESULT ) { /* back-ldap tried to send result */ - op->o_callback->sc_private = (void *)(1); + op->o_callback->sc_private = LDAP_CH_RES; } return 0; @@ -94,8 +145,13 @@ ldap_chain_cb_search_response( Operation *op, SlapReply *rs ) static int ldap_chain_cb_response( Operation *op, SlapReply *rs ) { + /* if in error, don't proceed any further */ + if ( op->o_callback->sc_private == LDAP_CH_ERR ) { + return 0; + } + if ( rs->sr_type == REP_RESULT ) { - op->o_callback->sc_private = (void *)(1); + op->o_callback->sc_private = LDAP_CH_RES; } else if ( op->o_tag == LDAP_REQ_SEARCH && rs->sr_type == REP_SEARCH ) { @@ -115,7 +171,9 @@ ldap_chain_op( { slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; struct ldapinfo li, *lip = (struct ldapinfo *)on->on_bi.bi_private; - int rc; + + /* NOTE: returned if ref is empty... */ + int rc = LDAP_OTHER; if ( lip->url != NULL ) { op->o_bd->be_private = on->on_bi.bi_private; @@ -204,10 +262,44 @@ ldap_chain_response( Operation *op, SlapReply *rs ) struct ldapinfo li, *lip = (struct ldapinfo *)on->on_bi.bi_private; +#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR + int sr_err = rs->sr_err; + slap_reply_t sr_type = rs->sr_type; + slap_mask_t chain_mask = 0; + ber_len_t chain_shift = 0; +#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ + if ( rs->sr_err != LDAP_REFERRAL && rs->sr_type != REP_SEARCHREF ) { return SLAP_CB_CONTINUE; } +#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR + if ( rs->sr_err == LDAP_REFERRAL && get_chaining( op ) > SLAP_CONTROL_IGNORED ) { + switch ( get_resolveBehavior( op ) ) { + case SLAP_CH_RESOLVE_REFERRALS_PREFERRED: + case SLAP_CH_RESOLVE_REFERRALS_REQUIRED: + return SLAP_CB_CONTINUE; + + default: + chain_mask = SLAP_CH_RESOLVE_MASK; + chain_shift = SLAP_CH_RESOLVE_SHIFT; + break; + } + + } else if ( rs->sr_type == REP_SEARCHREF && get_chaining( op ) > SLAP_CONTROL_IGNORED ) { + switch ( get_continuationBehavior( op ) ) { + case SLAP_CH_CONTINUATION_REFERRALS_PREFERRED: + case SLAP_CH_CONTINUATION_REFERRALS_REQUIRED: + return SLAP_CB_CONTINUE; + + default: + chain_mask = SLAP_CH_CONTINUATION_MASK; + chain_shift = SLAP_CH_CONTINUATION_SHIFT; + break; + } + } +#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ + /* * TODO: add checks on who/when chain operations; e.g.: * a) what identities are authorized @@ -254,6 +346,14 @@ ldap_chain_response( Operation *op, SlapReply *rs ) char textbuf[ SLAP_TEXT_BUFLEN ]; size_t textlen = sizeof( textbuf ); +#if 0 + /* FIXME: op->o_bd is still set to the BackendDB + * structure of the database that tried to handle + * the operation and actually returned a referral + * ... */ + assert( SLAP_DBFLAGS( op->o_bd ) & SLAP_DBFLAG_GLOBAL_OVERLAY ); +#endif + /* global overlay: create entry */ /* NOTE: this is a hack to use the chain overlay * as global. I expect to be able to remove this @@ -362,6 +462,8 @@ ldap_chain_response( Operation *op, SlapReply *rs ) if ( rc == LDAP_SUCCESS && rs->sr_err == LDAP_SUCCESS ) { break; } + + rc = rs->sr_err; } op->o_req_dn = odn; @@ -393,12 +495,38 @@ ldap_chain_response( Operation *op, SlapReply *rs ) break; } - if ( sc2.sc_private == NULL ) { +#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR + if ( rc != LDAP_SUCCESS || sc2.sc_private == LDAP_CH_ERR ) { + if ( rs->sr_err == LDAP_CANNOT_CHAIN ) { + goto cannot_chain; + } + + switch ( ( get_chainingBehavior( op ) & chain_mask ) >> chain_shift ) { + case LDAP_CHAINING_REQUIRED: +cannot_chain:; + op->o_callback = NULL; + send_ldap_error( op, rs, LDAP_CANNOT_CHAIN, "operation cannot be completed without chaining" ); + break; + + default: + rc = SLAP_CB_CONTINUE; + rs->sr_err = sr_err; + rs->sr_type = sr_type; + break; + } + goto dont_chain; + } +#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ + + if ( sc2.sc_private == LDAP_CH_NONE ) { op->o_callback = NULL; rc = rs->sr_err = slap_map_api2result( rs ); send_ldap_result( op, rs ); } +#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR +dont_chain:; +#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ op->o_do_not_cache = cache; op->o_bd->be_private = private; op->o_callback = sc; @@ -423,9 +551,9 @@ ldap_chain_db_config( int rc; be->be_private = on->on_bi.bi_private; - if ( strncasecmp( argv[ 0 ], "chain-", sizeof( "chain-" ) - 1 ) == 0 ) { + if ( strncasecmp( argv[ 0 ], "chain-", STRLENOF( "chain-" ) ) == 0 ) { argv0 = argv[ 0 ]; - argv[ 0 ] = &argv[ 0 ][ sizeof( "chain-" ) - 1 ]; + argv[ 0 ] = &argv[ 0 ][ STRLENOF( "chain-" ) ]; } rc = lback->bi_db_config( be, fname, lineno, argc, argv ); if ( argv0 ) { @@ -460,6 +588,16 @@ ldap_chain_db_init( return rc; } +#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR +static int +ldap_chain_db_open( + BackendDB *be +) +{ + return overlay_register_control( be, LDAP_CONTROL_X_CHAINING_BEHAVIOR ); +} +#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ + static int ldap_chain_db_destroy( BackendDB *be @@ -476,13 +614,156 @@ ldap_chain_db_destroy( return rc; } +#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR +static int +ldap_chain_parse_ctrl( + Operation *op, + SlapReply *rs, + LDAPControl *ctrl ) +{ + ber_tag_t tag; + BerElement *ber; + ber_int_t mode, + behavior; + + if ( get_chaining( op ) != SLAP_CONTROL_NONE ) { + rs->sr_text = "Chaining behavior control specified multiple times"; + return LDAP_PROTOCOL_ERROR; + } + + if ( op->o_pagedresults != SLAP_CONTROL_NONE ) { + rs->sr_text = "Chaining behavior control specified with pagedResults control"; + return LDAP_PROTOCOL_ERROR; + } + + if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) { + mode = (SLAP_CH_RESOLVE_DEFAULT|SLAP_CH_CONTINUATION_DEFAULT); + + } else { + ber_len_t len; + + /* Parse the control value + * ChainingBehavior ::= SEQUENCE { + * resolveBehavior Behavior OPTIONAL, + * continuationBehavior Behavior OPTIONAL } + * + * Behavior :: = ENUMERATED { + * chainingPreferred (0), + * chainingRequired (1), + * referralsPreferred (2), + * referralsRequired (3) } + */ + + ber = ber_init( &ctrl->ldctl_value ); + if( ber == NULL ) { + rs->sr_text = "internal error"; + return LDAP_OTHER; + } + + tag = ber_scanf( ber, "{e" /* } */, &behavior ); + /* FIXME: since the whole SEQUENCE is optional, + * should we accept no enumerations at all? */ + if ( tag != LBER_ENUMERATED ) { + rs->sr_text = "Chaining behavior control: resolveBehavior decoding error"; + return LDAP_PROTOCOL_ERROR; + } + + switch ( behavior ) { + case LDAP_CHAINING_PREFERRED: + mode = SLAP_CH_RESOLVE_CHAINING_PREFERRED; + break; + + case LDAP_CHAINING_REQUIRED: + mode = SLAP_CH_RESOLVE_CHAINING_REQUIRED; + break; + + case LDAP_REFERRALS_PREFERRED: + mode = SLAP_CH_RESOLVE_REFERRALS_PREFERRED; + break; + + case LDAP_REFERRALS_REQUIRED: + mode = SLAP_CH_RESOLVE_REFERRALS_REQUIRED; + break; + + default: + rs->sr_text = "Chaining behavior control: unknown resolveBehavior"; + return LDAP_PROTOCOL_ERROR; + } + + tag = ber_peek_tag( ber, &len ); + if ( tag == LBER_ENUMERATED ) { + tag = ber_scanf( ber, "e", &behavior ); + if ( tag == LBER_ERROR ) { + rs->sr_text = "Chaining behavior control: continuationBehavior decoding error"; + return LDAP_PROTOCOL_ERROR; + } + } + + if ( tag == LBER_DEFAULT ) { + mode |= SLAP_CH_CONTINUATION_DEFAULT; + + } else { + switch ( behavior ) { + case LDAP_CHAINING_PREFERRED: + mode |= SLAP_CH_CONTINUATION_CHAINING_PREFERRED; + break; + + case LDAP_CHAINING_REQUIRED: + mode |= SLAP_CH_CONTINUATION_CHAINING_REQUIRED; + break; + + case LDAP_REFERRALS_PREFERRED: + mode |= SLAP_CH_CONTINUATION_REFERRALS_PREFERRED; + break; + + case LDAP_REFERRALS_REQUIRED: + mode |= SLAP_CH_CONTINUATION_REFERRALS_REQUIRED; + break; + + default: + rs->sr_text = "Chaining behavior control: unknown continuationBehavior"; + return LDAP_PROTOCOL_ERROR; + } + } + + if ( ( ber_scanf( ber, /* { */ "}") ) == LBER_ERROR ) { + rs->sr_text = "Chaining behavior control: decoding error"; + return LDAP_PROTOCOL_ERROR; + } + + (void) ber_free( ber, 1 ); + } + + op->o_chaining = mode | ( ctrl->ldctl_iscritical + ? SLAP_CONTROL_CRITICAL + : SLAP_CONTROL_NONCRITICAL ); + + return LDAP_SUCCESS; +} +#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ + static slap_overinst ldapchain; int chain_init( void ) { +#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR + int rc; + + rc = register_supported_control( LDAP_CONTROL_X_CHAINING_BEHAVIOR, + /* SLAP_CTRL_GLOBAL| */ SLAP_CTRL_ACCESS|SLAP_CTRL_HIDE, NULL, + ldap_chain_parse_ctrl, &sc_chainingBehavior ); + if ( rc != LDAP_SUCCESS ) { + fprintf( stderr, "Failed to register chaining behavior control: %d\n", rc ); + return rc; + } +#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ + ldapchain.on_bi.bi_type = "chain"; ldapchain.on_bi.bi_db_init = ldap_chain_db_init; +#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR + ldapchain.on_bi.bi_db_open = ldap_chain_db_open; +#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ ldapchain.on_bi.bi_db_config = ldap_chain_db_config; ldapchain.on_bi.bi_db_destroy = ldap_chain_db_destroy; diff --git a/servers/slapd/back-ldap/search.c b/servers/slapd/back-ldap/search.c index b42352614f..cd84f8dcda 100644 --- a/servers/slapd/back-ldap/search.c +++ b/servers/slapd/back-ldap/search.c @@ -234,13 +234,34 @@ fail:; } } else { + char **references = NULL; + rc = ldap_parse_result( lc->lc_ld, res, &rs->sr_err, &match.bv_val, (char **)&rs->sr_text, - NULL, &rs->sr_ctrls, 1 ); - if (rc != LDAP_SUCCESS ) { + &references, &rs->sr_ctrls, 1 ); + if ( rc != LDAP_SUCCESS ) { rs->sr_err = rc; } rs->sr_err = slap_map_api2result( rs ); + + if ( references ) { + int cnt; + + for ( cnt = 0; references[ cnt ]; cnt++ ) + /* NO OP */ ; + + rs->sr_ref = ch_calloc( cnt + 1, sizeof( struct berval ) ); + + for ( cnt = 0; references[ cnt ]; cnt++ ) { + ber_str2bv( references[ cnt ], 0, 0, &rs->sr_ref[ cnt ] ); + } + + /* cleanup */ + if ( references ) { + ldap_value_free( references ); + } + } + rc = 0; break; } @@ -283,12 +304,19 @@ finish:; rs->sr_matched = NULL; LDAP_FREE( match.bv_val ); } + if ( rs->sr_text ) { if ( !dontfreetext ) { LDAP_FREE( (char *)rs->sr_text ); } rs->sr_text = NULL; } + + if ( rs->sr_ref ) { + ber_bvarray_free( rs->sr_ref ); + rs->sr_ref = NULL; + } + if ( attrs ) { ch_free( attrs ); } diff --git a/servers/slapd/back-meta/add.c b/servers/slapd/back-meta/add.c index 15f13ee892..fe9af550d4 100644 --- a/servers/slapd/back-meta/add.c +++ b/servers/slapd/back-meta/add.c @@ -169,7 +169,7 @@ meta_back_add( Operation *op, SlapReply *rs ) attrs[ i ] = NULL; rs->sr_err = ldap_add_ext_s( lc->mc_conns[ candidate ].msc_ld, mdn.bv_val, - attrs, NULL, NULL ); + attrs, op->o_ctrls, NULL ); for ( --i; i >= 0; --i ) { free( attrs[ i ]->mod_bvalues ); free( attrs[ i ] ); diff --git a/servers/slapd/back-meta/bind.c b/servers/slapd/back-meta/bind.c index 36dc7af36c..0dde00f584 100644 --- a/servers/slapd/back-meta/bind.c +++ b/servers/slapd/back-meta/bind.c @@ -192,18 +192,11 @@ meta_back_do_single_bind( return -1; } - if ( op->o_ctrls ) { - rs->sr_err = ldap_set_option( lsc->msc_ld, - LDAP_OPT_SERVER_CONTROLS, op->o_ctrls ); - if ( rs->sr_err != LDAP_SUCCESS ) { - rs->sr_err = slap_map_api2result( rs ); - goto return_results; - } - } - /* FIXME: this fixes the bind problem right now; we need * to use the asynchronous version to get the "matched" * and more in case of failure ... */ + /* FIXME: should be check if at least some of the op->o_ctrls + * can/should be passed? */ rs->sr_err = ldap_sasl_bind( lsc->msc_ld, mdn.bv_val, LDAP_SASL_SIMPLE, &op->orb_cred, op->o_ctrls, NULL, &msgid ); @@ -308,17 +301,6 @@ meta_back_dobind( struct metaconn *lc, Operation *op ) continue; } - /* - * If required, set controls - */ - if ( op->o_ctrls ) { - if ( ldap_set_option( lsc->msc_ld, LDAP_OPT_SERVER_CONTROLS, - op->o_ctrls ) != LDAP_SUCCESS ) { - ( void )meta_clear_one_candidate( lsc, 1 ); - continue; - } - } - /* * If the target is already bound it is skipped */ @@ -346,8 +328,10 @@ meta_back_dobind( struct metaconn *lc, Operation *op ) BER_BVZERO( &lsc->msc_cred ); } + /* FIXME: should be check if at least some of the op->o_ctrls + * can/should be passed? */ rc = ldap_sasl_bind( lsc->msc_ld, "", LDAP_SASL_SIMPLE, &cred, - op->o_ctrls, NULL, &msgid ); + NULL, NULL, &msgid ); if ( rc == LDAP_SUCCESS ) { LDAPMessage *res; struct timeval tv = { 0, 0 }; diff --git a/servers/slapd/back-meta/compare.c b/servers/slapd/back-meta/compare.c index 9a808a9581..3418717f7e 100644 --- a/servers/slapd/back-meta/compare.c +++ b/servers/slapd/back-meta/compare.c @@ -144,7 +144,7 @@ meta_back_compare( Operation *op, SlapReply *rs ) */ rc = ldap_compare_ext( lc->mc_conns[ i ].msc_ld, mdn.bv_val, mapped_attr.bv_val, &mapped_value, - NULL, NULL, &msgid[ i ] ); + op->o_ctrls, NULL, &msgid[ i ] ); if ( mdn.bv_val != op->o_req_dn.bv_val ) { free( mdn.bv_val ); diff --git a/servers/slapd/back-meta/config.c b/servers/slapd/back-meta/config.c index 9682b2d7af..28b057ed01 100644 --- a/servers/slapd/back-meta/config.c +++ b/servers/slapd/back-meta/config.c @@ -172,7 +172,8 @@ meta_back_db_config( ludp->lud_dn[ 0 ] = '\0'; - for ( tmpludp = ludp->lud_next; tmpludp; tmpludp = tmpludp->lud_next ) { + /* check all, to apply the scope check on the first one */ + for ( tmpludp = ludp; tmpludp; tmpludp = tmpludp->lud_next ) { if ( tmpludp->lud_dn != NULL && tmpludp->lud_dn[ 0 ] != '\0' ) { fprintf( stderr, "%s: line %d: " "multiple URIs must have " @@ -181,6 +182,10 @@ meta_back_db_config( return( 1 ); } + + if ( tmpludp->lud_scope == LDAP_SCOPE_BASE ) { + tmpludp->lud_scope = LDAP_SCOPE_DEFAULT; + } } li->targets[ i ]->mt_uri = ldap_url_list2urls( ludp ); diff --git a/servers/slapd/back-meta/delete.c b/servers/slapd/back-meta/delete.c index 13f8f527d9..cd719c08d5 100644 --- a/servers/slapd/back-meta/delete.c +++ b/servers/slapd/back-meta/delete.c @@ -73,7 +73,7 @@ meta_back_delete( Operation *op, SlapReply *rs ) } (void)ldap_delete_ext_s( lc->mc_conns[ candidate ].msc_ld, mdn.bv_val, - NULL, NULL ); + op->o_ctrls, NULL ); if ( mdn.bv_val != op->o_req_dn.bv_val ) { free( mdn.bv_val ); diff --git a/servers/slapd/back-meta/modify.c b/servers/slapd/back-meta/modify.c index 40709354a4..cd0a3ec00e 100644 --- a/servers/slapd/back-meta/modify.c +++ b/servers/slapd/back-meta/modify.c @@ -183,7 +183,7 @@ meta_back_modify( Operation *op, SlapReply *rs ) modv[ i ] = 0; rs->sr_err = ldap_modify_ext_s( lc->mc_conns[ candidate ].msc_ld, mdn.bv_val, - modv, NULL, NULL ); + modv, op->o_ctrls, NULL ); cleanup:; if ( mdn.bv_val != op->o_req_dn.bv_val ) { diff --git a/servers/slapd/back-meta/modrdn.c b/servers/slapd/back-meta/modrdn.c index d4ea67f895..756ae36d38 100644 --- a/servers/slapd/back-meta/modrdn.c +++ b/servers/slapd/back-meta/modrdn.c @@ -119,7 +119,7 @@ meta_back_modrdn( Operation *op, SlapReply *rs ) op->orr_newrdn.bv_val, mnewSuperior.bv_val, op->orr_deleteoldrdn, - NULL, NULL ) != LDAP_SUCCESS; + op->o_ctrls, NULL ) != LDAP_SUCCESS; cleanup:; if ( mdn.bv_val != op->o_req_dn.bv_val ) { diff --git a/servers/slapd/back-meta/search.c b/servers/slapd/back-meta/search.c index cd2c3f7bc6..6bc693b64b 100644 --- a/servers/slapd/back-meta/search.c +++ b/servers/slapd/back-meta/search.c @@ -259,7 +259,7 @@ meta_back_search( Operation *op, SlapReply *rs ) rc = ldap_search_ext( lsc->msc_ld, mbase.bv_val, realscope, mfilter.bv_val, mapped_attrs, op->ors_attrsonly, - NULL, NULL, + op->o_ctrls, NULL, NULL, op->ors_slimit, &msgid[ i ] ); if ( mapped_attrs ) { free( mapped_attrs ); diff --git a/servers/slapd/back-relay/init.c b/servers/slapd/back-relay/init.c index 9cb0a91a75..d5a3d9ac15 100644 --- a/servers/slapd/back-relay/init.c +++ b/servers/slapd/back-relay/init.c @@ -97,10 +97,20 @@ relay_back_db_open( Backend *be ) if ( !BER_BVISNULL( &ri->ri_realsuffix ) ) { ri->ri_bd = select_backend( &ri->ri_realsuffix, 0, 1 ); + /* must be there: it was during config! */ assert( ri->ri_bd ); - /* FIXME: (somehow) copy supported controls ? */ + /* inherit controls */ + if ( ri->ri_bd->be_controls ) { + be->be_controls = ldap_charray_dup( ri->ri_bd->be_controls ); + } + + } else { + /* inherit all? */ + if ( frontendDB->be_controls ) { + be->be_controls = ldap_charray_dup( frontendDB->be_controls ); + } } return 0; diff --git a/servers/slapd/backend.c b/servers/slapd/backend.c index 105dffe4f9..084a825688 100644 --- a/servers/slapd/backend.c +++ b/servers/slapd/backend.c @@ -74,7 +74,7 @@ int backend_init(void) if((nBackendInfo != 0) || (backendInfo != NULL)) { /* already initialized */ Debug( LDAP_DEBUG_ANY, - "backend_init: already initialized.\n", 0, 0, 0 ); + "backend_init: already initialized\n", 0, 0, 0 ); return -1; } @@ -164,7 +164,8 @@ int backend_add(BackendInfo *aBackendInfo) /* startup a specific backend database */ int backend_startup_one(Backend *be) { - int rc = 0; + int rc = 0; + BackendInfo *bi = be->bd_info; assert(be); @@ -173,6 +174,17 @@ int backend_startup_one(Backend *be) LDAP_TAILQ_INIT( be->be_pending_csn_list ); + /* back-relay takes care of itself; so may do other */ + if ( be->be_controls == NULL ) { + if ( overlay_is_over( be ) ) { + bi = ((slap_overinfo *)be->bd_info->bi_private)->oi_orig; + } + + if ( bi->bi_controls ) { + be->be_controls = ldap_charray_dup( bi->bi_controls ); + } + } + Debug( LDAP_DEBUG_TRACE, "backend_startup: starting \"%s\"\n", be->be_suffix ? be->be_suffix[0].bv_val : "(unknown)", @@ -185,6 +197,32 @@ int backend_startup_one(Backend *be) rc, 0, 0 ); } } + + /* back-relay takes care of itself; so may do other */ + bi = be->bd_info; + if ( overlay_is_over( be ) ) { + bi = ((slap_overinfo *)be->bd_info->bi_private)->oi_orig; + } + + if ( bi->bi_controls ) { + if ( be->be_controls == NULL ) { + be->be_controls = ldap_charray_dup( bi->bi_controls ); + + } else { + int i; + + /* maybe not efficient, but it's startup and few dozens of controls... */ + for ( i = 0; bi->bi_controls[ i ]; i++ ) { + if ( !ldap_charray_inlist( be->be_controls, bi->bi_controls[ i ] ) ) { + rc = ldap_charray_add( &be->be_controls, bi->bi_controls[ i ] ); + if ( rc != 0 ) { + break; + } + } + } + } + } + return rc; } @@ -410,6 +448,9 @@ int backend_destroy(void) free( bd->be_rootpw.bv_val ); } acl_destroy( bd->be_acl, frontendDB->be_acl ); + if ( bd->be_controls ) { + ldap_charray_free( bd->be_controls ); + } } free( backendDB ); @@ -500,6 +541,7 @@ backend_db_init( be = &backends[nbackends++]; be->bd_info = bi; + be->be_def_limit = frontendDB->be_def_limit; be->be_dfltaccess = frontendDB->be_dfltaccess; @@ -513,11 +555,11 @@ backend_db_init( /* assign a default depth limit for alias deref */ be->be_max_deref_depth = SLAPD_DEFAULT_MAXDEREFDEPTH; - if(bi->bi_db_init) { + if ( bi->bi_db_init ) { rc = bi->bi_db_init( be ); } - if(rc != 0) { + if ( rc != 0 ) { fprintf( stderr, "database init failed (%s)\n", type ); nbackends--; return NULL; @@ -541,6 +583,7 @@ be_db_close( void ) if ( frontendDB->bd_info->bi_db_close ) { (*frontendDB->bd_info->bi_db_close)( frontendDB ); } + } Backend * @@ -803,25 +846,34 @@ backend_check_controls( if( ctrls ) { for( ; *ctrls != NULL ; ctrls++ ) { - if( (*ctrls)->ldctl_iscritical && !ldap_charray_inlist( - op->o_bd->be_controls, (*ctrls)->ldctl_oid ) ) + int cid; + if( slap_find_control_id( (*ctrls)->ldctl_oid, &cid ) == + LDAP_CONTROL_NOT_FOUND ) + { + /* unrecognized control */ + if ( (*ctrls)->ldctl_iscritical ) { + /* should not be reachable */ + Debug( LDAP_DEBUG_ANY, + "backend_check_controls: unrecognized control: %s\n", + (*ctrls)->ldctl_oid, 0, 0 ); + assert( 0 ); + } + + } else if ( !slap_global_control( op, (*ctrls)->ldctl_oid ) && + !ldap_charray_inlist( op->o_bd->be_controls, + (*ctrls)->ldctl_oid ) ) { - /* FIXME: standards compliance issue - * - * Per RFC 2251 (and LDAPBIS discussions), if the control + /* Per RFC 2251 (and LDAPBIS discussions), if the control * is recognized and appropriate for the operation (which * we've already verified), then the server should make - * use of the control when performing the operation - * (without regard to criticality). This code is incorrect - * on two counts. - * 1) a service error (e.g., unwillingToPerform) should be - * returned where a particular backend cannot service the - * operation, - * 2) this error should be returned irregardless of the - * criticality of the control. + * use of the control when performing the operation. + * + * Here we find that operation extended by the control + * is not unavailable in a particular context, hence the + * return of unwillingToPerform. */ rs->sr_text = "control unavailable in context"; - rs->sr_err = LDAP_UNAVAILABLE_CRITICAL_EXTENSION; + rs->sr_err = LDAP_UNWILLING_TO_PERFORM; break; } } @@ -1435,13 +1487,21 @@ backend_attribute( BER_BVZERO( &anlist[ 1 ].an_name ); rs.sr_attrs = anlist; - rs.sr_attr_flags = slap_attr_flags( rs.sr_attrs ); - - rc = backend_operational( op, &rs ); + /* NOTE: backend_operational() is also called + * when returning results, so it's supposed + * to do no harm to entries */ + rs.sr_entry = e; + rc = backend_operational( op, &rs ); + rs.sr_entry = NULL; + + if ( rc == LDAP_SUCCESS ) { + if ( rs.sr_operational_attrs ) { + freeattr = 1; + a = rs.sr_operational_attrs; - if ( rc == LDAP_SUCCESS && rs.sr_operational_attrs ) { - freeattr = 1; - a = rs.sr_operational_attrs; + } else { + rc = LDAP_NO_SUCH_ATTRIBUTE; + } } } @@ -1523,6 +1583,144 @@ freeit: if ( e != target ) { return rc; } +#ifdef LDAP_SLAPI +static int backend_compute_output_attr_access(computed_attr_context *c, Slapi_Attr *a, Slapi_Entry *e) +{ + struct berval *nval = (struct berval *)c->cac_private; + Operation *op = NULL; + + slapi_pblock_get( c->cac_pb, SLAPI_OPERATION, &op ); + if ( op == NULL ) { + return 1; + } + + return access_allowed( op, e, a->a_desc, nval, ACL_AUTH, NULL ) == 0; +} +#endif /* LDAP_SLAPI */ + +int +backend_access( + Operation *op, + Entry *target, + struct berval *edn, + AttributeDescription *entry_at, + struct berval *nval, + slap_access_t access, + slap_mask_t *mask ) +{ + Entry *e = NULL; + int rc = LDAP_INSUFFICIENT_ACCESS; + Backend *be = op->o_bd; + + /* pedantic */ + assert( op ); + assert( op->o_conn ); + assert( edn ); + assert( access > ACL_NONE ); + + op->o_bd = select_backend( edn, 0, 0 ); + + if ( target && dn_match( &target->e_nname, edn ) ) { + e = target; + + } else { + rc = be_entry_get_rw( op, edn, NULL, entry_at, 0, &e ); + } + + if ( e ) { + Attribute *a = NULL; + int freeattr = 0; + + if ( entry_at == NULL ) { + entry_at = slap_schema.si_ad_entry; + } + + if ( entry_at == slap_schema.si_ad_entry || entry_at == slap_schema.si_ad_children ) + { + if ( access_allowed_mask( op, e, entry_at, + NULL, access, NULL, mask ) == 0 ) + { + rc = LDAP_INSUFFICIENT_ACCESS; + + } else { + rc = LDAP_SUCCESS; + } + + } else { + a = attr_find( e->e_attrs, entry_at ); + if ( a == NULL ) { + SlapReply rs = { 0 }; + AttributeName anlist[ 2 ]; + + anlist[ 0 ].an_name = entry_at->ad_cname; + anlist[ 0 ].an_desc = entry_at; + BER_BVZERO( &anlist[ 1 ].an_name ); + rs.sr_attrs = anlist; + + rs.sr_attr_flags = slap_attr_flags( rs.sr_attrs ); + + /* NOTE: backend_operational() is also called + * when returning results, so it's supposed + * to do no harm to entries */ + rs.sr_entry = e; + rc = backend_operational( op, &rs ); + rs.sr_entry = NULL; + + if ( rc == LDAP_SUCCESS ) { + if ( rs.sr_operational_attrs ) { + freeattr = 1; + a = rs.sr_operational_attrs; + + } else { + rc = LDAP_NO_SUCH_OBJECT; + } + } + } + + if ( a ) { + if ( access_allowed_mask( op, e, entry_at, + nval, access, NULL, mask ) == 0 ) + { + rc = LDAP_INSUFFICIENT_ACCESS; + goto freeit; + } + rc = LDAP_SUCCESS; + } +#ifdef LDAP_SLAPI + else if ( op->o_pb ) { + /* try any computed attributes */ + computed_attr_context ctx; + + slapi_int_pblock_set_operation( op->o_pb, op ); + + ctx.cac_pb = op->o_pb; + ctx.cac_attrs = NULL; + ctx.cac_userattrs = 0; + ctx.cac_opattrs = 0; + ctx.cac_private = (void *)nval; + + rc = compute_evaluator( &ctx, entry_at->ad_cname.bv_val, e, backend_compute_output_attr_access ); + if ( rc == 1 ) { + rc = LDAP_INSUFFICIENT_ACCESS; + + } else { + rc = LDAP_SUCCESS; + } + } +#endif /* LDAP_SLAPI */ + } +freeit: if ( e != target ) { + be_entry_release_r( op, e ); + } + if ( freeattr ) { + attr_free( a ); + } + } + + op->o_bd = be; + return rc; +} + int backend_operational( Operation *op, SlapReply *rs ) @@ -1539,15 +1737,15 @@ int backend_operational( * and the backend supports specific operational attributes, * add them to the attribute list */ - if ( SLAP_OPATTRS( rs->sr_attr_flags ) || ( op->ors_attrs && - ad_inlist( slap_schema.si_ad_entryDN, op->ors_attrs ))) + if ( SLAP_OPATTRS( rs->sr_attr_flags ) || ( rs->sr_attrs && + ad_inlist( slap_schema.si_ad_entryDN, rs->sr_attrs ))) { *ap = slap_operational_entryDN( rs->sr_entry ); ap = &(*ap)->a_next; } - if ( SLAP_OPATTRS( rs->sr_attr_flags ) || ( op->ors_attrs && - ad_inlist( slap_schema.si_ad_subschemaSubentry, op->ors_attrs ))) + if ( SLAP_OPATTRS( rs->sr_attr_flags ) || ( rs->sr_attrs && + ad_inlist( slap_schema.si_ad_subschemaSubentry, rs->sr_attrs ))) { *ap = slap_operational_subschemaSubentry( op->o_bd ); ap = &(*ap)->a_next; @@ -1558,7 +1756,7 @@ int backend_operational( if ( SLAP_ISOVERLAY( be_orig )) op->o_bd = select_backend( be_orig->be_nsuffix, 0, 0 ); - if (( SLAP_OPATTRS( rs->sr_attr_flags ) || op->ors_attrs ) && + if (( SLAP_OPATTRS( rs->sr_attr_flags ) || rs->sr_attrs ) && op->o_bd && op->o_bd->be_operational != NULL ) { Attribute *a; diff --git a/servers/slapd/backover.c b/servers/slapd/backover.c index 6e396a5904..4f0082b0d6 100644 --- a/servers/slapd/backover.c +++ b/servers/slapd/backover.c @@ -467,6 +467,45 @@ overlay_is_inst( BackendDB *be, const char *over_type ) return 0; } +int +overlay_register_control( BackendDB *be, const char *oid ) +{ + int rc = 0; + int gotit = 0; + + if ( SLAP_DBFLAGS( be ) & SLAP_DBFLAG_GLOBAL_OVERLAY ) { + int i; + + /* add to all backends... */ + for ( i = 0; i < nBackendDB; i++ ) { + BackendDB *bd = &backendDB[i]; + + if ( be == bd ) { + gotit = 1; + } + + if ( bd->be_controls == NULL || + !ldap_charray_inlist( bd->be_controls, oid ) ) + { + rc = ldap_charray_add( &bd->be_controls, oid ); + if ( rc ) { + break; + } + } + } + + } + + if ( rc == 0 && !gotit && !ldap_charray_inlist( be->be_controls, oid ) ) { + rc = ldap_charray_add( &be->be_controls, oid ); + if ( rc ) { + return rc; + } + } + + return rc; +} + /* add an overlay to a particular backend. */ int overlay_config( BackendDB *be, const char *ov ) @@ -489,6 +528,13 @@ overlay_config( BackendDB *be, const char *ov ) oi->oi_orig = be->bd_info; oi->oi_bi = *be->bd_info; + /* NOTE: the first time a global overlay is configured, + * frontendDB gets this flag; it is used later by overlays + * to determine if they're stacked on top of the frontendDB */ + if ( oi->oi_orig == frontendDB->bd_info ) { + SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_GLOBAL_OVERLAY; + } + /* Save a pointer to ourself in bi_private. */ oi->oi_bi.bi_private = oi; diff --git a/servers/slapd/compare.c b/servers/slapd/compare.c index d6596c2487..9c41d57d41 100644 --- a/servers/slapd/compare.c +++ b/servers/slapd/compare.c @@ -274,6 +274,7 @@ fe_op_compare( Operation *op, SlapReply *rs ) send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "subschemaSubentry compare not supported" ); +#ifndef SLAP_COMPARE_IN_FRONTEND } else if ( ava.aa_desc == slap_schema.si_ad_hasSubordinates && op->o_bd->be_has_subordinates ) { @@ -281,9 +282,16 @@ fe_op_compare( Operation *op, SlapReply *rs ) rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &entry ); if ( rc == 0 && entry ) { - rc = op->o_bd->be_has_subordinates( op, entry, - &hasSubordinates ); - be_entry_release_r( op, entry ); + if ( ! access_allowed( op, entry, + ava.aa_desc, &ava.aa_value, ACL_COMPARE, NULL ) ) + { + rc = rs->sr_err = LDAP_INSUFFICIENT_ACCESS; + + } else { + rc = rs->sr_err = op->o_bd->be_has_subordinates( op, + entry, &hasSubordinates ); + be_entry_release_r( op, entry ); + } } if ( rc == 0 ) { @@ -293,20 +301,90 @@ fe_op_compare( Operation *op, SlapReply *rs ) ? LDAP_COMPARE_TRUE : LDAP_COMPARE_FALSE; if ( hasSubordinates == asserted ) { rs->sr_err = LDAP_COMPARE_TRUE; + } else { rs->sr_err = LDAP_COMPARE_FALSE; } + + } else { +#ifdef SLAP_ACL_HONOR_DISCLOSE + /* return error only if "disclose" + * is granted on the object */ + if ( backend_access( op, NULL, &op->o_req_ndn, + slap_schema.si_ad_entry, + NULL, ACL_DISCLOSE, NULL ) == LDAP_INSUFFICIENT_ACCESS ) + { + rs->sr_err = LDAP_NO_SUCH_OBJECT; + } +#endif /* SLAP_ACL_HONOR_DISCLOSE */ } + send_ldap_result( op, rs ); - if( rc == 0 ) rs->sr_err = LDAP_SUCCESS; + if ( rc == 0 ) { + rs->sr_err = LDAP_SUCCESS; + } } else if ( op->o_bd->be_compare ) { op->o_bd->be_compare( op, rs ); +#endif /* ! SLAP_COMPARE_IN_FRONTEND */ } else { - send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, - "operation not supported within namingContext" ); + /* do our best to compare that AVA + * + * NOTE: this code is used only + * if SLAP_COMPARE_IN_FRONTEND + * is #define'd (it's not by default) + * or if op->o_bd->be_compare is NULL. + * + * FIXME: one potential issue is that + * if SLAP_COMPARE_IN_FRONTEND overlays + * are not executed for compare. */ + BerVarray vals = NULL; + int rc = LDAP_OTHER; + + rs->sr_err = backend_attribute( op, NULL, &op->o_req_ndn, + ava.aa_desc, &vals, ACL_COMPARE ); + switch ( rs->sr_err ) { + default: +#ifdef SLAP_ACL_HONOR_DISCLOSE + /* return error only if "disclose" + * is granted on the object */ + if ( backend_access( op, NULL, &op->o_req_ndn, + slap_schema.si_ad_entry, + NULL, ACL_DISCLOSE, NULL ) + == LDAP_INSUFFICIENT_ACCESS ) + { + rs->sr_err = LDAP_NO_SUCH_OBJECT; + } +#endif /* SLAP_ACL_HONOR_DISCLOSE */ + break; + + case LDAP_SUCCESS: + if ( value_find_ex( op->oq_compare.rs_ava->aa_desc, + SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | + SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, + vals, &ava.aa_value, op->o_tmpmemctx ) == 0 ) + { + rs->sr_err = LDAP_COMPARE_TRUE; + break; + + } else { + rs->sr_err = LDAP_COMPARE_FALSE; + } + rc = LDAP_SUCCESS; + break; + } + + send_ldap_result( op, rs ); + + if ( rc == 0 ) { + rs->sr_err = LDAP_SUCCESS; + } + + if ( vals ) { + ber_bvarray_free_x( vals, op->o_tmpmemctx ); + } } #if defined( LDAP_SLAPI ) diff --git a/servers/slapd/controls.c b/servers/slapd/controls.c index 8d01149172..c201273eb5 100644 --- a/servers/slapd/controls.c +++ b/servers/slapd/controls.c @@ -115,7 +115,7 @@ static struct slap_control control_defs[] = { #ifdef LDAP_CONTROL_X_DOMAIN_SCOPE { LDAP_CONTROL_X_DOMAIN_SCOPE, (int)offsetof(struct slap_control_ids, sc_domainScope), - SLAP_CTRL_FRONTEND|SLAP_CTRL_SEARCH, NULL, + SLAP_CTRL_GLOBAL|SLAP_CTRL_SEARCH, NULL, parseDomainScope, LDAP_SLIST_ENTRY_INITIALIZER(next) }, #endif #ifdef LDAP_CONTROL_X_PERMISSIVE_MODIFY @@ -133,7 +133,7 @@ static struct slap_control control_defs[] = { #ifdef LDAP_CONTORL_X_SEARCH_OPTIONS { LDAP_CONTORL_X_SEARCH_OPTIONS, (int)offsetof(struct slap_control_ids, sc_searchOptions), - SLAP_CTRL_FRONTEND|SLAP_CTRL_SEARCH, NULL, + SLAP_CTRL_GLOBAL|SLAP_CTRL_SEARCH, NULL, parseSearchOptions, LDAP_SLIST_ENTRY_INITIALIZER(next) }, #endif #ifdef LDAP_CONTROL_SUBENTRIES @@ -158,7 +158,7 @@ static struct slap_control control_defs[] = { parseManageDSAit, LDAP_SLIST_ENTRY_INITIALIZER(next) }, { LDAP_CONTROL_PROXY_AUTHZ, (int)offsetof(struct slap_control_ids, sc_proxyAuthz), - SLAP_CTRL_FRONTEND|SLAP_CTRL_ACCESS, proxy_authz_extops, + SLAP_CTRL_GLOBAL|SLAP_CTRL_ACCESS, proxy_authz_extops, parseProxyAuthz, LDAP_SLIST_ENTRY_INITIALIZER(next) }, { NULL, 0, 0, NULL, 0, LDAP_SLIST_ENTRY_INITIALIZER(next) } }; @@ -380,6 +380,34 @@ slap_find_control_id( return LDAP_CONTROL_NOT_FOUND; } +int +slap_global_control( Operation *op, const char *oid ) +{ + struct slap_control *ctrl = find_ctrl( oid ); + + if ( ctrl == NULL ) { + /* should not be reachable */ + Debug( LDAP_DEBUG_ANY, + "slap_global_control: unrecognized control: %s\n", + oid, 0, 0 ); + assert( 0 ); + return 0; + } + + if ( ctrl->sc_mask & SLAP_CTRL_GLOBAL ) return 1; + + if (( op->o_tag & LDAP_REQ_SEARCH ) && + ( ctrl->sc_mask & SLAP_CTRL_GLOBAL_SEARCH )) + { + return 1; + } + + Debug( LDAP_DEBUG_ANY, + "slap_global_control: unavailable control: %s\n", + oid, 0, 0 ); + return 0; +} + void slap_free_ctrls( Operation *op, LDAPControl **ctrls ) @@ -612,17 +640,6 @@ int get_ctrls( goto return_results; } - if ( sc->sc_mask & SLAP_CTRL_FRONTEND ) { - /* kludge to disable backend_control() check */ - c->ldctl_iscritical = 0; - - } else if ( tagmask == SLAP_CTRL_SEARCH && - sc->sc_mask & SLAP_CTRL_FRONTEND_SEARCH ) - { - /* kludge to disable backend_control() check */ - c->ldctl_iscritical = 0; - } - } else if( c->ldctl_iscritical ) { /* unavailable CRITICAL control */ rs->sr_err = LDAP_UNAVAILABLE_CRITICAL_EXTENSION; diff --git a/servers/slapd/filterentry.c b/servers/slapd/filterentry.c index 5cc91fbb8c..005c6f7aa4 100644 --- a/servers/slapd/filterentry.c +++ b/servers/slapd/filterentry.c @@ -172,7 +172,7 @@ static int test_mra_filter( * one attribute, and SEARCH permissions can be checked * directly. */ - if( !access_allowed( op, e, + if ( !access_allowed( op, e, mra->ma_desc, &mra->ma_value, ACL_SEARCH, NULL ) ) { return LDAP_INSUFFICIENT_ACCESS; @@ -191,18 +191,20 @@ static int test_mra_filter( return LDAP_COMPARE_FALSE; } - for(a = attrs_find( e->e_attrs, mra->ma_desc ); + for ( a = attrs_find( e->e_attrs, mra->ma_desc ); a != NULL; a = attrs_find( a->a_next, mra->ma_desc ) ) { - struct berval *bv; + struct berval *bv; + int normalize_attribute = 0; + #ifdef LDAP_COMP_MATCH /* Component Matching */ - if( mra->ma_cf && mra->ma_rule->smr_usage & SLAP_MR_COMPONENT ) { + if ( mra->ma_cf && mra->ma_rule->smr_usage & SLAP_MR_COMPONENT ) { num_attr_vals = 0; if ( !a->a_comp_data ) { for ( ; - a->a_vals[num_attr_vals].bv_val != NULL; + !BER_BVISNULL( &a->a_vals[num_attr_vals] ); num_attr_vals++ ) { /* empty */; @@ -231,22 +233,25 @@ static int test_mra_filter( /* If ma_rule is not the same as the attribute's * normal rule, then we can't use the a_nvals. */ - if (mra->ma_rule == a->a_desc->ad_type->sat_equality) { + if ( mra->ma_rule == a->a_desc->ad_type->sat_equality ) { bv = a->a_nvals; + } else { bv = a->a_vals; + normalize_attribute = 1; } #ifdef LDAP_COMP_MATCH i = 0; #endif - for ( ; bv->bv_val != NULL; bv++ ) { + for ( ; !BER_BVISNULL( bv ); bv++ ) { int ret; int rc; const char *text; #ifdef LDAP_COMP_MATCH - if( mra->ma_cf && - mra->ma_rule->smr_usage & SLAP_MR_COMPONENT ) { + if ( mra->ma_cf && + mra->ma_rule->smr_usage & SLAP_MR_COMPONENT ) + { /* Check if decoded component trees are already linked */ if ( num_attr_vals ) { a->a_comp_data->cd_tree[i] = attr_converter( @@ -262,11 +267,53 @@ static int test_mra_filter( } else #endif { + struct berval nbv = BER_BVNULL; + + if ( normalize_attribute && mra->ma_rule->smr_normalize ) { + /* + + Document: draft-ietf-ldapbis-protocol + + 4.5.1. Search Request + ... + If the type field is present and the matchingRule is present, + the matchValue is compared against entry attributes of the + specified type. In this case, the matchingRule MUST be one + suitable for use with the specified type (see [Syntaxes]), + otherwise the filter item is Undefined. + + + In this case, since the matchingRule requires the assertion + value to be normalized, we normalize the attribute value + according to the syntax of the matchingRule. + + This should likely be done inside value_match(), by passing + the appropriate flags, but this is not done at present. + See ITS#3406. + */ + if ( mra->ma_rule->smr_normalize( + SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, + mra->ma_rule->smr_syntax, + mra->ma_rule, + bv, &nbv, memctx ) != LDAP_SUCCESS ) + { + /* FIXME: stop processing? */ + continue; + } + + } else { + nbv = *bv; + } + rc = value_match( &ret, a->a_desc, mra->ma_rule, 0, - bv, &mra->ma_value, &text ); + &nbv, &mra->ma_value, &text ); + + if ( nbv.bv_val != bv->bv_val ) { + memfree( nbv.bv_val, memctx ); + } } - if( rc != LDAP_SUCCESS ) return rc; + if ( rc != LDAP_SUCCESS ) return rc; if ( ret == 0 ) return LDAP_COMPARE_TRUE; } } @@ -279,9 +326,10 @@ static int test_mra_filter( struct berval *bv, value; const char *text = NULL; int rc; + int normalize_attribute = 0; /* check if matching is appropriate */ - if ( !mr_usable_with_at( mra->ma_rule, a->a_desc->ad_type )) { + if ( !mr_usable_with_at( mra->ma_rule, a->a_desc->ad_type ) ) { continue; } @@ -293,20 +341,21 @@ static int test_mra_filter( /* check search access */ if ( !access_allowed( op, e, - a->a_desc, &value, ACL_SEARCH, NULL ) ) { + a->a_desc, &value, ACL_SEARCH, NULL ) ) + { memfree( value.bv_val, memctx ); continue; } #ifdef LDAP_COMP_MATCH /* Component Matching */ - if( mra->ma_cf && - mra->ma_rule->smr_usage & SLAP_MR_COMPONENT) + if ( mra->ma_cf && + mra->ma_rule->smr_usage & SLAP_MR_COMPONENT ) { int ret; rc = value_match( &ret, a->a_desc, mra->ma_rule, 0, (struct berval*)a, (void*)mra, &text ); - if( rc != LDAP_SUCCESS ) break; + if ( rc != LDAP_SUCCESS ) break; if ( ret == 0 ) { rc = LDAP_COMPARE_TRUE; @@ -317,19 +366,42 @@ static int test_mra_filter( #endif /* check match */ - if (mra->ma_rule == a->a_desc->ad_type->sat_equality) { + if ( mra->ma_rule == a->a_desc->ad_type->sat_equality ) { bv = a->a_nvals; + } else { bv = a->a_vals; + normalize_attribute = 1; } - for ( ; bv->bv_val != NULL; bv++ ) { - int ret; - + for ( ; !BER_BVISNULL( bv ); bv++ ) { + int ret; + struct berval nbv = BER_BVNULL; + + if ( normalize_attribute && mra->ma_rule->smr_normalize ) { + /* see comment above */ + if ( mra->ma_rule->smr_normalize( + SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, + mra->ma_rule->smr_syntax, + mra->ma_rule, + bv, &nbv, memctx ) != LDAP_SUCCESS ) + { + /* FIXME: stop processing? */ + continue; + } + + } else { + nbv = *bv; + } + rc = value_match( &ret, a->a_desc, mra->ma_rule, 0, - bv, &value, &text ); + &nbv, &value, &text ); + + if ( nbv.bv_val != bv->bv_val ) { + memfree( nbv.bv_val, memctx ); + } - if( rc != LDAP_SUCCESS ) break; + if ( rc != LDAP_SUCCESS ) break; if ( ret == 0 ) { rc = LDAP_COMPARE_TRUE; @@ -378,7 +450,7 @@ static int test_mra_filter( const char *text = NULL; /* check if matching is appropriate */ - if ( !mr_usable_with_at( mra->ma_rule, ad->ad_type )) { + if ( !mr_usable_with_at( mra->ma_rule, ad->ad_type ) ) { continue; } @@ -407,7 +479,7 @@ static int test_mra_filter( if ( rc == LDAP_SUCCESS && ret == 0 ) rc = LDAP_COMPARE_TRUE; - if( rc != LDAP_SUCCESS ) { + if ( rc != LDAP_SUCCESS ) { ldap_dnfree_x( dn, memctx ); return rc; } @@ -532,7 +604,7 @@ test_ava_filter( continue; } - for ( bv = a->a_nvals; bv->bv_val != NULL; bv++ ) { + for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) { int ret, match; const char *text; @@ -721,7 +793,7 @@ test_substrings_filter( continue; } - for ( bv = a->a_nvals; bv->bv_val != NULL; bv++ ) { + for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) { int ret, match; const char *text; diff --git a/servers/slapd/frontend.c b/servers/slapd/frontend.c index e1fca24d32..bf9635b875 100644 --- a/servers/slapd/frontend.c +++ b/servers/slapd/frontend.c @@ -42,8 +42,8 @@ #include "slapi/slapi.h" #endif -BackendInfo slap_frontendInfo; -BackendDB slap_frontendDB; +static BackendInfo slap_frontendInfo; +static BackendDB slap_frontendDB; BackendDB *frontendDB; int @@ -87,6 +87,7 @@ frontend_init( void ) /* known controls */ frontendDB->bd_info->bi_controls = slap_known_controls; + frontendDB->be_controls = ldap_charray_dup( slap_known_controls ); /* calls */ frontendDB->bd_info->bi_op_abandon = fe_op_abandon; diff --git a/servers/slapd/main.c b/servers/slapd/main.c index d458acb033..c88876e046 100644 --- a/servers/slapd/main.c +++ b/servers/slapd/main.c @@ -259,7 +259,6 @@ int main( int argc, char **argv ) char *serverName; int serverMode = SLAP_SERVER_MODE; - struct berval cookie = BER_BVNULL; struct sync_cookie *scp = NULL; struct sync_cookie *scp_entry = NULL; @@ -356,8 +355,7 @@ int main( int argc, char **argv ) case 'c': /* provide sync cookie, override if exist in replica */ scp = (struct sync_cookie *) ch_calloc( 1, sizeof( struct sync_cookie )); - ber_str2bv( optarg, strlen( optarg ), 1, &cookie ); - ber_bvarray_add( &scp->octet_str, &cookie ); + ber_str2bv( optarg, 0, 1, &scp->octet_str ); slap_parse_sync_cookie( scp ); LDAP_STAILQ_FOREACH( scp_entry, &slap_sync_cookie, sc_next ) { diff --git a/servers/slapd/matchedValues.c b/servers/slapd/matchedValues.c index b95765ef93..2ef1d934e8 100644 --- a/servers/slapd/matchedValues.c +++ b/servers/slapd/matchedValues.c @@ -171,7 +171,7 @@ test_ava_vrFilter( if( mr == NULL ) continue; bv = a->a_nvals; - for ( j=0; bv->bv_val != NULL; bv++, j++ ) { + for ( j=0; !BER_BVISNULL( bv ); bv++, j++ ) { int rc, match; const char *text; @@ -218,7 +218,7 @@ test_presence_vrFilter( if ( !is_ad_subtype( a->a_desc, desc ) ) continue; - for ( bv = a->a_vals, j=0; bv->bv_val != NULL; bv++, j++ ); + for ( bv = a->a_vals, j = 0; !BER_BVISNULL( bv ); bv++, j++ ); memset( (*e_flags)[i], 1, j); } @@ -245,7 +245,7 @@ test_substrings_vrFilter( if( mr == NULL ) continue; bv = a->a_nvals; - for ( j = 0; bv->bv_val != NULL; bv++, j++ ) { + for ( j = 0; !BER_BVISNULL( bv ); bv++, j++ ) { int rc, match; const char *text; @@ -270,10 +270,11 @@ test_mra_vrFilter( MatchingRuleAssertion *mra, char ***e_flags ) { - int i, j; + int i, j; - for ( i=0; a != NULL; a = a->a_next, i++ ) { - struct berval *bv, assertedValue; + for ( i = 0; a != NULL; a = a->a_next, i++ ) { + struct berval *bv, assertedValue; + int normalize_attribute = 0; if ( mra->ma_desc ) { if ( !is_ad_subtype( a->a_desc, mra->ma_desc ) ) { @@ -294,23 +295,47 @@ test_mra_vrFilter( SLAP_MR_EXT|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX, &mra->ma_value, &assertedValue, &text, op->o_tmpmemctx ); - if( rc != LDAP_SUCCESS ) continue; + if ( rc != LDAP_SUCCESS ) continue; } /* check match */ - if (mra->ma_rule == a->a_desc->ad_type->sat_equality) { + if ( mra->ma_rule == a->a_desc->ad_type->sat_equality ) { bv = a->a_nvals; + } else { bv = a->a_vals; + normalize_attribute = 1; } - for ( j = 0; bv->bv_val != NULL; bv++, j++ ) { - int rc, match; - const char *text; + for ( j = 0; !BER_BVISNULL( bv ); bv++, j++ ) { + int rc, match; + const char *text; + struct berval nbv = BER_BVNULL; + + if ( normalize_attribute && mra->ma_rule->smr_normalize ) { + /* see comment in filterentry.c */ + if ( mra->ma_rule->smr_normalize( + SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, + mra->ma_rule->smr_syntax, + mra->ma_rule, + bv, &nbv, op->o_tmpmemctx ) != LDAP_SUCCESS ) + { + /* FIXME: stop processing? */ + continue; + } + + } else { + nbv = *bv; + } rc = value_match( &match, a->a_desc, mra->ma_rule, 0, - bv, &assertedValue, &text ); - if( rc != LDAP_SUCCESS ) return rc; + &nbv, &assertedValue, &text ); + + if ( nbv.bv_val != bv->bv_val ) { + op->o_tmpfree( nbv.bv_val, op->o_tmpmemctx ); + } + + if ( rc != LDAP_SUCCESS ) return rc; if ( match == 0 ) { (*e_flags)[i][j] = 1; diff --git a/servers/slapd/mr.c b/servers/slapd/mr.c index 89381cc38b..976721669c 100644 --- a/servers/slapd/mr.c +++ b/servers/slapd/mr.c @@ -217,9 +217,7 @@ register_matching_rule( int code; const char *err; - if( def->mrd_usage == SLAP_MR_NONE && - def->mrd_compat_syntaxes == NULL ) - { + if( def->mrd_usage == SLAP_MR_NONE && def->mrd_compat_syntaxes == NULL ) { Debug( LDAP_DEBUG_ANY, "register_matching_rule: not usable %s\n", def->mrd_desc, 0, 0 ); @@ -228,10 +226,9 @@ register_matching_rule( if( def->mrd_associated != NULL ) { amr = mr_find( def->mrd_associated ); - if( amr == NULL ) { - Debug( LDAP_DEBUG_ANY, "register_matching_rule: could not locate " - "associated matching rule %s for %s\n", + Debug( LDAP_DEBUG_ANY, "register_matching_rule: " + "could not locate associated matching rule %s for %s\n", def->mrd_associated, def->mrd_desc, 0 ); return -1; @@ -243,17 +240,15 @@ register_matching_rule( if (( def->mrd_usage & SLAP_MR_EQUALITY ) && (( def->mrd_usage & SLAP_MR_SUBTYPE_MASK ) != SLAP_MR_NONE )) { - Debug( LDAP_DEBUG_ANY, - "register_matching_rule: inappropriate (approx) association " - "%s for %s\n", + Debug( LDAP_DEBUG_ANY, "register_matching_rule: " + "inappropriate (approx) association %s for %s\n", def->mrd_associated, def->mrd_desc, 0 ); return -1; } } else if (!( amr->smr_usage & SLAP_MR_EQUALITY )) { - Debug( LDAP_DEBUG_ANY, - "register_matching_rule: inappropriate (equalilty) association " - "%s for %s\n", + Debug( LDAP_DEBUG_ANY, "register_matching_rule: " + "inappropriate (equalilty) association %s for %s\n", def->mrd_associated, def->mrd_desc, 0 ); return -1; } diff --git a/servers/slapd/overlays/ppolicy.c b/servers/slapd/overlays/ppolicy.c index 11bd2ca7ee..f572875fef 100644 --- a/servers/slapd/overlays/ppolicy.c +++ b/servers/slapd/overlays/ppolicy.c @@ -1706,6 +1706,14 @@ ppolicy_db_init( return 0; } +static int +ppolicy_db_open( + BackendDB *be +) +{ + return overlay_register_control( be, LDAP_CONTROL_PASSWORDPOLICYREQUEST ); +} + static int ppolicy_close( BackendDB *be @@ -1802,7 +1810,7 @@ int ppolicy_init() } code = register_supported_control( LDAP_CONTROL_PASSWORDPOLICYREQUEST, - SLAP_CTRL_ADD|SLAP_CTRL_BIND|SLAP_CTRL_MODIFY, extops, + SLAP_CTRL_ADD|SLAP_CTRL_BIND|SLAP_CTRL_MODIFY|SLAP_CTRL_HIDE, extops, ppolicy_parseCtrl, &ppolicy_cid ); if ( code != LDAP_SUCCESS ) { fprintf( stderr, "Failed to register control %d\n", code ); @@ -1813,6 +1821,7 @@ int ppolicy_init() ppolicy.on_bi.bi_type = "ppolicy"; ppolicy.on_bi.bi_db_init = ppolicy_db_init; + ppolicy.on_bi.bi_db_open = ppolicy_db_open; ppolicy.on_bi.bi_db_config = ppolicy_config; ppolicy.on_bi.bi_db_close = ppolicy_close; diff --git a/servers/slapd/overlays/syncprov.c b/servers/slapd/overlays/syncprov.c index 8b5ca2077b..aa51bcd07e 100644 --- a/servers/slapd/overlays/syncprov.c +++ b/servers/slapd/overlays/syncprov.c @@ -2012,6 +2012,11 @@ syncprov_db_open( Attribute *a; int rc; + rc = overlay_register_control( be, LDAP_CONTROL_SYNC ); + if ( rc ) { + return rc; + } + connection_fake_init( &conn, op, thrctx ); op->o_bd = be; op->o_dn = be->be_rootdn; diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h index bacc1b3772..133ecb8d00 100644 --- a/servers/slapd/proto-slap.h +++ b/servers/slapd/proto-slap.h @@ -291,6 +291,15 @@ LDAP_SLAPD_F (int) backend_attribute LDAP_P(( slap_access_t access )); +LDAP_SLAPD_F (int) backend_access LDAP_P(( + Operation *op, + Entry *target, + struct berval *edn, + AttributeDescription *entry_at, + struct berval *nval, + slap_access_t access, + slap_mask_t *mask )); + LDAP_SLAPD_F (int) backend_operational LDAP_P(( Operation *op, SlapReply *rs @@ -315,6 +324,9 @@ LDAP_SLAPD_F (slap_overinst *) overlay_next LDAP_P(( slap_overinst *on )); LDAP_SLAPD_F (slap_overinst *) overlay_find LDAP_P(( const char *name )); LDAP_SLAPD_F (int) overlay_is_over LDAP_P(( BackendDB *be )); LDAP_SLAPD_F (int) overlay_is_inst LDAP_P(( BackendDB *be, const char *name )); +LDAP_SLAPD_F (int) overlay_register_control LDAP_P(( + BackendDB *be, + const char *oid )); /* * ch_malloc.c @@ -413,8 +425,12 @@ LDAP_SLAPD_F (int) register_supported_control LDAP_P(( LDAP_SLAPD_F (int) slap_controls_init LDAP_P ((void)); LDAP_SLAPD_F (void) controls_destroy LDAP_P ((void)); LDAP_SLAPD_F (int) controls_root_dse_info LDAP_P ((Entry *e)); -LDAP_SLAPD_F (int) get_supported_controls LDAP_P (( char ***ctrloidsp, slap_mask_t **ctrlmasks )); -LDAP_SLAPD_F (int) slap_find_control_id LDAP_P (( const char *oid, int *cid )); +LDAP_SLAPD_F (int) get_supported_controls LDAP_P (( + char ***ctrloidsp, slap_mask_t **ctrlmasks )); +LDAP_SLAPD_F (int) slap_find_control_id LDAP_P (( + const char *oid, int *cid )); +LDAP_SLAPD_F (int) slap_global_control LDAP_P (( + Operation *op, const char *oid )); /* * config.c @@ -422,9 +438,7 @@ LDAP_SLAPD_F (int) slap_find_control_id LDAP_P (( const char *oid, int *cid )); LDAP_SLAPD_F (int) read_config LDAP_P(( const char *fname, int depth )); LDAP_SLAPD_F (void) config_destroy LDAP_P ((void)); LDAP_SLAPD_F (char **) slap_str2clist LDAP_P(( - char ***, - char *, - const char * )); + char ***, char *, const char * )); #ifdef LDAP_SLAPI LDAP_SLAPD_V (int) slapi_plugins_used; #endif diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h index 79d3a38c13..08566e4730 100644 --- a/servers/slapd/slap.h +++ b/servers/slapd/slap.h @@ -1564,7 +1564,11 @@ struct slap_backend_db { */ #define be_has_subordinates bd_info->bi_has_subordinates -#define be_controls bd_info->bi_controls + /* supported controls */ + /* NOTE: this stores a duplicate of the control OIDs as listed + * in bd_info->bi_controls at database startup; later on, + * controls may be added run-time, e.g. by overlays */ + char **be_controls; #define be_connection_init bd_info->bi_connection_init #define be_connection_destroy bd_info->bi_connection_destroy @@ -1589,7 +1593,8 @@ struct slap_backend_db { #define SLAP_DBFLAG_GLUE_INSTANCE 0x0010U /* a glue backend */ #define SLAP_DBFLAG_GLUE_SUBORDINATE 0x0020U /* child of a glue hierarchy */ #define SLAP_DBFLAG_GLUE_LINKED 0x0040U /* child is connected to parent */ -#define SLAP_DBFLAG_OVERLAY 0x0080U /* this db struct is an overlay */ +#define SLAP_DBFLAG_OVERLAY 0x0080U /* this db struct is an overlay */ +#define SLAP_DBFLAG_GLOBAL_OVERLAY 0x0100U /* this db struct is a global overlay */ #define SLAP_DBFLAG_SHADOW 0x8000U /* a shadow */ #define SLAP_DBFLAG_SYNC_SHADOW 0x1000U /* a sync shadow */ #define SLAP_DBFLAG_SLURP_SHADOW 0x2000U /* a slurp shadow */ @@ -2558,8 +2563,8 @@ typedef struct slap_counters_t { #define SLAP_CTRL_HIDE 0x80000000U #endif -#define SLAP_CTRL_FRONTEND 0x00800000U -#define SLAP_CTRL_FRONTEND_SEARCH 0x00010000U /* for NOOP */ +#define SLAP_CTRL_GLOBAL 0x00800000U +#define SLAP_CTRL_GLOBAL_SEARCH 0x00010000U /* for NOOP */ #define SLAP_CTRL_OPFLAGS 0x0000FFFFU #define SLAP_CTRL_ABANDON 0x00000001U diff --git a/servers/slapd/slapcommon.c b/servers/slapd/slapcommon.c index c768f52f3e..41642c6ced 100644 --- a/servers/slapd/slapcommon.c +++ b/servers/slapd/slapcommon.c @@ -60,7 +60,7 @@ usage( int tool, const char *progname ) case SLAPADD: options = "\n\t[-n databasenumber | -b suffix]\n" - "\t[-l ldiffile] [-u] [-w]\n"; + "\t[-l ldiffile] [-q] [-u] [-w]\n"; break; case SLAPAUTH: @@ -77,7 +77,7 @@ usage( int tool, const char *progname ) break; case SLAPINDEX: - options = "\n\t[-n databasenumber | -b suffix]\n"; + options = "\n\t[-n databasenumber | -b suffix] [-q]\n"; break; case SLAPTEST: @@ -151,7 +151,7 @@ slap_tool_init( break; case SLAPINDEX: - options = "b:cd:f:n:v"; + options = "b:cd:f:n:qv"; mode |= SLAP_TOOL_READMAIN; break;