From 6d50de852659630d3b1de2db14b63342e7157366 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Thu, 20 Aug 2009 09:47:34 +0000 Subject: [PATCH] ITS#6152 pwdModify support --- servers/slapd/overlays/pcache.c | 324 ++++++++++++++++---------------- 1 file changed, 164 insertions(+), 160 deletions(-) diff --git a/servers/slapd/overlays/pcache.c b/servers/slapd/overlays/pcache.c index 8d3b8ef2b2..fc886a30ce 100644 --- a/servers/slapd/overlays/pcache.c +++ b/servers/slapd/overlays/pcache.c @@ -2524,11 +2524,58 @@ pcache_chk_controls( 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 ) { @@ -2536,42 +2583,10 @@ 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; - - 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; - Debug( pcache_debug, "pcache_bind_save: caching bind for %s\n", - op->o_req_dn.bv_val, 0, 0 ); - if ( op2.o_bd->be_modify( &op2, &sr ) == LDAP_SUCCESS ) - bci->qc->bindref_time = op->o_time + bci->qc->qtemp->bindttr; - ch_free( vals[0].bv_val ); - } + 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; } @@ -2678,78 +2693,97 @@ pc_bind_resp( Operation *op, SlapReply *rs ) 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; - Entry *e; - slap_callback cb = { 0 }, *sc; - bindinfo bi; - bindcacheinfo *bci; - Operation op2; - int is_priv = 0, rc; - -#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; + } } + /* 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 )) @@ -2772,9 +2806,6 @@ pcache_op_bind( e = NULL; rc = be_entry_get_rw( &op2, &op->o_req_ndn, NULL, NULL, 0, &e ); if ( rc == LDAP_SUCCESS && e ) { - int i; - Attribute *a; - bi.bi_flags |= BI_LOOKUP; op2.ors_filter = pc_bind_attrs( op, e, temp, &op2.ors_filterstr ); be_entry_release_r( &op2, e ); @@ -2837,73 +2868,6 @@ pcache_op_bind( 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, @@ -4863,6 +4827,7 @@ static char *extops[] = { }; #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 ); @@ -5136,6 +5101,7 @@ done:; return rs->sr_err; } +#endif /* PCACHE_EXOP_QUERY_DELETE */ static int pcache_op_extended( Operation *op, SlapReply *rs ) @@ -5149,6 +5115,7 @@ 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; @@ -5176,11 +5143,52 @@ pcache_op_extended( Operation *op, SlapReply *rs ) } 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 @@ -5566,11 +5574,7 @@ pcache_initialize() 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; -- 2.39.5