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