static int retcode_op_internal( Operation *op, SlapReply *rs ) { slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; Operation op2 = *op; BackendDB db = *op->o_bd; slap_callback sc = { 0 }; retcode_cb_t rdc; int rc; op2.o_tag = LDAP_REQ_SEARCH; op2.ors_scope = LDAP_SCOPE_BASE; op2.ors_deref = LDAP_DEREF_NEVER; op2.ors_tlimit = SLAP_NO_LIMIT; op2.ors_slimit = SLAP_NO_LIMIT; op2.ors_limit = NULL; op2.ors_attrsonly = 0; op2.ors_attrs = slap_anlist_all_attributes; ber_str2bv_x( "(objectClass=errAbsObject)", STRLENOF( "(objectClass=errAbsObject)" ), 1, &op2.ors_filterstr, op2.o_tmpmemctx ); op2.ors_filter = str2filter_x( &op2, op2.ors_filterstr.bv_val ); /* errAbsObject is defined by this overlay! */ assert( op2.ors_filter != NULL ); db.bd_info = on->on_info->oi_orig; op2.o_bd = &db; rdc.rdc_info = on->on_info->oi_orig; rdc.rdc_flags = RETCODE_FINDIR; if ( op->o_tag == LDAP_REQ_SEARCH ) { rdc.rdc_attrs = op->ors_attrs; } rdc.rdc_tag = op->o_tag; sc.sc_response = retcode_cb_response; sc.sc_private = &rdc; op2.o_callback = ≻ rc = op2.o_bd->be_search( &op2, rs ); op->o_abandon = op2.o_abandon; filter_free_x( &op2, op2.ors_filter, 1 ); ber_memfree_x( op2.ors_filterstr.bv_val, op2.o_tmpmemctx ); if ( rdc.rdc_flags == SLAP_CB_CONTINUE ) { return SLAP_CB_CONTINUE; } return rc; }
int asyncmeta_handle_search_msg(LDAPMessage *res, a_metaconn_t *mc, bm_context_t *bc, int candidate) { a_metainfo_t *mi; a_metatarget_t *mt; a_metasingleconn_t *msc; Operation *op = bc->op; SlapReply *rs; int i, rc = LDAP_SUCCESS, sres; SlapReply *candidates; char **references = NULL; LDAPControl **ctrls = NULL; a_dncookie dc; LDAPMessage *msg; ber_int_t id; rs = &bc->rs; mi = mc->mc_info; mt = mi->mi_targets[ candidate ]; msc = &mc->mc_conns[ candidate ]; dc.op = op; dc.target = mt; dc.to_from = MASSAGE_REP; id = ldap_msgid(res); candidates = bc->candidates; i = candidate; while (res && !META_BACK_CONN_INVALID(msc)) { for (msg = ldap_first_message(msc->msc_ldr, res); msg; msg = ldap_next_message(msc->msc_ldr, msg)) { switch(ldap_msgtype(msg)) { case LDAP_RES_SEARCH_ENTRY: Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_handle_search_msg: msc %p entry\n", op->o_log_prefix, msc ); if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) { /* don't retry any more... */ candidates[ i ].sr_type = REP_RESULT; } /* count entries returned by target */ candidates[ i ].sr_nentries++; if (bc->c_peer_name.bv_val == op->o_conn->c_peer_name.bv_val && !op->o_abandon) { rs->sr_err = asyncmeta_send_entry( &bc->copy_op, rs, mc, i, msg ); } else { goto err_cleanup; } switch ( rs->sr_err ) { case LDAP_SIZELIMIT_EXCEEDED: asyncmeta_send_ldap_result(bc, op, rs); rs->sr_err = LDAP_SUCCESS; goto err_cleanup; case LDAP_UNAVAILABLE: rs->sr_err = LDAP_OTHER; break; default: break; } bc->is_ok++; break; case LDAP_RES_SEARCH_REFERENCE: if ( META_BACK_TGT_NOREFS( mt ) ) { rs->sr_err = LDAP_OTHER; asyncmeta_send_ldap_result(bc, op, rs); goto err_cleanup; } if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) { /* don't retry any more... */ candidates[ i ].sr_type = REP_RESULT; } bc->is_ok++; rc = ldap_parse_reference( msc->msc_ldr, msg, &references, &rs->sr_ctrls, 0 ); if ( rc != LDAP_SUCCESS || references == NULL ) { rs->sr_err = LDAP_OTHER; asyncmeta_send_ldap_result(bc, op, rs); goto err_cleanup; } /* FIXME: merge all and return at the end */ { int cnt; for ( cnt = 0; references[ cnt ]; cnt++ ) ; rs->sr_ref = ber_memalloc_x( sizeof( struct berval ) * ( cnt + 1 ), op->o_tmpmemctx ); for ( cnt = 0; references[ cnt ]; cnt++ ) { ber_str2bv_x( references[ cnt ], 0, 1, &rs->sr_ref[ cnt ], op->o_tmpmemctx ); } BER_BVZERO( &rs->sr_ref[ cnt ] ); } { dc.memctx = op->o_tmpmemctx; ( void )asyncmeta_referral_result_rewrite( &dc, rs->sr_ref ); } if ( rs->sr_ref != NULL ) { if (!BER_BVISNULL( &rs->sr_ref[ 0 ] ) ) { /* ignore return value by now */ ( void )send_search_reference( op, rs ); } ber_bvarray_free_x( rs->sr_ref, op->o_tmpmemctx ); rs->sr_ref = NULL; } /* cleanup */ if ( references ) { ber_memvfree( (void **)references ); } if ( rs->sr_ctrls ) { ldap_controls_free( rs->sr_ctrls ); rs->sr_ctrls = NULL; } break; case LDAP_RES_INTERMEDIATE: if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) { /* don't retry any more... */ candidates[ i ].sr_type = REP_RESULT; } bc->is_ok++; /* FIXME: response controls * are passed without checks */ rs->sr_err = ldap_parse_intermediate( msc->msc_ldr, msg, (char **)&rs->sr_rspoid, &rs->sr_rspdata, &rs->sr_ctrls, 0 ); if ( rs->sr_err != LDAP_SUCCESS ) { candidates[ i ].sr_type = REP_RESULT; rs->sr_err = LDAP_OTHER; asyncmeta_send_ldap_result(bc, op, rs); goto err_cleanup; } slap_send_ldap_intermediate( op, rs ); if ( rs->sr_rspoid != NULL ) { ber_memfree( (char *)rs->sr_rspoid ); rs->sr_rspoid = NULL; } if ( rs->sr_rspdata != NULL ) { ber_bvfree( rs->sr_rspdata ); rs->sr_rspdata = NULL; } if ( rs->sr_ctrls != NULL ) { ldap_controls_free( rs->sr_ctrls ); rs->sr_ctrls = NULL; } break; case LDAP_RES_SEARCH_RESULT: if ( mi->mi_idle_timeout != 0 ) { asyncmeta_set_msc_time(msc); } Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_handle_search_msg: msc %p result\n", op->o_log_prefix, msc ); candidates[ i ].sr_type = REP_RESULT; candidates[ i ].sr_msgid = META_MSGID_IGNORE; /* NOTE: ignores response controls * (and intermediate response controls * as well, except for those with search * references); this may not be correct, * but if they're not ignored then * back-meta would need to merge them * consistently (think of pagedResults...) */ /* FIXME: response controls? */ rs->sr_err = ldap_parse_result( msc->msc_ldr, msg, &candidates[ i ].sr_err, (char **)&candidates[ i ].sr_matched, (char **)&candidates[ i ].sr_text, &references, &ctrls /* &candidates[ i ].sr_ctrls (unused) */ , 0 ); if ( rs->sr_err != LDAP_SUCCESS ) { candidates[ i ].sr_err = rs->sr_err; sres = slap_map_api2result( &candidates[ i ] ); candidates[ i ].sr_type = REP_RESULT; goto finish; } rs->sr_err = candidates[ i ].sr_err; /* massage matchedDN if need be */ if ( candidates[ i ].sr_matched != NULL ) { struct berval match, mmatch; ber_str2bv( candidates[ i ].sr_matched, 0, 0, &match ); candidates[ i ].sr_matched = NULL; dc.memctx = NULL; asyncmeta_dn_massage( &dc, &match, &mmatch ); if ( mmatch.bv_val == match.bv_val ) { candidates[ i ].sr_matched = ch_strdup( mmatch.bv_val ); } else { candidates[ i ].sr_matched = mmatch.bv_val; } bc->candidate_match++; ldap_memfree( match.bv_val ); } /* add references to array */ /* RFC 4511: referrals can only appear * if result code is LDAP_REFERRAL */ if ( references != NULL && references[ 0 ] != NULL && references[ 0 ][ 0 ] != '\0' ) { if ( rs->sr_err != LDAP_REFERRAL ) { Debug( LDAP_DEBUG_ANY, "%s asncmeta_search_result[%d]: " "got referrals with err=%d\n", op->o_log_prefix, i, rs->sr_err ); } else { BerVarray sr_ref; int cnt; for ( cnt = 0; references[ cnt ]; cnt++ ) ; sr_ref = ber_memalloc_x( sizeof( struct berval ) * ( cnt + 1 ), op->o_tmpmemctx ); for ( cnt = 0; references[ cnt ]; cnt++ ) { ber_str2bv_x( references[ cnt ], 0, 1, &sr_ref[ cnt ], op->o_tmpmemctx ); } BER_BVZERO( &sr_ref[ cnt ] ); dc.memctx = op->o_tmpmemctx; ( void )asyncmeta_referral_result_rewrite( &dc, sr_ref ); if ( rs->sr_v2ref == NULL ) { rs->sr_v2ref = sr_ref; } else { for ( cnt = 0; !BER_BVISNULL( &sr_ref[ cnt ] ); cnt++ ) { ber_bvarray_add_x( &rs->sr_v2ref, &sr_ref[ cnt ], op->o_tmpmemctx ); } ber_memfree_x( sr_ref, op->o_tmpmemctx ); } } } else if ( rs->sr_err == LDAP_REFERRAL ) { Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_search_result[%d]: " "got err=%d with null " "or empty referrals\n", op->o_log_prefix, i, rs->sr_err ); rs->sr_err = LDAP_NO_SUCH_OBJECT; } /* cleanup */ ber_memvfree( (void **)references ); sres = slap_map_api2result( rs ); if ( candidates[ i ].sr_err == LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_search_result[%d] " "match=\"%s\" err=%ld", op->o_log_prefix, i, candidates[ i ].sr_matched ? candidates[ i ].sr_matched : "", (long) candidates[ i ].sr_err ); } else { Debug( LDAP_DEBUG_ANY, "%s asyncmeta_search_result[%d] " "match=\"%s\" err=%ld (%s)", op->o_log_prefix, i, candidates[ i ].sr_matched ? candidates[ i ].sr_matched : "", (long) candidates[ i ].sr_err, ldap_err2string( candidates[ i ].sr_err ) ); } switch ( sres ) { case LDAP_NO_SUCH_OBJECT: /* is_ok is touched any time a valid * (even intermediate) result is * returned; as a consequence, if * a candidate returns noSuchObject * it is ignored and the candidate * is simply demoted. */ if ( bc->is_ok ) { sres = LDAP_SUCCESS; } break; case LDAP_SUCCESS: if ( ctrls != NULL && ctrls[0] != NULL ) { #ifdef SLAPD_META_CLIENT_PR LDAPControl *pr_c; pr_c = ldap_control_find( LDAP_CONTROL_PAGEDRESULTS, ctrls, NULL ); if ( pr_c != NULL ) { BerElementBuffer berbuf; BerElement *ber = (BerElement *)&berbuf; ber_tag_t tag; ber_int_t prsize; struct berval prcookie; /* unsolicited, do not accept */ if ( mt->mt_ps == 0 ) { rs->sr_err = LDAP_OTHER; goto err_pr; } ber_init2( ber, &pr_c->ldctl_value, LBER_USE_DER ); tag = ber_scanf( ber, "{im}", &prsize, &prcookie ); if ( tag == LBER_ERROR ) { rs->sr_err = LDAP_OTHER; goto err_pr; } /* more pages? new search request */ if ( !BER_BVISNULL( &prcookie ) && !BER_BVISEMPTY( &prcookie ) ) { if ( mt->mt_ps > 0 ) { /* ignore size if specified */ prsize = 0; } else if ( prsize == 0 ) { /* guess the page size from the entries returned so far */ prsize = candidates[ i ].sr_nentries; } candidates[ i ].sr_nentries = 0; candidates[ i ].sr_msgid = META_MSGID_IGNORE; candidates[ i ].sr_type = REP_INTERMEDIATE; assert( candidates[ i ].sr_matched == NULL ); assert( candidates[ i ].sr_text == NULL ); assert( candidates[ i ].sr_ref == NULL ); switch ( asyncmeta_back_search_start( &bc->copy_op, rs, mc, bc, i, &prcookie, prsize, 1 ) ) { case META_SEARCH_CANDIDATE: assert( candidates[ i ].sr_msgid >= 0 ); ldap_controls_free( ctrls ); // goto free_message; case META_SEARCH_ERR: case META_SEARCH_NEED_BIND: err_pr:; candidates[ i ].sr_err = rs->sr_err; candidates[ i ].sr_type = REP_RESULT; if ( META_BACK_ONERR_STOP( mi ) ) { asyncmeta_send_ldap_result(bc, op, rs); ldap_controls_free( ctrls ); goto err_cleanup; } /* fallthru */ case META_SEARCH_NOT_CANDIDATE: /* means that asyncmeta_back_search_start() * failed but onerr == continue */ candidates[ i ].sr_msgid = META_MSGID_IGNORE; candidates[ i ].sr_type = REP_RESULT; break; default: /* impossible */ assert( 0 ); break; } break; } } #endif /* SLAPD_META_CLIENT_PR */ ldap_controls_free( ctrls ); } /* fallthru */ case LDAP_REFERRAL: bc->is_ok++; break; case LDAP_SIZELIMIT_EXCEEDED: /* if a target returned sizelimitExceeded * and the entry count is equal to the * proxy's limit, the target would have * returned more, and the error must be * propagated to the client; otherwise, * the target enforced a limit lower * than what requested by the proxy; * ignore it */ candidates[ i ].sr_err = rs->sr_err; if ( rs->sr_nentries == op->ors_slimit || META_BACK_ONERR_STOP( mi ) ) { const char *save_text; got_err: save_text = rs->sr_text; rs->sr_text = candidates[ i ].sr_text; asyncmeta_send_ldap_result(bc, op, rs); if (candidates[ i ].sr_text != NULL) { ch_free( (char *)candidates[ i ].sr_text ); candidates[ i ].sr_text = NULL; } rs->sr_text = save_text; ldap_controls_free( ctrls ); goto err_cleanup; } break; default: candidates[ i ].sr_err = rs->sr_err; if ( META_BACK_ONERR_STOP( mi ) ) { goto got_err; } break; } /* if this is the last result we will ever receive, send it back */ rc = rs->sr_err; if (asyncmeta_is_last_result(mc, bc, i) == 0) { Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_handle_search_msg: msc %p last result\n", op->o_log_prefix, msc ); asyncmeta_search_last_result(mc, bc, i, sres); err_cleanup: rc = rs->sr_err; ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); asyncmeta_drop_bc( mc, bc); asyncmeta_clear_bm_context(bc); ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); ldap_msgfree(res); return rc; } finish: break; default: continue; } } ldap_msgfree(res); res = NULL; if (candidates[ i ].sr_type != REP_RESULT) { struct timeval tv = {0}; rc = ldap_result( msc->msc_ldr, id, LDAP_MSG_RECEIVED, &tv, &res ); if (res != NULL) { msc->msc_result_time = slap_get_time(); } } } ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); bc->bc_active--; ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); return rc; }
RETCODE backsql_BindRowAsStrings_x( SQLHSTMT sth, BACKSQL_ROW_NTS *row, void *ctx ) { RETCODE rc; if ( row == NULL ) { return SQL_ERROR; } #ifdef BACKSQL_TRACE Debug( LDAP_DEBUG_TRACE, "==> backsql_BindRowAsStrings()\n", 0, 0, 0 ); #endif /* BACKSQL_TRACE */ rc = SQLNumResultCols( sth, &row->ncols ); if ( rc != SQL_SUCCESS ) { #ifdef BACKSQL_TRACE Debug( LDAP_DEBUG_TRACE, "backsql_BindRowAsStrings(): " "SQLNumResultCols() failed:\n", 0, 0, 0 ); #endif /* BACKSQL_TRACE */ backsql_PrintErrors( SQL_NULL_HENV, SQL_NULL_HDBC, sth, rc ); } else { SQLCHAR colname[ 64 ]; SQLSMALLINT name_len, col_type, col_scale, col_null; UDWORD col_prec; int i; #ifdef BACKSQL_TRACE Debug( LDAP_DEBUG_TRACE, "backsql_BindRowAsStrings: " "ncols=%d\n", (int)row->ncols, 0, 0 ); #endif /* BACKSQL_TRACE */ row->col_names = (BerVarray)ber_memcalloc_x( row->ncols + 1, sizeof( struct berval ), ctx ); if ( row->col_names == NULL ) { goto nomem; } row->col_prec = (UDWORD *)ber_memcalloc_x( row->ncols, sizeof( UDWORD ), ctx ); if ( row->col_prec == NULL ) { goto nomem; } row->col_type = (SQLSMALLINT *)ber_memcalloc_x( row->ncols, sizeof( SQLSMALLINT ), ctx ); if ( row->col_type == NULL ) { goto nomem; } row->cols = (char **)ber_memcalloc_x( row->ncols + 1, sizeof( char * ), ctx ); if ( row->cols == NULL ) { goto nomem; } row->value_len = (SQLINTEGER *)ber_memcalloc_x( row->ncols, sizeof( SQLINTEGER ), ctx ); if ( row->value_len == NULL ) { goto nomem; } if ( 0 ) { nomem: ber_memfree_x( row->col_names, ctx ); row->col_names = NULL; ber_memfree_x( row->col_prec, ctx ); row->col_prec = NULL; ber_memfree_x( row->col_type, ctx ); row->col_type = NULL; ber_memfree_x( row->cols, ctx ); row->cols = NULL; ber_memfree_x( row->value_len, ctx ); row->value_len = NULL; Debug( LDAP_DEBUG_ANY, "backsql_BindRowAsStrings: " "out of memory\n", 0, 0, 0 ); return LDAP_NO_MEMORY; } for ( i = 0; i < row->ncols; i++ ) { SQLSMALLINT TargetType; rc = SQLDescribeCol( sth, (SQLSMALLINT)(i + 1), &colname[ 0 ], (SQLUINTEGER)( sizeof( colname ) - 1 ), &name_len, &col_type, &col_prec, &col_scale, &col_null ); /* FIXME: test rc? */ ber_str2bv_x( (char *)colname, 0, 1, &row->col_names[ i ], ctx ); #ifdef BACKSQL_TRACE Debug( LDAP_DEBUG_TRACE, "backsql_BindRowAsStrings: " "col_name=%s, col_prec[%d]=%d\n", colname, (int)(i + 1), (int)col_prec ); #endif /* BACKSQL_TRACE */ if ( col_type != SQL_CHAR && col_type != SQL_VARCHAR ) { col_prec = MAX_ATTR_LEN; } row->cols[ i ] = (char *)ber_memcalloc_x( col_prec + 1, sizeof( char ), ctx ); row->col_prec[ i ] = col_prec; row->col_type[ i ] = col_type; /* * ITS#3386, ITS#3113 - 20070308 * Note: there are many differences between various DPMS and ODBC * Systems; some support SQL_C_BLOB, SQL_C_BLOB_LOCATOR. YMMV: * This has only been tested on Linux/MySQL/UnixODBC * For BINARY-type Fields (BLOB, etc), read the data as BINARY */ if ( BACKSQL_IS_BINARY( col_type ) ) { #ifdef BACKSQL_TRACE Debug( LDAP_DEBUG_TRACE, "backsql_BindRowAsStrings: " "col_name=%s, col_type[%d]=%d: reading binary data\n", colname, (int)(i + 1), (int)col_type); #endif /* BACKSQL_TRACE */ TargetType = SQL_C_BINARY; } else { /* Otherwise read it as Character data */ #ifdef BACKSQL_TRACE Debug( LDAP_DEBUG_TRACE, "backsql_BindRowAsStrings: " "col_name=%s, col_type[%d]=%d: reading character data\n", colname, (int)(i + 1), (int)col_type); #endif /* BACKSQL_TRACE */ TargetType = SQL_C_CHAR; } rc = SQLBindCol( sth, (SQLUSMALLINT)(i + 1), TargetType, (SQLPOINTER)row->cols[ i ], col_prec + 1, &row->value_len[ i ] ); /* FIXME: test rc? */ } BER_BVZERO( &row->col_names[ i ] ); row->cols[ i ] = NULL; } #ifdef BACKSQL_TRACE Debug( LDAP_DEBUG_TRACE, "<== backsql_BindRowAsStrings()\n", 0, 0, 0 ); #endif /* BACKSQL_TRACE */ return rc; }
/* * NOTE: the dn must be normalized */ int backsql_dn2id( Operation *op, SlapReply *rs, SQLHDBC dbh, struct berval *ndn, backsql_entryID *id, int matched, int muck ) { backsql_info *bi = op->o_bd->be_private; SQLHSTMT sth = SQL_NULL_HSTMT; BACKSQL_ROW_NTS row = { 0 }; RETCODE rc; int res; struct berval realndn = BER_BVNULL; /* TimesTen */ char upperdn[ BACKSQL_MAX_DN_LEN + 1 ]; struct berval tbbDN; int i, j; /* * NOTE: id can be NULL; in this case, the function * simply checks whether the DN can be successfully * turned into an ID, returning LDAP_SUCCESS for * positive cases, or the most appropriate error */ Debug( LDAP_DEBUG_TRACE, "==>backsql_dn2id(\"%s\")%s%s\n", ndn->bv_val, id == NULL ? " (no ID expected)" : "", matched ? " matched expected" : "" ); if ( id ) { /* NOTE: trap inconsistencies */ assert( BER_BVISNULL( &id->eid_ndn ) ); } if ( ndn->bv_len > BACKSQL_MAX_DN_LEN ) { Debug( LDAP_DEBUG_TRACE, " backsql_dn2id(\"%s\"): DN length=%ld " "exceeds max DN length %d:\n", ndn->bv_val, ndn->bv_len, BACKSQL_MAX_DN_LEN ); return LDAP_OTHER; } /* return baseObject if available and matches */ /* FIXME: if ndn is already mucked, we cannot check this */ if ( bi->sql_baseObject != NULL && dn_match( ndn, &bi->sql_baseObject->e_nname ) ) { if ( id != NULL ) { #ifdef BACKSQL_ARBITRARY_KEY ber_dupbv_x( &id->eid_id, &backsql_baseObject_bv, op->o_tmpmemctx ); ber_dupbv_x( &id->eid_keyval, &backsql_baseObject_bv, op->o_tmpmemctx ); #else /* ! BACKSQL_ARBITRARY_KEY */ id->eid_id = BACKSQL_BASEOBJECT_ID; id->eid_keyval = BACKSQL_BASEOBJECT_KEYVAL; #endif /* ! BACKSQL_ARBITRARY_KEY */ id->eid_oc_id = BACKSQL_BASEOBJECT_OC; ber_dupbv_x( &id->eid_ndn, &bi->sql_baseObject->e_nname, op->o_tmpmemctx ); ber_dupbv_x( &id->eid_dn, &bi->sql_baseObject->e_name, op->o_tmpmemctx ); id->eid_next = NULL; } return LDAP_SUCCESS; } /* begin TimesTen */ Debug( LDAP_DEBUG_TRACE, " backsql_dn2id(\"%s\"): id_query \"%s\"\n", ndn->bv_val, bi->sql_id_query, 0 ); assert( bi->sql_id_query != NULL ); rc = backsql_Prepare( dbh, &sth, bi->sql_id_query, 0 ); if ( rc != SQL_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, " backsql_dn2id(\"%s\"): " "error preparing SQL:\n %s", ndn->bv_val, bi->sql_id_query, 0 ); backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); res = LDAP_OTHER; goto done; } realndn = *ndn; if ( muck ) { if ( backsql_api_dn2odbc( op, rs, &realndn ) ) { Debug( LDAP_DEBUG_TRACE, " backsql_dn2id(\"%s\"): " "backsql_api_dn2odbc(\"%s\") failed\n", ndn->bv_val, realndn.bv_val, 0 ); res = LDAP_OTHER; goto done; } } if ( BACKSQL_HAS_LDAPINFO_DN_RU( bi ) ) { /* * Prepare an upper cased, byte reversed version * that can be searched using indexes */ for ( i = 0, j = realndn.bv_len - 1; realndn.bv_val[ i ]; i++, j--) { upperdn[ i ] = realndn.bv_val[ j ]; } upperdn[ i ] = '\0'; ldap_pvt_str2upper( upperdn ); Debug( LDAP_DEBUG_TRACE, " backsql_dn2id(\"%s\"): " "upperdn=\"%s\"\n", ndn->bv_val, upperdn, 0 ); ber_str2bv( upperdn, 0, 0, &tbbDN ); } else { if ( BACKSQL_USE_REVERSE_DN( bi ) ) { AC_MEMCPY( upperdn, realndn.bv_val, realndn.bv_len + 1 ); ldap_pvt_str2upper( upperdn ); Debug( LDAP_DEBUG_TRACE, " backsql_dn2id(\"%s\"): " "upperdn=\"%s\"\n", ndn->bv_val, upperdn, 0 ); ber_str2bv( upperdn, 0, 0, &tbbDN ); } else { tbbDN = realndn; } } rc = backsql_BindParamBerVal( sth, 1, SQL_PARAM_INPUT, &tbbDN ); if ( rc != SQL_SUCCESS) { /* end TimesTen */ Debug( LDAP_DEBUG_TRACE, " backsql_dn2id(\"%s\"): " "error binding dn=\"%s\" parameter:\n", ndn->bv_val, tbbDN.bv_val, 0 ); backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); res = LDAP_OTHER; goto done; } rc = SQLExecute( sth ); if ( rc != SQL_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, " backsql_dn2id(\"%s\"): " "error executing query (\"%s\", \"%s\"):\n", ndn->bv_val, bi->sql_id_query, tbbDN.bv_val ); backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); res = LDAP_OTHER; goto done; } backsql_BindRowAsStrings_x( sth, &row, op->o_tmpmemctx ); rc = SQLFetch( sth ); if ( BACKSQL_SUCCESS( rc ) ) { char buf[ SLAP_TEXT_BUFLEN ]; #ifdef LDAP_DEBUG snprintf( buf, sizeof(buf), "id=%s keyval=%s oc_id=%s dn=%s", row.cols[ 0 ], row.cols[ 1 ], row.cols[ 2 ], row.cols[ 3 ] ); Debug( LDAP_DEBUG_TRACE, " backsql_dn2id(\"%s\"): %s\n", ndn->bv_val, buf, 0 ); #endif /* LDAP_DEBUG */ res = LDAP_SUCCESS; if ( id != NULL ) { struct berval dn; id->eid_next = NULL; #ifdef BACKSQL_ARBITRARY_KEY ber_str2bv_x( row.cols[ 0 ], 0, 1, &id->eid_id, op->o_tmpmemctx ); ber_str2bv_x( row.cols[ 1 ], 0, 1, &id->eid_keyval, op->o_tmpmemctx ); #else /* ! BACKSQL_ARBITRARY_KEY */ if ( lutil_atoulx( &id->eid_id, row.cols[ 0 ], 0 ) != 0 ) { res = LDAP_OTHER; goto done; } if ( lutil_atoulx( &id->eid_keyval, row.cols[ 1 ], 0 ) != 0 ) { res = LDAP_OTHER; goto done; } #endif /* ! BACKSQL_ARBITRARY_KEY */ if ( lutil_atoulx( &id->eid_oc_id, row.cols[ 2 ], 0 ) != 0 ) { res = LDAP_OTHER; goto done; } ber_str2bv( row.cols[ 3 ], 0, 0, &dn ); if ( backsql_api_odbc2dn( op, rs, &dn ) ) { res = LDAP_OTHER; goto done; } res = dnPrettyNormal( NULL, &dn, &id->eid_dn, &id->eid_ndn, op->o_tmpmemctx ); if ( res != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, " backsql_dn2id(\"%s\"): " "dnPrettyNormal failed (%d: %s)\n", realndn.bv_val, res, ldap_err2string( res ) ); /* cleanup... */ (void)backsql_free_entryID( id, 0, op->o_tmpmemctx ); } if ( dn.bv_val != row.cols[ 3 ] ) { free( dn.bv_val ); } } } else { res = LDAP_NO_SUCH_OBJECT; if ( matched ) { struct berval pdn = *ndn; /* * Look for matched */ rs->sr_matched = NULL; while ( !be_issuffix( op->o_bd, &pdn ) ) { char *matchedDN = NULL; dnParent( &pdn, &pdn ); /* * Empty DN ("") defaults to LDAP_SUCCESS */ rs->sr_err = backsql_dn2id( op, rs, dbh, &pdn, id, 0, 1 ); switch ( rs->sr_err ) { case LDAP_NO_SUCH_OBJECT: /* try another one */ break; case LDAP_SUCCESS: matchedDN = pdn.bv_val; /* fail over to next case */ default: rs->sr_err = LDAP_NO_SUCH_OBJECT; rs->sr_matched = matchedDN; goto done; } } } } done:; backsql_FreeRow_x( &row, op->o_tmpmemctx ); Debug( LDAP_DEBUG_TRACE, "<==backsql_dn2id(\"%s\"): err=%d\n", ndn->bv_val, res, 0 ); if ( sth != SQL_NULL_HSTMT ) { SQLFreeStmt( sth, SQL_DROP ); } if ( !BER_BVISNULL( &realndn ) && realndn.bv_val != ndn->bv_val ) { ch_free( realndn.bv_val ); } return res; }
int ldap_back_referral_result_rewrite( dncookie *dc, BerVarray a_vals, void *memctx ) { int i, last; assert( dc != NULL ); assert( a_vals != NULL ); for ( last = 0; !BER_BVISNULL( &a_vals[ last ] ); last++ ) ; last--; for ( i = 0; !BER_BVISNULL( &a_vals[ i ] ); i++ ) { struct berval dn, olddn = BER_BVNULL; int rc; LDAPURLDesc *ludp; rc = ldap_url_parse( a_vals[ i ].bv_val, &ludp ); if ( rc != LDAP_URL_SUCCESS ) { /* leave attr untouched if massage failed */ continue; } /* FIXME: URLs like "ldap:///dc=suffix" if passed * thru ldap_url_parse() and ldap_url_desc2str() * get rewritten as "ldap:///dc=suffix??base"; * we don't want this to occur... */ if ( ludp->lud_scope == LDAP_SCOPE_BASE ) { ludp->lud_scope = LDAP_SCOPE_DEFAULT; } ber_str2bv( ludp->lud_dn, 0, 0, &olddn ); rc = ldap_back_dn_massage( dc, &olddn, &dn ); switch ( rc ) { case LDAP_UNWILLING_TO_PERFORM: /* * FIXME: need to check if it may be considered * legal to trim values when adding/modifying; * it should be when searching (e.g. ACLs). */ ber_memfree( a_vals[ i ].bv_val ); if ( last > i ) { a_vals[ i ] = a_vals[ last ]; } BER_BVZERO( &a_vals[ last ] ); last--; i--; break; default: /* leave attr untouched if massage failed */ if ( !BER_BVISNULL( &dn ) && olddn.bv_val != dn.bv_val ) { char *newurl; ludp->lud_dn = dn.bv_val; newurl = ldap_url_desc2str( ludp ); free( dn.bv_val ); if ( newurl == NULL ) { /* FIXME: leave attr untouched * even if ldap_url_desc2str failed... */ break; } ber_memfree_x( a_vals[ i ].bv_val, memctx ); ber_str2bv_x( newurl, 0, 1, &a_vals[ i ], memctx ); ber_memfree( newurl ); ludp->lud_dn = olddn.bv_val; } break; } ldap_free_urldesc( ludp ); } return 0; }
struct berval * UTF8bvnormalize( struct berval *bv, struct berval *newbv, unsigned flags, void *ctx ) { int i, j, len, clen, outpos, ucsoutlen, outsize, last; int didnewbv = 0; char *out, *outtmp, *s; ac_uint4 *ucs, *p, *ucsout; static unsigned char mask[] = { 0, 0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01 }; unsigned casefold = flags & LDAP_UTF8_CASEFOLD; unsigned approx = flags & LDAP_UTF8_APPROX; if ( bv == NULL ) { return NULL; } s = bv->bv_val; len = bv->bv_len; if ( len == 0 ) { return ber_dupbv_x( newbv, bv, ctx ); } if ( !newbv ) { newbv = ber_memalloc_x( sizeof(struct berval), ctx ); if ( !newbv ) return NULL; didnewbv = 1; } /* Should first check to see if string is already in proper * normalized form. This is almost as time consuming as * the normalization though. */ /* finish off everything up to character before first non-ascii */ if ( LDAP_UTF8_ISASCII( s ) ) { if ( casefold ) { outsize = len + 7; out = (char *) ber_memalloc_x( outsize, ctx ); if ( out == NULL ) { fail: if ( didnewbv ) ber_memfree_x( newbv, ctx ); return NULL; } outpos = 0; for ( i = 1; (i < len) && LDAP_UTF8_ISASCII(s + i); i++ ) { out[outpos++] = TOLOWER( s[i-1] ); } if ( i == len ) { out[outpos++] = TOLOWER( s[len-1] ); out[outpos] = '\0'; newbv->bv_val = out; newbv->bv_len = outpos; return newbv; } } else { for ( i = 1; (i < len) && LDAP_UTF8_ISASCII(s + i); i++ ) { /* empty */ } if ( i == len ) { return ber_str2bv_x( s, len, 1, newbv, ctx ); } outsize = len + 7; out = (char *) ber_memalloc_x( outsize, ctx ); if ( out == NULL ) { goto fail; } outpos = i - 1; memcpy(out, s, outpos); } } else { outsize = len + 7; out = (char *) ber_memalloc_x( outsize, ctx ); if ( out == NULL ) { goto fail; } outpos = 0; i = 0; } p = ucs = ber_memalloc_x( len * sizeof(*ucs), ctx ); if ( ucs == NULL ) { ber_memfree_x(out, ctx); goto fail; } /* convert character before first non-ascii to ucs-4 */ if ( i > 0 ) { *p = casefold ? TOLOWER( s[i-1] ) : s[i-1]; p++; } /* s[i] is now first non-ascii character */ for (;;) { /* s[i] is non-ascii */ /* convert everything up to next ascii to ucs-4 */ while ( i < len ) { clen = LDAP_UTF8_CHARLEN2( s + i, clen ); if ( clen == 0 ) { ber_memfree_x( ucs, ctx ); ber_memfree_x( out, ctx ); goto fail; } if ( clen == 1 ) { /* ascii */ break; } *p = s[i] & mask[clen]; i++; for( j = 1; j < clen; j++ ) { if ( (s[i] & 0xc0) != 0x80 ) { ber_memfree_x( ucs, ctx ); ber_memfree_x( out, ctx ); goto fail; } *p <<= 6; *p |= s[i] & 0x3f; i++; } if ( casefold ) { *p = uctolower( *p ); } p++; } /* normalize ucs of length p - ucs */ uccompatdecomp( ucs, p - ucs, &ucsout, &ucsoutlen, ctx ); if ( approx ) { for ( j = 0; j < ucsoutlen; j++ ) { if ( ucsout[j] < 0x80 ) { out[outpos++] = ucsout[j]; } } } else { ucsoutlen = uccanoncomp( ucsout, ucsoutlen ); /* convert ucs to utf-8 and store in out */ for ( j = 0; j < ucsoutlen; j++ ) { /* allocate more space if not enough room for 6 bytes and terminator */ if ( outsize - outpos < 7 ) { outsize = ucsoutlen - j + outpos + 6; outtmp = (char *) ber_memrealloc_x( out, outsize, ctx ); if ( outtmp == NULL ) { ber_memfree_x( ucsout, ctx ); ber_memfree_x( ucs, ctx ); ber_memfree_x( out, ctx ); goto fail; } out = outtmp; } outpos += ldap_x_ucs4_to_utf8( ucsout[j], &out[outpos] ); } } ber_memfree_x( ucsout, ctx ); ucsout = NULL; if ( i == len ) { break; } last = i; /* Allocate more space in out if necessary */ if (len - i >= outsize - outpos) { outsize += 1 + ((len - i) - (outsize - outpos)); outtmp = (char *) ber_memrealloc_x(out, outsize, ctx); if (outtmp == NULL) { ber_memfree_x( ucs, ctx ); ber_memfree_x( out, ctx ); goto fail; } out = outtmp; } /* s[i] is ascii */ /* finish off everything up to char before next non-ascii */ for ( i++; (i < len) && LDAP_UTF8_ISASCII(s + i); i++ ) { out[outpos++] = casefold ? TOLOWER( s[i-1] ) : s[i-1]; } if ( i == len ) { out[outpos++] = casefold ? TOLOWER( s[len-1] ) : s[len-1]; break; } /* convert character before next non-ascii to ucs-4 */ *ucs = casefold ? TOLOWER( s[i-1] ) : s[i-1]; p = ucs + 1; } ber_memfree_x( ucs, ctx ); out[outpos] = '\0'; newbv->bv_val = out; newbv->bv_len = outpos; return newbv; }