summaryrefslogtreecommitdiffstats
path: root/src/lib-ldap/ldap-compare.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/lib-ldap/ldap-compare.c121
1 files changed, 121 insertions, 0 deletions
diff --git a/src/lib-ldap/ldap-compare.c b/src/lib-ldap/ldap-compare.c
new file mode 100644
index 0000000..9b17373
--- /dev/null
+++ b/src/lib-ldap/ldap-compare.c
@@ -0,0 +1,121 @@
+/* Copyright (c) 2016-2018 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "ldap-private.h"
+
+static int
+ldap_compare_callback(struct ldap_connection *conn,
+ struct ldap_op_queue_entry *req,
+ LDAPMessage *message, bool *finished_r)
+{
+ int msgtype = ldap_msgtype(message);
+ struct ldap_result res;
+ char *result_errmsg;
+ int ret, result_err;
+
+ if (msgtype != LDAP_RES_COMPARE) {
+ *finished_r = FALSE;
+ return 0;
+ }
+ *finished_r = TRUE;
+
+ ret = ldap_parse_result(conn->conn, message,
+ &result_err, NULL,
+ &result_errmsg, NULL, NULL, 0);
+ i_zero(&res);
+ res.openldap_ret = ret;
+ if (ret != LDAP_SUCCESS) {
+ res.error_string = t_strdup_printf(
+ "ldap_parse_result() failed to parse compare: %s",
+ ldap_err2string(ret));
+ } else if (result_err == LDAP_COMPARE_TRUE) {
+ res.compare_true = TRUE;
+ } else if (result_err == LDAP_COMPARE_FALSE) {
+ res.compare_true = FALSE;
+ } else {
+ const struct ldap_compare_input *input = &req->input.compare;
+ const char *error = result_errmsg != NULL ?
+ result_errmsg : ldap_err2string(result_err);
+ res.openldap_ret = result_err;
+ res.error_string = t_strdup_printf(
+ "ldap_compare_ext(dn=%s, attr=%s) failed: %s",
+ input->dn, input->attr, error);
+ }
+
+ req->result_callback(&res, req->result_callback_ctx);
+
+ if (result_errmsg != NULL)
+ ldap_memfree(result_errmsg);
+ return res.openldap_ret;
+}
+
+static int
+ldap_compare_send(struct ldap_connection *conn, struct ldap_op_queue_entry *req,
+ const char **error_r)
+{
+ const struct ldap_compare_input *input = &req->input.compare;
+ struct berval bv = {
+ .bv_len = strlen(input->value),
+ .bv_val = (void*)input->value
+ };
+
+ LDAPControl manageDSAIT = {
+ LDAP_CONTROL_MANAGEDSAIT, {0, 0}, 0
+ };
+
+ /* try to use ManageDSAIT if available */
+ LDAPControl *sctrls[] = {
+ &manageDSAIT,
+ NULL
+ };
+
+ int ret = ldap_compare_ext(conn->conn,
+ input->dn,
+ input->attr,
+ &bv,
+ sctrls,
+ NULL,
+ &(req->msgid));
+
+ if (ret != LDAP_SUCCESS) {
+ *error_r = t_strdup_printf(
+ "ldap_compare_ext(dn=%s, attr=%s) failed: %s",
+ input->dn, input->attr, ldap_err2string(ret));
+ }
+ return ret;
+}
+
+void ldap_connection_compare_start(struct ldap_connection *conn,
+ const struct ldap_compare_input *input,
+ ldap_result_callback_t *callback,
+ void *context)
+{
+ struct ldap_op_queue_entry *req;
+ pool_t pool = pool_alloconly_create(MEMPOOL_GROWING "ldap compare", 128);
+ req = p_new(pool, struct ldap_op_queue_entry, 1);
+ req->pool = pool;
+
+ req->internal_response_cb = ldap_compare_callback;
+
+ req->input.compare = *input;
+ req->result_callback = callback;
+ req->result_callback_ctx = context;
+
+ /* copy strings */
+ req->input.compare.dn = p_strdup(req->pool, input->dn);
+ req->input.compare.attr = p_strdup(req->pool, input->attr);
+ req->input.compare.value = p_strdup(req->pool, input->value);
+
+ req->send_request_cb = ldap_compare_send;
+ req->timeout_secs = input->timeout_secs;
+
+ ldap_connection_queue_request(conn, req);
+}
+
+bool ldap_compare_result(struct ldap_result *result)
+{
+ i_assert(result->openldap_ret == LDAP_SUCCESS);
+ i_assert(result->error_string == NULL);
+
+ return result->compare_true;
+}