1 /* $NetBSD: compare.c,v 1.2 2021/08/14 16:14:59 christos Exp $ */ 2 3 /* compare.c - compare exop handler for back-asyncmeta */ 4 /* $OpenLDAP$ */ 5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 2016-2021 The OpenLDAP Foundation. 8 * Portions Copyright 2016 Symas Corporation. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted only as authorized by the OpenLDAP 13 * Public License. 14 * 15 * A copy of this license is available in the file LICENSE in the 16 * top-level directory of the distribution or, alternatively, at 17 * <http://www.OpenLDAP.org/license.html>. 18 */ 19 20 /* ACKNOWLEDGEMENTS: 21 + * This work was developed by Symas Corporation 22 + * based on back-meta module for inclusion in OpenLDAP Software. 23 + * This work was sponsored by Ericsson. */ 24 25 #include <sys/cdefs.h> 26 __RCSID("$NetBSD: compare.c,v 1.2 2021/08/14 16:14:59 christos Exp $"); 27 28 #include "portable.h" 29 30 #include <stdio.h> 31 32 #include <ac/string.h> 33 #include <ac/socket.h> 34 #include "slap.h" 35 #include "../../../libraries/liblber/lber-int.h" 36 #include "../../../libraries/libldap/ldap-int.h" 37 #include "../back-ldap/back-ldap.h" 38 #include "back-asyncmeta.h" 39 40 meta_search_candidate_t 41 asyncmeta_back_compare_start(Operation *op, 42 SlapReply *rs, 43 a_metaconn_t *mc, 44 bm_context_t *bc, 45 int candidate, 46 int do_lock) 47 { 48 a_dncookie dc; 49 a_metainfo_t *mi = mc->mc_info; 50 a_metatarget_t *mt = mi->mi_targets[ candidate ]; 51 struct berval c_attr = op->orc_ava->aa_desc->ad_cname; 52 struct berval mdn = BER_BVNULL; 53 struct berval mapped_value = op->orc_ava->aa_value; 54 int rc = 0; 55 LDAPControl **ctrls = NULL; 56 meta_search_candidate_t retcode = META_SEARCH_CANDIDATE; 57 BerElement *ber = NULL; 58 a_metasingleconn_t *msc = &mc->mc_conns[ candidate ]; 59 SlapReply *candidates = bc->candidates; 60 ber_int_t msgid; 61 62 dc.op = op; 63 dc.target = mt; 64 dc.memctx = op->o_tmpmemctx; 65 dc.to_from = MASSAGE_REQ; 66 67 asyncmeta_dn_massage( &dc, &op->o_req_dn, &mdn ); 68 69 if ( op->orc_ava->aa_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) 70 asyncmeta_dn_massage( &dc, &op->orc_ava->aa_value, &mapped_value ); 71 72 asyncmeta_set_msc_time(msc); 73 ctrls = op->o_ctrls; 74 if ( asyncmeta_controls_add( op, rs, mc, candidate, bc->is_root,&ctrls ) != LDAP_SUCCESS ) 75 { 76 candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; 77 retcode = META_SEARCH_ERR; 78 goto done; 79 } 80 /* someone might have reset the connection */ 81 if (!( LDAP_BACK_CONN_ISBOUND( msc ) 82 || LDAP_BACK_CONN_ISANON( msc )) || msc->msc_ld == NULL ) { 83 Debug( asyncmeta_debug, "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ ); 84 goto error_unavailable; 85 } 86 87 ber = ldap_build_compare_req( msc->msc_ld, mdn.bv_val, c_attr.bv_val, &mapped_value, 88 ctrls, NULL, &msgid); 89 90 if (!ber) { 91 Debug( asyncmeta_debug, "%s asyncmeta_back_compare_start: Operation encoding failed with errno %d\n", 92 op->o_log_prefix, msc->msc_ld->ld_errno ); 93 rs->sr_err = LDAP_OPERATIONS_ERROR; 94 rs->sr_text = "Failed to encode proxied request"; 95 retcode = META_SEARCH_ERR; 96 goto done; 97 } 98 99 if (ber) { 100 struct timeval tv = {0, mt->mt_network_timeout*1000}; 101 ber_socket_t s; 102 if (!( LDAP_BACK_CONN_ISBOUND( msc ) 103 || LDAP_BACK_CONN_ISANON( msc )) || msc->msc_ld == NULL ) { 104 Debug( asyncmeta_debug, "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ ); 105 goto error_unavailable; 106 } 107 108 ldap_get_option( msc->msc_ld, LDAP_OPT_DESC, &s ); 109 if (s < 0) { 110 Debug( asyncmeta_debug, "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ ); 111 goto error_unavailable; 112 } 113 rc = ldap_int_poll( msc->msc_ld, s, &tv, 1); 114 if (rc < 0) { 115 Debug( asyncmeta_debug, "msc %p not writable within network timeout %s:%d\n", msc, __FILE__, __LINE__ ); 116 if ((msc->msc_result_time + META_BACK_RESULT_INTERVAL) < slap_get_time()) { 117 rc = LDAP_SERVER_DOWN; 118 } else { 119 goto error_unavailable; 120 } 121 } else { 122 candidates[ candidate ].sr_msgid = msgid; 123 rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_COMPARE, 124 mdn.bv_val, ber, msgid ); 125 if (rc == msgid) 126 rc = LDAP_SUCCESS; 127 else 128 rc = LDAP_SERVER_DOWN; 129 ber = NULL; 130 } 131 132 switch ( rc ) { 133 case LDAP_SUCCESS: 134 retcode = META_SEARCH_CANDIDATE; 135 asyncmeta_set_msc_time(msc); 136 goto done; 137 138 case LDAP_SERVER_DOWN: 139 /* do not lock if called from asyncmeta_handle_bind_result. Also do not reset the connection */ 140 if (do_lock > 0) { 141 ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); 142 asyncmeta_reset_msc(NULL, mc, candidate, 0, __FUNCTION__); 143 ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); 144 } 145 /* fall though*/ 146 default: 147 Debug( asyncmeta_debug, "msc %p ldap_send_initial_request failed. %s:%d\n", msc, __FILE__, __LINE__ ); 148 goto error_unavailable; 149 } 150 } 151 152 error_unavailable: 153 if (ber) 154 ber_free(ber, 1); 155 switch (bc->nretries[candidate]) { 156 case -1: /* nretries = forever */ 157 retcode = META_SEARCH_NEED_BIND; 158 break; 159 case 0: /* no retries left */ 160 candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; 161 rs->sr_err = LDAP_UNAVAILABLE; 162 rs->sr_text = "Unable to send compare request to target"; 163 retcode = META_SEARCH_ERR; 164 break; 165 default: /* more retries left - try to rebind and go again */ 166 retcode = META_SEARCH_NEED_BIND; 167 bc->nretries[candidate]--; 168 break; 169 } 170 done: 171 (void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls ); 172 173 if ( op->orc_ava->aa_value.bv_val != mapped_value.bv_val ) { 174 op->o_tmpfree( mapped_value.bv_val, op->o_tmpmemctx ); 175 } 176 177 if ( mdn.bv_val != op->o_req_dn.bv_val ) { 178 op->o_tmpfree( mdn.bv_val, op->o_tmpmemctx ); 179 } 180 181 Debug( LDAP_DEBUG_TRACE, "%s <<< asyncmeta_back_compare_start[%p]=%d\n", op->o_log_prefix, msc, candidates[candidate].sr_msgid ); 182 return retcode; 183 } 184 185 int 186 asyncmeta_back_compare( Operation *op, SlapReply *rs ) 187 { 188 a_metainfo_t *mi = ( a_metainfo_t * )op->o_bd->be_private; 189 a_metatarget_t *mt; 190 a_metaconn_t *mc; 191 int rc, candidate = -1; 192 void *thrctx = op->o_threadctx; 193 bm_context_t *bc; 194 SlapReply *candidates; 195 time_t current_time = slap_get_time(); 196 int max_pending_ops = (mi->mi_max_pending_ops == 0) ? META_BACK_CFG_MAX_PENDING_OPS : mi->mi_max_pending_ops; 197 198 Debug(LDAP_DEBUG_ARGS, "==> asyncmeta_back_compare: %s\n", 199 op->o_req_dn.bv_val ); 200 201 if (current_time > op->o_time) { 202 Debug( asyncmeta_debug, "==> asyncmeta_back_compare[%s]: o_time:[%ld], current time: [%ld]\n", 203 op->o_log_prefix, op->o_time, current_time ); 204 } 205 asyncmeta_new_bm_context(op, rs, &bc, mi->mi_ntargets, mi ); 206 if (bc == NULL) { 207 rs->sr_err = LDAP_OTHER; 208 send_ldap_result(op, rs); 209 return rs->sr_err; 210 } 211 212 candidates = bc->candidates; 213 mc = asyncmeta_getconn( op, rs, candidates, &candidate, LDAP_BACK_DONTSEND, 0); 214 if ( !mc || rs->sr_err != LDAP_SUCCESS) { 215 send_ldap_result(op, rs); 216 return rs->sr_err; 217 } 218 219 mt = mi->mi_targets[ candidate ]; 220 bc->timeout = mt->mt_timeout[ SLAP_OP_COMPARE ]; 221 bc->retrying = LDAP_BACK_RETRYING; 222 bc->sendok = ( LDAP_BACK_SENDRESULT | bc->retrying ); 223 bc->stoptime = op->o_time + bc->timeout; 224 bc->bc_active = 1; 225 226 if (mc->pending_ops >= max_pending_ops) { 227 rs->sr_err = LDAP_BUSY; 228 rs->sr_text = "Maximum pending ops limit exceeded"; 229 send_ldap_result(op, rs); 230 return rs->sr_err; 231 } 232 233 ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); 234 rc = asyncmeta_add_message_queue(mc, bc); 235 mc->mc_conns[candidate].msc_active++; 236 ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); 237 238 if (rc != LDAP_SUCCESS) { 239 rs->sr_err = LDAP_BUSY; 240 rs->sr_text = "Maximum pending ops limit exceeded"; 241 send_ldap_result(op, rs); 242 ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); 243 mc->mc_conns[candidate].msc_active--; 244 ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); 245 goto finish; 246 } 247 248 retry: 249 if (bc->timeout && bc->stoptime < slap_get_time()) { 250 int timeout_err; 251 timeout_err = op->o_protocol >= LDAP_VERSION3 ? 252 LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER; 253 rs->sr_err = timeout_err; 254 rs->sr_text = "Operation timed out before it was sent to target"; 255 asyncmeta_error_cleanup(op, rs, bc, mc, candidate); 256 goto finish; 257 } 258 259 rc = asyncmeta_dobind_init_with_retry(op, rs, bc, mc, candidate); 260 switch (rc) 261 { 262 case META_SEARCH_CANDIDATE: 263 /* target is already bound, just send the request */ 264 Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_compare: " 265 "cnd=\"%d\"\n", op->o_log_prefix, candidate ); 266 267 rc = asyncmeta_back_compare_start( op, rs, mc, bc, candidate, 1); 268 if (rc == META_SEARCH_ERR) { 269 asyncmeta_error_cleanup(op, rs, bc, mc, candidate); 270 goto finish; 271 272 } else if (rc == META_SEARCH_NEED_BIND) { 273 goto retry; 274 } 275 break; 276 case META_SEARCH_NOT_CANDIDATE: 277 Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_compare: NOT_CANDIDATE " 278 "cnd=\"%d\"\n", op->o_log_prefix, candidate ); 279 asyncmeta_error_cleanup(op, rs, bc, mc, candidate); 280 goto finish; 281 282 case META_SEARCH_NEED_BIND: 283 case META_SEARCH_BINDING: 284 Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_compare: BINDING " 285 "cnd=\"%d\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]); 286 /* Todo add the context to the message queue but do not send the request 287 the receiver must send this when we are done binding */ 288 /* question - how would do receiver know to which targets??? */ 289 break; 290 291 case META_SEARCH_ERR: 292 Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_compare: ERR " 293 "cnd=\"%d\"\n", op->o_log_prefix, candidate ); 294 asyncmeta_error_cleanup(op, rs, bc, mc, candidate); 295 goto finish; 296 default: 297 assert( 0 ); 298 break; 299 } 300 301 ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); 302 mc->mc_conns[candidate].msc_active--; 303 asyncmeta_start_one_listener(mc, candidates, bc, candidate); 304 bc->bc_active--; 305 ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); 306 rs->sr_err = SLAPD_ASYNCOP; 307 finish: 308 return rs->sr_err; 309 } 310