1/* $OpenLDAP$ */
2/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3 *
4 * Copyright 1998-2011 The OpenLDAP Foundation.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
9 * Public License.
10 *
11 * A copy of this license is available in the file LICENSE in the
12 * top-level directory of the distribution or, alternatively, at
13 * <http://www.OpenLDAP.org/license.html>.
14 */
15/* Portions Copyright (c) 1990 Regents of the University of Michigan.
16 * All rights reserved.
17 */
18
19#include "portable.h"
20
21#include <stdio.h>
22#include <ac/stdlib.h>
23
24#include <ac/socket.h>
25#include <ac/string.h>
26#include <ac/time.h>
27
28#include "ldap-int.h"
29
30/* An Unbind Request looks like this:
31 *
32 *	UnbindRequest ::= [APPLICATION 2] NULL
33 *
34 * and has no response.  (Source: RFC 4511)
35 */
36
37#ifdef LDAP_RESPONSE_RB_TREE
38#include "rb_response.h"
39#endif
40
41int
42ldap_unbind_ext(
43	LDAP *ld,
44	LDAPControl **sctrls,
45	LDAPControl **cctrls )
46{
47	int rc;
48
49	assert( ld != NULL );
50	assert( LDAP_VALID( ld ) );
51
52	/* check client controls */
53	rc = ldap_int_client_controls( ld, cctrls );
54	if( rc != LDAP_SUCCESS ) return rc;
55
56	return ldap_ld_free( ld, 1, sctrls, cctrls );
57}
58
59int
60ldap_unbind_ext_s(
61	LDAP *ld,
62	LDAPControl **sctrls,
63	LDAPControl **cctrls )
64{
65	return ldap_unbind_ext( ld, sctrls, cctrls );
66}
67
68int
69ldap_unbind( LDAP *ld )
70{
71	Debug( LDAP_DEBUG_TRACE, "ldap_unbind\n", 0, 0, 0 );
72
73	return( ldap_unbind_ext( ld, NULL, NULL ) );
74}
75
76
77int
78ldap_ld_free(
79	LDAP *ld,
80	int close,
81	LDAPControl **sctrls,
82	LDAPControl **cctrls )
83{
84	LDAPMessage	*lm, *next;
85	int		err = LDAP_SUCCESS;
86    LDAP_MUTEX_LOCK( &ld->ld_ldcmutex );
87	/* Someone else is still using this ld. */
88	if (ld->ld_ldcrefcnt > 1) {	/* but not last thread */
89		/* clean up self only */
90		ld->ld_ldcrefcnt--;
91		if ( ld->ld_error != NULL ) {
92			LDAP_FREE( ld->ld_error );
93			ld->ld_error = NULL;
94		}
95
96		if ( ld->ld_matched != NULL ) {
97			LDAP_FREE( ld->ld_matched );
98			ld->ld_matched = NULL;
99		}
100		if ( ld->ld_referrals != NULL) {
101			LDAP_VFREE(ld->ld_referrals);
102			ld->ld_referrals = NULL;
103		}
104		LDAP_MUTEX_UNLOCK( &ld->ld_ldcmutex );
105		LDAP_FREE( (char *) ld );
106		return( err );
107	}
108
109	/* This ld is the last thread. */
110
111	/* free LDAP structure and outstanding requests/responses */
112#ifdef LDAP_R_COMPILE
113#ifdef __APPLE__
114	/* If the ld is in async mode, this will stop the thread that's handling
115	 * the results messages.  This *must* be done before anything is torn
116	 * down to prevent the thread from using deallocated structs.  This is a
117	 * blocking call; it won't exit until the thread exits.	 If not in
118	 * async mode, this call does nothing.
119	 */
120	ldap_pvt_clear_search_results_callback( ld );
121#endif
122#endif
123	LDAP_MUTEX_LOCK( &ld->ld_req_mutex );
124	while ( ld->ld_requests != NULL ) {
125		ldap_free_request( ld, ld->ld_requests );
126	}
127	LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex );
128	LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
129
130	/* free and unbind from all open connections */
131	while ( ld->ld_conns != NULL ) {
132		ldap_free_connection( ld, ld->ld_conns, 1, close );
133	}
134	LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
135	LDAP_MUTEX_LOCK( &ld->ld_res_mutex );
136
137#ifdef LDAP_RESPONSE_RB_TREE
138    ldap_resp_rbt_free( ld );
139#else
140	for ( lm = ld->ld_responses; lm != NULL; lm = next ) {
141		next = lm->lm_next;
142		ldap_msgfree( lm );
143	}
144#endif
145
146	if ( ld->ld_abandoned != NULL ) {
147		LDAP_FREE( ld->ld_abandoned );
148		ld->ld_abandoned = NULL;
149	}
150	LDAP_MUTEX_UNLOCK( &ld->ld_res_mutex );
151	LDAP_MUTEX_LOCK( &ld->ld_ldopts_mutex );
152
153	/* final close callbacks */
154	{
155		ldaplist *ll, *next;
156
157		for ( ll = ld->ld_options.ldo_conn_cbs; ll; ll = next ) {
158			ldap_conncb *cb = ll->ll_data;
159			next = ll->ll_next;
160			cb->lc_del( ld, NULL, cb );
161			LDAP_FREE( ll );
162		}
163	}
164
165	if ( ld->ld_error != NULL ) {
166		LDAP_FREE( ld->ld_error );
167		ld->ld_error = NULL;
168	}
169
170	if ( ld->ld_matched != NULL ) {
171		LDAP_FREE( ld->ld_matched );
172		ld->ld_matched = NULL;
173	}
174
175	if ( ld->ld_referrals != NULL) {
176		LDAP_VFREE(ld->ld_referrals);
177		ld->ld_referrals = NULL;
178	}
179
180	if ( ld->ld_selectinfo != NULL ) {
181		ldap_free_select_info( ld->ld_selectinfo );
182		ld->ld_selectinfo = NULL;
183	}
184
185	if ( ld->ld_options.ldo_defludp != NULL ) {
186		ldap_free_urllist( ld->ld_options.ldo_defludp );
187		ld->ld_options.ldo_defludp = NULL;
188	}
189
190#ifdef LDAP_CONNECTIONLESS
191	if ( ld->ld_options.ldo_peer != NULL ) {
192		LDAP_FREE( ld->ld_options.ldo_peer );
193		ld->ld_options.ldo_peer = NULL;
194	}
195
196	if ( ld->ld_options.ldo_cldapdn != NULL ) {
197		LDAP_FREE( ld->ld_options.ldo_cldapdn );
198		ld->ld_options.ldo_cldapdn = NULL;
199	}
200#endif
201
202#ifdef HAVE_CYRUS_SASL
203	if ( ld->ld_options.ldo_def_sasl_mech != NULL ) {
204		LDAP_FREE( ld->ld_options.ldo_def_sasl_mech );
205		ld->ld_options.ldo_def_sasl_mech = NULL;
206	}
207
208	if ( ld->ld_options.ldo_def_sasl_realm != NULL ) {
209		LDAP_FREE( ld->ld_options.ldo_def_sasl_realm );
210		ld->ld_options.ldo_def_sasl_realm = NULL;
211	}
212
213	if ( ld->ld_options.ldo_def_sasl_authcid != NULL ) {
214		LDAP_FREE( ld->ld_options.ldo_def_sasl_authcid );
215		ld->ld_options.ldo_def_sasl_authcid = NULL;
216	}
217
218	if ( ld->ld_options.ldo_def_sasl_authzid != NULL ) {
219		LDAP_FREE( ld->ld_options.ldo_def_sasl_authzid );
220		ld->ld_options.ldo_def_sasl_authzid = NULL;
221	}
222#endif
223
224#ifdef HAVE_TLS
225	ldap_int_tls_destroy( &ld->ld_options );
226#endif
227
228	if ( ld->ld_options.ldo_sctrls != NULL ) {
229		ldap_controls_free( ld->ld_options.ldo_sctrls );
230		ld->ld_options.ldo_sctrls = NULL;
231	}
232
233	if ( ld->ld_options.ldo_cctrls != NULL ) {
234		ldap_controls_free( ld->ld_options.ldo_cctrls );
235		ld->ld_options.ldo_cctrls = NULL;
236	}
237
238	if ( ld->ld_options.ldo_sasl_secprops.property_names != NULL ) {
239		LDAP_FREE( ld->ld_options.ldo_sasl_secprops.property_names );
240		ld->ld_options.ldo_sasl_secprops.property_names = NULL;
241	}
242
243	if ( ld->ld_options.ldo_sasl_secprops.property_values != NULL ) {
244		LDAP_FREE( ld->ld_options.ldo_sasl_secprops.property_values );
245		ld->ld_options.ldo_sasl_secprops.property_values = NULL;
246	}
247
248	if ( ld->ld_options.ldo_sasl_fqdn != NULL ) {
249		LDAP_FREE( ld->ld_options.ldo_sasl_fqdn );
250		ld->ld_options.ldo_sasl_fqdn = NULL;
251	}
252    LDAP_MUTEX_UNLOCK( &ld->ld_ldopts_mutex );
253	ber_sockbuf_free( ld->ld_sb );
254
255#ifdef LDAP_R_COMPILE
256	ldap_pvt_thread_mutex_destroy( &ld->ld_msgid_mutex );
257	ldap_pvt_thread_mutex_destroy( &ld->ld_conn_mutex );
258	ldap_pvt_thread_mutex_destroy( &ld->ld_req_mutex );
259	ldap_pvt_thread_mutex_destroy( &ld->ld_res_mutex );
260	ldap_pvt_thread_mutex_destroy( &ld->ld_abandon_mutex );
261	ldap_pvt_thread_mutex_destroy( &ld->ld_ldopts_mutex );
262	ldap_pvt_thread_mutex_unlock( &ld->ld_ldcmutex );
263	ldap_pvt_thread_mutex_destroy( &ld->ld_ldcmutex );
264#endif
265#ifndef NDEBUG
266	LDAP_TRASH(ld);
267#endif
268	LDAP_FREE( (char *) ld->ldc );
269	LDAP_FREE( (char *) ld );
270
271	return( err );
272}
273
274int
275ldap_destroy( LDAP *ld )
276{
277	return ( ldap_ld_free( ld, 1, NULL, NULL ) );
278}
279
280int
281ldap_unbind_s( LDAP *ld )
282{
283	return( ldap_unbind_ext( ld, NULL, NULL ) );
284}
285
286/* FIXME: this function is called only by ldap_free_connection(),
287 * which, most of the times, is called with ld_req_mutex locked */
288int
289ldap_send_unbind(
290	LDAP *ld,
291	Sockbuf *sb,
292	LDAPControl **sctrls,
293	LDAPControl **cctrls )
294{
295	BerElement	*ber;
296	ber_int_t	id;
297
298	Debug( LDAP_DEBUG_TRACE, "ldap_send_unbind\n", 0, 0, 0 );
299
300#ifdef LDAP_CONNECTIONLESS
301	if (LDAP_IS_UDP(ld))
302		return LDAP_SUCCESS;
303#endif
304	/* create a message to send */
305	if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) {
306		return( ld->ld_errno );
307	}
308
309	LDAP_NEXT_MSGID(ld, id);
310
311	/* fill it in */
312	if ( ber_printf( ber, "{itn" /*}*/, id,
313	    LDAP_REQ_UNBIND ) == -1 ) {
314		ld->ld_errno = LDAP_ENCODING_ERROR;
315		ber_free( ber, 1 );
316		return( ld->ld_errno );
317	}
318
319	/* Put Server Controls */
320	if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) {
321		ber_free( ber, 1 );
322		return ld->ld_errno;
323	}
324
325	if ( ber_printf( ber, /*{*/ "N}", LDAP_REQ_UNBIND ) == -1 ) {
326		ld->ld_errno = LDAP_ENCODING_ERROR;
327		ber_free( ber, 1 );
328		return( ld->ld_errno );
329	}
330
331	ld->ld_errno = LDAP_SUCCESS;
332	/* send the message */
333	if ( ber_flush2( sb, ber, LBER_FLUSH_FREE_ALWAYS ) == -1 ) {
334		ld->ld_errno = LDAP_SERVER_DOWN;
335	}
336
337	return( ld->ld_errno );
338}
339