DEF(STR, base),
DEF(UINT, version),
DEF(STR, debug_level),
- DEF(STR, user_attrs),
DEF(STR, user_filter),
- DEF(STR, pass_attrs),
DEF(STR, pass_filter),
- DEF(STR, iterate_attrs),
+ DEF(STRLIST, iterate_attrs),
DEF(STR, iterate_filter),
SETTING_DEFINE_LIST_END
};
.base = "",
.version = 3,
.debug_level = "0",
- .user_attrs = "homeDirectory=home,uidNumber=uid,gidNumber=gid",
- .user_filter = "(&(objectClass=posixAccount)(uid=%u))",
- .pass_attrs = "uid=user,userPassword=password",
- .pass_filter = "(&(objectClass=posixAccount)(uid=%u))",
- .iterate_attrs = "uid=user",
- .iterate_filter = "(objectClass=posixAccount)",
+ .user_filter = "",
+ .pass_filter = "",
+ .iterate_attrs = ARRAY_INIT,
+ .iterate_filter = "",
};
static const struct setting_keyvalue ldap_default_settings_keyvalue[] = {
{ "passdb_ldap/passdb_default_password_scheme", "crypt" },
+ { "passdb_ldap/passdb_fields_import_all", "no" },
+ { "userdb_ldap/userdb_fields_import_all", "no" },
{ NULL, NULL }
};
const char *debug_level;
- const char *user_attrs;
const char *user_filter;
- const char *pass_attrs;
const char *pass_filter;
- const char *iterate_attrs;
const char *iterate_filter;
+ ARRAY_TYPE(const_string) iterate_attrs;
+
unsigned int version;
uid_t uid;
return 1;
}
-const char *const *db_ldap_parse_attrs(const char *cstr)
-{
- ARRAY_TYPE(const_string) entries;
- t_array_init(&entries, 32);
-
- char *ptr = t_strdup_noconst(cstr);
- const char *start = ptr;
- unsigned int nesting = 0;
- while (*ptr != '\0') {
- switch (*ptr) {
- case '{':
- nesting++;
- ptr++;
- break;
- case '}':
- if (nesting > 0)
- nesting--;
- ptr++;
- break;
- case ',':
- if (nesting > 0)
- ptr++;
- else {
- *ptr = '\0';
- if (*start != '\0')
- array_push_back(&entries, &start);
- start = ++ptr;
- }
- break;
- default:
- ptr++;
- break;
- }
- }
- if (*start != '\0')
- array_push_back(&entries, &start);
-
- unsigned int count ATTR_UNUSED;
- array_append_zero(&entries);
- return array_get(&entries, &count);
-}
-
-void db_ldap_set_attrs(struct ldap_connection *conn, const char *attrlist,
+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)
{
{ "ldap_ptr", db_ldap_field_find },
{ NULL, NULL }
};
- struct ldap_field_find_context ctx;
- struct ldap_field *field;
- string_t *tmp_str;
- const char *const *attr, *attr_data, *p, *error;
- char *ldap_attr, *name, *templ;
- unsigned int i;
- attr = db_ldap_parse_attrs(attrlist);
- if (*attr == NULL)
- return;
+ unsigned int count = array_is_empty(attrlist) ? 0 : array_count(attrlist);
+ i_assert(count % 2 == 0);
- tmp_str = t_str_new(128);
+ struct ldap_field_find_context ctx;
ctx.pool = conn->pool;
- p_array_init(&ctx.attr_names, conn->pool, 16);
- for (i = 0; attr[i] != NULL; i++) {
- /* allow spaces here so "foo=1, bar=2" works */
- attr_data = attr[i];
- while (*attr_data == ' ') attr_data++;
-
- p = strchr(attr_data, '=');
- if (p == NULL)
- 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);
+ p_array_init(&ctx.attr_names, conn->pool, count / 2);
+ 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;
}
- templ = strchr(name, '=');
+ 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,
}
if (*name == '\0')
- e_error(conn->event, "Invalid attrs entry: %s", attr_data);
+ e_error(conn->event, "Invalid empty attribute name");
else if (skip_attr == NULL || strcmp(skip_attr, name) != 0) {
- field = array_append_space(attr_map);
+ struct ldap_field *field = array_append_space(attr_map);
if (name[0] == '!' && name == ldap_attr) {
/* !ldapAttr */
name = "";
struct ldap_connection *db_ldap_init(struct event *event)
{
- const struct ldap_settings *set;
+ const struct ldap_settings *set;
const struct ssl_settings *ssl_set;
const char *error;
void db_ldap_request(struct ldap_connection *conn,
struct ldap_request *request);
-void db_ldap_set_attrs(struct ldap_connection *conn, const char *attrlist,
+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);
#include "str.h"
#include "password-scheme.h"
#include "auth-cache.h"
+#include "settings.h"
+#include "auth-settings.h"
#include "db-ldap.h"
#include <ldap.h>
} callback;
unsigned int entries;
- bool require_password;
+ bool require_password:1;
+ bool failed:1;
};
-static void
+static int
ldap_query_save_result(struct ldap_connection *conn,
struct auth_request *auth_request,
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;
_module->default_pass_scheme);
}
db_ldap_result_iterate_deinit(&ldap_iter);
+ return auth_request_set_passdb_fields(auth_request, fields);
}
static void
enum passdb_result passdb_result;
const char *password = NULL, *scheme;
- if (res == NULL) {
+ if (res == NULL || ldap_request->failed) {
passdb_result = PASSDB_RESULT_INTERNAL_FAILURE;
} else if (ldap_request->entries == 0) {
passdb_result = PASSDB_RESULT_USER_UNKNOWN;
if (ldap_request->entries++ == 0) {
/* first entry */
- ldap_query_save_result(conn, auth_request,
- &ldap_request->request.search, res);
+ if (ldap_query_save_result(conn, auth_request,
+ &ldap_request->request.search, res) < 0)
+ ldap_request->failed = TRUE;
}
}
static int passdb_ldap_preinit(pool_t pool, struct event *event,
struct passdb_module **module_r,
- const char **error_r ATTR_UNUSED)
+ const char **error_r)
{
+ const struct auth_passdb_post_settings *set;
struct ldap_passdb_module *module;
struct ldap_connection *conn;
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);
- db_ldap_set_attrs(conn, conn->set->pass_attrs, &conn->pass_attr_names,
+ 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);
- module->module.default_cache_key =
- auth_cache_parse_key(pool,
- t_strconcat(conn->set->base,
- conn->set->pass_attrs,
- conn->set->pass_filter, NULL));
+ module->module.default_cache_key = auth_cache_parse_key_and_fields(
+ pool, conn->set->base, &set->fields, NULL);
+
+ settings_free(set);
*module_r = &module->module;
return 0;
}
#endif
{
.name = "ldap",
+ .fields_supported = TRUE,
.preinit = passdb_ldap_preinit,
.init = passdb_ldap_init,
void passdb_mock_mod_init(void);
void passdb_mock_mod_deinit(void);
-void test_db_ldap_parse_attrs(void);
void test_db_ldap_field_multi_expand_parse_data(void);
void test_auth_init(void);
#include "db-ldap.h"
#include <stdio.h>
-void test_db_ldap_parse_attrs(void)
-{
- struct vectors {
- const char *inp;
- const char *out;
- } vectors[] = {
- { .inp = "", .out = ""},
- { .inp = "a", .out = "a"},
-
- /* tests with leading/trailing/no spaces*/
- { .inp = "a,b,c", .out = "a|b|c"},
- { .inp = "a, b, c", .out = "a| b| c"},
- { .inp = "a ,b ,c", .out = "a |b |c"},
-
- /* leading empty field */
- { .inp = ",a,b", .out = "a|b"},
- /* trailing empty field */
- { .inp = "a,b,", .out = "a|b"},
- /* middle empty field */
- { .inp = "a,,b", .out = "a|b"},
-
-
- /* simple nesting at begining/end of field */
- { .inp = "a,{b,c},d", .out = "a|{b,c}|d"},
-
- /* simple nesting in the middle of the field */
- { .inp = "a,b{c,d}e,f", .out = "a|b{c,d}e|f"},
-
- /* multiple nesting, balanced, prefixed and suffixed */
- { .inp = "a, {{b, c}, d}, e", .out = "a| {{b, c}, d}| e"},
- { .inp = "a, {b, {c, d}}, e", .out = "a| {b, {c, d}}| e"},
-
- /* unbalanced nesting, excess of {s */
- { .inp = "{", .out = "{"},
- { .inp = "a, {b, {c, d}, e", .out = "a| {b, {c, d}, e"},
-
- /* unbalanced nesting, excess of }s */
- { .inp = "}", .out = "}"},
- { .inp = "a, {b, {c, d}}}, e", .out = "a| {b, {c, d}}}| e"},
-
- {}
- };
-
- test_begin("db ldap parse attrs");
- unsigned int index = 0;
- for (struct vectors *vector = vectors; vector->inp != NULL; vector++, index++) {
- const char *const *array = db_ldap_parse_attrs(vector->inp);
- const char *out = t_strarray_join(array, "|");
- test_assert_strcmp_idx(vector->out, out, index);
- }
- test_end();
-}
-
void test_db_ldap_field_multi_expand_parse_data(void)
{
struct vectors {
int ret;
static const struct named_test test_functions[] = {
#if defined(BUILTIN_LDAP) || defined(PLUGIN_BUILD)
- TEST_NAMED(test_db_ldap_parse_attrs)
TEST_NAMED(test_db_ldap_field_multi_expand_parse_data)
#endif
TEST_NAMED(test_auth_request_var_expand)
#include "array.h"
#include "str.h"
#include "auth-cache.h"
+#include "settings.h"
+#include "auth-settings.h"
#include "db-ldap.h"
#include <ldap.h>
struct ldap_request_search request;
userdb_callback_t *userdb_callback;
unsigned int entries;
+ bool failed:1;
};
struct userdb_iter_ldap_request {
bool continued, in_callback, deinitialized;
};
-static void
+static int
ldap_query_get_result(struct ldap_connection *conn,
struct auth_request *auth_request,
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);
}
static void
{
enum userdb_result result = USERDB_RESULT_INTERNAL_FAILURE;
- if (res == NULL) {
+ if (res == NULL || urequest->failed) {
result = USERDB_RESULT_INTERNAL_FAILURE;
} else if (urequest->entries == 0) {
result = USERDB_RESULT_USER_UNKNOWN;
if (urequest->entries++ == 0) {
/* first entry */
- ldap_query_get_result(conn, auth_request,
- &urequest->request, res);
+ if (ldap_query_get_result(conn, auth_request,
+ &urequest->request, res) < 0)
+ urequest->failed = TRUE;
}
}
struct userdb_module **module_r,
const char **error_r ATTR_UNUSED)
{
+ const struct auth_passdb_post_settings *set;
struct ldap_userdb_module *module;
struct ldap_connection *conn;
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, conn->set->user_attrs, &conn->user_attr_names,
+ 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,
+ db_ldap_set_attrs(conn, &conn->set->iterate_attrs,
&conn->iterate_attr_names,
&conn->iterate_attr_map, NULL);
- module->module.default_cache_key =
- auth_cache_parse_key(pool,
- t_strconcat(conn->set->base,
- conn->set->user_attrs,
- conn->set->user_filter, NULL));
+ module->module.default_cache_key = auth_cache_parse_key_and_fields(
+ pool, conn->set->base, &set->fields, NULL);
+
+ settings_free(set);
*module_r = &module->module;
return 0;
}
#endif
{
.name = "ldap",
+ .fields_supported = TRUE,
.preinit = userdb_ldap_preinit,
.init = userdb_ldap_init,