diff --git a/SOURCES/0069-SYSDB-Add-search-index-originalADgidNumber.patch b/SOURCES/0069-SYSDB-Add-search-index-originalADgidNumber.patch new file mode 100644 index 0000000..b975313 --- /dev/null +++ b/SOURCES/0069-SYSDB-Add-search-index-originalADgidNumber.patch @@ -0,0 +1,165 @@ +From c4b1b8208cd26916dc99b29e09df071c5659b9d4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pawe=C5=82=20Po=C5=82awski?= +Date: Wed, 7 Jul 2021 00:29:59 +0200 +Subject: [PATCH 69/71] SYSDB: Add search index "originalADgidNumber" +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Commit 03bc962 introduced a change which can result in +unindexed search in some scenarios. The result is performance +drop comparing to older SSSD version. + +This PR adds missing search index: originalADgidNumber + +:relnote: Add search index "originalADgidNumber" to SYSDB + +Resolves: https://github.com/SSSD/sssd/issues/5430 + +Reviewed-by: Iker Pedrosa +Reviewed-by: Tomáš Halman + +(cherry picked with changes from commit 17e339d58c57861c093fc53b241873dce00ae958) + +Reviewed-by: Alexey Tikhonov +--- + src/db/sysdb.h | 2 ++ + src/db/sysdb_init.c | 7 ++++++ + src/db/sysdb_private.h | 5 +++- + src/db/sysdb_upgrade.c | 52 ++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 65 insertions(+), 1 deletion(-) + +diff --git a/src/db/sysdb.h b/src/db/sysdb.h +index d47099eff..c771ce633 100644 +--- a/src/db/sysdb.h ++++ b/src/db/sysdb.h +@@ -176,6 +176,8 @@ + #define OVERRIDE_PREFIX "override" + #define SYSDB_DEFAULT_OVERRIDE_NAME "defaultOverrideName" + ++#define SYSDB_ORIG_AD_GID_NUMBER "originalADgidNumber" ++ + #define SYSDB_AD_ACCOUNT_EXPIRES "adAccountExpires" + #define SYSDB_AD_USER_ACCOUNT_CONTROL "adUserAccountControl" + +diff --git a/src/db/sysdb_init.c b/src/db/sysdb_init.c +index 48e21baab..3632d5a19 100644 +--- a/src/db/sysdb_init.c ++++ b/src/db/sysdb_init.c +@@ -566,6 +566,13 @@ static errno_t sysdb_domain_cache_upgrade(TALLOC_CTX *mem_ctx, + } + + ++ if (strcmp(version, SYSDB_VERSION_0_21) == 0) { ++ ret = sysdb_upgrade_21(sysdb, &version); ++ if (ret != EOK) { ++ goto done; ++ } ++ } ++ + ret = EOK; + done: + sysdb->ldb = save_ldb; +diff --git a/src/db/sysdb_private.h b/src/db/sysdb_private.h +index 0ccfa43ac..895cc4ea0 100644 +--- a/src/db/sysdb_private.h ++++ b/src/db/sysdb_private.h +@@ -23,6 +23,7 @@ + #ifndef __INT_SYS_DB_H__ + #define __INT_SYS_DB_H__ + ++#define SYSDB_VERSION_0_22 "0.22" + #define SYSDB_VERSION_0_21 "0.21" + #define SYSDB_VERSION_0_20 "0.20" + #define SYSDB_VERSION_0_19 "0.19" +@@ -45,7 +46,7 @@ + #define SYSDB_VERSION_0_2 "0.2" + #define SYSDB_VERSION_0_1 "0.1" + +-#define SYSDB_VERSION SYSDB_VERSION_0_21 ++#define SYSDB_VERSION SYSDB_VERSION_0_22 + + #define SYSDB_BASE_LDIF \ + "dn: @ATTRIBUTES\n" \ +@@ -81,6 +82,7 @@ + "@IDXATTR: mail\n" \ + "@IDXATTR: userMappedCertificate\n" \ + "@IDXATTR: ccacheFile\n" \ ++ "@IDXATTR: originalADgidNumber\n" \ + "\n" \ + "dn: @MODULES\n" \ + "@LIST: asq,memberof\n" \ +@@ -174,6 +176,7 @@ int sysdb_upgrade_17(struct sysdb_ctx *sysdb, + int sysdb_upgrade_18(struct sysdb_ctx *sysdb, const char **ver); + int sysdb_upgrade_19(struct sysdb_ctx *sysdb, const char **ver); + int sysdb_upgrade_20(struct sysdb_ctx *sysdb, const char **ver); ++int sysdb_upgrade_21(struct sysdb_ctx *sysdb, const char **ver); + + int sysdb_ts_upgrade_01(struct sysdb_ctx *sysdb, const char **ver); + +diff --git a/src/db/sysdb_upgrade.c b/src/db/sysdb_upgrade.c +index 392d04b07..6f160f520 100644 +--- a/src/db/sysdb_upgrade.c ++++ b/src/db/sysdb_upgrade.c +@@ -2553,6 +2553,58 @@ done: + return ret; + } + ++int sysdb_upgrade_21(struct sysdb_ctx *sysdb, const char **ver) ++{ ++ struct upgrade_ctx *ctx; ++ errno_t ret; ++ struct ldb_message *msg = NULL; ++ ++ ret = commence_upgrade(sysdb, sysdb->ldb, SYSDB_VERSION_0_22, &ctx); ++ if (ret) { ++ return ret; ++ } ++ ++ /* Add missing indices */ ++ msg = ldb_msg_new(ctx); ++ if (msg == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ msg->dn = ldb_dn_new(msg, sysdb->ldb, "@INDEXLIST"); ++ if (msg->dn == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = ldb_msg_add_empty(msg, "@IDXATTR", LDB_FLAG_MOD_ADD, NULL); ++ if (ret != LDB_SUCCESS) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = ldb_msg_add_string(msg, "@IDXATTR", SYSDB_ORIG_AD_GID_NUMBER); ++ if (ret != LDB_SUCCESS) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = ldb_modify(sysdb->ldb, msg); ++ if (ret != LDB_SUCCESS) { ++ ret = sysdb_error_to_errno(ret); ++ goto done; ++ } ++ ++ talloc_free(msg); ++ ++ /* conversion done, update version number */ ++ ret = update_version(ctx); ++ ++done: ++ ret = finish_upgrade(ret, &ctx, ver); ++ return ret; ++} ++ + int sysdb_ts_upgrade_01(struct sysdb_ctx *sysdb, const char **ver) + { + struct upgrade_ctx *ctx; +-- +2.26.3 + diff --git a/SOURCES/0070-AD-do-not-override-LDAP-data-during-GC-lookups.patch b/SOURCES/0070-AD-do-not-override-LDAP-data-during-GC-lookups.patch new file mode 100644 index 0000000..0ed8c6a --- /dev/null +++ b/SOURCES/0070-AD-do-not-override-LDAP-data-during-GC-lookups.patch @@ -0,0 +1,66 @@ +From 7afd36a4c4b35d72742eec2d23bd6908e635c097 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 19 Jun 2020 13:36:49 +0200 +Subject: [PATCH 70/71] AD: do not override LDAP data during GC lookups +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The Global Catalog contains user and group information of the whole +forest and hence any Global Catalog server can be used. Currently when a +Global Catalog server is looked up the data of the LDAP server is +overwritten as well. I guess the original intention was to use a single +server for both services. + +However since the Global Catalog server can come from any domain in the +forest this might overwrite the LDAP data of a DC from the local domain +with the data from a AD of a remote domain and as a result lookups for +users and groups from the local domain might fail since the remote DC +does not has this information available at the LDAP port. In most cases +this overwrite is hidden by a following lookup to find a KDC for +authentication which is searched only in the local domain again where +the LDAP data is overwritten again to make sure the same DC is used for +LDAP and Kerberos communication. But depending on the connection +timeouts and lifetime of Kerberos tickets the KDC lookup might be +skipped because new credentials are not needed and as a result the wrong +LDAP data is used. + +To avoid this the LDAP data is now only set if the current lookup is not +a Global Catalog lookup. + +Resolves: https://github.com/SSSD/sssd/issues/5351 + +Reviewed-by: Pavel Březina +(cherry picked from commit 5f3b9e1d45df77bca1b2665e67bbd73b26fafbc2) + +Reviewed-by: Alexey Tikhonov +--- + src/providers/ad/ad_common.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c +index 4e51d08e6..c99c4d110 100644 +--- a/src/providers/ad/ad_common.c ++++ b/src/providers/ad/ad_common.c +@@ -942,10 +942,14 @@ ad_resolve_callback(void *private_data, struct fo_server *server) + } + + /* free old one and replace with new one */ +- talloc_zfree(service->sdap->uri); +- service->sdap->uri = new_uri; +- talloc_zfree(service->sdap->sockaddr); +- service->sdap->sockaddr = talloc_steal(service->sdap, sockaddr); ++ if (sdata == NULL || !sdata->gc) { ++ /* do not update LDAP data during GC lookups because the selected server ++ * might be from a different domain. */ ++ talloc_zfree(service->sdap->uri); ++ service->sdap->uri = new_uri; ++ talloc_zfree(service->sdap->sockaddr); ++ service->sdap->sockaddr = talloc_steal(service->sdap, sockaddr); ++ } + + talloc_zfree(service->gc->uri); + talloc_zfree(service->gc->sockaddr); +-- +2.26.3 + diff --git a/SOURCES/0071-simple-fix-memory-leak-while-reloading-lists.patch b/SOURCES/0071-simple-fix-memory-leak-while-reloading-lists.patch new file mode 100644 index 0000000..0e2877d --- /dev/null +++ b/SOURCES/0071-simple-fix-memory-leak-while-reloading-lists.patch @@ -0,0 +1,103 @@ +From 137924c7894fd5989446ebefd96010a0878004f1 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 12 Jan 2021 16:40:56 +0100 +Subject: [PATCH 71/71] simple: fix memory leak while reloading lists + +The simple access provider will reload the access and deny lists at +runtime to make sure that users and groups from domains which are +discovered at runtime are properly processed. + +While reloading the lists the original lists are not freed and an +intermediate list wasn't removed as well. + +Resolves: https://github.com/SSSD/sssd/issues/5456 + +:fixes: Memory leak in the simple access provider + +Reviewed-by: Alexey Tikhonov +(cherry picked from commit 19c2c641e669ee1c08d6706c132625dc30e64609) + +Reviewed-by: Alexey Tikhonov +--- + src/providers/simple/simple_access.c | 28 +++++++++++++++++++++------- + 1 file changed, 21 insertions(+), 7 deletions(-) + +diff --git a/src/providers/simple/simple_access.c b/src/providers/simple/simple_access.c +index 1868569b1..49226adf2 100644 +--- a/src/providers/simple/simple_access.c ++++ b/src/providers/simple/simple_access.c +@@ -117,17 +117,13 @@ int simple_access_obtain_filter_lists(struct simple_ctx *ctx) + const char *name; + const char *option; + char **orig_list; +- char ***ctx_list; ++ char **ctx_list; + } lists[] = {{"Allow users", CONFDB_SIMPLE_ALLOW_USERS, NULL, NULL}, + {"Deny users", CONFDB_SIMPLE_DENY_USERS, NULL, NULL}, + {"Allow groups", CONFDB_SIMPLE_ALLOW_GROUPS, NULL, NULL}, + {"Deny groups", CONFDB_SIMPLE_DENY_GROUPS, NULL, NULL}, + {NULL, NULL, NULL, NULL}}; + +- lists[0].ctx_list = &ctx->allow_users; +- lists[1].ctx_list = &ctx->deny_users; +- lists[2].ctx_list = &ctx->allow_groups; +- lists[3].ctx_list = &ctx->deny_groups; + + ret = sysdb_master_domain_update(bectx->domain); + if (ret != EOK) { +@@ -141,7 +137,6 @@ int simple_access_obtain_filter_lists(struct simple_ctx *ctx) + lists[i].option, &lists[i].orig_list); + if (ret == ENOENT) { + DEBUG(SSSDBG_FUNC_DATA, "%s list is empty.\n", lists[i].name); +- *lists[i].ctx_list = NULL; + continue; + } else if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "confdb_get_string_as_list failed.\n"); +@@ -149,7 +144,8 @@ int simple_access_obtain_filter_lists(struct simple_ctx *ctx) + } + + ret = simple_access_parse_names(ctx, bectx, lists[i].orig_list, +- lists[i].ctx_list); ++ &lists[i].ctx_list); ++ talloc_free(lists[i].orig_list); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse %s list [%d]: %s\n", + lists[i].name, ret, sss_strerror(ret)); +@@ -157,6 +153,18 @@ int simple_access_obtain_filter_lists(struct simple_ctx *ctx) + } + } + ++ talloc_free(ctx->allow_users); ++ ctx->allow_users = talloc_steal(ctx, lists[0].ctx_list); ++ ++ talloc_free(ctx->deny_users); ++ ctx->deny_users = talloc_steal(ctx, lists[1].ctx_list); ++ ++ talloc_free(ctx->allow_groups); ++ ctx->allow_groups = talloc_steal(ctx, lists[2].ctx_list); ++ ++ talloc_free(ctx->deny_groups); ++ ctx->deny_groups = talloc_steal(ctx, lists[3].ctx_list); ++ + if (!ctx->allow_users && + !ctx->allow_groups && + !ctx->deny_users && +@@ -165,9 +173,15 @@ int simple_access_obtain_filter_lists(struct simple_ctx *ctx) + "No rules supplied for simple access provider. " + "Access will be granted for all users.\n"); + } ++ ++ + return EOK; + + failed: ++ for (i = 0; lists[i].name != NULL; i++) { ++ talloc_free(lists[i].ctx_list); ++ } ++ + return ret; + } + +-- +2.26.3 + diff --git a/SOURCES/0072-TOOLS-replace-system-with-execvp.patch b/SOURCES/0072-TOOLS-replace-system-with-execvp.patch new file mode 100644 index 0000000..a5ae447 --- /dev/null +++ b/SOURCES/0072-TOOLS-replace-system-with-execvp.patch @@ -0,0 +1,277 @@ +From a0d310e2c86facc8727b781e060b2b769313a5dd Mon Sep 17 00:00:00 2001 +From: Alexey Tikhonov +Date: Fri, 30 Jul 2021 19:05:31 +0200 +Subject: [PATCH] TOOLS: replace system() with execvp() to avoid execution of + user supplied command + +A flaw was found in SSSD, where the sssctl command was vulnerable +to shell command injection via the logs-fetch and cache-expire +subcommands. This flaw allows an attacker to trick the root user +into running a specially crafted sssctl command, such as via sudo, +to gain root access. The highest threat from this vulnerability is +to confidentiality, integrity, as well as system availability. + +:fixes: CVE-2021-3621 +--- + src/tools/sssctl/sssctl.c | 40 +++++++++++++++++------- + src/tools/sssctl/sssctl.h | 2 +- + src/tools/sssctl/sssctl_data.c | 57 +++++++++++----------------------- + src/tools/sssctl/sssctl_logs.c | 31 ++++++++++++++---- + 4 files changed, 73 insertions(+), 57 deletions(-) + +diff --git a/src/tools/sssctl/sssctl.c b/src/tools/sssctl/sssctl.c +index 4a50a1d..bfc791b 100644 +--- a/src/tools/sssctl/sssctl.c ++++ b/src/tools/sssctl/sssctl.c +@@ -97,22 +97,37 @@ sssctl_prompt(const char *message, + return SSSCTL_PROMPT_ERROR; + } + +-errno_t sssctl_run_command(const char *command) ++errno_t sssctl_run_command(const char *const argv[]) + { + int ret; ++ int wstatus; + +- DEBUG(SSSDBG_TRACE_FUNC, "Running %s\n", command); ++ DEBUG(SSSDBG_TRACE_FUNC, "Running '%s'\n", argv[0]); + +- ret = system(command); ++ ret = fork(); + if (ret == -1) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to execute %s\n", command); + fprintf(stderr, _("Error while executing external command\n")); + return EFAULT; +- } else if (WEXITSTATUS(ret) != 0) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Command %s failed with [%d]\n", +- command, WEXITSTATUS(ret)); ++ } ++ ++ if (ret == 0) { ++ /* cast is safe - see ++ https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html ++ "The statement about argv[] and envp[] being constants ... " ++ */ ++ execvp(argv[0], discard_const_p(char * const, argv)); + fprintf(stderr, _("Error while executing external command\n")); +- return EIO; ++ _exit(1); ++ } else { ++ if (waitpid(ret, &wstatus, 0) == -1) { ++ fprintf(stderr, ++ _("Error while executing external command '%s'\n"), argv[0]); ++ return EFAULT; ++ } else if (WEXITSTATUS(wstatus) != 0) { ++ fprintf(stderr, ++ _("Command '%s' failed with [%d]\n"), argv[0], WEXITSTATUS(wstatus)); ++ return EIO; ++ } + } + + return EOK; +@@ -132,11 +147,14 @@ static errno_t sssctl_manage_service(enum sssctl_svc_action action) + #elif defined(HAVE_SERVICE) + switch (action) { + case SSSCTL_SVC_START: +- return sssctl_run_command(SERVICE_PATH" sssd start"); ++ return sssctl_run_command( ++ (const char *[]){SERVICE_PATH, "sssd", "start", NULL}); + case SSSCTL_SVC_STOP: +- return sssctl_run_command(SERVICE_PATH" sssd stop"); ++ return sssctl_run_command( ++ (const char *[]){SERVICE_PATH, "sssd", "stop", NULL}); + case SSSCTL_SVC_RESTART: +- return sssctl_run_command(SERVICE_PATH" sssd restart"); ++ return sssctl_run_command( ++ (const char *[]){SERVICE_PATH, "sssd", "restart", NULL}); + } + #endif + +diff --git a/src/tools/sssctl/sssctl.h b/src/tools/sssctl/sssctl.h +index 0115b24..599ef65 100644 +--- a/src/tools/sssctl/sssctl.h ++++ b/src/tools/sssctl/sssctl.h +@@ -47,7 +47,7 @@ enum sssctl_prompt_result + sssctl_prompt(const char *message, + enum sssctl_prompt_result defval); + +-errno_t sssctl_run_command(const char *command); ++errno_t sssctl_run_command(const char *const argv[]); /* argv[0] - command */ + bool sssctl_start_sssd(bool force); + bool sssctl_stop_sssd(bool force); + bool sssctl_restart_sssd(bool force); +diff --git a/src/tools/sssctl/sssctl_data.c b/src/tools/sssctl/sssctl_data.c +index cc46caf..8a04266 100644 +--- a/src/tools/sssctl/sssctl_data.c ++++ b/src/tools/sssctl/sssctl_data.c +@@ -105,15 +105,15 @@ static errno_t sssctl_backup(bool force) + } + } + +- ret = sssctl_run_command("sss_override user-export " +- SSS_BACKUP_USER_OVERRIDES); ++ ret = sssctl_run_command((const char *[]){"sss_override", "user-export", ++ SSS_BACKUP_USER_OVERRIDES, NULL}); + if (ret != EOK) { + fprintf(stderr, _("Unable to export user overrides\n")); + return ret; + } + +- ret = sssctl_run_command("sss_override group-export " +- SSS_BACKUP_GROUP_OVERRIDES); ++ ret = sssctl_run_command((const char *[]){"sss_override", "group-export", ++ SSS_BACKUP_GROUP_OVERRIDES, NULL}); + if (ret != EOK) { + fprintf(stderr, _("Unable to export group overrides\n")); + return ret; +@@ -158,8 +158,8 @@ static errno_t sssctl_restore(bool force_start, bool force_restart) + } + + if (sssctl_backup_file_exists(SSS_BACKUP_USER_OVERRIDES)) { +- ret = sssctl_run_command("sss_override user-import " +- SSS_BACKUP_USER_OVERRIDES); ++ ret = sssctl_run_command((const char *[]){"sss_override", "user-import", ++ SSS_BACKUP_USER_OVERRIDES, NULL}); + if (ret != EOK) { + fprintf(stderr, _("Unable to import user overrides\n")); + return ret; +@@ -167,8 +167,8 @@ static errno_t sssctl_restore(bool force_start, bool force_restart) + } + + if (sssctl_backup_file_exists(SSS_BACKUP_USER_OVERRIDES)) { +- ret = sssctl_run_command("sss_override group-import " +- SSS_BACKUP_GROUP_OVERRIDES); ++ ret = sssctl_run_command((const char *[]){"sss_override", "group-import", ++ SSS_BACKUP_GROUP_OVERRIDES, NULL}); + if (ret != EOK) { + fprintf(stderr, _("Unable to import group overrides\n")); + return ret; +@@ -296,40 +296,19 @@ errno_t sssctl_cache_expire(struct sss_cmdline *cmdline, + void *pvt) + { + errno_t ret; +- char *cmd_args = NULL; +- const char *cachecmd = SSS_CACHE; +- char *cmd = NULL; +- int i; +- +- if (cmdline->argc == 0) { +- ret = sssctl_run_command(cachecmd); +- goto done; +- } + +- cmd_args = talloc_strdup(tool_ctx, ""); +- if (cmd_args == NULL) { +- ret = ENOMEM; +- goto done; ++ const char **args = talloc_array_size(tool_ctx, ++ sizeof(char *), ++ cmdline->argc + 2); ++ if (!args) { ++ return ENOMEM; + } ++ memcpy(&args[1], cmdline->argv, sizeof(char *) * cmdline->argc); ++ args[0] = SSS_CACHE; ++ args[cmdline->argc + 1] = NULL; + +- for (i = 0; i < cmdline->argc; i++) { +- cmd_args = talloc_strdup_append(cmd_args, cmdline->argv[i]); +- if (i != cmdline->argc - 1) { +- cmd_args = talloc_strdup_append(cmd_args, " "); +- } +- } +- +- cmd = talloc_asprintf(tool_ctx, "%s %s", cachecmd, cmd_args); +- if (cmd == NULL) { +- ret = ENOMEM; +- goto done; +- } +- +- ret = sssctl_run_command(cmd); +- +-done: +- talloc_free(cmd_args); +- talloc_free(cmd); ++ ret = sssctl_run_command(args); + ++ talloc_free(args); + return ret; + } +diff --git a/src/tools/sssctl/sssctl_logs.c b/src/tools/sssctl/sssctl_logs.c +index aca988c..c85cc7a 100644 +--- a/src/tools/sssctl/sssctl_logs.c ++++ b/src/tools/sssctl/sssctl_logs.c +@@ -32,6 +32,7 @@ + #include + #include + #include ++#include + + #include "util/util.h" + #include "tools/common/sss_process.h" +@@ -231,6 +232,7 @@ errno_t sssctl_logs_remove(struct sss_cmdline *cmdline, + { + struct sssctl_logs_opts opts = {0}; + errno_t ret; ++ glob_t globbuf; + + /* Parse command line. */ + struct poptOption options[] = { +@@ -254,8 +256,19 @@ errno_t sssctl_logs_remove(struct sss_cmdline *cmdline, + + sss_signal(SIGHUP); + } else { ++ globbuf.gl_offs = 4; ++ ret = glob(LOG_PATH"/*.log", GLOB_ERR|GLOB_DOOFFS, NULL, &globbuf); ++ if (ret != 0) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to expand log files list\n"); ++ return ret; ++ } ++ globbuf.gl_pathv[0] = discard_const_p(char, "truncate"); ++ globbuf.gl_pathv[2] = discard_const_p(char, "--size"); ++ globbuf.gl_pathv[3] = discard_const_p(char, "0"); ++ + printf(_("Truncating log files...\n")); +- ret = sssctl_run_command("truncate --size 0 " LOG_FILES); ++ ret = sssctl_run_command((const char * const*)globbuf.gl_pathv); ++ globfree(&globbuf); + if (ret != EOK) { + fprintf(stderr, _("Unable to truncate log files\n")); + return ret; +@@ -270,8 +283,8 @@ errno_t sssctl_logs_fetch(struct sss_cmdline *cmdline, + void *pvt) + { + const char *file; +- const char *cmd; + errno_t ret; ++ glob_t globbuf; + + /* Parse command line. */ + ret = sss_tool_popt_ex(cmdline, NULL, SSS_TOOL_OPT_OPTIONAL, NULL, NULL, +@@ -281,13 +294,19 @@ errno_t sssctl_logs_fetch(struct sss_cmdline *cmdline, + return ret; + } + +- cmd = talloc_asprintf(tool_ctx, "tar -czf %s %s", file, LOG_FILES); +- if (cmd == NULL) { +- fprintf(stderr, _("Out of memory!")); ++ globbuf.gl_offs = 3; ++ ret = glob(LOG_PATH"/*.log", GLOB_ERR|GLOB_DOOFFS, NULL, &globbuf); ++ if (ret != 0) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to expand log files list\n"); ++ return ret; + } ++ globbuf.gl_pathv[0] = discard_const_p(char, "tar"); ++ globbuf.gl_pathv[1] = discard_const_p(char, "-czf"); ++ globbuf.gl_pathv[2] = discard_const_p(char, file); + + printf(_("Archiving log files into %s...\n"), file); +- ret = sssctl_run_command(cmd); ++ ret = sssctl_run_command((const char * const*)globbuf.gl_pathv); ++ globfree(&globbuf); + if (ret != EOK) { + fprintf(stderr, _("Unable to archive log files\n")); + return ret; +-- +2.26.3 + diff --git a/SOURCES/0073-cldap.patch b/SOURCES/0073-cldap.patch new file mode 100644 index 0000000..18ba08f --- /dev/null +++ b/SOURCES/0073-cldap.patch @@ -0,0 +1,2158 @@ +From db644a3a24c123a964129d41934365d8eb2174c7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Thu, 30 Jul 2020 12:59:01 +0200 +Subject: [PATCH 1/7] ldap: add support for cldap and udp connections + +Reviewed-by: Sumit Bose +(cherry picked from commit 414593cca65ed09fe4659e2786370a4553664cd0) + +Reviewed-by: Sumit Bose +--- + src/util/sss_ldap.c | 28 ++++++++++++++++++++----- + src/util/sss_sockets.c | 47 ++++++++++++++++++++++++++++-------------- + src/util/sss_sockets.h | 1 + + 3 files changed, 56 insertions(+), 20 deletions(-) + +diff --git a/src/util/sss_ldap.c b/src/util/sss_ldap.c +index 652b08ea7..71fa21f4a 100644 +--- a/src/util/sss_ldap.c ++++ b/src/util/sss_ldap.c +@@ -116,6 +116,7 @@ struct sss_ldap_init_state { + LDAP *ldap; + int sd; + const char *uri; ++ bool use_udp; + }; + + static int sss_ldap_init_state_destructor(void *data) +@@ -159,11 +160,13 @@ struct tevent_req *sss_ldap_init_send(TALLOC_CTX *mem_ctx, + state->ldap = NULL; + state->sd = -1; + state->uri = uri; ++ state->use_udp = strncmp(uri, "cldap", 5) == 0 ? true : false; + + #ifdef HAVE_LDAP_INIT_FD + struct tevent_req *subreq; + +- subreq = sssd_async_socket_init_send(state, ev, addr, addr_len, timeout); ++ subreq = sssd_async_socket_init_send(state, ev, state->use_udp, addr, ++ addr_len, timeout); + if (subreq == NULL) { + ret = ENOMEM; + DEBUG(SSSDBG_CRIT_FAILURE, "sssd_async_socket_init_send failed.\n"); +@@ -246,14 +249,29 @@ static void sss_ldap_init_sys_connect_done(struct tevent_req *subreq) + goto fail; + } + +- ret = unset_fcntl_flags(state->sd, O_NONBLOCK); +- if (ret != EOK) { +- goto fail; ++ /* openldap < 2.5 does not correctly handle O_NONBLOCK during starttls for ++ * ldaps, so we need to remove the flag here. This is fine since I/O events ++ * are handled via tevent so we only read when there is data available. ++ * ++ * We need to keep O_NONBLOCK due to a bug in openldap to correctly perform ++ * a parallel CLDAP pings without timeout. See: ++ * https://bugs.openldap.org/show_bug.cgi?id=9328 ++ * ++ * @todo remove this when the bug is fixed and we can put a hard requirement ++ * on newer openldap. ++ */ ++ if (!state->use_udp) { ++ ret = unset_fcntl_flags(state->sd, O_NONBLOCK); ++ if (ret != EOK) { ++ goto fail; ++ } + } + + /* Initialize LDAP handler */ + +- lret = ldap_init_fd(state->sd, LDAP_PROTO_TCP, state->uri, &state->ldap); ++ lret = ldap_init_fd(state->sd, ++ state->use_udp ? LDAP_PROTO_UDP : LDAP_PROTO_TCP, ++ state->uri, &state->ldap); + if (lret != LDAP_SUCCESS) { + DEBUG(SSSDBG_CRIT_FAILURE, + "ldap_init_fd failed: %s. [%d][%s]\n", +diff --git a/src/util/sss_sockets.c b/src/util/sss_sockets.c +index 6f2b71bc8..733360f3b 100644 +--- a/src/util/sss_sockets.c ++++ b/src/util/sss_sockets.c +@@ -80,6 +80,18 @@ static errno_t set_fd_common_opts(int fd, int timeout) + int ret; + struct timeval tv; + unsigned int milli; ++ int type; ++ socklen_t optlen = sizeof(int); ++ ++ /* Get protocol type. */ ++ ret = getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &optlen); ++ if (ret != 0) { ++ ret = errno; ++ DEBUG(SSSDBG_FUNC_DATA, "Unable to get socket type [%d]: %s.\n", ++ ret, strerror(ret)); ++ /* Assume TCP. */ ++ type = SOCK_STREAM; ++ } + + /* SO_KEEPALIVE and TCP_NODELAY are set by OpenLDAP client libraries but + * failures are ignored.*/ +@@ -91,12 +103,14 @@ static errno_t set_fd_common_opts(int fd, int timeout) + strerror(ret)); + } + +- ret = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &dummy, sizeof(dummy)); +- if (ret != 0) { +- ret = errno; +- DEBUG(SSSDBG_FUNC_DATA, +- "setsockopt TCP_NODELAY failed.[%d][%s].\n", ret, +- strerror(ret)); ++ if (type == SOCK_STREAM) { ++ ret = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &dummy, sizeof(dummy)); ++ if (ret != 0) { ++ ret = errno; ++ DEBUG(SSSDBG_FUNC_DATA, ++ "setsockopt TCP_NODELAY failed.[%d][%s].\n", ret, ++ strerror(ret)); ++ } + } + + if (timeout > 0) { +@@ -119,14 +133,16 @@ static errno_t set_fd_common_opts(int fd, int timeout) + strerror(ret)); + } + +- milli = timeout * 1000; /* timeout in milliseconds */ +- ret = setsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &milli, +- sizeof(milli)); +- if (ret != 0) { +- ret = errno; +- DEBUG(SSSDBG_FUNC_DATA, +- "setsockopt TCP_USER_TIMEOUT failed.[%d][%s].\n", ret, +- strerror(ret)); ++ if (type == SOCK_STREAM) { ++ milli = timeout * 1000; /* timeout in milliseconds */ ++ ret = setsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &milli, ++ sizeof(milli)); ++ if (ret != 0) { ++ ret = errno; ++ DEBUG(SSSDBG_FUNC_DATA, ++ "setsockopt TCP_USER_TIMEOUT failed.[%d][%s].\n", ret, ++ strerror(ret)); ++ } + } + } + +@@ -271,6 +287,7 @@ static void sssd_async_socket_init_done(struct tevent_req *subreq); + + struct tevent_req *sssd_async_socket_init_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, ++ bool use_udp, + struct sockaddr_storage *addr, + socklen_t addr_len, int timeout) + { +@@ -289,7 +306,7 @@ struct tevent_req *sssd_async_socket_init_send(TALLOC_CTX *mem_ctx, + talloc_set_destructor((TALLOC_CTX *)state, + sssd_async_socket_state_destructor); + +- state->sd = socket(addr->ss_family, SOCK_STREAM, 0); ++ state->sd = socket(addr->ss_family, use_udp ? SOCK_DGRAM : SOCK_STREAM, 0); + if (state->sd == -1) { + ret = errno; + DEBUG(SSSDBG_CRIT_FAILURE, +diff --git a/src/util/sss_sockets.h b/src/util/sss_sockets.h +index ccb05cb84..2758e6ed1 100644 +--- a/src/util/sss_sockets.h ++++ b/src/util/sss_sockets.h +@@ -32,6 +32,7 @@ int sssd_async_connect_recv(struct tevent_req *req); + + struct tevent_req *sssd_async_socket_init_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, ++ bool use_udp, + struct sockaddr_storage *addr, + socklen_t addr_len, int timeout); + int sssd_async_socket_init_recv(struct tevent_req *req, int *sd); +-- +2.26.3 + + +From 3efae1df18f4bfe7782025a14bcfbb5965496b32 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Thu, 30 Jul 2020 13:30:50 +0200 +Subject: [PATCH 2/7] ad: use cldap for site and forrest discover (perform + CLDAP ping) + +All Windows clients uses CLDAP (UDP) for LDAP ping. Even though AD +also supports LDAP ping over TCP IPA does not therefore it is crusial +for us to perform the ping over CLDAP protocol. + +Resolves: +https://github.com/SSSD/sssd/issues/5215 + +Reviewed-by: Sumit Bose +(cherry picked from commit 8265674a055e5cdb57acebad72d935356408540a) + +Reviewed-by: Sumit Bose +--- + src/providers/ad/ad_init.c | 6 +----- + src/providers/ad/ad_srv.c | 9 +++------ + src/providers/ad/ad_srv.h | 3 +-- + src/providers/ad/ad_subdomains.c | 2 +- + src/providers/ipa/ipa_subdomains_server.c | 2 +- + 5 files changed, 7 insertions(+), 15 deletions(-) + +diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c +index fb24a28e1..5abd28b7c 100644 +--- a/src/providers/ad/ad_init.c ++++ b/src/providers/ad/ad_init.c +@@ -187,14 +187,11 @@ static errno_t ad_init_srv_plugin(struct be_ctx *be_ctx, + const char *ad_site_override; + bool sites_enabled; + errno_t ret; +- bool ad_use_ldaps; + + hostname = dp_opt_get_string(ad_options->basic, AD_HOSTNAME); + ad_domain = dp_opt_get_string(ad_options->basic, AD_DOMAIN); + ad_site_override = dp_opt_get_string(ad_options->basic, AD_SITE); + sites_enabled = dp_opt_get_bool(ad_options->basic, AD_ENABLE_DNS_SITES); +- ad_use_ldaps = dp_opt_get_bool(ad_options->basic, AD_USE_LDAPS); +- + + if (!sites_enabled) { + ret = be_fo_set_dns_srv_lookup_plugin(be_ctx, hostname); +@@ -210,8 +207,7 @@ static errno_t ad_init_srv_plugin(struct be_ctx *be_ctx, + srv_ctx = ad_srv_plugin_ctx_init(be_ctx, be_ctx, be_ctx->be_res, + default_host_dbs, ad_options->id, + hostname, ad_domain, +- ad_site_override, +- ad_use_ldaps); ++ ad_site_override); + if (srv_ctx == NULL) { + DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory?\n"); + return ENOMEM; +diff --git a/src/providers/ad/ad_srv.c b/src/providers/ad/ad_srv.c +index ca15d3715..55e8f63f7 100644 +--- a/src/providers/ad/ad_srv.c ++++ b/src/providers/ad/ad_srv.c +@@ -335,9 +335,9 @@ static errno_t ad_get_client_site_next_dc(struct tevent_req *req) + state->be_res->resolv, + state->be_res->family_order, + state->host_db, +- state->ad_use_ldaps ? "ldaps" : "ldap", ++ "cldap", + state->dc.host, +- state->ad_use_ldaps ? 636 : state->dc.port, ++ state->dc.port, + false); + if (subreq == NULL) { + ret = ENOMEM; +@@ -497,7 +497,6 @@ struct ad_srv_plugin_ctx { + const char *ad_domain; + const char *ad_site_override; + const char *current_site; +- bool ad_use_ldaps; + }; + + struct ad_srv_plugin_ctx * +@@ -508,8 +507,7 @@ ad_srv_plugin_ctx_init(TALLOC_CTX *mem_ctx, + struct sdap_options *opts, + const char *hostname, + const char *ad_domain, +- const char *ad_site_override, +- bool ad_use_ldaps) ++ const char *ad_site_override) + { + struct ad_srv_plugin_ctx *ctx = NULL; + errno_t ret; +@@ -523,7 +521,6 @@ ad_srv_plugin_ctx_init(TALLOC_CTX *mem_ctx, + ctx->be_res = be_res; + ctx->host_dbs = host_dbs; + ctx->opts = opts; +- ctx->ad_use_ldaps = ad_use_ldaps; + + ctx->hostname = talloc_strdup(ctx, hostname); + if (ctx->hostname == NULL) { +diff --git a/src/providers/ad/ad_srv.h b/src/providers/ad/ad_srv.h +index 8e410ec26..e553d594d 100644 +--- a/src/providers/ad/ad_srv.h ++++ b/src/providers/ad/ad_srv.h +@@ -31,8 +31,7 @@ ad_srv_plugin_ctx_init(TALLOC_CTX *mem_ctx, + struct sdap_options *opts, + const char *hostname, + const char *ad_domain, +- const char *ad_site_override, +- bool ad_use_ldaps); ++ const char *ad_site_override); + + struct tevent_req *ad_srv_plugin_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, +diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c +index 16aecbc64..9b32196b7 100644 +--- a/src/providers/ad/ad_subdomains.c ++++ b/src/providers/ad/ad_subdomains.c +@@ -411,7 +411,7 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx, + ad_id_ctx->ad_options->id, + hostname, + ad_domain, +- ad_site_override, ad_use_ldaps); ++ ad_site_override); + if (srv_ctx == NULL) { + DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory?\n"); + return ENOMEM; +diff --git a/src/providers/ipa/ipa_subdomains_server.c b/src/providers/ipa/ipa_subdomains_server.c +index e2037b59d..f0d8a6a20 100644 +--- a/src/providers/ipa/ipa_subdomains_server.c ++++ b/src/providers/ipa/ipa_subdomains_server.c +@@ -344,7 +344,7 @@ ipa_ad_ctx_new(struct be_ctx *be_ctx, + ad_id_ctx->ad_options->id, + id_ctx->server_mode->hostname, + ad_domain, +- ad_site_override, false); ++ ad_site_override); + if (srv_ctx == NULL) { + DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory?\n"); + return ENOMEM; +-- +2.26.3 + + +From 7e856adefeaa377a50b40d397684e48ba82aa055 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Tue, 11 Aug 2020 13:27:42 +0200 +Subject: [PATCH 3/7] ad: connect to the first available server for cldap ping + +Resolves: +https://github.com/SSSD/sssd/issues/3743 + +Reviewed-by: Sumit Bose +(cherry picked from commit 1889ca60a9c642f0cca60b20a5b94de7a66924f6) + +Reviewed-by: Sumit Bose +--- + Makefile.am | 5 +- + src/providers/ad/ad_cldap_ping.c | 586 +++++++++++++++++++++++++++++++ + src/providers/ad/ad_srv.c | 434 +---------------------- + src/providers/ad/ad_srv.h | 14 + + 4 files changed, 613 insertions(+), 426 deletions(-) + create mode 100644 src/providers/ad/ad_cldap_ping.c + +diff --git a/Makefile.am b/Makefile.am +index b9ca9a7c6..17e20f1cb 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -4202,7 +4202,9 @@ libsss_ipa_la_SOURCES = \ + src/providers/ad/ad_pac.c \ + src/providers/ad/ad_pac_common.c \ + src/providers/ad/ad_srv.c \ +- src/providers/ad/ad_domain_info.c ++ src/providers/ad/ad_domain_info.c \ ++ src/providers/ad/ad_cldap_ping.c \ ++ $(NULL) + libsss_ipa_la_CFLAGS = \ + $(AM_CFLAGS) \ + $(OPENLDAP_CFLAGS) \ +@@ -4269,6 +4271,7 @@ libsss_ad_la_SOURCES = \ + src/providers/ad/ad_subdomains.c \ + src/providers/ad/ad_domain_info.c \ + src/providers/ad/ad_refresh.c \ ++ src/providers/ad/ad_cldap_ping.c \ + $(NULL) + + +diff --git a/src/providers/ad/ad_cldap_ping.c b/src/providers/ad/ad_cldap_ping.c +new file mode 100644 +index 000000000..5fc1a4d20 +--- /dev/null ++++ b/src/providers/ad/ad_cldap_ping.c +@@ -0,0 +1,586 @@ ++/* ++ Authors: ++ Pavel Březina ++ ++ Copyright (C) 2020 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 . ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "util/util.h" ++#include "util/sss_ldap.h" ++#include "resolv/async_resolv.h" ++#include "providers/backend.h" ++#include "providers/ad/ad_srv.h" ++#include "providers/ad/ad_common.h" ++#include "providers/fail_over.h" ++#include "providers/fail_over_srv.h" ++#include "providers/ldap/sdap.h" ++#include "providers/ldap/sdap_async.h" ++#include "db/sysdb.h" ++ ++struct ad_cldap_ping_dc_state { ++ struct tevent_context *ev; ++ struct sdap_options *opts; ++ struct fo_server_info *dc; ++ struct sdap_handle *sh; ++ const char *ad_domain; ++ ++ char *site; ++ char *forest; ++}; ++ ++static void ad_cldap_ping_dc_connect_done(struct tevent_req *subreq); ++static void ad_cldap_ping_dc_done(struct tevent_req *subreq); ++ ++static struct tevent_req *ad_cldap_ping_dc_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct sdap_options *opts, ++ struct be_resolv_ctx *be_res, ++ enum host_database *host_db, ++ struct fo_server_info *dc, ++ const char *ad_domain) ++{ ++ struct ad_cldap_ping_dc_state *state; ++ struct tevent_req *subreq; ++ struct tevent_req *req; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, ++ struct ad_cldap_ping_dc_state); ++ if (req == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); ++ return NULL; ++ } ++ ++ state->ev = ev; ++ state->opts = opts; ++ state->dc = dc; ++ state->ad_domain = ad_domain; ++ ++ subreq = sdap_connect_host_send(state, ev, opts, be_res->resolv, ++ be_res->family_order, host_db, "cldap", ++ dc->host, dc->port, false); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ tevent_req_set_callback(subreq, ad_cldap_ping_dc_connect_done, req); ++ ++ return req; ++ ++done: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ ++ return req; ++} ++ ++static void ad_cldap_ping_dc_connect_done(struct tevent_req *subreq) ++{ ++ static const char *attrs[] = {AD_AT_NETLOGON, NULL}; ++ struct ad_cldap_ping_dc_state *state; ++ struct tevent_req *req; ++ char *ntver; ++ char *filter; ++ int timeout; ++ errno_t ret; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, struct ad_cldap_ping_dc_state); ++ ++ ret = sdap_connect_host_recv(state, subreq, &state->sh); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ ntver = sss_ldap_encode_ndr_uint32(state, NETLOGON_NT_VERSION_5EX | ++ NETLOGON_NT_VERSION_WITH_CLOSEST_SITE); ++ if (ntver == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ filter = talloc_asprintf(state, "(&(%s=%s)(%s=%s))", AD_AT_DNS_DOMAIN, ++ state->ad_domain, AD_AT_NT_VERSION, ntver); ++ if (filter == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ timeout = dp_opt_get_int(state->opts->basic, SDAP_SEARCH_TIMEOUT); ++ subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh, "", ++ LDAP_SCOPE_BASE, filter, attrs, NULL, ++ 0, timeout, false); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ tevent_req_set_callback(subreq, ad_cldap_ping_dc_done, req); ++ ++ ret = EOK; ++ ++done: ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ } ++} ++ ++static void ad_cldap_ping_dc_done(struct tevent_req *subreq) ++{ ++ struct ad_cldap_ping_dc_state *state; ++ struct tevent_req *req; ++ struct sysdb_attrs **reply; ++ size_t reply_count; ++ errno_t ret; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, struct ad_cldap_ping_dc_state); ++ ++ ret = sdap_get_generic_recv(subreq, state, &reply_count, &reply); ++ ++ talloc_zfree(subreq); ++ talloc_zfree(state->sh); ++ ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "%s:%d: unable to get netlogon information\n", ++ state->dc->host, state->dc->port); ++ goto done; ++ } ++ ++ if (reply_count == 0) { ++ DEBUG(SSSDBG_OP_FAILURE, "%s:%d: no netlogon information available\n", ++ state->dc->host, state->dc->port); ++ ret = ENOENT; ++ goto done; ++ } ++ ++ ret = netlogon_get_domain_info(state, reply[0], true, NULL, &state->site, ++ &state->forest); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "%s:%d: unable to retrieve site name [%d]: %s\n", ++ state->dc->host, state->dc->port, ret, sss_strerror(ret)); ++ ret = ENOENT; ++ goto done; ++ } ++ ++ DEBUG(SSSDBG_TRACE_FUNC, "%s:%d: found site (%s) and forest (%s)\n", ++ state->dc->host, state->dc->port, state->site, state->forest); ++ ++ ret = EOK; ++ ++done: ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ tevent_req_done(req); ++} ++ ++static errno_t ad_cldap_ping_dc_recv(TALLOC_CTX *mem_ctx, ++ struct tevent_req *req, ++ const char **_site, ++ const char **_forest) ++{ ++ struct ad_cldap_ping_dc_state *state = NULL; ++ state = tevent_req_data(req, struct ad_cldap_ping_dc_state); ++ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ ++ *_site = talloc_steal(mem_ctx, state->site); ++ *_forest = talloc_steal(mem_ctx, state->forest); ++ ++ return EOK; ++} ++ ++struct ad_cldap_ping_parallel_state { ++ struct tevent_context *ev; ++ struct sdap_options *opts; ++ struct be_resolv_ctx *be_res; ++ enum host_database *host_db; ++ const char *ad_domain; ++ struct fo_server_info *dc_list; ++ size_t dc_count; ++ ++ TALLOC_CTX *reqs_ctx; ++ struct tevent_timer *te; ++ int active_requests; ++ size_t next_dc; ++ int batch; ++ ++ const char *site; ++ const char *forest; ++}; ++ ++static void ad_cldap_ping_parallel_batch(struct tevent_context *ev, ++ struct tevent_timer *te, ++ struct timeval tv, ++ void *data); ++static void ad_cldap_ping_parallel_done(struct tevent_req *subreq); ++ ++static struct tevent_req * ++ad_cldap_ping_parallel_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct sdap_options *opts, ++ struct be_resolv_ctx *be_res, ++ enum host_database *host_db, ++ struct fo_server_info *dc_list, ++ size_t dc_count, ++ const char *ad_domain) ++{ ++ struct ad_cldap_ping_parallel_state *state; ++ struct tevent_req *req; ++ struct timeval tv = {0, 0}; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, ++ struct ad_cldap_ping_parallel_state); ++ if (req == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); ++ return NULL; ++ } ++ ++ state->ev = ev; ++ state->opts = opts; ++ state->be_res = be_res; ++ state->host_db = host_db; ++ state->ad_domain = ad_domain; ++ state->dc_list = dc_list; ++ state->dc_count = dc_count; ++ ++ state->reqs_ctx = talloc_new(state); ++ if (state->reqs_ctx == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ state->next_dc = 0; ++ state->batch = 1; ++ ad_cldap_ping_parallel_batch(ev, NULL, tv, req); ++ ++ return req; ++ ++done: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ ++ return req; ++} ++ ++static void ad_cldap_ping_parallel_batch(struct tevent_context *ev, ++ struct tevent_timer *te, ++ struct timeval tv, ++ void *data) ++{ ++ struct ad_cldap_ping_parallel_state *state; ++ struct tevent_req *req; ++ struct tevent_req *subreq; ++ uint32_t delay; ++ size_t limit; ++ size_t i; ++ ++ req = talloc_get_type(data, struct tevent_req); ++ state = tevent_req_data(req, struct ad_cldap_ping_parallel_state); ++ ++ state->te = NULL; ++ ++ /* Issue three batches in total to avoid pinging too many domain controllers ++ * if not necessary. The first batch (5 pings) is issued immediately and we ++ * will wait 400ms for it to finish. If we don't get a reply in time we ++ * issue next batch (5 pings) and wait 200ms. If we still have no reply, ++ * we contact remaining domain controllers. ++ * ++ * This follows algorithm described at section 5.4.5.3 of MS-DISO: ++ * https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/WinArchive/%5bMS-DISO%5d.pdf ++ */ ++ switch (state->batch) { ++ case 1: ++ case 2: ++ limit = MIN(state->dc_count, 5 + state->next_dc); ++ delay = 400000 / state->batch; ++ break; ++ default: ++ limit = state->dc_count; ++ delay = 0; ++ } ++ ++ for (i = state->next_dc; i < limit; i++) { ++ DEBUG(SSSDBG_TRACE_ALL, "Batch %d: %s:%d\n", state->batch, ++ state->dc_list[i].host, state->dc_list[i].port); ++ } ++ ++ for (; state->next_dc < limit; state->next_dc++) { ++ subreq = ad_cldap_ping_dc_send(state->reqs_ctx, ev, state->opts, ++ state->be_res, state->host_db, ++ &state->dc_list[state->next_dc], ++ state->ad_domain); ++ if (subreq == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "Unable to create new ping request\n"); ++ goto fail; ++ } ++ ++ state->active_requests++; ++ tevent_req_set_callback(subreq, ad_cldap_ping_parallel_done, req); ++ } ++ ++ state->batch++; ++ if (delay > 0) { ++ tv = tevent_timeval_current_ofs(0, delay); ++ state->te = tevent_add_timer(ev, state->reqs_ctx, tv, ++ ad_cldap_ping_parallel_batch, req); ++ if (state->te == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "Unable to schedule next batch!\n"); ++ goto fail; ++ } ++ } ++ ++ return; ++ ++fail: ++ if (state->active_requests == 0) { ++ tevent_req_error(req, ENOMEM); ++ if (state->batch == 1) { ++ tevent_req_post(req, ev); ++ } ++ } ++} ++ ++static void ad_cldap_ping_parallel_done(struct tevent_req *subreq) ++{ ++ struct ad_cldap_ping_parallel_state *state; ++ struct timeval tv = {0, 0}; ++ struct tevent_req *req; ++ errno_t ret; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, struct ad_cldap_ping_parallel_state); ++ ++ ret = ad_cldap_ping_dc_recv(state, subreq, &state->site, &state->forest); ++ talloc_zfree(subreq); ++ state->active_requests--; ++ ++ if (ret == EOK) { ++ /* We have the answer. Terminate other attempts and finish. */ ++ talloc_zfree(state->reqs_ctx); ++ tevent_req_done(req); ++ } else if (state->active_requests == 0) { ++ /* There are still servers to try, don't wait for the timer. */ ++ if (state->next_dc < state->dc_count) { ++ talloc_zfree(state->te); ++ ad_cldap_ping_parallel_batch(state->ev, NULL, tv, req); ++ return; ++ } ++ /* There is no available server. */ ++ tevent_req_error(req, ENOENT); ++ } ++ ++ /* Wait for another request to finish. */ ++} ++ ++static errno_t ad_cldap_ping_parallel_recv(TALLOC_CTX *mem_ctx, ++ struct tevent_req *req, ++ const char **_site, ++ const char **_forest) ++{ ++ struct ad_cldap_ping_parallel_state *state = NULL; ++ state = tevent_req_data(req, struct ad_cldap_ping_parallel_state); ++ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ ++ *_site = talloc_steal(mem_ctx, state->site); ++ *_forest = talloc_steal(mem_ctx, state->forest); ++ ++ return EOK; ++} ++ ++struct ad_cldap_ping_state { ++ struct tevent_context *ev; ++ struct sdap_options *opts; ++ struct be_resolv_ctx *be_res; ++ enum host_database *host_db; ++ const char *ad_domain; ++ ++ struct fo_server_info *dc_list; ++ size_t dc_count; ++ const char *site; ++ const char *forest; ++}; ++ ++static void ad_cldap_ping_discovery_done(struct tevent_req *subreq); ++static void ad_cldap_ping_done(struct tevent_req *subreq); ++ ++struct tevent_req *ad_cldap_ping_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct sdap_options *opts, ++ struct be_resolv_ctx *be_res, ++ enum host_database *host_db, ++ const char *ad_domain, ++ const char *discovery_domain, ++ const char *current_site) ++{ ++ struct ad_cldap_ping_state *state; ++ struct tevent_req *subreq; ++ struct tevent_req *req; ++ const char **domains; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, struct ad_cldap_ping_state); ++ if (req == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); ++ return NULL; ++ } ++ ++ state->ev = ev; ++ state->opts = opts; ++ state->be_res = be_res; ++ state->host_db = host_db; ++ state->ad_domain = ad_domain; ++ ++ domains = talloc_zero_array(state, const char *, 3); ++ if (domains == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ if (current_site == NULL) { ++ domains[0] = discovery_domain; ++ domains[1] = NULL; ++ } else { ++ domains[0] = ad_site_dns_discovery_domain(state, current_site, ++ discovery_domain); ++ domains[1] = discovery_domain; ++ ++ if (domains[0] == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory!"); ++ ret = ENOMEM; ++ goto done; ++ } ++ } ++ ++ /* Even though we use CLDAP (UDP) to perform the ping we need to discover ++ * domain controllers in TCP namespace as they are not automatically ++ * available under UDP. */ ++ subreq = fo_discover_srv_send(state, ev, be_res->resolv, "ldap", ++ FO_PROTO_TCP, domains); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ tevent_req_set_callback(subreq, ad_cldap_ping_discovery_done, req); ++ ++ return req; ++ ++done: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ ++ return req; ++} ++ ++static void ad_cldap_ping_discovery_done(struct tevent_req *subreq) ++{ ++ struct ad_cldap_ping_state *state; ++ struct tevent_req *req; ++ char *domain; ++ errno_t ret; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, struct ad_cldap_ping_state); ++ ++ ret = fo_discover_srv_recv(state, subreq, &domain, NULL, &state->dc_list, ++ &state->dc_count); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ DEBUG(SSSDBG_TRACE_FUNC, "Found %zu domain controllers in domain %s\n", ++ state->dc_count, domain); ++ ++ subreq = ad_cldap_ping_parallel_send(state, state->ev, state->opts, ++ state->be_res, state->host_db, ++ state->dc_list, state->dc_count, ++ state->ad_domain); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ tevent_req_set_callback(subreq, ad_cldap_ping_done, req); ++ ++done: ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++} ++ ++static void ad_cldap_ping_done(struct tevent_req *subreq) ++{ ++ struct ad_cldap_ping_state *state; ++ struct tevent_req *req; ++ errno_t ret; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, struct ad_cldap_ping_state); ++ ++ ret = ad_cldap_ping_parallel_recv(state, subreq, &state->site, ++ &state->forest); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Unable to get site and forest information [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ DEBUG(SSSDBG_TRACE_FUNC, "Found site: %s\n", state->site); ++ DEBUG(SSSDBG_TRACE_FUNC, "Found forest: %s\n", state->forest); ++ ++done: ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ tevent_req_done(req); ++} ++ ++errno_t ad_cldap_ping_recv(TALLOC_CTX *mem_ctx, ++ struct tevent_req *req, ++ const char **_site, ++ const char **_forest) ++{ ++ struct ad_cldap_ping_state *state = NULL; ++ state = tevent_req_data(req, struct ad_cldap_ping_state); ++ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ ++ *_site = talloc_steal(mem_ctx, state->site); ++ *_forest = talloc_steal(mem_ctx, state->forest); ++ ++ return EOK; ++} +\ No newline at end of file +diff --git a/src/providers/ad/ad_srv.c b/src/providers/ad/ad_srv.c +index 55e8f63f7..d12f0971c 100644 +--- a/src/providers/ad/ad_srv.c ++++ b/src/providers/ad/ad_srv.c +@@ -116,378 +116,6 @@ static errno_t ad_sort_servers_by_dns(TALLOC_CTX *mem_ctx, + return EOK; + } + +-struct ad_get_dc_servers_state { +- struct fo_server_info *servers; +- size_t num_servers; +-}; +- +-static void ad_get_dc_servers_done(struct tevent_req *subreq); +- +-static struct tevent_req *ad_get_dc_servers_send(TALLOC_CTX *mem_ctx, +- struct tevent_context *ev, +- struct resolv_ctx *resolv_ctx, +- const char *discovery_domain, +- const char *site) +-{ +- struct ad_get_dc_servers_state *state = NULL; +- struct tevent_req *req = NULL; +- struct tevent_req *subreq = NULL; +- const char **domains = NULL; +- errno_t ret; +- +- req = tevent_req_create(mem_ctx, &state, +- struct ad_get_dc_servers_state); +- if (req == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); +- return NULL; +- } +- +- domains = talloc_zero_array(state, const char *, 3); +- if (domains == NULL) { +- ret = ENOMEM; +- goto immediately; +- } +- +- if (site == NULL) { +- DEBUG(SSSDBG_TRACE_FUNC, "Looking up domain controllers in domain " +- "%s\n", discovery_domain); +- +- domains[0] = talloc_strdup(domains, discovery_domain); +- if (domains[0] == NULL) { +- ret = ENOMEM; +- goto immediately; +- } +- } else { +- DEBUG(SSSDBG_TRACE_FUNC, "Looking up domain controllers in domain " +- "%s and site %s\n", discovery_domain, site); +- +- domains[0] = ad_site_dns_discovery_domain(domains, +- site, discovery_domain); +- if (domains[0] == NULL) { +- ret = ENOMEM; +- goto immediately; +- } +- +- domains[1] = talloc_strdup(domains, discovery_domain); +- if (domains[1] == NULL) { +- ret = ENOMEM; +- goto immediately; +- } +- } +- +- subreq = fo_discover_srv_send(state, ev, resolv_ctx, +- "ldap", FO_PROTO_TCP, domains); +- if (subreq == NULL) { +- ret = ENOMEM; +- goto immediately; +- } +- +- tevent_req_set_callback(subreq, ad_get_dc_servers_done, req); +- +- return req; +- +-immediately: +- tevent_req_error(req, ret); +- tevent_req_post(req, ev); +- +- return req; +-} +- +-static void ad_get_dc_servers_done(struct tevent_req *subreq) +-{ +- struct ad_get_dc_servers_state *state = NULL; +- struct tevent_req *req = NULL; +- char *domain = NULL; +- errno_t ret; +- +- req = tevent_req_callback_data(subreq, struct tevent_req); +- state = tevent_req_data(req, struct ad_get_dc_servers_state); +- +- ret = fo_discover_srv_recv(state, subreq, &domain, NULL, +- &state->servers, &state->num_servers); +- talloc_zfree(subreq); +- if (ret != EOK) { +- goto done; +- } +- +- DEBUG(SSSDBG_TRACE_FUNC, "Found %zu domain controllers in domain %s\n", +- state->num_servers, domain); +- +-done: +- if (ret != EOK) { +- tevent_req_error(req, ret); +- return; +- } +- +- tevent_req_done(req); +-} +- +-static int ad_get_dc_servers_recv(TALLOC_CTX *mem_ctx, +- struct tevent_req *req, +- struct fo_server_info **_dcs, +- size_t *_num_dcs) +-{ +- struct ad_get_dc_servers_state *state = NULL; +- state = tevent_req_data(req, struct ad_get_dc_servers_state); +- +- TEVENT_REQ_RETURN_ON_ERROR(req); +- +- *_dcs = talloc_steal(mem_ctx, state->servers); +- *_num_dcs = state->num_servers; +- +- return EOK; +-} +- +-struct ad_get_client_site_state { +- struct tevent_context *ev; +- struct be_resolv_ctx *be_res; +- enum host_database *host_db; +- struct sdap_options *opts; +- const char *ad_domain; +- bool ad_use_ldaps; +- struct fo_server_info *dcs; +- size_t num_dcs; +- size_t dc_index; +- struct fo_server_info dc; +- +- struct sdap_handle *sh; +- char *site; +- char *forest; +-}; +- +-static errno_t ad_get_client_site_next_dc(struct tevent_req *req); +-static void ad_get_client_site_connect_done(struct tevent_req *subreq); +-static void ad_get_client_site_done(struct tevent_req *subreq); +- +-struct tevent_req *ad_get_client_site_send(TALLOC_CTX *mem_ctx, +- struct tevent_context *ev, +- struct be_resolv_ctx *be_res, +- enum host_database *host_db, +- struct sdap_options *opts, +- const char *ad_domain, +- bool ad_use_ldaps, +- struct fo_server_info *dcs, +- size_t num_dcs) +-{ +- struct ad_get_client_site_state *state = NULL; +- struct tevent_req *req = NULL; +- errno_t ret; +- +- req = tevent_req_create(mem_ctx, &state, +- struct ad_get_client_site_state); +- if (req == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); +- return NULL; +- } +- +- if (be_res == NULL || host_db == NULL || opts == NULL) { +- ret = EINVAL; +- goto immediately; +- } +- +- state->ev = ev; +- state->be_res = be_res; +- state->host_db = host_db; +- state->opts = opts; +- state->ad_domain = ad_domain; +- state->ad_use_ldaps = ad_use_ldaps; +- state->dcs = dcs; +- state->num_dcs = num_dcs; +- +- state->dc_index = 0; +- ret = ad_get_client_site_next_dc(req); +- if (ret == EOK) { +- ret = ENOENT; +- goto immediately; +- } else if (ret != EAGAIN) { +- goto immediately; +- } +- +- return req; +- +-immediately: +- if (ret == EOK) { +- tevent_req_done(req); +- } else { +- tevent_req_error(req, ret); +- } +- tevent_req_post(req, ev); +- +- return req; +-} +- +-static errno_t ad_get_client_site_next_dc(struct tevent_req *req) +-{ +- struct ad_get_client_site_state *state = NULL; +- struct tevent_req *subreq = NULL; +- errno_t ret; +- +- state = tevent_req_data(req, struct ad_get_client_site_state); +- +- if (state->dc_index >= state->num_dcs) { +- ret = EOK; +- goto done; +- } +- +- state->dc = state->dcs[state->dc_index]; +- +- subreq = sdap_connect_host_send(state, state->ev, state->opts, +- state->be_res->resolv, +- state->be_res->family_order, +- state->host_db, +- "cldap", +- state->dc.host, +- state->dc.port, +- false); +- if (subreq == NULL) { +- ret = ENOMEM; +- goto done; +- } +- +- tevent_req_set_callback(subreq, ad_get_client_site_connect_done, req); +- +- state->dc_index++; +- ret = EAGAIN; +- +-done: +- return ret; +-} +- +-static void ad_get_client_site_connect_done(struct tevent_req *subreq) +-{ +- struct ad_get_client_site_state *state = NULL; +- struct tevent_req *req = NULL; +- static const char *attrs[] = {AD_AT_NETLOGON, NULL}; +- char *filter = NULL; +- char *ntver = NULL; +- errno_t ret; +- +- req = tevent_req_callback_data(subreq, struct tevent_req); +- state = tevent_req_data(req, struct ad_get_client_site_state); +- +- ret = sdap_connect_host_recv(state, subreq, &state->sh); +- talloc_zfree(subreq); +- if (ret != EOK) { +- DEBUG(SSSDBG_MINOR_FAILURE, "Unable to connect to domain controller " +- "[%s:%d]\n", state->dc.host, state->dc.port); +- +- ret = ad_get_client_site_next_dc(req); +- if (ret == EOK) { +- ret = ENOENT; +- } +- +- goto done; +- } +- +- ntver = sss_ldap_encode_ndr_uint32(state, NETLOGON_NT_VERSION_5EX | +- NETLOGON_NT_VERSION_WITH_CLOSEST_SITE); +- if (ntver == NULL) { +- ret = ENOMEM; +- goto done; +- } +- +- filter = talloc_asprintf(state, "(&(%s=%s)(%s=%s))", +- AD_AT_DNS_DOMAIN, state->ad_domain, +- AD_AT_NT_VERSION, ntver); +- if (filter == NULL) { +- ret = ENOMEM; +- goto done; +- } +- +- subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh, +- "", LDAP_SCOPE_BASE, filter, +- attrs, NULL, 0, +- dp_opt_get_int(state->opts->basic, +- SDAP_SEARCH_TIMEOUT), +- false); +- if (subreq == NULL) { +- ret = ENOMEM; +- goto done; +- } +- +- tevent_req_set_callback(subreq, ad_get_client_site_done, req); +- +- ret = EAGAIN; +- +-done: +- if (ret == EOK) { +- tevent_req_done(req); +- } else if (ret != EAGAIN) { +- tevent_req_error(req, ret); +- } +- +- return; +-} +- +-static void ad_get_client_site_done(struct tevent_req *subreq) +-{ +- struct ad_get_client_site_state *state = NULL; +- struct tevent_req *req = NULL; +- struct sysdb_attrs **reply = NULL; +- size_t reply_count; +- errno_t ret; +- +- req = tevent_req_callback_data(subreq, struct tevent_req); +- state = tevent_req_data(req, struct ad_get_client_site_state); +- +- ret = sdap_get_generic_recv(subreq, state, &reply_count, &reply); +- talloc_zfree(subreq); +- +- /* we're done with this LDAP, close connection */ +- talloc_zfree(state->sh); +- if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "Unable to get netlogon information\n"); +- +- ret = ad_get_client_site_next_dc(req); +- if (ret == EOK) { +- ret = ENOENT; +- } +- goto done; +- } +- +- if (reply_count == 0) { +- DEBUG(SSSDBG_OP_FAILURE, "No netlogon information retrieved\n"); +- ret = ENOENT; +- goto done; +- } +- +- ret = netlogon_get_domain_info(state, reply[0], true, NULL, &state->site, +- &state->forest); +- if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "Unable to retrieve site name [%d]: %s\n", +- ret, strerror(ret)); +- ret = ENOENT; +- goto done; +- } +- +- DEBUG(SSSDBG_TRACE_FUNC, "Found site: %s\n", state->site); +- DEBUG(SSSDBG_TRACE_FUNC, "Found forest: %s\n", state->forest); +- +-done: +- if (ret != EOK) { +- tevent_req_error(req, ret); +- return; +- } +- +- tevent_req_done(req); +-} +- +-int ad_get_client_site_recv(TALLOC_CTX *mem_ctx, +- struct tevent_req *req, +- const char **_site, +- const char **_forest) +-{ +- struct ad_get_client_site_state *state = NULL; +- state = tevent_req_data(req, struct ad_get_client_site_state); +- +- TEVENT_REQ_RETURN_ON_ERROR(req); +- +- *_site = talloc_steal(mem_ctx, state->site); +- *_forest = talloc_steal(mem_ctx, state->forest); +- +- return EOK; +-} +- + struct ad_srv_plugin_ctx { + struct be_ctx *be_ctx; + struct be_resolv_ctx *be_res; +@@ -610,8 +238,7 @@ struct ad_srv_plugin_state { + size_t num_backup_servers; + }; + +-static void ad_srv_plugin_dcs_done(struct tevent_req *subreq); +-static void ad_srv_plugin_site_done(struct tevent_req *subreq); ++static void ad_srv_plugin_ping_done(struct tevent_req *subreq); + static void ad_srv_plugin_servers_done(struct tevent_req *subreq); + + /* 1. Do a DNS lookup to find any DC in domain +@@ -677,15 +304,16 @@ struct tevent_req *ad_srv_plugin_send(TALLOC_CTX *mem_ctx, + + DEBUG(SSSDBG_TRACE_FUNC, "About to find domain controllers\n"); + +- subreq = ad_get_dc_servers_send(state, ev, ctx->be_res->resolv, +- state->discovery_domain, +- state->ctx->current_site); ++ subreq = ad_cldap_ping_send(state, ev, ctx->opts, ctx->be_res, ++ ctx->host_dbs, ctx->ad_domain, ++ state->discovery_domain, ++ state->ctx->current_site); + if (subreq == NULL) { + ret = ENOMEM; + goto immediately; + } + +- tevent_req_set_callback(subreq, ad_srv_plugin_dcs_done, req); ++ tevent_req_set_callback(subreq, ad_srv_plugin_ping_done, req); + + return req; + +@@ -696,52 +324,7 @@ immediately: + return req; + } + +-static void ad_srv_plugin_dcs_done(struct tevent_req *subreq) +-{ +- struct ad_srv_plugin_state *state = NULL; +- struct tevent_req *req = NULL; +- struct fo_server_info *dcs = NULL; +- size_t num_dcs = 0; +- errno_t ret; +- +- req = tevent_req_callback_data(subreq, struct tevent_req); +- state = tevent_req_data(req, struct ad_srv_plugin_state); +- +- ret = ad_get_dc_servers_recv(state, subreq, &dcs, &num_dcs); +- talloc_zfree(subreq); +- if (ret != EOK) { +- goto done; +- } +- +- DEBUG(SSSDBG_TRACE_FUNC, "About to locate suitable site\n"); +- +- subreq = ad_get_client_site_send(state, state->ev, +- state->ctx->be_res, +- state->ctx->host_dbs, +- state->ctx->opts, +- state->discovery_domain, +- state->ctx->ad_use_ldaps, +- dcs, num_dcs); +- if (subreq == NULL) { +- ret = ENOMEM; +- goto done; +- } +- +- tevent_req_set_callback(subreq, ad_srv_plugin_site_done, req); +- +- ret = EAGAIN; +- +-done: +- if (ret == EOK) { +- tevent_req_done(req); +- } else if (ret != EAGAIN) { +- tevent_req_error(req, ret); +- } +- +- return; +-} +- +-static void ad_srv_plugin_site_done(struct tevent_req *subreq) ++static void ad_srv_plugin_ping_done(struct tevent_req *subreq) + { + struct ad_srv_plugin_state *state = NULL; + struct tevent_req *req = NULL; +@@ -752,8 +335,9 @@ static void ad_srv_plugin_site_done(struct tevent_req *subreq) + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct ad_srv_plugin_state); + +- ret = ad_get_client_site_recv(state, subreq, &state->site, &state->forest); ++ ret = ad_cldap_ping_recv(state, subreq, &state->site, &state->forest); + talloc_zfree(subreq); ++ + /* Ignore AD site found by dns discovery if specific site is set in + * configuration file. */ + if (state->ctx->ad_site_override != NULL) { +diff --git a/src/providers/ad/ad_srv.h b/src/providers/ad/ad_srv.h +index e553d594d..c03ac873f 100644 +--- a/src/providers/ad/ad_srv.h ++++ b/src/providers/ad/ad_srv.h +@@ -53,4 +53,18 @@ char *ad_site_dns_discovery_domain(TALLOC_CTX *mem_ctx, + const char *site, + const char *domain); + ++struct tevent_req *ad_cldap_ping_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct sdap_options *opts, ++ struct be_resolv_ctx *be_res, ++ enum host_database *host_db, ++ const char *ad_domain, ++ const char *discovery_domain, ++ const char *current_site); ++ ++errno_t ad_cldap_ping_recv(TALLOC_CTX *mem_ctx, ++ struct tevent_req *req, ++ const char **_site, ++ const char **_forest); ++ + #endif /* __AD_SRV_H__ */ +-- +2.26.3 + + +From 27f394bb477aadb879c55df8e956fd37fa810109 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Tue, 25 Aug 2020 12:11:19 +0200 +Subject: [PATCH 4/7] ad: if all in-site dc are unreachable try off-site + controllers + +Previous implementation would not fallback to the off-site domain +controllers. This would cause problems if the site actually changed. + +Reviewed-by: Sumit Bose +(cherry picked from commit fcfd834c9d80d7690f938582335d81231a5f6e60) + +Reviewed-by: Sumit Bose +--- + src/providers/ad/ad_cldap_ping.c | 227 ++++++++++++++++++++++++------- + 1 file changed, 181 insertions(+), 46 deletions(-) + +diff --git a/src/providers/ad/ad_cldap_ping.c b/src/providers/ad/ad_cldap_ping.c +index 5fc1a4d20..7ecdcdbef 100644 +--- a/src/providers/ad/ad_cldap_ping.c ++++ b/src/providers/ad/ad_cldap_ping.c +@@ -415,7 +415,7 @@ static errno_t ad_cldap_ping_parallel_recv(TALLOC_CTX *mem_ctx, + return EOK; + } + +-struct ad_cldap_ping_state { ++struct ad_cldap_ping_domain_state { + struct tevent_context *ev; + struct sdap_options *opts; + struct be_resolv_ctx *be_res; +@@ -428,25 +428,25 @@ struct ad_cldap_ping_state { + const char *forest; + }; + +-static void ad_cldap_ping_discovery_done(struct tevent_req *subreq); +-static void ad_cldap_ping_done(struct tevent_req *subreq); ++static void ad_cldap_ping_domain_discovery_done(struct tevent_req *subreq); ++static void ad_cldap_ping_domain_done(struct tevent_req *subreq); + +-struct tevent_req *ad_cldap_ping_send(TALLOC_CTX *mem_ctx, +- struct tevent_context *ev, +- struct sdap_options *opts, +- struct be_resolv_ctx *be_res, +- enum host_database *host_db, +- const char *ad_domain, +- const char *discovery_domain, +- const char *current_site) ++static struct tevent_req * ++ad_cldap_ping_domain_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct sdap_options *opts, ++ struct be_resolv_ctx *be_res, ++ enum host_database *host_db, ++ const char *ad_domain, ++ const char *discovery_domain) + { +- struct ad_cldap_ping_state *state; ++ struct ad_cldap_ping_domain_state *state; + struct tevent_req *subreq; + struct tevent_req *req; + const char **domains; + errno_t ret; + +- req = tevent_req_create(mem_ctx, &state, struct ad_cldap_ping_state); ++ req = tevent_req_create(mem_ctx, &state, struct ad_cldap_ping_domain_state); + if (req == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); + return NULL; +@@ -458,25 +458,18 @@ struct tevent_req *ad_cldap_ping_send(TALLOC_CTX *mem_ctx, + state->host_db = host_db; + state->ad_domain = ad_domain; + +- domains = talloc_zero_array(state, const char *, 3); ++ domains = talloc_zero_array(state, const char *, 2); + if (domains == NULL) { + ret = ENOMEM; + goto done; + } + +- if (current_site == NULL) { +- domains[0] = discovery_domain; +- domains[1] = NULL; +- } else { +- domains[0] = ad_site_dns_discovery_domain(state, current_site, +- discovery_domain); +- domains[1] = discovery_domain; +- +- if (domains[0] == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory!"); +- ret = ENOMEM; +- goto done; +- } ++ domains[0] = discovery_domain; ++ domains[1] = NULL; ++ if (domains[0] == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory!"); ++ ret = ENOMEM; ++ goto done; + } + + /* Even though we use CLDAP (UDP) to perform the ping we need to discover +@@ -489,7 +482,7 @@ struct tevent_req *ad_cldap_ping_send(TALLOC_CTX *mem_ctx, + goto done; + } + +- tevent_req_set_callback(subreq, ad_cldap_ping_discovery_done, req); ++ tevent_req_set_callback(subreq, ad_cldap_ping_domain_discovery_done, req); + + return req; + +@@ -500,15 +493,15 @@ done: + return req; + } + +-static void ad_cldap_ping_discovery_done(struct tevent_req *subreq) ++static void ad_cldap_ping_domain_discovery_done(struct tevent_req *subreq) + { +- struct ad_cldap_ping_state *state; ++ struct ad_cldap_ping_domain_state *state; + struct tevent_req *req; + char *domain; + errno_t ret; + + req = tevent_req_callback_data(subreq, struct tevent_req); +- state = tevent_req_data(req, struct ad_cldap_ping_state); ++ state = tevent_req_data(req, struct ad_cldap_ping_domain_state); + + ret = fo_discover_srv_recv(state, subreq, &domain, NULL, &state->dc_list, + &state->dc_count); +@@ -529,7 +522,7 @@ static void ad_cldap_ping_discovery_done(struct tevent_req *subreq) + goto done; + } + +- tevent_req_set_callback(subreq, ad_cldap_ping_done, req); ++ tevent_req_set_callback(subreq, ad_cldap_ping_domain_done, req); + + done: + if (ret != EOK) { +@@ -538,41 +531,183 @@ done: + } + } + +-static void ad_cldap_ping_done(struct tevent_req *subreq) ++static void ad_cldap_ping_domain_done(struct tevent_req *subreq) + { +- struct ad_cldap_ping_state *state; ++ struct ad_cldap_ping_domain_state *state; + struct tevent_req *req; + errno_t ret; + + req = tevent_req_callback_data(subreq, struct tevent_req); +- state = tevent_req_data(req, struct ad_cldap_ping_state); ++ state = tevent_req_data(req, struct ad_cldap_ping_domain_state); + + ret = ad_cldap_ping_parallel_recv(state, subreq, &state->site, + &state->forest); + talloc_zfree(subreq); + if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, +- "Unable to get site and forest information [%d]: %s\n", +- ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ tevent_req_done(req); ++} ++ ++static errno_t ad_cldap_ping_domain_recv(TALLOC_CTX *mem_ctx, ++ struct tevent_req *req, ++ const char **_site, ++ const char **_forest) ++{ ++ struct ad_cldap_ping_domain_state *state = NULL; ++ state = tevent_req_data(req, struct ad_cldap_ping_domain_state); ++ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ ++ *_site = talloc_steal(mem_ctx, state->site); ++ *_forest = talloc_steal(mem_ctx, state->forest); ++ ++ return EOK; ++} ++ ++struct ad_cldap_ping_state { ++ struct tevent_context *ev; ++ struct sdap_options *opts; ++ struct be_resolv_ctx *be_res; ++ enum host_database *host_db; ++ const char *ad_domain; ++ const char *discovery_domain; ++ bool all_tried; ++ ++ const char *site; ++ const char *forest; ++}; ++ ++static errno_t ad_cldap_ping_step(struct tevent_req *req, ++ const char *domain); ++static void ad_cldap_ping_done(struct tevent_req *subreq); ++ ++struct tevent_req *ad_cldap_ping_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct sdap_options *opts, ++ struct be_resolv_ctx *be_res, ++ enum host_database *host_db, ++ const char *ad_domain, ++ const char *discovery_domain, ++ const char *current_site) ++{ ++ struct ad_cldap_ping_state *state; ++ struct tevent_req *req; ++ const char *domain; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, struct ad_cldap_ping_state); ++ if (req == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); ++ return NULL; ++ } ++ ++ state->ev = ev; ++ state->opts = opts; ++ state->be_res = be_res; ++ state->host_db = host_db; ++ state->ad_domain = ad_domain; ++ state->discovery_domain = discovery_domain; ++ ++ /* If possible, lookup the information in the current site first. */ ++ if (current_site != NULL) { ++ state->all_tried = false; ++ domain = ad_site_dns_discovery_domain(state, current_site, ++ discovery_domain); ++ if (domain == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory!"); ++ ret = ENOMEM; ++ goto done; ++ } ++ } else { ++ state->all_tried = true; ++ domain = discovery_domain; ++ } ++ ++ ret = ad_cldap_ping_step(req, domain); ++ if (ret != EOK) { + goto done; + } + +- DEBUG(SSSDBG_TRACE_FUNC, "Found site: %s\n", state->site); +- DEBUG(SSSDBG_TRACE_FUNC, "Found forest: %s\n", state->forest); ++ return req; + + done: +- if (ret != EOK) { +- tevent_req_error(req, ret); ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ ++ return req; ++} ++ ++static errno_t ad_cldap_ping_step(struct tevent_req *req, ++ const char *domain) ++{ ++ struct ad_cldap_ping_state *state; ++ struct tevent_req *subreq; ++ struct timeval tv; ++ int timeout; ++ ++ state = tevent_req_data(req, struct ad_cldap_ping_state); ++ ++ subreq = ad_cldap_ping_domain_send(state, state->ev, state->opts, ++ state->be_res, state->host_db, ++ state->ad_domain, domain); ++ if (subreq == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory!"); ++ return ENOMEM; ++ } ++ ++ tevent_req_set_callback(subreq, ad_cldap_ping_done, req); ++ ++ timeout = dp_opt_get_int(state->be_res->opts, ++ DP_RES_OPT_RESOLVER_OP_TIMEOUT); ++ if (timeout > 0) { ++ tv = tevent_timeval_current_ofs(timeout, 0); ++ tevent_req_set_endtime(subreq, state->ev, tv); ++ } ++ ++ return EOK; ++} ++ ++static void ad_cldap_ping_done(struct tevent_req *subreq) ++{ ++ struct ad_cldap_ping_state *state; ++ struct tevent_req *req; ++ errno_t ret; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, struct ad_cldap_ping_state); ++ ++ ret = ad_cldap_ping_domain_recv(state, subreq, &state->site, ++ &state->forest); ++ talloc_zfree(subreq); ++ if (ret == EOK) { ++ DEBUG(SSSDBG_TRACE_FUNC, "Found site: %s\n", state->site); ++ DEBUG(SSSDBG_TRACE_FUNC, "Found forest: %s\n", state->forest); ++ tevent_req_done(req); + return; + } + +- tevent_req_done(req); ++ if (!state->all_tried) { ++ state->all_tried = true; ++ ret = ad_cldap_ping_step(req, state->discovery_domain); ++ if (ret == EOK) { ++ return; ++ } ++ } ++ ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Unable to get site and forest information [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ ++ tevent_req_error(req, ret); + } + + errno_t ad_cldap_ping_recv(TALLOC_CTX *mem_ctx, +- struct tevent_req *req, +- const char **_site, +- const char **_forest) ++ struct tevent_req *req, ++ const char **_site, ++ const char **_forest) + { + struct ad_cldap_ping_state *state = NULL; + state = tevent_req_data(req, struct ad_cldap_ping_state); +-- +2.26.3 + + +From 8249161d967a37847f42b62e0e6a384d063884af Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Tue, 25 Aug 2020 13:43:32 +0200 +Subject: [PATCH 5/7] ad: renew site information only when SSSD was previously + offline + +Site and forest information is stable not dynamic. To avoid spamming +network with cldap pings all the time we will renew netlogon information +only when SSSD starts and when we are recovering from an offline state +to detect possible change (e.g. user moves to another location with laptop). + +Reviewed-by: Sumit Bose +(cherry picked from commit 9fdf5cfacd1a425691d44db53897096887bb3e6f) + +Reviewed-by: Sumit Bose +--- + src/providers/ad/ad_cldap_ping.c | 45 ++++++++++++++++---------- + src/providers/ad/ad_srv.c | 54 +++++++++++++++++++++----------- + src/providers/ad/ad_srv.h | 22 ++++++++----- + 3 files changed, 80 insertions(+), 41 deletions(-) + +diff --git a/src/providers/ad/ad_cldap_ping.c b/src/providers/ad/ad_cldap_ping.c +index 7ecdcdbef..dc25f6670 100644 +--- a/src/providers/ad/ad_cldap_ping.c ++++ b/src/providers/ad/ad_cldap_ping.c +@@ -586,12 +586,8 @@ static void ad_cldap_ping_done(struct tevent_req *subreq); + + struct tevent_req *ad_cldap_ping_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, +- struct sdap_options *opts, +- struct be_resolv_ctx *be_res, +- enum host_database *host_db, +- const char *ad_domain, +- const char *discovery_domain, +- const char *current_site) ++ struct ad_srv_plugin_ctx *srv_ctx, ++ const char *discovery_domain) + { + struct ad_cldap_ping_state *state; + struct tevent_req *req; +@@ -604,17 +600,30 @@ struct tevent_req *ad_cldap_ping_send(TALLOC_CTX *mem_ctx, + return NULL; + } + ++ if (!srv_ctx->renew_site) { ++ state->site = srv_ctx->current_site; ++ state->forest = srv_ctx->current_forest; ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "CLDAP ping is not necessary, using site '%s' and forest '%s'\n", ++ state->site != NULL ? state->site : "unknown", ++ state->forest != NULL ? state->forest : "unknown"); ++ ret = EOK; ++ goto done; ++ } ++ ++ DEBUG(SSSDBG_TRACE_FUNC, "Sending CLDAP ping\n"); ++ + state->ev = ev; +- state->opts = opts; +- state->be_res = be_res; +- state->host_db = host_db; +- state->ad_domain = ad_domain; ++ state->opts = srv_ctx->opts; ++ state->be_res = srv_ctx->be_res; ++ state->host_db = srv_ctx->host_dbs; ++ state->ad_domain = srv_ctx->ad_domain; + state->discovery_domain = discovery_domain; + + /* If possible, lookup the information in the current site first. */ +- if (current_site != NULL) { ++ if (srv_ctx->current_site != NULL) { + state->all_tried = false; +- domain = ad_site_dns_discovery_domain(state, current_site, ++ domain = ad_site_dns_discovery_domain(state, srv_ctx->current_site, + discovery_domain); + if (domain == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory!"); +@@ -634,7 +643,11 @@ struct tevent_req *ad_cldap_ping_send(TALLOC_CTX *mem_ctx, + return req; + + done: +- tevent_req_error(req, ret); ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ } else { ++ tevent_req_done(req); ++ } + tevent_req_post(req, ev); + + return req; +@@ -705,9 +718,9 @@ static void ad_cldap_ping_done(struct tevent_req *subreq) + } + + errno_t ad_cldap_ping_recv(TALLOC_CTX *mem_ctx, +- struct tevent_req *req, +- const char **_site, +- const char **_forest) ++ struct tevent_req *req, ++ const char **_site, ++ const char **_forest) + { + struct ad_cldap_ping_state *state = NULL; + state = tevent_req_data(req, struct ad_cldap_ping_state); +diff --git a/src/providers/ad/ad_srv.c b/src/providers/ad/ad_srv.c +index d12f0971c..e58c19aac 100644 +--- a/src/providers/ad/ad_srv.c ++++ b/src/providers/ad/ad_srv.c +@@ -116,16 +116,13 @@ static errno_t ad_sort_servers_by_dns(TALLOC_CTX *mem_ctx, + return EOK; + } + +-struct ad_srv_plugin_ctx { +- struct be_ctx *be_ctx; +- struct be_resolv_ctx *be_res; +- enum host_database *host_dbs; +- struct sdap_options *opts; +- const char *hostname; +- const char *ad_domain; +- const char *ad_site_override; +- const char *current_site; +-}; ++static void ad_srv_mark_renew_site(void *pvt) ++{ ++ struct ad_srv_plugin_ctx *ctx; ++ ++ ctx = talloc_get_type(pvt, struct ad_srv_plugin_ctx); ++ ctx->renew_site = true; ++} + + struct ad_srv_plugin_ctx * + ad_srv_plugin_ctx_init(TALLOC_CTX *mem_ctx, +@@ -149,6 +146,7 @@ ad_srv_plugin_ctx_init(TALLOC_CTX *mem_ctx, + ctx->be_res = be_res; + ctx->host_dbs = host_dbs; + ctx->opts = opts; ++ ctx->renew_site = true; + + ctx->hostname = talloc_strdup(ctx, hostname); + if (ctx->hostname == NULL) { +@@ -181,6 +179,12 @@ ad_srv_plugin_ctx_init(TALLOC_CTX *mem_ctx, + } + } + ++ ret = be_add_offline_cb(ctx, be_ctx, ad_srv_mark_renew_site, ctx, NULL); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "be_add_offline_cb failed.\n"); ++ goto fail; ++ } ++ + return ctx; + + fail: +@@ -190,11 +194,26 @@ fail: + + static errno_t + ad_srv_plugin_ctx_switch_site(struct ad_srv_plugin_ctx *ctx, +- const char *new_site) ++ const char *new_site, ++ const char *new_forest) + { + const char *site; ++ const char *forest; + errno_t ret; + ++ /* Switch forest. */ ++ if (new_forest != NULL ++ && (ctx->current_forest == NULL ++ || strcmp(ctx->current_forest, new_forest) != 0)) { ++ forest = talloc_strdup(ctx, new_forest); ++ if (forest == NULL) { ++ return ENOMEM; ++ } ++ ++ talloc_zfree(ctx->current_forest); ++ ctx->current_forest = forest; ++ } ++ + if (new_site == NULL) { + return EOK; + } +@@ -302,12 +321,7 @@ struct tevent_req *ad_srv_plugin_send(TALLOC_CTX *mem_ctx, + goto immediately; + } + +- DEBUG(SSSDBG_TRACE_FUNC, "About to find domain controllers\n"); +- +- subreq = ad_cldap_ping_send(state, ev, ctx->opts, ctx->be_res, +- ctx->host_dbs, ctx->ad_domain, +- state->discovery_domain, +- state->ctx->current_site); ++ subreq = ad_cldap_ping_send(state, ev, state->ctx, state->discovery_domain); + if (subreq == NULL) { + ret = ENOMEM; + goto immediately; +@@ -363,13 +377,17 @@ static void ad_srv_plugin_ping_done(struct tevent_req *subreq) + /* Remember current site so it can be used during next lookup so + * we can contact directory controllers within a known reachable + * site first. */ +- ret = ad_srv_plugin_ctx_switch_site(state->ctx, state->site); ++ ret = ad_srv_plugin_ctx_switch_site(state->ctx, state->site, ++ state->forest); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to set site [%d]: %s\n", + ret, sss_strerror(ret)); + goto done; + } + ++ /* Do not renew the site again unless we go offline. */ ++ state->ctx->renew_site = false; ++ + if (strcmp(state->service, "gc") == 0) { + if (state->forest != NULL) { + if (state->site != NULL) { +diff --git a/src/providers/ad/ad_srv.h b/src/providers/ad/ad_srv.h +index c03ac873f..3c6a779ea 100644 +--- a/src/providers/ad/ad_srv.h ++++ b/src/providers/ad/ad_srv.h +@@ -21,7 +21,19 @@ + #ifndef __AD_SRV_H__ + #define __AD_SRV_H__ + +-struct ad_srv_plugin_ctx; ++struct ad_srv_plugin_ctx { ++ struct be_ctx *be_ctx; ++ struct be_resolv_ctx *be_res; ++ enum host_database *host_dbs; ++ struct sdap_options *opts; ++ const char *hostname; ++ const char *ad_domain; ++ const char *ad_site_override; ++ const char *current_site; ++ const char *current_forest; ++ ++ bool renew_site; ++}; + + struct ad_srv_plugin_ctx * + ad_srv_plugin_ctx_init(TALLOC_CTX *mem_ctx, +@@ -55,12 +67,8 @@ char *ad_site_dns_discovery_domain(TALLOC_CTX *mem_ctx, + + struct tevent_req *ad_cldap_ping_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, +- struct sdap_options *opts, +- struct be_resolv_ctx *be_res, +- enum host_database *host_db, +- const char *ad_domain, +- const char *discovery_domain, +- const char *current_site); ++ struct ad_srv_plugin_ctx *srv_ctx, ++ const char *discovery_domain); + + errno_t ad_cldap_ping_recv(TALLOC_CTX *mem_ctx, + struct tevent_req *req, +-- +2.26.3 + + +From 08fde220baab823f53fd359746c7e75eaeb0580f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Wed, 30 Sep 2020 13:45:43 +0200 +Subject: [PATCH 6/7] tevent: correctly handle req timeout error + +Reviewed-by: Sumit Bose +(cherry picked from commit f0d650799d4390f90890d17c56a4e395e931d8cb) + +Reviewed-by: Sumit Bose +--- + src/util/util.h | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +diff --git a/src/util/util.h b/src/util/util.h +index 94c2e6e3b..2cc7f98a3 100644 +--- a/src/util/util.h ++++ b/src/util/util.h +@@ -139,13 +139,17 @@ extern int dbus_activated; + \ + if (tevent_req_is_error(req, &TRROEstate, &TRROEuint64)) { \ + TRROEerr = (errno_t)TRROEuint64; \ +- if (TRROEstate == TEVENT_REQ_USER_ERROR) { \ +- if (TRROEerr == 0) { \ ++ switch (TRROEstate) { \ ++ case TEVENT_REQ_USER_ERROR: \ ++ if (TRROEerr == 0) { \ ++ return ERR_INTERNAL; \ ++ } \ ++ return TRROEerr; \ ++ case TEVENT_REQ_TIMED_OUT: \ ++ return ETIMEDOUT; \ ++ default: \ + return ERR_INTERNAL; \ +- } \ +- return TRROEerr; \ + } \ +- return ERR_INTERNAL; \ + } \ + } while (0) + +-- +2.26.3 + + +From a431a977852dde6af194f9306291d7fcc2624cb6 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 5 Oct 2020 10:58:49 +0200 +Subject: [PATCH 7/7] ad: fix handling of current site and forest in cldap ping +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The current site and forest are stored in a long living context and we +have to make sure that they are not moved to a different talloc parent +with a shorter lifetime. To achieve this the values are copied at the +start of a new cldap ping although it is expected that the values won't +change. + +Resolves: https://github.com/SSSD/sssd/issues/3743 + +Reviewed-by: Pavel Březina +(cherry picked from commit 37ba37a425453d8222584176ae5975a795422091) + +Reviewed-by: Sumit Bose +--- + src/providers/ad/ad_cldap_ping.c | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +diff --git a/src/providers/ad/ad_cldap_ping.c b/src/providers/ad/ad_cldap_ping.c +index dc25f6670..ab234f4d7 100644 +--- a/src/providers/ad/ad_cldap_ping.c ++++ b/src/providers/ad/ad_cldap_ping.c +@@ -601,8 +601,16 @@ struct tevent_req *ad_cldap_ping_send(TALLOC_CTX *mem_ctx, + } + + if (!srv_ctx->renew_site) { +- state->site = srv_ctx->current_site; +- state->forest = srv_ctx->current_forest; ++ state->site = talloc_strdup(state, srv_ctx->current_site); ++ state->forest = talloc_strdup(state, srv_ctx->current_forest); ++ if ((srv_ctx->current_site != NULL && state->site == NULL) ++ || (srv_ctx->current_forest != NULL && state->forest == NULL)) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Failed to copy current site or forest name.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ + DEBUG(SSSDBG_TRACE_FUNC, + "CLDAP ping is not necessary, using site '%s' and forest '%s'\n", + state->site != NULL ? state->site : "unknown", +@@ -731,4 +739,4 @@ errno_t ad_cldap_ping_recv(TALLOC_CTX *mem_ctx, + *_forest = talloc_steal(mem_ctx, state->forest); + + return EOK; +-} +\ No newline at end of file ++} +-- +2.26.3 + diff --git a/SPECS/sssd.spec b/SPECS/sssd.spec index a9f72f5..f78d819 100644 --- a/SPECS/sssd.spec +++ b/SPECS/sssd.spec @@ -50,7 +50,7 @@ Name: sssd Version: 1.16.5 -Release: 10%{?dist}.8 +Release: 10%{?dist}.10 Group: Applications/System Summary: System Security Services Daemon License: GPLv3+ @@ -127,6 +127,11 @@ Patch0065: 0065-sss_domain_info-add-not_found_counter.patch Patch0066: 0066-AD-read-trusted-domains-from-local-domain-as-well.patch Patch0067: 0067-negcache-use-right-domain-in-nss_protocol_fill_initg.patch Patch0068: 0068-ldap-retry-ldap_install_tls-when-watchdog-interrupti.patch +Patch0069: 0069-SYSDB-Add-search-index-originalADgidNumber.patch +Patch0070: 0070-AD-do-not-override-LDAP-data-during-GC-lookups.patch +Patch0071: 0071-simple-fix-memory-leak-while-reloading-lists.patch +Patch0072: 0072-TOOLS-replace-system-with-execvp.patch +Patch0073: 0073-cldap.patch #Those patches should not be removed in RHEL-7 Patch0999: 0999-NOUPSTREAM-Default-to-root-if-sssd-user-is-not-spec @@ -1302,6 +1307,15 @@ systemctl try-restart sssd >/dev/null 2>&1 || : } %changelog +* Wed Aug 11 2021 Alexey Tikhonov 1.16.5-10.10 +- Resolves: rhbz#1973796 - SSSD is NOT able to contact the Global Catalog when local site is down + +* Mon Aug 09 2021 Alexey Tikhonov 1.16.5-10.9 +- Resolves: rhbz#1988463 - Missing search index for `originalADgidNumber` [rhel-7.9.z] +- Resolves: rhbz#1968330 - id lookup is failing intermittently +- Resolves: rhbz#1964415 - Memory leak in the simple access provider +- Resolves: rhbz#1985457 - EMBARGOED CVE-2021-3621 sssd: shell command injection in sssctl [rhel-7.9.z] + * Mon Apr 26 2021 Alexey Tikhonov 1.16.5-10.8 - Resolves: rhbz#1910131 - sssd throwing error " Unable to parse name test' [1432158283]: The internal name format cannot be parsed" at debug_level 2 [rhel-7.9.z] - Resolves: rhbz#1922244 - First smart refresh query contains modifyTimestamp even if the modifyTimestamp is 0. [rhel-7.9.z]