diff --git a/SOURCES/0012-Analyzer-Optimize-list-verbose-output.patch b/SOURCES/0012-Analyzer-Optimize-list-verbose-output.patch new file mode 100644 index 0000000..97db9b4 --- /dev/null +++ b/SOURCES/0012-Analyzer-Optimize-list-verbose-output.patch @@ -0,0 +1,141 @@ +From 70e254653edb21923d7565c80704e1ce6865d991 Mon Sep 17 00:00:00 2001 +From: Justin Stephenson +Date: Wed, 12 Oct 2022 08:48:45 -0400 +Subject: [PATCH] Analyzer: Optimize list verbose output +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Modify the analyzer to parse the responder log file in one pass. This +avoids repeated parsing of a single log file. This operation will now +store log lines in a dictionary on a single pass then format and print +the output accordingly. Does not affect 'list' or 'show' output. + +Reviewed-by: Alexey Tikhonov +Reviewed-by: Tomáš Halman + +Reviewed-by: Alexey Tikhonov +Reviewed-by: Tomáš Halman +--- + src/tools/analyzer/modules/request.py | 71 ++++++++++++++++++--------- + 1 file changed, 48 insertions(+), 23 deletions(-) + +diff --git a/src/tools/analyzer/modules/request.py b/src/tools/analyzer/modules/request.py +index b9fe3caf8..15c8e6bfb 100644 +--- a/src/tools/analyzer/modules/request.py ++++ b/src/tools/analyzer/modules/request.py +@@ -148,36 +148,57 @@ class RequestAnalyzer: + print(line) + return found_results + +- def print_formatted_verbose(self, source, patterns): ++ def print_formatted_verbose(self, source): + """ +- Parse line and print formatted verbose list_requests output ++ Parse log file and print formatted verbose list_requests output + + Args: + source (Reader): source Reader object +- patterns (list): List of regex patterns to use for +- matching lines + """ +- # Get CID number, and print the basic line first +- for line in self.matched_line(source, patterns): +- cid = self.print_formatted(line) +- +- # Loop through each line with this CID number to extract and +- # print the verbose data needed +- verbose_patterns = ["(cache_req_send|cache_req_process_input|" +- "cache_req_search_send)"] +- for cidline in self.matched_line(source, verbose_patterns): ++ data = {} ++ # collect cid log lines from single run through of parsing the log ++ # into dictionary # (cid, ts) -> logline_output ++ for line in source: ++ if "CID#" not in line: ++ continue ++ ++ # parse CID and ts from line, key is a tuple of (cid,ts) ++ fields = line.split("[") ++ # timestamp to the minute, cut off seconds, ms ++ ts = fields[0][:17] ++ result = re.search('CID#[0-9]*', fields[3]) ++ cid = result.group(0) ++ ++ # if mapping exists, append line to output. Otherwise create new mapping ++ if (cid, ts) in data.keys(): ++ data[(cid, ts)] += line ++ else: ++ data[(cid, ts)] = line ++ ++ # pretty print the data ++ for k, v in data.items(): ++ cr_done = [] ++ id_done = [] ++ for cidline in v.splitlines(): + plugin = "" + name = "" + id = "" + +- # skip any lines not pertaining to this CID +- if f"CID#{cid}]" not in cidline: +- continue +- if "refreshed" in cidline: +- continue ++ # CR number ++ fields = cidline.split("[") ++ cr_field = fields[3][7:] ++ cr = cr_field.split(":")[0][4:] ++ # Client connected, top-level info line ++ if re.search(r'\[cmd', cidline): ++ self.print_formatted(cidline) + # CR Plugin name + if re.search("cache_req_send", cidline): + plugin = cidline.split('\'')[1] ++ id_done.clear() ++ # Extract CR number ++ fields = cidline.split("[") ++ cr_field = fields[3][7:] ++ cr = cr_field.split(":")[0][4:] + # CR Input name + elif re.search("cache_req_process_input", cidline): + name = cidline.rsplit('[')[-1] +@@ -188,9 +209,14 @@ class RequestAnalyzer: + if plugin: + print(" - " + plugin) + if name: +- print(" - " + name[:-2]) ++ # Avoid duplicate output with the same CR # ++ if cr not in cr_done: ++ print(" - " + name[:-1]) ++ cr_done.append(cr) + if (id and ("UID" in cidline or "GID" in cidline)): +- print(" - " + id) ++ if id not in id_done: ++ print(" - " + id) ++ id_done.append(id) + + def print_formatted(self, line): + """ +@@ -237,7 +263,7 @@ class RequestAnalyzer: + logger.info(f"******** Listing {resp} client requests ********") + source.set_component(component, False) + if args.verbose: +- self.print_formatted_verbose(source, patterns) ++ self.print_formatted_verbose(source) + else: + for line in self.matched_line(source, patterns): + if isinstance(source, Journald): +@@ -258,8 +284,7 @@ class RequestAnalyzer: + be_results = False + component = source.Component.NSS + resp = "nss" +- pattern = [rf'REQ_TRACE.*\[CID #{cid}\]'] +- pattern.append(rf"\[CID#{cid}\]") ++ pattern = [rf"\[CID#{cid}\]"] + + if args.pam: + component = source.Component.PAM +-- +2.37.3 + diff --git a/SOURCES/0013-Analyzer-Ensure-parsed-id-contains-digit.patch b/SOURCES/0013-Analyzer-Ensure-parsed-id-contains-digit.patch new file mode 100644 index 0000000..aea3aae --- /dev/null +++ b/SOURCES/0013-Analyzer-Ensure-parsed-id-contains-digit.patch @@ -0,0 +1,43 @@ +From 89ea4a5feaf30f80a79ca3ba8166f304cc414e07 Mon Sep 17 00:00:00 2001 +From: Justin Stephenson +Date: Tue, 15 Nov 2022 12:47:51 -0500 +Subject: [PATCH] Analyzer: Ensure parsed id contains digit +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +In analyzer list verbose output, we parse the last field of cache_req_search_send() lines. +Certain log messages need to be filtered out by ensuring the parsed field is +a digit, such as the last line below. + +[cache_req_search_send] (0x0400): [CID#1] CR #1: Looking up GID:1031401119@testrealm.test +[cache_req_search_send] (0x0400): [CID#1] CR #1: Looking up GID:1031401119@testrealm.test +[cache_req_search_send] (0x0400): [CID#1] CR #1: Looking up GID:1031401119@domain-zflo.com +[cache_req_search_send] (0x0400): [CID#1] CR #1: Returning [GID:1031401119@domain-zflo.com] from cache + +Reviewed-by: Iker Pedrosa +Reviewed-by: Tomáš Halman +(cherry picked from commit bfa8d50c479cf8ef7b299eb5848309a3a9ea7f12) + +Reviewed-by: Iker Pedrosa +Reviewed-by: Tomáš Halman +--- + src/tools/analyzer/modules/request.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/tools/analyzer/modules/request.py b/src/tools/analyzer/modules/request.py +index 15c8e6bfb..bf279ea75 100644 +--- a/src/tools/analyzer/modules/request.py ++++ b/src/tools/analyzer/modules/request.py +@@ -214,7 +214,7 @@ class RequestAnalyzer: + print(" - " + name[:-1]) + cr_done.append(cr) + if (id and ("UID" in cidline or "GID" in cidline)): +- if id not in id_done: ++ if id not in id_done and bool(re.search(r'\d', id)): + print(" - " + id) + id_done.append(id) + +-- +2.37.3 + diff --git a/SOURCES/0014-TOOLS-don-t-export-internal-helpers.patch b/SOURCES/0014-TOOLS-don-t-export-internal-helpers.patch new file mode 100644 index 0000000..7a5c780 --- /dev/null +++ b/SOURCES/0014-TOOLS-don-t-export-internal-helpers.patch @@ -0,0 +1,94 @@ +From 7e23e6394b518dd013c6b03a1a63715899180935 Mon Sep 17 00:00:00 2001 +From: Alexey Tikhonov +Date: Sun, 6 Nov 2022 11:22:22 +0100 +Subject: [PATCH 14/16] TOOLS: don't export internal helpers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Iker Pedrosa +Reviewed-by: Justin Stephenson +Reviewed-by: Pavel Březina +(cherry picked from commit 6ef3aade0394e32540242f902c9f21bb8d6c41f2) + +Reviewed-by: Iker Pedrosa +Reviewed-by: Justin Stephenson +--- + src/tools/common/sss_tools.c | 16 ++++++++-------- + src/tools/common/sss_tools.h | 12 ------------ + 2 files changed, 8 insertions(+), 20 deletions(-) + +diff --git a/src/tools/common/sss_tools.c b/src/tools/common/sss_tools.c +index c066ddc5c..47b85bdd2 100644 +--- a/src/tools/common/sss_tools.c ++++ b/src/tools/common/sss_tools.c +@@ -178,9 +178,9 @@ static errno_t sss_tool_domains_init(TALLOC_CTX *mem_ctx, + return ret; + } + +-errno_t sss_tool_init(TALLOC_CTX *mem_ctx, +- int *argc, const char **argv, +- struct sss_tool_ctx **_tool_ctx) ++static errno_t sss_tool_init(TALLOC_CTX *mem_ctx, ++ int *argc, const char **argv, ++ struct sss_tool_ctx **_tool_ctx) + { + struct sss_tool_ctx *tool_ctx; + +@@ -235,7 +235,7 @@ static size_t sss_tool_max_length(struct sss_route_cmd *commands) + return max; + } + +-void sss_tool_usage(const char *tool_name, struct sss_route_cmd *commands) ++static void sss_tool_usage(const char *tool_name, struct sss_route_cmd *commands) + { + int min_len; + int i; +@@ -304,10 +304,10 @@ done: + return ret; + } + +-errno_t sss_tool_route(int argc, const char **argv, +- struct sss_tool_ctx *tool_ctx, +- struct sss_route_cmd *commands, +- void *pvt) ++static errno_t sss_tool_route(int argc, const char **argv, ++ struct sss_tool_ctx *tool_ctx, ++ struct sss_route_cmd *commands, ++ void *pvt) + { + struct sss_cmdline cmdline; + const char *cmd; +diff --git a/src/tools/common/sss_tools.h b/src/tools/common/sss_tools.h +index 0e4308ee6..578186633 100644 +--- a/src/tools/common/sss_tools.h ++++ b/src/tools/common/sss_tools.h +@@ -35,10 +35,6 @@ struct sss_tool_ctx { + struct sss_domain_info *domains; + }; + +-errno_t sss_tool_init(TALLOC_CTX *mem_ctx, +- int *argc, const char **argv, +- struct sss_tool_ctx **_tool_ctx); +- + struct sss_cmdline { + const char *exec; /* argv[0] */ + const char *command; /* command name */ +@@ -69,14 +65,6 @@ struct sss_route_cmd { + int flags; + }; + +-void sss_tool_usage(const char *tool_name, +- struct sss_route_cmd *commands); +- +-errno_t sss_tool_route(int argc, const char **argv, +- struct sss_tool_ctx *tool_ctx, +- struct sss_route_cmd *commands, +- void *pvt); +- + typedef errno_t (*sss_popt_fn)(poptContext pc, char option, void *pvt); + + enum sss_tool_opt { +-- +2.37.3 + diff --git a/SOURCES/0015-TOOLS-fixed-handling-of-init-error.patch b/SOURCES/0015-TOOLS-fixed-handling-of-init-error.patch new file mode 100644 index 0000000..45c291a --- /dev/null +++ b/SOURCES/0015-TOOLS-fixed-handling-of-init-error.patch @@ -0,0 +1,71 @@ +From bd16242ef6780fd2808bf03f79eda5d940094bc5 Mon Sep 17 00:00:00 2001 +From: Alexey Tikhonov +Date: Sun, 6 Nov 2022 12:25:37 +0100 +Subject: [PATCH 15/16] TOOLS: fixed handling of init error +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Before execution of `tool_cmd_init()` `init_err` wasn't set, +so `sss_tools_handles_init_error()` check was a no-op. + +Consequently, a proper check after `tool_cmd_init()` was missing. + +Reviewed-by: Iker Pedrosa +Reviewed-by: Justin Stephenson +Reviewed-by: Pavel Březina +(cherry picked from commit 7af46ba0e925da61b7b4003c3fa6d51c05c1116e) + +Reviewed-by: Iker Pedrosa +Reviewed-by: Justin Stephenson +--- + src/tools/common/sss_tools.c | 17 ++++------------- + src/tools/common/sss_tools.h | 1 - + 2 files changed, 4 insertions(+), 14 deletions(-) + +diff --git a/src/tools/common/sss_tools.c b/src/tools/common/sss_tools.c +index 47b85bdd2..38ae88306 100644 +--- a/src/tools/common/sss_tools.c ++++ b/src/tools/common/sss_tools.c +@@ -336,22 +336,13 @@ static errno_t sss_tool_route(int argc, const char **argv, + cmdline.argc = argc - 2; + cmdline.argv = argv + 2; + +- if (!sss_tools_handles_init_error(&commands[i], tool_ctx->init_err)) { +- DEBUG(SSSDBG_FATAL_FAILURE, +- "Command %s does not handle initialization error [%d] %s\n", +- cmdline.command, tool_ctx->init_err, +- sss_strerror(tool_ctx->init_err)); +- return tool_ctx->init_err; +- } +- + if (!tool_ctx->print_help) { + ret = tool_cmd_init(tool_ctx, &commands[i]); +- if (ret == ERR_SYSDB_VERSION_TOO_OLD) { +- tool_ctx->init_err = ret; +- } else if (ret != EOK) { ++ ++ if (!sss_tools_handles_init_error(&commands[i], ret)) { + DEBUG(SSSDBG_FATAL_FAILURE, +- "Command initialization failed [%d] %s\n", +- ret, sss_strerror(ret)); ++ "Command %s does not handle initialization error [%d] %s\n", ++ cmdline.command, ret, sss_strerror(ret)); + return ret; + } + } +diff --git a/src/tools/common/sss_tools.h b/src/tools/common/sss_tools.h +index 578186633..75dc15391 100644 +--- a/src/tools/common/sss_tools.h ++++ b/src/tools/common/sss_tools.h +@@ -30,7 +30,6 @@ struct sss_tool_ctx { + struct confdb_ctx *confdb; + + bool print_help; +- errno_t init_err; + char *default_domain; + struct sss_domain_info *domains; + }; +-- +2.37.3 + diff --git a/SOURCES/0016-SSSCTL-don-t-require-root-for-analyze-cmd.patch b/SOURCES/0016-SSSCTL-don-t-require-root-for-analyze-cmd.patch new file mode 100644 index 0000000..698472c --- /dev/null +++ b/SOURCES/0016-SSSCTL-don-t-require-root-for-analyze-cmd.patch @@ -0,0 +1,89 @@ +From 66c318d212d56e26f303fc52d5fecbde4a6b9589 Mon Sep 17 00:00:00 2001 +From: Alexey Tikhonov +Date: Thu, 10 Nov 2022 22:18:06 +0100 +Subject: [PATCH 16/16] SSSCTL: don't require 'root' for "analyze" cmd +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +:relnote: `sssctl analyze` tool doesn't require anymore to be run under root. + +Reviewed-by: Iker Pedrosa +Reviewed-by: Justin Stephenson +Reviewed-by: Pavel Březina +(cherry picked from commit 99791400bec1054cf0081884e013a3cbed75fe8a) + +Reviewed-by: Iker Pedrosa +Reviewed-by: Justin Stephenson +--- + src/tools/common/sss_tools.c | 16 +++++++++------- + src/tools/common/sss_tools.h | 3 ++- + src/tools/sssctl/sssctl.c | 2 +- + 3 files changed, 12 insertions(+), 9 deletions(-) + +diff --git a/src/tools/common/sss_tools.c b/src/tools/common/sss_tools.c +index 38ae88306..d16de7c4d 100644 +--- a/src/tools/common/sss_tools.c ++++ b/src/tools/common/sss_tools.c +@@ -267,6 +267,15 @@ static int tool_cmd_init(struct sss_tool_ctx *tool_ctx, + struct sss_route_cmd *command) + { + int ret; ++ uid_t uid; ++ ++ if (!(command->flags & SSS_TOOL_FLAG_SKIP_ROOT_CHECK)) { ++ uid = getuid(); ++ if (uid != 0) { ++ ERROR("'%s' must be run as root\n", command->command); ++ return EXIT_FAILURE; ++ } ++ } + + if (command->flags & SSS_TOOL_FLAG_SKIP_CMD_INIT) { + return EOK; +@@ -515,15 +524,8 @@ int sss_tool_main(int argc, const char **argv, + void *pvt) + { + struct sss_tool_ctx *tool_ctx; +- uid_t uid; + errno_t ret; + +- uid = getuid(); +- if (uid != 0) { +- ERROR("%1$s must be run as root\n", argv[0]); +- return EXIT_FAILURE; +- } +- + ret = sss_tool_init(NULL, &argc, argv, &tool_ctx); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tool context\n"); +diff --git a/src/tools/common/sss_tools.h b/src/tools/common/sss_tools.h +index 75dc15391..24dd4b559 100644 +--- a/src/tools/common/sss_tools.h ++++ b/src/tools/common/sss_tools.h +@@ -54,7 +54,8 @@ typedef errno_t + #define SSS_TOOL_DELIMITER(message) {"", _(message), 0, NULL, 0} + #define SSS_TOOL_LAST {NULL, NULL, 0, NULL, 0} + +-#define SSS_TOOL_FLAG_SKIP_CMD_INIT 0x01 ++#define SSS_TOOL_FLAG_SKIP_CMD_INIT 0x01 ++#define SSS_TOOL_FLAG_SKIP_ROOT_CHECK 0x02 + + struct sss_route_cmd { + const char *command; +diff --git a/src/tools/sssctl/sssctl.c b/src/tools/sssctl/sssctl.c +index f18689f9f..b73d19ffe 100644 +--- a/src/tools/sssctl/sssctl.c ++++ b/src/tools/sssctl/sssctl.c +@@ -296,7 +296,7 @@ int main(int argc, const char **argv) + SSS_TOOL_COMMAND("logs-remove", "Remove existing SSSD log files", 0, sssctl_logs_remove), + SSS_TOOL_COMMAND("logs-fetch", "Archive SSSD log files in tarball", 0, sssctl_logs_fetch), + SSS_TOOL_COMMAND("debug-level", "Change SSSD debug level", 0, sssctl_debug_level), +- SSS_TOOL_COMMAND_FLAGS("analyze", "Analyze logged data", 0, sssctl_analyze, SSS_TOOL_FLAG_SKIP_CMD_INIT), ++ SSS_TOOL_COMMAND_FLAGS("analyze", "Analyze logged data", 0, sssctl_analyze, SSS_TOOL_FLAG_SKIP_CMD_INIT|SSS_TOOL_FLAG_SKIP_ROOT_CHECK), + #ifdef HAVE_LIBINI_CONFIG_V1_3 + SSS_TOOL_DELIMITER("Configuration files tools:"), + SSS_TOOL_COMMAND_FLAGS("config-check", "Perform static analysis of SSSD configuration", 0, sssctl_config_check, SSS_TOOL_FLAG_SKIP_CMD_INIT), +-- +2.37.3 + diff --git a/SOURCES/0017-PAC-allow-to-disable-UPN-check.patch b/SOURCES/0017-PAC-allow-to-disable-UPN-check.patch new file mode 100644 index 0000000..f5b565d --- /dev/null +++ b/SOURCES/0017-PAC-allow-to-disable-UPN-check.patch @@ -0,0 +1,49 @@ +From a86d1740167031bf6444ff821a201164c11ba09c Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Wed, 16 Nov 2022 09:28:54 +0100 +Subject: [PATCH 17/19] PAC: allow to disable UPN check + +Currently it was not possible to skip the UPN check which checks if the +UPN in the PAC and the one stored in SSSD's cache are different. +Additionally the related debug message will show both principals if they +differ. + +Resolves: https://github.com/SSSD/sssd/issues/6451 + +(cherry picked from commit 91789449b7a8b20056e1edfedd8f8cf92f7a0a2a) + +Reviewed-by: Alexey Tikhonov +--- + src/providers/ad/ad_pac_common.c | 16 +++++++++++++--- + 1 file changed, 13 insertions(+), 3 deletions(-) + +diff --git a/src/providers/ad/ad_pac_common.c b/src/providers/ad/ad_pac_common.c +index 0ed817111..79f79b7a7 100644 +--- a/src/providers/ad/ad_pac_common.c ++++ b/src/providers/ad/ad_pac_common.c +@@ -224,9 +224,19 @@ errno_t check_upn_and_sid_from_user_and_pac(struct ldb_message *msg, + + if (user_data != NULL) { + if (strcasecmp(user_data, upn_dns_info->upn_name) != 0) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "UPN of user entry and PAC do not match.\n"); +- return ERR_CHECK_PAC_FAILED; ++ if (pac_check_opts & CHECK_PAC_CHECK_UPN) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "UPN of user entry [%s] and " ++ "PAC [%s] do not match.\n", ++ user_data, ++ upn_dns_info->upn_name); ++ return ERR_CHECK_PAC_FAILED; ++ } else { ++ DEBUG(SSSDBG_IMPORTANT_INFO, "UPN of user entry [%s] and " ++ "PAC [%s] do not match, " ++ "ignored.\n", user_data, ++ upn_dns_info->upn_name); ++ return EOK; ++ } + } + } + +-- +2.37.3 + diff --git a/SOURCES/0018-ipa-do-not-add-guessed-principal-to-the-cache.patch b/SOURCES/0018-ipa-do-not-add-guessed-principal-to-the-cache.patch new file mode 100644 index 0000000..7ab2783 --- /dev/null +++ b/SOURCES/0018-ipa-do-not-add-guessed-principal-to-the-cache.patch @@ -0,0 +1,90 @@ +From 29aa434816ce6ae2aaf3b0bcf24b89f05f426d1b Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 22 Nov 2022 13:39:26 +0100 +Subject: [PATCH 18/19] ipa: do not add guessed principal to the cache + +Currently on IPA clients a calculated principal based on the user name +and the Kerberos realm is added to the cached user object. This code is +quite old and might have been necessary at times when sub-domain support +was added to SSSD. But since quite some time SSSD is capable of +generating the principal on the fly during authentication if nothing is +stored in the cache. + +Removing the code makes the cache more consistent with other use-cases, +e.g. with the IPA server where this attribute is empty, and allows to +properly detect a missing UPN, e.g. during the PAC validation. + +Resolves: https://github.com/SSSD/sssd/issues/6451 + +(cherry picked from commit b3d7a4f6d4e1d4fa1bd33b296cd4301973f1860c) + +Reviewed-by: Alexey Tikhonov +--- + src/providers/ipa/ipa_s2n_exop.c | 44 -------------------------------- + 1 file changed, 44 deletions(-) + +diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c +index c68c1de26..81927a6b8 100644 +--- a/src/providers/ipa/ipa_s2n_exop.c ++++ b/src/providers/ipa/ipa_s2n_exop.c +@@ -2467,8 +2467,6 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom, + time_t now; + struct sss_nss_homedir_ctx homedir_ctx; + char *name = NULL; +- char *realm; +- char *short_name = NULL; + char *upn = NULL; + gid_t gid; + gid_t orig_gid = 0; +@@ -2607,48 +2605,6 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom, + goto done; + } + +- if (upn == NULL) { +- /* We also have to store a fake UPN here, because otherwise the +- * krb5 child later won't be able to properly construct one as +- * the username is fully qualified but the child doesn't have +- * access to the regex to deconstruct it */ +- /* FIXME: The real UPN is available from the PAC, we should get +- * it from there. */ +- realm = get_uppercase_realm(tmp_ctx, dom->name); +- if (!realm) { +- DEBUG(SSSDBG_OP_FAILURE, "failed to get realm.\n"); +- ret = ENOMEM; +- goto done; +- } +- +- ret = sss_parse_internal_fqname(tmp_ctx, attrs->a.user.pw_name, +- &short_name, NULL); +- if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "Cannot parse internal name %s\n", +- attrs->a.user.pw_name); +- goto done; +- } +- +- upn = talloc_asprintf(tmp_ctx, "%s@%s", short_name, realm); +- if (!upn) { +- DEBUG(SSSDBG_OP_FAILURE, "failed to format UPN.\n"); +- ret = ENOMEM; +- goto done; +- } +- +- /* We might already have the SID or the UPN from other sources +- * hence sysdb_attrs_add_string_safe is used to avoid double +- * entries. */ +- ret = sysdb_attrs_add_string_safe(attrs->sysdb_attrs, SYSDB_UPN, +- upn); +- if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, +- "sysdb_attrs_add_string failed.\n"); +- goto done; +- } +- } +- + if (req_input->type == REQ_INP_SECID) { + ret = sysdb_attrs_add_string_safe(attrs->sysdb_attrs, + SYSDB_SID_STR, +-- +2.37.3 + diff --git a/SOURCES/0019-pac-relax-default-check.patch b/SOURCES/0019-pac-relax-default-check.patch new file mode 100644 index 0000000..178a1e2 --- /dev/null +++ b/SOURCES/0019-pac-relax-default-check.patch @@ -0,0 +1,164 @@ +From 0e618c36ed74c240f7acd071ccb7bfd405b2d827 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 22 Nov 2022 14:43:21 +0100 +Subject: [PATCH 19/19] pac: relax default check + +To avoid issues with the UPN check during PAC validation when +'ldap_user_principal' is set to a not existing attribute to skip reading +user principals a new 'pac_check' option, 'check_upn_allow_missing' is +added to the default options. With this option only a log message is +shown but the check will not fail. + +Resolves: https://github.com/SSSD/sssd/issues/6451 + +(cherry picked from commit 51b11db8b99a77ba5ccf6f850c2e81b5a6ee9f79) + +Reviewed-by: Alexey Tikhonov +--- + src/confdb/confdb.h | 2 +- + src/man/sssd.conf.5.xml | 30 +++++++++++++++++++++++++++++- + src/providers/ad/ad_pac_common.c | 24 ++++++++++++++++++++---- + src/util/pac_utils.c | 10 ++++++++++ + src/util/util.h | 2 ++ + 5 files changed, 62 insertions(+), 6 deletions(-) + +diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h +index 83f6be7f9..5fda67585 100644 +--- a/src/confdb/confdb.h ++++ b/src/confdb/confdb.h +@@ -181,7 +181,7 @@ + #define CONFDB_PAC_LIFETIME "pac_lifetime" + #define CONFDB_PAC_CHECK "pac_check" + #define CONFDB_PAC_CHECK_DEFAULT "no_check" +-#define CONFDB_PAC_CHECK_IPA_AD_DEFAULT "check_upn, check_upn_dns_info_ex" ++#define CONFDB_PAC_CHECK_IPA_AD_DEFAULT "check_upn, check_upn_allow_missing, check_upn_dns_info_ex" + + /* InfoPipe */ + #define CONFDB_IFP_CONF_ENTRY "config/ifp" +diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml +index 7a9920815..d9f4a7481 100644 +--- a/src/man/sssd.conf.5.xml ++++ b/src/man/sssd.conf.5.xml +@@ -2275,6 +2275,34 @@ pam_gssapi_indicators_map = sudo:pkinit, sudo-i:pkinit + consistent. + + ++ ++ check_upn_allow_missing ++ ++ This option should be used together ++ with 'check_upn' and handles the case where ++ a UPN is set on the server-side but is not ++ read by SSSD. The typical example is a ++ FreeIPA domain where 'ldap_user_principal' ++ is set to a not existing attribute name. ++ This was typically done to work-around ++ issues in the handling of enterprise ++ principals. But this is fixed since quite ++ some time and FreeIPA can handle enterprise ++ principals just fine and there is no need ++ anymore to set 'ldap_user_principal'. ++ Currently this option is set by ++ default to avoid regressions in such ++ environments. A log message will be added ++ to the system log and SSSD's debug log in ++ case a UPN is found in the PAC but not in ++ SSSD's cache. To avoid this log message it ++ would be best to evaluate if the ++ 'ldap_user_principal' option can be removed. ++ If this is not possible, removing ++ 'check_upn' will skip the test and avoid the ++ log message. ++ ++ + + upn_dns_info_present + +@@ -2305,7 +2333,7 @@ pam_gssapi_indicators_map = sudo:pkinit, sudo-i:pkinit + + + Default: no_check (AD and IPA provider +- 'check_upn, check_upn_dns_info_ex') ++ 'check_upn, check_upn_allow_missing, check_upn_dns_info_ex') + + + +diff --git a/src/providers/ad/ad_pac_common.c b/src/providers/ad/ad_pac_common.c +index 79f79b7a7..fcb54cd2c 100644 +--- a/src/providers/ad/ad_pac_common.c ++++ b/src/providers/ad/ad_pac_common.c +@@ -215,10 +215,26 @@ errno_t check_upn_and_sid_from_user_and_pac(struct ldb_message *msg, + DEBUG(SSSDBG_MINOR_FAILURE, "User object does not have a UPN but PAC " + "says otherwise, maybe ldap_user_principal option is set.\n"); + if (pac_check_opts & CHECK_PAC_CHECK_UPN) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "UPN is missing but PAC UPN check required, " +- "PAC validation failed.\n"); +- return ERR_CHECK_PAC_FAILED; ++ if (pac_check_opts & CHECK_PAC_CHECK_UPN_ALLOW_MISSING) { ++ DEBUG(SSSDBG_IMPORTANT_INFO, ++ "UPN is missing but PAC UPN check required, " ++ "PAC validation failed. However, " ++ "'check_upn_allow_missing' is set and the error is " ++ "ignored. To make this message go away please check " ++ "why the UPN is not read from the server. In FreeIPA " ++ "environments 'ldap_user_principal' is most probably " ++ "set to a non-existing attribute name to avoid " ++ "issues with enterprise principals. This is not " ++ "needed anymore with recent versions of FreeIPA.\n"); ++ sss_log(SSS_LOG_CRIT, "PAC validation issue, please check " ++ "sssd_pac.log for details"); ++ return EOK; ++ } else { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "UPN is missing but PAC UPN check required, " ++ "PAC validation failed.\n"); ++ return ERR_CHECK_PAC_FAILED; ++ } + } + } + +diff --git a/src/util/pac_utils.c b/src/util/pac_utils.c +index c53b0c082..4499d8dfd 100644 +--- a/src/util/pac_utils.c ++++ b/src/util/pac_utils.c +@@ -64,6 +64,8 @@ static errno_t check_check_pac_opt(const char *inp, uint32_t *check_pac_flags) + flags |= CHECK_PAC_CHECK_UPN_DNS_INFO_EX; + flags |= CHECK_PAC_UPN_DNS_INFO_PRESENT; + flags |= CHECK_PAC_CHECK_UPN; ++ } else if (strcasecmp(list[c], CHECK_PAC_CHECK_UPN_ALLOW_MISSING_STR) == 0) { ++ flags |= CHECK_PAC_CHECK_UPN_ALLOW_MISSING; + } else { + DEBUG(SSSDBG_OP_FAILURE, "Unknown value [%s] for pac_check.\n", + list[c]); +@@ -72,6 +74,14 @@ static errno_t check_check_pac_opt(const char *inp, uint32_t *check_pac_flags) + } + } + ++ if ((flags & CHECK_PAC_CHECK_UPN_ALLOW_MISSING) ++ && !(flags & CHECK_PAC_CHECK_UPN)) { ++ DEBUG(SSSDBG_CONF_SETTINGS, ++ "pac_check option '%s' is set but '%s' is not set, this means " ++ "the UPN is not checked.\n", ++ CHECK_PAC_CHECK_UPN_ALLOW_MISSING_STR, CHECK_PAC_CHECK_UPN_STR); ++ } ++ + ret = EOK; + + done: +diff --git a/src/util/util.h b/src/util/util.h +index 6d9111874..4b2651c2c 100644 +--- a/src/util/util.h ++++ b/src/util/util.h +@@ -818,6 +818,8 @@ uint64_t get_spend_time_us(uint64_t st); + #define CHECK_PAC_CHECK_UPN_DNS_INFO_EX (1 << 3) + #define CHECK_PAC_UPN_DNS_INFO_EX_PRESENT_STR "upn_dns_info_ex_present" + #define CHECK_PAC_UPN_DNS_INFO_EX_PRESENT (1 << 4) ++#define CHECK_PAC_CHECK_UPN_ALLOW_MISSING_STR "check_upn_allow_missing" ++#define CHECK_PAC_CHECK_UPN_ALLOW_MISSING (1 << 5) + + errno_t get_pac_check_config(struct confdb_ctx *cdb, uint32_t *pac_check_opts); + #endif /* __SSSD_UTIL_H__ */ +-- +2.37.3 + diff --git a/SOURCES/0020-oidc_child-escape-scopes.patch b/SOURCES/0020-oidc_child-escape-scopes.patch new file mode 100644 index 0000000..606eb26 --- /dev/null +++ b/SOURCES/0020-oidc_child-escape-scopes.patch @@ -0,0 +1,102 @@ +From ace43c8ce02d19cf536ce35749aa2ed734089189 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 18 Aug 2022 13:55:21 +0200 +Subject: [PATCH 20/23] oidc_child: escape scopes +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Before using the user provided scopes in the HTTP request they should be +properly escaped according to RFC-3986. + +Resolves: https://github.com/SSSD/sssd/issues/6146 + +Reviewed-by: Justin Stephenson +Reviewed-by: Pavel Březina +(cherry picked from commit 12d5c6344ee304c1f3bc155a76ab37fcd20e78cb) + +Reviewed-by: Alexey Tikhonov +--- + src/oidc_child/oidc_child.c | 4 ++-- + src/oidc_child/oidc_child_curl.c | 35 ++++++++++++++++++++++++++++++++ + src/oidc_child/oidc_child_util.h | 2 ++ + 3 files changed, 39 insertions(+), 2 deletions(-) + +diff --git a/src/oidc_child/oidc_child.c b/src/oidc_child/oidc_child.c +index e58afccd3..aeeac3595 100644 +--- a/src/oidc_child/oidc_child.c ++++ b/src/oidc_child/oidc_child.c +@@ -119,9 +119,9 @@ static errno_t set_endpoints(struct devicecode_ctx *dc_ctx, + } + + if (scope != NULL && *scope != '\0') { +- dc_ctx->scope = talloc_strdup(dc_ctx, scope); ++ dc_ctx->scope = url_encode_string(dc_ctx, scope); + if (dc_ctx->scope == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Failed to copy scopes.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to encode and copy scopes.\n"); + ret = ENOMEM; + goto done; + } +diff --git a/src/oidc_child/oidc_child_curl.c b/src/oidc_child/oidc_child_curl.c +index 20e17a566..df438e007 100644 +--- a/src/oidc_child/oidc_child_curl.c ++++ b/src/oidc_child/oidc_child_curl.c +@@ -26,6 +26,41 @@ + #include + #include "oidc_child/oidc_child_util.h" + ++char *url_encode_string(TALLOC_CTX *mem_ctx, const char *inp) ++{ ++ CURL *curl_ctx = NULL; ++ char *tmp; ++ char *out = NULL; ++ ++ if (inp == NULL) { ++ DEBUG(SSSDBG_TRACE_ALL, "Empty input.\n"); ++ return NULL; ++ } ++ ++ curl_ctx = curl_easy_init(); ++ if (curl_ctx == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "Failed to initialize curl.\n"); ++ return NULL; ++ } ++ ++ tmp = curl_easy_escape(curl_ctx, inp, 0); ++ if (tmp == NULL) { ++ DEBUG(SSSDBG_TRACE_ALL, "curl_easy_escape failed for [%s].\n", inp); ++ goto done; ++ } ++ ++ out = talloc_strdup(mem_ctx, tmp); ++ curl_free(tmp); ++ if (out == NULL) { ++ DEBUG(SSSDBG_TRACE_ALL, "talloc_strdup failed.\n"); ++ goto done; ++ } ++ ++done: ++ curl_easy_cleanup(curl_ctx); ++ return (out); ++} ++ + /* The curl write_callback will always append the received data. To start a + * new string call clean_http_data() before the curl request.*/ + void clean_http_data(struct devicecode_ctx *dc_ctx) +diff --git a/src/oidc_child/oidc_child_util.h b/src/oidc_child/oidc_child_util.h +index c781bf1b1..ae5a72bc2 100644 +--- a/src/oidc_child/oidc_child_util.h ++++ b/src/oidc_child/oidc_child_util.h +@@ -61,6 +61,8 @@ struct devicecode_ctx { + }; + + /* oidc_child_curl.c */ ++char *url_encode_string(TALLOC_CTX *mem_ctx, const char *inp); ++ + errno_t init_curl(void *p); + + void clean_http_data(struct devicecode_ctx *dc_ctx); +-- +2.37.3 + diff --git a/SOURCES/0021-oidc_child-use-client-secret-if-available-to-get-dev.patch b/SOURCES/0021-oidc_child-use-client-secret-if-available-to-get-dev.patch new file mode 100644 index 0000000..2a4e9ab --- /dev/null +++ b/SOURCES/0021-oidc_child-use-client-secret-if-available-to-get-dev.patch @@ -0,0 +1,89 @@ +From 3e296c70d56e2aa83ce882d2ac1738f85606fd7a Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 18 Aug 2022 14:01:34 +0200 +Subject: [PATCH 21/23] oidc_child: use client secret if available to get + device code +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Some IdP have the concept of confidential client, i.e. clients where the +client's secret can be stored safely by the related application. For a +confidential client some IdPs expects that the client secret is used in +all requests together with the client ID although OAuth2 specs currently +only mention this explicitly for the token request. To make sure the +device code can be requested in this case the client secret is added to +the device code request if the secret is provided. + +Resolves: https://github.com/SSSD/sssd/issues/6146 + +Reviewed-by: Justin Stephenson +Reviewed-by: Pavel Březina +(cherry picked from commit a4d4617efeff871c5d2762e35f9dec57fa24fb1a) + +Reviewed-by: Alexey Tikhonov +--- + src/oidc_child/oidc_child.c | 2 +- + src/oidc_child/oidc_child_curl.c | 12 +++++++++++- + src/oidc_child/oidc_child_util.h | 2 +- + 3 files changed, 13 insertions(+), 3 deletions(-) + +diff --git a/src/oidc_child/oidc_child.c b/src/oidc_child/oidc_child.c +index aeeac3595..c8d35d5d8 100644 +--- a/src/oidc_child/oidc_child.c ++++ b/src/oidc_child/oidc_child.c +@@ -454,7 +454,7 @@ int main(int argc, const char *argv[]) + } + + if (opts.get_device_code) { +- ret = get_devicecode(dc_ctx, opts.client_id); ++ ret = get_devicecode(dc_ctx, opts.client_id, opts.client_secret); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Failed to get device code.\n"); + goto done; +diff --git a/src/oidc_child/oidc_child_curl.c b/src/oidc_child/oidc_child_curl.c +index df438e007..6e80c3abf 100644 +--- a/src/oidc_child/oidc_child_curl.c ++++ b/src/oidc_child/oidc_child_curl.c +@@ -428,7 +428,7 @@ done: + #define DEFAULT_SCOPE "user" + + errno_t get_devicecode(struct devicecode_ctx *dc_ctx, +- const char *client_id) ++ const char *client_id, const char *client_secret) + { + int ret; + +@@ -443,6 +443,16 @@ errno_t get_devicecode(struct devicecode_ctx *dc_ctx, + return ENOMEM; + } + ++ if (client_secret != NULL) { ++ post_data = talloc_asprintf_append(post_data, "&client_secret=%s", ++ client_secret); ++ if (post_data == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Failed to add client secret to POST data.\n"); ++ return ENOMEM; ++ } ++ } ++ + clean_http_data(dc_ctx); + ret = do_http_request(dc_ctx, dc_ctx->device_authorization_endpoint, + post_data, NULL); +diff --git a/src/oidc_child/oidc_child_util.h b/src/oidc_child/oidc_child_util.h +index ae5a72bc2..8b106ae79 100644 +--- a/src/oidc_child/oidc_child_util.h ++++ b/src/oidc_child/oidc_child_util.h +@@ -73,7 +73,7 @@ errno_t get_openid_configuration(struct devicecode_ctx *dc_ctx, + errno_t get_jwks(struct devicecode_ctx *dc_ctx); + + errno_t get_devicecode(struct devicecode_ctx *dc_ctx, +- const char *client_id); ++ const char *client_id, const char *client_secret); + + errno_t get_token(TALLOC_CTX *mem_ctx, + struct devicecode_ctx *dc_ctx, const char *client_id, +-- +2.37.3 + diff --git a/SOURCES/0022-oidc_child-increase-wait-interval-by-5s-if-slow_down.patch b/SOURCES/0022-oidc_child-increase-wait-interval-by-5s-if-slow_down.patch new file mode 100644 index 0000000..8d2183c --- /dev/null +++ b/SOURCES/0022-oidc_child-increase-wait-interval-by-5s-if-slow_down.patch @@ -0,0 +1,67 @@ +From 55bfa944ad0197ae294d85ac42abf98297fa3a5d Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 18 Aug 2022 14:19:59 +0200 +Subject: [PATCH 22/23] oidc_child: increase wait interval by 5s if 'slow_down' + is returned +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +While waiting for the user to authenticate with the IdP oidc_child +currently only handles the error code 'authorization_pending' and waits +for the given interval until a new request is send. But there is also +'slow_down' which should not be treated as fatal error but should just +increase the waiting time permanently for 5s. + +Resolves: https://github.com/SSSD/sssd/issues/6146 + +Reviewed-by: Justin Stephenson +Reviewed-by: Pavel Březina +(cherry picked from commit 5ed7670766483040211713f8182510775c76b962) + +Reviewed-by: Alexey Tikhonov +--- + src/oidc_child/oidc_child_curl.c | 8 +++++++- + src/oidc_child/oidc_child_json.c | 6 ++++++ + 2 files changed, 13 insertions(+), 1 deletion(-) + +diff --git a/src/oidc_child/oidc_child_curl.c b/src/oidc_child/oidc_child_curl.c +index 6e80c3abf..cf0976021 100644 +--- a/src/oidc_child/oidc_child_curl.c ++++ b/src/oidc_child/oidc_child_curl.c +@@ -378,8 +378,14 @@ errno_t get_token(TALLOC_CTX *mem_ctx, + break; + } + +- sleep(dc_ctx->interval); + waiting_time += dc_ctx->interval; ++ if (waiting_time >= dc_ctx->expires_in) { ++ /* Next sleep will end after the request is expired on the ++ * server side, so we can just error out now. */ ++ ret = ETIMEDOUT; ++ break; ++ } ++ sleep(dc_ctx->interval); + } while (waiting_time < dc_ctx->expires_in); + + if (ret != EOK) { +diff --git a/src/oidc_child/oidc_child_json.c b/src/oidc_child/oidc_child_json.c +index efc1997aa..a89794c4c 100644 +--- a/src/oidc_child/oidc_child_json.c ++++ b/src/oidc_child/oidc_child_json.c +@@ -413,6 +413,12 @@ errno_t parse_token_result(struct devicecode_ctx *dc_ctx, + if (strcmp(json_string_value(tmp), "authorization_pending") == 0) { + json_decref(result); + return EAGAIN; ++ } else if (strcmp(json_string_value(tmp), "slow_down") == 0) { ++ /* RFC 8628: "... the interval MUST be increased by 5 seconds for" ++ * "this and all subsequent requests." */ ++ dc_ctx->interval += 5; ++ json_decref(result); ++ return EAGAIN; + } else { + *error_description = get_json_string(dc_ctx, result, + "error_description"); +-- +2.37.3 + diff --git a/SOURCES/0023-oidc_child-add-client-secret-stdin-option.patch b/SOURCES/0023-oidc_child-add-client-secret-stdin-option.patch new file mode 100644 index 0000000..8ac9ba7 --- /dev/null +++ b/SOURCES/0023-oidc_child-add-client-secret-stdin-option.patch @@ -0,0 +1,194 @@ +From 2f3cd781879e7063fcd996389071458587623e1c Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 22 Aug 2022 11:37:07 +0200 +Subject: [PATCH 23/23] oidc_child: add --client-secret-stdin option +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Since there is the use-case of confidential client which requires that +the client secret must be sent to the IdP we should handle it +confidentially by not putting it on the command line but sending it via +stdin. + +Resolves: https://github.com/SSSD/sssd/issues/6146 + +Reviewed-by: Justin Stephenson +Reviewed-by: Pavel Březina +(cherry picked from commit 1a475e0c537c905c80406ceb88c7b34e6400bc40) + +Reviewed-by: Alexey Tikhonov +--- + src/oidc_child/oidc_child.c | 89 ++++++++++++++++++++++++++++++++++--- + 1 file changed, 82 insertions(+), 7 deletions(-) + +diff --git a/src/oidc_child/oidc_child.c b/src/oidc_child/oidc_child.c +index c8d35d5d8..7758cdc25 100644 +--- a/src/oidc_child/oidc_child.c ++++ b/src/oidc_child/oidc_child.c +@@ -34,7 +34,7 @@ + #include "util/atomic_io.h" + + #define IN_BUF_SIZE 4096 +-static errno_t read_device_code_from_stdin(struct devicecode_ctx *dc_ctx) ++static errno_t read_from_stdin(TALLOC_CTX *mem_ctx, char **out) + { + uint8_t buf[IN_BUF_SIZE]; + ssize_t len; +@@ -56,7 +56,7 @@ static errno_t read_device_code_from_stdin(struct devicecode_ctx *dc_ctx) + return EINVAL; + } + +- str = talloc_strndup(dc_ctx, (char *) buf, len); ++ str = talloc_strndup(mem_ctx, (char *) buf, len); + sss_erase_mem_securely(buf, IN_BUF_SIZE); + if (str == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strndup failed.\n"); +@@ -65,21 +65,72 @@ static errno_t read_device_code_from_stdin(struct devicecode_ctx *dc_ctx) + talloc_set_destructor((void *) str, sss_erase_talloc_mem_securely); + + if (strlen(str) != len) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "Input contains additional data, " +- "only JSON encoded device code expected.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "Input contains additional data.\n"); + talloc_free(str); + return EINVAL; + } + ++ *out = str; ++ ++ return EOK; ++} ++ ++static errno_t read_device_code_from_stdin(struct devicecode_ctx *dc_ctx, ++ const char **out) ++{ ++ char *str; ++ errno_t ret; ++ char *sep; ++ ++ ret = read_from_stdin(dc_ctx, &str); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "read_from_stdin failed.\n"); ++ return ret; ++ } ++ ++ if (out != NULL) { ++ /* expect the client secret in the first line */ ++ sep = strchr(str, '\n'); ++ if (sep == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Format error, expecting client secret and JSON data.\n"); ++ talloc_free(str); ++ return EINVAL; ++ } ++ *sep = '\0'; ++ *out = str; ++ sep++; ++ } else { ++ sep = str; ++ } ++ + clean_http_data(dc_ctx); +- dc_ctx->http_data = str; ++ dc_ctx->http_data = talloc_strdup(dc_ctx, sep); + + DEBUG(SSSDBG_TRACE_ALL, "JSON device code: [%s].\n", dc_ctx->http_data); + + return EOK; + } + ++static errno_t read_client_secret_from_stdin(struct devicecode_ctx *dc_ctx, ++ const char **out) ++{ ++ char *str; ++ errno_t ret; ++ ++ ret = read_from_stdin(dc_ctx, &str); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "read_from_stdin failed.\n"); ++ return ret; ++ } ++ ++ *out = str; ++ ++ DEBUG(SSSDBG_TRACE_ALL, "Client secret: [%s].\n", *out); ++ ++ return EOK; ++} ++ + static errno_t set_endpoints(struct devicecode_ctx *dc_ctx, + const char *device_auth_endpoint, + const char *token_endpoint, +@@ -210,6 +261,7 @@ struct cli_opts { + const char *jwks_uri; + const char *scope; + const char *client_secret; ++ bool client_secret_stdin; + const char *ca_db; + const char *user_identifier_attr; + bool libcurl_debug; +@@ -253,6 +305,8 @@ static int parse_cli(int argc, const char *argv[], struct cli_opts *opts) + {"client-id", 0, POPT_ARG_STRING, &opts->client_id, 0, _("Client ID"), NULL}, + {"client-secret", 0, POPT_ARG_STRING, &opts->client_secret, 0, + _("Client secret (if needed)"), NULL}, ++ {"client-secret-stdin", 0, POPT_ARG_NONE, NULL, 's', ++ _("Read client secret from standard input"), NULL}, + {"ca-db", 0, POPT_ARG_STRING, &opts->ca_db, 0, + _("Path to PEM file with CA certificates"), NULL}, + {"libcurl-debug", 0, POPT_ARG_NONE, NULL, 'c', +@@ -280,6 +334,9 @@ static int parse_cli(int argc, const char *argv[], struct cli_opts *opts) + case 'c': + opts->libcurl_debug = true; + break; ++ case 's': ++ opts->client_secret_stdin = true; ++ break; + default: + fprintf(stderr, "\nInvalid option %s: %s\n\n", + poptBadOption(pc, 0), poptStrerror(opt)); +@@ -324,6 +381,12 @@ static int parse_cli(int argc, const char *argv[], struct cli_opts *opts) + goto done; + } + ++ if (opts->client_secret != NULL && opts->client_secret_stdin) { ++ fprintf(stderr, "\n--client-secret and --client-secret-stdin are " ++ "mutually exclusive.\n\n"); ++ goto done; ++ } ++ + poptFreeContext(pc); + print_usage = false; + +@@ -454,6 +517,15 @@ int main(int argc, const char *argv[]) + } + + if (opts.get_device_code) { ++ if (opts.client_secret_stdin) { ++ ret = read_client_secret_from_stdin(dc_ctx, &opts.client_secret); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Failed to read client secret from stdin.\n"); ++ goto done; ++ } ++ } ++ + ret = get_devicecode(dc_ctx, opts.client_id, opts.client_secret); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Failed to get device code.\n"); +@@ -463,7 +535,10 @@ int main(int argc, const char *argv[]) + + if (opts.get_access_token) { + if (dc_ctx->device_code == NULL) { +- ret = read_device_code_from_stdin(dc_ctx); ++ ret = read_device_code_from_stdin(dc_ctx, ++ opts.client_secret_stdin ++ ? &opts.client_secret ++ : NULL); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "Failed to read device code from stdin.\n"); +-- +2.37.3 + diff --git a/SPECS/sssd.spec b/SPECS/sssd.spec index 1800e3b..4079416 100644 --- a/SPECS/sssd.spec +++ b/SPECS/sssd.spec @@ -19,7 +19,7 @@ Name: sssd Version: 2.7.3 -Release: 4%{?dist}.1 +Release: 4%{?dist}.3 Group: Applications/System Summary: System Security Services Daemon License: GPLv3+ @@ -38,6 +38,18 @@ Patch0008: 0008-RESPONDER-Fix-client-ID-tracking.patch Patch0009: 0009-Analyzer-support-parallel-requests-parsing.patch Patch0010: 0010-CLIENT-fix-client-fd-leak.patch Patch0011: 0011-krb5-respect-krb5_validate-for-PAC-checks.patch +Patch0012: 0012-Analyzer-Optimize-list-verbose-output.patch +Patch0013: 0013-Analyzer-Ensure-parsed-id-contains-digit.patch +Patch0014: 0014-TOOLS-don-t-export-internal-helpers.patch +Patch0015: 0015-TOOLS-fixed-handling-of-init-error.patch +Patch0016: 0016-SSSCTL-don-t-require-root-for-analyze-cmd.patch +Patch0017: 0017-PAC-allow-to-disable-UPN-check.patch +Patch0018: 0018-ipa-do-not-add-guessed-principal-to-the-cache.patch +Patch0019: 0019-pac-relax-default-check.patch +Patch0020: 0020-oidc_child-escape-scopes.patch +Patch0021: 0021-oidc_child-use-client-secret-if-available-to-get-dev.patch +Patch0022: 0022-oidc_child-increase-wait-interval-by-5s-if-slow_down.patch +Patch0023: 0023-oidc_child-add-client-secret-stdin-option.patch ### Downstream Patches ### @@ -1188,6 +1200,14 @@ fi %systemd_postun_with_restart sssd.service %changelog +* Thu Dec 15 2022 Alexey Tikhonov - 2.7.3-4.3 +- Resolves: rhbz#2152883 - authenticating against external IdP services okta (native app) with OAuth client secret failed [rhel-8.7.0.z] + +* Fri Dec 9 2022 Alexey Tikhonov - 2.7.3-4.2 +- Resolves: rhbz#2139871 - Analyzer: Optimize and remove duplicate messages in verbose list [rhel-8.7.0.z] +- Resolves: rhbz#2142961 - SSSD: `sssctl analyze` command shouldn't require 'root' privileged [rhel-8.7.0.z] +- Resolves: rhbz#2148989 - UPN check cannot be disabled explicitly but requires krb5_validate = false' as a work-around [rhel-8.7.0.z] + * Thu Oct 13 2022 Alexey Tikhonov - 2.7.3-4.1 - Resolves: rhbz#2128544 - Cannot SSH with AD user to ipa-client (`krb5_validate` and `pac_check` settings conflict) [rhel-8.7.0.z]