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