1/* $NetBSD: unbind.c,v 1.3 2021/08/14 16:14:56 christos Exp $ */ 2 3/* $OpenLDAP$ */ 4/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 * 6 * Copyright 1998-2021 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.3 2021/08/14 16:14:56 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 42int 43ldap_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 60int 61ldap_unbind_ext_s( 62 LDAP *ld, 63 LDAPControl **sctrls, 64 LDAPControl **cctrls ) 65{ 66 return ldap_unbind_ext( ld, sctrls, cctrls ); 67} 68 69int 70ldap_unbind( LDAP *ld ) 71{ 72 Debug0( LDAP_DEBUG_TRACE, "ldap_unbind\n" ); 73 74 return( ldap_unbind_ext( ld, NULL, NULL ) ); 75} 76 77 78int 79ldap_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 ldap_tavl_free( ld->ld_requests, ldap_do_free_request ); 117 ld->ld_requests = NULL; 118 LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex ); 119 LDAP_MUTEX_LOCK( &ld->ld_conn_mutex ); 120 121 /* free and unbind from all open connections */ 122 while ( ld->ld_conns != NULL ) { 123 ldap_free_connection( ld, ld->ld_conns, 1, close ); 124 } 125 LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); 126 LDAP_MUTEX_LOCK( &ld->ld_res_mutex ); 127 for ( lm = ld->ld_responses; lm != NULL; lm = next ) { 128 next = lm->lm_next; 129 ldap_msgfree( lm ); 130 } 131 132 if ( ld->ld_abandoned != NULL ) { 133 LDAP_FREE( ld->ld_abandoned ); 134 ld->ld_abandoned = NULL; 135 } 136 LDAP_MUTEX_UNLOCK( &ld->ld_res_mutex ); 137 138 /* Should already be closed by ldap_free_connection which knows not to free 139 * this one */ 140 ber_int_sb_destroy( ld->ld_sb ); 141 LBER_FREE( ld->ld_sb ); 142 143 LDAP_MUTEX_LOCK( &ld->ld_ldopts_mutex ); 144 145 /* final close callbacks */ 146 { 147 ldaplist *ll, *next; 148 149 for ( ll = ld->ld_options.ldo_conn_cbs; ll; ll = next ) { 150 ldap_conncb *cb = ll->ll_data; 151 next = ll->ll_next; 152 cb->lc_del( ld, NULL, cb ); 153 LDAP_FREE( ll ); 154 } 155 } 156 157 if ( ld->ld_error != NULL ) { 158 LDAP_FREE( ld->ld_error ); 159 ld->ld_error = NULL; 160 } 161 162 if ( ld->ld_matched != NULL ) { 163 LDAP_FREE( ld->ld_matched ); 164 ld->ld_matched = NULL; 165 } 166 167 if ( ld->ld_referrals != NULL) { 168 LDAP_VFREE(ld->ld_referrals); 169 ld->ld_referrals = NULL; 170 } 171 172 if ( ld->ld_selectinfo != NULL ) { 173 ldap_free_select_info( ld->ld_selectinfo ); 174 ld->ld_selectinfo = NULL; 175 } 176 177 if ( ld->ld_options.ldo_defludp != NULL ) { 178 ldap_free_urllist( ld->ld_options.ldo_defludp ); 179 ld->ld_options.ldo_defludp = NULL; 180 } 181 182 if ( ld->ld_options.ldo_local_ip_addrs.local_ip_addrs ) { 183 LDAP_FREE( ld->ld_options.ldo_local_ip_addrs.local_ip_addrs ); 184 memset( & ld->ld_options.ldo_local_ip_addrs, 0, 185 sizeof( ldapsourceip ) ); 186 } 187 188#ifdef LDAP_CONNECTIONLESS 189 if ( ld->ld_options.ldo_peer != NULL ) { 190 LDAP_FREE( ld->ld_options.ldo_peer ); 191 ld->ld_options.ldo_peer = NULL; 192 } 193 194 if ( ld->ld_options.ldo_cldapdn != NULL ) { 195 LDAP_FREE( ld->ld_options.ldo_cldapdn ); 196 ld->ld_options.ldo_cldapdn = NULL; 197 } 198#endif 199 200 if ( ld->ld_options.ldo_defbase != NULL ) { 201 LDAP_FREE( ld->ld_options.ldo_defbase ); 202 ld->ld_options.ldo_defbase = NULL; 203 } 204 205#ifdef HAVE_CYRUS_SASL 206 if ( ld->ld_options.ldo_def_sasl_mech != NULL ) { 207 LDAP_FREE( ld->ld_options.ldo_def_sasl_mech ); 208 ld->ld_options.ldo_def_sasl_mech = NULL; 209 } 210 211 if ( ld->ld_options.ldo_def_sasl_realm != NULL ) { 212 LDAP_FREE( ld->ld_options.ldo_def_sasl_realm ); 213 ld->ld_options.ldo_def_sasl_realm = NULL; 214 } 215 216 if ( ld->ld_options.ldo_def_sasl_authcid != NULL ) { 217 LDAP_FREE( ld->ld_options.ldo_def_sasl_authcid ); 218 ld->ld_options.ldo_def_sasl_authcid = NULL; 219 } 220 221 if ( ld->ld_options.ldo_def_sasl_authzid != NULL ) { 222 LDAP_FREE( ld->ld_options.ldo_def_sasl_authzid ); 223 ld->ld_options.ldo_def_sasl_authzid = NULL; 224 } 225#endif 226 227#ifdef HAVE_TLS 228 ldap_int_tls_destroy( &ld->ld_options ); 229#endif 230 231 if ( ld->ld_options.ldo_sctrls != NULL ) { 232 ldap_controls_free( ld->ld_options.ldo_sctrls ); 233 ld->ld_options.ldo_sctrls = NULL; 234 } 235 236 if ( ld->ld_options.ldo_cctrls != NULL ) { 237 ldap_controls_free( ld->ld_options.ldo_cctrls ); 238 ld->ld_options.ldo_cctrls = NULL; 239 } 240 LDAP_MUTEX_UNLOCK( &ld->ld_ldopts_mutex ); 241 242#ifdef LDAP_R_COMPILE 243 ldap_pvt_thread_mutex_destroy( &ld->ld_msgid_mutex ); 244 ldap_pvt_thread_mutex_destroy( &ld->ld_conn_mutex ); 245 ldap_pvt_thread_mutex_destroy( &ld->ld_req_mutex ); 246 ldap_pvt_thread_mutex_destroy( &ld->ld_res_mutex ); 247 ldap_pvt_thread_mutex_destroy( &ld->ld_abandon_mutex ); 248 ldap_pvt_thread_mutex_destroy( &ld->ld_ldopts_mutex ); 249 ldap_pvt_thread_mutex_destroy( &ld->ld_ldcmutex ); 250#endif 251#ifndef NDEBUG 252 LDAP_TRASH(ld); 253#endif 254 LDAP_FREE( (char *) ld->ldc ); 255 LDAP_FREE( (char *) ld ); 256 257 return( err ); 258} 259 260int 261ldap_destroy( LDAP *ld ) 262{ 263 return ( ldap_ld_free( ld, 1, NULL, NULL ) ); 264} 265 266int 267ldap_unbind_s( LDAP *ld ) 268{ 269 return( ldap_unbind_ext( ld, NULL, NULL ) ); 270} 271 272/* FIXME: this function is called only by ldap_free_connection(), 273 * which, most of the times, is called with ld_req_mutex locked */ 274int 275ldap_send_unbind( 276 LDAP *ld, 277 Sockbuf *sb, 278 LDAPControl **sctrls, 279 LDAPControl **cctrls ) 280{ 281 BerElement *ber; 282 ber_int_t id; 283 284 Debug0( LDAP_DEBUG_TRACE, "ldap_send_unbind\n" ); 285 286#ifdef LDAP_CONNECTIONLESS 287 if (LDAP_IS_UDP(ld)) 288 return LDAP_SUCCESS; 289#endif 290 /* create a message to send */ 291 if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) { 292 return( ld->ld_errno ); 293 } 294 295 LDAP_NEXT_MSGID(ld, id); 296 297 /* fill it in */ 298 if ( ber_printf( ber, "{itn" /*}*/, id, 299 LDAP_REQ_UNBIND ) == -1 ) { 300 ld->ld_errno = LDAP_ENCODING_ERROR; 301 ber_free( ber, 1 ); 302 return( ld->ld_errno ); 303 } 304 305 /* Put Server Controls */ 306 if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) { 307 ber_free( ber, 1 ); 308 return ld->ld_errno; 309 } 310 311 if ( ber_printf( ber, /*{*/ "N}", LDAP_REQ_UNBIND ) == -1 ) { 312 ld->ld_errno = LDAP_ENCODING_ERROR; 313 ber_free( ber, 1 ); 314 return( ld->ld_errno ); 315 } 316 317 ld->ld_errno = LDAP_SUCCESS; 318 /* send the message */ 319 if ( ber_flush2( sb, ber, LBER_FLUSH_FREE_ALWAYS ) == -1 ) { 320 ld->ld_errno = LDAP_SERVER_DOWN; 321 } 322 323 return( ld->ld_errno ); 324} 325