📄 mod_auth_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. *//* * mod_auth_ldap.c: LDAP authentication module * * 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 <apr_xlate.h>#define APR_WANT_STRFUNC#include <apr_want.h>#include "ap_config.h"#if APR_HAVE_UNISTD_H/* for getpid() */#include <unistd.h>#endif#include <ctype.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"#ifndef APU_HAS_LDAP#error mod_auth_ldap requires APR-util to have LDAP support built in#endif/* per directory configuration */typedef struct { apr_pool_t *pool; /* Pool that this config is allocated from */#if APR_HAS_THREADS apr_thread_mutex_t *lock; /* Lock for this config */#endif int auth_authoritative; /* Is this auth method the one and only? */ int enabled; /* Is auth_ldap enabled in this directory? */ /* These parameters are all derived from the AuthLDAPURL directive */ char *url; /* String representation of the URL */ char *host; /* Name of the LDAP server (or space separated list) */ int port; /* Port of the LDAP server */ char *basedn; /* Base DN to do all searches from */ char *attribute; /* Attribute to search for */ char **attributes; /* Array of all the attributes to return */ int scope; /* Scope of the search */ char *filter; /* Filter to further limit the search */ deref_options deref; /* how to handle alias dereferening */ char *binddn; /* DN to bind to server (can be NULL) */ char *bindpw; /* Password to bind to server (can be NULL) */ int frontpage_hack; /* Hack for frontpage support */ int user_is_dn; /* If true, connection->user is DN instead of userid */ int compare_dn_on_server; /* If true, will use server to do DN compare */ int have_ldap_url; /* Set if we have found an LDAP url */ apr_array_header_t *groupattr; /* List of Group attributes */ int group_attrib_is_dn; /* If true, the group attribute is the DN, otherwise, it's the exact string passed by the HTTP client */ int secure; /* True if SSL connections are requested */} mod_auth_ldap_config_t;typedef struct mod_auth_ldap_request_t { char *dn; /* The saved dn from a successful search */ char *user; /* The username provided by the client */} mod_auth_ldap_request_t;/* maximum group elements supported */#define GROUPATTR_MAX_ELTS 10struct mod_auth_ldap_groupattr_entry_t { char *name;};module AP_MODULE_DECLARE_DATA auth_ldap_module;/* function prototypes */void mod_auth_ldap_build_filter(char *filtbuf, request_rec *r, mod_auth_ldap_config_t *sec);int mod_auth_ldap_check_user_id(request_rec *r);int mod_auth_ldap_auth_checker(request_rec *r);void *mod_auth_ldap_create_dir_config(apr_pool_t *p, char *d);/* ---------------------------------------- */static apr_hash_t *charset_conversions = NULL;static char *to_charset = NULL; /* UTF-8 identifier derived from the charset.conv file *//* Derive a code page ID give a language name or ID */static char* derive_codepage_from_lang (apr_pool_t *p, char *language){ int lang_len; int check_short = 0; char *charset; if (!language) /* our default codepage */ return apr_pstrdup(p, "ISO-8859-1"); else lang_len = strlen(language); charset = (char*) apr_hash_get(charset_conversions, language, APR_HASH_KEY_STRING); if (!charset) { language[2] = '\0'; charset = (char*) apr_hash_get(charset_conversions, language, APR_HASH_KEY_STRING); } if (charset) { charset = apr_pstrdup(p, charset); } return charset;}static apr_xlate_t* get_conv_set (request_rec *r){ char *lang_line = (char*)apr_table_get(r->headers_in, "accept-language"); char *lang; apr_xlate_t *convset; if (lang_line) { lang_line = apr_pstrdup(r->pool, lang_line); for (lang = lang_line;*lang;lang++) { if ((*lang == ',') || (*lang == ';')) { *lang = '\0'; break; } } lang = derive_codepage_from_lang(r->pool, lang_line); if (lang && (apr_xlate_open(&convset, to_charset, lang, r->pool) == APR_SUCCESS)) { return convset; } } return NULL;}/* * Build the search filter, or at least as much of the search filter that * will fit in the buffer. We don't worry about the buffer not being able * to hold the entire filter. If the buffer wasn't big enough to hold the * filter, ldap_search_s will complain, but the only situation where this * is likely to happen is if the client sent a really, really long * username, most likely as part of an attack. * * The search filter consists of the filter provided with the URL, * combined with a filter made up of the attribute provided with the URL, * and the actual username passed by the HTTP client. For example, assume * that the LDAP URL is * * ldap://ldap.airius.com/ou=People, o=Airius?uid??(posixid=*) * * Further, assume that the userid passed by the client was `userj'. The * search filter will be (&(posixid=*)(uid=userj)). */#define FILTER_LENGTH MAX_STRING_LENvoid mod_auth_ldap_build_filter(char *filtbuf, request_rec *r, mod_auth_ldap_config_t *sec){ char *p, *q, *filtbuf_end; char *user; apr_xlate_t *convset = NULL; apr_size_t inbytes; apr_size_t outbytes; char *outbuf; if (r->user != NULL) { user = apr_pstrdup (r->pool, r->user); } else return; if (charset_conversions) { convset = get_conv_set(r); } if (convset) { inbytes = strlen(user); outbytes = (inbytes+1)*3; outbuf = apr_pcalloc(r->pool, outbytes); /* Convert the user name to UTF-8. This is only valid for LDAP v3 */ if (apr_xlate_conv_buffer(convset, user, &inbytes, outbuf, &outbytes) == APR_SUCCESS) { user = apr_pstrdup(r->pool, outbuf); } } /* * Create the first part of the filter, which consists of the * config-supplied portions. */ apr_snprintf(filtbuf, FILTER_LENGTH, "(&(%s)(%s=", sec->filter, sec->attribute); /* * Now add the client-supplied username to the filter, ensuring that any * LDAP filter metachars are escaped. */ filtbuf_end = filtbuf + FILTER_LENGTH - 1;#if APR_HAS_MICROSOFT_LDAPSDK for (p = user, q=filtbuf + strlen(filtbuf); *p && q < filtbuf_end; ) { if (strchr("*()\\", *p) != NULL) { if ( q + 3 >= filtbuf_end) break; /* Don't write part of escape sequence if we can't write all of it */ *q++ = '\\'; switch ( *p++ ) { case '*': *q++ = '2'; *q++ = 'a'; break; case '(': *q++ = '2'; *q++ = '8'; break; case ')': *q++ = '2'; *q++ = '9'; break; case '\\': *q++ = '5'; *q++ = 'c'; break; } } else *q++ = *p++; }#else for (p = user, q=filtbuf + strlen(filtbuf); *p && q < filtbuf_end; *q++ = *p++) { if (strchr("*()\\", *p) != NULL) { *q++ = '\\'; if (q >= filtbuf_end) { break; } } }#endif *q = '\0'; /* * Append the closing parens of the filter, unless doing so would * overrun the buffer. */ if (q + 2 <= filtbuf_end) strcat(filtbuf, "))");}static apr_status_t mod_auth_ldap_cleanup_connection_close(void *param){ util_ldap_connection_t *ldc = param; util_ldap_connection_close(ldc); return APR_SUCCESS;}/* * Authentication Phase * -------------------- * * This phase authenticates the credentials the user has sent with * the request (ie the username and password are checked). This is done * by making an attempt to bind to the LDAP server using this user's * DN and the supplied password. * */int mod_auth_ldap_check_user_id(request_rec *r){ int failures = 0; const char **vals = NULL; char filtbuf[FILTER_LENGTH]; mod_auth_ldap_config_t *sec = (mod_auth_ldap_config_t *)ap_get_module_config(r->per_dir_config, &auth_ldap_module); util_ldap_connection_t *ldc = NULL; const char *sent_pw; int result = 0; const char *dn = NULL; mod_auth_ldap_request_t *req = (mod_auth_ldap_request_t *)apr_pcalloc(r->pool, sizeof(mod_auth_ldap_request_t)); ap_set_module_config(r->request_config, &auth_ldap_module, req); if (!sec->enabled) { return DECLINED; } /* * Basic sanity checks before any LDAP operations even happen. */ if (!sec->have_ldap_url) { return DECLINED; }start_over: /* There is a good AuthLDAPURL, right? */ if (sec->host) { ldc = util_ldap_connection_find(r, sec->host, sec->port, sec->binddn, sec->bindpw, sec->deref, sec->secure); } else { ap_log_rerror(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r, "[%d] auth_ldap authenticate: no sec->host - weird...?", getpid()); return sec->auth_authoritative? HTTP_UNAUTHORIZED : DECLINED; } ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r, "[%d] auth_ldap authenticate: using URL %s", getpid(), sec->url); /* Get the password that the client sent */ if ((result = ap_get_basic_auth_pw(r, &sent_pw))) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r, "[%d] auth_ldap authenticate: " "ap_get_basic_auth_pw() returns %d", getpid(), result); util_ldap_connection_close(ldc); return result; } if (r->user == NULL) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r, "[%d] auth_ldap authenticate: no user specified", getpid()); util_ldap_connection_close(ldc); return sec->auth_authoritative? HTTP_UNAUTHORIZED : DECLINED; } /* build the username filter */ mod_auth_ldap_build_filter(filtbuf, r, sec); /* do the user search */ result = util_ldap_cache_checkuserid(r, ldc, sec->url, sec->basedn, sec->scope, sec->attributes, filtbuf, sent_pw, &dn, &vals); util_ldap_connection_close(ldc); /* sanity check - if server is down, retry it up to 5 times */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -