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
krb5_update_server_info(ldap_server_handle,server_info)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 *
krb5_get_ldap_handle(ldap_context)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 *
krb5_retry_get_ldap_handle(ldap_context,st)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
krb5_put_ldap_handle(ldap_server_handle)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
krb5_update_ldap_handle(ldap_server_handle,server_info)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
krb5_ldap_cleanup_handles(ldap_server_info)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
krb5_ldap_request_handle_from_pool(ldap_context,ldap_server_handle)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
krb5_ldap_request_next_handle_from_pool(ldap_context,ldap_server_handle)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
krb5_ldap_put_handle_to_pool(ldap_context,ldap_server_handle)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