/
githubmirror
/
sssd
Обзор
Документация
Войти
/
githubmirror
/
sssd
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/providers/ad/ad_pac.c
457 строк
15 KB
Sumit Bose
ad: move ad_get_sids_from_pac() to ad_pac_common.c
20 апр 2026, 14:06
20 апр 2026, 14:06
3f9c415
Код
Авторство
О чём код?
/* SSSD Authors: Sumit Bose <sbose@redhat.com> Copyright (C) 2016 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 "providers/ad/ad_pac.h" #include "providers/ad/ad_common.h" #include "providers/ad/ad_id.h" #include "providers/ldap/sdap_idmap.h" #include "providers/ldap/sdap_async_ad.h" static errno_t find_user_entry(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom, struct dp_id_data *ar, struct ldb_message **_msg) { const char *user_attrs[] = { SYSDB_NAME, SYSDB_OBJECTCATEGORY, SYSDB_PAC_BLOB, SYSDB_PAC_BLOB_EXPIRE, NULL }; struct ldb_message *msg; struct ldb_result *res; int ret; TALLOC_CTX *tmp_ctx = NULL; if (dom == NULL || ar == NULL) { DEBUG(SSSDBG_OP_FAILURE, "Missing arguments.\n"); return EINVAL; } tmp_ctx = talloc_new(NULL); if (tmp_ctx == NULL) { DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n"); return ENOMEM; } if (ar->extra_value && strcmp(ar->extra_value, EXTRA_NAME_IS_UPN) == 0) { ret = sysdb_search_user_by_upn(tmp_ctx, dom, false, ar->filter_value, user_attrs, &msg); } else { switch (ar->filter_type) { case BE_FILTER_SECID: ret = sysdb_search_user_by_sid_str(tmp_ctx, dom, ar->filter_value, user_attrs, &msg); break; case BE_FILTER_UUID: ret = sysdb_search_object_by_uuid(tmp_ctx, dom, ar->filter_value, user_attrs, &res); if (ret == EOK) { if (res->count == 1) { msg = res->msgs[0]; } else { talloc_free(res); DEBUG(SSSDBG_CRIT_FAILURE, "Search by UUID returned multiple results.\n"); ret = EINVAL; goto done; } } break; case BE_FILTER_NAME: ret = sysdb_search_user_by_name(tmp_ctx, dom, ar->filter_value, user_attrs, &msg); break; default: DEBUG(SSSDBG_OP_FAILURE, "Unsupported filter type [%d].\n", ar->filter_type); ret = EINVAL; goto done; } } if (ret != EOK) { if (ret == ENOENT) { DEBUG(SSSDBG_TRACE_ALL, "No user found with filter [%s].\n", ar->filter_value); } else { DEBUG(SSSDBG_OP_FAILURE, "Looking up user in cache with filter [%s] failed.\n", ar->filter_value); } goto done; } *_msg = talloc_steal(mem_ctx, msg); ret = EOK; done: talloc_free(tmp_ctx); return ret; } errno_t check_if_pac_is_available(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom, struct dp_id_data *ar, struct ldb_message **_msg) { struct ldb_message *msg; struct ldb_message_element *el; uint64_t pac_expires; time_t now; int ret; ret = find_user_entry(mem_ctx, dom, ar, &msg); if (ret != EOK) { if (ret == ENOENT) { DEBUG(SSSDBG_FUNC_DATA, "find_user_entry didn't find user entry.\n"); } else { DEBUG(SSSDBG_OP_FAILURE, "find_user_entry failed.\n"); } return ret; } el = ldb_msg_find_element(msg, SYSDB_PAC_BLOB); if (el == NULL) { DEBUG(SSSDBG_TRACE_ALL, "No PAC available.\n"); talloc_free(msg); return ENOENT; } pac_expires = ldb_msg_find_attr_as_uint64(msg, SYSDB_PAC_BLOB_EXPIRE, 0); now = time(NULL); if (pac_expires < now) { DEBUG(SSSDBG_TRACE_FUNC, "PAC available but too old.\n"); talloc_free(msg); return ENOENT; } if (_msg != NULL) { *_msg = msg; } return EOK; } errno_t ad_get_pac_data_from_user_entry(TALLOC_CTX *mem_ctx, struct ldb_message *msg, struct sss_idmap_ctx *idmap_ctx, char **_username, char **user_sid, char **primary_group_sid, size_t *num_sids, char ***group_sids) { int ret; struct ldb_message_element *el; struct PAC_LOGON_INFO *logon_info = NULL; const char *dummy; TALLOC_CTX *tmp_ctx = NULL; char *username; tmp_ctx = talloc_new(NULL); if (tmp_ctx == NULL) { DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n"); return ENOMEM; } el = ldb_msg_find_element(msg, SYSDB_PAC_BLOB); if (el == NULL) { DEBUG(SSSDBG_OP_FAILURE, "Missing PAC blob.\n"); ret = EINVAL; goto done; } if (el->num_values != 1) { DEBUG(SSSDBG_OP_FAILURE, "Expected only one PAC blob."); ret = EINVAL; goto done; } /* PAC was already checked when it was saved in the cache, so no * additional check is needed here. */ ret = ad_get_data_from_pac(tmp_ctx, 0, el->values[0].data, el->values[0].length, &logon_info, NULL); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, "get_data_from_pac failed.\n"); goto done; } dummy = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL); if (dummy == NULL) { DEBUG(SSSDBG_OP_FAILURE, "Missing user name in cache entry.\n"); ret = EINVAL; goto done; } username = talloc_strdup(tmp_ctx, dummy); if (username == NULL) { DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); ret = ENOMEM; goto done; } ret = ad_get_sids_from_pac(mem_ctx, idmap_ctx, logon_info, user_sid, primary_group_sid, num_sids, group_sids); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, "get_sids_from_pac failed.\n"); goto done; } *_username = talloc_steal(mem_ctx, username); ret = EOK; done: talloc_free(tmp_ctx); return ret; } struct ad_handle_pac_initgr_state { struct dp_id_data *ar; const char *err; int dp_error; int sdap_ret; struct sdap_options *opts; size_t num_missing_sids; char **missing_sids; size_t num_cached_groups; char **cached_groups; char *username; struct sss_domain_info *user_dom; }; static void ad_handle_pac_initgr_lookup_sids_done(struct tevent_req *subreq); struct tevent_req *ad_handle_pac_initgr_send(TALLOC_CTX *mem_ctx, struct be_ctx *be_ctx, struct dp_id_data *ar, struct sdap_id_ctx *id_ctx, struct sdap_domain *sdom, struct sdap_id_conn_ctx *conn, bool noexist_delete, struct ldb_message *msg) { int ret; struct ad_handle_pac_initgr_state *state; struct tevent_req *req; struct tevent_req *subreq; char *user_sid; char *primary_group_sid; size_t num_sids; char **group_sids; bool use_id_mapping; req = tevent_req_create(mem_ctx, &state, struct ad_handle_pac_initgr_state); if (req == NULL) { DEBUG(SSSDBG_OP_FAILURE, "tevent_req_create failed.\n"); return NULL; } state->user_dom = sdom->dom; state->opts = id_ctx->opts; /* The following variables are currently unused because no sub-request * returns any of them. But they are needed to allow the same signature as * sdap_handle_acct_req_recv() from the alternative group-membership * lookup path. */ state->err = NULL; state->dp_error = DP_ERR_OK; state->sdap_ret = EOK; ret = ad_get_pac_data_from_user_entry(state, msg, id_ctx->opts->idmap_ctx->map, &state->username, &user_sid, &primary_group_sid, &num_sids, &group_sids); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, "ad_get_pac_data_from_user_entry failed.\n"); goto done; } use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping( id_ctx->opts->idmap_ctx, sdom->dom->name, sdom->dom->domain_id); if (use_id_mapping && sdom->dom->ignore_group_members == false) { /* In contrast to the tokenGroups based group-membership lookup the * PAC based approach can be used for sub-domains with id-mapping as * well because the PAC will only contain groups which are valid in * the target domain, i.e. it will not contain domain-local groups for * domains other than the user domain. This means the groups must not * be looked up immediately to determine if they are domain-local or * not. * * Additionally, as a temporary workaround until * https://fedorahosted.org/sssd/ticket/2522 is fixed, we also fetch * the group object if group members are ignored to avoid having to * transfer and retain members when the fake tokengroups object * without name is replaced by the full group object. */ DEBUG(SSSDBG_TRACE_ALL, "Running PAC processing with id-mapping.\n"); ret = sdap_ad_save_group_membership_with_idmapping(state->username, state->opts, sdom->dom, id_ctx->opts->idmap_ctx, num_sids, group_sids); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, "sdap_ad_save_group_membership_with_idmapping failed.\n"); } /* this path only includes cache operation, so we can finish the * request immediately */ goto done; } else { DEBUG(SSSDBG_TRACE_ALL, "Running PAC processing with external IDs.\n"); ret = sdap_ad_tokengroups_get_posix_members(state, sdom->dom, num_sids, group_sids, &state->num_missing_sids, &state->missing_sids, &state->num_cached_groups, &state->cached_groups); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, "sdap_ad_tokengroups_get_posix_members failed.\n"); goto done; } /* download missing SIDs */ subreq = sdap_ad_resolve_sids_send(state, be_ctx->ev, id_ctx, conn, id_ctx->opts, sdom->dom, state->missing_sids); if (subreq == NULL) { DEBUG(SSSDBG_OP_FAILURE, "sdap_ad_resolve_sids_send failed.\n"); ret = ENOMEM; goto done; } tevent_req_set_callback(subreq, ad_handle_pac_initgr_lookup_sids_done, req); } return req; done: if (ret == EOK) { tevent_req_done(req); } else { tevent_req_error(req, ret); } tevent_req_post(req, be_ctx->ev); return req; } static void ad_handle_pac_initgr_lookup_sids_done(struct tevent_req *subreq) { struct ad_handle_pac_initgr_state *state; struct tevent_req *req = NULL; errno_t ret; char **cached_groups; size_t num_cached_groups; req = tevent_req_callback_data(subreq, struct tevent_req); state = tevent_req_data(req, struct ad_handle_pac_initgr_state); ret = sdap_ad_resolve_sids_recv(subreq); talloc_zfree(subreq); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Unable to resolve missing SIDs " "[%d]: %s\n", ret, strerror(ret)); goto done; } ret = sdap_ad_tokengroups_get_posix_members(state, state->user_dom, state->num_missing_sids, state->missing_sids, NULL, NULL, &num_cached_groups, &cached_groups); if (ret != EOK){ DEBUG(SSSDBG_MINOR_FAILURE, "sdap_ad_tokengroups_get_posix_members failed [%d]: %s\n", ret, strerror(ret)); goto done; } state->cached_groups = concatenate_string_array(state, state->cached_groups, state->num_cached_groups, cached_groups, num_cached_groups); if (state->cached_groups == NULL) { ret = ENOMEM; goto done; } /* update membership of existing groups */ ret = sdap_ad_tokengroups_update_members(state->username, state->user_dom->sysdb, state->user_dom, state->cached_groups); if (ret != EOK) { DEBUG(SSSDBG_MINOR_FAILURE, "Membership update failed [%d]: %s\n", ret, strerror(ret)); goto done; } done: if (ret != EOK) { tevent_req_error(req, ret); return; } tevent_req_done(req); } errno_t ad_handle_pac_initgr_recv(struct tevent_req *req, int *_dp_error, const char **_err, int *sdap_ret) { struct ad_handle_pac_initgr_state *state; state = tevent_req_data(req, struct ad_handle_pac_initgr_state); if (_dp_error) { *_dp_error = state->dp_error; } if (_err) { *_err = state->err; } if (sdap_ret) { *sdap_ret = state->sdap_ret; } TEVENT_REQ_RETURN_ON_ERROR(req); return EOK; }