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