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