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
ldap_abandon_ext(LDAP * ld,int msgid,LDAPControl ** sctrls,LDAPControl ** cctrls)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
ldap_abandon(LDAP * ld,int msgid)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
ldap_pvt_discard(LDAP * ld,ber_int_t msgid)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
do_abandon(LDAP * ld,ber_int_t origid,LDAPRequest * lr,LDAPControl ** sctrls,int sendabandon)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
ldap_int_bisect_find(ber_int_t * v,ber_len_t n,ber_int_t id,int * idxp)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
ldap_int_bisect_insert(ber_int_t ** vp,ber_len_t * np,int id,int idx)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
ldap_int_bisect_delete(ber_int_t ** vp,ber_len_t * np,int id,int idx)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