dovecot-2.1: ldap: Support using the same LDAP attribute in mult...
dovecot at dovecot.org
dovecot at dovecot.org
Thu Feb 2 01:07:49 EET 2012
details: http://hg.dovecot.org/dovecot-2.1/rev/6734aa225b4f
changeset: 14049:6734aa225b4f
user: Timo Sirainen <tss at iki.fi>
date: Thu Feb 02 01:07:37 2012 +0200
description:
ldap: Support using the same LDAP attribute in multiple fields.
diffstat:
src/auth/db-ldap.c | 386 +++++++++++++++++++++++++++---------------------
src/auth/db-ldap.h | 17 +-
src/auth/passdb-ldap.c | 12 +-
src/auth/userdb-ldap.c | 20 +-
4 files changed, 241 insertions(+), 194 deletions(-)
diffs (truncated from 641 to 300 lines):
diff -r fb659472b2a2 -r 6734aa225b4f src/auth/db-ldap.c
--- a/src/auth/db-ldap.c Wed Feb 01 23:33:51 2012 +0200
+++ b/src/auth/db-ldap.c Thu Feb 02 01:07:37 2012 +0200
@@ -49,19 +49,23 @@
# define LDAP_OPT_SUCCESS LDAP_SUCCESS
#endif
+struct db_ldap_value {
+ const char **values;
+ bool used;
+};
+
struct db_ldap_result_iterate_context {
- struct ldap_connection *conn;
- LDAPMessage *entry;
+ pool_t pool;
+
struct auth_request *auth_request;
+ const ARRAY_TYPE(ldap_field) *attr_map;
+ unsigned int attr_idx;
- struct hash_table *attr_map;
+ /* ldap_attr_name => struct db_ldap_value */
+ struct hash_table *ldap_attrs;
struct var_expand_table *var_table;
- char *attr, **vals;
- const char *name, *template, *val_1_arr[2];
- const char *const *static_attrs;
- BerElement *ber;
-
+ const char *val_1_arr[2];
string_t *var, *debug;
};
@@ -587,8 +591,9 @@
(struct ldap_request_search *)request;
auth_request_log_error(request->auth_request, "ldap",
- "ldap_search(%s) failed: %s",
- srequest->filter, ldap_err2string(ret));
+ "ldap_search(base=%s filter=%s) failed: %s",
+ srequest->base, srequest->filter,
+ ldap_err2string(ret));
res = NULL;
}
@@ -973,19 +978,18 @@
}
void db_ldap_set_attrs(struct ldap_connection *conn, const char *attrlist,
- char ***attr_names_r, struct hash_table *attr_map,
+ char ***attr_names_r, ARRAY_TYPE(ldap_field) *attr_map,
const char *skip_attr)
{
+ struct ldap_field *field;
const char *const *attr, *attr_data, *p;
- string_t *static_data;
- char *name, *value;
+ char *ldap_attr, *name, *templ;
unsigned int i, j, size;
if (*attrlist == '\0')
return;
- attr = t_strsplit(attrlist, ",");
- static_data = t_str_new(128);
+ attr = t_strsplit_spaces(attrlist, ",");
/* @UNSAFE */
for (size = 0; attr[size] != NULL; size++) ;
@@ -998,32 +1002,29 @@
p = strchr(attr_data, '=');
if (p == NULL)
- name = value = p_strdup(conn->pool, attr_data);
- else if (p != attr_data) {
- name = p_strdup_until(conn->pool, attr_data, p);
- value = p_strdup(conn->pool, p + 1);
- } else {
- /* =<static key>=<static value> */
- if (str_len(static_data) > 0)
- str_append_c(static_data, ',');
- str_append(static_data, p + 1);
- continue;
+ ldap_attr = name = p_strdup(conn->pool, attr_data);
+ else {
+ ldap_attr = p_strdup_until(conn->pool, attr_data, p);
+ name = p_strdup(conn->pool, p + 1);
}
- if (*name != '\0' &&
- (skip_attr == NULL || strcmp(skip_attr, value) != 0)) {
- if (hash_table_lookup(attr_map, name) != NULL) {
- i_fatal("ldap: LDAP attribute '%s' used multiple times. This is currently unsupported.",
- name);
- }
- hash_table_insert(attr_map, name, value);
- (*attr_names_r)[j++] = name;
+ templ = strchr(name, '=');
+ if (templ == NULL)
+ templ = "";
+ else
+ *templ++ = '\0';
+
+ if (*name == '\0')
+ i_error("ldap: Invalid attrs entry: %s", attr_data);
+ else if (skip_attr == NULL || strcmp(skip_attr, name) != 0) {
+ field = array_append_space(attr_map);
+ field->name = name;
+ field->value = templ;
+ field->ldap_attr_name = ldap_attr;
+ if (*ldap_attr != '\0')
+ (*attr_names_r)[j++] = ldap_attr;
}
}
- if (str_len(static_data) > 0) {
- hash_table_insert(attr_map, "",
- p_strdup(conn->pool, str_c(static_data)));
- }
}
struct var_expand_table *
@@ -1071,171 +1072,214 @@
return str_c(ret);
}
+static bool
+ldap_field_hide_password(struct db_ldap_result_iterate_context *ctx,
+ const char *attr)
+{
+ const struct ldap_field *field;
+
+ if (ctx->auth_request->set->debug_passwords)
+ return FALSE;
+
+ array_foreach(ctx->attr_map, field) {
+ if (strcmp(field->ldap_attr_name, attr) == 0) {
+ if (strcmp(field->name, "password") == 0 ||
+ strcmp(field->name, "password_noscheme") == 0)
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static void
+get_ldap_fields(struct db_ldap_result_iterate_context *ctx,
+ struct ldap_connection *conn, LDAPMessage *entry)
+{
+ struct db_ldap_value *ldap_value;
+ char *attr, **vals;
+ unsigned int i, count;
+ BerElement *ber;
+
+ attr = ldap_first_attribute(conn->ld, entry, &ber);
+ while (attr != NULL) {
+ vals = ldap_get_values(conn->ld, entry, attr);
+
+ ldap_value = p_new(ctx->pool, struct db_ldap_value, 1);
+ if (vals == NULL) {
+ ldap_value->values = p_new(ctx->pool, const char *, 1);
+ count = 0;
+ } else {
+ for (count = 0; vals[count] != NULL; count++) ;
+ }
+
+ ldap_value->values = p_new(ctx->pool, const char *, count + 1);
+ for (i = 0; i < count; i++)
+ ldap_value->values[i] = p_strdup(ctx->pool, vals[i]);
+
+ if (ctx->debug != NULL) {
+ str_printfa(ctx->debug, " %s=", attr);
+ if (count == 0)
+ str_append(ctx->debug, "<no values>");
+ else if (ldap_field_hide_password(ctx, attr))
+ str_append(ctx->debug, PASSWORD_HIDDEN_STR);
+ else {
+ str_append(ctx->debug, ldap_value->values[0]);
+ for (i = 1; i < count; i++) {
+ str_printfa(ctx->debug, ",%s",
+ ldap_value->values[0]);
+ }
+ }
+ }
+ hash_table_insert(ctx->ldap_attrs,
+ p_strdup(ctx->pool, attr), ldap_value);
+
+ ldap_value_free(vals);
+ ldap_memfree(attr);
+ attr = ldap_next_attribute(conn->ld, entry, ber);
+ }
+ ber_free(ber, 0);
+}
+
struct db_ldap_result_iterate_context *
db_ldap_result_iterate_init(struct ldap_connection *conn, LDAPMessage *entry,
struct auth_request *auth_request,
- struct hash_table *attr_map)
+ const ARRAY_TYPE(ldap_field) *attr_map)
{
struct db_ldap_result_iterate_context *ctx;
- const char *static_data;
+ pool_t pool;
- ctx = t_new(struct db_ldap_result_iterate_context, 1);
- ctx->conn = conn;
- ctx->entry = entry;
+ pool = pool_alloconly_create("ldap result iter", 1024);
+ ctx = p_new(pool, struct db_ldap_result_iterate_context, 1);
+ ctx->pool = pool;
ctx->auth_request = auth_request;
ctx->attr_map = attr_map;
-
- static_data = hash_table_lookup(attr_map, "");
- if (static_data != NULL) {
- const struct var_expand_table *table;
- string_t *str;
-
- table = auth_request_get_var_expand_table(auth_request, NULL);
- str = t_str_new(256);
- var_expand(str, static_data, table);
- ctx->static_attrs = t_strsplit(str_c(str), ",");
- }
-
+ ctx->ldap_attrs =
+ hash_table_create(default_pool, pool, 0, strcase_hash,
+ (hash_cmp_callback_t *)strcasecmp);
if (auth_request->set->debug)
ctx->debug = t_str_new(256);
- ctx->attr = ldap_first_attribute(conn->ld, entry, &ctx->ber);
+ get_ldap_fields(ctx, conn, entry);
return ctx;
}
-static void
-db_ldap_result_iterate_finish(struct db_ldap_result_iterate_context *ctx)
+static const char *const *
+db_ldap_result_return_value(struct db_ldap_result_iterate_context *ctx,
+ const struct ldap_field *field,
+ struct db_ldap_value *ldap_value)
{
- if (ctx->debug != NULL) {
- if (str_len(ctx->debug) > 0) {
- auth_request_log_debug(ctx->auth_request, "ldap",
- "result: %s", str_c(ctx->debug) + 1);
- } else {
- auth_request_log_debug(ctx->auth_request, "ldap",
- "no fields returned by the server");
+ const char *const *values;
+
+ if (*field->value == '\0') {
+ /* use the LDAP attribute's value */
+ if (ldap_value != NULL)
+ values = ldap_value->values;
+ else {
+ /* LDAP attribute doesn't exist */
+ ctx->val_1_arr[0] = NULL;
+ values = ctx->val_1_arr;
}
- }
-
- ber_free(ctx->ber, 0);
-}
-
-static void
-db_ldap_result_change_attr(struct db_ldap_result_iterate_context *ctx)
-{
- i_assert(ctx->vals == NULL);
-
- ctx->name = hash_table_lookup(ctx->attr_map, ctx->attr);
- ctx->template = NULL;
-
- if (ctx->debug != NULL) {
- str_printfa(ctx->debug, " %s(%s)=", ctx->attr,
- ctx->name != NULL ? ctx->name : "?unknown?");
- }
-
- if (ctx->name == NULL || *ctx->name == '\0')
- return;
-
- if (strchr(ctx->name, '%') != NULL &&
- (ctx->template = strchr(ctx->name, '=')) != NULL) {
- /* we want to use variables */
- ctx->name = t_strdup_until(ctx->name, ctx->template);
- ctx->template++;
+ } else {
+ /* template */
+ if (ldap_value->values[0] != NULL &&
+ ldap_value->values[1] != NULL) {
+ auth_request_log_warning(ctx->auth_request, "ldap",
+ "Multiple values found for '%s', "
+ "using value '%s'",
+ field->name, ldap_value->values[0]);
+ }
if (ctx->var_table == NULL) {
ctx->var_table = db_ldap_value_get_var_expand_table(
ctx->auth_request);
- ctx->var = t_str_new(256);
More information about the dovecot-cvs
mailing list