1251876Speter/* Licensed to the Apache Software Foundation (ASF) under one or more
2251876Speter * contributor license agreements.  See the NOTICE file distributed with
3251876Speter * this work for additional information regarding copyright ownership.
4251876Speter * The ASF licenses this file to You under the Apache License, Version 2.0
5251876Speter * (the "License"); you may not use this file except in compliance with
6251876Speter * the License.  You may obtain a copy of the License at
7251876Speter *
8251876Speter *     http://www.apache.org/licenses/LICENSE-2.0
9251876Speter *
10251876Speter * Unless required by applicable law or agreed to in writing, software
11251876Speter * distributed under the License is distributed on an "AS IS" BASIS,
12251876Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13251876Speter * See the License for the specific language governing permissions and
14251876Speter * limitations under the License.
15251876Speter */
16251876Speter
17251876Speter/*  apr_ldap_rebind.c -- LDAP rebind callbacks for referrals
18251876Speter *
19251876Speter *  The LDAP SDK allows a callback to be set to enable rebinding
20251876Speter *  for referral processing.
21251876Speter *
22251876Speter */
23251876Speter
24251876Speter#include "apr.h"
25251876Speter#include "apu.h"
26251876Speter#include "apu_config.h"
27251876Speter
28251876Speter#if APU_DSO_BUILD
29251876Speter#define APU_DSO_LDAP_BUILD
30251876Speter#endif
31251876Speter
32251876Speter#include "apr_ldap.h"
33251876Speter#include "apr_errno.h"
34251876Speter#include "apr_strings.h"
35251876Speter#include "apr_ldap_rebind.h"
36251876Speter
37251876Speter#include "stdio.h"
38251876Speter
39251876Speter#if APR_HAS_LDAP
40251876Speter
41251876Speter/* Used to store information about connections for use in the referral rebind callback. */
42251876Speterstruct apr_ldap_rebind_entry {
43251876Speter    apr_pool_t *pool;
44251876Speter    LDAP *index;
45251876Speter    const char *bindDN;
46251876Speter    const char *bindPW;
47251876Speter    struct apr_ldap_rebind_entry *next;
48251876Speter};
49251876Spetertypedef struct apr_ldap_rebind_entry apr_ldap_rebind_entry_t;
50251876Speter
51251876Speter
52251876Speter#ifdef NETWARE
53251876Speter#include "apr_private.h"
54251876Speter#define get_apd                 APP_DATA* apd = (APP_DATA*)get_app_data(gLibId);
55251876Speter#define apr_ldap_xref_lock      ((apr_thread_mutex_t *)(apd->gs_ldap_xref_lock))
56251876Speter#define xref_head               ((apr_ldap_rebind_entry_t *)(apd->gs_xref_head))
57251876Speter#else
58251876Speter#if APR_HAS_THREADS
59251876Speterstatic apr_thread_mutex_t *apr_ldap_xref_lock = NULL;
60251876Speter#endif
61251876Speterstatic apr_ldap_rebind_entry_t *xref_head = NULL;
62251876Speter#endif
63251876Speter
64251876Speterstatic int apr_ldap_rebind_set_callback(LDAP *ld);
65251876Speterstatic apr_status_t apr_ldap_rebind_remove_helper(void *data);
66251876Speter
67251876Speterstatic apr_status_t apr_ldap_pool_cleanup_set_null(void *data_)
68251876Speter{
69251876Speter    void **ptr = (void **)data_;
70251876Speter    *ptr = NULL;
71251876Speter    return APR_SUCCESS;
72251876Speter}
73251876Speter
74251876Speter
75251876Speter/* APR utility routine used to create the xref_lock. */
76251876SpeterAPU_DECLARE_LDAP(apr_status_t) apr_ldap_rebind_init(apr_pool_t *pool)
77251876Speter{
78251876Speter    apr_status_t retcode = APR_SUCCESS;
79251876Speter
80251876Speter#ifdef NETWARE
81251876Speter    get_apd
82251876Speter#endif
83251876Speter
84251876Speter#if APR_HAS_THREADS
85251876Speter    /* run after apr_thread_mutex_create cleanup */
86251876Speter    apr_pool_cleanup_register(pool, &apr_ldap_xref_lock, apr_ldap_pool_cleanup_set_null,
87251876Speter                              apr_pool_cleanup_null);
88251876Speter
89251876Speter    if (apr_ldap_xref_lock == NULL) {
90251876Speter        retcode = apr_thread_mutex_create(&apr_ldap_xref_lock, APR_THREAD_MUTEX_DEFAULT, pool);
91251876Speter    }
92251876Speter#endif
93251876Speter
94251876Speter    return(retcode);
95251876Speter}
96251876Speter
97251876Speter
98251876SpeterAPU_DECLARE_LDAP(apr_status_t) apr_ldap_rebind_add(apr_pool_t *pool,
99251876Speter                                                   LDAP *ld,
100251876Speter                                                   const char *bindDN,
101251876Speter                                                   const char *bindPW)
102251876Speter{
103251876Speter    apr_status_t retcode = APR_SUCCESS;
104251876Speter    apr_ldap_rebind_entry_t *new_xref;
105251876Speter
106251876Speter#ifdef NETWARE
107251876Speter    get_apd
108251876Speter#endif
109251876Speter
110251876Speter    new_xref = (apr_ldap_rebind_entry_t *)apr_pcalloc(pool, sizeof(apr_ldap_rebind_entry_t));
111251876Speter    if (new_xref) {
112251876Speter        new_xref->pool = pool;
113251876Speter        new_xref->index = ld;
114251876Speter        if (bindDN) {
115251876Speter            new_xref->bindDN = apr_pstrdup(pool, bindDN);
116251876Speter        }
117251876Speter        if (bindPW) {
118251876Speter            new_xref->bindPW = apr_pstrdup(pool, bindPW);
119251876Speter        }
120251876Speter
121251876Speter#if APR_HAS_THREADS
122251876Speter       retcode = apr_thread_mutex_lock(apr_ldap_xref_lock);
123251876Speter       if (retcode != APR_SUCCESS) {
124251876Speter           return retcode;
125251876Speter       }
126251876Speter#endif
127251876Speter
128251876Speter        new_xref->next = xref_head;
129251876Speter        xref_head = new_xref;
130251876Speter
131251876Speter#if APR_HAS_THREADS
132251876Speter        retcode = apr_thread_mutex_unlock(apr_ldap_xref_lock);
133251876Speter        if (retcode != APR_SUCCESS) {
134251876Speter           return retcode;
135251876Speter        }
136251876Speter#endif
137251876Speter    }
138251876Speter    else {
139251876Speter        return(APR_ENOMEM);
140251876Speter    }
141251876Speter
142251876Speter    retcode = apr_ldap_rebind_set_callback(ld);
143251876Speter    if (APR_SUCCESS != retcode) {
144251876Speter        apr_ldap_rebind_remove(ld);
145251876Speter        return retcode;
146251876Speter    }
147251876Speter
148251876Speter    apr_pool_cleanup_register(pool, ld,
149251876Speter                              apr_ldap_rebind_remove_helper,
150251876Speter                              apr_pool_cleanup_null);
151251876Speter
152251876Speter    return(APR_SUCCESS);
153251876Speter}
154251876Speter
155251876Speter
156251876SpeterAPU_DECLARE_LDAP(apr_status_t) apr_ldap_rebind_remove(LDAP *ld)
157251876Speter{
158251876Speter    apr_ldap_rebind_entry_t *tmp_xref, *prev = NULL;
159251876Speter    apr_status_t retcode = 0;
160251876Speter
161251876Speter#ifdef NETWARE
162251876Speter    get_apd
163251876Speter#endif
164251876Speter
165251876Speter#if APR_HAS_THREADS
166251876Speter    retcode = apr_thread_mutex_lock(apr_ldap_xref_lock);
167251876Speter    if (retcode != APR_SUCCESS) {
168251876Speter        return retcode;
169251876Speter    }
170251876Speter#endif
171251876Speter    tmp_xref = xref_head;
172251876Speter
173251876Speter    while ((tmp_xref) && (tmp_xref->index != ld)) {
174251876Speter        prev = tmp_xref;
175251876Speter        tmp_xref = tmp_xref->next;
176251876Speter    }
177251876Speter
178251876Speter    if (tmp_xref) {
179251876Speter        if (tmp_xref == xref_head) {
180251876Speter            xref_head = xref_head->next;
181251876Speter        }
182251876Speter        else {
183251876Speter            prev->next = tmp_xref->next;
184251876Speter        }
185251876Speter
186251876Speter        /* tmp_xref and its contents were pool allocated so they don't need to be freed here. */
187251876Speter
188251876Speter        /* remove the cleanup, just in case this was done manually */
189251876Speter        apr_pool_cleanup_kill(tmp_xref->pool, tmp_xref->index,
190251876Speter                              apr_ldap_rebind_remove_helper);
191251876Speter    }
192251876Speter
193251876Speter#if APR_HAS_THREADS
194251876Speter    retcode = apr_thread_mutex_unlock(apr_ldap_xref_lock);
195251876Speter    if (retcode != APR_SUCCESS) {
196251876Speter       return retcode;
197251876Speter    }
198251876Speter#endif
199251876Speter    return APR_SUCCESS;
200251876Speter}
201251876Speter
202251876Speter
203251876Speterstatic apr_status_t apr_ldap_rebind_remove_helper(void *data)
204251876Speter{
205251876Speter    LDAP *ld = (LDAP *)data;
206251876Speter    apr_ldap_rebind_remove(ld);
207251876Speter    return APR_SUCCESS;
208251876Speter}
209251876Speter
210251876Speter#if APR_HAS_TIVOLI_LDAPSDK || APR_HAS_OPENLDAP_LDAPSDK || APR_HAS_NOVELL_LDAPSDK
211251876Speterstatic apr_ldap_rebind_entry_t *apr_ldap_rebind_lookup(LDAP *ld)
212251876Speter{
213251876Speter    apr_ldap_rebind_entry_t *tmp_xref, *match = NULL;
214251876Speter
215251876Speter#ifdef NETWARE
216251876Speter    get_apd
217251876Speter#endif
218251876Speter
219251876Speter#if APR_HAS_THREADS
220251876Speter    apr_thread_mutex_lock(apr_ldap_xref_lock);
221251876Speter#endif
222251876Speter    tmp_xref = xref_head;
223251876Speter
224251876Speter    while (tmp_xref) {
225251876Speter        if (tmp_xref->index == ld) {
226251876Speter            match = tmp_xref;
227251876Speter            tmp_xref = NULL;
228251876Speter        }
229251876Speter        else {
230251876Speter            tmp_xref = tmp_xref->next;
231251876Speter        }
232251876Speter    }
233251876Speter
234251876Speter#if APR_HAS_THREADS
235251876Speter    apr_thread_mutex_unlock(apr_ldap_xref_lock);
236251876Speter#endif
237251876Speter
238251876Speter    return (match);
239251876Speter}
240251876Speter#endif
241251876Speter
242251876Speter#if APR_HAS_TIVOLI_LDAPSDK
243251876Speter
244251876Speter/* LDAP_rebindproc() Tivoli LDAP style
245251876Speter *     Rebind callback function. Called when chasing referrals. See API docs.
246251876Speter * ON ENTRY:
247251876Speter *     ld       Pointer to an LDAP control structure. (input only)
248251876Speter *     binddnp  Pointer to an Application DName used for binding (in *or* out)
249251876Speter *     passwdp  Pointer to the password associated with the DName (in *or* out)
250251876Speter *     methodp  Pointer to the Auth method (output only)
251251876Speter *     freeit   Flag to indicate if this is a lookup or a free request (input only)
252251876Speter */
253251876Speterstatic int LDAP_rebindproc(LDAP *ld, char **binddnp, char **passwdp, int *methodp, int freeit)
254251876Speter{
255251876Speter    if (!freeit) {
256251876Speter        apr_ldap_rebind_entry_t *my_conn;
257251876Speter
258251876Speter        *methodp = LDAP_AUTH_SIMPLE;
259251876Speter        my_conn = apr_ldap_rebind_lookup(ld);
260251876Speter
261251876Speter        if ((my_conn) && (my_conn->bindDN != NULL)) {
262251876Speter            *binddnp = strdup(my_conn->bindDN);
263251876Speter            *passwdp = strdup(my_conn->bindPW);
264251876Speter        } else {
265251876Speter            *binddnp = NULL;
266251876Speter            *passwdp = NULL;
267251876Speter        }
268251876Speter    } else {
269251876Speter        if (*binddnp) {
270251876Speter            free(*binddnp);
271251876Speter        }
272251876Speter        if (*passwdp) {
273251876Speter            free(*passwdp);
274251876Speter        }
275251876Speter    }
276251876Speter
277251876Speter    return LDAP_SUCCESS;
278251876Speter}
279251876Speter
280251876Speterstatic int apr_ldap_rebind_set_callback(LDAP *ld)
281251876Speter{
282251876Speter    ldap_set_rebind_proc(ld, (LDAPRebindProc)LDAP_rebindproc);
283251876Speter    return APR_SUCCESS;
284251876Speter}
285251876Speter
286251876Speter#elif APR_HAS_OPENLDAP_LDAPSDK
287251876Speter
288251876Speter/* LDAP_rebindproc() openLDAP V3 style
289251876Speter * ON ENTRY:
290251876Speter *     ld       Pointer to an LDAP control structure. (input only)
291251876Speter *     url      Unused in this routine
292251876Speter *     request  Unused in this routine
293251876Speter *     msgid    Unused in this routine
294251876Speter *     params   Unused in this routine
295251876Speter *
296251876Speter *     or
297251876Speter *
298251876Speter *     ld       Pointer to an LDAP control structure. (input only)
299251876Speter *     url      Unused in this routine
300251876Speter *     request  Unused in this routine
301251876Speter *     msgid    Unused in this routine
302251876Speter */
303251876Speter#if defined(LDAP_SET_REBIND_PROC_THREE)
304251876Speterstatic int LDAP_rebindproc(LDAP *ld, LDAP_CONST char *url, ber_tag_t request,
305251876Speter                           ber_int_t msgid, void *params)
306251876Speter#else
307251876Speterstatic int LDAP_rebindproc(LDAP *ld, LDAP_CONST char *url, int request,
308251876Speter                           ber_int_t msgid)
309251876Speter#endif
310251876Speter{
311251876Speter    apr_ldap_rebind_entry_t *my_conn;
312251876Speter    const char *bindDN = NULL;
313251876Speter    const char *bindPW = NULL;
314251876Speter
315251876Speter    my_conn = apr_ldap_rebind_lookup(ld);
316251876Speter
317251876Speter    if ((my_conn) && (my_conn->bindDN != NULL)) {
318251876Speter        bindDN = my_conn->bindDN;
319251876Speter        bindPW = my_conn->bindPW;
320251876Speter    }
321251876Speter
322251876Speter    return (ldap_bind_s(ld, bindDN, bindPW, LDAP_AUTH_SIMPLE));
323251876Speter}
324251876Speter
325251876Speterstatic int apr_ldap_rebind_set_callback(LDAP *ld)
326251876Speter{
327251876Speter#if defined(LDAP_SET_REBIND_PROC_THREE)
328251876Speter    ldap_set_rebind_proc(ld, LDAP_rebindproc, NULL);
329251876Speter#else
330251876Speter    ldap_set_rebind_proc(ld, LDAP_rebindproc);
331251876Speter#endif
332251876Speter    return APR_SUCCESS;
333251876Speter}
334251876Speter
335251876Speter#elif APR_HAS_NOVELL_LDAPSDK
336251876Speter
337251876Speter/* LDAP_rebindproc() openLDAP V3 style
338251876Speter * ON ENTRY:
339251876Speter *     ld       Pointer to an LDAP control structure. (input only)
340251876Speter *     url      Unused in this routine
341251876Speter *     request  Unused in this routine
342251876Speter *     msgid    Unused in this routine
343251876Speter */
344251876Speterstatic int LDAP_rebindproc(LDAP *ld, LDAP_CONST char *url, int request, ber_int_t msgid)
345251876Speter{
346251876Speter
347251876Speter    apr_ldap_rebind_entry_t *my_conn;
348251876Speter    const char *bindDN = NULL;
349251876Speter    const char *bindPW = NULL;
350251876Speter
351251876Speter    my_conn = apr_ldap_rebind_lookup(ld);
352251876Speter
353251876Speter    if ((my_conn) && (my_conn->bindDN != NULL)) {
354251876Speter        bindDN = my_conn->bindDN;
355251876Speter        bindPW = my_conn->bindPW;
356251876Speter    }
357251876Speter
358251876Speter    return (ldap_bind_s(ld, bindDN, bindPW, LDAP_AUTH_SIMPLE));
359251876Speter}
360251876Speter
361251876Speterstatic int apr_ldap_rebind_set_callback(LDAP *ld)
362251876Speter{
363251876Speter    ldap_set_rebind_proc(ld, LDAP_rebindproc);
364251876Speter    return APR_SUCCESS;
365251876Speter}
366251876Speter
367251876Speter#else         /* Implementation not recognised */
368251876Speter
369251876Speterstatic int apr_ldap_rebind_set_callback(LDAP *ld)
370251876Speter{
371251876Speter    return APR_ENOTIMPL;
372251876Speter}
373251876Speter
374251876Speter#endif
375251876Speter
376251876Speter
377251876Speter#endif       /* APR_HAS_LDAP */
378