[mod_auth*] use config_plugin_values_init()

This commit is contained in:
Glenn Strauss 2019-11-06 19:37:11 -05:00
parent 12b11f3042
commit 8e713130b3
7 changed files with 1010 additions and 947 deletions

View File

@ -19,21 +19,15 @@
*/
typedef struct {
/* auth */
array *auth_require;
buffer *auth_backend_conf;
unsigned short auth_extern_authn;
/* generated */
const http_auth_backend_t *auth_backend;
const http_auth_backend_t *auth_backend;
const array *auth_require;
unsigned int auth_extern_authn;
} plugin_config;
typedef struct {
PLUGIN_DATA;
plugin_config **config_storage;
plugin_config conf;
PLUGIN_DATA;
plugin_config defaults;
plugin_config conf;
} plugin_data;
static handler_t mod_auth_check_basic(server *srv, connection *con, void *p_d, const struct http_auth_require_t *require, const struct http_auth_backend_t *backend);
@ -56,31 +50,34 @@ INIT_FUNC(mod_auth_init) {
return p;
}
static void mod_auth_free_config(plugin_data * const p) {
if (NULL == p->cvlist) return;
/* (init i to 0 if global context; to 1 to skip empty global context) */
for (int i = !p->cvlist[0].v.u2[1], used = p->nconfig; i < used; ++i) {
config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
for (; -1 != cpv->k_id; ++cpv) {
if (cpv->vtype != T_CONFIG_LOCAL || NULL == cpv->v.v) continue;
switch (cpv->k_id) {
case 1: /* auth.require */
array_free(cpv->v.v);
break;
default:
break;
}
}
}
}
FREE_FUNC(mod_auth_free) {
plugin_data *p = p_d;
plugin_data *p = p_d;
if (!p) return HANDLER_GO_ON;
UNUSED(srv);
mod_auth_free_config(p);
if (!p) return HANDLER_GO_ON;
if (p->config_storage) {
size_t i;
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
if (NULL == s) continue;
array_free(s->auth_require);
buffer_free(s->auth_backend_conf);
free(s);
}
free(p->config_storage);
}
free(p);
return HANDLER_GO_ON;
free(p->cvlist);
free(p);
UNUSED(srv);
return HANDLER_GO_ON;
}
/* data type for mod_auth structured data
@ -268,63 +265,11 @@ static int mod_auth_require_parse (server *srv, http_auth_require_t * const requ
return 1; /* success */
}
SETDEFAULTS_FUNC(mod_auth_set_defaults) {
plugin_data *p = p_d;
size_t i;
config_values_t cv[] = {
{ "auth.backend", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
{ "auth.require", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
{ "auth.extern-authn", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },/* 2 */
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *));
for (i = 0; i < srv->config_context->used; i++) {
data_config const* config = (data_config const*)srv->config_context->data[i];
plugin_config *s;
size_t n;
const data_array *da;
s = calloc(1, sizeof(plugin_config));
s->auth_backend_conf = buffer_init();
s->auth_require = array_init();
cv[0].destination = s->auth_backend_conf;
cv[1].destination = s->auth_require; /* T_CONFIG_LOCAL; not modified by config_insert_values_global() */
cv[2].destination = &s->auth_extern_authn;
p->config_storage[i] = s;
if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
return HANDLER_ERROR;
}
if (!buffer_string_is_empty(s->auth_backend_conf)) {
s->auth_backend = http_auth_backend_get(s->auth_backend_conf);
if (NULL == s->auth_backend) {
log_error_write(srv, __FILE__, __LINE__, "sb", "auth.backend not supported:", s->auth_backend_conf);
return HANDLER_ERROR;
}
}
/* no auth.require for this section */
if (NULL == (da = (const data_array *)array_get_element_klen(config->value, CONST_STR_LEN("auth.require")))) continue;
if (da->type != TYPE_ARRAY || !array_is_kvarray(&da->value)) {
log_error_write(srv, __FILE__, __LINE__, "ss",
"unexpected value for auth.require; expected ",
"auth.require = ( \"urlpath\" => ( \"option\" => \"value\" ) )");
return HANDLER_ERROR;
}
for (n = 0; n < da->value.used; n++) {
static handler_t mod_auth_require_parse_array(server *srv, const array *value, array * const auth_require)
{
for (uint32_t n = 0; n < value->used; ++n) {
size_t m;
data_array *da_file = (data_array *)da->value.data[n];
data_array *da_file = (data_array *)value->data[n];
const buffer *method = NULL, *realm = NULL, *require = NULL;
const http_auth_scheme_t *auth_scheme;
buffer *algos = NULL;
@ -417,54 +362,125 @@ SETDEFAULTS_FUNC(mod_auth_set_defaults) {
dauth->fn->free((data_unset *)dauth);
return HANDLER_ERROR;
}
array_insert_unique(s->auth_require, (data_unset *)dauth);
array_insert_unique(auth_require, (data_unset *)dauth);
}
}
}
return HANDLER_GO_ON;
}
#define PATCH(x) \
p->conf.x = s->x;
static int mod_auth_patch_connection(server *srv, connection *con, plugin_data *p) {
size_t i, j;
plugin_config *s = p->config_storage[0];
PATCH(auth_backend);
PATCH(auth_require);
PATCH(auth_extern_authn);
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
if (!config_check_cond(con, i)) continue; /* condition not matched */
data_config *dc = (data_config *)srv->config_context->data[i];
s = p->config_storage[i];
/* merge config */
for (j = 0; j < dc->value->used; j++) {
data_unset *du = dc->value->data[j];
if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend"))) {
PATCH(auth_backend);
} else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.require"))) {
PATCH(auth_require);
} else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.extern-authn"))) {
PATCH(auth_extern_authn);
}
}
}
return 0;
static void mod_auth_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) {
switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
case 0: /* auth.backend */
if (cpv->vtype == T_CONFIG_LOCAL)
pconf->auth_backend = cpv->v.v;
break;
case 1: /* auth.require */
if (cpv->vtype == T_CONFIG_LOCAL)
pconf->auth_require = cpv->v.v;
break;
case 2: /* auth.extern-authn */
pconf->auth_extern_authn = cpv->v.u;
default:/* should not happen */
return;
}
}
static void mod_auth_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
do {
mod_auth_merge_config_cpv(pconf, cpv);
} while ((++cpv)->k_id != -1);
}
static void mod_auth_patch_config(connection * const con, plugin_data * const p) {
memcpy(&p->conf, &p->defaults, sizeof(plugin_config));
for (int i = 1, used = p->nconfig; i < used; ++i) {
if (config_check_cond(con, (uint32_t)p->cvlist[i].k_id))
mod_auth_merge_config(&p->conf, p->cvlist + p->cvlist[i].v.u2[0]);
}
}
SETDEFAULTS_FUNC(mod_auth_set_defaults) {
static const config_plugin_keys_t cpk[] = {
{ CONST_STR_LEN("auth.backend"),
T_CONFIG_STRING,
T_CONFIG_SCOPE_CONNECTION }
,{ CONST_STR_LEN("auth.require"),
T_CONFIG_ARRAY,
T_CONFIG_SCOPE_CONNECTION }
,{ CONST_STR_LEN("auth.extern-authn"),
T_CONFIG_BOOL,
T_CONFIG_SCOPE_CONNECTION }
,{ NULL, 0,
T_CONFIG_UNSET,
T_CONFIG_SCOPE_UNSET }
};
plugin_data * const p = p_d;
if (!config_plugin_values_init(srv, p, cpk, "mod_auth"))
return HANDLER_ERROR;
/* process and validate config directives
* (init i to 0 if global context; to 1 to skip empty global context) */
for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) {
config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
for (; -1 != cpv->k_id; ++cpv) {
switch (cpv->k_id) {
case 0: /* auth.backend */
if (!buffer_string_is_empty(cpv->v.b)) {
const http_auth_backend_t * const auth_backend =
http_auth_backend_get(cpv->v.b);
if (NULL == auth_backend) {
log_error(srv->errh, __FILE__, __LINE__,
"auth.backend not supported: %s", cpv->v.b->ptr);
return HANDLER_ERROR;
}
*(const http_auth_backend_t **)&cpv->v.v = auth_backend;
cpv->vtype = T_CONFIG_LOCAL;
}
break;
case 1: /* auth.require */
if (array_is_kvarray(cpv->v.a)) {
array * const a = array_init();
if (HANDLER_GO_ON !=
mod_auth_require_parse_array(srv, cpv->v.a, a)) {
array_free(a);
return HANDLER_ERROR;
}
cpv->v.a = a;
cpv->vtype = T_CONFIG_LOCAL;
}
else {
log_error(srv->errh, __FILE__, __LINE__,
"unexpected value for %s; expected "
"%s = ( \"urlpath\" => ( \"option\" => \"value\" ) )",
cpk[cpv->k_id].k, cpk[cpv->k_id].k);
return HANDLER_ERROR;
}
break;
case 2: /* auth.extern-authn */
break;
default:/* should not happen */
break;
}
}
}
/* initialize p->defaults from global config context */
if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
if (-1 != cpv->k_id)
mod_auth_merge_config(&p->defaults, cpv);
}
return HANDLER_GO_ON;
}
#undef PATCH
static handler_t mod_auth_uri_handler(server *srv, connection *con, void *p_d) {
plugin_data *p = p_d;
data_auth *dauth;
mod_auth_patch_connection(srv, con, p);
mod_auth_patch_config(con, p);
if (p->conf.auth_require == NULL) return HANDLER_GO_ON;

View File

@ -47,15 +47,15 @@
*/
typedef struct {
buffer *auth_plain_groupfile;
buffer *auth_plain_userfile;
buffer *auth_htdigest_userfile;
buffer *auth_htpasswd_userfile;
const buffer *auth_plain_groupfile;
const buffer *auth_plain_userfile;
const buffer *auth_htdigest_userfile;
const buffer *auth_htpasswd_userfile;
} plugin_config;
typedef struct {
PLUGIN_DATA;
plugin_config **config_storage;
plugin_config defaults;
plugin_config conf;
} plugin_data;
@ -91,110 +91,81 @@ INIT_FUNC(mod_authn_file_init) {
FREE_FUNC(mod_authn_file_free) {
plugin_data *p = p_d;
UNUSED(srv);
if (!p) return HANDLER_GO_ON;
if (p->config_storage) {
size_t i;
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
if (NULL == s) continue;
buffer_free(s->auth_plain_groupfile);
buffer_free(s->auth_plain_userfile);
buffer_free(s->auth_htdigest_userfile);
buffer_free(s->auth_htpasswd_userfile);
free(s);
}
free(p->config_storage);
}
free(p->cvlist);
free(p);
UNUSED(srv);
return HANDLER_GO_ON;
}
static void mod_authn_file_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) {
switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
case 0: /* auth.backend.plain.groupfile */
pconf->auth_plain_groupfile = cpv->v.b;
break;
case 1: /* auth.backend.plain.userfile */
pconf->auth_plain_userfile = cpv->v.b;
break;
case 2: /* auth.backend.htdigest.userfile */
pconf->auth_htdigest_userfile = cpv->v.b;
break;
case 3: /* auth.backend.htpasswd.userfile */
pconf->auth_htpasswd_userfile = cpv->v.b;
break;
default:/* should not happen */
return;
}
}
static void mod_authn_file_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
do {
mod_authn_file_merge_config_cpv(pconf, cpv);
} while ((++cpv)->k_id != -1);
}
static void mod_authn_file_patch_config(connection * const con, plugin_data * const p) {
memcpy(&p->conf, &p->defaults, sizeof(plugin_config));
for (int i = 1, used = p->nconfig; i < used; ++i) {
if (config_check_cond(con, (uint32_t)p->cvlist[i].k_id))
mod_authn_file_merge_config(&p->conf,
p->cvlist + p->cvlist[i].v.u2[0]);
}
}
SETDEFAULTS_FUNC(mod_authn_file_set_defaults) {
plugin_data *p = p_d;
size_t i;
config_values_t cv[] = {
{ "auth.backend.plain.groupfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
{ "auth.backend.plain.userfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
{ "auth.backend.htdigest.userfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
{ "auth.backend.htpasswd.userfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
static const config_plugin_keys_t cpk[] = {
{ CONST_STR_LEN("auth.backend.plain.groupfile"),
T_CONFIG_STRING,
T_CONFIG_SCOPE_CONNECTION }
,{ CONST_STR_LEN("auth.backend.plain.userfile"),
T_CONFIG_STRING,
T_CONFIG_SCOPE_CONNECTION }
,{ CONST_STR_LEN("auth.backend.htdigest.userfile"),
T_CONFIG_STRING,
T_CONFIG_SCOPE_CONNECTION }
,{ CONST_STR_LEN("auth.backend.htpasswd.userfile"),
T_CONFIG_STRING,
T_CONFIG_SCOPE_CONNECTION }
,{ NULL, 0,
T_CONFIG_UNSET,
T_CONFIG_SCOPE_UNSET }
};
p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *));
plugin_data * const p = p_d;
if (!config_plugin_values_init(srv, p, cpk, "mod_authn_file"))
return HANDLER_ERROR;
for (i = 0; i < srv->config_context->used; i++) {
data_config const* config = (data_config const*)srv->config_context->data[i];
plugin_config *s;
s = calloc(1, sizeof(plugin_config));
s->auth_plain_groupfile = buffer_init();
s->auth_plain_userfile = buffer_init();
s->auth_htdigest_userfile = buffer_init();
s->auth_htpasswd_userfile = buffer_init();
cv[0].destination = s->auth_plain_groupfile;
cv[1].destination = s->auth_plain_userfile;
cv[2].destination = s->auth_htdigest_userfile;
cv[3].destination = s->auth_htpasswd_userfile;
p->config_storage[i] = s;
if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
return HANDLER_ERROR;
}
/* initialize p->defaults from global config context */
if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
if (-1 != cpv->k_id)
mod_authn_file_merge_config(&p->defaults, cpv);
}
return HANDLER_GO_ON;
}
#define PATCH(x) \
p->conf.x = s->x;
static int mod_authn_file_patch_connection(server *srv, connection *con, plugin_data *p) {
size_t i, j;
plugin_config *s = p->config_storage[0];
PATCH(auth_plain_groupfile);
PATCH(auth_plain_userfile);
PATCH(auth_htdigest_userfile);
PATCH(auth_htpasswd_userfile);
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
if (!config_check_cond(con, i)) continue; /* condition not matched */
data_config *dc = (data_config *)srv->config_context->data[i];
s = p->config_storage[i];
/* merge config */
for (j = 0; j < dc->value->used; j++) {
data_unset *du = dc->value->data[j];
if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.plain.groupfile"))) {
PATCH(auth_plain_groupfile);
} else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.plain.userfile"))) {
PATCH(auth_plain_userfile);
} else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.htdigest.userfile"))) {
PATCH(auth_htdigest_userfile);
} else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.htpasswd.userfile"))) {
PATCH(auth_htpasswd_userfile);
}
}
}
return 0;
}
#undef PATCH
@ -314,7 +285,7 @@ static int mod_authn_file_htdigest_get(server *srv, connection *con, void *p_d,
const buffer *auth_fn;
FILE *fp;
mod_authn_file_patch_connection(srv, con, p);
mod_authn_file_patch_config(con, p);
auth_fn = p->conf.auth_htdigest_userfile;
if (buffer_string_is_empty(auth_fn)) return -1;
@ -425,7 +396,7 @@ static handler_t mod_authn_file_plain_digest(server *srv, connection *con, void
plugin_data *p = (plugin_data *)p_d;
buffer *password_buf = buffer_init();/* password-string from auth-backend */
int rc;
mod_authn_file_patch_connection(srv, con, p);
mod_authn_file_patch_config(con, p);
rc = mod_authn_file_htpasswd_get(srv, p->conf.auth_plain_userfile, ai->username, ai->ulen, password_buf);
if (0 == rc) {
/* generate password from plain-text */
@ -439,7 +410,7 @@ static handler_t mod_authn_file_plain_basic(server *srv, connection *con, void *
plugin_data *p = (plugin_data *)p_d;
buffer *password_buf = buffer_init();/* password-string from auth-backend */
int rc;
mod_authn_file_patch_connection(srv, con, p);
mod_authn_file_patch_config(con, p);
rc = mod_authn_file_htpasswd_get(srv, p->conf.auth_plain_userfile, CONST_BUF_LEN(username), password_buf);
if (0 == rc) {
rc = http_auth_const_time_memeq_pad(CONST_BUF_LEN(password_buf), pw, strlen(pw)) ? 0 : -1;
@ -663,7 +634,7 @@ static handler_t mod_authn_file_htpasswd_basic(server *srv, connection *con, voi
plugin_data *p = (plugin_data *)p_d;
buffer *password = buffer_init();/* password-string from auth-backend */
int rc;
mod_authn_file_patch_connection(srv, con, p);
mod_authn_file_patch_config(con, p);
rc = mod_authn_file_htpasswd_get(srv, p->conf.auth_htpasswd_userfile, CONST_BUF_LEN(username), password);
if (0 == rc) {
char sample[256];

View File

@ -30,7 +30,6 @@
#include "http_header.h"
#include "base.h"
#include "log.h"
#include "md5.h"
#include "base64.h"
#include <errno.h>
@ -39,14 +38,14 @@
#include <unistd.h>
typedef struct {
buffer *auth_gssapi_keytab;
buffer *auth_gssapi_principal;
unsigned short int auth_gssapi_store_creds;
const buffer *auth_gssapi_keytab;
const buffer *auth_gssapi_principal;
unsigned int auth_gssapi_store_creds;
} plugin_config;
typedef struct {
PLUGIN_DATA;
plugin_config **config_storage;
plugin_config defaults;
plugin_config conf;
} plugin_data;
@ -71,104 +70,78 @@ INIT_FUNC(mod_authn_gssapi_init) {
FREE_FUNC(mod_authn_gssapi_free) {
plugin_data *p = p_d;
UNUSED(srv);
if (!p) return HANDLER_GO_ON;
if (p->config_storage) {
size_t i;
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
if (NULL == s) continue;
buffer_free(s->auth_gssapi_keytab);
buffer_free(s->auth_gssapi_principal);
free(s);
}
free(p->config_storage);
}
free(p->cvlist);
free(p);
UNUSED(srv);
return HANDLER_GO_ON;
}
static void mod_authn_gssapi_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) {
switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
case 0: /* auth.backend.gssapi.keytab */
pconf->auth_gssapi_keytab = cpv->v.b;
break;
case 1: /* auth.backend.gssapi.principal */
pconf->auth_gssapi_principal = cpv->v.b;
break;
case 2: /* auth.backend.gssapi.store-creds */
pconf->auth_gssapi_store_creds = cpv->v.u;
break;
default:/* should not happen */
return;
}
}
static void mod_authn_gssapi_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
do {
mod_authn_gssapi_merge_config_cpv(pconf, cpv);
} while ((++cpv)->k_id != -1);
}
static void mod_authn_gssapi_patch_config(connection * const con, plugin_data * const p) {
memcpy(&p->conf, &p->defaults, sizeof(plugin_config));
for (int i = 1, used = p->nconfig; i < used; ++i) {
if (config_check_cond(con, (uint32_t)p->cvlist[i].k_id))
mod_authn_gssapi_merge_config(&p->conf,
p->cvlist + p->cvlist[i].v.u2[0]);
}
}
SETDEFAULTS_FUNC(mod_authn_gssapi_set_defaults) {
plugin_data *p = p_d;
size_t i;
config_values_t cv[] = {
{ "auth.backend.gssapi.keytab", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
{ "auth.backend.gssapi.principal", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
{ "auth.backend.gssapi.store-creds",NULL, T_CONFIG_BOOLEAN,T_CONFIG_SCOPE_CONNECTION },
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
static const config_plugin_keys_t cpk[] = {
{ CONST_STR_LEN("auth.backend.gssapi.keytab"),
T_CONFIG_STRING,
T_CONFIG_SCOPE_CONNECTION }
,{ CONST_STR_LEN("auth.backend.gssapi.principal"),
T_CONFIG_STRING,
T_CONFIG_SCOPE_CONNECTION }
,{ CONST_STR_LEN("auth.backend.gssapi.store-creds"),
T_CONFIG_BOOL,
T_CONFIG_SCOPE_CONNECTION }
,{ NULL, 0,
T_CONFIG_UNSET,
T_CONFIG_SCOPE_UNSET }
};
p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *));
plugin_data * const p = p_d;
if (!config_plugin_values_init(srv, p, cpk, "mod_authn_gssapi"))
return HANDLER_ERROR;
for (i = 0; i < srv->config_context->used; i++) {
data_config const* config = (data_config const*)srv->config_context->data[i];
plugin_config *s;
/* default enabled for backwards compatibility; disable in future */
p->defaults.auth_gssapi_store_creds = 1;
s = calloc(1, sizeof(plugin_config));
s->auth_gssapi_keytab = buffer_init();
s->auth_gssapi_principal = buffer_init();
cv[0].destination = s->auth_gssapi_keytab;
cv[1].destination = s->auth_gssapi_principal;
cv[2].destination = &s->auth_gssapi_store_creds;
/* default enabled for backwards compatibility; disable in future */
s->auth_gssapi_store_creds = 1;
p->config_storage[i] = s;
if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
return HANDLER_ERROR;
}
/* initialize p->defaults from global config context */
if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
if (-1 != cpv->k_id)
mod_authn_gssapi_merge_config(&p->defaults, cpv);
}
return HANDLER_GO_ON;
}
#define PATCH(x) \
p->conf.x = s->x;
static int mod_authn_gssapi_patch_connection(server *srv, connection *con, plugin_data *p)
{
size_t i, j;
plugin_config *s = p->config_storage[0];
PATCH(auth_gssapi_keytab);
PATCH(auth_gssapi_principal);
PATCH(auth_gssapi_store_creds);
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
if (!config_check_cond(con, i)) continue; /* condition not matched */
data_config *dc = (data_config *)srv->config_context->data[i];
s = p->config_storage[i];
/* merge config */
for (j = 0; j < dc->value->used; j++) {
data_unset *du = dc->value->data[j];
if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.gssapi.keytab"))) {
PATCH(auth_gssapi_keytab);
} else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.gssapi.principal"))) {
PATCH(auth_gssapi_principal);
} else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.gssapi.store-creds"))) {
PATCH(auth_gssapi_store_creds);
}
}
}
return 0;
}
#undef PATCH
static handler_t mod_authn_gssapi_send_400_bad_request (server *srv, connection *con)
{
UNUSED(srv);
@ -357,7 +330,7 @@ static handler_t mod_authn_gssapi_check_spnego(server *srv, connection *con, plu
return mod_authn_gssapi_send_400_bad_request(srv, con);
}
mod_authn_gssapi_patch_connection(srv, con, p);
mod_authn_gssapi_patch_config(con, p);
{
/* ??? Should code = krb5_kt_resolve(kcontext, p->conf.auth_gssapi_keytab->ptr, &keytab);
@ -661,7 +634,7 @@ static handler_t mod_authn_gssapi_basic(server *srv, connection *con, void *p_d,
return mod_authn_gssapi_send_401_unauthorized_basic(con);
}
mod_authn_gssapi_patch_connection(srv, con, p);
mod_authn_gssapi_patch_config(con, p);
code = krb5_init_context(&kcontext);
if (code) {
@ -669,6 +642,11 @@ static handler_t mod_authn_gssapi_basic(server *srv, connection *con, void *p_d,
return mod_authn_gssapi_send_401_unauthorized_basic(con); /*(well, should be 500)*/
}
if (buffer_string_is_empty(p->conf.auth_gssapi_keytab)) {
log_error_write(srv, __FILE__, __LINE__, "s", "auth.backend.gssapi.keytab not configured");
return mod_authn_gssapi_send_401_unauthorized_basic(con); /*(well, should be 500)*/
}
code = krb5_kt_resolve(kcontext, p->conf.auth_gssapi_keytab->ptr, &keytab);
if (code) {
log_error_write(srv, __FILE__, __LINE__, "sdb", "krb5_kt_resolve():", code, p->conf.auth_gssapi_keytab);

View File

@ -14,24 +14,32 @@
typedef struct {
LDAP *ldap;
server *srv;
const char *auth_ldap_hostname;
const char *auth_ldap_binddn;
const char *auth_ldap_bindpw;
const char *auth_ldap_cafile;
int auth_ldap_starttls;
} plugin_config_ldap;
buffer *auth_ldap_hostname;
buffer *auth_ldap_basedn;
buffer *auth_ldap_binddn;
buffer *auth_ldap_bindpw;
buffer *auth_ldap_filter;
buffer *auth_ldap_cafile;
buffer *auth_ldap_groupmember;
unsigned short auth_ldap_starttls;
unsigned short auth_ldap_allow_empty_pw;
typedef struct {
plugin_config_ldap *ldc;
const char *auth_ldap_basedn;
const buffer *auth_ldap_filter;
const buffer *auth_ldap_groupmember;
int auth_ldap_allow_empty_pw;
int auth_ldap_starttls;
const char *auth_ldap_binddn;
const char *auth_ldap_bindpw;
const char *auth_ldap_cafile;
} plugin_config;
typedef struct {
PLUGIN_DATA;
plugin_config **config_storage;
plugin_config conf, *anon_conf; /* this is only used as long as no handler_ctx is setup */
plugin_config defaults;
plugin_config conf;
buffer *ldap_filter;
buffer ldap_filter;
} plugin_data;
static handler_t mod_authn_ldap_basic(server *srv, connection *con, void *p_d, const http_auth_require_t *require, const buffer *username, const char *pw);
@ -40,7 +48,6 @@ INIT_FUNC(mod_authn_ldap_init) {
static http_auth_backend_t http_auth_backend_ldap =
{ "ldap", mod_authn_ldap_basic, NULL, NULL };
plugin_data *p = calloc(1, sizeof(*p));
p->ldap_filter = buffer_init();
/* register http_auth_backend_ldap */
http_auth_backend_ldap.p_d = p;
@ -49,41 +56,91 @@ INIT_FUNC(mod_authn_ldap_init) {
return p;
}
static void mod_authn_ldap_free_config(plugin_data *p) {
if (NULL == p->cvlist) return;
/* (init i to 0 if global context; to 1 to skip empty global context) */
for (int i = !p->cvlist[0].v.u2[1], used = p->nconfig; i < used; ++i) {
config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
for (; -1 != cpv->k_id; ++cpv) {
switch (cpv->k_id) {
case 0: /* auth.backend.ldap.hostname */
if (cpv->vtype == T_CONFIG_LOCAL) {
plugin_config_ldap *s = cpv->v.v;
if (NULL != s->ldap) ldap_unbind_ext_s(s->ldap, NULL, NULL);
free(s);
}
break;
default:
break;
}
}
}
}
FREE_FUNC(mod_authn_ldap_free) {
plugin_data *p = p_d;
UNUSED(srv);
if (!p) return HANDLER_GO_ON;
buffer_free(p->ldap_filter);
if (p->config_storage) {
size_t i;
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
if (NULL == s) continue;
buffer_free(s->auth_ldap_hostname);
buffer_free(s->auth_ldap_basedn);
buffer_free(s->auth_ldap_binddn);
buffer_free(s->auth_ldap_bindpw);
buffer_free(s->auth_ldap_filter);
buffer_free(s->auth_ldap_cafile);
buffer_free(s->auth_ldap_groupmember);
if (NULL != s->ldap) ldap_unbind_ext_s(s->ldap, NULL, NULL);
free(s);
}
free(p->config_storage);
}
mod_authn_ldap_free_config(p);
free(p->ldap_filter.ptr);
free(p->cvlist);
free(p);
UNUSED(srv);
return HANDLER_GO_ON;
}
static void mod_authn_ldap_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) {
switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
case 0: /* auth.backend.ldap.hostname */
if (cpv->vtype == T_CONFIG_LOCAL)
pconf->ldc = cpv->v.v;
break;
case 1: /* auth.backend.ldap.base-dn */
if (cpv->vtype == T_CONFIG_LOCAL)
pconf->auth_ldap_basedn = cpv->v.v;
break;
case 2: /* auth.backend.ldap.filter */
pconf->auth_ldap_filter = cpv->v.v;
break;
case 3: /* auth.backend.ldap.ca-file */
pconf->auth_ldap_cafile = cpv->v.v;
break;
case 4: /* auth.backend.ldap.starttls */
pconf->auth_ldap_starttls = (int)cpv->v.u;
break;
case 5: /* auth.backend.ldap.bind-dn */
pconf->auth_ldap_binddn = cpv->v.v;
break;
case 6: /* auth.backend.ldap.bind-pw */
pconf->auth_ldap_bindpw = cpv->v.v;
break;
case 7: /* auth.backend.ldap.allow-empty-pw */
pconf->auth_ldap_allow_empty_pw = (int)cpv->v.u;
break;
case 8: /* auth.backend.ldap.groupmember */
pconf->auth_ldap_groupmember = cpv->v.b;
break;
default:/* should not happen */
return;
}
}
static void mod_authn_ldap_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
do {
mod_authn_ldap_merge_config_cpv(pconf, cpv);
} while ((++cpv)->k_id != -1);
}
static void mod_authn_ldap_patch_config(connection * const con, plugin_data * const p) {
memcpy(&p->conf, &p->defaults, sizeof(plugin_config));
for (int i = 1, used = p->nconfig; i < used; ++i) {
if (config_check_cond(con, (uint32_t)p->cvlist[i].k_id))
mod_authn_ldap_merge_config(&p->conf,
p->cvlist + p->cvlist[i].v.u2[0]);
}
}
/*(copied from mod_vhostdb_ldap.c)*/
static void mod_authn_add_scheme (server *srv, buffer *host)
{
@ -118,133 +175,155 @@ static void mod_authn_add_scheme (server *srv, buffer *host)
}
SETDEFAULTS_FUNC(mod_authn_ldap_set_defaults) {
plugin_data *p = p_d;
size_t i;
config_values_t cv[] = {
{ "auth.backend.ldap.hostname", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
{ "auth.backend.ldap.base-dn", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
{ "auth.backend.ldap.filter", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
{ "auth.backend.ldap.ca-file", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
{ "auth.backend.ldap.starttls", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
{ "auth.backend.ldap.bind-dn", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
{ "auth.backend.ldap.bind-pw", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 6 */
{ "auth.backend.ldap.allow-empty-pw", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 7 */
{ "auth.backend.ldap.groupmember", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
static const config_plugin_keys_t cpk[] = {
{ CONST_STR_LEN("auth.backend.ldap.hostname"),
T_CONFIG_STRING,
T_CONFIG_SCOPE_CONNECTION }
,{ CONST_STR_LEN("auth.backend.ldap.base-dn"),
T_CONFIG_STRING,
T_CONFIG_SCOPE_CONNECTION }
,{ CONST_STR_LEN("auth.backend.ldap.filter"),
T_CONFIG_STRING,
T_CONFIG_SCOPE_CONNECTION }
,{ CONST_STR_LEN("auth.backend.ldap.ca-file"),
T_CONFIG_STRING,
T_CONFIG_SCOPE_CONNECTION }
,{ CONST_STR_LEN("auth.backend.ldap.starttls"),
T_CONFIG_BOOL,
T_CONFIG_SCOPE_CONNECTION }
,{ CONST_STR_LEN("auth.backend.ldap.bind-dn"),
T_CONFIG_STRING,
T_CONFIG_SCOPE_CONNECTION }
,{ CONST_STR_LEN("auth.backend.ldap.bind-pw"),
T_CONFIG_STRING,
T_CONFIG_SCOPE_CONNECTION }
,{ CONST_STR_LEN("auth.backend.ldap.allow-empty-pw"),
T_CONFIG_BOOL,
T_CONFIG_SCOPE_CONNECTION }
,{ CONST_STR_LEN("auth.backend.ldap.groupmember"),
T_CONFIG_STRING,
T_CONFIG_SCOPE_CONNECTION }
,{ NULL, 0,
T_CONFIG_UNSET,
T_CONFIG_SCOPE_UNSET }
};
p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *));
plugin_data * const p = p_d;
if (!config_plugin_values_init(srv, p, cpk, "mod_authn_ldap"))
return HANDLER_ERROR;
for (i = 0; i < srv->config_context->used; i++) {
data_config const* config = (data_config const*)srv->config_context->data[i];
plugin_config *s;
s = calloc(1, sizeof(plugin_config));
s->auth_ldap_hostname = buffer_init();
s->auth_ldap_basedn = buffer_init();
s->auth_ldap_binddn = buffer_init();
s->auth_ldap_bindpw = buffer_init();
s->auth_ldap_filter = buffer_init();
s->auth_ldap_cafile = buffer_init();
s->auth_ldap_groupmember = buffer_init_string("memberUid");
s->auth_ldap_starttls = 0;
s->ldap = NULL;
cv[0].destination = s->auth_ldap_hostname;
cv[1].destination = s->auth_ldap_basedn;
cv[2].destination = s->auth_ldap_filter;
cv[3].destination = s->auth_ldap_cafile;
cv[4].destination = &(s->auth_ldap_starttls);
cv[5].destination = s->auth_ldap_binddn;
cv[6].destination = s->auth_ldap_bindpw;
cv[7].destination = &(s->auth_ldap_allow_empty_pw);
cv[8].destination = s->auth_ldap_groupmember;
p->config_storage[i] = s;
if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
return HANDLER_ERROR;
}
if (!buffer_string_is_empty(s->auth_ldap_filter)) {
if (*s->auth_ldap_filter->ptr != ',') {
/*(translate '$' to '?' for consistency with other modules)*/
char *d = s->auth_ldap_filter->ptr;
for (; NULL != (d = strchr(d, '$')); ++d) *d = '?';
if (NULL == strchr(s->auth_ldap_filter->ptr, '?')) {
log_error_write(srv, __FILE__, __LINE__, "s", "ldap: auth.backend.ldap.filter is missing a replace-operator '?'");
return HANDLER_ERROR;
/* process and validate config directives
* (init i to 0 if global context; to 1 to skip empty global context) */
for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) {
config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
plugin_config_ldap *ldc = NULL;
char *binddn = NULL, *bindpw = NULL, *cafile = NULL;
int starttls = 0;
for (; -1 != cpv->k_id; ++cpv) {
switch (cpv->k_id) {
case 0: /* auth.backend.ldap.hostname */
if (!buffer_string_is_empty(cpv->v.b)) {
buffer *b;
*(const buffer **)&b = cpv->v.b;
mod_authn_add_scheme(srv, b);
ldc = malloc(sizeof(plugin_config_ldap));
force_assert(ldc);
ldc->srv = srv;
ldc->auth_ldap_hostname = b->ptr;
cpv->v.v = ldc;
}
else {
cpv->v.v = NULL;
}
cpv->vtype = T_CONFIG_LOCAL;
break;
case 1: /* auth.backend.ldap.base-dn */
cpv->vtype = T_CONFIG_LOCAL;
cpv->v.v = !buffer_string_is_empty(cpv->v.b)
? cpv->v.b->ptr
: NULL;
break;
case 2: /* auth.backend.ldap.filter */
if (!buffer_string_is_empty(cpv->v.b)) {
buffer *b;
*(const buffer **)&b = cpv->v.b;
if (*b->ptr != ',') {
/*(translate $ to ? for consistency w/ other modules)*/
char *d = b->ptr;
for (; NULL != (d = strchr(d, '$')); ++d) *d = '?';
if (NULL == strchr(b->ptr, '?')) {
log_error(srv->errh, __FILE__, __LINE__,
"ldap: %s is missing a replace-operator '?'",
cpk[cpv->k_id].k);
return HANDLER_ERROR;
}
}
cpv->v.v = b;
}
else {
cpv->v.v = NULL;
}
cpv->vtype = T_CONFIG_LOCAL;
break;
case 3: /* auth.backend.ldap.ca-file */
cafile = !buffer_string_is_empty(cpv->v.b)
? cpv->v.b->ptr
: NULL;
cpv->vtype = T_CONFIG_LOCAL;
cpv->v.v = cafile;
break;
case 4: /* auth.backend.ldap.starttls */
starttls = (int)cpv->v.u;
break;
case 5: /* auth.backend.ldap.bind-dn */
binddn = !buffer_string_is_empty(cpv->v.b)
? cpv->v.b->ptr
: NULL;
cpv->vtype = T_CONFIG_LOCAL;
cpv->v.v = binddn;
break;
case 6: /* auth.backend.ldap.bind-pw */
cpv->vtype = T_CONFIG_LOCAL;
cpv->v.v = bindpw = cpv->v.b->ptr;
break;
case 7: /* auth.backend.ldap.allow-empty-pw */
case 8: /* auth.backend.ldap.groupmember */
break;
default:/* should not happen */
break;
}
}
mod_authn_add_scheme(srv, s->auth_ldap_hostname);
if (ldc) {
ldc->auth_ldap_binddn = binddn;
ldc->auth_ldap_bindpw = bindpw;
ldc->auth_ldap_cafile = cafile;
ldc->auth_ldap_starttls = starttls;
}
}
static const struct { const char *ptr; uint32_t used; uint32_t size; }
memberUid = { "memberUid", sizeof("memberUid"), 0 };
*(const buffer **)&p->defaults.auth_ldap_groupmember =
(const buffer *)&memberUid;
/* initialize p->defaults from global config context */
if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
if (-1 != cpv->k_id)
mod_authn_ldap_merge_config(&p->defaults, cpv);
}
return HANDLER_GO_ON;
}
#define PATCH(x) \
p->conf.x = s->x;
static int mod_authn_ldap_patch_connection(server *srv, connection *con, plugin_data *p) {
size_t i, j;
plugin_config *s = p->config_storage[0];
PATCH(auth_ldap_hostname);
PATCH(auth_ldap_basedn);
PATCH(auth_ldap_binddn);
PATCH(auth_ldap_bindpw);
PATCH(auth_ldap_filter);
PATCH(auth_ldap_cafile);
PATCH(auth_ldap_starttls);
PATCH(auth_ldap_allow_empty_pw);
PATCH(auth_ldap_groupmember);
p->anon_conf = s;
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
if (!config_check_cond(con, i)) continue; /* condition not matched */
data_config *dc = (data_config *)srv->config_context->data[i];
s = p->config_storage[i];
/* merge config */
for (j = 0; j < dc->value->used; j++) {
data_unset *du = dc->value->data[j];
if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.ldap.hostname"))) {
PATCH(auth_ldap_hostname);
p->anon_conf = s;
} else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.ldap.base-dn"))) {
PATCH(auth_ldap_basedn);
} else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.ldap.filter"))) {
PATCH(auth_ldap_filter);
} else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.ldap.ca-file"))) {
PATCH(auth_ldap_cafile);
} else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.ldap.starttls"))) {
PATCH(auth_ldap_starttls);
} else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.ldap.bind-dn"))) {
PATCH(auth_ldap_binddn);
} else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.ldap.bind-pw"))) {
PATCH(auth_ldap_bindpw);
} else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.ldap.allow-empty-pw"))) {
PATCH(auth_ldap_allow_empty_pw);
} else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.ldap.groupmember"))) {
PATCH(auth_ldap_groupmember);
}
}
}
return 0;
}
#undef PATCH
__attribute_cold__
static void mod_authn_ldap_err(server *srv, const char *file, unsigned long line, const char *fn, int err)
{
log_error_write(srv,file,line,"sSss","ldap:",fn,":",ldap_err2string(err));
}
__attribute_cold__
static void mod_authn_ldap_opt_err(server *srv, const char *file, unsigned long line, const char *fn, LDAP *ld)
{
int err;
@ -383,13 +462,13 @@ static void mod_authn_append_ldap_filter_escape(buffer * const filter, const buf
}
}
static LDAP * mod_authn_ldap_host_init(server *srv, plugin_config *s) {
static LDAP * mod_authn_ldap_host_init(server *srv, plugin_config_ldap *s) {
LDAP *ld;
int ret;
if (buffer_string_is_empty(s->auth_ldap_hostname)) return NULL;
if (NULL == s->auth_ldap_hostname) return NULL;
if (LDAP_SUCCESS != ldap_initialize(&ld, s->auth_ldap_hostname->ptr)) {
if (LDAP_SUCCESS != ldap_initialize(&ld, s->auth_ldap_hostname)) {
log_error_write(srv, __FILE__, __LINE__, "sss", "ldap:",
"ldap_initialize():", strerror(errno));
return NULL;
@ -409,9 +488,9 @@ static LDAP * mod_authn_ldap_host_init(server *srv, plugin_config *s) {
if (s->auth_ldap_starttls) {
/* if no CA file is given, it is ok, as we will use encryption
* if the server requires a CAfile it will tell us */
if (!buffer_string_is_empty(s->auth_ldap_cafile)) {
if (s->auth_ldap_cafile) {
ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE,
s->auth_ldap_cafile->ptr);
s->auth_ldap_cafile);
if (LDAP_OPT_SUCCESS != ret) {
mod_authn_ldap_err(srv, __FILE__, __LINE__,
"ldap_set_option(LDAP_OPT_X_TLS_CACERTFILE)",
@ -455,18 +534,18 @@ static int mod_authn_ldap_bind(server *srv, LDAP *ld, const char *dn, const char
}
static int mod_authn_ldap_rebind_proc (LDAP *ld, LDAP_CONST char *url, ber_tag_t ldap_request, ber_int_t msgid, void *params) {
plugin_config *s = (plugin_config *)params;
const plugin_config_ldap *s = (const plugin_config_ldap *)params;
UNUSED(url);
UNUSED(ldap_request);
UNUSED(msgid);
return !buffer_string_is_empty(s->auth_ldap_binddn)
return s->auth_ldap_binddn
? mod_authn_ldap_bind(s->srv, ld,
s->auth_ldap_binddn->ptr,
s->auth_ldap_bindpw->ptr)
s->auth_ldap_binddn,
s->auth_ldap_bindpw)
: mod_authn_ldap_bind(s->srv, ld, NULL, NULL);
}
static LDAPMessage * mod_authn_ldap_search(server *srv, plugin_config *s, char *base, char *filter) {
static LDAPMessage * mod_authn_ldap_search(server *srv, plugin_config_ldap *s, const char *base, const char *filter) {
LDAPMessage *lm = NULL;
char *attrs[] = { LDAP_NO_ATTRS, NULL };
int ret;
@ -521,7 +600,7 @@ static LDAPMessage * mod_authn_ldap_search(server *srv, plugin_config *s, char *
return lm;
}
static char * mod_authn_ldap_get_dn(server *srv, plugin_config *s, char *base, char *filter) {
static char * mod_authn_ldap_get_dn(server *srv, plugin_config_ldap *s, const char *base, const char *filter) {
LDAP *ld;
LDAPMessage *lm, *first;
char *dn;
@ -576,11 +655,12 @@ static handler_t mod_authn_ldap_memberOf(server *srv, plugin_config *s, const ht
}
buffer_append_string_len(filter, CONST_STR_LEN(")"));
plugin_config_ldap * const ldc = s->ldc;
for (size_t i = 0; i < groups->used; ++i) {
char *base = groups->data[i]->key.ptr;
LDAPMessage *lm = mod_authn_ldap_search(srv, s, base, filter->ptr);
const char *base = groups->data[i]->key.ptr;
LDAPMessage *lm = mod_authn_ldap_search(srv, ldc, base, filter->ptr);
if (NULL != lm) {
int count = ldap_count_entries(s->ldap, lm);
int count = ldap_count_entries(ldc->ldap, lm);
ldap_msgfree(lm);
if (count > 0) {
rc = HANDLER_GO_ON;
@ -597,88 +677,101 @@ static handler_t mod_authn_ldap_basic(server *srv, connection *con, void *p_d, c
plugin_data *p = (plugin_data *)p_d;
LDAP *ld;
char *dn;
buffer *template;
handler_t rc;
mod_authn_ldap_patch_connection(srv, con, p);
p->anon_conf->srv = srv;
p->conf.srv = srv;
mod_authn_ldap_patch_config(con, p);
if (pw[0] == '\0' && !p->conf.auth_ldap_allow_empty_pw)
return HANDLER_ERROR;
template = p->conf.auth_ldap_filter;
if (buffer_string_is_empty(template)) {
const buffer * const template = p->conf.auth_ldap_filter;
if (NULL == template)
return HANDLER_ERROR;
}
/* build filter to get DN for uid = username */
buffer_clear(p->ldap_filter);
buffer * const ldap_filter = &p->ldap_filter;
buffer_clear(ldap_filter);
if (*template->ptr == ',') {
/* special-case filter template beginning with ',' to be explicit DN */
buffer_append_string_len(p->ldap_filter, CONST_STR_LEN("uid="));
mod_authn_append_ldap_dn_escape(p->ldap_filter, username);
buffer_append_string_buffer(p->ldap_filter, template);
dn = p->ldap_filter->ptr;
} else {
for (char *b = template->ptr, *d; *b; b = d+1) {
buffer_append_string_len(ldap_filter, CONST_STR_LEN("uid="));
mod_authn_append_ldap_dn_escape(ldap_filter, username);
buffer_append_string_buffer(ldap_filter, template);
dn = ldap_filter->ptr;
}
else {
for (const char *b = template->ptr, *d; *b; b = d+1) {
if (NULL != (d = strchr(b, '?'))) {
buffer_append_string_len(p->ldap_filter, b, (size_t)(d - b));
mod_authn_append_ldap_filter_escape(p->ldap_filter, username);
} else {
buffer_append_string_len(ldap_filter, b, (size_t)(d - b));
mod_authn_append_ldap_filter_escape(ldap_filter, username);
}
else {
d = template->ptr + buffer_string_length(template);
buffer_append_string_len(p->ldap_filter, b, (size_t)(d - b));
buffer_append_string_len(ldap_filter, b, (size_t)(d - b));
break;
}
}
/* ldap_search for DN (synchronous; blocking) */
dn = mod_authn_ldap_get_dn(srv, p->anon_conf,
p->conf.auth_ldap_basedn->ptr,
p->ldap_filter->ptr);
if (NULL == dn) {
return HANDLER_ERROR;
}
dn = mod_authn_ldap_get_dn(srv, p->conf.ldc,
p->conf.auth_ldap_basedn, ldap_filter->ptr);
if (NULL == dn) return HANDLER_ERROR;
}
/* auth against LDAP server (synchronous; blocking) */
/*(Check ldc here rather than further up to preserve historical behavior
* where p->conf.ldc above (was p->anon_conf above) is set of directives in
* same context as auth_ldap_hostname. Preference: admin intentions are
* clearer if directives are always together in a set in same context)*/
ld = mod_authn_ldap_host_init(srv, &p->conf);
if (NULL == ld) {
if (dn != p->ldap_filter->ptr) ldap_memfree(dn);
return HANDLER_ERROR;
plugin_config_ldap * const ldc_base = p->conf.ldc;
plugin_config_ldap ldc_custom;