summaryrefslogtreecommitdiff
path: root/src/providers
diff options
context:
space:
mode:
Diffstat (limited to 'src/providers')
-rw-r--r--src/providers/ad/ad_srv.c89
1 files changed, 89 insertions, 0 deletions
diff --git a/src/providers/ad/ad_srv.c b/src/providers/ad/ad_srv.c
index 4ae91f07..af25c107 100644
--- a/src/providers/ad/ad_srv.c
+++ b/src/providers/ad/ad_srv.c
@@ -38,6 +38,77 @@
#define AD_AT_NT_VERSION "NtVer"
#define AD_AT_NETLOGON "netlogon"
+static errno_t ad_sort_servers_by_dns(TALLOC_CTX *mem_ctx,
+ const char *domain,
+ struct fo_server_info **_srv,
+ size_t num)
+{
+ struct fo_server_info *out = NULL;
+ struct fo_server_info *srv = NULL;
+ struct fo_server_info in_domain[num];
+ struct fo_server_info out_domain[num];
+ size_t srv_index = 0;
+ size_t in_index = 0;
+ size_t out_index = 0;
+ size_t i, j;
+
+ if (_srv == NULL) {
+ return EINVAL;
+ }
+
+ srv = *_srv;
+
+ if (num <= 1) {
+ return EOK;
+ }
+
+ out = talloc_zero_array(mem_ctx, struct fo_server_info, num);
+ if (out == NULL) {
+ return ENOMEM;
+ }
+
+ /* When several servers share priority, we will prefer the one that
+ * is located in the same domain as client (e.g. child domain instead
+ * of forest root) but obey their weight. We will use the fact that
+ * the servers are already sorted by priority. */
+
+ for (i = 0; i < num; i++) {
+ if (is_host_in_domain(srv[i].host, domain)) {
+ /* this is a preferred server, push it to the in domain list */
+ in_domain[in_index] = srv[i];
+ in_index++;
+ } else {
+ /* this is a normal server, push it to the out domain list */
+ out_domain[out_index] = srv[i];
+ out_index++;
+ }
+
+ if (i + 1 == num || srv[i].priority != srv[i + 1].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 */
+ for (j = 0; j < in_index; j++) {
+ out[srv_index] = in_domain[j];
+ talloc_steal(out, out[srv_index].host);
+ srv_index++;
+ }
+
+ for (j = 0; j < out_index; j++) {
+ out[srv_index] = out_domain[j];
+ talloc_steal(out, out[srv_index].host);
+ srv_index++;
+ }
+
+ in_index = 0;
+ out_index = 0;
+ }
+ }
+
+ talloc_free(*_srv);
+ *_srv = out;
+ return EOK;
+}
+
struct ad_get_dc_servers_state {
struct fo_server_info *servers;
size_t num_servers;
@@ -762,6 +833,24 @@ static void ad_srv_plugin_servers_done(struct tevent_req *subreq)
DEBUG(SSSDBG_TRACE_FUNC, ("Got %lu primary and %lu backup servers\n",
state->num_primary_servers, state->num_backup_servers));
+ ret = ad_sort_servers_by_dns(state, state->discovery_domain,
+ &state->primary_servers,
+ state->num_primary_servers);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_MINOR_FAILURE, ("Unable to sort primary servers by DNS"
+ "[%d]: %s\n", ret, sss_strerror(ret)));
+ /* continue */
+ }
+
+ ret = ad_sort_servers_by_dns(state, state->discovery_domain,
+ &state->backup_servers,
+ state->num_backup_servers);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_MINOR_FAILURE, ("Unable to sort backup servers by DNS"
+ "[%d]: %s\n", ret, sss_strerror(ret)));
+ /* continue */
+ }
+
tevent_req_done(req);
}