1 1.3 christos /* $NetBSD: abandon.c,v 1.4 2025/09/05 21:16:20 christos Exp $ */ 2 1.2 christos 3 1.1 lukem /* abandon.c */ 4 1.2 christos /* $OpenLDAP$ */ 5 1.1 lukem /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 1.1 lukem * 7 1.4 christos * Copyright 1998-2024 The OpenLDAP Foundation. 8 1.1 lukem * All rights reserved. 9 1.1 lukem * 10 1.1 lukem * Redistribution and use in source and binary forms, with or without 11 1.1 lukem * modification, are permitted only as authorized by the OpenLDAP 12 1.1 lukem * Public License. 13 1.1 lukem * 14 1.1 lukem * A copy of this license is available in the file LICENSE in the 15 1.1 lukem * top-level directory of the distribution or, alternatively, at 16 1.1 lukem * <http://www.OpenLDAP.org/license.html>. 17 1.1 lukem */ 18 1.1 lukem /* Portions Copyright (c) 1990 Regents of the University of Michigan. 19 1.1 lukem * All rights reserved. 20 1.1 lukem */ 21 1.1 lukem 22 1.2 christos #include <sys/cdefs.h> 23 1.3 christos __RCSID("$NetBSD: abandon.c,v 1.4 2025/09/05 21:16:20 christos Exp $"); 24 1.2 christos 25 1.1 lukem #include "portable.h" 26 1.1 lukem 27 1.1 lukem #include <stdio.h> 28 1.1 lukem 29 1.1 lukem #include <ac/stdlib.h> 30 1.1 lukem 31 1.1 lukem #include <ac/socket.h> 32 1.1 lukem #include <ac/string.h> 33 1.1 lukem #include <ac/time.h> 34 1.1 lukem 35 1.1 lukem #include "ldap-int.h" 36 1.1 lukem 37 1.1 lukem /* 38 1.1 lukem * An abandon request looks like this: 39 1.1 lukem * AbandonRequest ::= [APPLICATION 16] MessageID 40 1.1 lukem * and has no response. (Source: RFC 4511) 41 1.1 lukem */ 42 1.1 lukem #include "lutil.h" 43 1.1 lukem 44 1.1 lukem static int 45 1.1 lukem do_abandon( 46 1.1 lukem LDAP *ld, 47 1.1 lukem ber_int_t origid, 48 1.3 christos LDAPRequest *lr, 49 1.1 lukem LDAPControl **sctrls, 50 1.1 lukem int sendabandon ); 51 1.1 lukem 52 1.1 lukem /* 53 1.1 lukem * ldap_abandon_ext - perform an ldap extended abandon operation. 54 1.1 lukem * 55 1.1 lukem * Parameters: 56 1.1 lukem * ld LDAP descriptor 57 1.1 lukem * msgid The message id of the operation to abandon 58 1.1 lukem * scntrls Server Controls 59 1.1 lukem * ccntrls Client Controls 60 1.1 lukem * 61 1.1 lukem * ldap_abandon_ext returns a LDAP error code. 62 1.1 lukem * (LDAP_SUCCESS if everything went ok) 63 1.1 lukem * 64 1.1 lukem * Example: 65 1.1 lukem * ldap_abandon_ext( ld, msgid, scntrls, ccntrls ); 66 1.1 lukem */ 67 1.1 lukem int 68 1.1 lukem ldap_abandon_ext( 69 1.1 lukem LDAP *ld, 70 1.1 lukem int msgid, 71 1.1 lukem LDAPControl **sctrls, 72 1.1 lukem LDAPControl **cctrls ) 73 1.1 lukem { 74 1.1 lukem int rc; 75 1.1 lukem 76 1.3 christos Debug1( LDAP_DEBUG_TRACE, "ldap_abandon_ext %d\n", msgid ); 77 1.1 lukem 78 1.1 lukem /* check client controls */ 79 1.2 christos LDAP_MUTEX_LOCK( &ld->ld_req_mutex ); 80 1.1 lukem 81 1.1 lukem rc = ldap_int_client_controls( ld, cctrls ); 82 1.1 lukem if ( rc == LDAP_SUCCESS ) { 83 1.3 christos rc = do_abandon( ld, msgid, NULL, sctrls, 1 ); 84 1.1 lukem } 85 1.1 lukem 86 1.2 christos LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex ); 87 1.1 lukem 88 1.1 lukem return rc; 89 1.1 lukem } 90 1.1 lukem 91 1.1 lukem 92 1.1 lukem /* 93 1.1 lukem * ldap_abandon - perform an ldap abandon operation. Parameters: 94 1.1 lukem * 95 1.1 lukem * ld LDAP descriptor 96 1.1 lukem * msgid The message id of the operation to abandon 97 1.1 lukem * 98 1.1 lukem * ldap_abandon returns 0 if everything went ok, -1 otherwise. 99 1.1 lukem * 100 1.1 lukem * Example: 101 1.1 lukem * ldap_abandon( ld, msgid ); 102 1.1 lukem */ 103 1.1 lukem int 104 1.1 lukem ldap_abandon( LDAP *ld, int msgid ) 105 1.1 lukem { 106 1.3 christos Debug1( LDAP_DEBUG_TRACE, "ldap_abandon %d\n", msgid ); 107 1.1 lukem return ldap_abandon_ext( ld, msgid, NULL, NULL ) == LDAP_SUCCESS 108 1.1 lukem ? 0 : -1; 109 1.1 lukem } 110 1.1 lukem 111 1.1 lukem 112 1.1 lukem int 113 1.1 lukem ldap_pvt_discard( 114 1.1 lukem LDAP *ld, 115 1.1 lukem ber_int_t msgid ) 116 1.1 lukem { 117 1.1 lukem int rc; 118 1.1 lukem 119 1.2 christos LDAP_MUTEX_LOCK( &ld->ld_req_mutex ); 120 1.3 christos rc = do_abandon( ld, msgid, NULL, NULL, 0 ); 121 1.2 christos LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex ); 122 1.1 lukem return rc; 123 1.1 lukem } 124 1.1 lukem 125 1.1 lukem static int 126 1.1 lukem do_abandon( 127 1.1 lukem LDAP *ld, 128 1.1 lukem ber_int_t origid, 129 1.3 christos LDAPRequest *lr, 130 1.1 lukem LDAPControl **sctrls, 131 1.1 lukem int sendabandon ) 132 1.1 lukem { 133 1.1 lukem BerElement *ber; 134 1.1 lukem int i, err; 135 1.3 christos ber_int_t msgid = origid; 136 1.1 lukem Sockbuf *sb; 137 1.3 christos LDAPRequest needle = {0}; 138 1.1 lukem 139 1.3 christos needle.lr_msgid = origid; 140 1.1 lukem 141 1.1 lukem if ( lr != NULL ) { 142 1.3 christos msgid = lr->lr_msgid; 143 1.3 christos Debug2( LDAP_DEBUG_TRACE, "do_abandon origid %d, msgid %d\n", 144 1.3 christos origid, msgid ); 145 1.3 christos } else if ( (lr = ldap_tavl_find( ld->ld_requests, &needle, ldap_req_cmp )) != NULL ) { 146 1.3 christos Debug2( LDAP_DEBUG_TRACE, "do_abandon origid %d, msgid %d\n", 147 1.3 christos origid, msgid ); 148 1.3 christos if ( lr->lr_parent != NULL ) { 149 1.1 lukem /* don't let caller abandon child requests! */ 150 1.1 lukem ld->ld_errno = LDAP_PARAM_ERROR; 151 1.1 lukem return( LDAP_PARAM_ERROR ); 152 1.1 lukem } 153 1.3 christos msgid = lr->lr_msgid; 154 1.3 christos } 155 1.3 christos 156 1.3 christos if ( lr != NULL ) { 157 1.3 christos LDAPRequest **childp = &lr->lr_child; 158 1.3 christos 159 1.3 christos needle.lr_msgid = lr->lr_msgid; 160 1.3 christos 161 1.1 lukem if ( lr->lr_status != LDAP_REQST_INPROGRESS ) { 162 1.1 lukem /* no need to send abandon message */ 163 1.1 lukem sendabandon = 0; 164 1.1 lukem } 165 1.3 christos 166 1.3 christos while ( *childp ) { 167 1.3 christos /* Abandon children */ 168 1.3 christos LDAPRequest *child = *childp; 169 1.3 christos 170 1.3 christos (void)do_abandon( ld, lr->lr_origid, child, sctrls, sendabandon ); 171 1.3 christos if ( *childp == child ) { 172 1.3 christos childp = &child->lr_refnext; 173 1.3 christos } 174 1.3 christos } 175 1.1 lukem } 176 1.1 lukem 177 1.1 lukem /* ldap_msgdelete locks the res_mutex. Give up the req_mutex 178 1.1 lukem * while we're in there. 179 1.1 lukem */ 180 1.2 christos LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex ); 181 1.1 lukem err = ldap_msgdelete( ld, msgid ); 182 1.2 christos LDAP_MUTEX_LOCK( &ld->ld_req_mutex ); 183 1.1 lukem if ( err == 0 ) { 184 1.1 lukem ld->ld_errno = LDAP_SUCCESS; 185 1.1 lukem return LDAP_SUCCESS; 186 1.1 lukem } 187 1.1 lukem 188 1.1 lukem /* fetch again the request that we are abandoning */ 189 1.1 lukem if ( lr != NULL ) { 190 1.3 christos lr = ldap_tavl_find( ld->ld_requests, &needle, ldap_req_cmp ); 191 1.1 lukem } 192 1.1 lukem 193 1.1 lukem err = 0; 194 1.1 lukem if ( sendabandon ) { 195 1.1 lukem if ( ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, NULL ) == -1 ) { 196 1.1 lukem /* not connected */ 197 1.1 lukem err = -1; 198 1.1 lukem ld->ld_errno = LDAP_SERVER_DOWN; 199 1.1 lukem 200 1.1 lukem } else if ( ( ber = ldap_alloc_ber_with_options( ld ) ) == NULL ) { 201 1.1 lukem /* BER element allocation failed */ 202 1.1 lukem err = -1; 203 1.1 lukem ld->ld_errno = LDAP_NO_MEMORY; 204 1.1 lukem 205 1.1 lukem } else { 206 1.1 lukem /* 207 1.1 lukem * We already have the mutex in LDAP_R_COMPILE, so 208 1.1 lukem * don't try to get it again. 209 1.1 lukem * LDAP_NEXT_MSGID(ld, i); 210 1.1 lukem */ 211 1.1 lukem 212 1.2 christos LDAP_NEXT_MSGID(ld, i); 213 1.1 lukem #ifdef LDAP_CONNECTIONLESS 214 1.1 lukem if ( LDAP_IS_UDP(ld) ) { 215 1.2 christos struct sockaddr_storage sa = {0}; 216 1.1 lukem /* dummy, filled with ldo_peer in request.c */ 217 1.2 christos err = ber_write( ber, (char *) &sa, sizeof(sa), 0 ); 218 1.1 lukem } 219 1.1 lukem if ( LDAP_IS_UDP(ld) && ld->ld_options.ldo_version == 220 1.1 lukem LDAP_VERSION2 ) 221 1.1 lukem { 222 1.2 christos char *dn; 223 1.2 christos LDAP_MUTEX_LOCK( &ld->ld_options.ldo_mutex ); 224 1.2 christos dn = ld->ld_options.ldo_cldapdn; 225 1.1 lukem if (!dn) dn = ""; 226 1.1 lukem err = ber_printf( ber, "{isti", /* '}' */ 227 1.1 lukem i, dn, 228 1.1 lukem LDAP_REQ_ABANDON, msgid ); 229 1.2 christos LDAP_MUTEX_UNLOCK( &ld->ld_options.ldo_mutex ); 230 1.1 lukem } else 231 1.1 lukem #endif 232 1.1 lukem { 233 1.1 lukem /* create a message to send */ 234 1.1 lukem err = ber_printf( ber, "{iti", /* '}' */ 235 1.1 lukem i, 236 1.1 lukem LDAP_REQ_ABANDON, msgid ); 237 1.1 lukem } 238 1.1 lukem 239 1.1 lukem if ( err == -1 ) { 240 1.1 lukem /* encoding error */ 241 1.1 lukem ld->ld_errno = LDAP_ENCODING_ERROR; 242 1.1 lukem 243 1.1 lukem } else { 244 1.1 lukem /* Put Server Controls */ 245 1.1 lukem if ( ldap_int_put_controls( ld, sctrls, ber ) 246 1.1 lukem != LDAP_SUCCESS ) 247 1.1 lukem { 248 1.1 lukem err = -1; 249 1.1 lukem 250 1.1 lukem } else { 251 1.1 lukem /* close '{' */ 252 1.1 lukem err = ber_printf( ber, /*{*/ "N}" ); 253 1.1 lukem 254 1.1 lukem if ( err == -1 ) { 255 1.1 lukem /* encoding error */ 256 1.1 lukem ld->ld_errno = LDAP_ENCODING_ERROR; 257 1.1 lukem } 258 1.1 lukem } 259 1.1 lukem } 260 1.1 lukem 261 1.1 lukem if ( err == -1 ) { 262 1.1 lukem ber_free( ber, 1 ); 263 1.1 lukem 264 1.1 lukem } else { 265 1.1 lukem /* send the message */ 266 1.1 lukem if ( lr != NULL ) { 267 1.1 lukem assert( lr->lr_conn != NULL ); 268 1.1 lukem sb = lr->lr_conn->lconn_sb; 269 1.1 lukem } else { 270 1.1 lukem sb = ld->ld_sb; 271 1.1 lukem } 272 1.1 lukem 273 1.1 lukem if ( ber_flush2( sb, ber, LBER_FLUSH_FREE_ALWAYS ) != 0 ) { 274 1.1 lukem ld->ld_errno = LDAP_SERVER_DOWN; 275 1.1 lukem err = -1; 276 1.1 lukem } else { 277 1.1 lukem err = 0; 278 1.1 lukem } 279 1.1 lukem } 280 1.1 lukem } 281 1.1 lukem } 282 1.1 lukem 283 1.1 lukem if ( lr != NULL ) { 284 1.2 christos LDAPConn *lc; 285 1.2 christos int freeconn = 0; 286 1.1 lukem if ( sendabandon || lr->lr_status == LDAP_REQST_WRITING ) { 287 1.2 christos freeconn = 1; 288 1.2 christos lc = lr->lr_conn; 289 1.1 lukem } 290 1.1 lukem if ( origid == msgid ) { 291 1.1 lukem ldap_free_request( ld, lr ); 292 1.1 lukem 293 1.1 lukem } else { 294 1.1 lukem lr->lr_abandoned = 1; 295 1.1 lukem } 296 1.2 christos 297 1.2 christos if ( freeconn ) { 298 1.2 christos /* release ld_req_mutex while grabbing ld_conn_mutex to 299 1.2 christos * prevent deadlock. 300 1.2 christos */ 301 1.2 christos LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex ); 302 1.2 christos LDAP_MUTEX_LOCK( &ld->ld_conn_mutex ); 303 1.2 christos ldap_free_connection( ld, lc, 0, 1 ); 304 1.2 christos LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); 305 1.2 christos LDAP_MUTEX_LOCK( &ld->ld_req_mutex ); 306 1.2 christos } 307 1.1 lukem } 308 1.1 lukem 309 1.2 christos LDAP_MUTEX_LOCK( &ld->ld_abandon_mutex ); 310 1.1 lukem 311 1.1 lukem /* use bisection */ 312 1.1 lukem i = 0; 313 1.1 lukem if ( ld->ld_nabandoned == 0 || 314 1.1 lukem ldap_int_bisect_find( ld->ld_abandoned, ld->ld_nabandoned, msgid, &i ) == 0 ) 315 1.1 lukem { 316 1.1 lukem ldap_int_bisect_insert( &ld->ld_abandoned, &ld->ld_nabandoned, msgid, i ); 317 1.1 lukem } 318 1.1 lukem 319 1.1 lukem if ( err != -1 ) { 320 1.1 lukem ld->ld_errno = LDAP_SUCCESS; 321 1.1 lukem } 322 1.1 lukem 323 1.2 christos LDAP_MUTEX_UNLOCK( &ld->ld_abandon_mutex ); 324 1.1 lukem return( ld->ld_errno ); 325 1.1 lukem } 326 1.1 lukem 327 1.1 lukem /* 328 1.1 lukem * ldap_int_bisect_find 329 1.1 lukem * 330 1.1 lukem * args: 331 1.1 lukem * v: array of length n (in) 332 1.1 lukem * n: length of array v (in) 333 1.1 lukem * id: value to look for (in) 334 1.1 lukem * idxp: pointer to location of value/insert point 335 1.1 lukem * 336 1.1 lukem * return: 337 1.1 lukem * 0: not found 338 1.1 lukem * 1: found 339 1.1 lukem * -1: error 340 1.1 lukem */ 341 1.1 lukem int 342 1.1 lukem ldap_int_bisect_find( ber_int_t *v, ber_len_t n, ber_int_t id, int *idxp ) 343 1.1 lukem { 344 1.1 lukem int begin, 345 1.1 lukem end, 346 1.1 lukem rc = 0; 347 1.1 lukem 348 1.1 lukem assert( id >= 0 ); 349 1.1 lukem 350 1.1 lukem begin = 0; 351 1.1 lukem end = n - 1; 352 1.1 lukem 353 1.1 lukem if ( n <= 0 || id < v[ begin ] ) { 354 1.1 lukem *idxp = 0; 355 1.1 lukem 356 1.1 lukem } else if ( id > v[ end ] ) { 357 1.1 lukem *idxp = n; 358 1.1 lukem 359 1.1 lukem } else { 360 1.1 lukem int pos; 361 1.1 lukem ber_int_t curid; 362 1.1 lukem 363 1.1 lukem do { 364 1.1 lukem pos = (begin + end)/2; 365 1.1 lukem curid = v[ pos ]; 366 1.1 lukem 367 1.1 lukem if ( id < curid ) { 368 1.1 lukem end = pos - 1; 369 1.1 lukem 370 1.1 lukem } else if ( id > curid ) { 371 1.1 lukem begin = ++pos; 372 1.1 lukem 373 1.1 lukem } else { 374 1.1 lukem /* already abandoned? */ 375 1.1 lukem rc = 1; 376 1.1 lukem break; 377 1.1 lukem } 378 1.1 lukem } while ( end >= begin ); 379 1.1 lukem 380 1.1 lukem *idxp = pos; 381 1.1 lukem } 382 1.1 lukem 383 1.1 lukem return rc; 384 1.1 lukem } 385 1.1 lukem 386 1.1 lukem /* 387 1.1 lukem * ldap_int_bisect_insert 388 1.1 lukem * 389 1.1 lukem * args: 390 1.1 lukem * vp: pointer to array of length *np (in/out) 391 1.1 lukem * np: pointer to length of array *vp (in/out) 392 1.1 lukem * id: value to insert (in) 393 1.1 lukem * idx: location of insert point (as computed by ldap_int_bisect_find()) 394 1.1 lukem * 395 1.1 lukem * return: 396 1.1 lukem * 0: inserted 397 1.1 lukem * -1: error 398 1.1 lukem */ 399 1.1 lukem int 400 1.1 lukem ldap_int_bisect_insert( ber_int_t **vp, ber_len_t *np, int id, int idx ) 401 1.1 lukem { 402 1.1 lukem ber_int_t *v; 403 1.1 lukem ber_len_t n; 404 1.1 lukem int i; 405 1.1 lukem 406 1.1 lukem assert( vp != NULL ); 407 1.1 lukem assert( np != NULL ); 408 1.1 lukem assert( idx >= 0 ); 409 1.2 christos assert( (unsigned) idx <= *np ); 410 1.1 lukem 411 1.1 lukem n = *np; 412 1.1 lukem 413 1.1 lukem v = ber_memrealloc( *vp, sizeof( ber_int_t ) * ( n + 1 ) ); 414 1.1 lukem if ( v == NULL ) { 415 1.1 lukem return -1; 416 1.1 lukem } 417 1.1 lukem *vp = v; 418 1.1 lukem 419 1.1 lukem for ( i = n; i > idx; i-- ) { 420 1.1 lukem v[ i ] = v[ i - 1 ]; 421 1.1 lukem } 422 1.1 lukem v[ idx ] = id; 423 1.1 lukem ++(*np); 424 1.1 lukem 425 1.1 lukem return 0; 426 1.1 lukem } 427 1.1 lukem 428 1.1 lukem /* 429 1.1 lukem * ldap_int_bisect_delete 430 1.1 lukem * 431 1.1 lukem * args: 432 1.1 lukem * vp: pointer to array of length *np (in/out) 433 1.1 lukem * np: pointer to length of array *vp (in/out) 434 1.1 lukem * id: value to delete (in) 435 1.1 lukem * idx: location of value to delete (as computed by ldap_int_bisect_find()) 436 1.1 lukem * 437 1.1 lukem * return: 438 1.1 lukem * 0: deleted 439 1.1 lukem */ 440 1.1 lukem int 441 1.1 lukem ldap_int_bisect_delete( ber_int_t **vp, ber_len_t *np, int id, int idx ) 442 1.1 lukem { 443 1.1 lukem ber_int_t *v; 444 1.2 christos ber_len_t i, n; 445 1.1 lukem 446 1.1 lukem assert( vp != NULL ); 447 1.1 lukem assert( np != NULL ); 448 1.1 lukem assert( idx >= 0 ); 449 1.2 christos assert( (unsigned) idx < *np ); 450 1.1 lukem 451 1.1 lukem v = *vp; 452 1.1 lukem 453 1.1 lukem assert( v[ idx ] == id ); 454 1.1 lukem 455 1.1 lukem --(*np); 456 1.1 lukem n = *np; 457 1.1 lukem 458 1.1 lukem for ( i = idx; i < n; i++ ) { 459 1.1 lukem v[ i ] = v[ i + 1 ]; 460 1.1 lukem } 461 1.1 lukem 462 1.1 lukem return 0; 463 1.1 lukem } 464