abandon.c 9.05 KB
Newer Older
1
/* abandon.c */
2
/* $OpenLDAP$ */
3
4
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 *
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
5
 * Copyright 1998-2021 The OpenLDAP Foundation.
6
 * All rights reserved.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
7
 *
8
9
10
11
12
13
14
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted only as authorized by the OpenLDAP
 * Public License.
 *
 * A copy of this license is available in the file LICENSE in the
 * top-level directory of the distribution or, alternatively, at
 * <http://www.OpenLDAP.org/license.html>.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
15
 */
16
17
18
/* Portions  Copyright (c) 1990 Regents of the University of Michigan.
 * All rights reserved.
 */
19

Kurt Zeilenga's avatar
Kurt Zeilenga committed
20
21
#include "portable.h"

Kurt Zeilenga's avatar
Kurt Zeilenga committed
22
#include <stdio.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
23
24

#include <ac/stdlib.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
25

Kurt Zeilenga's avatar
Kurt Zeilenga committed
26
27
28
#include <ac/socket.h>
#include <ac/string.h>
#include <ac/time.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
29
30
31

#include "ldap-int.h"

Kurt Zeilenga's avatar
Kurt Zeilenga committed
32
33
34
35
36
/*
 * An abandon request looks like this:
 *		AbandonRequest ::= [APPLICATION 16] MessageID
 * and has no response.  (Source: RFC 4511)
 */
37
#include "lutil.h"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
38

39
40
static int
do_abandon(
Kurt Zeilenga's avatar
Kurt Zeilenga committed
41
	LDAP *ld,
42
	ber_int_t origid,
43
	LDAPRequest *lr,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
44
	LDAPControl **sctrls,
45
	int sendabandon );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
46

Kurt Zeilenga's avatar
Kurt Zeilenga committed
47
/*
Kurt Zeilenga's avatar
Kurt Zeilenga committed
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
 * ldap_abandon_ext - perform an ldap extended abandon operation.
 *
 * Parameters:
 *	ld			LDAP descriptor
 *	msgid		The message id of the operation to abandon
 *	scntrls		Server Controls
 *	ccntrls		Client Controls
 *
 * ldap_abandon_ext returns a LDAP error code.
 *		(LDAP_SUCCESS if everything went ok)
 *
 * Example:
 *	ldap_abandon_ext( ld, msgid, scntrls, ccntrls );
 */
int
ldap_abandon_ext(
	LDAP *ld,
	int msgid,
	LDAPControl **sctrls,
	LDAPControl **cctrls )
{
69
70
	int	rc;

71
	Debug1( LDAP_DEBUG_TRACE, "ldap_abandon_ext %d\n", msgid );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
72

73
	/* check client controls */
Howard Chu's avatar
Howard Chu committed
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

Howard Chu's avatar
Howard Chu committed
81
	LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex );
82

83
	return rc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
84
85
86
87
88
}


/*
 * ldap_abandon - perform an ldap abandon operation. Parameters:
Kurt Zeilenga's avatar
Kurt Zeilenga committed
89
90
91
92
93
94
95
96
97
98
99
100
 *
 *	ld		LDAP descriptor
 *	msgid		The message id of the operation to abandon
 *
 * ldap_abandon returns 0 if everything went ok, -1 otherwise.
 *
 * Example:
 *	ldap_abandon( ld, msgid );
 */
int
ldap_abandon( LDAP *ld, int msgid )
{
101
	Debug1( LDAP_DEBUG_TRACE, "ldap_abandon %d\n", msgid );
102
	return ldap_abandon_ext( ld, msgid, NULL, NULL ) == LDAP_SUCCESS
Kurt Zeilenga's avatar
Kurt Zeilenga committed
103
		? 0 : -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
104
105
106
}


107
int
108
ldap_pvt_discard(
109
110
111
112
113
	LDAP *ld,
	ber_int_t msgid )
{
	int	rc;

Howard Chu's avatar
Howard Chu committed
114
	LDAP_MUTEX_LOCK( &ld->ld_req_mutex );
115
	rc = do_abandon( ld, msgid, NULL, NULL, 0 );
Howard Chu's avatar
Howard Chu committed
116
	LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex );
117
118
119
	return rc;
}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
120
static int
Kurt Zeilenga's avatar
Kurt Zeilenga committed
121
122
do_abandon(
	LDAP *ld,
123
	ber_int_t origid,
124
	LDAPRequest *lr,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
125
	LDAPControl **sctrls,
126
	int sendabandon )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
