1 /* $NetBSD: abandon.c,v 1.2 2020/08/11 13:15:37 christos Exp $ */ 2 3 /* abandon.c */ 4 /* $OpenLDAP$ */ 5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 1998-2020 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.2 2020/08/11 13:15:37 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 ber_int_t msgid, 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 Debug( LDAP_DEBUG_TRACE, "ldap_abandon_ext %d\n", msgid, 0, 0 ); 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, msgid, 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 Debug( LDAP_DEBUG_TRACE, "ldap_abandon %d\n", msgid, 0, 0 ); 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, msgid, 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 ber_int_t msgid, 130 LDAPControl **sctrls, 131 int sendabandon ) 132 { 133 BerElement *ber; 134 int i, err; 135 Sockbuf *sb; 136 LDAPRequest *lr; 137 138 Debug( LDAP_DEBUG_TRACE, "do_abandon origid %d, msgid %d\n", 139 origid, msgid, 0 ); 140 141 /* find the request that we are abandoning */ 142 start_again:; 143 lr = ld->ld_requests; 144 while ( lr != NULL ) { 145 /* this message */ 146 if ( lr->lr_msgid == msgid ) { 147 break; 148 } 149 150 /* child: abandon it */ 151 if ( lr->lr_origid == msgid && !lr->lr_abandoned ) { 152 (void)do_abandon( ld, lr->lr_origid, lr->lr_msgid, 153 sctrls, sendabandon ); 154 155 /* restart, as lr may now be dangling... */ 156 goto start_again; 157 } 158 159 lr = lr->lr_next; 160 } 161 162 if ( lr != NULL ) { 163 if ( origid == msgid && lr->lr_parent != NULL ) { 164 /* don't let caller abandon child requests! */ 165 ld->ld_errno = LDAP_PARAM_ERROR; 166 return( LDAP_PARAM_ERROR ); 167 } 168 if ( lr->lr_status != LDAP_REQST_INPROGRESS ) { 169 /* no need to send abandon message */ 170 sendabandon = 0; 171 } 172 } 173 174 /* ldap_msgdelete locks the res_mutex. Give up the req_mutex 175 * while we're in there. 176 */ 177 LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex ); 178 err = ldap_msgdelete( ld, msgid ); 179 LDAP_MUTEX_LOCK( &ld->ld_req_mutex ); 180 if ( err == 0 ) { 181 ld->ld_errno = LDAP_SUCCESS; 182 return LDAP_SUCCESS; 183 } 184 185 /* fetch again the request that we are abandoning */ 186 if ( lr != NULL ) { 187 for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) { 188 /* this message */ 189 if ( lr->lr_msgid == msgid ) { 190 break; 191 } 192 } 193 } 194 195 err = 0; 196 if ( sendabandon ) { 197 if ( ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, NULL ) == -1 ) { 198 /* not connected */ 199 err = -1; 200 ld->ld_errno = LDAP_SERVER_DOWN; 201 202 } else if ( ( ber = ldap_alloc_ber_with_options( ld ) ) == NULL ) { 203 /* BER element allocation failed */ 204 err = -1; 205 ld->ld_errno = LDAP_NO_MEMORY; 206 207 } else { 208 /* 209 * We already have the mutex in LDAP_R_COMPILE, so 210 * don't try to get it again. 211 * LDAP_NEXT_MSGID(ld, i); 212 */ 213 214 LDAP_NEXT_MSGID(ld, i); 215 #ifdef LDAP_CONNECTIONLESS 216 if ( LDAP_IS_UDP(ld) ) { 217 struct sockaddr_storage sa = {0}; 218 /* dummy, filled with ldo_peer in request.c */ 219 err = ber_write( ber, (char *) &sa, sizeof(sa), 0 ); 220 } 221 if ( LDAP_IS_UDP(ld) && ld->ld_options.ldo_version == 222 LDAP_VERSION2 ) 223 { 224 char *dn; 225 LDAP_MUTEX_LOCK( &ld->ld_options.ldo_mutex ); 226 dn = ld->ld_options.ldo_cldapdn; 227 if (!dn) dn = ""; 228 err = ber_printf( ber, "{isti", /* '}' */ 229 i, dn, 230 LDAP_REQ_ABANDON, msgid ); 231 LDAP_MUTEX_UNLOCK( &ld->ld_options.ldo_mutex ); 232 } else 233 #endif 234 { 235 /* create a message to send */ 236 err = ber_printf( ber, "{iti", /* '}' */ 237 i, 238 LDAP_REQ_ABANDON, msgid ); 239 } 240 241 if ( err == -1 ) { 242 /* encoding error */ 243 ld->ld_errno = LDAP_ENCODING_ERROR; 244 245 } else { 246 /* Put Server Controls */ 247 if ( ldap_int_put_controls( ld, sctrls, ber ) 248 != LDAP_SUCCESS ) 249 { 250 err = -1; 251 252 } else { 253 /* close '{' */ 254 err = ber_printf( ber, /*{*/ "N}" ); 255 256 if ( err == -1 ) { 257 /* encoding error */ 258 ld->ld_errno = LDAP_ENCODING_ERROR; 259 } 260 } 261 } 262 263 if ( err == -1 ) { 264 ber_free( ber, 1 ); 265 266 } else { 267 /* send the message */ 268 if ( lr != NULL ) { 269 assert( lr->lr_conn != NULL ); 270 sb = lr->lr_conn->lconn_sb; 271 } else { 272 sb = ld->ld_sb; 273 } 274 275 if ( ber_flush2( sb, ber, LBER_FLUSH_FREE_ALWAYS ) != 0 ) { 276 ld->ld_errno = LDAP_SERVER_DOWN; 277 err = -1; 278 } else { 279 err = 0; 280 } 281 } 282 } 283 } 284 285 if ( lr != NULL ) { 286 LDAPConn *lc; 287 int freeconn = 0; 288 if ( sendabandon || lr->lr_status == LDAP_REQST_WRITING ) { 289 freeconn = 1; 290 lc = lr->lr_conn; 291 } 292 if ( origid == msgid ) { 293 ldap_free_request( ld, lr ); 294 295 } else { 296 lr->lr_abandoned = 1; 297 } 298 299 if ( freeconn ) { 300 /* release ld_req_mutex while grabbing ld_conn_mutex to 301 * prevent deadlock. 302 */ 303 LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex ); 304 LDAP_MUTEX_LOCK( &ld->ld_conn_mutex ); 305 ldap_free_connection( ld, lc, 0, 1 ); 306 LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); 307 LDAP_MUTEX_LOCK( &ld->ld_req_mutex ); 308 } 309 } 310 311 LDAP_MUTEX_LOCK( &ld->ld_abandon_mutex ); 312 313 /* use bisection */ 314 i = 0; 315 if ( ld->ld_nabandoned == 0 || 316 ldap_int_bisect_find( ld->ld_abandoned, ld->ld_nabandoned, msgid, &i ) == 0 ) 317 { 318 ldap_int_bisect_insert( &ld->ld_abandoned, &ld->ld_nabandoned, msgid, i ); 319 } 320 321 if ( err != -1 ) { 322 ld->ld_errno = LDAP_SUCCESS; 323 } 324 325 LDAP_MUTEX_UNLOCK( &ld->ld_abandon_mutex ); 326 return( ld->ld_errno ); 327 } 328 329 /* 330 * ldap_int_bisect_find 331 * 332 * args: 333 * v: array of length n (in) 334 * n: length of array v (in) 335 * id: value to look for (in) 336 * idxp: pointer to location of value/insert point 337 * 338 * return: 339 * 0: not found 340 * 1: found 341 * -1: error 342 */ 343 int 344 ldap_int_bisect_find( ber_int_t *v, ber_len_t n, ber_int_t id, int *idxp ) 345 { 346 int begin, 347 end, 348 rc = 0; 349 350 assert( id >= 0 ); 351 352 begin = 0; 353 end = n - 1; 354 355 if ( n <= 0 || id < v[ begin ] ) { 356 *idxp = 0; 357 358 } else if ( id > v[ end ] ) { 359 *idxp = n; 360 361 } else { 362 int pos; 363 ber_int_t curid; 364 365 do { 366 pos = (begin + end)/2; 367 curid = v[ pos ]; 368 369 if ( id < curid ) { 370 end = pos - 1; 371 372 } else if ( id > curid ) { 373 begin = ++pos; 374 375 } else { 376 /* already abandoned? */ 377 rc = 1; 378 break; 379 } 380 } while ( end >= begin ); 381 382 *idxp = pos; 383 } 384 385 return rc; 386 } 387 388 /* 389 * ldap_int_bisect_insert 390 * 391 * args: 392 * vp: pointer to array of length *np (in/out) 393 * np: pointer to length of array *vp (in/out) 394 * id: value to insert (in) 395 * idx: location of insert point (as computed by ldap_int_bisect_find()) 396 * 397 * return: 398 * 0: inserted 399 * -1: error 400 */ 401 int 402 ldap_int_bisect_insert( ber_int_t **vp, ber_len_t *np, int id, int idx ) 403 { 404 ber_int_t *v; 405 ber_len_t n; 406 int i; 407 408 assert( vp != NULL ); 409 assert( np != NULL ); 410 assert( idx >= 0 ); 411 assert( (unsigned) idx <= *np ); 412 413 n = *np; 414 415 v = ber_memrealloc( *vp, sizeof( ber_int_t ) * ( n + 1 ) ); 416 if ( v == NULL ) { 417 return -1; 418 } 419 *vp = v; 420 421 for ( i = n; i > idx; i-- ) { 422 v[ i ] = v[ i - 1 ]; 423 } 424 v[ idx ] = id; 425 ++(*np); 426 427 return 0; 428 } 429 430 /* 431 * ldap_int_bisect_delete 432 * 433 * args: 434 * vp: pointer to array of length *np (in/out) 435 * np: pointer to length of array *vp (in/out) 436 * id: value to delete (in) 437 * idx: location of value to delete (as computed by ldap_int_bisect_find()) 438 * 439 * return: 440 * 0: deleted 441 */ 442 int 443 ldap_int_bisect_delete( ber_int_t **vp, ber_len_t *np, int id, int idx ) 444 { 445 ber_int_t *v; 446 ber_len_t i, n; 447 448 assert( vp != NULL ); 449 assert( np != NULL ); 450 assert( idx >= 0 ); 451 assert( (unsigned) idx < *np ); 452 453 v = *vp; 454 455 assert( v[ idx ] == id ); 456 457 --(*np); 458 n = *np; 459 460 for ( i = idx; i < n; i++ ) { 461 v[ i ] = v[ i + 1 ]; 462 } 463 464 return 0; 465 } 466