Feature #1248 » lighttpd_trunk.ldap.userdn.patch
lighttpd-trunk.patched/src/http_auth.c 2007-06-28 14:50:13.000000000 +0200 | ||
---|---|---|
#ifdef USE_LDAP
|
||
LDAP *ldap;
|
||
LDAPMessage *lm, *first;
|
||
char *dn;
|
||
const char *dn;
|
||
int ret;
|
||
char *attrs[] = { LDAP_NO_ATTRS, NULL };
|
||
size_t i;
|
||
const char *username_token = username->ptr;
|
||
unsigned int token_length = 0;
|
||
/* If we don't allow empty passwords, and this one is empty, there's
|
||
* no point in continuing. */
|
||
if (p->conf.auth_ldap_allow_empty_pw != 1 && pw[0] == '\0')
|
||
return -1;
|
||
/* for now we stay synchronous */
|
||
/*
|
||
* 1. connect anonymously (done in plugin init)
|
||
* 2. get DN for uid = username
|
||
* 3. auth against ldap server
|
||
* 4. (optional) check a field
|
||
* 5. disconnect
|
||
* 1. If we need to find the user DN
|
||
* a. connect anonymously (or using configured bind) (done in plugin init)
|
||
* b. get DN for uid = username
|
||
* 2. auth against ldap server
|
||
* 3. disconnect
|
||
*
|
||
*/
|
||
/* check username
|
||
*
|
||
* we have to protect us againt username which modifies out filter in
|
||
* a unpleasant way
|
||
* we have to protect us againt usernames which modify our filter or
|
||
* user-dn in an unpleasant way. Filters need to have the following
|
||
* characters escaped: ['\\', '*', '(', ')']
|
||
* Custom DNs are tougher, because the escape list is longer, and
|
||
* there are specialized rules for characters at the beginning and
|
||
* end of the value. Escaped: [',', '+', '"', '\\', '<', '>', ';']
|
||
* Also at the beginning of the string: [' ', '#']
|
||
* At the end of the string: [' ']
|
||
*/
|
||
for (i = 0; i < username->used - 1; i++) {
|
||
char c = username->ptr[i];
|
||
if (!isalpha(c) &&
|
||
!isdigit(c)) {
|
||
buffer_copy_string(p->ldap_username, "");
|
||
log_error_write(srv, __FILE__, __LINE__, "sbd",
|
||
"ldap: invalid character (a-zA-Z0-9 allowed) in username:", username, i);
|
||
/* Create a username escaped for the filter first. */
|
||
/* LDAP filter escape rules */
|
||
for (i = 0; i < username->used - 1; ++i) {
|
||
char c = username->ptr[i];
|
||
char s[3] = {'\\',c,0};
|
||
return -1;
|
||
if (('\\' != c) &&
|
||
('*' != c) &&
|
||
('(' != c) &&
|
||
(')' != c)) {
|
||
++token_length;
|
||
} else {
|
||
if (token_length) {
|
||
buffer_append_string_len(p->ldap_username, username_token, token_length);
|
||
token_length = 0;
|
||
}
|
||
buffer_append_string(p->ldap_username, s);
|
||
username_token = username->ptr + i + 1;
|
||
}
|
||
}
|
||
if (p->conf.auth_ldap_allow_empty_pw != 1 && pw[0] == '\0')
|
||
return -1;
|
||
/* If there's a token we never added to the buffer */
|
||
if (token_length) {
|
||
buffer_append_string_len(p->ldap_username, username_token, token_length);
|
||
token_length = 0;
|
||
}
|
||
/* build filter */
|
||
buffer_copy_string_buffer(p->ldap_filter, p->conf.ldap_filter_pre);
|
||
buffer_append_string_buffer(p->ldap_filter, username);
|
||
buffer_append_string_buffer(p->ldap_filter, p->ldap_username);
|
||
buffer_append_string_buffer(p->ldap_filter, p->conf.ldap_filter_post);
|
||
if (p->conf.auth_ldap_userdn->used) {
|
||
buffer_copy_string(p->ldap_username, "");
|
||
/* User-DN escape rules */
|
||
for (i = 0; i < username->used - 1; ++i) {
|
||
char c = username->ptr[i];
|
||
char s[3] = {'\\',c,0};
|
||
if ((0 == i) &&
|
||
((' ' == c) ||
|
||
('#' == c))) {
|
||
buffer_copy_string(p->ldap_username, s);
|
||
username_token = username->ptr + i + 1;
|
||
} else if (((username->used - 2) == i) &&
|
||
(' ' == c)) {
|
||
if (token_length) {
|
||
buffer_append_string_len(p->ldap_username, username_token, token_length);
|
||
token_length = 0;
|
||
}
|
||
buffer_append_string(p->ldap_username, s);
|
||
username_token = username->ptr + i + 1;
|
||
} else if ((',' != c) &&
|
||
('+' != c) &&
|
||
('"' != c) &&
|
||
('\\' != c) &&
|
||
('<' != c) &&
|
||
('>' != c) &&
|
||
(';' != c)) {
|
||
/* 2. */
|
||
if (p->conf.ldap == NULL ||
|
||
LDAP_SUCCESS != (ret = ldap_search_s(p->conf.ldap, p->conf.auth_ldap_basedn->ptr, LDAP_SCOPE_SUBTREE, p->ldap_filter->ptr, attrs, 0, &lm))) {
|
||
if (auth_ldap_init(srv, &p->conf) != HANDLER_GO_ON)
|
||
return -1;
|
||
if (LDAP_SUCCESS != (ret = ldap_search_s(p->conf.ldap, p->conf.auth_ldap_basedn->ptr, LDAP_SCOPE_SUBTREE, p->ldap_filter->ptr, attrs, 0, &lm))) {
|
||
++token_length;
|
||
} else {
|
||
log_error_write(srv, __FILE__, __LINE__, "sssb",
|
||
"ldap:", ldap_err2string(ret), "filter:", p->ldap_filter);
|
||
if (token_length) {
|
||
buffer_append_string_len(p->ldap_username, username_token, token_length);
|
||
token_length = 0;
|
||
}
|
||
buffer_append_string(p->ldap_username, s);
|
||
username_token = username->ptr + i + 1;
|
||
}
|
||
}
|
||
return -1;
|
||
/* If there's a token we never added to the buffer */
|
||
if (token_length) {
|
||
buffer_append_string_len(p->ldap_username, username_token, token_length);
|
||
token_length = 0;
|
||
}
|
||
/* build userdn */
|
||
buffer_copy_string_buffer(p->ldap_userdn, p->conf.ldap_userdn_pre);
|
||
buffer_append_string_buffer(p->ldap_userdn, p->ldap_username);
|
||
buffer_append_string_buffer(p->ldap_userdn, p->conf.ldap_userdn_post);
|
||
dn = p->ldap_userdn->ptr;
|
||
}
|
||
if (NULL == (first = ldap_first_entry(p->conf.ldap, lm))) {
|
||
log_error_write(srv, __FILE__, __LINE__, "s", "ldap ...");
|
||
if (!p->conf.auth_ldap_userdn->used) {
|
||
ldap_msgfree(lm);
|
||
/* 1b. */
|
||
if (p->conf.ldap == NULL ||
|
||
LDAP_SUCCESS != (ret = ldap_search_s(p->conf.ldap, p->conf.auth_ldap_basedn->ptr, LDAP_SCOPE_SUBTREE, p->ldap_filter->ptr, attrs, 0, &lm))) {
|
||
if (auth_ldap_init(srv, &p->conf) != HANDLER_GO_ON)
|
||
return -1;
|
||
if (LDAP_SUCCESS != (ret = ldap_search_s(p->conf.ldap, p->conf.auth_ldap_basedn->ptr, LDAP_SCOPE_SUBTREE, p->ldap_filter->ptr, attrs, 0, &lm))) {
|
||
return -1;
|
||
}
|
||
log_error_write(srv, __FILE__, __LINE__, "sssb",
|
||
"ldap:", ldap_err2string(ret), "filter:", p->ldap_filter);
|
||
return -1;
|
||
}
|
||
}
|
||
if (NULL == (dn = ldap_get_dn(p->conf.ldap, first))) {
|
||
log_error_write(srv, __FILE__, __LINE__, "s", "ldap ...");
|
||
if (NULL == (first = ldap_first_entry(p->conf.ldap, lm))) {
|
||
log_error_write(srv, __FILE__, __LINE__, "s", "ldap ...");
|
||
ldap_msgfree(lm);
|
||
ldap_msgfree(lm);
|
||
return -1;
|
||
}
|
||
return -1;
|
||
}
|
||
ldap_msgfree(lm);
|
||
if (NULL == (dn = ldap_get_dn(p->conf.ldap, first))) {
|
||
log_error_write(srv, __FILE__, __LINE__, "s", "ldap ...");
|
||
ldap_msgfree(lm);
|
||
/* 3. */
|
||
return -1;
|
||
}
|
||
ldap_msgfree(lm);
|
||
}
|
||
/* 2. */
|
||
if (NULL == (ldap = ldap_init(p->conf.auth_ldap_hostname->ptr, LDAP_PORT))) {
|
||
log_error_write(srv, __FILE__, __LINE__, "ss", "ldap ...", strerror(errno));
|
||
return -1;
|
||
... | ... | |
return -1;
|
||
}
|
||
/* 5. */
|
||
/* If we're using the userdn, we haven't applied the filter previously, so
|
||
* we'll do it now. */
|
||
if (p->conf.auth_ldap_userdn->used) {
|
||
if (LDAP_SUCCESS != (ret = ldap_search_s(ldap, dn, LDAP_SCOPE_BASE, p->ldap_filter->ptr, attrs, 0, &lm))) {
|
||
log_error_write(srv, __FILE__, __LINE__, "sssb",
|
||
"ldap:", ldap_err2string(ret), "filter:", p->ldap_filter);
|
||
return -1;
|
||
}
|
||
if (NULL == (first = ldap_first_entry(p->conf.ldap, lm))) {
|
||
log_error_write(srv, __FILE__, __LINE__, "s", "ldap ...");
|
||
ldap_msgfree(lm);
|
||
return -1;
|
||
}
|
||
ldap_msgfree(lm);
|
||
}
|
||
/* 3. */
|
||
ldap_unbind_s(ldap);
|
||
/* everything worked, good, access granted */
|
lighttpd-trunk.patched/src/http_auth.h 2007-06-28 14:50:13.000000000 +0200 | ||
---|---|---|
buffer *auth_ldap_basedn;
|
||
buffer *auth_ldap_binddn;
|
||
buffer *auth_ldap_bindpw;
|
||
buffer *auth_ldap_userdn;
|
||
buffer *auth_ldap_filter;
|
||
buffer *auth_ldap_cafile;
|
||
buffer *auth_ldap_cert;
|
||
... | ... | |
buffer *ldap_filter_pre;
|
||
buffer *ldap_filter_post;
|
||
buffer *ldap_userdn_pre;
|
||
buffer *ldap_userdn_post;
|
||
#endif
|
||
} mod_auth_plugin_config;
|
||
... | ... | |
#ifdef USE_LDAP
|
||
buffer *ldap_filter;
|
||
buffer *ldap_username;
|
||
buffer *ldap_userdn;
|
||
#endif
|
||
mod_auth_plugin_config **config_storage;
|
lighttpd-trunk.patched/src/mod_auth.c 2007-06-28 14:59:39.000000000 +0200 | ||
---|---|---|
p->auth_user = buffer_init();
|
||
#ifdef USE_LDAP
|
||
p->ldap_filter = buffer_init();
|
||
p->ldap_username = buffer_init();
|
||
p->ldap_userdn = buffer_init();
|
||
#endif
|
||
return p;
|
||
... | ... | |
buffer_free(p->auth_user);
|
||
#ifdef USE_LDAP
|
||
buffer_free(p->ldap_filter);
|
||
buffer_free(p->ldap_username);
|
||
buffer_free(p->ldap_userdn);
|
||
#endif
|
||
if (p->config_storage) {
|
||
... | ... | |
buffer_free(s->auth_ldap_basedn);
|
||
buffer_free(s->auth_ldap_binddn);
|
||
buffer_free(s->auth_ldap_bindpw);
|
||
buffer_free(s->auth_ldap_userdn);
|
||
buffer_free(s->auth_ldap_filter);
|
||
buffer_free(s->auth_ldap_cafile);
|
||
buffer_free(s->auth_ldap_cert);
|
||
... | ... | |
#ifdef USE_LDAP
|
||
buffer_free(s->ldap_filter_pre);
|
||
buffer_free(s->ldap_filter_post);
|
||
buffer_free(s->ldap_userdn_pre);
|
||
buffer_free(s->ldap_userdn_post);
|
||
if (s->ldap) ldap_unbind_s(s->ldap);
|
||
#endif
|
||
... | ... | |
PATCH_OPTION(auth_ldap_basedn);
|
||
PATCH_OPTION(auth_ldap_binddn);
|
||
PATCH_OPTION(auth_ldap_bindpw);
|
||
PATCH_OPTION(auth_ldap_userdn);
|
||
PATCH_OPTION(auth_ldap_filter);
|
||
PATCH_OPTION(auth_ldap_cafile);
|
||
PATCH_OPTION(auth_ldap_cert);
|
||
... | ... | |
PATCH_OPTION(ldap);
|
||
PATCH_OPTION(ldap_filter_pre);
|
||
PATCH_OPTION(ldap_filter_post);
|
||
PATCH_OPTION(ldap_userdn_pre);
|
||
PATCH_OPTION(ldap_userdn_post);
|
||
#endif
|
||
/* skip the first, the global context */
|
||
... | ... | |
PATCH_OPTION(ldap);
|
||
PATCH_OPTION(ldap_filter_pre);
|
||
PATCH_OPTION(ldap_filter_post);
|
||
PATCH_OPTION(ldap_userdn_pre);
|
||
PATCH_OPTION(ldap_userdn_post);
|
||
#endif
|
||
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.base-dn"))) {
|
||
PATCH_OPTION(auth_ldap_basedn);
|
||
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.bind-dn"))) {
|
||
PATCH_OPTION(auth_ldap_binddn);
|
||
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.bind-pw"))) {
|
||
PATCH_OPTION(auth_ldap_bindpw);
|
||
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.user-dn"))) {
|
||
PATCH_OPTION(auth_ldap_userdn);
|
||
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.filter"))) {
|
||
PATCH_OPTION(auth_ldap_filter);
|
||
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.ca-file"))) {
|
||
... | ... | |
{ "auth.backend.ldap.starttls", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 10 */
|
||
{ "auth.backend.ldap.bind-dn", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 11 */
|
||
{ "auth.backend.ldap.bind-pw", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 12 */
|
||
{ "auth.backend.ldap.allow-empty-pw", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 13 */
|
||
{ "auth.backend.htdigest.userfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 14 */
|
||
{ "auth.backend.htpasswd.userfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 15 */
|
||
{ "auth.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 16 */
|
||
{ "auth.backend.ldap.user-dn", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 13 */
|
||
{ "auth.backend.ldap.allow-empty-pw", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 14 */
|
||
{ "auth.backend.htdigest.userfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 15 */
|
||
{ "auth.backend.htpasswd.userfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 16 */
|
||
{ "auth.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 17 */
|
||
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
|
||
};
|
||
... | ... | |
s->auth_ldap_basedn = buffer_init();
|
||
s->auth_ldap_binddn = buffer_init();
|
||
s->auth_ldap_bindpw = buffer_init();
|
||
s->auth_ldap_userdn = buffer_init();
|
||
s->auth_ldap_filter = buffer_init();
|
||
s->auth_ldap_cafile = buffer_init();
|
||
s->auth_ldap_cert = buffer_init();
|
||
... | ... | |
#ifdef USE_LDAP
|
||
s->ldap_filter_pre = buffer_init();
|
||
s->ldap_filter_post = buffer_init();
|
||
s->ldap_userdn_pre = buffer_init();
|
||
s->ldap_userdn_post = buffer_init();
|
||
s->ldap = NULL;
|
||
#endif
|
||
... | ... | |
cv[10].destination = &(s->auth_ldap_starttls);
|
||
cv[11].destination = s->auth_ldap_binddn;
|
||
cv[12].destination = s->auth_ldap_bindpw;
|
||
cv[13].destination = &(s->auth_ldap_allow_empty_pw);
|
||
cv[14].destination = s->auth_htdigest_userfile;
|
||
cv[15].destination = s->auth_htpasswd_userfile;
|
||
cv[16].destination = &(s->auth_debug);
|
||
cv[13].destination = s->auth_ldap_userdn;
|
||
cv[14].destination = &(s->auth_ldap_allow_empty_pw);
|
||
cv[15].destination = s->auth_htdigest_userfile;
|
||
cv[16].destination = s->auth_htpasswd_userfile;
|
||
cv[17].destination = &(s->auth_debug);
|
||
p->config_storage[i] = s;
|
||
ca = ((data_config *)srv->config_context->data[i])->value;
|
||
... | ... | |
}
|
||
/* 1. */
|
||
if (s->auth_ldap_binddn->used) {
|
||
if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(s->ldap, s->auth_ldap_binddn->ptr, s->auth_ldap_bindpw->ptr))) {
|
||
log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
|
||
/* If the user DN is supplied, we don't need to do an initial bind
|
||
* to find it. */
|
||
if (s->auth_ldap_userdn->used) {
|
||
char *dollar;
|
||
/* parse userdn */
|
||
if (NULL == (dollar = strchr(s->auth_ldap_userdn->ptr, '$'))) {
|
||
log_error_write(srv, __FILE__, __LINE__, "s", "ldap: auth.backend.ldap.user-dn is missing a replace-operator '$'");
|
||
return HANDLER_ERROR;
|
||
}
|
||
} else {
|
||
if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(s->ldap, NULL, NULL))) {
|
||
log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
|
||
return HANDLER_ERROR;
|
||
buffer_copy_string_len(s->ldap_userdn_pre, s->auth_ldap_userdn->ptr, dollar - s->auth_ldap_userdn->ptr);
|
||
buffer_copy_string(s->ldap_userdn_post, dollar+1);
|
||
} else {
|
||
/* 1. */
|
||
if (s->auth_ldap_binddn->used) {
|
||
if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(s->ldap, s->auth_ldap_binddn->ptr, s->auth_ldap_bindpw->ptr))) {
|
||
log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
|
||
return HANDLER_ERROR;
|
||
}
|
||
} else {
|
||
if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(s->ldap, NULL, NULL))) {
|
||
log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
|
||
return HANDLER_ERROR;
|
||
}
|
||
}
|
||
}
|
||
}
|