Imported Upstream version 1.15.1
[platform/upstream/krb5.git] / src / plugins / kdb / ldap / libkdb_ldap / ldap_handle.c
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* plugins/kdb/ldap/libkdb_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(krb5_ldap_server_handle *ldap_server_handle,
47                         krb5_ldap_server_info *server_info)
48 {
49     krb5_error_code            st=0;
50     struct timeval             ztime={0, 0};
51     LDAPMessage                *result=NULL;
52
53     if (ldap_server_handle == NULL || server_info == NULL)
54         return -1;
55
56     while (st == 0) {
57         st = ldap_result(ldap_server_handle->ldap_handle, ldap_server_handle->msgid,
58                          LDAP_MSG_ALL, &ztime, &result);
59         switch (st) {
60         case -1:
61             server_info->server_status = OFF;
62             time(&server_info->downtime);
63             break;
64
65         case 0:
66             continue;
67             break;
68
69         case LDAP_RES_BIND:
70             if ((st=ldap_result2error(ldap_server_handle->ldap_handle, result, 1)) == LDAP_SUCCESS) {
71                 server_info->server_status = ON;
72             } else {
73                 server_info->server_status = OFF;
74                 time(&server_info->downtime);
75             }
76             ldap_msgfree(result);
77             break;
78         default:
79             ldap_msgfree(result);
80             continue;
81             break;
82         }
83     }
84     ldap_server_handle->server_info_update_pending = FALSE;
85     return 0;
86 }
87 #endif
88
89 /*
90  * Return ldap server handle from the pool. If the pool is exhausted return NULL.
91  * Do not lock the mutex, caller should lock it
92  */
93
94 static krb5_ldap_server_handle *
95 krb5_get_ldap_handle(krb5_ldap_context *ldap_context)
96 {
97     krb5_ldap_server_handle    *ldap_server_handle=NULL;
98     krb5_ldap_server_info      *ldap_server_info=NULL;
99     int                        cnt=0;
100
101     while (ldap_context->server_info_list[cnt] != NULL) {
102         ldap_server_info = ldap_context->server_info_list[cnt];
103         if (ldap_server_info->server_status != OFF) {
104             if (ldap_server_info->ldap_server_handles != NULL) {
105                 ldap_server_handle = ldap_server_info->ldap_server_handles;
106                 ldap_server_info->ldap_server_handles = ldap_server_handle->next;
107                 break;
108 #ifdef ASYNC_BIND
109                 if (ldap_server_handle->server_info_update_pending == TRUE) {
110                     krb5_update_server_info(context, ldap_server_handle,
111                                             ldap_server_info);
112                 }
113
114                 if (ldap_server_info->server_status == ON) {
115                     ldap_server_info->ldap_server_handles = ldap_server_handle->next;
116                     break;
117                 } else
118                     ldap_server_handle = NULL;
119 #endif
120             }
121         }
122         ++cnt;
123     }
124     return ldap_server_handle;
125 }
126
127 /*
128  * This is called incase krb5_get_ldap_handle returns NULL.
129  * Try getting a single connection (handle) and return the same by
130  * calling krb5_get_ldap_handle function.
131  * Do not lock the mutex here. The caller should lock it
132  */
133
134 static krb5_ldap_server_handle *
135 krb5_retry_get_ldap_handle(krb5_ldap_context *ldap_context,
136                            krb5_error_code *st)
137 {
138     krb5_ldap_server_handle    *ldap_server_handle=NULL;
139
140     if ((*st=krb5_ldap_db_single_init(ldap_context)) != 0)
141         return NULL;
142
143     ldap_server_handle = krb5_get_ldap_handle(ldap_context);
144     return ldap_server_handle;
145 }
146
147 /*
148  * Put back the ldap server handle to the front of the list of handles of the
149  * ldap server info structure.
150  * Do not lock the mutex here. The caller should lock it.
151  */
152
153 static krb5_error_code
154 krb5_put_ldap_handle(krb5_ldap_server_handle *ldap_server_handle)
155 {
156
157     if (ldap_server_handle == NULL)
158         return 0;
159
160     ldap_server_handle->next = ldap_server_handle->server_info->ldap_server_handles;
161     ldap_server_handle->server_info->ldap_server_handles = ldap_server_handle;
162     return 0;
163 }
164
165 /*
166  * Free up all the ldap server handles of the server info.
167  * This function is called when the ldap server returns LDAP_SERVER_DOWN.
168  */
169
170 static krb5_error_code
171 krb5_ldap_cleanup_handles(krb5_ldap_server_info *ldap_server_info)
172 {
173     krb5_ldap_server_handle    *ldap_server_handle = NULL;
174
175     while (ldap_server_info->ldap_server_handles != NULL) {
176         ldap_server_handle = ldap_server_info->ldap_server_handles;
177         ldap_server_info->ldap_server_handles = ldap_server_handle->next;
178         /* ldap_unbind_s(ldap_server_handle); */
179         free (ldap_server_handle);
180         ldap_server_handle = NULL;
181     }
182     return 0;
183 }
184
185 /*
186  * wrapper function called from outside to get a handle.
187  */
188
189 krb5_error_code
190 krb5_ldap_request_handle_from_pool(krb5_ldap_context *ldap_context,
191                                    krb5_ldap_server_handle **
192                                    ldap_server_handle)
193 {
194     krb5_error_code            st=0;
195
196     *ldap_server_handle = NULL;
197
198     HNDL_LOCK(ldap_context);
199     if (((*ldap_server_handle)=krb5_get_ldap_handle(ldap_context)) == NULL)
200         (*ldap_server_handle)=krb5_retry_get_ldap_handle(ldap_context, &st);
201     HNDL_UNLOCK(ldap_context);
202     return st;
203 }
204
205 /*
206  * wrapper function wrapper called to get the next ldap server handle, when the current
207  * ldap server handle returns LDAP_SERVER_DOWN.
208  */
209
210 krb5_error_code
211 krb5_ldap_request_next_handle_from_pool(krb5_ldap_context *ldap_context,
212                                         krb5_ldap_server_handle **
213                                         ldap_server_handle)
214 {
215     krb5_error_code            st=0;
216
217     HNDL_LOCK(ldap_context);
218     (*ldap_server_handle)->server_info->server_status = OFF;
219     time(&(*ldap_server_handle)->server_info->downtime);
220     krb5_put_ldap_handle(*ldap_server_handle);
221     krb5_ldap_cleanup_handles((*ldap_server_handle)->server_info);
222
223     if (((*ldap_server_handle)=krb5_get_ldap_handle(ldap_context)) == NULL)
224         (*ldap_server_handle)=krb5_retry_get_ldap_handle(ldap_context, &st);
225     HNDL_UNLOCK(ldap_context);
226     return st;
227 }
228
229 /*
230  * wrapper function to call krb5_put_ldap_handle.
231  */
232
233 void
234 krb5_ldap_put_handle_to_pool(krb5_ldap_context *ldap_context,
235                              krb5_ldap_server_handle *ldap_server_handle)
236 {
237     if (ldap_server_handle != NULL) {
238         HNDL_LOCK(ldap_context);
239         krb5_put_ldap_handle(ldap_server_handle);
240         HNDL_UNLOCK(ldap_context);
241     }
242     return;
243 }