/* 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; }