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