summaryrefslogtreecommitdiffstats
path: root/src/providers/ipa/ipa_views.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/providers/ipa/ipa_views.c')
-rw-r--r--src/providers/ipa/ipa_views.c653
1 files changed, 653 insertions, 0 deletions
diff --git a/src/providers/ipa/ipa_views.c b/src/providers/ipa/ipa_views.c
new file mode 100644
index 0000000..3e58949
--- /dev/null
+++ b/src/providers/ipa/ipa_views.c
@@ -0,0 +1,653 @@
+/*
+ SSSD
+
+ IPA Identity Backend Module for views and overrides
+
+ Authors:
+ Sumit Bose <sbose@redhat.com>
+
+ Copyright (C) 2014 Red Hat
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "util/util.h"
+#include "util/strtonum.h"
+#include "util/cert.h"
+#include "providers/ldap/sdap_async.h"
+#include "providers/ipa/ipa_id.h"
+#include "db/sysdb.h"
+
+#define MAX_USER_AND_GROUP_REPLIES 2
+
+static errno_t get_user_or_group(TALLOC_CTX *mem_ctx,
+ struct ipa_options *ipa_opts,
+ struct sysdb_attrs *attrs,
+ enum sysdb_obj_type *_what_is)
+{
+ errno_t ret;
+ const char **values;
+ const char **value;
+ bool is_user = false;
+ bool is_group = false;
+ const char *ov_user_name = ipa_opts->override_map[IPA_OC_OVERRIDE_USER].name;
+ const char *ov_group_name = ipa_opts->override_map[IPA_OC_OVERRIDE_GROUP].name;
+
+ ret = sysdb_attrs_get_string_array(attrs, SYSDB_ORIG_OBJECTCLASS, mem_ctx, &values);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "Failed to retrieve attribute [%s].\n",
+ SYSDB_ORIG_OBJECTCLASS);
+ return ret;
+ }
+
+ /* We assume an entry can be a user or a group override but not both.
+ * So we leave as soon as we identify one of them. */
+ if (values != NULL) {
+ for (value = values; *value != NULL; value++) {
+ if (strcasecmp(*value, ov_user_name) == 0) {
+ is_user = true;
+ break;
+ } else if (strcasecmp(*value, ov_group_name) == 0) {
+ is_group = true;
+ break;
+ }
+ }
+ talloc_free(values);
+ }
+
+ /* We also assume it must be necessarily a user or a group. */
+ if (!is_user && !is_group) {
+ DEBUG(SSSDBG_OP_FAILURE, "Unexpected override found.\n");
+ return EINVAL;
+ }
+
+ if (_what_is != NULL) {
+ *_what_is = is_user ? SYSDB_USER : SYSDB_GROUP;
+ }
+
+ return EOK;
+}
+
+/* Verify there are exactly 1 user and 1 group override. Any other combination
+ * is wrong. Then keep only the group override. */
+static errno_t check_and_filter_user_and_group(struct ipa_options *ipa_opts,
+ struct sysdb_attrs **reply,
+ size_t *reply_count)
+{
+ errno_t ret;
+ TALLOC_CTX *tmp_ctx;
+ enum sysdb_obj_type entry_is[MAX_USER_AND_GROUP_REPLIES];
+ int i;
+
+ if (*reply_count != MAX_USER_AND_GROUP_REPLIES) {
+ DEBUG(SSSDBG_TRACE_INTERNAL, "Expected %i replies but got %lu\n",
+ MAX_USER_AND_GROUP_REPLIES, *reply_count);
+ return EINVAL;
+ }
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to allocate memory.\n");
+ return ENOMEM;
+ }
+
+ for (i = 0; i < MAX_USER_AND_GROUP_REPLIES; i++) {
+ ret = get_user_or_group(tmp_ctx, ipa_opts, reply[i], &entry_is[i]);
+ if (ret != EOK) {
+ goto done;
+ }
+ }
+
+ if (entry_is[0] == SYSDB_USER && entry_is[1] == SYSDB_USER) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Found 2 user overrides.\n");
+ ret = EINVAL;
+ goto done;
+ } else if (entry_is[0] == SYSDB_GROUP && entry_is[1] == SYSDB_GROUP) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Found 2 group overrides.\n");
+ ret = EINVAL;
+ goto done;
+ }
+
+ /* We have one user and one group override. Keep only the group override. */
+ DEBUG(SSSDBG_TRACE_INTERNAL, "Keeping only the group override.\n");
+ if (entry_is[0] == SYSDB_USER) {
+ talloc_free(reply[0]);
+ reply[0] = reply[1];
+ } else {
+ talloc_free(reply[1]);
+ }
+ reply[1] = NULL;
+ *reply_count = 1;
+
+done:
+ talloc_free(tmp_ctx);
+
+ return ret;
+}
+
+static errno_t dp_id_data_to_override_filter(TALLOC_CTX *mem_ctx,
+ struct ipa_options *ipa_opts,
+ struct dp_id_data *ar,
+ char **override_filter)
+{
+ char *filter;
+ uint32_t id;
+ char *endptr;
+ char *cert_filter;
+ int ret;
+ char *shortname;
+ char *sanitized_name;
+
+ switch (ar->filter_type) {
+ case BE_FILTER_NAME:
+ ret = sss_parse_internal_fqname(mem_ctx, ar->filter_value,
+ &shortname, NULL);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ ret = sss_filter_sanitize(mem_ctx, shortname, &sanitized_name);
+ talloc_free(shortname);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "sss_filter_sanitize failed.\n");
+ return ret;
+ }
+
+ switch ((ar->entry_type & BE_REQ_TYPE_MASK)) {
+ case BE_REQ_USER:
+ case BE_REQ_INITGROUPS:
+ filter = talloc_asprintf(mem_ctx, "(&(objectClass=%s)(%s=%s))",
+ ipa_opts->override_map[IPA_OC_OVERRIDE_USER].name,
+ ipa_opts->override_map[IPA_AT_OVERRIDE_USER_NAME].name,
+ sanitized_name);
+ break;
+
+ case BE_REQ_GROUP:
+ filter = talloc_asprintf(mem_ctx, "(&(objectClass=%s)(%s=%s))",
+ ipa_opts->override_map[IPA_OC_OVERRIDE_GROUP].name,
+ ipa_opts->override_map[IPA_AT_OVERRIDE_GROUP_NAME].name,
+ sanitized_name);
+ break;
+
+ case BE_REQ_USER_AND_GROUP:
+ filter = talloc_asprintf(mem_ctx,
+ "(|(&(objectClass=%s)(%s=%s))(&(objectClass=%s)(%s=%s)))",
+ ipa_opts->override_map[IPA_OC_OVERRIDE_USER].name,
+ ipa_opts->override_map[IPA_AT_OVERRIDE_USER_NAME].name,
+ sanitized_name,
+ ipa_opts->override_map[IPA_OC_OVERRIDE_GROUP].name,
+ ipa_opts->override_map[IPA_AT_OVERRIDE_GROUP_NAME].name,
+ sanitized_name);
+ break;
+ default:
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected entry type [%d] for name filter.\n",
+ ar->entry_type);
+ talloc_free(sanitized_name);
+ return EINVAL;
+ }
+ talloc_free(sanitized_name);
+ break;
+
+ case BE_FILTER_IDNUM:
+ id = strtouint32(ar->filter_value, &endptr, 10);
+ if (errno != 0|| *endptr != '\0' || (ar->filter_value == endptr)) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Invalid id value [%s].\n",
+ ar->filter_value);
+ return EINVAL;
+ }
+ switch ((ar->entry_type & BE_REQ_TYPE_MASK)) {
+ case BE_REQ_USER:
+ case BE_REQ_INITGROUPS:
+ filter = talloc_asprintf(mem_ctx, "(&(objectClass=%s)(%s=%"PRIu32"))",
+ ipa_opts->override_map[IPA_OC_OVERRIDE_USER].name,
+ ipa_opts->override_map[IPA_AT_OVERRIDE_UID_NUMBER].name,
+ id);
+ break;
+
+ case BE_REQ_GROUP:
+ filter = talloc_asprintf(mem_ctx,
+ "(&(objectClass=%s)(%s=%"PRIu32"))",
+ ipa_opts->override_map[IPA_OC_OVERRIDE_GROUP].name,
+ ipa_opts->override_map[IPA_AT_OVERRIDE_GROUP_GID_NUMBER].name,
+ id);
+ break;
+
+ case BE_REQ_USER_AND_GROUP:
+ filter = talloc_asprintf(mem_ctx,
+ "(|(&(objectClass=%s)(%s=%"PRIu32"))(&(objectClass=%s)(%s=%"PRIu32")))",
+ ipa_opts->override_map[IPA_OC_OVERRIDE_USER].name,
+ ipa_opts->override_map[IPA_AT_OVERRIDE_UID_NUMBER].name,
+ id,
+ ipa_opts->override_map[IPA_OC_OVERRIDE_GROUP].name,
+ ipa_opts->override_map[IPA_AT_OVERRIDE_GROUP_GID_NUMBER].name,
+ id);
+ break;
+ default:
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Unexpected entry type [%d] for id filter.\n",
+ ar->entry_type);
+ return EINVAL;
+ }
+ break;
+
+ case BE_FILTER_SECID:
+ if ((ar->entry_type & BE_REQ_TYPE_MASK) == BE_REQ_BY_SECID) {
+ filter = talloc_asprintf(mem_ctx, "(&(objectClass=%s)(%s=:SID:%s))",
+ ipa_opts->override_map[IPA_OC_OVERRIDE].name,
+ ipa_opts->override_map[IPA_AT_OVERRIDE_ANCHOR_UUID].name,
+ ar->filter_value);
+ } else {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Unexpected entry type [%d] for SID filter.\n",
+ ar->entry_type);
+ return EINVAL;
+ }
+ break;
+
+ case BE_FILTER_UUID:
+ if ((ar->entry_type & BE_REQ_TYPE_MASK) == BE_REQ_BY_UUID) {
+ filter = talloc_asprintf(mem_ctx, "(&(objectClass=%s)(%s=:IPA:%s:%s))",
+ ipa_opts->override_map[IPA_OC_OVERRIDE].name,
+ ipa_opts->override_map[IPA_AT_OVERRIDE_ANCHOR_UUID].name,
+ dp_opt_get_string(ipa_opts->basic, IPA_DOMAIN),
+ ar->filter_value);
+ } else {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Unexpected entry type [%d] for UUID filter.\n",
+ ar->entry_type);
+ return EINVAL;
+ }
+ break;
+
+ case BE_FILTER_CERT:
+ if ((ar->entry_type & BE_REQ_TYPE_MASK) == BE_REQ_BY_CERT) {
+ ret = sss_cert_derb64_to_ldap_filter(mem_ctx, ar->filter_value,
+ ipa_opts->override_map[IPA_AT_OVERRIDE_USER_CERT].name,
+ NULL, NULL, &cert_filter);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "sss_cert_derb64_to_ldap_filter failed.\n");
+ return ret;
+ }
+ filter = talloc_asprintf(mem_ctx, "(&(objectClass=%s)%s)",
+ ipa_opts->override_map[IPA_OC_OVERRIDE_USER].name,
+ cert_filter);
+ talloc_free(cert_filter);
+ } else {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Unexpected entry type [%d] for certificate filter.\n",
+ ar->entry_type);
+ return EINVAL;
+ }
+ break;
+
+ default:
+ DEBUG(SSSDBG_OP_FAILURE, "Invalid sub-domain filter type.\n");
+ return EINVAL;
+ }
+
+ if (filter == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
+ return ENOMEM;
+ }
+
+ *override_filter = filter;
+
+ return EOK;
+}
+
+static errno_t get_dp_id_data_for_xyz(TALLOC_CTX *mem_ctx, const char *val,
+ const char *domain_name,
+ int type,
+ struct dp_id_data **_ar)
+{
+ struct dp_id_data *ar;
+
+ ar = talloc_zero(mem_ctx, struct dp_id_data);
+ if (ar == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n");
+ return ENOMEM;
+ }
+
+ switch (type) {
+ case BE_REQ_BY_SECID:
+ ar->entry_type = BE_REQ_BY_SECID;
+ ar->filter_type = BE_FILTER_SECID;
+ break;
+ case BE_REQ_BY_UUID:
+ ar->entry_type = BE_REQ_BY_UUID;
+ ar->filter_type = BE_FILTER_UUID;
+ break;
+ case BE_REQ_USER:
+ ar->entry_type = BE_REQ_USER;
+ ar->filter_type = BE_FILTER_NAME;
+ break;
+ default:
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported request type [%d].\n", type);
+ talloc_free(ar);
+ return EINVAL;
+ }
+
+ ar->filter_value = talloc_strdup(ar, val);
+ ar->domain = talloc_strdup(ar, domain_name);
+ if (ar->filter_value == NULL || ar->domain == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup failed.\n");
+ talloc_free(ar);
+ return ENOMEM;
+ }
+
+
+ *_ar = ar;
+
+ return EOK;
+}
+
+errno_t get_dp_id_data_for_sid(TALLOC_CTX *mem_ctx, const char *sid,
+ const char *domain_name,
+ struct dp_id_data **_ar)
+{
+ return get_dp_id_data_for_xyz(mem_ctx, sid, domain_name, BE_REQ_BY_SECID,
+ _ar);
+}
+
+errno_t get_dp_id_data_for_uuid(TALLOC_CTX *mem_ctx, const char *uuid,
+ const char *domain_name,
+ struct dp_id_data **_ar)
+{
+ return get_dp_id_data_for_xyz(mem_ctx, uuid, domain_name, BE_REQ_BY_UUID,
+ _ar);
+}
+
+errno_t get_dp_id_data_for_user_name(TALLOC_CTX *mem_ctx,
+ const char *user_name,
+ const char *domain_name,
+ struct dp_id_data **_ar)
+{
+ return get_dp_id_data_for_xyz(mem_ctx, user_name, domain_name, BE_REQ_USER,
+ _ar);
+}
+
+struct ipa_get_ad_override_state {
+ struct tevent_context *ev;
+ struct sdap_id_ctx *sdap_id_ctx;
+ struct ipa_options *ipa_options;
+ const char *ipa_realm;
+ const char *ipa_view_name;
+ struct dp_id_data *ar;
+
+ struct sdap_id_op *sdap_op;
+ int dp_error;
+ struct sysdb_attrs *override_attrs;
+ char *filter;
+};
+
+static void ipa_get_ad_override_connect_done(struct tevent_req *subreq);
+static errno_t ipa_get_ad_override_qualify_name(
+ struct ipa_get_ad_override_state *state);
+static void ipa_get_ad_override_done(struct tevent_req *subreq);
+
+struct tevent_req *ipa_get_ad_override_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct sdap_id_ctx *sdap_id_ctx,
+ struct ipa_options *ipa_options,
+ const char *ipa_realm,
+ const char *view_name,
+ struct dp_id_data *ar)
+{
+ int ret;
+ struct tevent_req *req;
+ struct tevent_req *subreq;
+ struct ipa_get_ad_override_state *state;
+
+ req = tevent_req_create(mem_ctx, &state, struct ipa_get_ad_override_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "tevent_req_create failed.\n");
+ return NULL;
+ }
+
+ state->ev = ev;
+ state->sdap_id_ctx = sdap_id_ctx;
+ state->ipa_options = ipa_options;
+ state->ipa_realm = ipa_realm;
+ state->ar = ar;
+ state->dp_error = -1;
+ state->override_attrs = NULL;
+ state->filter = NULL;
+
+ if (view_name == NULL) {
+ DEBUG(SSSDBG_TRACE_ALL, "View not defined, nothing to do.\n");
+ ret = EOK;
+ goto done;
+ }
+
+ if (is_default_view(view_name)) {
+ state->ipa_view_name = IPA_DEFAULT_VIEW_NAME;
+ } else {
+ state->ipa_view_name = view_name;
+ }
+
+ state->sdap_op = sdap_id_op_create(state,
+ state->sdap_id_ctx->conn->conn_cache);
+ if (state->sdap_op == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ subreq = sdap_id_op_connect_send(state->sdap_op, state, &ret);
+ if (subreq == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_connect_send failed: %d(%s).\n",
+ ret, strerror(ret));
+ goto done;
+ }
+
+ tevent_req_set_callback(subreq, ipa_get_ad_override_connect_done, req);
+
+ return req;
+
+done:
+ if (ret != EOK) {
+ state->dp_error = DP_ERR_FATAL;
+ tevent_req_error(req, ret);
+ } else {
+ state->dp_error = DP_ERR_OK;
+ tevent_req_done(req);
+ }
+ tevent_req_post(req, state->ev);
+
+ return req;
+}
+
+static void ipa_get_ad_override_connect_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct ipa_get_ad_override_state *state = tevent_req_data(req,
+ struct ipa_get_ad_override_state);
+ int ret;
+ char *basedn;
+ char *search_base;
+ struct ipa_options *ipa_opts = state->ipa_options;
+
+ ret = sdap_id_op_connect_recv(subreq, &state->dp_error);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ if (state->dp_error == DP_ERR_OFFLINE) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "No IPA server is available, going offline\n");
+ } else {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Failed to connect to IPA server: [%d](%s)\n",
+ ret, strerror(ret));
+ }
+
+ goto fail;
+ }
+
+ ret = domain_to_basedn(state, state->ipa_realm, &basedn);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "domain_to_basedn failed.\n");
+ goto fail;
+ }
+
+ search_base = talloc_asprintf(state, "cn=%s,%s", state->ipa_view_name,
+ ipa_opts->views_search_bases[0]->basedn);
+ if (search_base == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ ret = dp_id_data_to_override_filter(state, state->ipa_options, state->ar,
+ &state->filter);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "dp_id_data_to_override_filter failed.\n");
+ goto fail;
+ }
+
+ DEBUG(SSSDBG_TRACE_ALL,
+ "Searching for overrides in view [%s] with filter [%s].\n",
+ state->ipa_view_name, state->filter);
+
+ subreq = sdap_get_generic_send(state, state->ev, state->sdap_id_ctx->opts,
+ sdap_id_op_handle(state->sdap_op), search_base,
+ LDAP_SCOPE_SUBTREE,
+ state->filter, NULL,
+ state->ipa_options->override_map,
+ IPA_OPTS_OVERRIDE,
+ dp_opt_get_int(state->sdap_id_ctx->opts->basic,
+ SDAP_SEARCH_TIMEOUT),
+ false);
+ if (subreq == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "sdap_get_generic_send failed.\n");
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ tevent_req_set_callback(subreq, ipa_get_ad_override_done, req);
+ return;
+
+fail:
+ state->dp_error = DP_ERR_FATAL;
+ tevent_req_error(req, ret);
+ return;
+}
+
+static void ipa_get_ad_override_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct ipa_get_ad_override_state *state = tevent_req_data(req,
+ struct ipa_get_ad_override_state);
+ int ret;
+ size_t reply_count = 0;
+ struct sysdb_attrs **reply = NULL;
+
+ ret = sdap_get_generic_recv(subreq, state, &reply_count, &reply);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "ipa_get_ad_override request failed.\n");
+ goto fail;
+ }
+
+ if (reply_count == 0) {
+ DEBUG(SSSDBG_TRACE_ALL, "No override found with filter [%s].\n",
+ state->filter);
+ state->dp_error = DP_ERR_OK;
+ tevent_req_done(req);
+ return;
+ } else if (reply_count == MAX_USER_AND_GROUP_REPLIES &&
+ (state->ar->entry_type & BE_REQ_TYPE_MASK) == BE_REQ_USER_AND_GROUP) {
+ DEBUG(SSSDBG_TRACE_ALL,
+ "Found two overrides with BE_REQ_USER_AND_GROUP filter [%s].\n",
+ state->filter);
+ ret = check_and_filter_user_and_group(state->ipa_options, reply,
+ &reply_count);
+ if (ret != EOK) {
+ goto fail;
+ }
+ } else if (reply_count > 1) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Found [%zu] overrides with filter [%s], expected only 1.\n",
+ reply_count, state->filter);
+ ret = EINVAL;
+ goto fail;
+ }
+
+ DEBUG(SSSDBG_TRACE_ALL, "Found override for object with filter [%s].\n",
+ state->filter);
+ state->override_attrs = reply[0];
+
+ ret = ipa_get_ad_override_qualify_name(state);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot qualify object name\n");
+ goto fail;
+ }
+
+ state->dp_error = DP_ERR_OK;
+ tevent_req_done(req);
+ return;
+
+fail:
+ state->dp_error = DP_ERR_FATAL;
+ tevent_req_error(req, ret);
+ return;
+}
+
+static errno_t ipa_get_ad_override_qualify_name(
+ struct ipa_get_ad_override_state *state)
+{
+ int ret;
+ struct ldb_message_element *name;
+ char *fqdn;
+
+ ret = sysdb_attrs_get_el_ext(state->override_attrs, SYSDB_NAME,
+ false, &name);
+ if (ret == ENOENT) {
+ return EOK; /* Does not override name */
+ } else if (ret != EOK && ret != ENOENT) {
+ return ret;
+ }
+
+ fqdn = sss_create_internal_fqname(name->values,
+ (const char *) name->values[0].data,
+ state->ar->domain);
+ if (fqdn == NULL) {
+ return ENOMEM;
+ }
+
+ name->values[0].data = (uint8_t *) fqdn;
+ name->values[0].length = strlen(fqdn);
+ return EOK;
+}
+
+errno_t ipa_get_ad_override_recv(struct tevent_req *req, int *dp_error_out,
+ TALLOC_CTX *mem_ctx,
+ struct sysdb_attrs **override_attrs)
+{
+ struct ipa_get_ad_override_state *state = tevent_req_data(req,
+ struct ipa_get_ad_override_state);
+
+ if (dp_error_out != NULL) {
+ *dp_error_out = state->dp_error;
+ }
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ if (override_attrs != NULL) {
+ *override_attrs = talloc_steal(mem_ctx, state->override_attrs);
+ }
+
+ return EOK;
+}