*
* Copyright 2003-2009 The OpenLDAP Foundation.
* Portions Copyright 2003 IBM Corporation.
- * Portions Copyright 2003 Symas Corporation.
+ * Portions Copyright 2003-2009 Symas Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
struct query_template_s *qtemp; /* template of the query */
time_t expiry_time; /* time till the query is considered invalid */
time_t refresh_time; /* time till the query is refreshed */
+ time_t bindref_time; /* time till the bind is refreshed */
unsigned long answerable_cnt; /* how many times it was answerable */
int refcnt; /* references since last refresh */
ldap_pvt_thread_mutex_t answerable_cnt_mutex;
CachedQuery* query_last; /* oldest query cached for the template */
ldap_pvt_thread_rdwr_t t_rwlock; /* Rd/wr lock for accessing queries in the template */
struct berval querystr; /* Filter string corresponding to the QT */
+ struct berval bindbase; /* base DN for Bind request */
+ struct berval bindfilterstr; /* Filter string for Bind request */
+ Filter *bindfilter;
+ int bindscope;
int attr_set_index; /* determines the projected attributes */
int no_of_queries; /* Total number of queries in the template */
time_t ttl; /* TTL for the queries of this template */
time_t negttl; /* TTL for negative results */
time_t limitttl; /* TTL for sizelimit exceeding results */
time_t ttr; /* time to refresh */
+ time_t bindttr; /* TTR for cached binds */
struct attr_set t_attrs; /* filter attrs + attr_set */
} QueryTemplate;
#define PCACHE_RESPONSE_CB_HEAD 0
#define PCACHE_RESPONSE_CB_TAIL 1
char defer_db_open; /* defer open for online add */
+ char cache_binds; /* cache binds or just passthru */
time_t cc_period; /* interval between successive consistency checks (sec) */
#define PCACHE_CC_PAUSED 1
AttributeDescription **adp;
} s_ad[] = {
{ "( PCacheAttributes:1 "
- "NAME 'queryId' "
+ "NAME 'pcacheQueryID' "
"DESC 'ID of query the entry belongs to, formatted as a UUID' "
"EQUALITY octetStringMatch "
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.40{64} "
"USAGE directoryOperation )",
&ad_queryId },
{ "( PCacheAttributes:2 "
- "NAME 'cachedQueryURL' "
+ "NAME 'pcacheQueryURL' "
"DESC 'URI describing a cached query' "
"EQUALITY caseExactMatch "
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 "
filter2template(
Operation *op,
Filter *f,
- struct berval *fstr,
- AttributeName** filter_attrs,
- int* filter_cnt,
- int* filter_got_oc );
+ struct berval *fstr );
static CachedQuery *
add_query(
return 0;
}
+static int
+template_attrs( char *template, struct attr_set *set, AttributeName **ret,
+ const char **text )
+{
+ int got_oc = 0;
+ int alluser = 0;
+ int allop = 0;
+ int i;
+ int attr_cnt;
+ int t_cnt = 0;
+ struct berval bv;
+ char *p1, *p2;
+ AttributeDescription *ad;
+ AttributeName *attrs;
+
+ p1 = template;
+
+ *ret = NULL;
+
+ attrs = ch_malloc(( set->count+1 )*sizeof(AttributeName));
+ for ( i=0; i < set->count; i++ )
+ attrs[i] = set->attrs[i];
+ attr_cnt = i;
+ alluser = an_find( attrs, slap_bv_all_user_attrs );
+ allop = an_find( attrs, slap_bv_all_operational_attrs );
+
+ for (;;) {
+ while ( *p1 == '(' || *p1 == '&' || *p1 == '|' ) p1++;
+ p2 = strchr( p1, '=' );
+ if ( !p2 )
+ break;
+ if ( p2[-1] == '<' || p2[-1] == '>' ) p2--;
+ bv.bv_val = p1;
+ bv.bv_len = p2 - p1;
+ ad = NULL;
+ i = slap_bv2ad( &bv, &ad, text );
+ if ( i ) {
+ ch_free( attrs );
+ return -1;
+ }
+ t_cnt++;
+
+ if ( ad == slap_schema.si_ad_objectClass )
+ got_oc = 1;
+
+ if ( is_at_operational(ad->ad_type)) {
+ if ( allop ) {
+ goto bottom;
+ }
+ } else if ( alluser ) {
+ goto bottom;
+ }
+ if ( !ad_inlist( ad, attrs )) {
+ attrs = (AttributeName *)ch_realloc(attrs,
+ (attr_cnt + 2)*sizeof(AttributeName));
+
+ attrs[attr_cnt].an_desc = ad;
+ attrs[attr_cnt].an_name = ad->ad_cname;
+ attrs[attr_cnt].an_oc = NULL;
+ attrs[attr_cnt].an_flags = 0;
+ BER_BVZERO( &attrs[attr_cnt+1].an_name );
+ attr_cnt++;
+ }
+
+bottom:
+ p1 = p2+2;
+ }
+ if ( !t_cnt ) {
+ *text = "couldn't parse template";
+ return -1;
+ }
+ if ( !got_oc && !( set->flags & PC_GOT_OC )) {
+ attrs = (AttributeName *)ch_realloc(attrs,
+ (attr_cnt + 2)*sizeof(AttributeName));
+
+ ad = slap_schema.si_ad_objectClass;
+ attrs[attr_cnt].an_desc = ad;
+ attrs[attr_cnt].an_name = ad->ad_cname;
+ attrs[attr_cnt].an_oc = NULL;
+ attrs[attr_cnt].an_flags = 0;
+ BER_BVZERO( &attrs[attr_cnt+1].an_name );
+ attr_cnt++;
+ }
+ *ret = attrs;
+ return attr_cnt;
+}
+
/*
* Turn an URL representing a formerly cached query into a cached query,
* and try to cache it
tempstr.bv_val = ch_malloc( strlen( lud->lud_filter ) + 1 );
tempstr.bv_len = 0;
- if ( filter2template( op, query.filter, &tempstr, NULL, NULL, NULL ) ) {
+ if ( filter2template( op, query.filter, &tempstr ) ) {
ch_free( tempstr.bv_val );
rc = -1;
goto error;
op->ors_deref = LDAP_DEREF_NEVER;
op->ors_slimit = SLAP_NO_LIMIT;
op->ors_tlimit = SLAP_NO_LIMIT;
+ op->ors_limit = NULL;
op->ors_filter = &filter;
op->ors_filterstr.bv_val = filter_str;
op->ors_filterstr.bv_len = strlen(filter_str);
filter2template(
Operation *op,
Filter *f,
- struct berval *fstr,
- AttributeName** filter_attrs,
- int* filter_cnt,
- int* filter_got_oc )
+ struct berval *fstr )
{
AttributeDescription *ad;
int len, ret;
fstr->bv_len++;
for ( f = f->f_list; f != NULL; f = f->f_next ) {
- rc = filter2template( op, f, fstr, filter_attrs, filter_cnt,
- filter_got_oc );
+ rc = filter2template( op, f, fstr );
if ( rc ) break;
}
fstr->bv_val[fstr->bv_len++] = ')';
return -1;
}
- if ( filter_attrs != NULL ) {
- *filter_attrs = (AttributeName *)op->o_tmprealloc(*filter_attrs,
- (*filter_cnt + 2)*sizeof(AttributeName), op->o_tmpmemctx);
-
- (*filter_attrs)[*filter_cnt].an_desc = ad;
- (*filter_attrs)[*filter_cnt].an_name = ad->ad_cname;
- (*filter_attrs)[*filter_cnt].an_oc = NULL;
- (*filter_attrs)[*filter_cnt].an_flags = 0;
- BER_BVZERO( &(*filter_attrs)[*filter_cnt+1].an_name );
- (*filter_cnt)++;
- if ( ad == slap_schema.si_ad_objectClass )
- *filter_got_oc = 1;
- }
-
return 0;
}
+typedef struct bindinfo {
+ CachedQuery *bi_query;
+ struct berval *bi_querystr;
+ struct berval *bi_base;
+ Filter *bi_filter;
+ int bi_scope;
+ int bi_hashed;
+ int bi_didcb;
+ slap_callback bi_cb;
+} bindinfo;
+
struct search_info {
slap_overinst *on;
Query query;
int slimit_exceeded;
pc_caching_reason_t caching_reason;
Entry *head, *tail;
+ bindinfo *pbi;
};
static void
op->ors_filter = &f;
op->ors_slimit = 1;
op->ors_tlimit = SLAP_NO_LIMIT;
+ op->ors_limit = NULL;
attrs[ 0 ].an_desc = ad_queryId;
attrs[ 0 ].an_name = ad_queryId->ad_cname;
op->ors_attrs = attrs;
op->ors_filter = &f;
op->ors_slimit = 1;
op->ors_tlimit = SLAP_NO_LIMIT;
+ op->ors_limit = NULL;
attrs[ 0 ].an_desc = ad_queryId;
attrs[ 0 ].an_name = ad_queryId->ad_cname;
op->ors_attrs = attrs;
switch ( si->caching_reason ) {
case PC_POSITIVE:
cache_entries( op, rs, &qc->q_uuid );
+ if ( si->pbi )
+ si->pbi->bi_query = qc;
break;
case PC_SIZELIMIT:
return SLAP_CB_CONTINUE;
}
-static int
-add_filter_attrs(
- Operation *op,
- AttributeName** new_attrs,
- struct attr_set *attrs,
- AttributeName* filter_attrs,
- int fattr_cnt,
- int fattr_got_oc)
-{
- int alluser = 0;
- int allop = 0;
- int i, j;
- int count;
- int addoc = 0;
-
- /* duplicate attrs */
- count = attrs->count + fattr_cnt;
- if ( !fattr_got_oc && !(attrs->flags & PC_GOT_OC)) {
- addoc = 1;
- count++;
- }
-
- *new_attrs = (AttributeName*)ch_calloc( count + 1,
- sizeof(AttributeName) );
- for (i=0; i<attrs->count; i++) {
- (*new_attrs)[i].an_name = attrs->attrs[i].an_name;
- (*new_attrs)[i].an_desc = attrs->attrs[i].an_desc;
- }
- BER_BVZERO( &(*new_attrs)[i].an_name );
- alluser = an_find( *new_attrs, slap_bv_all_user_attrs );
- allop = an_find( *new_attrs, slap_bv_all_operational_attrs );
-
- j = i;
- for ( i=0; i<fattr_cnt; i++ ) {
- if ( an_find(*new_attrs, &filter_attrs[i].an_name ) ) {
- continue;
- }
- if ( is_at_operational(filter_attrs[i].an_desc->ad_type) ) {
- if ( allop ) {
- continue;
- }
- } else if ( alluser ) {
- continue;
- }
- (*new_attrs)[j].an_name = filter_attrs[i].an_name;
- (*new_attrs)[j].an_desc = filter_attrs[i].an_desc;
- (*new_attrs)[j].an_oc = NULL;
- (*new_attrs)[j].an_flags = 0;
- j++;
- }
- if ( addoc ) {
- (*new_attrs)[j].an_name = slap_schema.si_ad_objectClass->ad_cname;
- (*new_attrs)[j].an_desc = slap_schema.si_ad_objectClass;
- (*new_attrs)[j].an_oc = NULL;
- (*new_attrs)[j].an_flags = 0;
- j++;
- }
- BER_BVZERO( &(*new_attrs)[j].an_name );
-
- return j;
-}
-
/* NOTE: this is a quick workaround to let pcache minimally interact
* with pagedResults. A more articulated solutions would be to
* perform the remote query without control and cache all results,
return rs->sr_err;
}
+typedef struct bindcacheinfo {
+ slap_overinst *on;
+ CachedQuery *qc;
+} bindcacheinfo;
+
+static int
+pc_bind_save( Operation *op, SlapReply *rs )
+{
+ if ( rs->sr_err == LDAP_SUCCESS ) {
+ bindcacheinfo *bci = op->o_callback->sc_private;
+ slap_overinst *on = bci->on;
+ cache_manager *cm = on->on_bi.bi_private;
+ struct berval vals[2];
+ const char *text = NULL;
+
+ BER_BVZERO( &vals[0] );
+ BER_BVZERO( &vals[1] );
+ slap_passwd_hash( &op->orb_cred, &vals[0], &text );
+ if ( BER_BVISEMPTY( &vals[0] )) {
+ Debug( pcache_debug, "pcache_bind_save: hash failed %s\n",
+ text, 0, 0 );
+ } else {
+ Operation op2 = *op;
+ Modifications mod;
+ SlapReply sr = { REP_RESULT };
+ slap_callback cb = { 0, slap_null_cb, 0, 0 };
+
+ mod.sml_op = LDAP_MOD_REPLACE;
+ mod.sml_flags = 0;
+ mod.sml_desc = slap_schema.si_ad_userPassword;
+ mod.sml_type = mod.sml_desc->ad_cname;
+ mod.sml_values = vals;
+ mod.sml_nvalues = NULL;
+ mod.sml_numvals = 1;
+ mod.sml_next = NULL;
+
+ op2.o_tag = LDAP_REQ_MODIFY;
+ op2.orm_modlist = &mod;
+ op2.o_bd = &cm->db;
+ op2.o_dn = op2.o_bd->be_rootdn;
+ op2.o_ndn = op2.o_bd->be_rootndn;
+ op2.o_callback = &cb;
+ if ( op2.o_bd->be_modify( &op2, &sr ) == LDAP_SUCCESS )
+ bci->qc->bindref_time = op->o_time + bci->qc->qtemp->bindttr;
+ }
+ }
+ return SLAP_CB_CONTINUE;
+}
+
+/* Check if the requested entry is from the cache and has a valid
+ * ttr and password hash
+ */
+static int
+pc_bind_search( Operation *op, SlapReply *rs )
+{
+ if ( rs->sr_type == REP_SEARCH ) {
+ bindinfo *pbi = op->o_callback->sc_private;
+
+ /* We only care if this is an already cached result and we're
+ * below the refresh time.
+ */
+ if ( pbi->bi_query && op->o_time < pbi->bi_query->bindref_time ) {
+ Attribute *a;
+
+ /* See if a recognized password is hashed here */
+ a = attr_find( rs->sr_entry->e_attrs,
+ slap_schema.si_ad_userPassword );
+ if ( a && a->a_vals[0].bv_val[0] == '{' &&
+ lutil_passwd_scheme( a->a_vals[0].bv_val ))
+ pbi->bi_hashed = 1;
+ }
+ }
+ return 0;
+}
+
+/* We always want pc_bind_search to run after the search handlers */
+static int
+pc_bind_resp( Operation *op, SlapReply *rs )
+{
+ bindinfo *pbi = op->o_callback->sc_private;
+ if ( !pbi->bi_didcb ) {
+ slap_callback *sc = op->o_callback;
+ while ( sc && sc->sc_response != pcache_response )
+ sc = sc->sc_next;
+ if ( !sc )
+ sc = op->o_callback;
+ pbi->bi_cb.sc_next = sc->sc_next;
+ sc->sc_next = &pbi->bi_cb;
+ pbi->bi_didcb = 1;
+ }
+ return SLAP_CB_CONTINUE;
+}
+
+static int
+pcache_op_bind(
+ Operation *op,
+ SlapReply *rs )
+{
+ slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
+ cache_manager *cm = on->on_bi.bi_private;
+ QueryTemplate *temp;
+ slap_callback cb = { 0 }, *sc;
+ bindinfo bi;
+ bindcacheinfo *bci;
+ Operation op2;
+ int is_priv = 0;
+
+#ifdef PCACHE_CONTROL_PRIVDB
+ if ( op->o_ctrlflag[ privDB_cid ] == SLAP_CONTROL_CRITICAL )
+ is_priv = 1;
+#endif
+
+ /* Skip if we're not configured for Binds, and no priv control */
+ if ( !cm->cache_binds && !is_priv )
+ return SLAP_CB_CONTINUE;
+
+ /* The cache DB isn't open yet */
+ if ( cm->defer_db_open ) {
+ if ( !is_priv ) {
+ /* Just passthru for now */
+ return SLAP_CB_CONTINUE;
+ } else {
+ send_ldap_error( op, rs, LDAP_UNAVAILABLE,
+ "pcachePrivDB: cacheDB not available" );
+ return rs->sr_err;
+ }
+ }
+
+ if ( is_priv ) {
+ int rc;
+ slap_callback *save_cb;
+
+ /* FIXME: might be a little bit exaggerated... */
+ if ( !be_isroot( op ) ) {
+ save_cb = op->o_callback;
+ op->o_callback = NULL;
+ send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
+ "pcachePrivDB: operation not allowed" );
+ op->o_callback = save_cb;
+
+ return rs->sr_err;
+ }
+
+ /* execute, if possible */
+ if ( cm->db.be_bind != NULL ) {
+ op2 = *op;
+ op2.o_bd = &cm->db;
+
+ rc = op2.o_bd->be_bind( &op2, rs );
+ if ( rc == LDAP_SUCCESS ) {
+ op->o_conn->c_authz_cookie = cm->db.be_private;
+ }
+ } else {
+ /* otherwise fall back to error */
+ save_cb = op->o_callback;
+ op->o_callback = NULL;
+ send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
+ "operation not supported with pcachePrivDB control" );
+ op->o_callback = save_cb;
+ }
+
+ return rs->sr_err;
+ }
+
+ /* First search for the target entry and userPassword. This will
+ * give us a cached_query to work with. Find a matching template
+ * to use for the search.
+ */
+ for ( temp=cm->qm->templates; temp; temp=temp->qmnext ) {
+ if ( temp->bindttr && dnIsSuffix( &op->o_req_ndn, &temp->bindbase ))
+ break;
+ }
+ /* Didn't find a suitable template, just passthru */
+ if ( !temp )
+ return SLAP_CB_CONTINUE;
+
+ op2 = *op;
+ op2.o_dn = op->o_bd->be_rootdn;
+ op2.o_ndn = op->o_bd->be_rootndn;
+
+ op2.o_tag = LDAP_REQ_SEARCH;
+ op2.ors_scope = LDAP_SCOPE_BASE;
+ op2.ors_deref = LDAP_DEREF_NEVER;
+ op2.ors_slimit = 1;
+ op2.ors_tlimit = SLAP_NO_LIMIT;
+ op2.ors_limit = NULL;
+ op2.ors_filter = temp->bindfilter;
+ op2.ors_filterstr = temp->bindfilterstr;
+ op2.ors_attrs = cm->qm->attr_sets[temp->attr_set_index].attrs;
+ op2.ors_attrsonly = 0;
+
+ /* We want to invoke search at the same level of the stack
+ * as we're already at...
+ */
+ bi.bi_query = NULL;
+ bi.bi_querystr = &temp->querystr;
+ bi.bi_hashed = 0;
+ bi.bi_didcb = 0;
+ bi.bi_cb.sc_response = pc_bind_search;
+ bi.bi_cb.sc_cleanup = NULL;
+ bi.bi_cb.sc_private = &bi;
+ cb.sc_private = &bi;
+ cb.sc_response = pc_bind_resp;
+ op2.o_callback = &cb;
+ overlay_op_walk( &op2, rs, op_search, on->on_info, on );
+
+ /* OK, just bind locally */
+ if ( bi.bi_hashed ) {
+ BackendDB *be = op->o_bd;
+ op->o_bd = &cm->db;
+
+ if ( op->o_bd->be_bind( op, rs ) == LDAP_SUCCESS ) {
+ op->o_conn->c_authz_cookie = cm->db.be_private;
+ }
+ op->o_bd = be;
+ return rs->sr_err;
+ }
+
+ /* We have a cached query to work with */
+ if ( bi.bi_query ) {
+ sc = op->o_tmpalloc( sizeof(slap_callback) + sizeof(bindcacheinfo),
+ op->o_tmpmemctx );
+ sc->sc_response = pc_bind_save;
+ sc->sc_cleanup = NULL;
+ sc->sc_private = sc+1;
+ bci = sc->sc_private;
+ sc->sc_next = op->o_callback;
+ op->o_callback = sc;
+ bci->on = on;
+ bci->qc = bi.bi_query;
+ }
+ return SLAP_CB_CONTINUE;
+}
+
#ifdef PCACHE_CONTROL_PRIVDB
static int
pcache_op_privdb(
int i = -1;
- AttributeName *filter_attrs = NULL;
-
Query query;
QueryTemplate *qtemp = NULL;
+ bindinfo *pbi = NULL;
int attr_set = -1;
CachedQuery *answerable = NULL;
int cacheable = 0;
- int fattr_cnt=0;
- int fattr_got_oc = 0;
struct berval tempstr;
/* pickup runtime ACL changes */
cm->db.be_acl = op->o_bd->be_acl;
- tempstr.bv_val = op->o_tmpalloc( op->ors_filterstr.bv_len+1, op->o_tmpmemctx );
- tempstr.bv_len = 0;
- if ( filter2template( op, op->ors_filter, &tempstr, &filter_attrs,
- &fattr_cnt, &fattr_got_oc ))
{
- op->o_tmpfree( tempstr.bv_val, op->o_tmpmemctx );
- return SLAP_CB_CONTINUE;
+ /* See if we're processing a Bind request */
+ slap_callback *cb = op->o_callback;
+
+ for ( ; cb; cb=cb->sc_next ) {
+ if ( cb->sc_response == pc_bind_resp ) {
+ pbi = cb->sc_private;
+ break;
+ }
+ }
+ }
+
+ if ( pbi ) {
+ tempstr = *pbi->bi_querystr;
+ } else {
+ tempstr.bv_val = op->o_tmpalloc( op->ors_filterstr.bv_len+1,
+ op->o_tmpmemctx );
+ tempstr.bv_len = 0;
+ if ( filter2template( op, op->ors_filter, &tempstr ))
+ {
+ op->o_tmpfree( tempstr.bv_val, op->o_tmpmemctx );
+ return SLAP_CB_CONTINUE;
+ }
}
Debug( pcache_debug, "query template of incoming query = %s\n",
break;
}
}
- op->o_tmpfree( tempstr.bv_val, op->o_tmpmemctx );
+ if ( !pbi )
+ op->o_tmpfree( tempstr.bv_val, op->o_tmpmemctx );
+
if (answerable) {
BackendDB *save_bd = op->o_bd;
- slap_callback *save_cb = op->o_callback;
ldap_pvt_thread_mutex_lock( &answerable->answerable_cnt_mutex );
answerable->answerable_cnt++;
answerable->answerable_cnt, 0, 0 );
ldap_pvt_thread_mutex_unlock( &answerable->answerable_cnt_mutex );
- op->o_tmpfree( filter_attrs, op->o_tmpmemctx );
ldap_pvt_thread_rdwr_rlock(&answerable->rwlock);
if ( BER_BVISNULL( &answerable->q_uuid )) {
/* No entries cached, just an empty result set */
i = rs->sr_err = 0;
send_ldap_result( op, rs );
} else {
+ /* Let Bind know we used a cached query */
+ if ( pbi )
+ pbi->bi_query = answerable;
+
op->o_bd = &cm->db;
+#if 0
if ( cm->response_cb == PCACHE_RESPONSE_CB_TAIL ) {
/* The cached entry was already processed by any
* other overlays, so don't let it get processed again.
*/
op->o_callback = NULL;
}
+#endif
i = cm->db.bd_info->bi_op_search( op, rs );
}
ldap_pvt_thread_rdwr_runlock(&answerable->rwlock);
/* locked by qtemp->qcfunc (query_containment) */
ldap_pvt_thread_rdwr_runlock(&qtemp->t_rwlock);
op->o_bd = save_bd;
- op->o_callback = save_cb;
return i;
}
Debug( pcache_debug, "QUERY CACHEABLE\n", 0, 0, 0 );
query.filter = filter_dup(op->ors_filter, NULL);
- ldap_pvt_thread_rdwr_wlock(&qtemp->t_rwlock);
- if ( !qtemp->t_attrs.count ) {
- qtemp->t_attrs.count = add_filter_attrs(op,
- &qtemp->t_attrs.attrs,
- &qm->attr_sets[attr_set],
- filter_attrs, fattr_cnt, fattr_got_oc);
- }
- ldap_pvt_thread_rdwr_wunlock(&qtemp->t_rwlock);
cb = op->o_tmpalloc( sizeof(*cb) + sizeof(*si), op->o_tmpmemctx );
cb->sc_response = pcache_response;
si->tail = NULL;
si->swap_saved_attrs = 1;
si->save_attrs = op->ors_attrs;
+ si->pbi = pbi;
op->ors_attrs = qtemp->t_attrs.attrs;
0, 0, 0);
}
- op->o_tmpfree( filter_attrs, op->o_tmpmemctx );
-
return SLAP_CB_CONTINUE;
}
op->ors_scope = query->scope;
op->ors_slimit = SLAP_NO_LIMIT;
op->ors_tlimit = SLAP_NO_LIMIT;
+ op->ors_limit = NULL;
op->ors_filter = query->filter;
filter2bv_x( op, query->filter, &op->ors_filterstr );
op->ors_attrs = query->qtemp->t_attrs.attrs;
PC_RESP,
PC_QUERIES,
PC_OFFLINE,
+ PC_BIND,
PC_PRIVATE_DB
};
"( OLcfgOvAt:2.8 NAME 'olcPcacheOffline' "
"DESC 'Set cache to offline mode and disable expiration' "
"SYNTAX OMsBoolean )", NULL, NULL },
+ { "pcacheBind", "filter> <attrset-index> <TTR> <scope> <base",
+ 6, 6, 0, ARG_MAGIC|PC_BIND, pc_cf_gen,
+ "( OLcfgOvAt:2.9 NAME 'olcPcacheBind' "
+ "DESC 'Parameters for caching Binds' "
+ "SYNTAX OMsDirectoryString )", NULL, NULL },
{ "pcache-", "private database args",
1, 0, STRLENOF("pcache-"), ARG_MAGIC|PC_PRIVATE_DB, pc_cf_gen,
NULL, NULL, NULL },
"SUP olcOverlayConfig "
"MUST ( olcPcache $ olcPcacheAttrset $ olcPcacheTemplate ) "
"MAY ( olcPcachePosition $ olcPcacheMaxQueries $ olcPcachePersist $ "
- "olcPcacheValidate $ olcPcacheOffline ) )",
+ "olcPcacheValidate $ olcPcacheOffline $ olcPcacheBind ) )",
Cft_Overlay, pccfg, NULL, pc_cfadd },
{ "( OLcfgOvOc:2.2 "
"NAME 'olcPcacheDatabase' "
if ( !c->rvalue_vals )
rc = 1;
break;
+ case PC_BIND:
+ for (temp=qm->templates; temp; temp=temp->qmnext) {
+ if ( !temp->bindttr ) continue;
+ bv.bv_len = snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ " %d %ld %s ",
+ temp->attr_set_index,
+ temp->bindttr,
+ ldap_pvt_scope2str( temp->bindscope ));
+ bv.bv_len += temp->bindbase.bv_len + temp->querystr.bv_len + 3;
+ bv.bv_val = ch_malloc( bv.bv_len+1 );
+ ptr = bv.bv_val;
+ *ptr++ = '"';
+ ptr = lutil_strcopy( ptr, temp->querystr.bv_val );
+ *ptr++ = '"';
+ ptr = lutil_strcopy( ptr, c->cr_msg );
+ *ptr++ = '"';
+ ptr = lutil_strcopy( ptr, temp->bindbase.bv_val );
+ *ptr++ = '"';
+ *ptr = '\0';
+ ber_bvarray_add( &c->rvalue_vals, &bv );
+ }
+ if ( !c->rvalue_vals )
+ rc = 1;
+ break;
case PC_RESP:
if ( cm->response_cb == PCACHE_RESPONSE_CB_HEAD ) {
BER_BVSTR( &bv, "head" );
switch( c->type ) {
case PC_ATTR: /* FIXME */
case PC_TEMP:
+ case PC_BIND:
break;
case PC_OFFLINE:
cm->cc_paused &= ~PCACHE_CC_OFFLINE;
switch( c->type ) {
case PC_MAIN:
if ( cm->numattrsets > 0 ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ), "\"proxycache\" directive already provided" );
+ snprintf( c->cr_msg, sizeof( c->cr_msg ), "\"pcache\" directive already provided" );
Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", c->log, c->cr_msg, 0 );
return( 1 );
}
break;
case PC_ATTR:
if ( cm->numattrsets == 0 ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ), "\"proxycache\" directive not provided yet" );
+ snprintf( c->cr_msg, sizeof( c->cr_msg ), "\"pcache\" directive not provided yet" );
Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", c->log, c->cr_msg, 0 );
return( 1 );
}
break;
case PC_TEMP:
if ( cm->numattrsets == 0 ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ), "\"proxycache\" directive not provided yet" );
+ snprintf( c->cr_msg, sizeof( c->cr_msg ), "\"pcache\" directive not provided yet" );
Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", c->log, c->cr_msg, 0 );
return( 1 );
}
Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", c->log, c->cr_msg, 0 );
return 1;
}
- temp = ch_calloc( 1, sizeof( QueryTemplate ));
- temp->qmnext = qm->templates;
- qm->templates = temp;
+ {
+ AttributeName *attrs;
+ int cnt;
+ cnt = template_attrs( c->argv[1], &qm->attr_sets[i], &attrs, &text );
+ if ( cnt < 0 ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ), "unable to parse template: %s",
+ text );
+ Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", c->log, c->cr_msg, 0 );
+ return 1;
+ }
+ temp = ch_calloc( 1, sizeof( QueryTemplate ));
+ temp->qmnext = qm->templates;
+ qm->templates = temp;
+ temp->t_attrs.attrs = attrs;
+ temp->t_attrs.count = cnt;
+ }
ldap_pvt_thread_rdwr_init( &temp->t_rwlock );
temp->query = temp->query_last = NULL;
if ( lutil_parse_time( c->argv[3], &t ) != 0 ) {
"unable to parse template ttl=\"%s\"",
c->argv[3] );
Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", c->log, c->cr_msg, 0 );
+pc_temp_fail:
+ ch_free( temp->t_attrs.attrs );
+ ch_free( temp );
return( 1 );
}
temp->ttl = (time_t)t;
"unable to parse template ttr=\"%s\"",
c->argv[6] );
Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", c->log, c->cr_msg, 0 );
- return( 1 );
+ goto pc_temp_fail;
}
temp->ttr = (time_t)t;
/* fallthru */
"unable to parse template sizelimit ttl=\"%s\"",
c->argv[5] );
Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", c->log, c->cr_msg, 0 );
- return( 1 );
+ goto pc_temp_fail;
}
temp->limitttl = (time_t)t;
/* fallthru */
"unable to parse template negative ttl=\"%s\"",
c->argv[4] );
Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", c->log, c->cr_msg, 0 );
- return( 1 );
+ goto pc_temp_fail;
}
temp->negttl = (time_t)t;
break;
attrarray[i].an_name.bv_val, 0, 0 );
}
break;
+ case PC_BIND:
+ if ( !qm->templates ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ), "\"pcacheTemplate\" directive not provided yet" );
+ Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", c->log, c->cr_msg, 0 );
+ return( 1 );
+ }
+ if ( lutil_atoi( &i, c->argv[2] ) != 0 ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ), "unable to parse Bind index #=\"%s\"",
+ c->argv[2] );
+ Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", c->log, c->cr_msg, 0 );
+ return( 1 );
+ }
+
+ if ( i < 0 || i >= cm->numattrsets ||
+ !(qm->attr_sets[i].flags & PC_CONFIGURED )) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ), "Bind index %d invalid (%s%d)",
+ i, cm->numattrsets > 1 ? "0->" : "", cm->numattrsets - 1 );
+ Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", c->log, c->cr_msg, 0 );
+ return 1;
+ }
+ { struct berval bv;
+ ber_str2bv( c->argv[1], 0, 0, &bv );
+ for ( temp = qm->templates; temp; temp=temp->qmnext ) {
+ if ( temp->attr_set_index == i && bvmatch( &bv,
+ &temp->querystr ))
+ break;
+ }
+ if ( !temp ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ), "Bind template %s %d invalid",
+ c->argv[1], i );
+ Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", c->log, c->cr_msg, 0 );
+ return 1;
+ }
+ }
+ if ( lutil_parse_time( c->argv[3], &t ) != 0 ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "unable to parse bind ttr=\"%s\"",
+ c->argv[3] );
+ Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", c->log, c->cr_msg, 0 );
+ return( 1 );
+ }
+ i = ldap_pvt_str2scope( c->argv[4] );
+ if ( i < 0 ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "unable to parse bind scope=\"%s\"",
+ c->argv[4] );
+ Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", c->log, c->cr_msg, 0 );
+ return( 1 );
+ }
+ {
+ struct berval dn, ndn;
+ ber_str2bv( c->argv[5], 0, 0, &dn );
+ rc = dnNormalize( 0, NULL, NULL, &dn, &ndn, NULL );
+ if ( rc ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "invalid bind baseDN=\"%s\"",
+ c->argv[5] );
+ Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", c->log, c->cr_msg, 0 );
+ return( 1 );
+ }
+ if ( temp->bindbase.bv_val )
+ ch_free( temp->bindbase.bv_val );
+ temp->bindbase = ndn;
+ }
+ {
+ /* convert the template into all presence filters */
+ struct berval bv;
+ char *eq = temp->querystr.bv_val, *e2;
+ Filter *f;
+ i = 0;
+ while ((eq = strchr(eq, '=' ))) {
+ eq++;
+ i++;
+ }
+ bv.bv_len = temp->querystr.bv_len + i;
+ bv.bv_val = ch_malloc( bv.bv_len + 1 );
+ for ( e2 = bv.bv_val, eq = temp->querystr.bv_val;
+ *eq; eq++ ) {
+ if ( *eq == '=' ) {
+ *e2++ = '=';
+ *e2++ = '*';
+ } else {
+ *e2++ = *eq;
+ }
+ }
+ *e2 = '\0';
+ f = str2filter( bv.bv_val );
+ if ( !f ) {
+ ch_free( bv.bv_val );
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "unable to parse bindfilter=\"%s\"", bv.bv_val );
+ Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", c->log, c->cr_msg, 0 );
+ return( 1 );
+ }
+ if ( temp->bindfilter )
+ filter_free( temp->bindfilter );
+ if ( temp->bindfilterstr.bv_val )
+ ch_free( temp->bindfilterstr.bv_val );
+ temp->bindfilterstr = bv;
+ temp->bindfilter = f;
+ }
+ temp->bindttr = (time_t)t;
+ temp->bindscope = i;
+ cm->cache_binds = 1;
+ break;
+
case PC_RESP:
if ( strcasecmp( c->argv[1], "head" ) == 0 ) {
cm->response_cb = PCACHE_RESPONSE_CB_HEAD;
ConfigArgs c2 = *c;
char *argv0 = c->argv[ 0 ];
- c->argv[ 0 ] = &argv0[ STRLENOF( "proxycache-" ) ];
+ c->argv[ 0 ] = &argv0[ STRLENOF( "pcache-" ) ];
ct = config_find_keyword( cm->db.bd_info->bi_cf_ocs->co_table, c );
if ( ct == NULL ) {
} else if ( cm->db.be_config != NULL ) {
char *argv0 = c->argv[ 0 ];
- c->argv[ 0 ] = &argv0[ STRLENOF( "proxycache-" ) ];
+ c->argv[ 0 ] = &argv0[ STRLENOF( "pcache-" ) ];
rc = cm->db.be_config( &cm->db, c->fname, c->lineno, c->argc, c->argv );
c->argv[ 0 ] = argv0;
Debug( LDAP_DEBUG_ANY, "pcache_db_open(): "
"underlying database of type \"%s\"\n"
" serving naming context \"%s\"\n"
- " has no \"rootdn\", required by \"proxycache\".\n",
+ " has no \"rootdn\", required by \"pcache\".\n",
on->on_info->oi_orig->bi_type,
cm->db.be_suffix[0].bv_val, 0 );
return 1;
op->ors_deref = LDAP_DEREF_NEVER;
op->ors_slimit = 1;
op->ors_tlimit = SLAP_NO_LIMIT;
+ op->ors_limit = NULL;
ber_str2bv( "(cachedQueryURL=*)", 0, 0, &op->ors_filterstr );
f.f_choice = LDAP_FILTER_PRESENT;
f.f_desc = ad_cachedQueryURL;
pcache.on_bi.bi_db_destroy = pcache_db_destroy;
pcache.on_bi.bi_op_search = pcache_op_search;
+ pcache.on_bi.bi_op_bind = pcache_op_bind;
#ifdef PCACHE_CONTROL_PRIVDB
- pcache.on_bi.bi_op_bind = pcache_op_privdb;
pcache.on_bi.bi_op_compare = pcache_op_privdb;
pcache.on_bi.bi_op_modrdn = pcache_op_privdb;
pcache.on_bi.bi_op_modify = pcache_op_privdb;