127
128
{
	BerElement	*ber;
129
	int		i, err;
130
	ber_int_t	msgid = origid;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
131
	Sockbuf		*sb;
132
	LDAPRequest	needle = {0};
133

134
	needle.lr_msgid = origid;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
135
136

	if ( lr != NULL ) {
137
138
139
140
141
142
143
		msgid = lr->lr_msgid;
		Debug2( LDAP_DEBUG_TRACE, "do_abandon origid %d, msgid %d\n",
				origid, msgid );
	} else if ( (lr = ldap_tavl_find( ld->ld_requests, &needle, ldap_req_cmp )) != NULL ) {
		Debug2( LDAP_DEBUG_TRACE, "do_abandon origid %d, msgid %d\n",
				origid, msgid );
		if ( lr->lr_parent != NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
144
145
			/* don't let caller abandon child requests! */
			ld->ld_errno = LDAP_PARAM_ERROR;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
146
			return( LDAP_PARAM_ERROR );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
147
		}
148
149
150
151
152
153
154
155
		msgid = lr->lr_msgid;
	}

	if ( lr != NULL ) {
		LDAPRequest **childp = &lr->lr_child;

		needle.lr_msgid = lr->lr_msgid;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
156
157
158
159
		if ( lr->lr_status != LDAP_REQST_INPROGRESS ) {
			/* no need to send abandon message */
			sendabandon = 0;
		}
160
161
162
163
164
165
166
167
168
169

		while ( *childp ) {
			/* Abandon children */
			LDAPRequest *child = *childp;

			(void)do_abandon( ld, lr->lr_origid, child, sctrls, sendabandon );
			if ( *childp == child ) {
				childp = &child->lr_refnext;
			}
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
170
171
	}

172
173
174
	/* ldap_msgdelete locks the res_mutex. Give up the req_mutex
	 * while we're in there.
	 */
Howard Chu's avatar
Howard Chu committed
175
	LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex );
176
	err = ldap_msgdelete( ld, msgid );
Howard Chu's avatar
Howard Chu committed
177
	LDAP_MUTEX_LOCK( &ld->ld_req_mutex );
178
	if ( err == 0 ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
179
		ld->ld_errno = LDAP_SUCCESS;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
180
		return LDAP_SUCCESS;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
181
182
	}

183
184
	/* fetch again the request that we are abandoning */
	if ( lr != NULL ) {
185
		lr = ldap_tavl_find( ld->ld_requests, &needle, ldap_req_cmp );
186
187
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
188
189
	err = 0;
	if ( sendabandon ) {
190
		if ( ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, NULL ) == -1 ) {
191
192
193
194
			/* not connected */
			err = -1;
			ld->ld_errno = LDAP_SERVER_DOWN;

195
196
		} else if ( ( ber = ldap_alloc_ber_with_options( ld ) ) == NULL ) {
			/* BER element allocation failed */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
197
198
			err = -1;
			ld->ld_errno = LDAP_NO_MEMORY;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
199

Kurt Zeilenga's avatar
Kurt Zeilenga committed
200
		} else {
201
202
203
204
205
206
			/*
			 * We already have the mutex in LDAP_R_COMPILE, so
			 * don't try to get it again.
			 *		LDAP_NEXT_MSGID(ld, i);
			 */

207
			LDAP_NEXT_MSGID(ld, i);
208
209
#ifdef LDAP_CONNECTIONLESS
			if ( LDAP_IS_UDP(ld) ) {
210
				struct sockaddr_storage sa = {0};
Howard Chu's avatar
Howard Chu committed
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 ==
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
215
216
				LDAP_VERSION2 )
			{
217
218
219
				char *dn;
				LDAP_MUTEX_LOCK( &ld->ld_options.ldo_mutex );
				dn = ld->ld_options.ldo_cldapdn;
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
220
221
222
223
				if (!dn) dn = "";
				err = ber_printf( ber, "{isti",  /* '}' */
					i, dn,
					LDAP_REQ_ABANDON, msgid );
224
				LDAP_MUTEX_UNLOCK( &ld->ld_options.ldo_mutex );
225
226
227
			} else
#endif
			{
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
228
229
230
231
				/* create a message to send */
				err = ber_printf( ber, "{iti",  /* '}' */
					i,
					LDAP_REQ_ABANDON, msgid );
232
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
233

234
			if ( err == -1 ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
235
				/* encoding error */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
236
				ld->ld_errno = LDAP_ENCODING_ERROR;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
237
238
239
240
241
242
243
244
245
246

			} else {
				/* Put Server Controls */
				if ( ldap_int_put_controls( ld, sctrls, ber )
					!= LDAP_SUCCESS )
				{
					err = -1;

				} else {
					/* close '{' */
247
					err = ber_printf( ber, /*{*/ "N}" );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
248

249
					if ( err == -1 ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
250
251
252
253
254
255
256
						/* encoding error */
						ld->ld_errno = LDAP_ENCODING_ERROR;
					}
				}
			}

			if ( err == -1 ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
257
				ber_free( ber, 1 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
258

Kurt Zeilenga's avatar
Kurt Zeilenga committed
259
260
261
			} else {
				/* send the message */
				if ( lr != NULL ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
262
					assert( lr->lr_conn != NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
263
					sb = lr->lr_conn->lconn_sb;
Kurt Zeilenga's avatar
ldap.h:    
Kurt Zeilenga committed
264
				} else {
265
					sb = ld->ld_sb;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
266
				}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
267

Pierangelo Masarati's avatar
Pierangelo Masarati committed
268
				if ( ber_flush2( sb, ber, LBER_FLUSH_FREE_ALWAYS ) != 0 ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
269
270
271
272
273
274
275
276
277
278
					ld->ld_errno = LDAP_SERVER_DOWN;
					err = -1;
				} else {
					err = 0;
				}
			}
		}
	}

	if ( lr != NULL ) {
Howard Chu's avatar
Howard Chu committed
279
280
		LDAPConn *lc;
		int freeconn = 0;
281
		if ( sendabandon || lr->lr_status == LDAP_REQST_WRITING ) {
Howard Chu's avatar
Howard Chu committed
282
283
284
285
286
287
288
289
290
291
292
			freeconn = 1;
			lc = lr->lr_conn;
		}
		if ( origid == msgid ) {
			ldap_free_request( ld, lr );

		} else {
			lr->lr_abandoned = 1;
		}

		if ( freeconn ) {
293
294
295
296
			/* release ld_req_mutex while grabbing ld_conn_mutex to
			 * prevent deadlock.
			 */
			LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex );
297
			LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
Howard Chu's avatar
Howard Chu committed
298
			ldap_free_connection( ld, lc, 0, 1 );
299
			LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
300
			LDAP_MUTEX_LOCK( &ld->ld_req_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
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
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
313
314
315
316

	if ( err != -1 ) {
		ld->ld_errno = LDAP_SUCCESS;
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
317

318
	LDAP_MUTEX_UNLOCK( &ld->ld_abandon_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
319
	return( ld->ld_errno );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
320
}
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347

/*
 * ldap_int_bisect_find
 *
 * args:
 *	v:	array of length n (in)
 *	n:	length of array v (in)
 *	id:	value to look for (in)
 *	idxp:	pointer to location of value/insert point
 *
 * return:
 *	0:	not found
 *	1:	found
 *	-1:	error
 */
int
ldap_int_bisect_find( ber_int_t *v, ber_len_t n, ber_int_t id, int *idxp )
{
	int		begin,
			end,
			rc = 0;

	assert( id >= 0 );

	begin = 0;
	end = n - 1;

348
		if ( n <= 0 || id < v[ begin ] ) {
349
350
351
352
353
354
355
356
357
			*idxp = 0;

		} else if ( id > v[ end ] ) {
			*idxp = n;

		} else {
			int		pos;
			ber_int_t	curid;
	
358
			do {
359
360
361
362
363
364
365
				pos = (begin + end)/2;
				curid = v[ pos ];
	
				if ( id < curid ) {
					end = pos - 1;
	
				} else if ( id > curid ) {
366
					begin = ++pos;
367
368
369
370
371
372
	
				} else {
					/* already abandoned? */
					rc = 1;
					break;
				}
373
			} while ( end >= begin );
374
	
375
			*idxp = pos;
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
		}

	return rc;
}

/*
 * ldap_int_bisect_insert
 *
 * args:
 *	vp:	pointer to array of length *np (in/out)
 *	np:	pointer to length of array *vp (in/out)
 *	id:	value to insert (in)
 *	idx:	location of insert point (as computed by ldap_int_bisect_find())
 *
 * return:
 *	0:	inserted
 *	-1:	error
 */
int
ldap_int_bisect_insert( ber_int_t **vp, ber_len_t *np, int id, int idx )
{
	ber_int_t	*v;
	ber_len_t	n;
	int		i;

	assert( vp != NULL );
	assert( np != NULL );
	assert( idx >= 0 );
404
	assert( (unsigned) idx <= *np );
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438

	n = *np;

	v = ber_memrealloc( *vp, sizeof( ber_int_t ) * ( n + 1 ) );
	if ( v == NULL ) {
		return -1;
	}
	*vp = v;

	for ( i = n; i > idx; i-- ) {
		v[ i ] = v[ i - 1 ];
	}
	v[ idx ] = id;
	++(*np);

	return 0;
}

/*
 * ldap_int_bisect_delete
 *
 * args:
 *	vp:	pointer to array of length *np (in/out)
 *	np:	pointer to length of array *vp (in/out)
 *	id:	value to delete (in)
 *	idx:	location of value to delete (as computed by ldap_int_bisect_find())
 *
 * return:
 *	0:	deleted
 */
int
ldap_int_bisect_delete( ber_int_t **vp, ber_len_t *np, int id, int idx )
{
	ber_int_t	*v;
439
	ber_len_t	i, n;
440
441
442
443

	assert( vp != NULL );
	assert( np != NULL );
	assert( idx >= 0 );
444
	assert( (unsigned) idx < *np );
445
446
447
448
449
450
451
452
453
454
455
456
457
458

	v = *vp;

	assert( v[ idx ] == id );

	--(*np);
	n = *np;

	for ( i = idx; i < n; i++ ) {
		v[ i ] = v[ i + 1 ];
	}

	return 0;
}