From 86c8d01eb434f2e52eecaa0e2b16a0b9f7298574 Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Tue, 24 Mar 2026 19:33:36 +0100 Subject: [PATCH 1/3] ad: move ad_get_sids_from_pac() to ad_pac_common.c To make ad_get_sids_from_pac() better reusable it is moved with its dependencies into ad_pac_common.c --- src/providers/ad/ad_pac.c | 293 ------------------------------- src/providers/ad/ad_pac_common.c | 293 +++++++++++++++++++++++++++++++ 2 files changed, 293 insertions(+), 293 deletions(-) diff --git a/src/providers/ad/ad_pac.c b/src/providers/ad/ad_pac.c index fd15c63995c..73bc192b68d 100644 --- a/src/providers/ad/ad_pac.c +++ b/src/providers/ad/ad_pac.c @@ -150,299 +150,6 @@ errno_t check_if_pac_is_available(TALLOC_CTX *mem_ctx, return EOK; } -static errno_t -add_sids_from_rid_array_to_hash_table(struct dom_sid *dom_sid, - struct samr_RidWithAttributeArray *groups, - struct sss_idmap_ctx *idmap_ctx, - hash_table_t *sid_table) -{ - enum idmap_error_code err; - char *dom_sid_str = NULL; - size_t dom_sid_str_len; - char *sid_str = NULL; - char *rid_start; - hash_key_t key; - hash_value_t value; - int ret; - size_t c; - TALLOC_CTX *tmp_ctx = NULL; - - tmp_ctx = talloc_new(NULL); - if (tmp_ctx == NULL) { - DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n"); - return ENOMEM; - } - - key.type = HASH_KEY_STRING; - value.type = HASH_VALUE_ULONG; - - err = sss_idmap_smb_sid_to_sid(idmap_ctx, dom_sid, &dom_sid_str); - if (err != IDMAP_SUCCESS) { - DEBUG(SSSDBG_OP_FAILURE, "sss_idmap_smb_sid_to_sid failed.\n"); - ret = EFAULT; - goto done; - } - - dom_sid_str_len = strlen(dom_sid_str); - sid_str = talloc_zero_size(tmp_ctx, dom_sid_str_len + 12); - if (sid_str == NULL) { - DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_size failed.\n"); - ret = ENOMEM; - goto done; - } - rid_start = sid_str + dom_sid_str_len; - - memcpy(sid_str, dom_sid_str, dom_sid_str_len); - - for (c = 0; c < groups->count; c++) { - memset(rid_start, '\0', 12); - ret = snprintf(rid_start, 12, "-%lu", - (unsigned long) groups->rids[c].rid); - if (ret < 0 || ret > 12) { - DEBUG(SSSDBG_OP_FAILURE, "snprintf failed.\n"); - ret = EIO; - goto done; - } - - key.str = sid_str; - value.ul = 0; - - ret = hash_enter(sid_table, &key, &value); - if (ret != HASH_SUCCESS) { - DEBUG(SSSDBG_OP_FAILURE, "hash_enter failed [%d][%s].\n", - ret, hash_error_string(ret)); - ret = EIO; - goto done; - } - - } - - ret = EOK; - -done: - sss_idmap_free_sid(idmap_ctx, dom_sid_str); - talloc_free(tmp_ctx); - - return ret; -} - -struct resource_groups { - struct dom_sid2 *domain_sid; - struct samr_RidWithAttributeArray groups; -}; - -errno_t ad_get_sids_from_pac(TALLOC_CTX *mem_ctx, - struct sss_idmap_ctx *idmap_ctx, - struct PAC_LOGON_INFO *logon_info, - char **_user_sid_str, - char **_primary_group_sid_str, - size_t *_num_sids, - char *** _sid_list) -{ - int ret; - size_t s; - struct netr_SamInfo3 *info3; - struct resource_groups resource_groups = { 0 }; - char *sid_str = NULL; - char *msid_str = NULL; - char *user_dom_sid_str = NULL; - size_t user_dom_sid_str_len; - enum idmap_error_code err; - hash_table_t *sid_table = NULL; - hash_key_t key; - hash_value_t value; - char *rid_start; - char *user_sid_str = NULL; - char *primary_group_sid_str = NULL; - size_t c; - size_t num_sids = 0; - char **sid_list = NULL; - struct hash_iter_context_t *iter = NULL; - hash_entry_t *entry; - TALLOC_CTX *tmp_ctx; - - if (idmap_ctx == NULL || logon_info == NULL - || _num_sids == NULL || _sid_list == NULL) { - DEBUG(SSSDBG_OP_FAILURE, "Missing parameter.\n"); - return EINVAL; - } - - tmp_ctx = talloc_new(NULL); - if (tmp_ctx == NULL) { - DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n"); - return ENOMEM; - } - - info3 = &logon_info->info3; -#ifdef HAVE_STRUCT_PAC_LOGON_INFO_RESOURCE_GROUPS - resource_groups.domain_sid = logon_info->resource_groups.domain_sid; - resource_groups.groups.count = logon_info->resource_groups.groups.count; - resource_groups.groups.rids = logon_info->resource_groups.groups.rids; -#endif - - ret = sss_hash_create(tmp_ctx, - info3->sidcount + info3->base.groups.count + 2 - + resource_groups.groups.count, - &sid_table); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "sss_hash_create failed.\n"); - goto done; - } - - key.type = HASH_KEY_STRING; - value.type = HASH_VALUE_ULONG; - - err = sss_idmap_smb_sid_to_sid(idmap_ctx, info3->base.domain_sid, - &user_dom_sid_str); - if (err != IDMAP_SUCCESS) { - DEBUG(SSSDBG_OP_FAILURE, "sss_idmap_smb_sid_to_sid failed.\n"); - ret = EFAULT; - goto done; - } - - user_dom_sid_str_len = strlen(user_dom_sid_str); - sid_str = talloc_zero_size(tmp_ctx, user_dom_sid_str_len + 12); - if (sid_str == NULL) { - DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_size failed.\n"); - ret = ENOMEM; - goto done; - } - rid_start = sid_str + user_dom_sid_str_len; - - memcpy(sid_str, user_dom_sid_str, user_dom_sid_str_len); - - memset(rid_start, '\0', 12); - ret = snprintf(rid_start, 12, "-%lu", - (unsigned long) info3->base.rid); - if (ret < 0 || ret > 12) { - DEBUG(SSSDBG_OP_FAILURE, "snprintf failed.\n"); - ret = EIO; - goto done; - } - - user_sid_str = talloc_strdup(tmp_ctx, sid_str); - if (user_sid_str == NULL) { - DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); - ret = ENOMEM; - goto done; - } - - key.str = sid_str; - value.ul = 0; - - memset(rid_start, '\0', 12); - ret = snprintf(rid_start, 12, "-%lu", - (unsigned long) info3->base.primary_gid); - if (ret < 0 || ret > 12) { - DEBUG(SSSDBG_OP_FAILURE, "snprintf failed.\n"); - ret = EIO; - goto done; - } - - primary_group_sid_str = talloc_strdup(tmp_ctx, sid_str); - if (primary_group_sid_str == NULL) { - DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); - ret = ENOMEM; - goto done; - } - - key.str = sid_str; - value.ul = 0; - - ret = hash_enter(sid_table, &key, &value); - if (ret != HASH_SUCCESS) { - DEBUG(SSSDBG_OP_FAILURE, "hash_enter failed [%d][%s].\n", - ret, hash_error_string(ret)); - ret = EIO; - goto done; - } - - ret = add_sids_from_rid_array_to_hash_table(info3->base.domain_sid, - &info3->base.groups, - idmap_ctx, sid_table); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, - "add_sids_from_rid_array_to_hash_table failed.\n"); - goto done; - } - - for(s = 0; s < info3->sidcount; s++) { - err = sss_idmap_smb_sid_to_sid(idmap_ctx, info3->sids[s].sid, - &msid_str); - if (err != IDMAP_SUCCESS) { - DEBUG(SSSDBG_OP_FAILURE, "sss_idmap_smb_sid_to_sid failed.\n"); - ret = EFAULT; - goto done; - } - - key.str = msid_str; - value.ul = 0; - - ret = hash_enter(sid_table, &key, &value); - sss_idmap_free_sid(idmap_ctx, msid_str); - if (ret != HASH_SUCCESS) { - DEBUG(SSSDBG_OP_FAILURE, "hash_enter failed [%d][%s].\n", - ret, hash_error_string(ret)); - ret = EIO; - goto done; - } - } - - if (resource_groups.domain_sid != NULL) { - ret = add_sids_from_rid_array_to_hash_table(resource_groups.domain_sid, - &resource_groups.groups, - idmap_ctx, sid_table); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, - "add_sids_from_rid_array_to_hash_table failed.\n"); - goto done; - } - } - - num_sids = hash_count(sid_table); - sid_list = talloc_array(tmp_ctx, char *, num_sids); - if (sid_list == NULL) { - DEBUG(SSSDBG_OP_FAILURE, "talloc_array failed.\n"); - ret = ENOMEM; - goto done; - } - - iter = new_hash_iter_context(sid_table); - if (iter == NULL) { - DEBUG(SSSDBG_OP_FAILURE, "new_hash_iter_context failed.\n"); - ret = EINVAL; - goto done; - } - - c = 0; - while ((entry = iter->next(iter)) != NULL) { - sid_list[c] = talloc_strdup(sid_list, entry->key.str); - if (sid_list[c] == NULL) { - DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); - ret = ENOMEM; - goto done; - } - c++; - } - - ret = EOK; - -done: - sss_idmap_free_sid(idmap_ctx, user_dom_sid_str); - hash_destroy(sid_table); - - if (ret == EOK) { - *_sid_list = talloc_steal(mem_ctx, sid_list); - *_user_sid_str = talloc_steal(mem_ctx, user_sid_str); - *_num_sids = num_sids; - *_primary_group_sid_str = talloc_steal(mem_ctx, primary_group_sid_str); - } - - talloc_free(tmp_ctx); - - return ret; -} - errno_t ad_get_pac_data_from_user_entry(TALLOC_CTX *mem_ctx, struct ldb_message *msg, struct sss_idmap_ctx *idmap_ctx, diff --git a/src/providers/ad/ad_pac_common.c b/src/providers/ad/ad_pac_common.c index a9fed5d17db..0461a1714b0 100644 --- a/src/providers/ad/ad_pac_common.c +++ b/src/providers/ad/ad_pac_common.c @@ -468,3 +468,296 @@ errno_t ad_get_data_from_pac(TALLOC_CTX *mem_ctx, const uint32_t pac_check_opts, return ret; } + +static errno_t +add_sids_from_rid_array_to_hash_table(struct dom_sid *dom_sid, + struct samr_RidWithAttributeArray *groups, + struct sss_idmap_ctx *idmap_ctx, + hash_table_t *sid_table) +{ + enum idmap_error_code err; + char *dom_sid_str = NULL; + size_t dom_sid_str_len; + char *sid_str = NULL; + char *rid_start; + hash_key_t key; + hash_value_t value; + int ret; + size_t c; + TALLOC_CTX *tmp_ctx = NULL; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n"); + return ENOMEM; + } + + key.type = HASH_KEY_STRING; + value.type = HASH_VALUE_ULONG; + + err = sss_idmap_smb_sid_to_sid(idmap_ctx, dom_sid, &dom_sid_str); + if (err != IDMAP_SUCCESS) { + DEBUG(SSSDBG_OP_FAILURE, "sss_idmap_smb_sid_to_sid failed.\n"); + ret = EFAULT; + goto done; + } + + dom_sid_str_len = strlen(dom_sid_str); + sid_str = talloc_zero_size(tmp_ctx, dom_sid_str_len + 12); + if (sid_str == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_size failed.\n"); + ret = ENOMEM; + goto done; + } + rid_start = sid_str + dom_sid_str_len; + + memcpy(sid_str, dom_sid_str, dom_sid_str_len); + + for (c = 0; c < groups->count; c++) { + memset(rid_start, '\0', 12); + ret = snprintf(rid_start, 12, "-%lu", + (unsigned long) groups->rids[c].rid); + if (ret < 0 || ret > 12) { + DEBUG(SSSDBG_OP_FAILURE, "snprintf failed.\n"); + ret = EIO; + goto done; + } + + key.str = sid_str; + value.ul = 0; + + ret = hash_enter(sid_table, &key, &value); + if (ret != HASH_SUCCESS) { + DEBUG(SSSDBG_OP_FAILURE, "hash_enter failed [%d][%s].\n", + ret, hash_error_string(ret)); + ret = EIO; + goto done; + } + + } + + ret = EOK; + +done: + sss_idmap_free_sid(idmap_ctx, dom_sid_str); + talloc_free(tmp_ctx); + + return ret; +} + +struct resource_groups { + struct dom_sid2 *domain_sid; + struct samr_RidWithAttributeArray groups; +}; + +errno_t ad_get_sids_from_pac(TALLOC_CTX *mem_ctx, + struct sss_idmap_ctx *idmap_ctx, + struct PAC_LOGON_INFO *logon_info, + char **_user_sid_str, + char **_primary_group_sid_str, + size_t *_num_sids, + char *** _sid_list) +{ + int ret; + size_t s; + struct netr_SamInfo3 *info3; + struct resource_groups resource_groups = { 0 }; + char *sid_str = NULL; + char *msid_str = NULL; + char *user_dom_sid_str = NULL; + size_t user_dom_sid_str_len; + enum idmap_error_code err; + hash_table_t *sid_table = NULL; + hash_key_t key; + hash_value_t value; + char *rid_start; + char *user_sid_str = NULL; + char *primary_group_sid_str = NULL; + size_t c; + size_t num_sids = 0; + char **sid_list = NULL; + struct hash_iter_context_t *iter = NULL; + hash_entry_t *entry; + TALLOC_CTX *tmp_ctx; + + if (idmap_ctx == NULL || logon_info == NULL + || _num_sids == NULL || _sid_list == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "Missing parameter.\n"); + return EINVAL; + } + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n"); + return ENOMEM; + } + + info3 = &logon_info->info3; +#ifdef HAVE_STRUCT_PAC_LOGON_INFO_RESOURCE_GROUPS + resource_groups.domain_sid = logon_info->resource_groups.domain_sid; + resource_groups.groups.count = logon_info->resource_groups.groups.count; + resource_groups.groups.rids = logon_info->resource_groups.groups.rids; +#endif + + ret = sss_hash_create(tmp_ctx, + info3->sidcount + info3->base.groups.count + 2 + + resource_groups.groups.count, + &sid_table); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "sss_hash_create failed.\n"); + goto done; + } + + key.type = HASH_KEY_STRING; + value.type = HASH_VALUE_ULONG; + + err = sss_idmap_smb_sid_to_sid(idmap_ctx, info3->base.domain_sid, + &user_dom_sid_str); + if (err != IDMAP_SUCCESS) { + DEBUG(SSSDBG_OP_FAILURE, "sss_idmap_smb_sid_to_sid failed.\n"); + ret = EFAULT; + goto done; + } + + user_dom_sid_str_len = strlen(user_dom_sid_str); + sid_str = talloc_zero_size(tmp_ctx, user_dom_sid_str_len + 12); + if (sid_str == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_size failed.\n"); + ret = ENOMEM; + goto done; + } + rid_start = sid_str + user_dom_sid_str_len; + + memcpy(sid_str, user_dom_sid_str, user_dom_sid_str_len); + + memset(rid_start, '\0', 12); + ret = snprintf(rid_start, 12, "-%lu", + (unsigned long) info3->base.rid); + if (ret < 0 || ret > 12) { + DEBUG(SSSDBG_OP_FAILURE, "snprintf failed.\n"); + ret = EIO; + goto done; + } + + user_sid_str = talloc_strdup(tmp_ctx, sid_str); + if (user_sid_str == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); + ret = ENOMEM; + goto done; + } + + key.str = sid_str; + value.ul = 0; + + memset(rid_start, '\0', 12); + ret = snprintf(rid_start, 12, "-%lu", + (unsigned long) info3->base.primary_gid); + if (ret < 0 || ret > 12) { + DEBUG(SSSDBG_OP_FAILURE, "snprintf failed.\n"); + ret = EIO; + goto done; + } + + primary_group_sid_str = talloc_strdup(tmp_ctx, sid_str); + if (primary_group_sid_str == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); + ret = ENOMEM; + goto done; + } + + key.str = sid_str; + value.ul = 0; + + ret = hash_enter(sid_table, &key, &value); + if (ret != HASH_SUCCESS) { + DEBUG(SSSDBG_OP_FAILURE, "hash_enter failed [%d][%s].\n", + ret, hash_error_string(ret)); + ret = EIO; + goto done; + } + + ret = add_sids_from_rid_array_to_hash_table(info3->base.domain_sid, + &info3->base.groups, + idmap_ctx, sid_table); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "add_sids_from_rid_array_to_hash_table failed.\n"); + goto done; + } + + for(s = 0; s < info3->sidcount; s++) { + err = sss_idmap_smb_sid_to_sid(idmap_ctx, info3->sids[s].sid, + &msid_str); + if (err != IDMAP_SUCCESS) { + DEBUG(SSSDBG_OP_FAILURE, "sss_idmap_smb_sid_to_sid failed.\n"); + ret = EFAULT; + goto done; + } + + key.str = msid_str; + value.ul = 0; + + ret = hash_enter(sid_table, &key, &value); + sss_idmap_free_sid(idmap_ctx, msid_str); + if (ret != HASH_SUCCESS) { + DEBUG(SSSDBG_OP_FAILURE, "hash_enter failed [%d][%s].\n", + ret, hash_error_string(ret)); + ret = EIO; + goto done; + } + } + + if (resource_groups.domain_sid != NULL) { + ret = add_sids_from_rid_array_to_hash_table(resource_groups.domain_sid, + &resource_groups.groups, + idmap_ctx, sid_table); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "add_sids_from_rid_array_to_hash_table failed.\n"); + goto done; + } + } + + num_sids = hash_count(sid_table); + sid_list = talloc_array(tmp_ctx, char *, num_sids); + if (sid_list == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_array failed.\n"); + ret = ENOMEM; + goto done; + } + + iter = new_hash_iter_context(sid_table); + if (iter == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "new_hash_iter_context failed.\n"); + ret = EINVAL; + goto done; + } + + c = 0; + while ((entry = iter->next(iter)) != NULL) { + sid_list[c] = talloc_strdup(sid_list, entry->key.str); + if (sid_list[c] == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); + ret = ENOMEM; + goto done; + } + c++; + } + + ret = EOK; + +done: + sss_idmap_free_sid(idmap_ctx, user_dom_sid_str); + hash_destroy(sid_table); + + if (ret == EOK) { + *_sid_list = talloc_steal(mem_ctx, sid_list); + *_user_sid_str = talloc_steal(mem_ctx, user_sid_str); + *_num_sids = num_sids; + *_primary_group_sid_str = talloc_steal(mem_ctx, primary_group_sid_str); + } + + talloc_free(tmp_ctx); + + return ret; +} From dd718f55274a17d10174d84a024591d3bc52977f Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Wed, 25 Mar 2026 16:10:34 +0100 Subject: [PATCH 2/3] pam: add pam_gssapi_indicators_apply option --- src/confdb/confdb.h | 4 ++++ src/config/SSSDConfig/sssdoptions.py | 3 +++ src/config/SSSDConfigTest.py | 2 ++ src/config/cfg_rules.ini | 3 +++ src/config/etc/sssd.api.conf | 2 ++ src/db/sysdb_subdomains.c | 12 +++++++++++ src/man/sssd.conf.5.xml | 32 ++++++++++++++++++++++++++++ src/responder/pam/pamsrv.c | 21 ++++++++++++++++++ src/responder/pam/pamsrv.h | 1 + 9 files changed, 80 insertions(+) diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h index 15046a367ca..827e0b58c14 100644 --- a/src/confdb/confdb.h +++ b/src/confdb/confdb.h @@ -146,6 +146,7 @@ #define CONFDB_PAM_GSSAPI_SERVICES "pam_gssapi_services" #define CONFDB_PAM_GSSAPI_CHECK_UPN "pam_gssapi_check_upn" #define CONFDB_PAM_GSSAPI_INDICATORS_MAP "pam_gssapi_indicators_map" +#define CONFDB_PAM_GSSAPI_INDICATORS_APPLY "pam_gssapi_indicators_apply" #define CONFDB_PAM_PASSKEY_AUTH "pam_passkey_auth" #define CONFDB_PAM_PASSKEY_CHILD_TIMEOUT "passkey_child_timeout" #define CONFDB_PAM_PASSKEY_DEBUG_LIBFIDO2 "passkey_debug_libfido2" @@ -446,6 +447,9 @@ struct sss_domain_info { char *gssapi_check_upn; /* true | false | NULL */ /* List of indicators associated with the specific PAM service */ char **gssapi_indicators_map; + /* List of addition Kerberos ticket data assigned to authentication + * indicators */ + char **gssapi_indicators_apply; /* Counts how often the domain was not found during a refresh of the * domain list */ diff --git a/src/config/SSSDConfig/sssdoptions.py b/src/config/SSSDConfig/sssdoptions.py index 0424497fca5..872e2d8e58b 100644 --- a/src/config/SSSDConfig/sssdoptions.py +++ b/src/config/SSSDConfig/sssdoptions.py @@ -110,6 +110,9 @@ def __init__(self): 'pam_gssapi_check_upn': _('Whether to match authenticated UPN with target user'), 'pam_gssapi_indicators_map': _('List of pairs : that ' 'must be enforced for PAM access with GSSAPI authentication'), + 'pam_gssapi_indicators_apply': _('List of triples :: that ' + 'assigns additional information from the Kerberos ticket to an' + 'authentication indicator.'), 'pam_passkey_auth': _('Allow passkey device authentication.'), 'passkey_child_timeout': _('How many seconds will pam_sss wait for passkey_child to finish'), 'passkey_debug_libfido2': _('Enable debugging in the libfido2 library'), diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py index 8e641be2bda..7c2016b092f 100755 --- a/src/config/SSSDConfigTest.py +++ b/src/config/SSSDConfigTest.py @@ -602,6 +602,7 @@ def testListOptions(self): 'pam_gssapi_services', 'pam_gssapi_check_upn', 'pam_gssapi_indicators_map', + 'pam_gssapi_indicators_apply', 'refresh_expired_interval', 'refresh_expired_interval_offset', 'local_auth_policy'] @@ -966,6 +967,7 @@ def testRemoveProvider(self): 'pam_gssapi_services', 'pam_gssapi_check_upn', 'pam_gssapi_indicators_map', + 'pam_gssapi_indicators_apply', 'refresh_expired_interval', 'refresh_expired_interval_offset', 'dyndns_refresh_interval', diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini index 04db3628bc9..fc3a00e1aba 100644 --- a/src/config/cfg_rules.ini +++ b/src/config/cfg_rules.ini @@ -140,6 +140,7 @@ option = pam_initgroups_scheme option = pam_gssapi_services option = pam_gssapi_check_upn option = pam_gssapi_indicators_map +option = pam_gssapi_indicators_apply option = pam_passkey_auth option = passkey_child_timeout option = passkey_debug_libfido2 @@ -414,6 +415,7 @@ option = auto_private_groups option = pam_gssapi_services option = pam_gssapi_check_upn option = pam_gssapi_indicators_map +option = pam_gssapi_indicators_apply option = local_auth_policy #Entry cache timeouts @@ -821,6 +823,7 @@ option = auto_private_groups option = pam_gssapi_services option = pam_gssapi_check_upn option = pam_gssapi_indicators_map +option = pam_gssapi_indicators_apply [rule/sssd_checks] validator = sssd_checks diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf index 4cbf22c51c4..ded5494899e 100644 --- a/src/config/etc/sssd.api.conf +++ b/src/config/etc/sssd.api.conf @@ -83,6 +83,7 @@ pam_initgroups_scheme = str, None, false pam_gssapi_services = str, None, false pam_gssapi_check_upn = bool, None, false pam_gssapi_indicators_map = str, None, false +pam_gssapi_indicators_apply = str, None, false pam_passkey_auth = bool, None, false passkey_child_timeout = int, None, false passkey_debug_libfido2 = bool, None, false @@ -190,6 +191,7 @@ auto_private_groups = str, None, false pam_gssapi_services = str, None, false pam_gssapi_check_upn = bool, None, false pam_gssapi_indicators_map = str, None, false +pam_gssapi_indicators_apply = str, None, false local_auth_policy = str, None, false #Entry cache timeouts diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c index 7f1b89c9822..0da2a699300 100644 --- a/src/db/sysdb_subdomains.c +++ b/src/db/sysdb_subdomains.c @@ -202,6 +202,7 @@ struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx, dom->gssapi_services = parent->gssapi_services; dom->gssapi_indicators_map = parent->gssapi_indicators_map; + dom->gssapi_indicators_apply = parent->gssapi_indicators_apply; dom->not_found_counter = 0; @@ -297,6 +298,17 @@ check_subdom_config_file(struct confdb_ctx *confdb, goto done; } + /* allow to set pam_gssapi_indicators_apply */ + ret = confdb_get_string_as_list(confdb, subdomain, sd_conf_path, + CONFDB_PAM_GSSAPI_INDICATORS_APPLY, + &subdomain->gssapi_indicators_apply); + if (ret != EOK && ret != ENOENT) { + DEBUG(SSSDBG_OP_FAILURE, + "Failed to get %s option for the subdomain: %s\n", + CONFDB_PAM_GSSAPI_INDICATORS_APPLY, subdomain->name); + goto done; + } + /* case_sensitive=Preserving */ ret = confdb_get_string(confdb, tmp_ctx, sd_conf_path, CONFDB_DOMAIN_CASE_SENSITIVE, NULL, diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml index 4725cb8d2bc..c7435c9d3e8 100644 --- a/src/man/sssd.conf.5.xml +++ b/src/man/sssd.conf.5.xml @@ -1981,6 +1981,38 @@ pam_gssapi_indicators_map = sudo:pkinit, sudo-i:pkinit + + pam_gssapi_indicators_apply + + + Comma separated list of triples to assign + additional information from the Kerberos ticket, + e.g. a SID from the PAC, to authentication + indicators. + + + Currently supported is: + + + SID:S-1-5-[domain]-[RID]:[authentication indicator] + + + + + Example: To assign a SID, which is e.g. set by + Active Directory's Authentication Mechanism + Assurance (AMA) if the AD user used a Smartcard + for authentication, to the 'pkinit' + authentication indicator use: + +pam_gssapi_indicators_apply = SID:S-1-5-12345-23456-34567-4321:pkinit + + + + Default: not set + + + pam_json_services (string) diff --git a/src/responder/pam/pamsrv.c b/src/responder/pam/pamsrv.c index 5c0bbcfab67..be95d7251ee 100644 --- a/src/responder/pam/pamsrv.c +++ b/src/responder/pam/pamsrv.c @@ -404,6 +404,27 @@ static int pam_process_init(TALLOC_CTX *mem_ctx, } } + ret = confdb_get_string(pctx->rctx->cdb, pctx, CONFDB_PAM_CONF_ENTRY, + CONFDB_PAM_GSSAPI_INDICATORS_APPLY, NULL, &tmpstr); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, + "Failed to determine additional authentication indicator mapping.\n"); + goto done; + } + DEBUG(SSSDBG_TRACE_INTERNAL, "Found value [%s] for option [%s].\n", tmpstr, + CONFDB_PAM_GSSAPI_INDICATORS_APPLY); + + if (tmpstr != NULL) { + ret = split_on_separator(pctx, tmpstr, ',', true, true, + &pctx->gssapi_indicators_apply, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, + "split_on_separator() failed [%d]: [%s].\n", ret, + sss_strerror(ret)); + goto done; + } + } + /* Check if JSON authentication selection method is enabled for any PAM * services */ diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h index d843715c494..1d2e7bc0d14 100644 --- a/src/responder/pam/pamsrv.h +++ b/src/responder/pam/pamsrv.h @@ -73,6 +73,7 @@ struct pam_ctx { char **gssapi_services; /* List of authentication indicators associated with a PAM service */ char **gssapi_indicators_map; + char **gssapi_indicators_apply; bool gssapi_check_upn; bool passkey_auth; struct pam_passkey_table_data *pk_table_data; From 6bddc35af86ee036202bc5d54865c48466a145e0 Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Wed, 18 Mar 2026 15:49:50 +0100 Subject: [PATCH 3/3] pam: apply SIDs from PAC to authentication indicators This patch reads the PAC of a Kerberos ticket while evaluating the authentication indicators of the Kerberos ticket during a pam_sss_gss request. Based on the value of the pam_gssapi_indicators_apply option the found SIDs might add additional authentication indicators to the evaluation. The primary use case is to handle SIDs added by Active Directory's Authentication Mechanism Assurance (AMA). --- Makefile.am | 9 + src/responder/pam/pamsrv_gssapi.c | 257 ++++++++++++++++++++++++++--- src/tests/system/tests/test_ipa.py | 108 ++++++++++++ 3 files changed, 349 insertions(+), 25 deletions(-) diff --git a/Makefile.am b/Makefile.am index 05e0baba934..9fcf693cab0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1512,6 +1512,7 @@ sssd_pam_SOURCES = \ src/responder/pam/pam_prompting_config.c \ src/sss_client/pam_sss_prompt_config.c \ src/responder/pam/pam_helpers.c \ + src/providers/ad/ad_pac_common.c \ $(SSSD_RESPONDER_OBJ) if BUILD_PASSKEY sssd_pam_SOURCES += src/responder/pam/pamsrv_passkey.c @@ -1519,6 +1520,7 @@ endif sssd_pam_CFLAGS = \ $(AM_CFLAGS) \ $(GSSAPI_KRB5_CFLAGS) \ + $(NDR_KRB5PAC_CFLAGS) \ $(NULL) sssd_pam_LDADD = \ $(LIBADD_DL) \ @@ -1530,6 +1532,8 @@ sssd_pam_LDADD = \ $(SSSD_INTERNAL_LTLIBS) \ libsss_iface.la \ libsss_sbus.la \ + $(NDR_KRB5PAC_LIBS) \ + libsss_idmap.la \ $(NULL) if BUILD_SUDO @@ -2554,6 +2558,7 @@ pam_srv_tests_SOURCES = \ src/responder/pam/pamsrv_dp.c \ src/responder/pam/pam_prompting_config.c \ src/sss_client/pam_sss_prompt_config.c \ + src/providers/ad/ad_pac_common.c \ $(NULL) pam_srv_tests_CFLAGS = \ -U SSSD_LIBEXEC_PATH -DSSSD_LIBEXEC_PATH=\"$(abs_builddir)\" \ @@ -2561,6 +2566,7 @@ pam_srv_tests_CFLAGS = \ $(AM_CFLAGS) \ $(CMOCKA_CFLAGS) \ $(GSSAPI_KRB5_CFLAGS) \ + $(NDR_KRB5PAC_CFLAGS) \ $(NULL) pam_srv_tests_LDFLAGS = \ -Wl,-wrap,sss_packet_get_body \ @@ -2582,6 +2588,7 @@ pam_srv_tests_LDADD = \ libsss_certmap.la \ libsss_iface.la \ libsss_sbus.la \ + $(NDR_KRB5PAC_LIBS) \ $(NULL) if BUILD_PASSKEY pam_srv_tests_SOURCES += src/responder/pam/pamsrv_passkey.c @@ -2598,6 +2605,7 @@ test_pamsrv_json_SOURCES = \ src/responder/pam/pam_prompting_config.c \ src/sss_client/pam_sss_prompt_config.c \ src/tests/cmocka/test_pamsrv_json.c \ + src/providers/ad/ad_pac_common.c \ $(NULL) if BUILD_PASSKEY test_pamsrv_json_SOURCES += src/responder/pam/pamsrv_passkey.c @@ -2622,6 +2630,7 @@ test_pamsrv_json_LDADD = \ libsss_certmap.la \ libsss_iface.la \ libsss_sbus.la \ + $(NDR_KRB5PAC_LIBS) \ $(NULL) test_sss_pam_data_SOURCES = \ diff --git a/src/responder/pam/pamsrv_gssapi.c b/src/responder/pam/pamsrv_gssapi.c index ebc95717282..97b114e34be 100644 --- a/src/responder/pam/pamsrv_gssapi.c +++ b/src/responder/pam/pamsrv_gssapi.c @@ -37,6 +37,7 @@ #include "sss_client/sss_cli.h" #include "util/util.h" #include "util/sss_utf8.h" +#include "providers/ad/ad_pac.h" static errno_t read_str(size_t body_len, uint8_t *body, @@ -497,9 +498,126 @@ static char *gssapi_get_name(TALLOC_CTX *mem_ctx, gss_name_t gss_name) return exported; } +struct gssapi_state { + struct cli_ctx *cli_ctx; + struct sss_domain_info *domain; + const char *username; + + char *authenticated_upn; + char **auth_indicators; + char **indicators_apply_sid; + bool established; + gss_ctx_id_t ctx; + struct sss_idmap_ctx *idmap_ctx; +}; + +static void *idmap_talloc(size_t size, void *pvt) +{ + return talloc_size(pvt, size); +} + +static void idmap_free(void *ptr, void *pvt) +{ + talloc_free(ptr); +} + + +static errno_t handle_pac(struct gssapi_state *state, + uint8_t *pac_blob, size_t pac_len, + char **exported_from_pac) +{ + errno_t ret; + struct PAC_LOGON_INFO *logon_info = NULL; + TALLOC_CTX *tmp_ctx; + char *user_sid; + char *primary_group_sid; + size_t num_sids; + char **group_sids; + char *exported = NULL; + size_t c; + size_t d; + size_t l; + enum idmap_error_code err; + char *sep; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + return ENOMEM; + } + + ret = ad_get_data_from_pac(tmp_ctx, 0, pac_blob, pac_len, &logon_info, + NULL); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Cannot read logon_info buffer from PAC.\n"); + goto done; + } + + if (state->idmap_ctx == NULL) { + err = sss_idmap_init(idmap_talloc, state, idmap_free, + &state->idmap_ctx); + if (err != IDMAP_SUCCESS) { + ret = EIO; + DEBUG(SSSDBG_OP_FAILURE, "failed to init idmap library.\n"); + goto done; + } + } + + ret = ad_get_sids_from_pac(tmp_ctx, state->idmap_ctx, logon_info, + &user_sid, &primary_group_sid, + &num_sids, &group_sids); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "Failed to extract SIDs from logon_info buffer.\n"); + goto done; + } + + exported = talloc_strdup(state, ""); + if (exported == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Unable to pre-allocate indicators\n"); + ret = ENOMEM; + goto done; + } + + /* we are only interested in the additional SIDs */ + for (c = 0; c < num_sids; c++) { + for (d = 0; state->indicators_apply_sid[d] != NULL; d++) { + sep = strchr(state->indicators_apply_sid[d], ':'); + if (sep == NULL) { + /* missing authentication indicator part, ignored */ + continue; + } + l = strlen(group_sids[c]); + if ( (sep - state->indicators_apply_sid[d]) == l + && strncasecmp(state->indicators_apply_sid[d], + group_sids[c], l) == 0) { + exported = talloc_asprintf_append(exported, "%s ", + state->indicators_apply_sid[d] + l + 1); + } + } + } + + if (*exported == '\0') { + DEBUG(SSSDBG_TRACE_FUNC, + "No PAC base authentication indicators found.\n"); + } else { + DEBUG(SSSDBG_TRACE_FUNC, + "PAC base authentication indicators: [%s] \n", exported); + } + + *exported_from_pac = exported; + + ret = EOK; +done: + talloc_free(tmp_ctx); + return ret; +} + #define AUTH_INDICATORS_TAG "auth-indicators" +#define MSPAC_TAG "urn:mspac:" -static char **gssapi_get_indicators(TALLOC_CTX *mem_ctx, gss_name_t gss_name) +static char **gssapi_get_indicators(struct gssapi_state *state, + gss_name_t gss_name) { gss_buffer_set_t attrs = GSS_C_NO_BUFFER_SET; int is_mechname; @@ -508,6 +626,7 @@ static char **gssapi_get_indicators(TALLOC_CTX *mem_ctx, gss_name_t gss_name) gss_buffer_desc value = GSS_C_EMPTY_BUFFER; gss_buffer_desc display_value = GSS_C_EMPTY_BUFFER; char *exported = NULL; + char *exported_from_pac = NULL; char **map = NULL; int res; @@ -522,7 +641,7 @@ static char **gssapi_get_indicators(TALLOC_CTX *mem_ctx, gss_name_t gss_name) return NULL; } - exported = talloc_strdup(mem_ctx, ""); + exported = talloc_strdup(state, ""); if (exported == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Unable to pre-allocate indicators\n"); @@ -533,11 +652,34 @@ static char **gssapi_get_indicators(TALLOC_CTX *mem_ctx, gss_name_t gss_name) int authenticated = 0; int complete = 0; int more = -1; + bool is_auth_indicator; + bool is_mspac; + + DEBUG(SSSDBG_TRACE_ALL, "Checking: [%.*s]\n", + (int) attrs->elements[i].length, + (char *) attrs->elements[i].value); - /* skip anything but auth-indicators */ + /* skip anything but auth-indicators or PAC */ if (strncmp(AUTH_INDICATORS_TAG, attrs->elements[i].value, - sizeof(AUTH_INDICATORS_TAG) - 1) != 0) + sizeof(AUTH_INDICATORS_TAG) - 1) == 0) { + is_auth_indicator = true; + is_mspac = false; + } else if (attrs->elements[i].length == (sizeof(MSPAC_TAG) - 1) + && strncmp(MSPAC_TAG, attrs->elements[i].value, + sizeof(MSPAC_TAG) - 1) == 0) { + is_mspac = true; + is_auth_indicator = false; + } else { + is_auth_indicator = false; + is_mspac = false; + continue; + } + + DEBUG(SSSDBG_TRACE_ALL, + "Found: PAC[%s] authentication indicator[%s].\n", + is_mspac ? "true" : "false", + is_auth_indicator ? "true" : "false"); /* retrieve all indicators */ while (more != 0) { @@ -557,19 +699,40 @@ static char **gssapi_get_indicators(TALLOC_CTX *mem_ctx, gss_name_t gss_name) } if ((value.value != NULL) && authenticated) { - DEBUG(SSSDBG_TRACE_FUNC, - "attribute's [%.*s] value [%.*s] authenticated\n", - (int) attrs->elements[i].length, - (char*) attrs->elements[i].value, - (int) value.length, - (char*) value.value); - exported = talloc_asprintf_append(exported, "%.*s ", - (int) value.length, - (char*) value.value); + /* Only check PAC if SIDs to apply are configured */ + if (is_mspac && state->indicators_apply_sid != NULL) { + res = handle_pac(state, + (uint8_t *) value.value, + value.length, + &exported_from_pac); + if (res != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "Failed to evaluate data from PAC, ignored.\n"); + } + + if (exported_from_pac != NULL) { + /* exported_from_pac will have a trailing whitespace */ + exported = talloc_asprintf_append(exported, "%s", + exported_from_pac); + talloc_zfree(exported_from_pac); + } + } + + if (is_auth_indicator) { + DEBUG(SSSDBG_TRACE_FUNC, + "attribute's [%.*s] value [%.*s] authenticated\n", + (int) attrs->elements[i].length, + (char*) attrs->elements[i].value, + (int) value.length, + (char*) value.value); + exported = talloc_asprintf_append(exported, "%.*s ", + (int) value.length, + (char*) value.value); + } } if (exported == NULL) { - /* Since we allocate on mem_ctx, caller will free + /* Since we allocate on state, caller will free * the previous version of 'exported' */ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to collect an attribute value\n"); @@ -589,7 +752,7 @@ static char **gssapi_get_indicators(TALLOC_CTX *mem_ctx, gss_name_t gss_name) goto done; } - res = split_on_separator(mem_ctx, exported, ' ', true, true, + res = split_on_separator(state, exported, ' ', true, true, &map, NULL); if (res != 0) { DEBUG(SSSDBG_FATAL_FAILURE, @@ -609,17 +772,51 @@ static char **gssapi_get_indicators(TALLOC_CTX *mem_ctx, gss_name_t gss_name) return map; } +errno_t gssapi_get_apply_sid_list(TALLOC_CTX *mem_ctx, + struct pam_ctx *pam_ctx, + struct sss_domain_info *domain, + char ***_indicators_apply_sid) +{ + char **indicators_apply; + char **indicators_apply_sid = NULL; + size_t c; + size_t d; -struct gssapi_state { - struct cli_ctx *cli_ctx; - struct sss_domain_info *domain; - const char *username; + /* Use apply list from the domain, if defined and + * fallback to the [pam] section otherwise */ + indicators_apply = domain->gssapi_indicators_apply ? + domain->gssapi_indicators_apply : + (pam_ctx->gssapi_indicators_apply ? + pam_ctx->gssapi_indicators_apply : NULL); + if (indicators_apply != NULL && *indicators_apply[0] != '\0') { + for (c = 0; indicators_apply[c] != NULL; c++); + indicators_apply_sid = talloc_array(mem_ctx, char *, c + 1); + if (indicators_apply_sid == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "Failed to allocate memory.\n"); + return ENOMEM; + } + d = 0; + for (c = 0; indicators_apply[c] != NULL; c++) { + if (strncmp(indicators_apply[c], "SID:", 4) == 0) { + indicators_apply_sid[d] = + talloc_strdup(indicators_apply_sid, + indicators_apply[c] + 4); + if (indicators_apply_sid[d] == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "Failed to copy string [%s].\n", + indicators_apply[c] + 4); + talloc_free(indicators_apply_sid); + return ENOMEM; + } + d++; + } + } + indicators_apply_sid[d] = NULL; + } - char *authenticated_upn; - char **auth_indicators; - bool established; - gss_ctx_id_t ctx; -}; + *_indicators_apply_sid = indicators_apply_sid; + + return EOK; +} int gssapi_state_destructor(struct gssapi_state *state) { @@ -631,6 +828,7 @@ int gssapi_state_destructor(struct gssapi_state *state) } static struct gssapi_state *gssapi_get_state(struct cli_ctx *cli_ctx, + struct pam_ctx *pam_ctx, const char *username, struct sss_domain_info *domain) { @@ -659,6 +857,14 @@ static struct gssapi_state *gssapi_get_state(struct cli_ctx *cli_ctx, cli_ctx->state_ctx = state; + if (gssapi_get_apply_sid_list(state, pam_ctx, domain, + &state->indicators_apply_sid) != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Failed to get list of SID to apply to " + "authentication indicators.\n"); + talloc_free(state); + return NULL; + } + return state; } @@ -922,7 +1128,7 @@ pam_cmd_gssapi_sec_ctx(struct cli_ctx *cli_ctx) goto done; } - state = gssapi_get_state(cli_ctx, username, domain); + state = gssapi_get_state(cli_ctx, pam_ctx, username, domain); if (state == NULL) { ret = ENOMEM; goto done; @@ -955,6 +1161,7 @@ pam_cmd_gssapi_sec_ctx(struct cli_ctx *cli_ctx) domain->gssapi_indicators_map : (pam_ctx->gssapi_indicators_map ? pam_ctx->gssapi_indicators_map : NULL); + if (indicators_map != NULL) { ret = pam_gssapi_check_indicators(state, pam_service, diff --git a/src/tests/system/tests/test_ipa.py b/src/tests/system/tests/test_ipa.py index 4c84a1769ba..d55d0d529ec 100644 --- a/src/tests/system/tests/test_ipa.py +++ b/src/tests/system/tests/test_ipa.py @@ -398,6 +398,114 @@ def test_ipa__check_gssapi_authentication_indicator(client: Client, ipa: IPA): assert "indicators: 2" in log2, "String `indicators: 2` not found in logs!" +@pytest.mark.importance("low") +@pytest.mark.topology(KnownTopology.IPA) +def test_ipa__check_gssapi_authentication_indicator_apply(client: Client, ipa: IPA): + """ + :title: Check logs for authentication indicators from PAC + :description: + Checks the assignment of SIDs from the PAC to authentication indicators + :setup: + 1. Create a user and a group and make the user a member of the group + 2. Configure SSSD for sudo and gssapi, require 'pkinit' authentication + indicator for 'sudo' services and assign a non-exiting SID to 'pkinit' + 3. Create sudo rule for the user + :steps: + 1. Login as the test user and obtain ticket + 2. Try 'sudo -l' as user + 3. Check if acquired service ticket has indicators: 1 (denied) in sssd_pam.log + 4. Update config by assigning the SID of the new group to 'otp' and restart sssd + 5. Login as the test user and obtain a new ticket + 6. Try 'sudo -l' as user + 7. Check if acquired service ticket has indicators: 1 (denied) in sssd_pam.log + 8. Update config by assigning the SID of the new group to 'pkinit' and restart sssd + 9. Login as the test user and obtain a new ticket + 10. Try 'sudo -l' as user + 11. Check if acquired service ticket has indicators: 0 (success) in sssd_pam.log + :expectedresults: + 1. Login successful and ticket obtained + 2. "Sudo -l" should fail + 3. "indicators: 1" should be there in the sssd_pam.log + 4. Configuration is updated and SSSD is restarted + 5. Login successful and new ticket obtained + 6. "Sudo -l" should fail + 7. "indicators: 1" should be there in the sssd_pam.log + 8. Configuration is updated and SSSD is restarted + 9. Login successful and new ticket obtained + 10. "Sudo -l" should show the expected allowed command + 11. "indicators: 0" should be there in the sssd_pam.log + :customerscenario: True + """ + user = ipa.user("user-1").add(password="Secret123") + password = "Secret123" + + group = ipa.group("group1").add().add_member(user) + res = group.get(["ipaNTSecurityIdentifier"]) + assert res is not None, "Missing ipaNTSecurityIdentifier!" + group_sid = res["ipaNTSecurityIdentifier"][0] + + # In future some other string replacement module may be created, for now generic sed module is used. + for path in ["/etc/pam.d/sudo", "/etc/pam.d/sudo-i"]: + client.fs.sed(path=path, command="2s/^/auth sufficient pam_sss_gss.so debug\\n/", args=["-i"]) + + ipa.sudorule("testrule").add(user=user.name, host="ALL", command="/bin/my_precious") + + client.sssd.common.sudo() + + # wrong SID, expected authentication indicator + client.sssd.config["pam"] = { + "pam_gssapi_services": "sudo, sudo-i", + "pam_gssapi_indicators_map": "sudo:pkinit, sudo-i:pkinit", + "pam_gssapi_indicators_apply": "SID:S-1-5-21-12345-23456-34567-1234:pkinit", + } + client.sssd.start() + + with client.ssh(user.name, password) as ssh: + ssh.run(f"kinit {user.name}@{ipa.host.realm}", input=password) + ssh.run("klist") + ssh.disconnect() + assert not client.auth.sudo.list(user.name, expected=["(root) /bin/my_precious"]), "Sudo list did not fail!" + time.sleep(3) + log1 = client.fs.read(client.sssd.logs.pam) + assert "indicators: 1" in log1, "String `indicators: 1` not found in logs!" + + # expected SID, wrong authentication indicator + client.sssd.config["pam"] = { + "pam_gssapi_services": "sudo, sudo-i", + "pam_gssapi_indicators_map": "sudo:pkinit, sudo-i:pkinit", + "pam_gssapi_indicators_apply": f"SID:{group_sid}:otp", + } + client.sssd.clear(logs=False) + client.sssd.start() + + with client.ssh(user.name, password) as ssh: + ssh.run(f"kinit {user.name}@{ipa.host.realm}", input=password) + ssh.run("klist") + ssh.disconnect() + assert not client.auth.sudo.list(user.name, expected=["(root) /bin/my_precious"]), "Sudo list did not fail!" + time.sleep(3) + log1 = client.fs.read(client.sssd.logs.pam) + assert "indicators: 1" in log1, "String `indicators: 1` not found in logs!" + + # expected SID, expected authentication indicator + client.sssd.config["pam"] = { + "pam_gssapi_services": "sudo, sudo-i", + "pam_gssapi_indicators_map": "sudo:pkinit, sudo-i:pkinit", + "pam_gssapi_indicators_apply": f"SID:{group_sid}:pkinit", + } + client.sssd.clear(logs=False) + client.sssd.restart() + + with client.ssh(user.name, password) as ssh: + ssh.run(f"kinit {user.name}@{ipa.host.realm}", input=password) + ssh.run("klist") + ssh.disconnect() + assert client.auth.sudo.list(user.name, expected=["(root) /bin/my_precious"]), "Sudo list failed!" + time.sleep(3) + log2 = client.fs.read(client.sssd.logs.pam) + assert "indicators: 0" in log2, "String `indicators: 0` not found in logs!" + + @pytest.mark.importance("high") @pytest.mark.topology(KnownTopology.IPA) @pytest.mark.parametrize(