summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/providers/ad/ad_srv.c72
1 files changed, 71 insertions, 1 deletions
diff --git a/src/providers/ad/ad_srv.c b/src/providers/ad/ad_srv.c
index dfb15b30..01660c48 100644
--- a/src/providers/ad/ad_srv.c
+++ b/src/providers/ad/ad_srv.c
@@ -26,6 +26,7 @@
#include "util/util.h"
#include "util/sss_ldap.h"
+#include "util/slinklist.h"
#include "resolv/async_resolv.h"
#include "providers/dp_backend.h"
#include "providers/fail_over.h"
@@ -548,6 +549,75 @@ 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_servers_done(struct tevent_req *subreq);
+static errno_t ad_sort_servers(struct ares_srv_reply **list, void *pvt)
+{
+ struct ad_srv_plugin_state *state = NULL;
+ struct ares_srv_reply *final_list = NULL;
+ struct ares_srv_reply *inside_list = NULL;
+ struct ares_srv_reply *outside_list = NULL;
+ struct ares_srv_reply *cur = NULL;
+ struct ares_srv_reply *next = NULL;
+ const char *domain = NULL;
+ errno_t ret;
+
+ if (list == NULL) {
+ ret = EINVAL;
+ goto done;
+ }
+
+ if (*list == NULL || (*list)->next == NULL) {
+ ret = EOK;
+ goto done;
+ }
+
+ state = talloc_get_type(pvt, struct ad_srv_plugin_state);
+ domain = state->discovery_domain;
+
+ /* first sort by rfc2782 */
+ ret = resolv_sort_srv_reply(list);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("resolv_sort_srv_reply() failed "
+ "[%d]: %s\n", ret, strerror(ret)));
+ goto done;
+ }
+
+ /* when several servers share priority, prefer the one that is located
+ * in the same domain as client (e.g. child domain instead of forest
+ * root) but obey their weight */
+
+ next = *list;
+ do {
+ cur = next;
+ next = cur->next;
+
+ /* split servers into two lists - inside and outside of the preferred
+ * domain */
+ if (is_host_in_domain(cur->host, domain)) {
+ SLIST_ADD_END(inside_list, cur, struct ares_srv_reply);
+ } else {
+ SLIST_ADD_END(outside_list, cur, struct ares_srv_reply);
+ }
+ cur->next = NULL;
+
+ if (next == NULL || cur->priority != next->priority) {
+ /* priority has changed or we have reached the end of the srv list,
+ * we will merge the list into final list and start over with
+ * next priority */
+ SLIST_CONCATENATE(final_list, inside_list, struct ares_srv_reply);
+ SLIST_CONCATENATE(final_list, outside_list, struct ares_srv_reply);
+ inside_list = NULL;
+ outside_list = NULL;
+ }
+ } while (next != NULL);
+
+ *list = final_list;
+
+ ret = EOK;
+
+done:
+ return ret;
+}
+
/* 1. Do a DNS lookup to find any DC in domain
* _ldap._tcp.domain.name
* 2. Send a CLDAP ping to the found DC to get the desirable site
@@ -720,7 +790,7 @@ static void ad_srv_plugin_site_done(struct tevent_req *subreq)
state->ctx->be_res->resolv,
state->service, state->protocol,
primary_domain, backup_domain,
- NULL, NULL);
+ ad_sort_servers, state);
if (subreq == NULL) {
ret = ENOMEM;
goto done;