1 /* 2 * lib/kdb/kdb_ldap/ldap_handle.c 3 * 4 * Copyright (c) 2004-2005, Novell, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are met: 9 * 10 * * Redistributions of source code must retain the above copyright notice, 11 * this list of conditions and the following disclaimer. 12 * * Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * * The copyright holder's name is not used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "ldap_main.h" 32 33 34 #ifdef ASYNC_BIND 35 36 /* 37 * Update the server info structure. In case of an asynchronous bind, 38 * this function is called to check the bind status. A flag 39 * server_info_upate_pending is refered before calling this function. 40 * This function sets the server_status to either ON or OFF and 41 * sets the server_info_udpate_pending to OFF. 42 * Do not lock the mutex here. The caller should lock it 43 */ 44 45 static krb5_error_code 46 krb5_update_server_info(ldap_server_handle, server_info) 47 krb5_ldap_server_handle *ldap_server_handle; 48 krb5_ldap_server_info *server_info; 49 { 50 krb5_error_code st=0; 51 struct timeval ztime={0, 0}; 52 LDAPMessage *result=NULL; 53 54 if (ldap_server_handle == NULL || server_info == NULL) 55 return -1; 56 57 while (st == 0) { 58 st = ldap_result(ldap_server_handle->ldap_handle, ldap_server_handle->msgid, 59 LDAP_MSG_ALL, &ztime, &result); 60 switch (st) { 61 case -1: 62 server_info->server_status = OFF; 63 time(&server_info->downtime); 64 break; 65 66 case 0: 67 continue; 68 break; 69 70 case LDAP_RES_BIND: 71 if ((st=ldap_result2error(ldap_server_handle->ldap_handle, result, 1)) == LDAP_SUCCESS) { 72 server_info->server_status = ON; 73 } else { 74 /* ?? */ krb5_set_error_message(0, 0, "%s", ldap_err2string(st)); 75 server_info->server_status = OFF; 76 time(&server_info->downtime); 77 } 78 ldap_msgfree(result); 79 break; 80 default: 81 ldap_msgfree(result); 82 continue; 83 break; 84 } 85 } 86 ldap_server_handle->server_info_update_pending = FALSE; 87 return 0; 88 } 89 #endif 90 91 /* 92 * Return ldap server handle from the pool. If the pool is exhausted return NULL. 93 * Do not lock the mutex, caller should lock it 94 */ 95 96 static krb5_ldap_server_handle * 97 krb5_get_ldap_handle(ldap_context) 98 krb5_ldap_context *ldap_context; 99 { 100 krb5_ldap_server_handle *ldap_server_handle=NULL; 101 krb5_ldap_server_info *ldap_server_info=NULL; 102 int cnt=0; 103 104 while (ldap_context->server_info_list[cnt] != NULL) { 105 ldap_server_info = ldap_context->server_info_list[cnt]; 106 if (ldap_server_info->server_status != OFF) { 107 if (ldap_server_info->ldap_server_handles != NULL) { 108 ldap_server_handle = ldap_server_info->ldap_server_handles; 109 ldap_server_info->ldap_server_handles = ldap_server_handle->next; 110 break; 111 #ifdef ASYNC_BIND 112 if (ldap_server_handle->server_info_update_pending == TRUE) { 113 krb5_update_server_info(context, ldap_server_handle, 114 ldap_server_info); 115 } 116 117 if (ldap_server_info->server_status == ON) { 118 ldap_server_info->ldap_server_handles = ldap_server_handle->next; 119 break; 120 } else 121 ldap_server_handle = NULL; 122 #endif 123 } 124 } 125 ++cnt; 126 } 127 return ldap_server_handle; 128 } 129 130 /* 131 * This is called incase krb5_get_ldap_handle returns NULL. 132 * Try getting a single connection (handle) and return the same by 133 * calling krb5_get_ldap_handle function. 134 * Do not lock the mutex here. The caller should lock it 135 */ 136 137 static krb5_ldap_server_handle * 138 krb5_retry_get_ldap_handle(ldap_context, st) 139 krb5_ldap_context *ldap_context; 140 krb5_error_code *st; 141 { 142 krb5_ldap_server_handle *ldap_server_handle=NULL; 143 144 if ((*st=krb5_ldap_db_single_init(ldap_context)) != 0) 145 return NULL; 146 147 ldap_server_handle = krb5_get_ldap_handle(ldap_context); 148 return ldap_server_handle; 149 } 150 151 /* 152 * Put back the ldap server handle to the front of the list of handles of the 153 * ldap server info structure. 154 * Do not lock the mutex here. The caller should lock it. 155 */ 156 157 static krb5_error_code 158 krb5_put_ldap_handle(ldap_server_handle) 159 krb5_ldap_server_handle *ldap_server_handle; 160 { 161 162 if (ldap_server_handle == NULL) 163 return 0; 164 165 ldap_server_handle->next = ldap_server_handle->server_info->ldap_server_handles; 166 ldap_server_handle->server_info->ldap_server_handles = ldap_server_handle; 167 return 0; 168 } 169 170 /* 171 * Add a new ldap server handle structure to the server info structure. 172 * This function name can be changed to krb5_insert_ldap_handle. 173 * Do not lock the mutex here. The caller should lock it 174 */ 175 176 krb5_error_code 177 krb5_update_ldap_handle(ldap_server_handle, server_info) 178 krb5_ldap_server_handle *ldap_server_handle; 179 krb5_ldap_server_info *server_info; 180 { 181 182 if (ldap_server_handle == NULL || server_info == NULL) 183 return 0; 184 185 ldap_server_handle->next = server_info->ldap_server_handles; 186 server_info->ldap_server_handles = ldap_server_handle; 187 server_info->num_conns++; 188 ldap_server_handle->server_info = server_info; 189 return 0; 190 } 191 192 /* 193 * Free up all the ldap server handles of the server info. 194 * This function is called when the ldap server returns LDAP_SERVER_DOWN. 195 */ 196 197 static krb5_error_code 198 krb5_ldap_cleanup_handles(ldap_server_info) 199 krb5_ldap_server_info *ldap_server_info; 200 { 201 krb5_ldap_server_handle *ldap_server_handle = NULL; 202 203 while (ldap_server_info->ldap_server_handles != NULL) { 204 ldap_server_handle = ldap_server_info->ldap_server_handles; 205 ldap_server_info->ldap_server_handles = ldap_server_handle->next; 206 /* Solaris kerberos: don't leak ldap handles */ 207 ldap_unbind_s(ldap_server_handle->ldap_handle); 208 free (ldap_server_handle); 209 ldap_server_handle = NULL; 210 } 211 return 0; 212 } 213 214 /* 215 * wrapper function called from outside to get a handle. 216 */ 217 218 krb5_error_code 219 krb5_ldap_request_handle_from_pool(ldap_context, ldap_server_handle) 220 krb5_ldap_context *ldap_context; 221 krb5_ldap_server_handle **ldap_server_handle; 222 { 223 krb5_error_code st=0; 224 225 *ldap_server_handle = NULL; 226 227 HNDL_LOCK(ldap_context); 228 if (((*ldap_server_handle)=krb5_get_ldap_handle(ldap_context)) == NULL) 229 (*ldap_server_handle)=krb5_retry_get_ldap_handle(ldap_context, &st); 230 HNDL_UNLOCK(ldap_context); 231 return st; 232 } 233 234 /* 235 * wrapper function wrapper called to get the next ldap server handle, when the current 236 * ldap server handle returns LDAP_SERVER_DOWN. 237 */ 238 239 krb5_error_code 240 krb5_ldap_request_next_handle_from_pool(ldap_context, ldap_server_handle) 241 krb5_ldap_context *ldap_context; 242 krb5_ldap_server_handle **ldap_server_handle; 243 { 244 krb5_error_code st=0; 245 246 HNDL_LOCK(ldap_context); 247 (*ldap_server_handle)->server_info->server_status = OFF; 248 time(&(*ldap_server_handle)->server_info->downtime); 249 krb5_put_ldap_handle(*ldap_server_handle); 250 krb5_ldap_cleanup_handles((*ldap_server_handle)->server_info); 251 252 if (((*ldap_server_handle)=krb5_get_ldap_handle(ldap_context)) == NULL) 253 (*ldap_server_handle)=krb5_retry_get_ldap_handle(ldap_context, &st); 254 HNDL_UNLOCK(ldap_context); 255 return st; 256 } 257 258 /* 259 * wrapper function to call krb5_put_ldap_handle. 260 */ 261 262 void 263 krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle) 264 krb5_ldap_context *ldap_context; 265 krb5_ldap_server_handle *ldap_server_handle; 266 { 267 268 if (ldap_server_handle != NULL) { 269 HNDL_LOCK(ldap_context); 270 krb5_put_ldap_handle(ldap_server_handle); 271 HNDL_UNLOCK(ldap_context); 272 } 273 return; 274 } 275 276