📄 util_ldap.c
字号:
/* Copyright 2001-2005 The Apache Software Foundation or its licensors, as * applicable. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *//* * util_ldap.c: LDAP things * * Original code from auth_ldap module for Apache v1.3: * Copyright 1998, 1999 Enbridge Pipelines Inc. * Copyright 1999-2001 Dave Carrigan */#include <apr_ldap.h>#include <apr_strings.h>#include "ap_config.h"#include "httpd.h"#include "http_config.h"#include "http_core.h"#include "http_log.h"#include "http_protocol.h"#include "http_request.h"#include "util_ldap.h"#include "util_ldap_cache.h"#if APR_HAVE_UNISTD_H#include <unistd.h>#endif#ifndef APU_HAS_LDAP#error mod_ldap requires APR-util to have LDAP support built in#endif /* defines for certificate file types */#define LDAP_CA_TYPE_UNKNOWN 0#define LDAP_CA_TYPE_DER 1#define LDAP_CA_TYPE_BASE64 2#define LDAP_CA_TYPE_CERT7_DB 3module AP_MODULE_DECLARE_DATA ldap_module;int util_ldap_handler(request_rec *r);void *util_ldap_create_config(apr_pool_t *p, server_rec *s);/* * Some definitions to help between various versions of apache. */#ifndef DOCTYPE_HTML_2_0#define DOCTYPE_HTML_2_0 "<!DOCTYPE HTML PUBLIC \"-//IETF//" \ "DTD HTML 2.0//EN\">\n"#endif#ifndef DOCTYPE_HTML_3_2#define DOCTYPE_HTML_3_2 "<!DOCTYPE HTML PUBLIC \"-//W3C//" \ "DTD HTML 3.2 Final//EN\">\n"#endif#ifndef DOCTYPE_HTML_4_0S#define DOCTYPE_HTML_4_0S "<!DOCTYPE HTML PUBLIC \"-//W3C//" \ "DTD HTML 4.0//EN\"\n" \ "\"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"#endif#ifndef DOCTYPE_HTML_4_0T#define DOCTYPE_HTML_4_0T "<!DOCTYPE HTML PUBLIC \"-//W3C//" \ "DTD HTML 4.0 Transitional//EN\"\n" \ "\"http://www.w3.org/TR/REC-html40/loose.dtd\">\n"#endif#ifndef DOCTYPE_HTML_4_0F#define DOCTYPE_HTML_4_0F "<!DOCTYPE HTML PUBLIC \"-//W3C//" \ "DTD HTML 4.0 Frameset//EN\"\n" \ "\"http://www.w3.org/TR/REC-html40/frameset.dtd\">\n"#endif#define LDAP_CACHE_LOCK() \ if (st->util_ldap_cache_lock) \ apr_global_mutex_lock(st->util_ldap_cache_lock)#define LDAP_CACHE_UNLOCK() \ if (st->util_ldap_cache_lock) \ apr_global_mutex_unlock(st->util_ldap_cache_lock)static void util_ldap_strdup (char **str, const char *newstr){ if (*str) { free(*str); *str = NULL; } if (newstr) { *str = calloc(1, strlen(newstr)+1); strcpy (*str, newstr); }}/* * Status Handler * -------------- * * This handler generates a status page about the current performance of * the LDAP cache. It is enabled as follows: * * <Location /ldap-status> * SetHandler ldap-status * </Location> * */int util_ldap_handler(request_rec *r){ util_ldap_state_t *st = (util_ldap_state_t *)ap_get_module_config(r->server->module_config, &ldap_module); r->allowed |= (1 << M_GET); if (r->method_number != M_GET) return DECLINED; if (strcmp(r->handler, "ldap-status")) { return DECLINED; } r->content_type = "text/html"; if (r->header_only) return OK; ap_rputs(DOCTYPE_HTML_3_2 "<html><head><title>LDAP Cache Information</title></head>\n", r); ap_rputs("<body bgcolor='#ffffff'><h1 align=center>LDAP Cache Information</h1>\n", r); util_ald_cache_display(r, st); return OK;}/* ------------------------------------------------------------------ *//* * Closes an LDAP connection by unlocking it. The next time * util_ldap_connection_find() is called this connection will be * available for reuse. */LDAP_DECLARE(void) util_ldap_connection_close(util_ldap_connection_t *ldc){ /* * QUESTION: * * Is it safe leaving bound connections floating around between the * different modules? Keeping the user bound is a performance boost, * but it is also a potential security problem - maybe. * * For now we unbind the user when we finish with a connection, but * we don't have to... */ /* mark our connection as available for reuse */#if APR_HAS_THREADS apr_thread_mutex_unlock(ldc->lock);#endif}/* * Destroys an LDAP connection by unbinding and closing the connection to * the LDAP server. It is used to bring the connection back to a known * state after an error, and during pool cleanup. */LDAP_DECLARE_NONSTD(apr_status_t) util_ldap_connection_unbind(void *param){ util_ldap_connection_t *ldc = param; if (ldc) { if (ldc->ldap) { ldap_unbind_s(ldc->ldap); ldc->ldap = NULL; } ldc->bound = 0; } return APR_SUCCESS;}/* * Clean up an LDAP connection by unbinding and unlocking the connection. * This function is registered with the pool cleanup function - causing * the LDAP connections to be shut down cleanly on graceful restart. */LDAP_DECLARE_NONSTD(apr_status_t) util_ldap_connection_cleanup(void *param){ util_ldap_connection_t *ldc = param; if (ldc) { /* unbind and disconnect from the LDAP server */ util_ldap_connection_unbind(ldc); /* free the username and password */ if (ldc->bindpw) { free((void*)ldc->bindpw); } if (ldc->binddn) { free((void*)ldc->binddn); } /* unlock this entry */ util_ldap_connection_close(ldc); } return APR_SUCCESS;}/* * Connect to the LDAP server and binds. Does not connect if already * connected (i.e. ldc->ldap is non-NULL.) Does not bind if already bound. * * Returns LDAP_SUCCESS on success; and an error code on failure */LDAP_DECLARE(int) util_ldap_connection_open(request_rec *r, util_ldap_connection_t *ldc){ int result = 0; int failures = 0; int version = LDAP_VERSION3; util_ldap_state_t *st = (util_ldap_state_t *)ap_get_module_config( r->server->module_config, &ldap_module); /* If the connection is already bound, return */ if (ldc->bound) { ldc->reason = "LDAP: connection open successful (already bound)"; return LDAP_SUCCESS; } /* create the ldap session handle */ if (NULL == ldc->ldap) { /* clear connection requested */ if (!ldc->secure) { ldc->ldap = ldap_init(const_cast(ldc->host), ldc->port); } else /* ssl connnection requested */ { /* check configuration to make sure it supports SSL */ if (st->ssl_support) { #if APR_HAS_LDAP_SSL #if APR_HAS_NOVELL_LDAPSDK ldc->ldap = ldapssl_init(ldc->host, ldc->port, 1); #elif APR_HAS_NETSCAPE_LDAPSDK ldc->ldap = ldapssl_init(ldc->host, ldc->port, 1); #elif APR_HAS_OPENLDAP_LDAPSDK ldc->ldap = ldap_init(ldc->host, ldc->port); if (NULL != ldc->ldap) { int SSLmode = LDAP_OPT_X_TLS_HARD; result = ldap_set_option(ldc->ldap, LDAP_OPT_X_TLS, &SSLmode); if (LDAP_SUCCESS != result) { ldap_unbind_s(ldc->ldap); ldc->reason = "LDAP: ldap_set_option - LDAP_OPT_X_TLS_HARD failed"; ldc->ldap = NULL; } } #elif APR_HAS_MICROSOFT_LDAPSDK ldc->ldap = ldap_sslinit(const_cast(ldc->host), ldc->port, 1); #else ldc->reason = "LDAP: ssl connections not supported"; #endif /* APR_HAS_NOVELL_LDAPSDK */ #endif /* APR_HAS_LDAP_SSL */ } else ldc->reason = "LDAP: ssl connections not supported"; } if (NULL == ldc->ldap) { ldc->bound = 0; if (NULL == ldc->reason) ldc->reason = "LDAP: ldap initialization failed"; return(-1); } /* Set the alias dereferencing option */ ldap_set_option(ldc->ldap, LDAP_OPT_DEREF, &(ldc->deref)); /* always default to LDAP V3 */ ldap_set_option(ldc->ldap, LDAP_OPT_PROTOCOL_VERSION, &version); } /* loop trying to bind up to 10 times if LDAP_SERVER_DOWN error is * returned. Break out of the loop on Success or any other error. * * NOTE: Looping is probably not a great idea. If the server isn't * responding the chances it will respond after a few tries are poor. * However, the original code looped and it only happens on * the error condition. */ for (failures=0; failures<10; failures++) { result = ldap_simple_bind_s(ldc->ldap, const_cast(ldc->binddn), const_cast(ldc->bindpw)); if (LDAP_SERVER_DOWN != result) break; } /* free the handle if there was an error */ if (LDAP_SUCCESS != result) { ldap_unbind_s(ldc->ldap); ldc->ldap = NULL; ldc->bound = 0; ldc->reason = "LDAP: ldap_simple_bind_s() failed"; } else { ldc->bound = 1; ldc->reason = "LDAP: connection open successful"; } return(result);}/* * Find an existing ldap connection struct that matches the * provided ldap connection parameters. * * If not found in the cache, a new ldc structure will be allocated from st->pool * and returned to the caller. If found in the cache, a pointer to the existing * ldc structure will be returned. */LDAP_DECLARE(util_ldap_connection_t *)util_ldap_connection_find(request_rec *r, const char *host, int port, const char *binddn, const char *bindpw, deref_options deref, int secure ){ struct util_ldap_connection_t *l, *p; /* To traverse the linked list */ util_ldap_state_t *st = (util_ldap_state_t *)ap_get_module_config(r->server->module_config, &ldap_module);#if APR_HAS_THREADS /* mutex lock this function */ if (!st->mutex) { apr_thread_mutex_create(&st->mutex, APR_THREAD_MUTEX_DEFAULT, st->pool); } apr_thread_mutex_lock(st->mutex);#endif /* Search for an exact connection match in the list that is not * being used. */ for (l=st->connections,p=NULL; l; l=l->next) {#if APR_HAS_THREADS if (APR_SUCCESS == apr_thread_mutex_trylock(l->lock)) {#endif if ((l->port == port) && (strcmp(l->host, host) == 0) && ((!l->binddn && !binddn) || (l->binddn && binddn && !strcmp(l->binddn, binddn))) && ((!l->bindpw && !bindpw) || (l->bindpw && bindpw && !strcmp(l->bindpw, bindpw))) && (l->deref == deref) && (l->secure == secure)) { break; }#if APR_HAS_THREADS /* If this connection didn't match the criteria, then we * need to unlock the mutex so it is available to be reused. */ apr_thread_mutex_unlock(l->lock); }#endif p = l; } /* If nothing found, search again, but we don't care about the * binddn and bindpw this time. */ if (!l) { for (l=st->connections,p=NULL; l; l=l->next) {#if APR_HAS_THREADS if (APR_SUCCESS == apr_thread_mutex_trylock(l->lock)) {#endif if ((l->port == port) && (strcmp(l->host, host) == 0) && (l->deref == deref) && (l->secure == secure)) { /* the bind credentials have changed */ l->bound = 0; util_ldap_strdup((char**)&(l->binddn), binddn); util_ldap_strdup((char**)&(l->bindpw), bindpw); break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -