1/* Licensed to the Apache Software Foundation (ASF) under one or more 2 * contributor license agreements. See the NOTICE file distributed with 3 * this work for additional information regarding copyright ownership. 4 * The ASF licenses this file to You under the Apache License, Version 2.0 5 * (the "License"); you may not use this file except in compliance with 6 * the License. You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17/* apr_ldap_rebind.c -- LDAP rebind callbacks for referrals 18 * 19 * The LDAP SDK allows a callback to be set to enable rebinding 20 * for referral processing. 21 * 22 */ 23 24#include "apr.h" 25#include "apu.h" 26#include "apu_config.h" 27 28#if APU_DSO_BUILD 29#define APU_DSO_LDAP_BUILD 30#endif 31 32#include "apr_ldap.h" 33#include "apr_errno.h" 34#include "apr_strings.h" 35#include "apr_ldap_rebind.h" 36 37#include "stdio.h" 38 39#if APR_HAS_LDAP 40 41/* Used to store information about connections for use in the referral rebind callback. */ 42struct apr_ldap_rebind_entry { 43 apr_pool_t *pool; 44 LDAP *index; 45 const char *bindDN; 46 const char *bindPW; 47 struct apr_ldap_rebind_entry *next; 48}; 49typedef struct apr_ldap_rebind_entry apr_ldap_rebind_entry_t; 50 51 52#ifdef NETWARE 53#include "apr_private.h" 54#define get_apd APP_DATA* apd = (APP_DATA*)get_app_data(gLibId); 55#define apr_ldap_xref_lock ((apr_thread_mutex_t *)(apd->gs_ldap_xref_lock)) 56#define xref_head ((apr_ldap_rebind_entry_t *)(apd->gs_xref_head)) 57#else 58#if APR_HAS_THREADS 59static apr_thread_mutex_t *apr_ldap_xref_lock = NULL; 60#endif 61static apr_ldap_rebind_entry_t *xref_head = NULL; 62#endif 63 64static int apr_ldap_rebind_set_callback(LDAP *ld); 65static apr_status_t apr_ldap_rebind_remove_helper(void *data); 66 67static apr_status_t apr_ldap_pool_cleanup_set_null(void *data_) 68{ 69 void **ptr = (void **)data_; 70 *ptr = NULL; 71 return APR_SUCCESS; 72} 73 74 75/* APR utility routine used to create the xref_lock. */ 76APU_DECLARE_LDAP(apr_status_t) apr_ldap_rebind_init(apr_pool_t *pool) 77{ 78 apr_status_t retcode = APR_SUCCESS; 79 80#ifdef NETWARE 81 get_apd 82#endif 83 84#if APR_HAS_THREADS 85 /* run after apr_thread_mutex_create cleanup */ 86 apr_pool_cleanup_register(pool, &apr_ldap_xref_lock, apr_ldap_pool_cleanup_set_null, 87 apr_pool_cleanup_null); 88 89 if (apr_ldap_xref_lock == NULL) { 90 retcode = apr_thread_mutex_create(&apr_ldap_xref_lock, APR_THREAD_MUTEX_DEFAULT, pool); 91 } 92#endif 93 94 return(retcode); 95} 96 97 98APU_DECLARE_LDAP(apr_status_t) apr_ldap_rebind_add(apr_pool_t *pool, 99 LDAP *ld, 100 const char *bindDN, 101 const char *bindPW) 102{ 103 apr_status_t retcode = APR_SUCCESS; 104 apr_ldap_rebind_entry_t *new_xref; 105 106#ifdef NETWARE 107 get_apd 108#endif 109 110 new_xref = (apr_ldap_rebind_entry_t *)apr_pcalloc(pool, sizeof(apr_ldap_rebind_entry_t)); 111 if (new_xref) { 112 new_xref->pool = pool; 113 new_xref->index = ld; 114 if (bindDN) { 115 new_xref->bindDN = apr_pstrdup(pool, bindDN); 116 } 117 if (bindPW) { 118 new_xref->bindPW = apr_pstrdup(pool, bindPW); 119 } 120 121#if APR_HAS_THREADS 122 retcode = apr_thread_mutex_lock(apr_ldap_xref_lock); 123 if (retcode != APR_SUCCESS) { 124 return retcode; 125 } 126#endif 127 128 new_xref->next = xref_head; 129 xref_head = new_xref; 130 131#if APR_HAS_THREADS 132 retcode = apr_thread_mutex_unlock(apr_ldap_xref_lock); 133 if (retcode != APR_SUCCESS) { 134 return retcode; 135 } 136#endif 137 } 138 else { 139 return(APR_ENOMEM); 140 } 141 142 retcode = apr_ldap_rebind_set_callback(ld); 143 if (APR_SUCCESS != retcode) { 144 apr_ldap_rebind_remove(ld); 145 return retcode; 146 } 147 148 apr_pool_cleanup_register(pool, ld, 149 apr_ldap_rebind_remove_helper, 150 apr_pool_cleanup_null); 151 152 return(APR_SUCCESS); 153} 154 155 156APU_DECLARE_LDAP(apr_status_t) apr_ldap_rebind_remove(LDAP *ld) 157{ 158 apr_ldap_rebind_entry_t *tmp_xref, *prev = NULL; 159 apr_status_t retcode = 0; 160 161#ifdef NETWARE 162 get_apd 163#endif 164 165#if APR_HAS_THREADS 166 retcode = apr_thread_mutex_lock(apr_ldap_xref_lock); 167 if (retcode != APR_SUCCESS) { 168 return retcode; 169 } 170#endif 171 tmp_xref = xref_head; 172 173 while ((tmp_xref) && (tmp_xref->index != ld)) { 174 prev = tmp_xref; 175 tmp_xref = tmp_xref->next; 176 } 177 178 if (tmp_xref) { 179 if (tmp_xref == xref_head) { 180 xref_head = xref_head->next; 181 } 182 else { 183 prev->next = tmp_xref->next; 184 } 185 186 /* tmp_xref and its contents were pool allocated so they don't need to be freed here. */ 187 188 /* remove the cleanup, just in case this was done manually */ 189 apr_pool_cleanup_kill(tmp_xref->pool, tmp_xref->index, 190 apr_ldap_rebind_remove_helper); 191 } 192 193#if APR_HAS_THREADS 194 retcode = apr_thread_mutex_unlock(apr_ldap_xref_lock); 195 if (retcode != APR_SUCCESS) { 196 return retcode; 197 } 198#endif 199 return APR_SUCCESS; 200} 201 202 203static apr_status_t apr_ldap_rebind_remove_helper(void *data) 204{ 205 LDAP *ld = (LDAP *)data; 206 apr_ldap_rebind_remove(ld); 207 return APR_SUCCESS; 208} 209 210#if APR_HAS_TIVOLI_LDAPSDK || APR_HAS_OPENLDAP_LDAPSDK || APR_HAS_NOVELL_LDAPSDK 211static apr_ldap_rebind_entry_t *apr_ldap_rebind_lookup(LDAP *ld) 212{ 213 apr_ldap_rebind_entry_t *tmp_xref, *match = NULL; 214 215#ifdef NETWARE 216 get_apd 217#endif 218 219#if APR_HAS_THREADS 220 apr_thread_mutex_lock(apr_ldap_xref_lock); 221#endif 222 tmp_xref = xref_head; 223 224 while (tmp_xref) { 225 if (tmp_xref->index == ld) { 226 match = tmp_xref; 227 tmp_xref = NULL; 228 } 229 else { 230 tmp_xref = tmp_xref->next; 231 } 232 } 233 234#if APR_HAS_THREADS 235 apr_thread_mutex_unlock(apr_ldap_xref_lock); 236#endif 237 238 return (match); 239} 240#endif 241 242#if APR_HAS_TIVOLI_LDAPSDK 243 244/* LDAP_rebindproc() Tivoli LDAP style 245 * Rebind callback function. Called when chasing referrals. See API docs. 246 * ON ENTRY: 247 * ld Pointer to an LDAP control structure. (input only) 248 * binddnp Pointer to an Application DName used for binding (in *or* out) 249 * passwdp Pointer to the password associated with the DName (in *or* out) 250 * methodp Pointer to the Auth method (output only) 251 * freeit Flag to indicate if this is a lookup or a free request (input only) 252 */ 253static int LDAP_rebindproc(LDAP *ld, char **binddnp, char **passwdp, int *methodp, int freeit) 254{ 255 if (!freeit) { 256 apr_ldap_rebind_entry_t *my_conn; 257 258 *methodp = LDAP_AUTH_SIMPLE; 259 my_conn = apr_ldap_rebind_lookup(ld); 260 261 if ((my_conn) && (my_conn->bindDN != NULL)) { 262 *binddnp = strdup(my_conn->bindDN); 263 *passwdp = strdup(my_conn->bindPW); 264 } else { 265 *binddnp = NULL; 266 *passwdp = NULL; 267 } 268 } else { 269 if (*binddnp) { 270 free(*binddnp); 271 } 272 if (*passwdp) { 273 free(*passwdp); 274 } 275 } 276 277 return LDAP_SUCCESS; 278} 279 280static int apr_ldap_rebind_set_callback(LDAP *ld) 281{ 282 ldap_set_rebind_proc(ld, (LDAPRebindProc)LDAP_rebindproc); 283 return APR_SUCCESS; 284} 285 286#elif APR_HAS_OPENLDAP_LDAPSDK 287 288/* LDAP_rebindproc() openLDAP V3 style 289 * ON ENTRY: 290 * ld Pointer to an LDAP control structure. (input only) 291 * url Unused in this routine 292 * request Unused in this routine 293 * msgid Unused in this routine 294 * params Unused in this routine 295 * 296 * or 297 * 298 * ld Pointer to an LDAP control structure. (input only) 299 * url Unused in this routine 300 * request Unused in this routine 301 * msgid Unused in this routine 302 */ 303#if defined(LDAP_SET_REBIND_PROC_THREE) 304static int LDAP_rebindproc(LDAP *ld, LDAP_CONST char *url, ber_tag_t request, 305 ber_int_t msgid, void *params) 306#else 307static int LDAP_rebindproc(LDAP *ld, LDAP_CONST char *url, int request, 308 ber_int_t msgid) 309#endif 310{ 311 apr_ldap_rebind_entry_t *my_conn; 312 const char *bindDN = NULL; 313 const char *bindPW = NULL; 314 315 my_conn = apr_ldap_rebind_lookup(ld); 316 317 if ((my_conn) && (my_conn->bindDN != NULL)) { 318 bindDN = my_conn->bindDN; 319 bindPW = my_conn->bindPW; 320 } 321 322 return (ldap_bind_s(ld, bindDN, bindPW, LDAP_AUTH_SIMPLE)); 323} 324 325static int apr_ldap_rebind_set_callback(LDAP *ld) 326{ 327#if defined(LDAP_SET_REBIND_PROC_THREE) 328 ldap_set_rebind_proc(ld, LDAP_rebindproc, NULL); 329#else 330 ldap_set_rebind_proc(ld, LDAP_rebindproc); 331#endif 332 return APR_SUCCESS; 333} 334 335#elif APR_HAS_NOVELL_LDAPSDK 336 337/* LDAP_rebindproc() openLDAP V3 style 338 * ON ENTRY: 339 * ld Pointer to an LDAP control structure. (input only) 340 * url Unused in this routine 341 * request Unused in this routine 342 * msgid Unused in this routine 343 */ 344static int LDAP_rebindproc(LDAP *ld, LDAP_CONST char *url, int request, ber_int_t msgid) 345{ 346 347 apr_ldap_rebind_entry_t *my_conn; 348 const char *bindDN = NULL; 349 const char *bindPW = NULL; 350 351 my_conn = apr_ldap_rebind_lookup(ld); 352 353 if ((my_conn) && (my_conn->bindDN != NULL)) { 354 bindDN = my_conn->bindDN; 355 bindPW = my_conn->bindPW; 356 } 357 358 return (ldap_bind_s(ld, bindDN, bindPW, LDAP_AUTH_SIMPLE)); 359} 360 361static int apr_ldap_rebind_set_callback(LDAP *ld) 362{ 363 ldap_set_rebind_proc(ld, LDAP_rebindproc); 364 return APR_SUCCESS; 365} 366 367#else /* Implementation not recognised */ 368 369static int apr_ldap_rebind_set_callback(LDAP *ld) 370{ 371 return APR_ENOTIMPL; 372} 373 374#endif 375 376 377#endif /* APR_HAS_LDAP */ 378