xref: /netbsd-src/external/bsd/openldap/dist/libraries/libldap/abandon.c (revision 946379e7b37692fc43f68eb0d1c10daa0a7f3b6c)
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