/* <settings checks> */
#include "ldap-settings-parse.h"
+
+static bool
+dict_ldap_map_settings_post_check(void *set, pool_t pool, const char **error_r);
+
/* </settings checks> */
#undef DEF
DEF(STR, pattern),
DEFN(STR, base, ldap_base),
DEFN(ENUM, scope, ldap_scope),
- DEF(BOOLLIST, values),
SETTING_DEFINE_LIST_END
};
static const struct dict_ldap_map_settings dict_ldap_map_default_settings = {
.pattern = "",
- .values = ARRAY_INIT,
.base = "",
.scope = "subtree:onelevel:base",
};
.pool_offset1 = 1 + offsetof(struct dict_ldap_map_pre_settings, pool),
};
+#undef DEF
+#define DEF(type, name) \
+ SETTING_DEFINE_STRUCT_##type("dict_map_"#name, name, struct dict_ldap_map_post_settings)
+
+static const struct setting_define dict_ldap_map_post_setting_defines[] = {
+ DEF(STR, value),
+ SETTING_DEFINE_LIST_END
+};
+
+static const struct dict_ldap_map_post_settings dict_ldap_map_post_default_settings = {
+ .value = "",
+};
+
+const struct setting_parser_info dict_ldap_map_post_setting_parser_info = {
+ .name = "dict_ldap_map_post",
+
+ .defines = dict_ldap_map_post_setting_defines,
+ .defaults = &dict_ldap_map_post_default_settings,
+ .check_func = dict_ldap_map_settings_post_check,
+
+ .struct_size = sizeof(struct dict_ldap_map_post_settings),
+ .pool_offset1 = 1 + offsetof(struct dict_ldap_map_post_settings, pool),
+};
+
#undef DEF
#define DEF(type, name) \
SETTING_DEFINE_STRUCT_##type("ldap_"#name, name, struct dict_ldap_settings)
.pool_offset1 = 1 + offsetof(struct dict_ldap_settings, pool),
};
+/* <settings checks> */
+
+static bool
+dict_ldap_map_settings_post_check(void *_set, pool_t pool,
+ const char **error_r ATTR_UNUSED)
+{
+ struct dict_ldap_map_post_settings *set = _set;
+ p_array_init(&set->values, pool, 1);
+ if (*set->value != '\0')
+ array_push_back(&set->values, &set->value);
+ return TRUE;
+}
+
+/* </settings checks> */
+
+static int ldap_parse_attributes(struct dict_ldap_map_settings *set,
+ struct dict_ldap_map_post_settings *post,
+ const char **error_r)
+{
+ const char *value;
+ p_array_init(&set->parsed_attributes, set->pool, 2);
+ array_foreach_elem(&post->values, value) {
+ struct var_expand_program *prog;
+
+ if (var_expand_program_create(value, &prog, error_r) < 0) {
+ *error_r = t_strdup_printf("Invalid ldap_map_value %s: %s",
+ value, *error_r);
+ return -1;
+ }
+
+ const char *const *vars = var_expand_program_variables(prog);
+ for (; *vars != NULL; vars++) {
+ const char *ldap_attr;
+ if (!str_begins(*vars, "ldap:", &ldap_attr) &&
+ !str_begins(*vars, "ldap_multi:", &ldap_attr))
+ continue;
+
+ /* When we free program, this name would be invalid,
+ so dup it here. */
+ ldap_attr = p_strdup(set->pool, ldap_attr);
+ array_push_back(&set->parsed_attributes, &ldap_attr);
+ }
+ var_expand_program_free(&prog);
+ }
+ return 0;
+}
+
static int
dict_ldap_map_settings_postcheck(struct dict_ldap_map_settings *set,
struct dict_ldap_map_pre_settings *pre,
+ struct dict_ldap_map_post_settings *post,
const char **error_r)
{
if (!str_begins_with(pre->filter, "(")) {
return -1;
}
- if (array_is_empty(&set->values)) {
+ if (array_is_empty(&post->values)) {
*error_r = "ldap_map_value not set";
return -1;
- } else {
- array_append_zero(&set->values);
- array_pop_back(&set->values);
}
if (ldap_parse_scope(set->scope, &set->parsed_scope) < 0) {
return -1;
}
- return 0;
+ return ldap_parse_attributes(set, post, error_r);
}
static const char *pattern_read_name(const char **pattern)
array_foreach_elem(&set->maps, name) {
struct dict_ldap_map_settings *map = NULL;
struct dict_ldap_map_pre_settings *pre = NULL;
+ struct dict_ldap_map_post_settings *post = NULL;
if (settings_get_filter(event, "dict_map", name,
&dict_ldap_map_setting_parser_info,
0, &map, error_r) < 0 ||
settings_get_filter(event, "dict_map", name,
&dict_ldap_map_pre_setting_parser_info,
SETTINGS_GET_FLAG_NO_EXPAND,
- &pre, error_r) < 0) {
+ &pre, error_r) < 0 ||
+ settings_get_filter(event, "dict_map", name,
+ &dict_ldap_map_post_setting_parser_info,
+ SETTINGS_GET_FLAG_NO_EXPAND,
+ &post, error_r) < 0) {
*error_r = t_strdup_printf("Failed to get dict_map %s: %s",
name, *error_r);
settings_free(map);
settings_free(pre);
+ settings_free(post);
return -1;
}
- if (dict_ldap_map_settings_postcheck(map, pre, error_r) < 0) {
+ if (dict_ldap_map_settings_postcheck(map, pre, post, error_r) < 0) {
settings_free(map);
settings_free(pre);
+ settings_free(post);
return -1;
}
settings_free(pre);
+ settings_free(post);
dict_ldap_settings_parse_pattern(map);
chain_ref(set->pool, map->pool);
pool_t pool;
const char *pattern;
- ARRAY_TYPE(const_string) values;
const char *base;
const char *scope;
/* parsed */
+ ARRAY_TYPE(const_string) parsed_attributes;
+
/* attributes sorted by the position in parsed_pattern. */
ARRAY_TYPE(const_string) parsed_pattern_keys;
int parsed_scope;
const char *filter;
};
+struct dict_ldap_map_post_settings {
+ pool_t pool;
+ const char *value;
+
+ /* parsed */
+
+ /* This is preliminary support for supporting multiple values.
+ For now the array contains only the single value coming
+ from 'value' above. */
+ ARRAY_TYPE(const_string) values;
+};
+
struct dict_ldap_settings {
pool_t pool;
ARRAY_TYPE(const_string) maps;
extern const struct setting_parser_info dict_ldap_map_setting_parser_info;
extern const struct setting_parser_info dict_ldap_map_pre_setting_parser_info;
+extern const struct setting_parser_info dict_ldap_map_post_setting_parser_info;
extern const struct setting_parser_info dict_ldap_setting_parser_info;
int dict_ldap_settings_get(struct event *event,
static const char *LDAP_ESCAPE_CHARS = "*,\\#+<>;\"()= ";
struct ldap_dict;
+struct key_value {
+ /* pre lower-cased */
+ const char *key_lcase;
-struct dict_ldap_vars_context {
- const struct dict_ldap_map_settings *set;
- ARRAY_TYPE(const_string) values;
- const char *username;
- bool private;
+ const char *value;
};
struct dict_ldap_op {
struct ldap_dict *dict;
struct event *event;
const struct dict_ldap_map_settings *map;
+ ARRAY_TYPE(const_string) pattern_values;
+ ARRAY(struct key_value) attribute_values;
+
+ const char *username;
+ bool private;
pool_t pool;
unsigned long txid;
struct dict_lookup_result res;
e_debug(op->event, "got dn %s",
ldap_entry_dn(entry));
- ARRAY_TYPE(const_string) resp_values;
- p_array_init(&resp_values, op->pool, array_count(&op->map->values) + 1);
-
const char *attribute;
- array_foreach_elem(&op->map->values, attribute) {
+ array_foreach_elem(&op->map->parsed_attributes, attribute) {
const char *const *values = ldap_entry_get_attribute(entry, attribute);
bool no_attribute = values == NULL;
e_debug(op->event, "%s attribute %s",
no_attribute ? "dit not get" : "got", attribute);
- if (no_attribute && array_is_empty(&resp_values))
- break;
- const char *value = no_attribute ? "" : p_strdup(op->pool, values[0]);
+ if (no_attribute)
+ continue;
+ struct key_value *kv = array_append_space(&op->attribute_values);
+ kv->key_lcase = p_strdup(op->pool, t_str_lcase(attribute));
+ kv->value = p_strdup(op->pool, values[0]);
+ }
+
+ struct dict_ldap_map_post_settings *post;
+ if (settings_get_filter(op->event, "dict_map", op->map->pattern,
+ &dict_ldap_map_post_setting_parser_info,
+ 0, &post, &op->res.error) < 0) {
+ op->res.ret = -1;
+ return;
+ }
+
+ ARRAY_TYPE(const_string) resp_values;
+ p_array_init(&resp_values, op->pool, array_count(&post->values) + 1);
+
+ const char *value;
+ array_foreach_elem(&post->values, value) {
+ value = p_strdup(op->pool, value);
array_push_back(&resp_values, &value);
}
+ settings_free(post);
array_append_zero(&resp_values);
array_pop_back(&resp_values);
bool got_values = array_not_empty(&resp_values);
op->res.values = got_values ? array_front(&resp_values) : NULL;
op->res.value = got_values ? op->res.values[0] : NULL;
- op->res.ret = got_values ? 1 : 0;
+ op->res.ret = 1;
}
static void
const char *key, long long diff);
*/
+static int
+ldap_dict_ldap_expand(const char *key, const char **value_r, void *_ctx,
+ const char **error_r ATTR_UNUSED)
+{
+ struct dict_ldap_op *op = _ctx;
+ *value_r = "";
+
+ if (array_not_empty(&op->attribute_values)) {
+ key = t_str_lcase(key);
+
+ const struct key_value *attr;
+ array_foreach(&op->attribute_values, attr) {
+ if (strcmp(key, attr->key_lcase) == 0) {
+ *value_r = attr->value;
+ return 0;
+ }
+ }
+ }
+
+ *error_r = t_strdup_printf("ldap attribute %s not found", key);
+ return -1;
+}
+
static int
ldap_dict_pattern_expand(const char *key, const char **value_r, void *_ctx,
const char **error_r)
op->callback_ctx = context;
op->txid = ctx->last_txid++;
op->event = event_create(op->dict->dict.event);
+ op->private = str_begins_with(key, DICT_PATH_PRIVATE);
+ op->username = set->username;
+ op->map = ldap_dict_find_map(ctx, key, &op->pattern_values);
+ p_array_init(&op->attribute_values, op->pool, 2);
- struct dict_ldap_vars_context *pattern_ctx =
- p_new(op->pool, struct dict_ldap_vars_context, 1);
- t_array_init(&pattern_ctx->values, 2);
- pattern_ctx->private = str_begins_with(key, DICT_PATH_PRIVATE);
- if (pattern_ctx->private)
- pattern_ctx->username = set->username;
-
- const struct dict_ldap_map_settings *map = pattern_ctx->set =
- ldap_dict_find_map(ctx, key, &pattern_ctx->values);
-
- if (map != NULL) {
- op->map = map;
-
+ if (op->map != NULL) {
static const struct var_expand_provider providers[] = {
{ "pattern", ldap_dict_pattern_expand },
+ { "ldap", ldap_dict_ldap_expand},
{ NULL, NULL }
};
params->context = op;
params->table = table;
event_set_ptr(op->event, SETTINGS_EVENT_VAR_EXPAND_PARAMS, params);
- if (str_begins_with(key, DICT_PATH_PRIVATE))
- event_add_str(op->event, "user", set->username);
-
struct dict_ldap_map_pre_settings *pre;
- if (settings_get_filter(op->event, "dict_map", map->pattern,
+ if (settings_get_filter(op->event, "dict_map", op->map->pattern,
&dict_ldap_map_pre_setting_parser_info,
0, &pre, &op->res.error) < 0) {
/* build lookup */
i_zero(&input);
- input.base_dn = map->base;
- input.scope = map->parsed_scope;
input.filter = pre->filter;
+ input.base_dn = op->map->base;
+ input.scope = op->map->parsed_scope;
/* Guaranteed to be NULL-terminated by
dict_ldap_map_settings_postcheck() */
- input.attributes = array_front(&map->values);
+ input.attributes =
+ array_is_empty(&op->map->parsed_attributes) ? NULL :
+ array_front(&op->map->parsed_attributes);
ctx->pending++;
ldap_search_start(ctx->client, &input, ldap_dict_lookup_callback, op);
settings_free(pre);