📄 mod_authnz_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. */#include "ap_provider.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 "mod_auth.h"#include "apr_strings.h"#include "apr_xlate.h"#define APR_WANT_STRFUNC#include "apr_want.h"#include "apr_lib.h"#if APR_HAVE_UNISTD_H/* for getpid() */#include <unistd.h>#endif#include <ctype.h>#if !APR_HAS_LDAP#error mod_authnz_ldap requires APR-util to have LDAP support built in. To fix add --with-ldap to ./configure.#endiftypedef 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 authz_enabled; Is ldap authorization 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 user_is_dn; /* If true, connection->user is DN instead of userid */ char *remote_user_attribute; /* If set, connection->user is this attribute 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 */} authn_ldap_config_t;typedef struct { char *dn; /* The saved dn from a successful search */ char *user; /* The username provided by the client */} authn_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 authnz_ldap_module;static APR_OPTIONAL_FN_TYPE(uldap_connection_close) *util_ldap_connection_close;static APR_OPTIONAL_FN_TYPE(uldap_connection_find) *util_ldap_connection_find;static APR_OPTIONAL_FN_TYPE(uldap_cache_comparedn) *util_ldap_cache_comparedn;static APR_OPTIONAL_FN_TYPE(uldap_cache_compare) *util_ldap_cache_compare;static APR_OPTIONAL_FN_TYPE(uldap_cache_checkuserid) *util_ldap_cache_checkuserid;static APR_OPTIONAL_FN_TYPE(uldap_cache_getuserdn) *util_ldap_cache_getuserdn;static APR_OPTIONAL_FN_TYPE(uldap_ssl_supported) *util_ldap_ssl_supported;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; 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_LENstatic void authn_ldap_build_filter(char *filtbuf, request_rec *r, const char* sent_user, const char* sent_filter, authn_ldap_config_t *sec){ char *p, *q, *filtbuf_end; char *user, *filter; apr_xlate_t *convset = NULL; apr_size_t inbytes; apr_size_t outbytes; char *outbuf; if (sent_user != NULL) { user = apr_pstrdup (r->pool, sent_user); } else return; if (sent_filter != NULL) { filter = apr_pstrdup (r->pool, sent_filter); } else filter = sec->filter; 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=", 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 void *create_authnz_ldap_dir_config(apr_pool_t *p, char *d){ authn_ldap_config_t *sec = (authn_ldap_config_t *)apr_pcalloc(p, sizeof(authn_ldap_config_t)); sec->pool = p;#if APR_HAS_THREADS apr_thread_mutex_create(&sec->lock, APR_THREAD_MUTEX_DEFAULT, p);#endif/* sec->authz_enabled = 1;*/ sec->groupattr = apr_array_make(p, GROUPATTR_MAX_ELTS, sizeof(struct mod_auth_ldap_groupattr_entry_t)); sec->have_ldap_url = 0; sec->url = ""; sec->host = NULL; sec->binddn = NULL; sec->bindpw = NULL; sec->deref = always; sec->group_attrib_is_dn = 1; sec->auth_authoritative = 1;/* sec->frontpage_hack = 0;*/ sec->secure = -1; /*Initialize to unset*/ sec->user_is_dn = 0; sec->remote_user_attribute = NULL; sec->compare_dn_on_server = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -