diff options
Diffstat (limited to '')
-rw-r--r-- | src/lib-ldap/ldap-compare.c | 121 |
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; +} |