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