summaryrefslogtreecommitdiffstats
path: root/src/providers/data_provider/dp_iface_failover.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 05:31:45 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 05:31:45 +0000
commit74aa0bc6779af38018a03fd2cf4419fe85917904 (patch)
tree9cb0681aac9a94a49c153d5823e7a55d1513d91f /src/providers/data_provider/dp_iface_failover.c
parentInitial commit. (diff)
downloadsssd-74aa0bc6779af38018a03fd2cf4419fe85917904.tar.xz
sssd-74aa0bc6779af38018a03fd2cf4419fe85917904.zip
Adding upstream version 2.9.4.upstream/2.9.4
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/providers/data_provider/dp_iface_failover.c')
-rw-r--r--src/providers/data_provider/dp_iface_failover.c328
1 files changed, 328 insertions, 0 deletions
diff --git a/src/providers/data_provider/dp_iface_failover.c b/src/providers/data_provider/dp_iface_failover.c
new file mode 100644
index 0000000..99d8ac0
--- /dev/null
+++ b/src/providers/data_provider/dp_iface_failover.c
@@ -0,0 +1,328 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2016 Red Hat
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <talloc.h>
+#include <tevent.h>
+
+#include "sbus/sbus_request.h"
+#include "providers/data_provider/dp_private.h"
+#include "providers/data_provider/dp_iface.h"
+#include "providers/backend.h"
+#include "util/util.h"
+
+static errno_t
+dp_failover_list_services_ldap(struct be_ctx *be_ctx,
+ const char **services,
+ int *_count)
+{
+ struct be_svc_data *svc;
+ int count;
+
+ count = 0;
+ DLIST_FOR_EACH(svc, be_ctx->be_fo->svcs) {
+ services[count] = talloc_strdup(services, svc->name);
+ if (services[count] == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup() failed\n");
+ return ENOMEM;
+ }
+ count++;
+ }
+
+ *_count = count;
+
+ return EOK;
+}
+
+static errno_t
+dp_failover_list_services_ad(struct be_ctx *be_ctx,
+ struct sss_domain_info *domain,
+ const char **services,
+ int *_count)
+{
+ char *fo_svc_name = NULL;
+ struct be_svc_data *svc;
+ errno_t ret;
+ int count;
+
+ fo_svc_name = talloc_asprintf(services, "sd_%s", domain->name);
+ if (fo_svc_name == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ count = 0;
+ DLIST_FOR_EACH(svc, be_ctx->be_fo->svcs) {
+ /* Drop each sd_gc_* since this service is not used with AD at all,
+ * we only connect to AD_GC for global catalog. */
+ if (strncasecmp(svc->name, "sd_gc_", strlen("sd_gc_")) == 0) {
+ continue;
+ }
+
+ /* Drop all subdomain services for different domain. */
+ if (strncasecmp(svc->name, "sd_", strlen("sd_")) == 0) {
+ if (!IS_SUBDOMAIN(domain)) {
+ continue;
+ }
+
+ if (strcasecmp(svc->name, fo_svc_name) != 0) {
+ continue;
+ }
+ }
+
+ if (IS_SUBDOMAIN(domain)) {
+ /* Drop AD since we connect to subdomain.com for LDAP. */
+ if (strcasecmp(svc->name, "AD") == 0) {
+ continue;
+ }
+ }
+
+ services[count] = talloc_strdup(services, svc->name);
+ if (services[count] == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup() failed\n");
+ ret = ENOMEM;
+ goto done;
+ }
+ count++;
+ }
+
+ *_count = count;
+
+ ret = EOK;
+
+done:
+ talloc_free(fo_svc_name);
+ return ret;
+}
+
+static errno_t
+dp_failover_list_services_ipa(struct be_ctx *be_ctx,
+ struct sss_domain_info *domain,
+ const char **services,
+ int *_count)
+{
+ struct be_svc_data *svc;
+ char *fo_svc_name = NULL;
+ char *fo_gc_name = NULL;
+ errno_t ret;
+ int count;
+
+ fo_svc_name = talloc_asprintf(services, "sd_%s", domain->name);
+ if (fo_svc_name == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ fo_gc_name = talloc_asprintf(services, "sd_gc_%s", domain->name);
+ if (fo_gc_name == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ count = 0;
+ DLIST_FOR_EACH(svc, be_ctx->be_fo->svcs) {
+ /* Drop all subdomain services for different domain. */
+ if (strncasecmp(svc->name, "sd_", strlen("sd_")) == 0) {
+ if (!IS_SUBDOMAIN(domain)) {
+ continue;
+ }
+
+ if (strcasecmp(svc->name, fo_svc_name) != 0
+ && strcasecmp(svc->name, fo_gc_name) != 0) {
+ continue;
+ }
+ }
+
+ services[count] = talloc_strdup(services, svc->name);
+ if (services[count] == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup() failed\n");
+ return ENOMEM;
+ }
+ count++;
+ }
+
+ *_count = count;
+
+ ret = EOK;
+
+done:
+ talloc_free(fo_svc_name);
+ talloc_free(fo_gc_name);
+
+ return ret;
+}
+
+enum dp_fo_svc_type {
+ DP_FO_SVC_LDAP = 0,
+ DP_FO_SVC_AD = 1,
+ DP_FO_SVC_IPA = 1 << 1,
+ DP_FO_SVC_MIXED = DP_FO_SVC_AD | DP_FO_SVC_IPA
+};
+
+errno_t
+dp_failover_list_services(TALLOC_CTX *mem_ctx,
+ struct sbus_request *sbus_req,
+ struct be_ctx *be_ctx,
+ const char *domname,
+ const char ***_services)
+{
+ enum dp_fo_svc_type svc_type = DP_FO_SVC_LDAP;
+ struct sss_domain_info *domain;
+ struct be_svc_data *svc;
+ const char **services;
+ int num_services;
+ errno_t ret;
+
+ if (SBUS_REQ_STRING_IS_EMPTY(domname)) {
+ domain = be_ctx->domain;
+ } else {
+ domain = find_domain_by_name(be_ctx->domain, domname, false);
+ if (domain == NULL) {
+ return ERR_DOMAIN_NOT_FOUND;
+ }
+ }
+
+ /**
+ * Returning list of failover services is currently rather difficult
+ * since there is only one failover context for the whole backend.
+ *
+ * The list of services for the given domain depends on whether it is
+ * a master domain or a subdomain and whether we are using IPA, AD or
+ * LDAP backend.
+ *
+ * For LDAP we just return everything we have.
+ * For AD master domain we return AD, AD_GC.
+ * For AD subdomain we return subdomain.com, AD_GC.
+ * For IPA in client mode we return IPA.
+ * For IPA in server mode we return IPA for master domain and
+ * subdomain.com, gc_subdomain.com for subdomain.
+ *
+ * We also return everything else for all cases if any other service
+ * such as kerberos is configured separately.
+ */
+
+ /* Allocate enough space. */
+ num_services = 0;
+ DLIST_FOR_EACH(svc, be_ctx->be_fo->svcs) {
+ num_services++;
+
+ if (strcasecmp(svc->name, "AD") == 0) {
+ svc_type |= DP_FO_SVC_AD;
+ } else if (strcasecmp(svc->name, "IPA") == 0) {
+ svc_type |= DP_FO_SVC_IPA;
+ }
+ }
+
+ services = talloc_zero_array(mem_ctx, const char *, num_services + 1);
+ if (services == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero_array() failed\n");
+ return ENOMEM;
+ }
+
+ /* Fill the list. */
+ switch (svc_type) {
+ case DP_FO_SVC_LDAP:
+ case DP_FO_SVC_MIXED:
+ ret = dp_failover_list_services_ldap(be_ctx, services, &num_services);
+ break;
+ case DP_FO_SVC_AD:
+ ret = dp_failover_list_services_ad(be_ctx, domain,
+ services, &num_services);
+ break;
+ case DP_FO_SVC_IPA:
+ ret = dp_failover_list_services_ipa(be_ctx, domain,
+ services, &num_services);
+ break;
+ default:
+ ret = ERR_INTERNAL;
+ break;
+ }
+
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create service list [%d]: %s\n",
+ ret, sss_strerror(ret));
+ talloc_free(services);
+ return ret;
+ }
+
+ *_services = services;
+
+ return EOK;
+}
+
+errno_t
+dp_failover_active_server(TALLOC_CTX *mem_ctx,
+ struct sbus_request *sbus_req,
+ struct be_ctx *be_ctx,
+ const char *service_name,
+ const char **_server)
+{
+ struct be_svc_data *svc;
+ bool found = false;
+
+ DLIST_FOR_EACH(svc, be_ctx->be_fo->svcs) {
+ if (strcmp(svc->name, service_name) == 0) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get server name\n");
+ return ENOENT;
+ }
+
+ *_server = svc->last_good_srv == NULL ? "" : svc->last_good_srv;
+
+ return EOK;
+}
+
+errno_t
+dp_failover_list_servers(TALLOC_CTX *mem_ctx,
+ struct sbus_request *sbus_req,
+ struct be_ctx *be_ctx,
+ const char *service_name,
+ const char ***_servers)
+{
+ struct be_svc_data *svc;
+ const char **servers;
+ bool found = false;
+ size_t count;
+
+ DLIST_FOR_EACH(svc, be_ctx->be_fo->svcs) {
+ if (strcmp(svc->name, service_name) == 0) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get server list\n");
+ return ENOENT;
+ }
+
+ servers = fo_svc_server_list(sbus_req, svc->fo_service, &count);
+ if (servers == NULL) {
+ return ENOMEM;
+ }
+
+ *_servers = servers;
+
+ return EOK;
+}