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 */
+ struct berval bindftemp; /* bind filter template */
Filter *bindfilter;
+ AttributeDescription **bindfattrs; /* attrs to substitute in ftemp */
+ int bindnattrs; /* number of bindfattrs */
int bindscope;
int attr_set_index; /* determines the projected attributes */
int no_of_queries; /* Total number of queries in the template */
static AttributeDescription *ad_queryId, *ad_cachedQueryURL;
#ifdef PCACHE_MONITOR
+static AttributeDescription *ad_numQueries, *ad_numEntries;
static ObjectClass *oc_olmPCache;
#endif /* PCACHE_MONITOR */
"NO-USER-MODIFICATION "
"USAGE directoryOperation )",
&ad_cachedQueryURL },
+#ifdef PCACHE_MONITOR
+ { "( PCacheAttributes:3 "
+ "NAME 'pcacheNumQueries' "
+ "DESC 'Number of cached queries' "
+ "EQUALITY integerMatch "
+ "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 "
+ "NO-USER-MODIFICATION "
+ "USAGE directoryOperation )",
+ &ad_numQueries },
+ { "( PCacheAttributes:4 "
+ "NAME 'pcacheNumEntries' "
+ "DESC 'Number of cached entries' "
+ "EQUALITY integerMatch "
+ "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 "
+ "NO-USER-MODIFICATION "
+ "USAGE directoryOperation )",
+ &ad_numEntries },
+#endif /* PCACHE_MONITOR */
{ NULL }
};
"NAME ( 'olmPCache' ) "
"SUP top AUXILIARY "
"MAY ( "
- "cachedQueryURL"
- ") )",
+ "pcacheQueryURL "
+ "$ pcacheNumQueries "
+ "$ pcacheNumEntries "
+ " ) )",
&oc_olmPCache },
#endif /* PCACHE_MONITOR */
return 0;
}
+/* Find and record the empty filter clauses */
+
+static int
+ftemp_attrs( struct berval *ftemp, struct berval *template,
+ AttributeDescription ***ret, const char **text )
+{
+ int i;
+ int attr_cnt=0;
+ struct berval bv;
+ char *p1, *p2, *t1;
+ AttributeDescription *ad;
+ AttributeDescription **descs = NULL;
+ char *temp2;
+
+ temp2 = ch_malloc( ftemp->bv_len );
+ p1 = ftemp->bv_val;
+ t1 = temp2;
+
+ *ret = NULL;
+
+ for (;;) {
+ while ( *p1 == '(' || *p1 == '&' || *p1 == '|' || *p1 == ')' )
+ *t1++ = *p1++;
+
+ p2 = strchr( p1, '=' );
+ if ( !p2 )
+ break;
+ i = p2 - p1;
+ AC_MEMCPY( t1, p1, i );
+ t1 += i;
+ *t1++ = '=';
+
+ 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( descs );
+ return -1;
+ }
+ if ( *p2 == '<' || *p2 == '>' ) p2++;
+ if ( p2[1] != ')' ) {
+ p2++;
+ while ( *p2 != ')' ) p2++;
+ p1 = p2;
+ continue;
+ }
+
+ descs = (AttributeDescription **)ch_realloc(descs,
+ (attr_cnt + 2)*sizeof(AttributeDescription *));
+
+ descs[attr_cnt++] = ad;
+
+ p1 = p2+1;
+ }
+ *t1 = '\0';
+ descs[attr_cnt] = NULL;
+ *ret = descs;
+ template->bv_val = temp2;
+ template->bv_len = t1 - temp2;
+ return attr_cnt;
+}
+
static int
template_attrs( char *template, struct attr_set *set, AttributeName **ret,
const char **text )
*ret = NULL;
- attrs = ch_malloc(( set->count+1 )*sizeof(AttributeName));
+ attrs = ch_calloc( set->count + 1, sizeof(AttributeName) );
for ( i=0; i < set->count; i++ )
attrs[i] = set->attrs[i];
attr_cnt = i;
allop = an_find( attrs, slap_bv_all_operational_attrs );
for (;;) {
- while ( *p1 == '(' || *p1 == '&' || *p1 == '|' ) p1++;
+ while ( *p1 == '(' || *p1 == '&' || *p1 == '|' || *p1 == ')' ) p1++;
p2 = strchr( p1, '=' );
if ( !p2 )
break;
}
query.scope = lud->lud_scope;
query.filter = str2filter( lud->lud_filter );
+ if ( query.filter == NULL ) {
+ rc = -1;
+ goto error;
+ }
tempstr.bv_val = ch_malloc( strlen( lud->lud_filter ) + 1 );
tempstr.bv_len = 0;
merge_entry(
Operation *op,
Entry *e,
+ int dup,
struct berval* query_uuid )
{
int rc;
slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
+ if ( dup )
+ e = entry_dup( e );
attr = e->e_attrs;
e->e_attrs = NULL;
modlist->sml_op = LDAP_MOD_ADD;
op->o_tag = LDAP_REQ_MODIFY;
op->orm_modlist = modlist;
+ op->o_managedsait = SLAP_CONTROL_CRITICAL;
op->o_bd->be_modify( op, &sreply );
slap_mods_free( modlist, 1 );
} else if ( rc == LDAP_REFERRAL ||
}
} else {
if ( op->ora_e == e )
- be_entry_release_w( op, e );
+ entry_free( e );
rc = 1;
}
struct berval *query_uuid )
{
struct query_info *qi, *qnext;
- char filter_str[ LDAP_LUTIL_UUIDSTR_BUFSIZE + STRLENOF( "(queryId=)" ) ];
+ char filter_str[ LDAP_LUTIL_UUIDSTR_BUFSIZE + STRLENOF( "(pcacheQueryID=)" ) ];
AttributeAssertion ava = ATTRIBUTEASSERTION_INIT;
Filter filter = {LDAP_FILTER_EQUALITY};
SlapReply sreply = {REP_RESULT};
return 0;
}
+#define BI_HASHED 0x01
+#define BI_DIDCB 0x02
+#define BI_LOOKUP 0x04
+
+struct search_info;
+
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;
+ cache_manager *bi_cm;
+ CachedQuery *bi_cq;
+ QueryTemplate *bi_templ;
+ struct search_info *bi_si;
+ int bi_flags;
slap_callback bi_cb;
} bindinfo;
slap_callback sc = { 0 };
SlapReply rs = { REP_RESULT };
Filter f = { 0 };
- char filter_str[ LDAP_LUTIL_UUIDSTR_BUFSIZE + STRLENOF( "(queryId=)" ) ];
+ char filter_str[ LDAP_LUTIL_UUIDSTR_BUFSIZE + STRLENOF( "(pcacheQueryID=)" ) ];
AttributeAssertion ava = ATTRIBUTEASSERTION_INIT;
AttributeName attrs[ 2 ] = {{{ 0 }}};
int rc;
remove_query_and_data( op_tmp, rs, cm, &crp_uuid );
}
- return_val = merge_entry(op_tmp, e, query_uuid);
+ return_val = merge_entry(op_tmp, e, 0, query_uuid);
ldap_pvt_thread_mutex_lock(&cm->cache_mutex);
cm->cur_entries += return_val;
Debug( pcache_debug,
case PC_POSITIVE:
cache_entries( op, rs, &qc->q_uuid );
if ( si->pbi )
- si->pbi->bi_query = qc;
+ si->pbi->bi_cq = qc;
break;
case PC_SIZELIMIT:
} else if ( rs->sr_err == LDAP_SIZELIMIT_EXCEEDED
&& si->qtemp->limitttl )
{
+ Entry *e;
+
si->caching_reason = PC_SIZELIMIT;
+ for (;si->head; si->head=e) {
+ e = si->head->e_private;
+ si->head->e_private = NULL;
+ entry_free(si->head);
+ }
}
} else if ( si->qtemp->negttl && !si->count && !si->over &&
return rs->sr_err;
}
+static int
+pc_setpw( Operation *op, struct berval *pwd, cache_manager *cm )
+{
+ struct berval vals[2];
+
+ {
+ const char *text = NULL;
+ BER_BVZERO( &vals[0] );
+ slap_passwd_hash( pwd, &vals[0], &text );
+ if ( BER_BVISEMPTY( &vals[0] )) {
+ Debug( pcache_debug, "pc_setpw: hash failed %s\n",
+ text, 0, 0 );
+ return LDAP_OTHER;
+ }
+ }
+
+ BER_BVZERO( &vals[1] );
+
+ {
+ Modifications mod;
+ SlapReply sr = { REP_RESULT };
+ slap_callback cb = { 0, slap_null_cb, 0, 0 };
+ int rc;
+
+ 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;
+
+ op->o_tag = LDAP_REQ_MODIFY;
+ op->orm_modlist = &mod;
+ op->o_bd = &cm->db;
+ op->o_dn = op->o_bd->be_rootdn;
+ op->o_ndn = op->o_bd->be_rootndn;
+ op->o_callback = &cb;
+ Debug( pcache_debug, "pc_setpw: CACHING BIND for %s\n",
+ op->o_req_dn.bv_val, 0, 0 );
+ rc = op->o_bd->be_modify( op, &sr );
+ ch_free( vals[0].bv_val );
+ return rc;
+ }
+}
+
typedef struct bindcacheinfo {
slap_overinst *on;
CachedQuery *qc;
} bindcacheinfo;
-
+
static int
pc_bind_save( Operation *op, SlapReply *rs )
{
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;
+ Operation op2 = *op;
+ if ( pc_setpw( &op2, &op->orb_cred, cm ) == LDAP_SUCCESS )
+ bci->qc->bindref_time = op->o_time + bci->qc->qtemp->bindttr;
+ }
+ return SLAP_CB_CONTINUE;
+}
- 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;
+static Filter *
+pc_bind_attrs( Operation *op, Entry *e, QueryTemplate *temp,
+ struct berval *fbv )
+{
+ int i, len = 0;
+ struct berval *vals, pres = BER_BVC("*");
+ char *p1, *p2, *t1;
+ Attribute *a;
+
+ vals = op->o_tmpalloc( temp->bindnattrs * sizeof( struct berval ),
+ op->o_tmpmemctx );
+
+ for ( i=0; i<temp->bindnattrs; i++ ) {
+ a = attr_find( e->e_attrs, temp->bindfattrs[i] );
+ if ( a && a->a_vals ) {
+ vals[i] = a->a_vals[0];
+ len += a->a_vals[0].bv_len;
+ } else {
+ vals[i] = pres;
}
}
- return SLAP_CB_CONTINUE;
+ fbv->bv_len = len + temp->bindftemp.bv_len;
+ fbv->bv_val = op->o_tmpalloc( fbv->bv_len + 1, op->o_tmpmemctx );
+
+ p1 = temp->bindftemp.bv_val;
+ p2 = fbv->bv_val;
+ i = 0;
+ while ( *p1 ) {
+ *p2++ = *p1;
+ if ( p1[0] == '=' && p1[1] == ')' ) {
+ AC_MEMCPY( p2, vals[i].bv_val, vals[i].bv_len );
+ p2 += vals[i].bv_len;
+ i++;
+ }
+ p1++;
+ }
+ *p2 = '\0';
+ op->o_tmpfree( vals, op->o_tmpmemctx );
+
+ /* FIXME: are we sure str2filter_x can't fail?
+ * caller needs to check */
+ {
+ Filter *f = str2filter_x( op, fbv->bv_val );
+ assert( f != NULL );
+ return f;
+ }
}
/* Check if the requested entry is from the cache and has a valid
bindinfo *pbi = op->o_callback->sc_private;
/* We only care if this is an already cached result and we're
- * below the refresh time.
+ * below the refresh time, or we're offline.
*/
- if ( pbi->bi_query && op->o_time < pbi->bi_query->bindref_time ) {
- Attribute *a;
+ if ( pbi->bi_cq ) {
+ if (( pbi->bi_cm->cc_paused & PCACHE_CC_OFFLINE ) ||
+ op->o_time < pbi->bi_cq->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_flags |= BI_HASHED;
+ } else {
+ Debug( pcache_debug, "pc_bind_search: cache is stale, "
+ "reftime: %ld, current time: %ld\n",
+ pbi->bi_cq->bindref_time, op->o_time, 0 );
+ }
+ } else if ( pbi->bi_si ) {
+ /* This search result is going into the cache */
+ struct berval fbv;
+ Filter *f;
- /* 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;
+ filter_free( pbi->bi_si->query.filter );
+ f = pc_bind_attrs( op, rs->sr_entry, pbi->bi_templ, &fbv );
+ op->o_tmpfree( fbv.bv_val, op->o_tmpmemctx );
+ pbi->bi_si->query.filter = filter_dup( f, NULL );
+ filter_free_x( op, f, 1 );
}
}
return 0;
pc_bind_resp( Operation *op, SlapReply *rs )
{
bindinfo *pbi = op->o_callback->sc_private;
- if ( !pbi->bi_didcb ) {
+ if ( !( pbi->bi_flags & BI_DIDCB )) {
slap_callback *sc = op->o_callback;
while ( sc && sc->sc_response != pcache_response )
sc = sc->sc_next;
sc = op->o_callback;
pbi->bi_cb.sc_next = sc->sc_next;
sc->sc_next = &pbi->bi_cb;
- pbi->bi_didcb = 1;
+ pbi->bi_flags |= BI_DIDCB;
}
return SLAP_CB_CONTINUE;
}
+#ifdef PCACHE_CONTROL_PRIVDB
static int
-pcache_op_bind(
+pcache_op_privdb(
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
+ slap_callback *save_cb;
+ slap_op_t type;
- /* Skip if we're not configured for Binds, and no priv control */
- if ( !cm->cache_binds && !is_priv )
+ /* skip if control is unset */
+ if ( op->o_ctrlflag[ privDB_cid ] != SLAP_CONTROL_CRITICAL ) {
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;
- }
+ 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;
- /* 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;
+ }
- return rs->sr_err;
- }
+ /* map tag to operation */
+ type = slap_req2op( op->o_tag );
+ if ( type != SLAP_OP_LAST ) {
+ BI_op_func **func;
+ int rc;
/* execute, if possible */
- if ( cm->db.be_bind != NULL ) {
- op2 = *op;
+ func = &cm->db.be_bind;
+ if ( func[ type ] != NULL ) {
+ Operation op2 = *op;
+
op2.o_bd = &cm->db;
- rc = op2.o_bd->be_bind( &op2, rs );
- if ( rc == LDAP_SUCCESS ) {
+ rc = func[ type ]( &op2, rs );
+ if ( type == SLAP_OP_BIND && 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;
+ 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.
- */
+ /* 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;
+}
+#endif /* PCACHE_CONTROL_PRIVDB */
+
+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;
+ Entry *e;
+ slap_callback cb = { 0 }, *sc;
+ bindinfo bi;
+ bindcacheinfo *bci;
+ Operation op2;
+ int rc;
+
+#ifdef PCACHE_CONTROL_PRIVDB
+ if ( op->o_ctrlflag[ privDB_cid ] == SLAP_CONTROL_CRITICAL )
+ return pcache_op_privdb( op, rs );
+#endif /* PCACHE_CONTROL_PRIVDB */
+
+ /* Skip if we're not configured for Binds, or cache DB isn't open yet */
+ if ( !cm->cache_binds || cm->defer_db_open )
+ return SLAP_CB_CONTINUE;
+
+ /* First find a matching template with Bind info */
for ( temp=cm->qm->templates; temp; temp=temp->qmnext ) {
if ( temp->bindttr && dnIsSuffix( &op->o_req_ndn, &temp->bindbase ))
break;
if ( !temp )
return SLAP_CB_CONTINUE;
+ /* See if the entry is already locally cached. If so, we can
+ * populate the query filter to retrieve the cached query. We
+ * need to check the bindrefresh time in the query.
+ */
op2 = *op;
op2.o_dn = op->o_bd->be_rootdn;
op2.o_ndn = op->o_bd->be_rootndn;
+ bi.bi_flags = 0;
+
+ op2.o_bd = &cm->db;
+ e = NULL;
+ rc = be_entry_get_rw( &op2, &op->o_req_ndn, NULL, NULL, 0, &e );
+ if ( rc == LDAP_SUCCESS && e ) {
+ bi.bi_flags |= BI_LOOKUP;
+ op2.ors_filter = pc_bind_attrs( op, e, temp, &op2.ors_filterstr );
+ be_entry_release_r( &op2, e );
+ } else {
+ op2.ors_filter = temp->bindfilter;
+ op2.ors_filterstr = temp->bindfilterstr;
+ }
+ op2.o_bd = op->o_bd;
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_cm = cm;
+ bi.bi_templ = temp;
+ bi.bi_cq = NULL;
+ bi.bi_si = NULL;
+
bi.bi_cb.sc_response = pc_bind_search;
bi.bi_cb.sc_cleanup = NULL;
bi.bi_cb.sc_private = &bi;
overlay_op_walk( &op2, rs, op_search, on->on_info, on );
/* OK, just bind locally */
- if ( bi.bi_hashed ) {
+ if ( bi.bi_flags & BI_HASHED ) {
BackendDB *be = op->o_bd;
op->o_bd = &cm->db;
+ Debug( pcache_debug, "pcache_op_bind: CACHED BIND for %s\n",
+ op->o_req_dn.bv_val, 0, 0 );
+
if ( op->o_bd->be_bind( op, rs ) == LDAP_SUCCESS ) {
op->o_conn->c_authz_cookie = cm->db.be_private;
}
}
/* We have a cached query to work with */
- if ( bi.bi_query ) {
+ if ( bi.bi_cq ) {
sc = op->o_tmpalloc( sizeof(slap_callback) + sizeof(bindcacheinfo),
op->o_tmpmemctx );
sc->sc_response = pc_bind_save;
sc->sc_next = op->o_callback;
op->o_callback = sc;
bci->on = on;
- bci->qc = bi.bi_query;
+ bci->qc = bi.bi_cq;
}
return SLAP_CB_CONTINUE;
}
-#ifdef PCACHE_CONTROL_PRIVDB
-static int
-pcache_op_privdb(
- Operation *op,
- SlapReply *rs )
-{
- slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
- cache_manager *cm = on->on_bi.bi_private;
- slap_callback *save_cb;
- slap_op_t type;
-
- /* skip if control is unset */
- if ( op->o_ctrlflag[ privDB_cid ] != SLAP_CONTROL_CRITICAL ) {
- return SLAP_CB_CONTINUE;
- }
-
- /* The cache DB isn't open yet */
- if ( cm->defer_db_open ) {
- send_ldap_error( op, rs, LDAP_UNAVAILABLE,
- "pcachePrivDB: cacheDB not available" );
- return rs->sr_err;
- }
-
- /* 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;
- }
-
- /* map tag to operation */
- type = slap_req2op( op->o_tag );
- if ( type != SLAP_OP_LAST ) {
- BI_op_func **func;
- int rc;
-
- /* execute, if possible */
- func = &cm->db.be_bind;
- if ( func[ type ] != NULL ) {
- Operation op2 = *op;
-
- op2.o_bd = &cm->db;
-
- rc = func[ type ]( &op2, rs );
- if ( type == SLAP_OP_BIND && rc == LDAP_SUCCESS ) {
- op->o_conn->c_authz_cookie = cm->db.be_private;
- }
-
- return rs->sr_err;
- }
- }
-
- /* 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;
-}
-#endif /* PCACHE_CONTROL_PRIVDB */
-
static int
pcache_op_search(
Operation *op,
}
}
+ /* FIXME: cannot cache/answer requests with pagedResults control */
+
+ query.filter = op->ors_filter;
+
if ( pbi ) {
- tempstr = *pbi->bi_querystr;
+ query.base = pbi->bi_templ->bindbase;
+ query.scope = pbi->bi_templ->bindscope;
+ attr_set = pbi->bi_templ->attr_set_index;
+ cacheable = 1;
+ qtemp = pbi->bi_templ;
+ if ( pbi->bi_flags & BI_LOOKUP )
+ answerable = qm->qcfunc(op, qm, &query, qtemp);
+
} else {
tempstr.bv_val = op->o_tmpalloc( op->ors_filterstr.bv_len+1,
op->o_tmpmemctx );
op->o_tmpfree( tempstr.bv_val, op->o_tmpmemctx );
return SLAP_CB_CONTINUE;
}
- }
- Debug( pcache_debug, "query template of incoming query = %s\n",
- tempstr.bv_val, 0, 0 );
+ Debug( pcache_debug, "query template of incoming query = %s\n",
+ tempstr.bv_val, 0, 0 );
- /* FIXME: cannot cache/answer requests with pagedResults control */
-
- /* find attr set */
- attr_set = get_attr_set(op->ors_attrs, qm, cm->numattrsets);
+ /* find attr set */
+ attr_set = get_attr_set(op->ors_attrs, qm, cm->numattrsets);
- query.filter = op->ors_filter;
- query.base = op->o_req_ndn;
- query.scope = op->ors_scope;
+ query.base = op->o_req_ndn;
+ query.scope = op->ors_scope;
- /* check for query containment */
- if (attr_set > -1) {
- QueryTemplate *qt = qm->attr_sets[attr_set].templates;
- for (; qt; qt = qt->qtnext ) {
- /* find if template i can potentially answer tempstr */
- if ( ber_bvstrcasecmp( &qt->querystr, &tempstr ) != 0 )
- continue;
- cacheable = 1;
- qtemp = qt;
- Debug( pcache_debug, "Entering QC, querystr = %s\n",
- op->ors_filterstr.bv_val, 0, 0 );
- answerable = qm->qcfunc(op, qm, &query, qt);
-
- /* if != NULL, rlocks qtemp->t_rwlock */
- if (answerable)
- break;
+ /* check for query containment */
+ if (attr_set > -1) {
+ QueryTemplate *qt = qm->attr_sets[attr_set].templates;
+ for (; qt; qt = qt->qtnext ) {
+ /* find if template i can potentially answer tempstr */
+ if ( ber_bvstrcasecmp( &qt->querystr, &tempstr ) != 0 )
+ continue;
+ cacheable = 1;
+ qtemp = qt;
+ Debug( pcache_debug, "Entering QC, querystr = %s\n",
+ op->ors_filterstr.bv_val, 0, 0 );
+ answerable = qm->qcfunc(op, qm, &query, qt);
+
+ /* if != NULL, rlocks qtemp->t_rwlock */
+ if (answerable)
+ break;
+ }
}
- }
- if ( !pbi )
op->o_tmpfree( tempstr.bv_val, op->o_tmpmemctx );
-
+ }
if (answerable) {
BackendDB *save_bd = op->o_bd;
} else {
/* Let Bind know we used a cached query */
if ( pbi )
- pbi->bi_query = answerable;
+ pbi->bi_cq = answerable;
op->o_bd = &cm->db;
#if 0
si->swap_saved_attrs = 1;
si->save_attrs = op->ors_attrs;
si->pbi = pbi;
+ if ( pbi )
+ pbi->bi_si = si;
op->ors_attrs = qtemp->t_attrs.attrs;
/* No local entry, just add it. FIXME: we are not checking
* the cache entry limit here
*/
- merge_entry( op, rs->sr_entry, &ri->ri_q->q_uuid );
+ merge_entry( op, rs->sr_entry, 1, &ri->ri_q->q_uuid );
} else {
/* Entry exists, update it */
Entry ne;
{
slap_callback cb = { 0 };
refresh_info ri = { 0 };
- char filter_str[ LDAP_LUTIL_UUIDSTR_BUFSIZE + STRLENOF( "(queryId=)" ) ];
+ char filter_str[ LDAP_LUTIL_UUIDSTR_BUFSIZE + STRLENOF( "(pcacheQueryID=)" ) ];
AttributeAssertion ava = ATTRIBUTEASSERTION_INIT;
Filter filter = {LDAP_FILTER_EQUALITY};
AttributeName attrs[ 2 ] = {{{ 0 }}};
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 );
+ bv.bv_len += temp->bindbase.bv_len + temp->bindftemp.bv_len + 4;
+ bv.bv_val = ch_malloc( bv.bv_len + 1 );
ptr = bv.bv_val;
*ptr++ = '"';
- ptr = lutil_strcopy( ptr, temp->querystr.bv_val );
+ ptr = lutil_strcopy( ptr, temp->bindftemp.bv_val );
*ptr++ = '"';
ptr = lutil_strcopy( ptr, c->cr_msg );
*ptr++ = '"';
Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", c->log, c->cr_msg, 0 );
return 1;
}
- { struct berval bv;
+ { struct berval bv, tempbv;
+ AttributeDescription **descs;
+ int ndescs;
ber_str2bv( c->argv[1], 0, 0, &bv );
+ ndescs = ftemp_attrs( &bv, &tempbv, &descs, &text );
+ if ( ndescs < 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;
+ }
for ( temp = qm->templates; temp; temp=temp->qmnext ) {
- if ( temp->attr_set_index == i && bvmatch( &bv,
+ if ( temp->attr_set_index == i && bvmatch( &tempbv,
&temp->querystr ))
break;
}
+ ch_free( tempbv.bv_val );
if ( !temp ) {
+ ch_free( descs );
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;
}
+ ber_dupbv( &temp->bindftemp, &bv );
+ temp->bindfattrs = descs;
+ temp->bindnattrs = ndescs;
}
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 );
+pc_bind_fail:
+ ch_free( temp->bindfattrs );
+ temp->bindfattrs = NULL;
+ ch_free( temp->bindftemp.bv_val );
+ BER_BVZERO( &temp->bindftemp );
+ return( 1 );
}
- i = ldap_pvt_str2scope( c->argv[4] );
- if ( i < 0 ) {
+ num = ldap_pvt_str2scope( c->argv[4] );
+ if ( num < 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 );
+ goto pc_bind_fail;
}
{
struct berval dn, ndn;
"invalid bind baseDN=\"%s\"",
c->argv[5] );
Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", c->log, c->cr_msg, 0 );
- return( 1 );
+ goto pc_bind_fail;
}
if ( temp->bindbase.bv_val )
ch_free( temp->bindbase.bv_val );
temp->bindbase = ndn;
}
{
- /* convert the template into all presence filters */
+ /* convert the template into dummy filter */
struct berval bv;
- char *eq = temp->querystr.bv_val, *e2;
+ char *eq = temp->bindftemp.bv_val, *e2;
Filter *f;
i = 0;
while ((eq = strchr(eq, '=' ))) {
eq++;
- i++;
+ if ( eq[1] == ')' )
+ i++;
}
- bv.bv_len = temp->querystr.bv_len + i;
+ bv.bv_len = temp->bindftemp.bv_len + i;
bv.bv_val = ch_malloc( bv.bv_len + 1 );
- for ( e2 = bv.bv_val, eq = temp->querystr.bv_val;
+ for ( e2 = bv.bv_val, eq = temp->bindftemp.bv_val;
*eq; eq++ ) {
if ( *eq == '=' ) {
*e2++ = '=';
- *e2++ = '*';
+ if ( eq[1] == ')' )
+ *e2++ = '*';
} else {
*e2++ = *eq;
}
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 );
+ ch_free( temp->bindbase.bv_val );
+ BER_BVZERO( &temp->bindbase );
+ goto pc_bind_fail;
}
if ( temp->bindfilter )
filter_free( temp->bindfilter );
temp->bindfilter = f;
}
temp->bindttr = (time_t)t;
- temp->bindscope = i;
+ temp->bindscope = num;
cm->cache_binds = 1;
break;
cm->check_cacheability = 0;
cm->response_cb = PCACHE_RESPONSE_CB_TAIL;
cm->defer_db_open = 1;
+ cm->cache_binds = 0;
cm->cc_period = 1000;
cm->cc_paused = 0;
cm->cc_arg = NULL;
+#ifdef PCACHE_MONITOR
+ cm->monitor_cb = NULL;
+#endif /* PCACHE_MONITOR */
qm->attr_sets = NULL;
qm->templates = NULL;
AttributeAssertion ava = ATTRIBUTEASSERTION_INIT;
AttributeName attrs[ 2 ] = {{{ 0 }}};
- connection_fake_init( &conn, &opbuf, thrctx );
+ connection_fake_init2( &conn, &opbuf, thrctx, 0 );
op = &opbuf.ob_op;
op->o_bd = &cm->db;
op->ors_slimit = 1;
op->ors_tlimit = SLAP_NO_LIMIT;
op->ors_limit = NULL;
- ber_str2bv( "(cachedQueryURL=*)", 0, 0, &op->ors_filterstr );
+ ber_str2bv( "(pcacheQueryURL=*)", 0, 0, &op->ors_filterstr );
f.f_choice = LDAP_FILTER_PRESENT;
f.f_desc = ad_cachedQueryURL;
op->ors_filter = &f;
QueryTemplate *tm;
int i, rc = 0;
+ /* stop the thread ... */
+ if ( cm->cc_arg ) {
+ ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
+ if ( ldap_pvt_runqueue_isrunning( &slapd_rq, cm->cc_arg ) ) {
+ ldap_pvt_runqueue_stoptask( &slapd_rq, cm->cc_arg );
+ }
+ ldap_pvt_runqueue_remove( &slapd_rq, cm->cc_arg );
+ ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
+ }
+
if ( cm->save_queries ) {
CachedQuery *qc;
BerVarray vals = NULL;
thrctx = ldap_pvt_thread_pool_context();
- connection_fake_init( &conn, &opbuf, thrctx );
+ connection_fake_init2( &conn, &opbuf, thrctx, 0 );
op = &opbuf.ob_op;
if ( qm->templates != NULL ) {
cm->db.be_limits = NULL;
cm->db.be_acl = NULL;
- /* stop the thread ... */
- if ( cm->cc_arg ) {
- ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
- if ( ldap_pvt_runqueue_isrunning( &slapd_rq, cm->cc_arg ) ) {
- ldap_pvt_runqueue_stoptask( &slapd_rq, cm->cc_arg );
- }
- ldap_pvt_runqueue_remove( &slapd_rq, cm->cc_arg );
- ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
- }
if ( cm->db.bd_info->bi_db_close ) {
rc = cm->db.bd_info->bi_db_close( &cm->db, NULL );
}
avl_free( tm->qbase, pcache_free_qbase );
free( tm->querystr.bv_val );
+ free( tm->bindfattrs );
+ free( tm->bindftemp.bv_val );
+ free( tm->bindfilterstr.bv_val );
+ free( tm->bindbase.bv_val );
+ filter_free( tm->bindfilter );
ldap_pvt_thread_rdwr_destroy( &tm->t_rwlock );
free( tm->t_attrs.attrs );
free( tm );
};
#endif /* PCACHE_CONTROL_PRIVDB */
+static struct berval pcache_exop_MODIFY_PASSWD = BER_BVC( LDAP_EXOP_MODIFY_PASSWD );
#ifdef PCACHE_EXOP_QUERY_DELETE
static struct berval pcache_exop_QUERY_DELETE = BER_BVC( PCACHE_EXOP_QUERY_DELETE );
len = snprintf( buf, sizeof( buf ), " dn=\"%s\"", op->o_req_ndn.bv_val );
if ( !BER_BVISNULL( &uuid ) && len < sizeof( buf ) ) {
- snprintf( &buf[ len ], sizeof( buf ) - len, " queryId=\"%s\"", uuid.bv_val );
+ snprintf( &buf[ len ], sizeof( buf ) - len, " pcacheQueryId=\"%s\"", uuid.bv_val );
}
Debug( LDAP_DEBUG_STATS, "%s QUERY DELETE%s\n",
return rs->sr_err;
}
+#endif /* PCACHE_EXOP_QUERY_DELETE */
static int
pcache_op_extended( Operation *op, SlapReply *rs )
}
#endif /* PCACHE_CONTROL_PRIVDB */
+#ifdef PCACHE_EXOP_QUERY_DELETE
if ( bvmatch( &op->ore_reqoid, &pcache_exop_QUERY_DELETE ) ) {
struct berval uuid = BER_BVNULL;
ber_tag_t tag = LBER_DEFAULT;
}
op->o_tmpfree( uuid.bv_val, op->o_tmpmemctx );
+ return rs->sr_err;
}
+#endif /* PCACHE_EXOP_QUERY_DELETE */
- return rs->sr_err;
+ /* We only care if we're configured for Bind caching */
+ if ( bvmatch( &op->ore_reqoid, &pcache_exop_MODIFY_PASSWD ) &&
+ cm->cache_binds ) {
+ /* See if the local entry exists and has a password.
+ * It's too much work to find the matching query, so
+ * we just see if there's a hashed password to update.
+ */
+ Operation op2 = *op;
+ Entry *e = NULL;
+ int rc;
+ int doit = 0;
+
+ op2.o_bd = &cm->db;
+ op2.o_dn = op->o_bd->be_rootdn;
+ op2.o_ndn = op->o_bd->be_rootndn;
+ rc = be_entry_get_rw( &op2, &op->o_req_ndn, NULL,
+ slap_schema.si_ad_userPassword, 0, &e );
+ if ( rc == LDAP_SUCCESS && e ) {
+ /* See if a recognized password is hashed here */
+ Attribute *a = attr_find( e->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 )) {
+ doit = 1;
+ }
+ be_entry_release_r( &op2, e );
+ }
+
+ if ( doit ) {
+ rc = overlay_op_walk( op, rs, op_extended, on->on_info,
+ on->on_next );
+ if ( rc == LDAP_SUCCESS ) {
+ req_pwdexop_s *qpw = &op->oq_pwdexop;
+
+ /* We don't care if it succeeds or not */
+ pc_setpw( &op2, &qpw->rs_new, cm );
+ }
+ return rc;
+ }
+ }
+ return SLAP_CB_CONTINUE;
}
-#endif /* PCACHE_EXOP_QUERY_DELETE */
#ifdef PCACHE_MONITOR
CachedQuery *qc;
BerVarray vals = NULL;
- assert( ad_cachedQueryURL != NULL );
-
attr_delete( &e->e_attrs, ad_cachedQueryURL );
if ( ( SLAP_OPATTRS( rs->sr_attr_flags ) || ad_inlist( ad_cachedQueryURL, rs->sr_attrs ) )
&& qm->templates != NULL )
}
}
+ {
+ Attribute *a;
+ char buf[ SLAP_TEXT_BUFLEN ];
+ struct berval bv;
+
+ /* number of cached queries */
+ a = attr_find( e->e_attrs, ad_numQueries );
+ assert( a != NULL );
+
+ bv.bv_val = buf;
+ bv.bv_len = snprintf( buf, sizeof( buf ), "%lu", cm->num_cached_queries );
+
+ if ( a->a_nvals != a->a_vals ) {
+ ber_bvreplace( &a->a_nvals[ 0 ], &bv );
+ }
+ ber_bvreplace( &a->a_vals[ 0 ], &bv );
+
+ /* number of cached entries */
+ a = attr_find( e->e_attrs, ad_numEntries );
+ assert( a != NULL );
+
+ bv.bv_val = buf;
+ bv.bv_len = snprintf( buf, sizeof( buf ), "%d", cm->cur_entries );
+
+ if ( a->a_nvals != a->a_vals ) {
+ ber_bvreplace( &a->a_nvals[ 0 ], &bv );
+ }
+ ber_bvreplace( &a->a_vals[ 0 ], &bv );
+ }
+
return SLAP_CB_CONTINUE;
}
textbuf, sizeof( textbuf ) );
/* don't care too much about return code... */
+ /* remove attrs */
+ mod.sm_values = NULL;
+ mod.sm_desc = ad_numQueries;
+ mod.sm_numvals = 0;
+ rc = modify_delete_values( e, &mod, 1, &text,
+ textbuf, sizeof( textbuf ) );
+ /* don't care too much about return code... */
+
+ /* remove attrs */
+ mod.sm_values = NULL;
+ mod.sm_desc = ad_numEntries;
+ mod.sm_numvals = 0;
+ rc = modify_delete_values( e, &mod, 1, &text,
+ textbuf, sizeof( textbuf ) );
+ /* don't care too much about return code... */
+
return SLAP_CB_CONTINUE;
}
}
/* alloc as many as required (plus 1 for objectClass) */
- a = attrs_alloc( 1 + 0 );
+ a = attrs_alloc( 1 + 2 );
if ( a == NULL ) {
rc = 1;
goto cleanup;
attr_valadd( a, &oc_olmPCache->soc_cname, NULL, 1 );
next = a->a_next;
+ {
+ struct berval bv = BER_BVC( "0" );
+
+ next->a_desc = ad_numQueries;
+ attr_valadd( next, &bv, NULL, 1 );
+ next = next->a_next;
+
+ next->a_desc = ad_numEntries;
+ attr_valadd( next, &bv, NULL, 1 );
+ next = next->a_next;
+ }
+
cb = ch_calloc( sizeof( monitor_callback_t ), 1 );
cb->mc_update = pcache_monitor_update;
cb->mc_free = pcache_monitor_free;
pcache.on_bi.bi_op_add = pcache_op_privdb;
pcache.on_bi.bi_op_delete = pcache_op_privdb;
#endif /* PCACHE_CONTROL_PRIVDB */
-#ifdef PCACHE_EXOP_QUERY_DELETE
pcache.on_bi.bi_extended = pcache_op_extended;
-#elif defined( PCACHE_CONTROL_PRIVDB )
- pcache.on_bi.bi_extended = pcache_op_privdb;
-#endif
pcache.on_bi.bi_chk_controls = pcache_chk_controls;