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