📄 chain.c
字号:
ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex ); } else { temporary = 1; } } lb->lb_op_f = op_f; lb->lb_depth = depth + 1; rc = op_f( op, &rs2 ); /* note the first error */ if ( first_rc == -1 ) { first_rc = rc; }cleanup:; ldap_memfree( li.li_uri ); li.li_uri = NULL; if ( temporary ) { lip->li_uri = NULL; lip->li_bvuri = NULL; (void)ldap_chain_db_close_one( op->o_bd ); (void)ldap_chain_db_destroy_one( op->o_bd ); }further_cleanup:; if ( !BER_BVISNULL( &pdn ) ) { op->o_tmpfree( pdn.bv_val, op->o_tmpmemctx ); } op->o_req_dn = save_req_dn; if ( !BER_BVISNULL( &ndn ) ) { op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx ); } op->o_req_ndn = save_req_ndn; if ( rc == LDAP_SUCCESS && rs2.sr_err == LDAP_SUCCESS ) { *rs = rs2; break; } rc = rs2.sr_err; }#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR (void)chaining_control_remove( op, &ctrls );#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ if ( rc != LDAP_SUCCESS && first_rc > 0 ) { rc = first_rc; } return rc;}static intldap_chain_search( Operation *op, SlapReply *rs, BerVarray ref, int depth ){ slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private; ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private; ldapinfo_t li = { 0 }, *lip = NULL; struct berval bvuri[ 2 ] = { { 0 } }; struct berval odn = op->o_req_dn, ondn = op->o_req_ndn; slap_response *save_response = op->o_callback->sc_response; int rc = LDAP_OTHER, first_rc = -1;#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR LDAPControl **ctrls = NULL; (void)chaining_control_add( lc, op, &ctrls );#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ rs->sr_type = REP_SEARCH; op->o_callback->sc_response = ldap_chain_cb_search_response; /* if we parse the URI then by no means * we can cache stuff or reuse connections, * because in back-ldap there's no caching * based on the URI value, which is supposed * to be set once for all (correct?) */ li.li_bvuri = bvuri; for ( ; !BER_BVISNULL( &ref[0] ); ref++ ) { SlapReply rs2 = { 0 }; LDAPURLDesc *srv; struct berval save_req_dn = op->o_req_dn, save_req_ndn = op->o_req_ndn, dn, pdn = BER_BVNULL, ndn = BER_BVNULL; int temporary = 0; /* parse reference and use * proto://[host][:port]/ only */ rc = ldap_url_parse_ext( ref[0].bv_val, &srv ); if ( rc != LDAP_URL_SUCCESS ) { /* try next */ rs->sr_err = LDAP_OTHER; continue; } /* normalize DN */ ber_str2bv( srv->lud_dn, 0, 0, &dn ); rc = dnPrettyNormal( NULL, &dn, &pdn, &ndn, op->o_tmpmemctx ); if ( rc == LDAP_SUCCESS ) { /* remove DN essentially because later on * ldap_initialize() will parse the URL * as a comma-separated URL list */ srv->lud_dn = ""; srv->lud_scope = LDAP_SCOPE_DEFAULT; li.li_uri = ldap_url_desc2str( srv ); srv->lud_dn = dn.bv_val; } ldap_free_urldesc( srv ); if ( rc != LDAP_SUCCESS ) { /* try next */ rc = LDAP_OTHER; continue; } if ( li.li_uri == NULL ) { /* try next */ rc = LDAP_OTHER; goto further_cleanup; } op->o_req_dn = pdn; op->o_req_ndn = ndn; ber_str2bv( li.li_uri, 0, 0, &li.li_bvuri[ 0 ] ); /* Searches for a ldapinfo in the avl tree */ ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex ); lip = (ldapinfo_t *)avl_find( lc->lc_lai.lai_tree, (caddr_t)&li, ldap_chain_uri_cmp ); ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex ); if ( lip != NULL ) { op->o_bd->be_private = (void *)lip; } else { /* if none is found, create a temporary... */ rc = ldap_chain_db_init_one( op->o_bd ); if ( rc != 0 ) { goto cleanup; } lip = (ldapinfo_t *)op->o_bd->be_private; lip->li_uri = li.li_uri; lip->li_bvuri = bvuri; rc = ldap_chain_db_open_one( op->o_bd ); if ( rc != 0 ) { lip->li_uri = NULL; lip->li_bvuri = NULL; (void)ldap_chain_db_destroy_one( op->o_bd ); goto cleanup; } if ( LDAP_CHAIN_CACHE_URI( lc ) ) { ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex ); if ( avl_insert( &lc->lc_lai.lai_tree, (caddr_t)lip, ldap_chain_uri_cmp, ldap_chain_uri_dup ) ) { /* someone just inserted another; * don't bother, use this and then * just free it */ temporary = 1; } ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex ); } else { temporary = 1; } } lb->lb_op_f = lback->bi_op_search; lb->lb_depth = depth + 1; /* FIXME: should we also copy filter and scope? * according to RFC3296, no */ rc = lback->bi_op_search( op, &rs2 ); if ( first_rc == -1 ) { first_rc = rc; }cleanup:; ldap_memfree( li.li_uri ); li.li_uri = NULL; op->o_tmpfree( op->o_req_dn.bv_val, op->o_tmpmemctx ); op->o_tmpfree( op->o_req_ndn.bv_val, op->o_tmpmemctx ); if ( temporary ) { lip->li_uri = NULL; lip->li_bvuri = NULL; (void)ldap_chain_db_close_one( op->o_bd ); (void)ldap_chain_db_destroy_one( op->o_bd ); } further_cleanup:; if ( !BER_BVISNULL( &pdn ) ) { op->o_tmpfree( pdn.bv_val, op->o_tmpmemctx ); } op->o_req_dn = save_req_dn; if ( !BER_BVISNULL( &ndn ) ) { op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx ); } op->o_req_ndn = save_req_ndn; if ( rc == LDAP_SUCCESS && rs2.sr_err == LDAP_SUCCESS ) { *rs = rs2; break; } rc = rs2.sr_err; }#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR (void)chaining_control_remove( op, &ctrls );#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ op->o_req_dn = odn; op->o_req_ndn = ondn; op->o_callback->sc_response = save_response; rs->sr_type = REP_SEARCHREF; rs->sr_entry = NULL; if ( rc != LDAP_SUCCESS ) { /* couldn't chase any of the referrals */ if ( first_rc != -1 ) { rc = first_rc; } else { rc = SLAP_CB_CONTINUE; } } return rc;}static intldap_chain_response( Operation *op, SlapReply *rs ){ slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private; BackendDB db, *bd = op->o_bd; ldap_chain_cb_t lb = { 0 }; slap_callback *sc = op->o_callback, sc2 = { 0 }; int rc = 0; char *text = NULL; const char *matched; BerVarray ref; struct berval ndn = op->o_ndn; int sr_err = rs->sr_err; slap_reply_t sr_type = rs->sr_type;#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR 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 * b) what request DN (e.g. only chain requests rooted at <DN>) * c) what referral URIs * d) what protocol scheme (e.g. only ldaps://) * e) what ssf */ db = *op->o_bd; op->o_bd = &db; text = rs->sr_text; rs->sr_text = NULL; matched = rs->sr_matched; rs->sr_matched = NULL; ref = rs->sr_ref; rs->sr_ref = NULL; /* we need this to know if back-ldap returned any result */ lb.lb_lc = lc; sc2.sc_private = &lb; sc2.sc_response = ldap_chain_cb_response; op->o_callback = &sc2; /* Chaining can be performed by a privileged user on behalf * of normal users, using the ProxyAuthz control, by exploiting * the identity assertion feature of back-ldap; see idassert-* * directives in slapd-ldap(5). * * FIXME: the idassert-authcDN is one, will it be fine regardless * of the URI we obtain from the referral? */ switch ( op->o_tag ) { case LDAP_REQ_BIND: { struct berval rndn = op->o_req_ndn; Connection *conn = op->o_conn; /* FIXME: can we really get a referral for binds? */ op->o_req_ndn = slap_empty_bv; op->o_conn = NULL; rc = ldap_chain_op( op, rs, lback->bi_op_bind, ref, 0 ); op->o_req_ndn = rndn; op->o_conn = conn; } break; case LDAP_REQ_ADD: rc = ldap_chain_op( op, rs, lback->bi_op_add, ref, 0 ); break; case LDAP_REQ_DELETE: rc = ldap_chain_op( op, rs, lback->bi_op_delete, ref, 0 ); break; case LDAP_REQ_MODRDN: rc = ldap_chain_op( op, rs, lback->bi_op_modrdn, ref, 0 ); break; case LDAP_REQ_MODIFY: rc = ldap_chain_op( op, rs, lback->bi_op_modify, ref, 0 ); break; case LDAP_REQ_COMPARE: rc = ldap_chain_op( op, rs, lback->bi_op_compare, ref, 0 ); if ( rs->sr_err == LDAP_COMPARE_TRUE || rs->sr_err == LDAP_COMPARE_FALSE ) { rc = LDAP_SUCCESS; } break; case LDAP_REQ_SEARCH: if ( rs->sr_type == REP_SEARCHREF ) { rc = ldap_chain_search( op, rs, ref, 0 ); } else { /* we might get here before any database actually * performed a search; in those cases, we need * to check limits, to make sure safe defaults * are in place */ if ( op->ors_limit != NULL || limits_check( op, rs ) == 0 ) { rc = ldap_chain_op( op, rs, lback->bi_op_search, ref, 0 ); } else { rc = SLAP_CB_CONTINUE; } } break; case LDAP_REQ_EXTENDED: rc = ldap_chain_op( op, rs, lback->bi_extended, ref, 0 ); /* FIXME: ldap_back_extended() by design * doesn't send result; frontend is expected * to send it... */ /* FIXME: what about chaining? */ if ( rc != SLAPD_ABANDON ) { send_ldap_extended( op, rs ); rc = LDAP_SUCCESS; } lb.lb_status = LDAP_CH_RES; break; default: rc = SLAP_CB_CONTINUE; break; } switch ( rc ) { case SLAPD_ABANDON: goto dont_chain; case LDAP_SUCCESS: case LDAP_REFERRAL: /* slapd-ldap sent response */ if ( !op->o_abandon && lb.lb_status != LDAP_CH_RES ) { /* FIXME: should we send response? */ Debug( LDAP_DEBUG_ANY, "%s: ldap_chain_response: " "overlay should have sent result.\n", op->o_log_prefix, 0, 0 ); } break; default:#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR if ( lb.lb_status == LDAP_CH_ERR && rs->sr_err == LDAP_X_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_X_CANNOT_CHAIN, "operation cannot be completed without chaining" ); goto dont_chain; default:#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ if ( LDAP_CHAIN_RETURN_ERR( lc ) ) { rs->sr_err = rc; rs->sr_type = sr_type; } else { rc = SLAP_CB_CONTINUE; rs->sr_err = sr_err; rs->sr_type = sr_type; rs->sr_text = text; rs->sr_matched = matched; rs->sr_ref = ref; }#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR break; }#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ } if ( lb.lb_status == LDAP_CH_NONE && rc != SLAPD_ABANDON ) { op->o_callback = NULL; rc = rs->sr_err = slap_map_api2result( rs ); send_ldap_result( op, rs ); }dont_chain:; rs->sr_err = sr_err; rs->sr_type = sr_type; rs->sr_text = text; rs->sr_matched = matched; rs->sr_ref = ref; op->o_bd = bd; op->o_callback = sc; op->o_ndn = ndn; return rc;}#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIORstatic intldap_chain_parse_ctrl( Operation *op, SlapReply *rs, LDAPControl *ctrl );static intstr2chain( const char *s ){ if ( strcasecmp( s, "chainingPreferred" ) == 0 ) { return LDAP_CHAINING_PREFERRED; } else if ( strcasecmp( s, "chainingRequired" ) == 0 ) { return LDAP_CHAINING_REQUIRED; } else if ( strcasecmp( s, "referralsPreferred" ) == 0 ) { return LDAP_REFERRALS_PREFERRED; } else if ( strcasecmp( s, "referralsRequired" ) == 0 ) { return LDAP_REFERRALS_REQUIRED; } return -1;}#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR *//* * configuration... */enum { CH_CHAINING = 1,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -