summaryrefslogtreecommitdiffstats
path: root/src/auth/passdb-dict.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/auth/passdb-dict.c')
-rw-r--r--src/auth/passdb-dict.c186
1 files changed, 186 insertions, 0 deletions
diff --git a/src/auth/passdb-dict.c b/src/auth/passdb-dict.c
new file mode 100644
index 0000000..f264035
--- /dev/null
+++ b/src/auth/passdb-dict.c
@@ -0,0 +1,186 @@
+/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
+
+#include "auth-common.h"
+#include "passdb.h"
+
+#include "array.h"
+#include "str.h"
+#include "var-expand.h"
+#include "dict.h"
+#include "password-scheme.h"
+#include "auth-cache.h"
+#include "db-dict.h"
+
+#include <string.h>
+
+struct dict_passdb_module {
+ struct passdb_module module;
+
+ struct dict_connection *conn;
+};
+
+struct passdb_dict_request {
+ struct auth_request *auth_request;
+ union {
+ verify_plain_callback_t *verify_plain;
+ lookup_credentials_callback_t *lookup_credentials;
+ } callback;
+};
+
+static int
+dict_query_save_results(struct auth_request *auth_request,
+ struct dict_connection *conn,
+ struct db_dict_value_iter *iter)
+{
+ const char *key, *value, *error;
+
+ while (db_dict_value_iter_next(iter, &key, &value)) {
+ if (value != NULL) {
+ auth_request_set_field(auth_request, key, value,
+ conn->set.default_pass_scheme);
+ }
+ }
+ if (db_dict_value_iter_deinit(&iter, &error) < 0) {
+ e_error(authdb_event(auth_request), "%s", error);
+ return -1;
+ }
+ return 0;
+}
+
+static enum passdb_result
+passdb_dict_lookup_key(struct auth_request *auth_request,
+ struct dict_passdb_module *module)
+{
+ struct db_dict_value_iter *iter;
+ int ret;
+
+ ret = db_dict_value_iter_init(module->conn, auth_request,
+ &module->conn->set.passdb_fields,
+ &module->conn->set.parsed_passdb_objects,
+ &iter);
+ if (ret < 0)
+ return PASSDB_RESULT_INTERNAL_FAILURE;
+ else if (ret == 0) {
+ auth_request_log_unknown_user(auth_request, AUTH_SUBSYS_DB);
+ return PASSDB_RESULT_USER_UNKNOWN;
+ } else {
+ if (dict_query_save_results(auth_request, module->conn, iter) < 0)
+ return PASSDB_RESULT_INTERNAL_FAILURE;
+
+ if (auth_request->passdb_password == NULL &&
+ !auth_fields_exists(auth_request->fields.extra_fields,
+ "nopassword")) {
+ return auth_request_password_missing(auth_request);
+ } else {
+ return PASSDB_RESULT_OK;
+ }
+ }
+}
+
+static void passdb_dict_lookup_pass(struct passdb_dict_request *dict_request)
+{
+ struct auth_request *auth_request = dict_request->auth_request;
+ struct passdb_module *_module = auth_request->passdb->passdb;
+ struct dict_passdb_module *module =
+ (struct dict_passdb_module *)_module;
+ const char *password = NULL, *scheme = NULL;
+ enum passdb_result passdb_result;
+ int ret;
+
+ if (array_count(&module->conn->set.passdb_fields) == 0 &&
+ array_count(&module->conn->set.parsed_passdb_objects) == 0) {
+ e_error(authdb_event(auth_request),
+ "No passdb_objects or passdb_fields specified");
+ passdb_result = PASSDB_RESULT_INTERNAL_FAILURE;
+ } else {
+ passdb_result = passdb_dict_lookup_key(auth_request, module);
+ }
+
+ if (passdb_result == PASSDB_RESULT_OK) {
+ /* passdb_password may change on the way,
+ so we'll need to strdup. */
+ password = t_strdup(auth_request->passdb_password);
+ scheme = password_get_scheme(&password);
+ /* auth_request_set_field() sets scheme */
+ i_assert(password == NULL || scheme != NULL);
+ }
+
+ if (auth_request->wanted_credentials_scheme != NULL) {
+ passdb_handle_credentials(passdb_result, password, scheme,
+ dict_request->callback.lookup_credentials,
+ auth_request);
+ } else {
+ if (password != NULL) {
+ ret = auth_request_password_verify(auth_request,
+ auth_request->mech_password,
+ password, scheme, AUTH_SUBSYS_DB);
+ passdb_result = ret > 0 ? PASSDB_RESULT_OK :
+ PASSDB_RESULT_PASSWORD_MISMATCH;
+ }
+
+ dict_request->callback.verify_plain(passdb_result,
+ auth_request);
+ }
+}
+
+static void dict_verify_plain(struct auth_request *request,
+ const char *password ATTR_UNUSED,
+ verify_plain_callback_t *callback)
+{
+ struct passdb_dict_request *dict_request;
+
+ dict_request = p_new(request->pool, struct passdb_dict_request, 1);
+ dict_request->auth_request = request;
+ dict_request->callback.verify_plain = callback;
+
+ passdb_dict_lookup_pass(dict_request);
+}
+
+static void dict_lookup_credentials(struct auth_request *request,
+ lookup_credentials_callback_t *callback)
+{
+ struct passdb_dict_request *dict_request;
+
+ dict_request = p_new(request->pool, struct passdb_dict_request, 1);
+ dict_request->auth_request = request;
+ dict_request->callback.lookup_credentials = callback;
+
+ passdb_dict_lookup_pass(dict_request);
+}
+
+static struct passdb_module *
+passdb_dict_preinit(pool_t pool, const char *args)
+{
+ struct dict_passdb_module *module;
+ struct dict_connection *conn;
+
+ module = p_new(pool, struct dict_passdb_module, 1);
+ module->conn = conn = db_dict_init(args);
+
+ module->module.blocking = TRUE;
+ module->module.default_cache_key = auth_cache_parse_key(pool,
+ db_dict_parse_cache_key(&conn->set.keys, &conn->set.passdb_fields,
+ &conn->set.parsed_passdb_objects));
+ module->module.default_pass_scheme = conn->set.default_pass_scheme;
+ return &module->module;
+}
+
+static void passdb_dict_deinit(struct passdb_module *_module)
+{
+ struct dict_passdb_module *module =
+ (struct dict_passdb_module *)_module;
+
+ db_dict_unref(&module->conn);
+}
+
+struct passdb_module_interface passdb_dict = {
+ "dict",
+
+ passdb_dict_preinit,
+ NULL,
+ passdb_dict_deinit,
+
+ dict_verify_plain,
+ dict_lookup_credentials,
+ NULL
+};