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