summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGlenn Strauss <gstrauss@gluelogic.com>2019-11-06 19:37:11 -0500
committerGlenn Strauss <gstrauss@gluelogic.com>2020-07-08 18:08:51 -0400
commit8e713130b390c687ee01f333986ece7e4ea2b2ba (patch)
treef6c2c9c5ba858e201745261c2349ecedf5fa2e25
parent12b11f30421defc4ea61d2200241cf6bb976e10d (diff)
downloadlighttpd-git-8e713130b390c687ee01f333986ece7e4ea2b2ba.tar.gz
[mod_auth*] use config_plugin_values_init()
-rw-r--r--src/mod_auth.c266
-rw-r--r--src/mod_authn_file.c163
-rw-r--r--src/mod_authn_gssapi.c152
-rw-r--r--src/mod_authn_ldap.c515
-rw-r--r--src/mod_authn_mysql.c465
-rw-r--r--src/mod_authn_pam.c125
-rw-r--r--src/mod_authn_sasl.c239
7 files changed, 994 insertions, 931 deletions
diff --git a/src/mod_auth.c b/src/mod_auth.c
index 93ccdf11..b1490a5a 100644
--- a/src/mod_auth.c
+++ b/src/mod_auth.c
@@ -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;
}
-FREE_FUNC(mod_auth_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;
-
- array_free(s->auth_require);
- buffer_free(s->auth_backend_conf);
+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(s);
- }
- free(p->config_storage);
- }
+FREE_FUNC(mod_auth_free) {
+ plugin_data *p = p_d;
+ if (!p) return HANDLER_GO_ON;
- free(p);
+ mod_auth_free_config(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);
- }
- }
- }
+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;
+ }
+}
- return 0;
+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;
diff --git a/src/mod_authn_file.c b/src/mod_authn_file.c
index 8cd5d0d4..d7c149a2 100644
--- a/src/mod_authn_file.c
+++ b/src/mod_authn_file.c
@@ -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(p->cvlist);
+ free(p);
+ UNUSED(srv);
+ return HANDLER_GO_ON;
+}
- free(s);
- }
- free(p->config_storage);
+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;
}
+}
- free(p);
+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);
+}
- return HANDLER_GO_ON;
+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 *));
-
- 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();
+ plugin_data * const p = p_d;
+ if (!config_plugin_values_init(srv, p, cpk, "mod_authn_file"))
+ return HANDLER_ERROR;
- 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];
diff --git a/src/mod_authn_gssapi.c b/src/mod_authn_gssapi.c
index 23154d98..bc8f6d81 100644
--- a/src/mod_authn_gssapi.c
+++ b/src/mod_authn_gssapi.c
@@ -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(p->cvlist);
+ free(p);
+ UNUSED(srv);
+ return HANDLER_GO_ON;
+}
- free(s);
- }
- free(p->config_storage);
+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;
}
+}
- free(p);
+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);
+}
- return HANDLER_GO_ON;
+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 *));
-
- 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_gssapi_keytab = buffer_init();
- s->auth_gssapi_principal = buffer_init();
+ plugin_data * const p = p_d;
+ if (!config_plugin_values_init(srv, p, cpk, "mod_authn_gssapi"))
+ return HANDLER_ERROR;
- 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;
+ /* default enabled for backwards compatibility; disable in future */
+ p->defaults.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);
diff --git a/src/mod_authn_ldap.c b/src/mod_authn_ldap.c
index ee2c5503..0c7699e6 100644
--- a/src/mod_authn_ldap.c
+++ b/src/mod_authn_ldap.c
@@ -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,39 +56,89 @@ 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;
+ mod_authn_ldap_free_config(p);
+ free(p->ldap_filter.ptr);
- 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);
+ free(p->cvlist);
+ free(p);
+ UNUSED(srv);
+ return HANDLER_GO_ON;
+}
- if (NULL != s->ldap) ldap_unbind_ext_s(s->ldap, NULL, NULL);
- free(s);
- }
- free(p->config_storage);
+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;
}
+}
- free(p);
+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);
+}
- return HANDLER_GO_ON;
+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)*/
@@ -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 *));
-
- 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;
- }
+ plugin_data * const p = p_d;
+ if (!config_plugin_values_init(srv, p, cpk, "mod_authn_ldap"))
+ 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;
+ }
}
- return HANDLER_GO_ON;
-}
+ 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;
-#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);
- }
- }
+ /* 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 0;
+ return HANDLER_GO_ON;
}
-#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) */
-
- ld = mod_authn_ldap_host_init(srv, &p->conf);
- if (NULL == ld) {
- if (dn != p->ldap_filter->ptr) ldap_memfree(dn);
- return HANDLER_ERROR;
+ /*(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)*/
+
+ plugin_config_ldap * const ldc_base = p->conf.ldc;
+ plugin_config_ldap ldc_custom;
+
+ if ( p->conf.ldc->auth_ldap_starttls != p->conf.auth_ldap_starttls
+ || p->conf.ldc->auth_ldap_binddn != p->conf.auth_ldap_binddn
+ || p->conf.ldc->auth_ldap_bindpw != p->conf.auth_ldap_bindpw
+ || p->conf.ldc->auth_ldap_cafile != p->conf.auth_ldap_cafile ) {
+ ldc_custom.ldap = NULL;
+ ldc_custom.srv = srv;
+ ldc_custom.auth_ldap_hostname = ldc_base->auth_ldap_hostname;
+ ldc_custom.auth_ldap_starttls = p->conf.auth_ldap_starttls;
+ ldc_custom.auth_ldap_binddn = p->conf.auth_ldap_binddn;
+ ldc_custom.auth_ldap_bindpw = p->conf.auth_ldap_bindpw;
+ ldc_custom.auth_ldap_cafile = p->conf.auth_ldap_cafile;
+ p->conf.ldc = &ldc_custom;
}
- /* Disable referral tracking. Target user should be in provided scope */
- {
+ handler_t rc = HANDLER_ERROR;
+ do {
+ /* auth against LDAP server (synchronous; blocking) */
+
+ ld = mod_authn_ldap_host_init(srv, p->conf.ldc);
+ if (NULL == ld)
+ break;
+
+ /* Disable referral tracking; target user should be in provided scope */
int ret = ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
if (LDAP_OPT_SUCCESS != ret) {
mod_authn_ldap_err(srv,__FILE__,__LINE__,"ldap_set_option()",ret);
- ldap_destroy(ld);
- if (dn != p->ldap_filter->ptr) ldap_memfree(dn);
- return HANDLER_ERROR;
+ break;
}
- }
- if (LDAP_SUCCESS != mod_authn_ldap_bind(srv, ld, dn, pw)) {
- ldap_destroy(ld);
- if (dn != p->ldap_filter->ptr) ldap_memfree(dn);
- return HANDLER_ERROR;
- }
+ if (LDAP_SUCCESS != mod_authn_ldap_bind(srv, ld, dn, pw))
+ break;
- ldap_unbind_ext_s(ld, NULL, NULL); /* disconnect */
+ ldap_unbind_ext_s(ld, NULL, NULL); /* disconnect */
+ ld = NULL;
- if (http_auth_match_rules(require, username->ptr, NULL, NULL)) {
- rc = HANDLER_GO_ON; /* access granted */
- } else {
- rc = HANDLER_ERROR;
- if (require->group->used) {
- /*(must not re-use p->ldap_filter, since it might be used for dn)*/
- rc = mod_authn_ldap_memberOf(srv, &p->conf, require, username, dn);
+ if (http_auth_match_rules(require, username->ptr, NULL, NULL)) {
+ rc = HANDLER_GO_ON; /* access granted */
}
- }
+ else if (require->group->used) {
+ /*(must not re-use ldap_filter, since it might be used for dn)*/
+ rc = mod_authn_ldap_memberOf(srv,&p->conf,require,username,dn);
+ }
+ } while (0);
- if (dn != p->ldap_filter->ptr) ldap_memfree(dn);
+ if (NULL != ld) ldap_destroy(ld);
+ if (ldc_base != p->conf.ldc && NULL != p->conf.ldc->ldap)
+ ldap_unbind_ext_s(p->conf.ldc->ldap, NULL, NULL);
+ if (dn != ldap_filter->ptr) ldap_memfree(dn);
return rc;
}
diff --git a/src/mod_authn_mysql.c b/src/mod_authn_mysql.c
index dc11a706..1195aad8 100644
--- a/src/mod_authn_mysql.c
+++ b/src/mod_authn_mysql.c
@@ -39,99 +39,105 @@
#endif
typedef struct {
- MYSQL *mysql_conn;
- buffer *mysql_conn_host;
- buffer *mysql_conn_user;
- buffer *mysql_conn_pass;
- buffer *mysql_conn_db;
- int mysql_conn_port;
int auth_mysql_port;
- buffer *auth_mysql_host;
- buffer *auth_mysql_user;
- buffer *auth_mysql_pass;
- buffer *auth_mysql_db;
- buffer *auth_mysql_socket;
- buffer *auth_mysql_users_table;
- buffer *auth_mysql_col_user;
- buffer *auth_mysql_col_pass;
- buffer *auth_mysql_col_realm;
+ const char *auth_mysql_host;
+ const char *auth_mysql_user;
+ const char *auth_mysql_pass;
+ const char *auth_mysql_db;
+ const char *auth_mysql_socket;
+ const char *auth_mysql_users_table;
+ const char *auth_mysql_col_user;
+ const char *auth_mysql_col_pass;
+ const char *auth_mysql_col_realm;
} plugin_config;
typedef struct {
PLUGIN_DATA;
- plugin_config **config_storage;
+ plugin_config defaults;
plugin_config conf;
+
+ MYSQL *mysql_conn;
+ const char *mysql_conn_host;
+ const char *mysql_conn_user;
+ const char *mysql_conn_pass;
+ const char *mysql_conn_db;
+ int mysql_conn_port;
} plugin_data;
-static void mod_authn_mysql_sock_close(plugin_config *pconf) {
- if (NULL != pconf->mysql_conn) {
- mysql_close(pconf->mysql_conn);
- pconf->mysql_conn = NULL;
+static void mod_authn_mysql_sock_close(plugin_data *p) {
+ if (NULL != p->mysql_conn) {
+ mysql_close(p->mysql_conn);
+ p->mysql_conn = NULL;
}
}
-static MYSQL * mod_authn_mysql_sock_connect(server *srv, plugin_config *pconf) {
- if (NULL != pconf->mysql_conn) {
+static MYSQL * mod_authn_mysql_sock_connect(server *srv, plugin_data *p) {
+ plugin_config * const pconf = &p->conf;
+ if (NULL != p->mysql_conn) {
/* reuse open db connection if same ptrs to host user pass db port */
- if ( pconf->mysql_conn_host == pconf->auth_mysql_host
- && pconf->mysql_conn_user == pconf->auth_mysql_user
- && pconf->mysql_conn_pass == pconf->auth_mysql_pass
- && pconf->mysql_conn_db == pconf->auth_mysql_db
- && pconf->mysql_conn_port == pconf->auth_mysql_port) {
- return pconf->mysql_conn;
+ if ( p->mysql_conn_host == pconf->auth_mysql_host
+ && p->mysql_conn_user == pconf->auth_mysql_user
+ && p->mysql_conn_pass == pconf->auth_mysql_pass
+ && p->mysql_conn_db == pconf->auth_mysql_db
+ && p->mysql_conn_port == pconf->auth_mysql_port) {
+ return p->mysql_conn;
}
- mod_authn_mysql_sock_close(pconf);
+ mod_authn_mysql_sock_close(p);
}
/* !! mysql_init() is not thread safe !! (see MySQL doc) */
- pconf->mysql_conn = mysql_init(NULL);
- if (mysql_real_connect(pconf->mysql_conn,
- pconf->auth_mysql_host->ptr,
- pconf->auth_mysql_user->ptr,
- pconf->auth_mysql_pass->ptr,
- pconf->auth_mysql_db->ptr,
+ p->mysql_conn = mysql_init(NULL);
+ if (mysql_real_connect(p->mysql_conn,
+ pconf->auth_mysql_host,
+ pconf->auth_mysql_user,
+ pconf->auth_mysql_pass,
+ pconf->auth_mysql_db,
pconf->auth_mysql_port,
- !buffer_string_is_empty(pconf->auth_mysql_socket)
- ? pconf->auth_mysql_socket->ptr
+ (pconf->auth_mysql_socket && *pconf->auth_mysql_socket)
+ ? pconf->auth_mysql_socket
: NULL,
CLIENT_IGNORE_SIGPIPE)) {
- /* (copy ptrs to config data (has lifetime until server shutdown)) */
- pconf->mysql_conn_host = pconf->auth_mysql_host;
- pconf->mysql_conn_user = pconf->auth_mysql_user;
- pconf->mysql_conn_pass = pconf->auth_mysql_pass;
- pconf->mysql_conn_db = pconf->auth_mysql_db;
- pconf->mysql_conn_port = pconf->auth_mysql_port;
- return pconf->mysql_conn;
+ /* (copy ptrs to plugin data (has lifetime until server shutdown)) */
+ p->mysql_conn_host = pconf->auth_mysql_host;
+ p->mysql_conn_user = pconf->auth_mysql_user;
+ p->mysql_conn_pass = pconf->auth_mysql_pass;
+ p->mysql_conn_db = pconf->auth_mysql_db;
+ p->mysql_conn_port = pconf->auth_mysql_port;
+ return p->mysql_conn;
}
else {
- /*(note: any of these params might be buffers with b->ptr == NULL)*/
- log_error_write(srv, __FILE__, __LINE__, "sbsb"/*sb*/"sbss",
- "opening connection to mysql:", pconf->auth_mysql_host,
- "user:", pconf->auth_mysql_user,
- /*"pass:", pconf->auth_mysql_pass,*//*(omit from logs)*/
- "db:", pconf->auth_mysql_db,
- "failed:", mysql_error(pconf->mysql_conn));
- mod_authn_mysql_sock_close(pconf);
+ /*(note: any of these params might be NULL)*/
+ log_error_write(srv, __FILE__, __LINE__, "ssss"/*ss*/"ssss",
+ "opening connection to mysql:",
+ pconf->auth_mysql_host ? pconf->auth_mysql_host : NULL,
+ "user:",
+ pconf->auth_mysql_user ? pconf->auth_mysql_user : NULL,
+ /*"pass:",*//*(omit pass from logs)*/
+ /*pconf->auth_mysql_pass ? pconf->auth_mysql_pass : NULL,*/
+ "db:",
+ pconf->auth_mysql_db ? pconf->auth_mysql_db : NULL,
+ "failed:", mysql_error(p->mysql_conn));
+ mod_authn_mysql_sock_close(p);
return NULL;
}
}
-static MYSQL * mod_authn_mysql_sock_acquire(server *srv, plugin_config *pconf) {
- return mod_authn_mysql_sock_connect(srv, pconf);
+static MYSQL * mod_authn_mysql_sock_acquire(server *srv, plugin_data *p) {
+ return mod_authn_mysql_sock_connect(srv, p);
}
-static void mod_authn_mysql_sock_release(server *srv, plugin_config *pconf) {
+static void mod_authn_mysql_sock_release(server *srv, plugin_data *p) {
UNUSED(srv);
- UNUSED(pconf);
+ UNUSED(p);
/*(empty; leave db connection open)*/
/* Note: mod_authn_mysql_result() calls mod_authn_mysql_sock_error()
* on error, so take that into account if making changes here.
- * Must check if (NULL == pconf->mysql_conn) */
+ * Must check if (NULL == p->mysql_conn) */
}
-static void mod_authn_mysql_sock_error(server *srv, plugin_config *pconf) {
+static void mod_authn_mysql_sock_error(server *srv, plugin_data *p) {
UNUSED(srv);
- mod_authn_mysql_sock_close(pconf);
+ mod_authn_mysql_sock_close(p);
}
static handler_t mod_authn_mysql_basic(server *srv, connection *con, void *p_d, const http_auth_require_t *require, const buffer *username, const char *pw);
@@ -151,185 +157,151 @@ INIT_FUNC(mod_authn_mysql_init) {
FREE_FUNC(mod_authn_mysql_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];
+ mod_authn_mysql_sock_close(p);
- if (NULL == s) continue;
-
- buffer_free(s->auth_mysql_host);
- buffer_free(s->auth_mysql_user);
- buffer_free(s->auth_mysql_pass);
- buffer_free(s->auth_mysql_db);
- buffer_free(s->auth_mysql_socket);
- buffer_free(s->auth_mysql_users_table);
- buffer_free(s->auth_mysql_col_user);
- buffer_free(s->auth_mysql_col_pass);
- buffer_free(s->auth_mysql_col_realm);
-
- if (s->mysql_conn) mod_authn_mysql_sock_close(s);
+ free(p->cvlist);
+ free(p);
+ UNUSED(srv);
+ return HANDLER_GO_ON;
+}
- free(s);
- }
- free(p->config_storage);
+static void mod_authn_mysql_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.mysql.host */
+ pconf->auth_mysql_host = cpv->v.b->ptr;
+ break;
+ case 1: /* auth.backend.mysql.user */
+ pconf->auth_mysql_user = cpv->v.b->ptr;
+ break;
+ case 2: /* auth.backend.mysql.pass */
+ pconf->auth_mysql_pass = cpv->v.b->ptr;
+ break;
+ case 3: /* auth.backend.mysql.db */
+ pconf->auth_mysql_db = cpv->v.b->ptr;
+ break;
+ case 4: /* auth.backend.mysql.port */
+ pconf->auth_mysql_port = (int)cpv->v.shrt;
+ break;
+ case 5: /* auth.backend.mysql.socket */
+ pconf->auth_mysql_socket = cpv->v.b->ptr;
+ break;
+ case 6: /* auth.backend.mysql.users_table */
+ pconf->auth_mysql_users_table = cpv->v.b->ptr;
+ break;
+ case 7: /* auth.backend.mysql.col_user */
+ pconf->auth_mysql_col_user = cpv->v.b->ptr;
+ break;
+ case 8: /* auth.backend.mysql.col_pass */
+ pconf->auth_mysql_col_pass = cpv->v.b->ptr;
+ break;
+ case 9: /* auth.backend.mysql.col_realm */
+ pconf->auth_mysql_col_realm = cpv->v.b->ptr;
+ break;
+ default:/* should not happen */
+ return;
}
- mod_authn_mysql_sock_close(&p->conf);
+}
- free(p);
+static void mod_authn_mysql_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
+ do {
+ mod_authn_mysql_merge_config_cpv(pconf, cpv);
+ } while ((++cpv)->k_id != -1);
+}
- return HANDLER_GO_ON;
+static void mod_authn_mysql_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_mysql_merge_config(&p->conf,
+ p->cvlist + p->cvlist[i].v.u2[0]);
+ }
}
SETDEFAULTS_FUNC(mod_authn_mysql_set_defaults) {
- plugin_data *p = p_d;
- size_t i;
- config_values_t cv[] = {
- { "auth.backend.mysql.host", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { "auth.backend.mysql.user", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { "auth.backend.mysql.pass", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { "auth.backend.mysql.db", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { "auth.backend.mysql.port", NULL, T_CONFIG_INT, T_CONFIG_SCOPE_CONNECTION },
- { "auth.backend.mysql.socket", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { "auth.backend.mysql.users_table", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { "auth.backend.mysql.col_user", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { "auth.backend.mysql.col_pass", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { "auth.backend.mysql.col_realm", NULL, T_CONFIG_STRING, 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.mysql.host"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("auth.backend.mysql.user"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("auth.backend.mysql.pass"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("auth.backend.mysql.db"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("auth.backend.mysql.port"),
+ T_CONFIG_SHORT,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("auth.backend.mysql.socket"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("auth.backend.mysql.users_table"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("auth.backend.mysql.col_user"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("auth.backend.mysql.col_pass"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("auth.backend.mysql.col_realm"),
+ 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 *));
-
- 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->mysql_conn = NULL;
- s->auth_mysql_host = buffer_init();
- s->auth_mysql_user = buffer_init();
- s->auth_mysql_pass = buffer_init();
- s->auth_mysql_db = buffer_init();
- s->auth_mysql_socket = buffer_init();
- s->auth_mysql_users_table = buffer_init();
- s->auth_mysql_col_user = buffer_init();
- s->auth_mysql_col_pass = buffer_init();
- s->auth_mysql_col_realm = buffer_init();
-
- cv[0].destination = s->auth_mysql_host;
- cv[1].destination = s->auth_mysql_user;
- cv[2].destination = s->auth_mysql_pass;
- cv[3].destination = s->auth_mysql_db;
- cv[4].destination = &s->auth_mysql_port;
- cv[5].destination = s->auth_mysql_socket;
- cv[6].destination = s->auth_mysql_users_table;
- cv[7].destination = s->auth_mysql_col_user;
- cv[8].destination = s->auth_mysql_col_pass;
- cv[9].destination = s->auth_mysql_col_realm;
-
- 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_is_empty(s->auth_mysql_col_user)
- && buffer_string_is_empty(s->auth_mysql_col_user)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "auth.backend.mysql.col_user must not be blank");
- return HANDLER_ERROR;
- }
- if (!buffer_is_empty(s->auth_mysql_col_pass)
- && buffer_string_is_empty(s->auth_mysql_col_pass)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "auth.backend.mysql.col_pass must not be blank");
- return HANDLER_ERROR;
- }
- if (!buffer_is_empty(s->auth_mysql_col_realm)
- && buffer_string_is_empty(s->auth_mysql_col_realm)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "auth.backend.mysql.col_realm must not be blank");
- return HANDLER_ERROR;
- }
- }
+ plugin_data * const p = p_d;
+ if (!config_plugin_values_init(srv, p, cpk, "mod_authn_mysql"))
+ return HANDLER_ERROR;
- if (p->config_storage[0]) { /*(always true)*/
- plugin_config *s = p->config_storage[0];
- if (buffer_is_empty(s->auth_mysql_col_user)) {
- buffer_copy_string_len(s->auth_mysql_col_user, CONST_STR_LEN("user"));
- }
- if (buffer_is_empty(s->auth_mysql_col_pass)) {
- buffer_copy_string_len(s->auth_mysql_col_pass, CONST_STR_LEN("password"));
- }
- if (buffer_is_empty(s->auth_mysql_col_realm)) {
- buffer_copy_string_len(s->auth_mysql_col_realm, CONST_STR_LEN("realm"));
+ /* 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.mysql.host */
+ case 1: /* auth.backend.mysql.user */
+ case 2: /* auth.backend.mysql.pass */
+ case 3: /* auth.backend.mysql.db */
+ case 4: /* auth.backend.mysql.port */
+ case 5: /* auth.backend.mysql.socket */
+ case 6: /* auth.backend.mysql.users_table */
+ break;
+ case 7: /* auth.backend.mysql.col_user */
+ case 8: /* auth.backend.mysql.col_pass */
+ case 9: /* auth.backend.mysql.col_realm */
+ if (buffer_string_is_empty(cpv->v.b)) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "%s must not be blank", cpk[cpv->k_id].k);
+ return HANDLER_ERROR;
+ }
+ break;
+ default:/* should not happen */
+ break;
+ }
}
}
- return HANDLER_GO_ON;
-}
+ p->defaults.auth_mysql_col_user = "user";
+ p->defaults.auth_mysql_col_pass = "password";
+ p->defaults.auth_mysql_col_realm = "realm";
-#define PATCH(x) \
- p->conf.x = s->x;
-static int mod_authn_mysql_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i, j;
- plugin_config *s = p->config_storage[0];
-
- PATCH(auth_mysql_host);
- PATCH(auth_mysql_user);
- PATCH(auth_mysql_pass);
- PATCH(auth_mysql_db);
- PATCH(auth_mysql_port);
- PATCH(auth_mysql_socket);
- PATCH(auth_mysql_users_table);
- PATCH(auth_mysql_col_user);
- PATCH(auth_mysql_col_pass);
- PATCH(auth_mysql_col_realm);
-
- /* 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.mysql.host"))) {
- PATCH(auth_mysql_host);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.mysql.user"))) {
- PATCH(auth_mysql_user);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.mysql.pass"))) {
- PATCH(auth_mysql_pass);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.mysql.db"))) {
- PATCH(auth_mysql_db);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.mysql.port"))) {
- PATCH(auth_mysql_port);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.mysql.socket"))) {
- PATCH(auth_mysql_socket);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.mysql.users_table"))) {
- PATCH(auth_mysql_users_table);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.mysql.col_user"))) {
- PATCH(auth_mysql_col_user);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.mysql.col_pass"))) {
- PATCH(auth_mysql_col_pass);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.mysql.col_realm"))) {
- PATCH(auth_mysql_col_realm);
- }
- }
+ /* 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_mysql_merge_config(&p->defaults, cpv);
}
- return 0;
+ return HANDLER_GO_ON;
}
-#undef PATCH
static int mod_authn_mysql_password_cmp(const char *userpw, unsigned long userpwlen, const char *reqpw) {
#if defined(HAVE_CRYPT_R) || defined(HAVE_CRYPT)
@@ -387,7 +359,7 @@ static int mod_authn_mysql_password_cmp(const char *userpw, unsigned long userpw
}
static int mod_authn_mysql_result(server *srv, plugin_data *p, http_auth_info_t *ai, const char *pw) {
- MYSQL_RES *result = mysql_store_result(p->conf.mysql_conn);
+ MYSQL_RES *result = mysql_store_result(p->mysql_conn);
int rc = -1;
my_ulonglong num_rows;
@@ -395,9 +367,9 @@ static int mod_authn_mysql_result(server *srv, plugin_data *p, http_auth_info_t
/*(future: might log mysql_error() string)*/
#if 0
log_error_write(srv, __FILE__, __LINE__, "ss", "mysql_store_result:",
- mysql_error(p->conf.mysql_conn));
+ mysql_error(p->mysql_conn));
#endif
- mod_authn_mysql_sock_error(srv, &p->conf);
+ mod_authn_mysql_sock_error(srv, p);
return -1;
}
@@ -434,9 +406,9 @@ static handler_t mod_authn_mysql_query(server *srv, connection *con, void *p_d,
plugin_data *p = (plugin_data *)p_d;
int rc = -1;
- mod_authn_mysql_patch_connection(srv, con, p);
+ mod_authn_mysql_patch_config(con, p);
- if (buffer_string_is_empty(p->conf.auth_mysql_users_table)) {
+ if (NULL == p->conf.auth_mysql_users_table) {
/*(auth.backend.mysql.host, auth.backend.mysql.db might be NULL; do not log)*/
log_error_write(srv, __FILE__, __LINE__, "sb",
"auth config missing auth.backend.mysql.users_table for uri:",
@@ -453,35 +425,35 @@ static handler_t mod_authn_mysql_query(server *srv, connection *con, void *p_d,
if (ai->rlen > sizeof(urealm)/2-1)
return HANDLER_ERROR;
- if (!mod_authn_mysql_sock_acquire(srv, &p->conf)) {
+ if (!mod_authn_mysql_sock_acquire(srv, p)) {
return HANDLER_ERROR;
}
#if 0
- mrc = mysql_real_escape_string_quote(p->conf.mysql_conn, uname,
+ mrc = mysql_real_escape_string_quote(p->mysql_conn, uname,
ai->username, ai->ulen, '\'');
if ((unsigned long)~0 == mrc) break;
- mrc = mysql_real_escape_string_quote(p->conf.mysql_conn, urealm,
+ mrc = mysql_real_escape_string_quote(p->mysql_conn, urealm,
ai->realm, ai->rlen, '\'');
if ((unsigned long)~0 == mrc) break;
#else
- mrc = mysql_real_escape_string(p->conf.mysql_conn, uname,
+ mrc = mysql_real_escape_string(p->mysql_conn, uname,
ai->username, ai->ulen);
if ((unsigned long)~0 == mrc) break;
- mrc = mysql_real_escape_string(p->conf.mysql_conn, urealm,
+ mrc = mysql_real_escape_string(p->mysql_conn, urealm,
ai->realm, ai->rlen);
if ((unsigned long)~0 == mrc) break;
#endif
rc = snprintf(q, sizeof(q),
"SELECT %s FROM %s WHERE %s='%s' AND %s='%s'",
- p->conf.auth_mysql_col_pass->ptr,
- p->conf.auth_mysql_users_table->ptr,
- p->conf.auth_mysql_col_user->ptr,
+ p->conf.auth_mysql_col_pass,
+ p->conf.auth_mysql_users_table,
+ p->conf.auth_mysql_col_user,
uname,
- p->conf.auth_mysql_col_realm->ptr,
+ p->conf.auth_mysql_col_realm,
urealm);
if (rc >= (int)sizeof(q)) {
@@ -490,23 +462,26 @@ static handler_t mod_authn_mysql_query(server *srv, connection *con, void *p_d,
}
/* for now we stay synchronous */
- if (0 != mysql_query(p->conf.mysql_conn, q)) {
+ if (0 != mysql_query(p->mysql_conn, q)) {
/* reconnect to db and retry once if query error occurs */
- mod_authn_mysql_sock_error(srv, &p->conf);
- if (!mod_authn_mysql_sock_acquire(srv, &p->conf)) {
+ mod_authn_mysql_sock_error(srv, p);
+ if (!mod_authn_mysql_sock_acquire(srv, p)) {
rc = -1;
break;
}
- if (0 != mysql_query(p->conf.mysql_conn, q)) {
+ if (0 != mysql_query(p->mysql_conn, q)) {
/*(note: any of these params might be bufs w/ b->ptr == NULL)*/
- log_error_write(srv, __FILE__, __LINE__, "sbsb"/*sb*/"sbssss",
- "mysql_query host:", p->conf.auth_mysql_host,
- "user:", p->conf.auth_mysql_user,
- /*(omit pass from logs)*/
- /*"pass:", p->conf.auth_mysql_pass,*/
- "db:", p->conf.auth_mysql_db,
- "query:", q,
- "failed:", mysql_error(p->conf.mysql_conn));
+ log_error_write(srv, __FILE__, __LINE__, "ssss"/*ss*/"ssssss",
+ "mysql_query host:",
+ p->conf.auth_mysql_host ? p->conf.auth_mysql_host : NULL,
+ "user:",
+ p->conf.auth_mysql_user ? p->conf.auth_mysql_user : NULL,
+ /*"pass:",*//*(omit pass from logs)*/
+ /*p->conf.auth_mysql_pass ? p->conf.auth_mysql_pass : NULL,*/
+ "db:",
+ p->conf.auth_mysql_db ? p->conf.auth_mysql_db : NULL,
+ "query:", q,
+ "failed:", mysql_error(p->mysql_conn));
rc = -1;
break;
}
@@ -516,7 +491,7 @@ static handler_t mod_authn_mysql_query(server *srv, connection *con, void *p_d,
} while (0);
- mod_authn_mysql_sock_release(srv, &p->conf);
+ mod_authn_mysql_sock_release(srv, p);
return (0 == rc) ? HANDLER_GO_ON : HANDLER_ERROR;
}
diff --git a/src/mod_authn_pam.c b/src/mod_authn_pam.c
index c9676b93..61925e80 100644
--- a/src/mod_authn_pam.c
+++ b/src/mod_authn_pam.c
@@ -22,13 +22,12 @@
#include <string.h>
typedef struct {
- array *opts;
const char *service;
} plugin_config;
typedef struct {
PLUGIN_DATA;
- plugin_config **config_storage;
+ plugin_config defaults;
plugin_config conf;
} plugin_data;
@@ -50,81 +49,83 @@ FREE_FUNC(mod_authn_pam_free) {
plugin_data *p = p_d;
if (!p) return HANDLER_GO_ON;
- if (p->config_storage) {
- for (size_t i = 0; i < srv->config_context->used; ++i) {
- plugin_config *s = p->config_storage[i];
- if (NULL == s) continue;
- array_free(s->opts);
- free(s);
- }
- free(p->config_storage);
- }
+ free(p->cvlist);
free(p);
UNUSED(srv);
return HANDLER_GO_ON;
}
-SETDEFAULTS_FUNC(mod_authn_pam_set_defaults) {
- plugin_data *p = p_d;
- config_values_t cv[] = {
- { "auth.backend.pam.opts", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *));
-
- for (size_t i = 0; i < srv->config_context->used; ++i) {
- data_config const *config = (data_config const*)srv->config_context->data[i];
- const data_string *ds;
- plugin_config *s = calloc(1, sizeof(plugin_config));
- s->opts = array_init();
-
- cv[0].destination = s->opts;
-
- 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 (0 == s->opts->used) continue;
-
- ds = (const data_string *)
- array_get_element_klen(s->opts, CONST_STR_LEN("service"));
- s->service = (NULL != ds) ? ds->value.ptr : "http";
+static void mod_authn_pam_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.pam.opts */
+ if (cpv->vtype == T_CONFIG_LOCAL)
+ pconf->service = cpv->v.v;
+ break;
+ default:/* should not happen */
+ return;
}
-
- if (p->config_storage[0]->service == NULL)
- p->config_storage[0]->service = "http";
-
- return HANDLER_GO_ON;
}
-#define PATCH(x) \
- p->conf.x = s->x;
-static int mod_authn_pam_patch_connection(server *srv, connection *con, plugin_data *p) {
- plugin_config *s = p->config_storage[0];
- PATCH(service);
+static void mod_authn_pam_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
+ do {
+ mod_authn_pam_merge_config_cpv(pconf, cpv);
+ } while ((++cpv)->k_id != -1);
+}
- /* skip the first, the global context */
- for (size_t i = 1; i < srv->config_context->used; ++i) {
- if (!config_check_cond(con, i)) continue; /* condition not matched */
+static void mod_authn_pam_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_pam_merge_config(&p->conf,
+ p->cvlist + p->cvlist[i].v.u2[0]);
+ }
+}
- data_config *dc = (data_config *)srv->config_context->data[i];
+SETDEFAULTS_FUNC(mod_authn_pam_set_defaults) {
+ static const config_plugin_keys_t cpk[] = {
+ { CONST_STR_LEN("auth.backend.pam.opts"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ NULL, 0,
+ T_CONFIG_UNSET,
+ T_CONFIG_SCOPE_UNSET }
+ };
- /* merge config */
- s = p->config_storage[i];
- for (size_t 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.pam.opts"))) {
- PATCH(service);
+ plugin_data * const p = p_d;
+ if (!config_plugin_values_init(srv, p, cpk, "mod_authn_pam"))
+ 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.pam.opts */
+ if (cpv->v.a->used) {
+ const data_string *ds = (const data_string *)
+ array_get_element_klen(cpv->v.a,CONST_STR_LEN("service"));
+ cpv->v.v = (NULL != ds) ? ds->value.ptr : "http";
+ cpv->vtype = T_CONFIG_LOCAL;
+ }
+ break;
+ default:/* should not happen */
+ break;
}
}
}
- return 0;
+ p->defaults.service = "http";
+
+ /* 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_pam_merge_config(&p->defaults, cpv);
+ }
+
+ return HANDLER_GO_ON;
}
-#undef PATCH
static int mod_authn_pam_fn_conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr) {
const char * const pw = (char *)appdata_ptr;
@@ -149,7 +150,7 @@ static handler_t mod_authn_pam_query(server *srv, connection *con, void *p_d, co
UNUSED(realm);
*(const char **)&conv.appdata_ptr = pw; /*(cast away const)*/
- mod_authn_pam_patch_connection(srv, con, p);
+ mod_authn_pam_patch_config(con, p);
rc = pam_start(p->conf.service, username->ptr, &conv, &pamh);
if (PAM_SUCCESS != rc
diff --git a/src/mod_authn_sasl.c b/src/mod_authn_sasl.c
index 83d06408..deafde30 100644
--- a/src/mod_authn_sasl.c
+++ b/src/mod_authn_sasl.c
@@ -19,12 +19,10 @@
#include "plugin.h"
#include <sys/utsname.h>
-#include <errno.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
- array *opts;
const char *service;
const char *fqdn;
const buffer *pwcheck_method;
@@ -33,9 +31,9 @@ typedef struct {
typedef struct {
PLUGIN_DATA;
- plugin_config **config_storage;
+ plugin_config defaults;
plugin_config conf;
- buffer *fqdn;
+
int initonce;
} plugin_data;
@@ -53,133 +51,164 @@ INIT_FUNC(mod_authn_sasl_init) {
return p;
}
+static void mod_authn_sasl_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) {
+ switch (cpv->k_id) {
+ case 0: /* auth.backend.sasl.opts */
+ if (cpv->vtype == T_CONFIG_LOCAL) free(cpv->v.v);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
FREE_FUNC(mod_authn_sasl_free) {
plugin_data *p = p_d;
if (!p) return HANDLER_GO_ON;
if (p->initonce) sasl_done();
- if (p->config_storage) {
- for (size_t i = 0; i < srv->config_context->used; ++i) {
- plugin_config *s = p->config_storage[i];
- if (NULL == s) continue;
- array_free(s->opts);
- free(s);
- }
- free(p->config_storage);
- }
- buffer_free(p->fqdn);
+ mod_authn_sasl_free_config(p);
+
+ free(p->cvlist);
free(p);
UNUSED(srv);
return HANDLER_GO_ON;
}
-SETDEFAULTS_FUNC(mod_authn_sasl_set_defaults) {
- plugin_data *p = p_d;
- size_t i;
- config_values_t cv[] = {
- { "auth.backend.sasl.opts", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
- { 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];
- const data_string *ds;
- plugin_config *s = calloc(1, sizeof(plugin_config));
- s->opts = array_init();
-
- cv[0].destination = s->opts;
+static void mod_authn_sasl_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.sasl.opts */
+ if (cpv->vtype == T_CONFIG_LOCAL)
+ memcpy(pconf, cpv->v.v, sizeof(plugin_config));
+ break;
+ default:/* should not happen */
+ return;
+ }
+}
- p->config_storage[i] = s;
+static void mod_authn_sasl_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
+ do {
+ mod_authn_sasl_merge_config_cpv(pconf, cpv);
+ } while ((++cpv)->k_id != -1);
+}
- if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
- return HANDLER_ERROR;
- }
+static void mod_authn_sasl_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_sasl_merge_config(&p->conf,
+ p->cvlist + p->cvlist[i].v.u2[0]);
+ }
+}
- if (0 == s->opts->used) continue;
-
- ds = (const data_string *)
- array_get_element_klen(s->opts, CONST_STR_LEN("service"));
- s->service = (NULL != ds) ? ds->value.ptr : "http";
-
- ds = (const data_string *)
- array_get_element_klen(s->opts, CONST_STR_LEN("fqdn"));
- if (NULL != ds) s->fqdn = ds->value.ptr;
- if (NULL == s->fqdn) {
- if (NULL == p->fqdn) {
- struct utsname uts;
- if (0 != uname(&uts)) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
- "uname():", strerror(errno));
- return HANDLER_ERROR;
- }
- p->fqdn = buffer_init_string(uts.nodename);
+static plugin_config * mod_authn_sasl_parse_opts(server *srv, const array * const opts) {
+ const data_string *ds;
+ const char *service = NULL;
+ const char *fqdn = NULL;
+ const buffer *pwcheck_method = NULL;
+ const buffer *sasldb_path = NULL;
+
+ ds = (const data_string *)
+ array_get_element_klen(opts, CONST_STR_LEN("service"));
+ service = (NULL != ds) ? ds->value.ptr : "http";
+
+ ds = (const data_string *)
+ array_get_element_klen(opts, CONST_STR_LEN("fqdn"));
+ if (NULL != ds) fqdn = ds->value.ptr;
+ if (NULL == fqdn) {
+ static struct utsname uts;
+ if (uts.nodename[0] == '\0') {
+ if (0 != uname(&uts)) {
+ log_perror(srv->errh, __FILE__, __LINE__, "uname()");
+ return NULL;
}
- s->fqdn = p->fqdn->ptr;
}
+ fqdn = uts.nodename;
+ }
- ds = (const data_string *)
- array_get_element_klen(s->opts, CONST_STR_LEN("pwcheck_method"));
- if (NULL != ds) {
- s->pwcheck_method = &ds->value;
- if (!buffer_is_equal_string(&ds->value, CONST_STR_LEN("saslauthd"))
- && !buffer_is_equal_string(&ds->value, CONST_STR_LEN("auxprop"))
- && !buffer_is_equal_string(&ds->value, CONST_STR_LEN("sasldb"))){
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "sasl pwcheck_method must be one of saslauthd, "
- "sasldb, or auxprop, not:", &ds->value);
- return HANDLER_ERROR;
- }
- if (buffer_is_equal_string(&ds->value, CONST_STR_LEN("sasldb"))) {
- /* Cyrus libsasl2 expects "auxprop" instead of "sasldb"
- * (mod_authn_sasl_cb_getopt auxprop_plugin returns "sasldb") */
- buffer *pwcheck_method =
- array_get_buf_ptr(s->opts, CONST_STR_LEN("pwcheck_method"));
- buffer_copy_string_len(pwcheck_method, CONST_STR_LEN("auxprop"));
- }
+ ds = (const data_string *)
+ array_get_element_klen(opts, CONST_STR_LEN("pwcheck_method"));
+ if (NULL != ds) {
+ pwcheck_method = &ds->value;
+ if (!buffer_is_equal_string(&ds->value, CONST_STR_LEN("saslauthd"))
+ && !buffer_is_equal_string(&ds->value, CONST_STR_LEN("auxprop"))
+ && !buffer_is_equal_string(&ds->value, CONST_STR_LEN("sasldb"))){
+ log_error(srv->errh, __FILE__, __LINE__,
+ "sasl pwcheck_method must be one of saslauthd, "
+ "sasldb, or auxprop, not: %s", ds->value.ptr);
+ return NULL;
+ }
+ if (buffer_is_equal_string(&ds->value, CONST_STR_LEN("sasldb"))) {
+ /* Cyrus libsasl2 expects "auxprop" instead of "sasldb"
+ * (mod_authn_sasl_cb_getopt auxprop_plugin returns "sasldb") */
+ buffer *b;
+ *(const buffer **)&b = &ds->value;
+ buffer_copy_string_len(b, CONST_STR_LEN("auxprop"));
}
-
- ds = (const data_string *)
- array_get_element_klen(s->opts, CONST_STR_LEN("sasldb_path"));
- if (NULL != ds) s->sasldb_path = &ds->value;
}
- return HANDLER_GO_ON;
+ ds = (const data_string *)
+ array_get_element_klen(opts, CONST_STR_LEN("sasldb_path"));
+ if (NULL != ds) sasldb_path = &ds->value;
+
+ plugin_config *pconf = malloc(sizeof(plugin_config));
+ force_assert(pconf);
+ pconf->service = service;
+ pconf->fqdn = fqdn;
+ pconf->pwcheck_method = pwcheck_method;
+ pconf->sasldb_path = sasldb_path;
+ return pconf;
}
-#define PATCH(x) \
- p->conf.x = s->x;
-static int mod_authn_sasl_patch_connection(server *srv, connection *con, plugin_data *p) {
- plugin_config *s = p->config_storage[0];
- PATCH(service);
- PATCH(fqdn);
- PATCH(pwcheck_method);
- PATCH(sasldb_path);
-
- /* skip the first, the global context */
- for (size_t 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];
-
- /* merge config */
- s = p->config_storage[i];
- for (size_t 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.sasl.opts"))) {
- PATCH(service);
- PATCH(fqdn);
- PATCH(pwcheck_method);
- PATCH(sasldb_path);
+SETDEFAULTS_FUNC(mod_authn_sasl_set_defaults) {
+ static const config_plugin_keys_t cpk[] = {
+ { CONST_STR_LEN("auth.backend.sasl.opts"),
+ T_CONFIG_ARRAY,
+ 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_authn_sasl"))
+ 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.sasl.opts */
+ if (cpv->v.a->used) {
+ cpv->v.v = mod_authn_sasl_parse_opts(srv, cpv->v.a);
+ if (NULL == cpv->v.v) return HANDLER_ERROR;
+ cpv->vtype = T_CONFIG_LOCAL;
+ }
+ break;
+ default:/* should not happen */
+ break;
}
}
}
- return 0;
+ /* 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_sasl_merge_config(&p->defaults, cpv);
+ }
+
+ return HANDLER_GO_ON;
}
-#undef PATCH
static int mod_authn_sasl_cb_getopt(void *p_d, const char *plugin_name, const char *opt, const char **res, unsigned *len) {
plugin_data *p = (plugin_data *)p_d;
@@ -243,7 +272,7 @@ static handler_t mod_authn_sasl_query(server *srv, connection *con, void *p_d, c
};
int rc;
- mod_authn_sasl_patch_connection(srv, con, p);
+ mod_authn_sasl_patch_config(con, p);
if (!p->initonce) {
/* must be done once, but after fork() if multiple lighttpd workers */