From c2ccdab8d09dec65753ee42366f48d53d7f47cfd Mon Sep 17 00:00:00 2001 From: Marco Bettini Date: Mon, 8 Jul 2024 14:40:35 +0000 Subject: [PATCH] auth: ldap - Split pre/post settings and finish the conversion --- src/auth/db-ldap-settings.c | 90 +++++++-- src/auth/db-ldap-settings.h | 32 ++- src/auth/db-ldap.c | 342 ++++++++++----------------------- src/auth/db-ldap.h | 30 ++- src/auth/passdb-ldap.c | 196 ++++++++----------- src/auth/userdb-ldap.c | 204 +++++++++++--------- src/lib-ldap/ldap-connection.c | 2 +- 7 files changed, 416 insertions(+), 480 deletions(-) diff --git a/src/auth/db-ldap-settings.c b/src/auth/db-ldap-settings.c index c9bc857ebd..5f07218e3d 100644 --- a/src/auth/db-ldap-settings.c +++ b/src/auth/db-ldap-settings.c @@ -14,8 +14,6 @@ static bool ldap_setting_check(void *_set, pool_t pool, const char **error_r); #undef DEF #define DEF(type, name) \ SETTING_DEFINE_STRUCT_##type("ldap_"#name, name, struct ldap_settings) -#define DEFN(type, field, name) \ - SETTING_DEFINE_STRUCT_##type(#name, field, struct ldap_settings) static const struct setting_define ldap_setting_defines[] = { { .type = SET_FILTER_NAME, .key = "passdb_ldap", }, @@ -24,20 +22,14 @@ static const struct setting_define ldap_setting_defines[] = { DEF(STR, uris), DEF(STR, auth_dn), DEF(STR, auth_dn_password), - DEFN(BOOL, passdb_ldap_bind, passdb_ldap_bind), - DEFN(STR, passdb_ldap_bind_userdn, passdb_ldap_bind_userdn), DEF(STR, auth_sasl_mechanism), DEF(STR, auth_sasl_realm), DEF(STR, auth_sasl_authz_id), DEF(BOOL, starttls), DEF(STR, deref), DEF(STR, scope), - DEF(STR, base), DEF(UINT, version), DEF(STR, debug_level), - DEF(STR, filter), - DEF(STRLIST, iterate_attrs), - DEF(STR, iterate_filter), SETTING_DEFINE_LIST_END }; @@ -46,20 +38,14 @@ static const struct ldap_settings ldap_default_settings = { .uris = "", .auth_dn = "", .auth_dn_password = "", - .passdb_ldap_bind = FALSE, - .passdb_ldap_bind_userdn = "", .auth_sasl_mechanism = "", .auth_sasl_realm = "", .auth_sasl_authz_id = "", .starttls = FALSE, .deref = "never", .scope = "subtree", - .base = "", .version = 3, .debug_level = "0", - .filter = "", - .iterate_attrs = ARRAY_INIT, - .iterate_filter = "", }; static const struct setting_keyvalue ldap_default_settings_keyvalue[] = { @@ -81,6 +67,67 @@ const struct setting_parser_info ldap_setting_parser_info = { .pool_offset1 = 1 + offsetof(struct ldap_settings, pool), }; +#undef DEF +#undef DEFN +#define DEF(type, field) \ + SETTING_DEFINE_STRUCT_##type("ldap_"#field, field, struct ldap_pre_settings) +#define DEFN(type, field, name) \ + SETTING_DEFINE_STRUCT_##type(#name, field, struct ldap_pre_settings) + +static const struct setting_define ldap_pre_setting_defines[] = { + { .type = SET_FILTER_NAME, .key = "passdb_ldap", }, + { .type = SET_FILTER_NAME, .key = "userdb_ldap", }, + DEF(STR, base), + DEFN(BOOL, passdb_ldap_bind, passdb_ldap_bind), + DEFN(STR, passdb_ldap_bind_userdn, passdb_ldap_bind_userdn), + DEF(STR, filter), + DEF(STR, iterate_filter), + SETTING_DEFINE_LIST_END +}; + +static const struct ldap_pre_settings ldap_pre_default_settings = { + .base = "", + .passdb_ldap_bind = FALSE, + .passdb_ldap_bind_userdn = "", + .filter = "", + .iterate_filter = "", +}; + +const struct setting_parser_info ldap_pre_setting_parser_info = { + .name = "auth_ldap_pre", + + .defines = ldap_pre_setting_defines, + .defaults = &ldap_pre_default_settings, + + .struct_size = sizeof(struct ldap_pre_settings), + .pool_offset1 = 1 + offsetof(struct ldap_pre_settings, pool), +}; + +#undef DEF +#define DEF(type, field) \ + SETTING_DEFINE_STRUCT_##type("ldap_"#field, field, struct ldap_post_settings) + +static const struct setting_define ldap_post_setting_defines[] = { + { .type = SET_FILTER_NAME, .key = "passdb_ldap", }, + { .type = SET_FILTER_NAME, .key = "userdb_ldap", }, + DEF(STRLIST, iterate_fields), + SETTING_DEFINE_LIST_END +}; + +static const struct ldap_post_settings ldap_post_default_settings = { + .iterate_fields = ARRAY_INIT, +}; + +const struct setting_parser_info ldap_post_setting_parser_info = { + .name = "auth_ldap_post", + + .defines = ldap_post_setting_defines, + .defaults = &ldap_post_default_settings, + + .struct_size = sizeof(struct ldap_post_settings), + .pool_offset1 = 1 + offsetof(struct ldap_post_settings, pool), +}; + /* */ static int ldap_parse_deref(const char *str, int *ref_r) @@ -157,11 +204,6 @@ static bool ldap_setting_check(void *_set, pool_t pool ATTR_UNUSED, int ldap_setting_post_check(const struct ldap_settings *set, const char **error_r) { - if (*set->base == '\0') { - *error_r = "No ldap_base given"; - return -1; - } - if (*set->uris == '\0' && *set->hosts == '\0') { *error_r = "Neither ldap_uris nor ldap_hosts set"; return -1; @@ -180,3 +222,13 @@ int ldap_setting_post_check(const struct ldap_settings *set, const char **error_ return 0; } + +int ldap_pre_settings_pre_check(const struct ldap_pre_settings *set, const char **error_r) +{ + if (*set->base == '\0') { + *error_r = "No ldap_base given"; + return -1; + } + + return 0; +} diff --git a/src/auth/db-ldap-settings.h b/src/auth/db-ldap-settings.h index f6973db45d..9cba46e615 100644 --- a/src/auth/db-ldap-settings.h +++ b/src/auth/db-ldap-settings.h @@ -8,7 +8,6 @@ struct ldap_settings { const char *uris; const char *auth_dn; const char *auth_dn_password; - const char *passdb_ldap_bind_userdn; const char *auth_sasl_mechanism; const char *auth_sasl_realm; @@ -16,21 +15,14 @@ struct ldap_settings { const char *deref; const char *scope; - const char *base; const char *debug_level; - const char *filter; - const char *iterate_filter; - - ARRAY_TYPE(const_string) iterate_attrs; - unsigned int version; uid_t uid; gid_t gid; - bool passdb_ldap_bind; bool starttls; /* parsed */ @@ -38,7 +30,31 @@ struct ldap_settings { int parsed_scope; }; +struct ldap_pre_settings { + pool_t pool; + + /* shared: */ + const char *base; + const char *filter; + + /* passdb: */ + bool passdb_ldap_bind; + const char *passdb_ldap_bind_userdn; + + /* userdb: */ + const char *iterate_filter; +}; + +struct ldap_post_settings { + pool_t pool; + ARRAY_TYPE(const_string) iterate_fields; +}; + extern const struct setting_parser_info ldap_setting_parser_info; +extern const struct setting_parser_info ldap_pre_setting_parser_info; +extern const struct setting_parser_info ldap_post_setting_parser_info; + int ldap_setting_post_check(const struct ldap_settings *set, const char **error_r); +int ldap_pre_settings_pre_check(const struct ldap_pre_settings *set, const char **error_r); #endif diff --git a/src/auth/db-ldap.c b/src/auth/db-ldap.c index b2e60677f8..4201956226 100644 --- a/src/auth/db-ldap.c +++ b/src/auth/db-ldap.c @@ -50,6 +50,7 @@ #endif #define DB_LDAP_REQUEST_MAX_ATTEMPT_COUNT 3 +#define DB_LDAP_ATTR_DN "~dn" static const char *LDAP_ESCAPE_CHARS = "*,\\#+<>;\"()= "; @@ -67,8 +68,7 @@ struct db_ldap_result_iterate_context { pool_t pool; struct ldap_request *ldap_request; - const ARRAY_TYPE(ldap_field) *attr_map; - unsigned int attr_idx; + char **attr_next; /* attribute name => value */ HASH_TABLE(char *, struct db_ldap_value *) ldap_attrs; @@ -355,13 +355,13 @@ static int db_ldap_connect_finish(struct ldap_connection *conn, int ret) { if (ret == LDAP_SERVER_DOWN) { e_error(conn->event, "Can't connect to server: %s", - conn->set->uris != NULL ? + *conn->set->uris != '\0' ? conn->set->uris : conn->set->hosts); return -1; } if (ret != LDAP_SUCCESS) { e_error(conn->event, "binding failed (dn %s): %s", - conn->set->auth_dn == NULL ? "(none)" : conn->set->auth_dn, + *conn->set->auth_dn == '\0' ? "(none)" : conn->set->auth_dn, ldap_get_error(conn)); return -1; } @@ -905,7 +905,7 @@ static void db_ldap_init_ld(struct ldap_connection *conn) { int ret; - if (conn->set->uris != NULL) { + if (*conn->set->uris != '\0') { #ifdef LDAP_HAVE_INITIALIZE ret = ldap_initialize(&conn->ld, conn->set->uris); if (ret != LDAP_SUCCESS) { @@ -948,7 +948,7 @@ int db_ldap_connect(struct ldap_connection *conn) ret = ldap_start_tls_s(conn->ld, NULL, NULL); if (ret != LDAP_SUCCESS) { if (ret == LDAP_OPERATIONS_ERROR && - conn->set->uris != NULL && + *conn->set->uris != '\0' && str_begins_with(conn->set->uris, "ldaps:")) { i_fatal("LDAP: Don't use both ldap_starttls=yes and ldaps URI"); } @@ -1072,15 +1072,14 @@ db_ldap_field_find(const char *data, void *context, return 1; } -void db_ldap_set_attrs(struct ldap_connection *conn, - const ARRAY_TYPE(const_string) *attrlist, - char ***attr_names_r, ARRAY_TYPE(ldap_field) *attr_map, - const char *skip_attr) +void db_ldap_get_attribute_names(struct ldap_connection *conn, + const ARRAY_TYPE(const_string) *attrlist, + char ***attr_names_r, + const char *skip_attr) { static struct var_expand_func_table var_funcs_table[] = { { "ldap", db_ldap_field_find }, { "ldap_multi", db_ldap_field_find }, - { "ldap_ptr", db_ldap_field_find }, { NULL, NULL } }; @@ -1093,86 +1092,21 @@ void db_ldap_set_attrs(struct ldap_connection *conn, string_t *tmp_str = t_str_new(128); for (unsigned int index = 0; index < count; ) { - char *key = p_strdup(conn->pool, array_idx_elem(attrlist, index++)); - char *value = p_strdup(conn->pool, array_idx_elem(attrlist, index++)); - char *ldap_attr, *name; - - switch (*value) { - case '\0': - ldap_attr = key; - name = key; - break; - default: - ldap_attr = key; - name = value; - } + const char *name = array_idx_elem(attrlist, index++); + const char *value = array_idx_elem(attrlist, index++); - char *templ = strchr(name, '='); - if (templ == NULL) { - if (*ldap_attr == '\0') { - /* =foo static value */ - templ = ""; - } - } else { - const char *error ATTR_UNUSED; - *templ++ = '\0'; - str_truncate(tmp_str, 0); - if (var_expand_with_funcs(tmp_str, templ, NULL, - var_funcs_table, &ctx, &error) <= 0) { - /* This var_expand_with_funcs call fills the - * ldap_field_find_context in ctx, but the - * resulting string_t is not used, and the - * return value or error_r is not checked since - * it gives errors for non-ldap variable - * expansions. */ - } - if (strchr(templ, '%') == NULL) { - /* backwards compatibility: - attr=name=prefix means same as - attr=name=prefix%$ when %vars are missing */ - templ = p_strconcat(conn->pool, templ, - "%$", NULL); - } - } + if (skip_attr != NULL && strcmp(skip_attr, name) == 0) + continue; - if (*name == '\0') - e_error(conn->event, "Invalid empty attribute name"); - else if (skip_attr == NULL || strcmp(skip_attr, name) != 0) { - struct ldap_field *field = array_append_space(attr_map); - if (name[0] == '!' && name == ldap_attr) { - /* !ldapAttr */ - name = ""; - i_assert(ldap_attr[0] == '!'); - ldap_attr++; - field->skip = TRUE; - } - field->name = name; - field->value = templ; - field->ldap_attr_name = ldap_attr; - if (*ldap_attr != '\0') { - /* root request's attribute */ - array_push_back(&ctx.attr_names, &ldap_attr); - } - } + const char *error ATTR_UNUSED; + str_truncate(tmp_str, 0); + + (void)var_expand_with_funcs(tmp_str, value, NULL, var_funcs_table, &ctx, &error); } array_append_zero(&ctx.attr_names); *attr_names_r = array_front_modifiable(&ctx.attr_names); } -static const struct var_expand_table * -db_ldap_value_get_var_expand_table(struct auth_request *auth_request, - const char *ldap_value) -{ - struct var_expand_table *table; - unsigned int count = 1; - - table = auth_request_get_var_expand_table_full(auth_request, - auth_request->fields.user, NULL, &count); - table[0].key = '$'; - table[0].value = ldap_value; - return table; -} - #define IS_LDAP_ESCAPED_CHAR(c) \ ((((unsigned char)(c)) & 0x80) != 0 || strchr(LDAP_ESCAPE_CHARS, (c)) != NULL) @@ -1265,7 +1199,7 @@ db_ldap_result_iterate_init_full(struct ldap_connection *conn, ctx = p_new(pool, struct db_ldap_result_iterate_context, 1); ctx->pool = pool; ctx->ldap_request = &ldap_request->request; - ctx->attr_map = ldap_request->attr_map; + ctx->attr_next = ldap_request->attributes; ctx->skip_null_values = skip_null_values; hash_table_create(&ctx->ldap_attrs, pool, 0, strcase_hash, strcasecmp); ctx->var = str_new(ctx->pool, 256); @@ -1295,50 +1229,6 @@ db_ldap_result_iterate_init(struct ldap_connection *conn, skip_null_values); } -static const char *db_ldap_field_get_default(const char *data) -{ - const char *p; - - p = i_strchr_to_next(data, ':'); - if (p == NULL) - return ""; - else { - /* default value given */ - return p; - } -} - -static int -db_ldap_field_expand(const char *data, void *context, - const char **value_r, const char **error_r ATTR_UNUSED) -{ - struct db_ldap_result_iterate_context *ctx = context; - struct db_ldap_value *ldap_value; - const char *field_name = t_strcut(data, ':'); - - ldap_value = hash_table_lookup(ctx->ldap_attrs, field_name); - if (ldap_value == NULL) { - /* requested ldap attribute wasn't returned at all */ - str_printfa(ctx->debug, "; %s missing", field_name); - *value_r = db_ldap_field_get_default(data); - return 1; - } - ldap_value->used = TRUE; - - if (ldap_value->values[0] == NULL) { - /* no value for ldap attribute */ - *value_r = db_ldap_field_get_default(data); - return 1; - } - if (ldap_value->values[1] != NULL) { - e_warning(authdb_event(ctx->ldap_request->auth_request), - "Multiple values found for '%s', using value '%s'", - field_name, ldap_value->values[0]); - } - *value_r = ldap_value->values[0]; - return 1; -} - void db_ldap_field_multi_expand_parse_data( const char *data, const char **field_name_r, const char **separator_r, const char **default_r) @@ -1388,12 +1278,17 @@ void db_ldap_field_multi_expand_parse_data( *default_r = ptr; } +const char *db_ldap_attribute_as_multi(const char *name) +{ + return t_strconcat(DB_LDAP_ATTR_MULTI_PREFIX, name, NULL); +} + static int db_ldap_field_multi_expand(const char *data, void *context, const char **value_r, const char **error_r ATTR_UNUSED) { - struct db_ldap_result_iterate_context *ctx = context; - struct db_ldap_value *ldap_value; + struct db_ldap_field_expand_context *ctx = context; + struct auth_fields *fields = ctx->fields; const char *field_name; const char *field_separator; @@ -1402,156 +1297,121 @@ db_ldap_field_multi_expand(const char *data, void *context, db_ldap_field_multi_expand_parse_data(data, &field_name, &field_separator, &field_default); - *value_r = field_default; - ldap_value = hash_table_lookup(ctx->ldap_attrs, field_name); - if (ldap_value == NULL) { - /* requested ldap attribute wasn't returned at all */ - str_printfa(ctx->debug, "; %s missing", field_name); - return 1; - } - ldap_value->used = TRUE; + const char *value = auth_fields_find(fields, + db_ldap_attribute_as_multi(field_name)); + if (value == NULL || *value == '\0') + value = auth_fields_find(fields, field_name); - if (ldap_value->values[0] == NULL) { - /* no value for ldap attribute */ - return 1; + if (value == NULL || *value == '\0') + value = field_default == NULL ? "" : field_default; + else { + const char **entries = t_strsplit(value, DB_LDAP_ATTR_SEPARATOR); + value = t_strarray_join(entries, field_separator); } - - *value_r = t_strarray_join(ldap_value->values, field_separator); + *value_r = value; return 1; } static int -db_ldap_field_ptr_expand(const char *data, void *context, - const char **value_r, const char **error_r) +db_ldap_field_single_expand(const char *data ATTR_UNUSED, void *context, + const char **value_r, const char **error_r ATTR_UNUSED) { - struct db_ldap_result_iterate_context *ctx = context; - const char *field_name, *suffix; + struct db_ldap_field_expand_context *ctx = context; + struct auth_fields *fields = ctx->fields; + const char *field_default = strchr(data, ':'); + const char *field_name = field_default == NULL ? data : t_strdup_until(data, field_default); - suffix = strchr(t_strcut(data, ':'), '@'); - if (db_ldap_field_expand(data, ctx, &field_name, error_r) <= 0) - i_unreached(); - if (field_name[0] == '\0') { - *value_r = ""; - return 1; + *value_r = NULL; + if (fields != NULL) + *value_r = auth_fields_find(fields, field_name); + + if (*value_r == NULL || **value_r == '\0') + *value_r = field_default == NULL ? "" : field_default + 1; + else if (auth_fields_find(fields, + db_ldap_attribute_as_multi(field_name)) != NULL) { + e_warning(ctx->event, "Multiple values found for '%s': " + "using value '%s'", field_name, *value_r); } - field_name = t_strconcat(field_name, suffix, NULL); - return db_ldap_field_expand(field_name, ctx, value_r, error_r); + + return 1; } static int -db_ldap_field_dn_expand(const char *data ATTR_UNUSED, void *context ATTR_UNUSED, +db_ldap_field_dn_expand(const char *data ATTR_UNUSED, void *context, const char **value_r, const char **error_r ATTR_UNUSED) { - struct db_ldap_result_iterate_context *ctx = context; - char *dn = ldap_get_dn(ctx->ld, ctx->ldap_msg); - *value_r = t_strdup(dn); - ldap_memfree(dn); + struct db_ldap_field_expand_context *ctx = context; + struct auth_fields *fields = ctx->fields; + *value_r = auth_fields_find(fields, DB_LDAP_ATTR_DN); return 1; } -static struct var_expand_func_table ldap_var_funcs_table[] = { - { "ldap", db_ldap_field_expand }, +const struct var_expand_func_table db_ldap_field_expand_fn_table[] = { + { "ldap", db_ldap_field_single_expand }, { "ldap_multi", db_ldap_field_multi_expand }, - { "ldap_ptr", db_ldap_field_ptr_expand }, - { "ldap_dn", db_ldap_field_dn_expand }, + { "ldap_dn", db_ldap_field_dn_expand }, { NULL, NULL } }; -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) +struct auth_fields * +ldap_query_get_fields(pool_t pool, + struct ldap_connection *conn, + struct ldap_request_search *ldap_request, + LDAPMessage *res, bool skip_null_values) { - const struct var_expand_table *var_table; - const char *const *values, *error; + struct auth_fields *fields = auth_fields_init(pool); + struct db_ldap_result_iterate_context *ldap_iter; + const char *name, *const *values; - 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; - } + const char *dn = ldap_get_dn(conn->ld, res); + auth_fields_add(fields, DB_LDAP_ATTR_DN, dn, 0); - if (field->value == NULL) { - /* use the LDAP attribute's value */ - } else { - /* template */ - if (values[0] == NULL && *field->ldap_attr_name != '\0') { - /* ldapAttr=key=template%$, but ldapAttr doesn't - exist. */ - return values; - } + ldap_iter = db_ldap_result_iterate_init(conn, ldap_request, res, + skip_null_values); + while (db_ldap_result_iterate_next(ldap_iter, &name, &values)) { + auth_fields_add(fields, name, values[0], 0); if (values[0] != NULL && values[1] != NULL) { - e_warning(authdb_event(ctx->ldap_request->auth_request), - "Multiple values found for '%s', " - "using value '%s'", - field->name, values[0]); - } - - /* do this lookup separately for each expansion, because: - 1) the values are allocated from data stack - 2) if "user" field is updated, we want %u/%n/%d updated - (and less importantly the same for other variables) */ - var_table = db_ldap_value_get_var_expand_table( - ctx->ldap_request->auth_request, values[0]); - if (var_expand_with_funcs(ctx->var, field->value, var_table, - ldap_var_funcs_table, ctx, &error) <= 0) { - e_warning(authdb_event(ctx->ldap_request->auth_request), - "Failed to expand template %s: %s", - field->value, error); + const char *mname = db_ldap_attribute_as_multi(name); + const char *mvalue = t_strarray_join(values, DB_LDAP_ATTR_SEPARATOR); + auth_fields_add(fields, mname, mvalue, 0); } - ctx->val_1_arr[0] = str_c(ctx->var); - values = ctx->val_1_arr; } - return values; + db_ldap_result_iterate_deinit(&ldap_iter); + return fields; +} + +static const char *const * +db_ldap_result_return_value(struct db_ldap_result_iterate_context *ctx, + struct db_ldap_value *ldap_value) +{ + if (ldap_value != NULL && ldap_value->values[0] != NULL) + return ldap_value->values; + + /* LDAP attribute doesn't exist */ + ctx->val_1_arr[0] = ""; + return ctx->val_1_arr; } bool db_ldap_result_iterate_next(struct db_ldap_result_iterate_context *ctx, const char **name_r, const char *const **values_r) { - const struct var_expand_table *tab; - const struct ldap_field *field; - struct db_ldap_value *ldap_value; - unsigned int pos; - const char *error; + const char *name = *ctx->attr_next; + if (name == NULL) + return FALSE; - do { - if (ctx->attr_idx == array_count(ctx->attr_map)) - return FALSE; - field = array_idx(ctx->attr_map, ctx->attr_idx++); - } while (field->skip); + ctx->attr_next++; - ldap_value = *field->ldap_attr_name == '\0' ? NULL : - hash_table_lookup(ctx->ldap_attrs, field->ldap_attr_name); + struct db_ldap_value *ldap_value = hash_table_lookup(ctx->ldap_attrs, name); if (ldap_value != NULL) ldap_value->used = TRUE; - else if (*field->ldap_attr_name != '\0') - str_printfa(ctx->debug, "; %s missing", field->ldap_attr_name); + else + str_printfa(ctx->debug, "; %s missing", name); str_truncate(ctx->var, 0); - *values_r = db_ldap_result_return_value(ctx, field, ldap_value); - - if (strchr(field->name, '%') == NULL) - *name_r = field->name; - else { - /* expand %variables also for LDAP name fields. we'll use the - same ctx->var, which may already contain the value. */ - str_append_c(ctx->var, '\0'); - pos = str_len(ctx->var); - - tab = auth_request_get_var_expand_table( - ctx->ldap_request->auth_request, NULL); - if (var_expand_with_funcs(ctx->var, field->name, tab, - ldap_var_funcs_table, ctx, &error) <= 0) { - e_warning(authdb_event(ctx->ldap_request->auth_request), - "Failed to expand %s: %s", field->name, error); - } - *name_r = str_c(ctx->var) + pos; - } - + *name_r = name; + *values_r = db_ldap_result_return_value(ctx, ldap_value); if (ctx->skip_null_values && (*values_r)[0] == NULL) { /* no values. don't confuse the caller with this reply. */ return db_ldap_result_iterate_next(ctx, name_r, values_r); diff --git a/src/auth/db-ldap.h b/src/auth/db-ldap.h index 8de5bb74ed..235dd00869 100644 --- a/src/auth/db-ldap.h +++ b/src/auth/db-ldap.h @@ -20,8 +20,12 @@ #define DB_LDAP_IDLE_RECONNECT_SECS 60 #include +#include "var-expand.h" #include "db-ldap-settings.h" +#define DB_LDAP_ATTR_MULTI_PREFIX "+" +#define DB_LDAP_ATTR_SEPARATOR "\001" + struct auth_request; struct ldap_connection; struct ldap_request; @@ -81,8 +85,7 @@ struct ldap_request_search { const char *base; const char *filter; - char **attributes; /* points to pass_attr_names / user_attr_names */ - const ARRAY_TYPE(ldap_field) *attr_map; + char **attributes; /* points to (pass|user) module attributes */ struct db_ldap_result *result; ARRAY(struct ldap_request_named_result) named_results; @@ -137,18 +140,24 @@ struct ldap_connection { time_t last_reply_stamp; char **pass_attr_names, **user_attr_names, **iterate_attr_names; - ARRAY_TYPE(ldap_field) pass_attr_map, user_attr_map, iterate_attr_map; bool delayed_connect; }; +struct db_ldap_field_expand_context { + struct event *event; + struct auth_fields *fields; +}; + +extern const struct var_expand_func_table db_ldap_field_expand_fn_table[]; + /* Send/queue request */ void db_ldap_request(struct ldap_connection *conn, struct ldap_request *request); -void db_ldap_set_attrs(struct ldap_connection *conn, - const ARRAY_TYPE(const_string) *attrlist, - char ***attr_names_r, ARRAY_TYPE(ldap_field) *attr_map, - const char *skip_attr) ATTR_NULL(5); +void db_ldap_get_attribute_names(struct ldap_connection *conn, + const ARRAY_TYPE(const_string) *attrlist, + char ***attr_names_r, + const char *skip_attr) ATTR_NULL(4); struct ldap_connection *db_ldap_init(struct event *event); void db_ldap_unref(struct ldap_connection **conn); @@ -171,6 +180,13 @@ bool db_ldap_result_iterate_next(struct db_ldap_result_iterate_context *ctx, const char *const **values_r); void db_ldap_result_iterate_deinit(struct db_ldap_result_iterate_context **ctx); +struct auth_fields * +ldap_query_get_fields(pool_t pool, + struct ldap_connection *conn, + struct ldap_request_search *ldap_request, + LDAPMessage *res, bool skip_null_values); +const char *db_ldap_attribute_as_multi(const char *name); + /* exposed only for unit tests */ const char *const *db_ldap_parse_attrs(const char *cstr); diff --git a/src/auth/passdb-ldap.c b/src/auth/passdb-ldap.c index d2bf79e201..1e0dd1a785 100644 --- a/src/auth/passdb-ldap.c +++ b/src/auth/passdb-ldap.c @@ -16,6 +16,8 @@ #include +#define RAW_SETTINGS (SETTINGS_GET_FLAG_NO_CHECK | SETTINGS_GET_FLAG_NO_EXPAND) + struct ldap_passdb_module { struct passdb_module module; @@ -46,30 +48,18 @@ ldap_query_save_result(struct ldap_connection *conn, struct ldap_request_search *ldap_request, LDAPMessage *res) { - struct passdb_module *_module = auth_request->passdb->passdb; - struct auth_fields *fields = auth_fields_init(auth_request->pool); - struct db_ldap_result_iterate_context *ldap_iter; - const char *name, *const *values; - - ldap_iter = db_ldap_result_iterate_init(conn, ldap_request, res, FALSE); - while (db_ldap_result_iterate_next(ldap_iter, &name, &values)) { - auth_fields_add(fields, name, values[0], 0); - if (!auth_request->passdb->set->fields_import_all) - continue; - if (values[0] == NULL) { - auth_request_set_null_field(auth_request, name); - continue; - } - if (values[1] != NULL) { - e_warning(authdb_event(auth_request), - "Multiple values found for '%s', " - "using value '%s'", name, values[0]); - } - auth_request_set_field(auth_request, name, values[0], - _module->default_pass_scheme); - } - db_ldap_result_iterate_deinit(&ldap_iter); - return auth_request_set_passdb_fields(auth_request, fields); + struct db_ldap_field_expand_context ctx = { + .event = authdb_event(auth_request), + .fields = ldap_query_get_fields(auth_request->pool, conn, + ldap_request, res, FALSE) + }; + + const char *default_password_scheme = + auth_request->passdb->set->default_password_scheme; + + return auth_request_set_passdb_fields_ex(auth_request, &ctx, + default_password_scheme, + db_ldap_field_expand_fn_table); } static void @@ -285,6 +275,7 @@ static void ldap_bind_lookup_dn_callback(struct ldap_connection *conn, static void ldap_lookup_pass(struct auth_request *auth_request, struct passdb_ldap_request *request, + const struct ldap_pre_settings *ldap_set, bool require_password) { struct passdb_module *_module = auth_request->passdb->passdb; @@ -293,33 +284,11 @@ static void ldap_lookup_pass(struct auth_request *auth_request, struct ldap_connection *conn = module->conn; struct ldap_request_search *srequest = &request->request.search; const char **attr_names = (const char **)conn->pass_attr_names; - const char *error; - string_t *str; request->require_password = require_password; srequest->request.type = LDAP_REQUEST_TYPE_SEARCH; - - str = t_str_new(512); - if (auth_request_var_expand(str, conn->set->base, auth_request, - ldap_escape, &error) <= 0) { - e_error(authdb_event(auth_request), - "Failed to expand base=%s: %s", conn->set->base, error); - passdb_ldap_request_fail(request, PASSDB_RESULT_INTERNAL_FAILURE); - return; - } - srequest->base = p_strdup(auth_request->pool, str_c(str)); - - str_truncate(str, 0); - if (auth_request_var_expand(str, conn->set->filter, - auth_request, ldap_escape, &error) <= 0) { - e_error(authdb_event(auth_request), - "Failed to expand ldap_filter=%s: %s", - conn->set->filter, error); - passdb_ldap_request_fail(request, PASSDB_RESULT_INTERNAL_FAILURE); - return; - } - srequest->filter = p_strdup(auth_request->pool, str_c(str)); - srequest->attr_map = &conn->pass_attr_map; + srequest->base = p_strdup(auth_request->pool, ldap_set->base); + srequest->filter = p_strdup(auth_request->pool, ldap_set->filter); srequest->attributes = conn->pass_attr_names; e_debug(authdb_event(auth_request), "pass search: " @@ -333,43 +302,22 @@ static void ldap_lookup_pass(struct auth_request *auth_request, } static void ldap_bind_lookup_dn(struct auth_request *auth_request, - struct passdb_ldap_request *request) + struct passdb_ldap_request *request, + const struct ldap_pre_settings *ldap_set) { struct passdb_module *_module = auth_request->passdb->passdb; struct ldap_passdb_module *module = (struct ldap_passdb_module *)_module; struct ldap_connection *conn = module->conn; struct ldap_request_search *srequest = &request->request.search; - const char *error; - string_t *str; srequest->request.type = LDAP_REQUEST_TYPE_SEARCH; - - str = t_str_new(512); - if (auth_request_var_expand(str, conn->set->base, auth_request, - ldap_escape, &error) <= 0) { - e_error(authdb_event(auth_request), - "Failed to expand base=%s: %s", conn->set->base, error); - passdb_ldap_request_fail(request, PASSDB_RESULT_INTERNAL_FAILURE); - return; - } - srequest->base = p_strdup(auth_request->pool, str_c(str)); - - str_truncate(str, 0); - if (auth_request_var_expand(str, conn->set->filter, - auth_request, ldap_escape, &error) <= 0) { - e_error(authdb_event(auth_request), - "Failed to expand filter=%s: %s", - conn->set->filter, error); - passdb_ldap_request_fail(request, PASSDB_RESULT_INTERNAL_FAILURE); - return; - } - srequest->filter = p_strdup(auth_request->pool, str_c(str)); + srequest->base = p_strdup(auth_request->pool, ldap_set->base); + srequest->filter = p_strdup(auth_request->pool, ldap_set->filter); /* we don't need the attributes to perform authentication, but they may contain some extra parameters. if a password is returned, it's just ignored. */ - srequest->attr_map = &conn->pass_attr_map; srequest->attributes = conn->pass_attr_names; e_debug(authdb_event(auth_request), @@ -382,29 +330,17 @@ static void ldap_bind_lookup_dn(struct auth_request *auth_request, static void ldap_verify_plain_auth_bind_userdn(struct auth_request *auth_request, - struct passdb_ldap_request *request) + struct passdb_ldap_request *request, + const struct ldap_pre_settings *ldap_set) { struct passdb_module *_module = auth_request->passdb->passdb; struct ldap_passdb_module *module = (struct ldap_passdb_module *)_module; struct ldap_connection *conn = module->conn; struct ldap_request_bind *brequest = &request->request.bind; - string_t *dn; - const char *error; brequest->request.type = LDAP_REQUEST_TYPE_BIND; - - dn = t_str_new(512); - if (auth_request_var_expand(dn, conn->set->passdb_ldap_bind_userdn, - auth_request, ldap_escape, &error) <= 0) { - e_error(authdb_event(auth_request), - "Failed to expand passdb_ldap_bind_userdn=%s: %s", - conn->set->passdb_ldap_bind_userdn, error); - passdb_ldap_request_fail(request, PASSDB_RESULT_INTERNAL_FAILURE); - return; - } - - brequest->dn = p_strdup(auth_request->pool, str_c(dn)); + brequest->dn = p_strdup(auth_request->pool, ldap_set->passdb_ldap_bind_userdn); ldap_auth_bind(conn, brequest); } @@ -417,7 +353,9 @@ ldap_verify_plain(struct auth_request *request, struct ldap_passdb_module *module = (struct ldap_passdb_module *)_module; struct ldap_connection *conn = module->conn; + struct event *event = authdb_event(request); struct passdb_ldap_request *ldap_request; + const char *error; /* reconnect if needed. this is also done by db_ldap_search(), but with auth binds we'll have to do it ourself */ @@ -426,67 +364,97 @@ ldap_verify_plain(struct auth_request *request, return; } + const struct ldap_pre_settings *ldap_pre = NULL; + if (settings_get(event, &ldap_pre_setting_parser_info, 0, + &ldap_pre, &error) < 0 || + ldap_pre_settings_pre_check(ldap_pre, &error) < 0) { + e_error(event, "%s", error); + callback(PASSDB_RESULT_INTERNAL_FAILURE, request); + settings_free(ldap_pre); + return; + } + ldap_request = p_new(request->pool, struct passdb_ldap_request, 1); ldap_request->callback.verify_plain = callback; auth_request_ref(request); ldap_request->request.ldap.auth_request = request; - if (!conn->set->passdb_ldap_bind) - ldap_lookup_pass(request, ldap_request, TRUE); - else if (conn->set->passdb_ldap_bind_userdn == NULL) - ldap_bind_lookup_dn(request, ldap_request); + if (!ldap_pre->passdb_ldap_bind) + ldap_lookup_pass(request, ldap_request, ldap_pre, TRUE); + else if (*ldap_pre->passdb_ldap_bind_userdn == '\0') + ldap_bind_lookup_dn(request, ldap_request, ldap_pre); else - ldap_verify_plain_auth_bind_userdn(request, ldap_request); + ldap_verify_plain_auth_bind_userdn(request, ldap_request, ldap_pre); + + settings_free(ldap_pre); } static void ldap_lookup_credentials(struct auth_request *request, lookup_credentials_callback_t *callback) { - struct passdb_module *_module = request->passdb->passdb; - struct ldap_passdb_module *module = - (struct ldap_passdb_module *)_module; - struct passdb_ldap_request *ldap_request; - bool require_password; - - ldap_request = p_new(request->pool, struct passdb_ldap_request, 1); + struct event *event = authdb_event(request); + struct passdb_ldap_request *ldap_request = + p_new(request->pool, struct passdb_ldap_request, 1); ldap_request->callback.lookup_credentials = callback; auth_request_ref(request); ldap_request->request.ldap.auth_request = request; + const char *error; + const struct ldap_pre_settings *ldap_pre = NULL; + if (settings_get(event, &ldap_pre_setting_parser_info, 0, + &ldap_pre, &error) < 0 || + ldap_pre_settings_pre_check(ldap_pre, &error) < 0) { + e_error(event, "%s", error); + passdb_ldap_request_fail(ldap_request, PASSDB_RESULT_INTERNAL_FAILURE); + settings_free(ldap_pre); + return; + } + /* with auth_bind=yes we don't necessarily have a password. this will fail actual password credentials lookups, but it's fine for passdb lookups done by lmtp/doveadm */ - require_password = !module->conn->set->passdb_ldap_bind; - ldap_lookup_pass(request, ldap_request, require_password); + bool require_password = !ldap_pre->passdb_ldap_bind; + ldap_lookup_pass(request, ldap_request, ldap_pre, require_password); + settings_free(ldap_pre); } static int passdb_ldap_preinit(pool_t pool, struct event *event, struct passdb_module **module_r, const char **error_r) { - const struct auth_passdb_post_settings *set; + const struct auth_passdb_post_settings *auth_post = NULL; + const struct ldap_pre_settings *ldap_pre = NULL; struct ldap_passdb_module *module; struct ldap_connection *conn; + int ret = -1; + + if (settings_get(event, &auth_passdb_post_setting_parser_info, + RAW_SETTINGS, &auth_post, error_r) < 0) + goto failed; + if (settings_get(event, &ldap_pre_setting_parser_info, + RAW_SETTINGS, &ldap_pre, error_r) < 0) + goto failed; module = p_new(pool, struct ldap_passdb_module, 1); module->conn = conn = db_ldap_init(event); - p_array_init(&conn->pass_attr_map, pool, 16); - if (settings_get(event, &auth_passdb_post_setting_parser_info, - SETTINGS_GET_FLAG_NO_CHECK | SETTINGS_GET_FLAG_NO_EXPAND, - &set, error_r) < 0) - return -1; - db_ldap_set_attrs(conn, &set->fields, &conn->pass_attr_names, - &conn->pass_attr_map, - conn->set->passdb_ldap_bind ? "password" : NULL); + db_ldap_get_attribute_names(conn, &auth_post->fields, + &conn->pass_attr_names, + ldap_pre->passdb_ldap_bind ? "password" : NULL); + module->module.default_cache_key = auth_cache_parse_key_and_fields( - pool, conn->set->base, &set->fields, NULL); + pool, t_strconcat(ldap_pre->base, ldap_pre->filter, NULL), + &auth_post->fields, NULL); - settings_free(set); *module_r = &module->module; - return 0; + ret = 0; + +failed: + settings_free(auth_post); + settings_free(ldap_pre); + return ret; } static void passdb_ldap_init(struct passdb_module *_module) diff --git a/src/auth/userdb-ldap.c b/src/auth/userdb-ldap.c index 8b18dd236f..b2a05dd276 100644 --- a/src/auth/userdb-ldap.c +++ b/src/auth/userdb-ldap.c @@ -15,6 +15,8 @@ #include +#define RAW_SETTINGS (SETTINGS_GET_FLAG_NO_CHECK | SETTINGS_GET_FLAG_NO_EXPAND) + struct ldap_userdb_module { struct userdb_module module; @@ -48,20 +50,14 @@ ldap_query_get_result(struct ldap_connection *conn, struct ldap_request_search *ldap_request, LDAPMessage *res) { - struct auth_fields *fields = auth_fields_init(auth_request->pool); - struct db_ldap_result_iterate_context *ldap_iter; - const char *name, *const *values; - - ldap_iter = db_ldap_result_iterate_init(conn, ldap_request, res, TRUE); - while (db_ldap_result_iterate_next(ldap_iter, &name, &values)) { - auth_fields_add(fields, name, values[0], 0); - if (!auth_request->userdb->set->fields_import_all) - continue; - auth_request_set_userdb_field_values(auth_request, - name, values); - } - db_ldap_result_iterate_deinit(&ldap_iter); - return auth_request_set_userdb_fields(auth_request, fields); + struct db_ldap_field_expand_context ctx = { + .event = authdb_event(auth_request), + .fields = ldap_query_get_fields(auth_request->pool, conn, + ldap_request, res, FALSE) + }; + + return auth_request_set_userdb_fields_ex(auth_request, &ctx, + db_ldap_field_expand_fn_table); } static void @@ -117,41 +113,32 @@ static void userdb_ldap_lookup(struct auth_request *auth_request, struct ldap_userdb_module *module = (struct ldap_userdb_module *)_module; struct ldap_connection *conn = module->conn; + struct event *event = authdb_event(auth_request); const char **attr_names = (const char **)conn->user_attr_names; + struct userdb_ldap_request *request; const char *error; - string_t *str; - auth_request_ref(auth_request); - request = p_new(auth_request->pool, struct userdb_ldap_request, 1); - request->userdb_callback = callback; - - str = t_str_new(512); - if (auth_request_var_expand(str, conn->set->base, auth_request, - ldap_escape, &error) <= 0) { - e_error(authdb_event(auth_request), - "Failed to expand base=%s: %s", conn->set->base, error); + const struct ldap_pre_settings *ldap_pre = NULL; + if (settings_get(event, &ldap_pre_setting_parser_info, 0, + &ldap_pre, &error) < 0 || + ldap_pre_settings_pre_check(ldap_pre, &error) < 0) { + e_error(event, "%s", error); callback(USERDB_RESULT_INTERNAL_FAILURE, auth_request); + settings_free(ldap_pre); return; } - request->request.base = p_strdup(auth_request->pool, str_c(str)); - str_truncate(str, 0); - if (auth_request_var_expand(str, conn->set->filter, auth_request, - ldap_escape, &error) <= 0) { - e_error(authdb_event(auth_request), - "Failed to expand ldap_filter=%s: %s", - conn->set->filter, error); - callback(USERDB_RESULT_INTERNAL_FAILURE, auth_request); - return; - } - request->request.filter = p_strdup(auth_request->pool, str_c(str)); - - request->request.attr_map = &conn->user_attr_map; + auth_request_ref(auth_request); + request = p_new(auth_request->pool, struct userdb_ldap_request, 1); + request->userdb_callback = callback; + request->request.base = p_strdup(auth_request->pool, ldap_pre->base); + request->request.filter = p_strdup(auth_request->pool, ldap_pre->filter); request->request.attributes = conn->user_attr_names; - e_debug(authdb_event(auth_request), "user search: " - "base=%s scope=%s filter=%s fields=%s", + settings_free(ldap_pre); + + e_debug(event, "user search: base=%s scope=%s filter=%s fields=%s", request->request.base, conn->set->scope, request->request.filter, attr_names == NULL ? "(all)" : @@ -169,8 +156,6 @@ static void userdb_ldap_iterate_callback(struct ldap_connection *conn, struct userdb_iter_ldap_request *urequest = (struct userdb_iter_ldap_request *)request; struct ldap_userdb_iterate_context *ctx = urequest->ctx; - struct db_ldap_result_iterate_context *ldap_iter; - const char *name, *const *values; if (res == NULL || ldap_msgtype(res) == LDAP_RES_SEARCH_RESULT) { if (res == NULL) @@ -189,20 +174,54 @@ static void userdb_ldap_iterate_callback(struct ldap_connection *conn, request->create_time = ioloop_time; ctx->in_callback = TRUE; - ldap_iter = db_ldap_result_iterate_init(conn, &urequest->request, - res, TRUE); - while (db_ldap_result_iterate_next(ldap_iter, &name, &values)) { - if (strcmp(name, "user") != 0) { - e_warning(authdb_event(request->auth_request), "iterate: " - "Ignoring field not named 'user': %s", name); - continue; - } - for (; *values != NULL; values++) { + + struct db_ldap_field_expand_context fctx = { + .event = authdb_event(request->auth_request), + .fields = ldap_query_get_fields(pool_datastack_create(), conn, + &urequest->request, res, TRUE) + }; + + struct var_expand_params params = { + .func_table = db_ldap_field_expand_fn_table, + .func_context = &fctx + }; + + struct event *event = event_create(authdb_event(urequest->request.request.auth_request)); + event_set_ptr(event, SETTINGS_EVENT_VAR_EXPAND_PARAMS, ¶ms); + + const struct ldap_post_settings *set; + const char *error; + if (settings_get(event, &ldap_post_setting_parser_info, 0, + &set, &error) < 0) { + e_error(event, "%s", error); + ctx->ctx.failed = TRUE; + } + else { + unsigned int count; + const char *const *items = array_get(&set->iterate_fields, &count); + for (unsigned int ndx = 0; ndx < count - 1;) { + const char *name = items[ndx++]; + const char *value = items[ndx++]; + if (strcmp(name, DB_LDAP_ATTR_MULTI_PREFIX"user") == 0) { + value = t_strsplit(value, DB_LDAP_ATTR_SEPARATOR)[0]; + e_warning(authdb_event(request->auth_request), + "iterate: Taking only first value of %s: %s", + name + 1, value); + continue; + } + if (strcmp(name, "user") != 0) { + e_warning(authdb_event(request->auth_request), + "iterate: Ignoring field not named 'user': %s", + name); + continue; + } ctx->continued = FALSE; - ctx->ctx.callback(*values, ctx->ctx.context); + ctx->ctx.callback(value, ctx->ctx.context); } + settings_free(set); } - db_ldap_result_iterate_deinit(&ldap_iter); + event_unref(&event); + if (!ctx->continued) db_ldap_enable_input(conn, FALSE); ctx->in_callback = FALSE; @@ -216,11 +235,12 @@ userdb_ldap_iterate_init(struct auth_request *auth_request, struct ldap_userdb_module *module = (struct ldap_userdb_module *)_module; struct ldap_connection *conn = module->conn; + struct event *event = authdb_event(auth_request); + struct ldap_userdb_iterate_context *ctx; struct userdb_iter_ldap_request *request; const char **attr_names = (const char **)conn->iterate_attr_names; const char *error; - string_t *str; ctx = p_new(auth_request->pool, struct ldap_userdb_iterate_context, 1); ctx->ctx.auth_request = auth_request; @@ -230,34 +250,25 @@ userdb_ldap_iterate_init(struct auth_request *auth_request, request = &ctx->request; request->ctx = ctx; - auth_request_ref(auth_request); - request->request.request.auth_request = auth_request; - - str = t_str_new(512); - if (auth_request_var_expand(str, conn->set->base, auth_request, - ldap_escape, &error) <= 0) { - e_error(authdb_event(auth_request), - "Failed to expand base=%s: %s", conn->set->base, error); + const struct ldap_pre_settings *ldap_pre = NULL; + if (settings_get(event, &ldap_pre_setting_parser_info, 0, + &ldap_pre, &error) < 0 || + ldap_pre_settings_pre_check(ldap_pre, &error) < 0) { + e_error(event, "%s", error); + settings_free(ldap_pre); ctx->ctx.failed = TRUE; return &ctx->ctx; } - request->request.base = p_strdup(auth_request->pool, str_c(str)); - str_truncate(str, 0); - if (auth_request_var_expand(str, conn->set->iterate_filter, - auth_request, ldap_escape, &error) <= 0) { - e_error(authdb_event(auth_request), - "Failed to expand iterate_filter=%s: %s", - conn->set->iterate_filter, error); - ctx->ctx.failed = TRUE; - return &ctx->ctx; - } - request->request.filter = p_strdup(auth_request->pool, str_c(str)); - request->request.attr_map = &conn->iterate_attr_map; + auth_request_ref(auth_request); + request->request.request.auth_request = auth_request; + request->request.base = p_strdup(auth_request->pool, ldap_pre->base); + request->request.filter = p_strdup(auth_request->pool, ldap_pre->iterate_filter); request->request.attributes = conn->iterate_attr_names; request->request.multi_entry = TRUE; + settings_free(ldap_pre); - e_debug(auth_request->event, "ldap: iterate: base=%s scope=%s filter=%s fields=%s", + e_debug(event, "ldap: iterate: base=%s scope=%s filter=%s fields=%s", request->request.base, conn->set->scope, request->request.filter, attr_names == NULL ? "(all)" : t_strarray_join(attr_names, ",")); @@ -295,30 +306,43 @@ static int userdb_ldap_preinit(pool_t pool, struct event *event, struct userdb_module **module_r, const char **error_r ATTR_UNUSED) { - const struct auth_passdb_post_settings *set; + const struct auth_userdb_post_settings *auth_post = NULL; + const struct ldap_post_settings *ldap_post = NULL; + const struct ldap_pre_settings *ldap_pre = NULL; struct ldap_userdb_module *module; struct ldap_connection *conn; + int ret = -1; + + if (settings_get(event, &auth_userdb_post_setting_parser_info, + RAW_SETTINGS, &auth_post, error_r) < 0) + goto failed; + if (settings_get(event, &ldap_post_setting_parser_info, + RAW_SETTINGS, &ldap_post, error_r) < 0) + goto failed; + if (settings_get(event, &ldap_pre_setting_parser_info, + RAW_SETTINGS, &ldap_pre, error_r) < 0) + goto failed; module = p_new(pool, struct ldap_userdb_module, 1); module->conn = conn = db_ldap_init(event); - p_array_init(&conn->user_attr_map, pool, 16); - p_array_init(&conn->iterate_attr_map, pool, 16); - if (settings_get(event, &auth_passdb_post_setting_parser_info, - SETTINGS_GET_FLAG_NO_CHECK | SETTINGS_GET_FLAG_NO_EXPAND, - &set, error_r) < 0) - return -1; - - db_ldap_set_attrs(conn, &set->fields, &conn->user_attr_names, - &conn->user_attr_map, NULL); - db_ldap_set_attrs(conn, &conn->set->iterate_attrs, - &conn->iterate_attr_names, - &conn->iterate_attr_map, NULL); + + db_ldap_get_attribute_names(conn, &auth_post->fields, + &conn->user_attr_names, NULL); + db_ldap_get_attribute_names(conn, &ldap_post->iterate_fields, + &conn->iterate_attr_names, NULL); + module->module.default_cache_key = auth_cache_parse_key_and_fields( - pool, conn->set->base, &set->fields, NULL); + pool, t_strconcat(ldap_pre->base, ldap_pre->filter, NULL), + &auth_post->fields, NULL); - settings_free(set); *module_r = &module->module; - return 0; + ret = 0; + +failed: + settings_free(auth_post); + settings_free(ldap_pre); + settings_free(ldap_post); + return ret; } static void userdb_ldap_init(struct userdb_module *_module) diff --git a/src/lib-ldap/ldap-connection.c b/src/lib-ldap/ldap-connection.c index f33d374ebc..aa820d02f2 100644 --- a/src/lib-ldap/ldap-connection.c +++ b/src/lib-ldap/ldap-connection.c @@ -177,7 +177,7 @@ int ldap_connection_init(struct ldap_client *client, /* deep copy relevant strings */ conn->set.uri = p_strdup(pool, set->uri); conn->set.bind_dn = p_strdup(pool, set->bind_dn); - if (set->password != NULL) { + if (*set->password != '\0') { conn->set.password = p_strdup(pool, set->password); ber_str2bv(conn->set.password, strlen(conn->set.password), 0, &conn->cred); } -- 2.47.3