📄 util_ldap.c
字号:
/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 "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"#include <apr_strings.h>#if APR_HAVE_UNISTD_H#include <unistd.h>#endif#if !APR_HAS_LDAP#error mod_ldap requires APR-util to have LDAP support built in#endif#ifdef AP_NEED_SET_MUTEX_PERMS#include "unixd.h"#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 3/* Default define for ldap functions that need a SIZELIMIT but * do not have the define * XXX This should be removed once a supporting #define is * released through APR-Util. */#ifndef APR_LDAP_SIZELIMIT#define APR_LDAP_SIZELIMIT -1#endifmodule AP_MODULE_DECLARE_DATA ldap_module;#define LDAP_CACHE_LOCK() do { \ if (st->util_ldap_cache_lock) \ apr_global_mutex_lock(st->util_ldap_cache_lock); \} while (0)#define LDAP_CACHE_UNLOCK() do { \ if (st->util_ldap_cache_lock) \ apr_global_mutex_unlock(st->util_ldap_cache_lock); \} while (0)static void util_ldap_strdup (char **str, const char *newstr){ if (*str) { free(*str); *str = NULL; } if (newstr) { *str = strdup(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> * */static 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; charset=ISO-8859-1"; 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 * uldap_connection_find() is called this connection will be * available for reuse. */static void uldap_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. */static apr_status_t uldap_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. */static apr_status_t uldap_connection_cleanup(void *param){ util_ldap_connection_t *ldc = param; if (ldc) { /* unbind and disconnect from the LDAP server */ uldap_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 */ uldap_connection_close(ldc); } return APR_SUCCESS;}static int uldap_connection_init(request_rec *r, util_ldap_connection_t *ldc ){ int rc = 0, ldap_option = 0; int version = LDAP_VERSION3; apr_ldap_err_t *result = NULL;#ifdef LDAP_OPT_NETWORK_TIMEOUT struct timeval timeOut = {10,0}; /* 10 second connection timeout */#endif util_ldap_state_t *st = (util_ldap_state_t *)ap_get_module_config(r->server->module_config, &ldap_module); /* Since the host will include a port if the default port is not used, * always specify the default ports for the port parameter. This will * allow a host string that contains multiple hosts the ability to mix * some hosts with ports and some without. All hosts which do not * specify a port will use the default port. */ apr_ldap_init(r->pool, &(ldc->ldap), ldc->host, APR_LDAP_SSL == ldc->secure ? LDAPS_PORT : LDAP_PORT, APR_LDAP_NONE, &(result)); if (result != NULL && result->rc) { ldc->reason = result->reason; } if (NULL == ldc->ldap) { ldc->bound = 0; if (NULL == ldc->reason) { ldc->reason = "LDAP: ldap initialization failed"; } else { ldc->reason = result->reason; } return(result->rc); } /* always default to LDAP V3 */ ldap_set_option(ldc->ldap, LDAP_OPT_PROTOCOL_VERSION, &version); /* set client certificates */ if (!apr_is_empty_array(ldc->client_certs)) { apr_ldap_set_option(r->pool, ldc->ldap, APR_LDAP_OPT_TLS_CERT, ldc->client_certs, &(result)); if (LDAP_SUCCESS != result->rc) { uldap_connection_unbind( ldc ); ldc->reason = result->reason; return(result->rc); } } /* switch on SSL/TLS */ if (APR_LDAP_NONE != ldc->secure) { apr_ldap_set_option(r->pool, ldc->ldap, APR_LDAP_OPT_TLS, &ldc->secure, &(result)); if (LDAP_SUCCESS != result->rc) { uldap_connection_unbind( ldc ); ldc->reason = result->reason; return(result->rc); } } /* Set the alias dereferencing option */ ldap_option = ldc->deref; ldap_set_option(ldc->ldap, LDAP_OPT_DEREF, &ldap_option);/*XXX All of the #ifdef's need to be removed once apr-util 1.2 is released */#ifdef APR_LDAP_OPT_VERIFY_CERT apr_ldap_set_option(r->pool, ldc->ldap, APR_LDAP_OPT_VERIFY_CERT, &(st->verify_svr_cert), &(result));#else#if defined(LDAPSSL_VERIFY_SERVER) if (st->verify_svr_cert) { result->rc = ldapssl_set_verify_mode(LDAPSSL_VERIFY_SERVER); } else { result->rc = ldapssl_set_verify_mode(LDAPSSL_VERIFY_NONE); }#elif defined(LDAP_OPT_X_TLS_REQUIRE_CERT) /* This is not a per-connection setting so just pass NULL for the Ldap connection handle */ if (st->verify_svr_cert) { int i = LDAP_OPT_X_TLS_DEMAND; result->rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &i); } else { int i = LDAP_OPT_X_TLS_NEVER; result->rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &i); }#endif#endif#ifdef LDAP_OPT_NETWORK_TIMEOUT if (st->connectionTimeout > 0) { timeOut.tv_sec = st->connectionTimeout; } if (st->connectionTimeout >= 0) { rc = apr_ldap_set_option(r->pool, ldc->ldap, LDAP_OPT_NETWORK_TIMEOUT, (void *)&timeOut, &(result)); if (APR_SUCCESS != rc) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, "LDAP: Could not set the connection timeout"); } }#endif return(rc);}/* * 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 */static int uldap_connection_open(request_rec *r, util_ldap_connection_t *ldc){ int rc = 0; int failures = 0; /* sanity check for NULL */ if (!ldc) { return -1; } /* 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) { rc = uldap_connection_init( r, ldc ); if (LDAP_SUCCESS != rc) { return rc; } } /* 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++) { rc = ldap_simple_bind_s(ldc->ldap, (char *)ldc->binddn, (char *)ldc->bindpw); if (!AP_LDAP_IS_SERVER_DOWN(rc)) { break; } else if (failures == 5) { /* attempt to init the connection once again */ uldap_connection_unbind( ldc ); rc = uldap_connection_init( r, ldc ); if (LDAP_SUCCESS != rc) { break; } } } /* free the handle if there was an error */ if (LDAP_SUCCESS != rc) { uldap_connection_unbind(ldc); ldc->reason = "LDAP: ldap_simple_bind_s() failed"; } else { ldc->bound = 1; ldc->reason = "LDAP: connection open successful"; } return(rc);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -