summaryrefslogtreecommitdiffstats
path: root/src/lib-ldap/ldap-compare.c
blob: 9b17373e995112dea47df2f811d80bfba4353ffb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
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;
}