diff -Nuar a/samba-4.1.0/dfs_server/dfs_server_ad.c.orig b/samba-4.1.0/dfs_server/dfs_server_ad.c --- a/samba-4.1.0/dfs_server/dfs_server_ad.c.orig 2014-01-07 21:23:28.588000000 +0100 +++ b/samba-4.1.0/dfs_server/dfs_server_ad.c 2014-01-07 20:57:27.004000000 +0100 @@ -56,6 +56,28 @@ } } +static void shuffle_dc_set_preferred(struct dc_set *list, uint32_t preferred_index) +{ + uint32_t j; + + srandom(time(NULL)); + + const char *tmp; + tmp = list->names[preferred_index]; + list->names[preferred_index] = list->names[0]; + list->names[0] = tmp; + + for (j = list->count - 1; j > 1; j--) { + uint32_t r; + + r = 1 + random() % j; + + tmp = list->names[j]; + list->names[j] = list->names[r]; + list->names[r] = tmp; + } +} + /* fill a referral type structure */ @@ -187,6 +209,7 @@ get the DCs list within a site */ static NTSTATUS get_dcs_insite(TALLOC_CTX *ctx, struct ldb_context *ldb, + const char *logon_server, struct ldb_dn *sitedn, struct dc_set *list, bool dofqdn) { @@ -196,6 +219,8 @@ unsigned int i; int ret; const char **dc_list; + uint32_t preferred_index; + bool preferred_dc = false; ret = ldb_search(ldb, ctx, &r, sitedn, LDB_SCOPE_SUBTREE, attrs, "(&(objectClass=server)(serverReference=*))"); @@ -238,19 +263,8 @@ return NT_STATUS_INTERNAL_ERROR; } - if (dofqdn) { - const char *dns = ldb_msg_find_attr_as_string(r2->msgs[0], "dNSHostName", NULL); - if (dns == NULL) { - DEBUG(2,(__location__ ": dNSHostName missing on %s\n", - ldb_dn_get_linearized(dn))); - talloc_free(r); - return NT_STATUS_INTERNAL_ERROR; - } - - list->names[list->count] = talloc_strdup(list->names, dns); - NT_STATUS_HAVE_NO_MEMORY_AND_FREE(list->names[list->count], r); - } else { - char *tmp; + char *netbios_name = NULL; + if (!dofqdn || logon_server != NULL) { const char *aname = ldb_msg_find_attr_as_string(r2->msgs[0], "sAMAccountName", NULL); if (aname == NULL) { DEBUG(2,(__location__ ": sAMAccountName missing on %s\n", @@ -259,18 +273,47 @@ return NT_STATUS_INTERNAL_ERROR; } - tmp = talloc_strdup(list->names, aname); - NT_STATUS_HAVE_NO_MEMORY_AND_FREE(tmp, r); + netbios_name = talloc_strdup(list->names, aname); + NT_STATUS_HAVE_NO_MEMORY_AND_FREE(netbios_name, r); /* Netbios name is also the sAMAccountName for computer but without the final $ */ - tmp[strlen(tmp) - 1] = '\0'; - list->names[list->count] = tmp; + netbios_name[strlen(netbios_name) - 1] = '\0'; + + if (logon_server != NULL && strcasecmp(logon_server, netbios_name) == 0) { + preferred_index = list->count; + preferred_dc = true; + } + + if (!dofqdn) { + list->names[list->count] = netbios_name; + } else { + talloc_free(netbios_name); + } } + + if (dofqdn) { + const char *dns = ldb_msg_find_attr_as_string(r2->msgs[0], "dNSHostName", NULL); + if (dns == NULL) { + DEBUG(2,(__location__ ": dNSHostName missing on %s\n", + ldb_dn_get_linearized(dn))); + talloc_free(r); + return NT_STATUS_INTERNAL_ERROR; + } + + list->names[list->count] = talloc_strdup(list->names, dns); + NT_STATUS_HAVE_NO_MEMORY_AND_FREE(list->names[list->count], r); + } + list->count++; talloc_free(r2); } - shuffle_dc_set(list); + + if (preferred_dc) { + shuffle_dc_set_preferred(list, preferred_index); + } else { + shuffle_dc_set(list); + } talloc_free(r); return NT_STATUS_OK; @@ -281,6 +324,7 @@ get all DCs */ static NTSTATUS get_dcs(TALLOC_CTX *ctx, struct ldb_context *ldb, + const char *logon_server, const char *searched_site, bool need_fqdn, struct dc_set ***pset_list, uint32_t flags) { @@ -361,7 +405,7 @@ set_list[current_pos]->names = NULL; set_list[current_pos]->count = 0; - status = get_dcs_insite(subctx, ldb, sitedn, + status = get_dcs_insite(subctx, ldb, logon_server, sitedn, set_list[current_pos], need_fqdn); if (!NT_STATUS_IS_OK(status)) { DEBUG(2,(__location__ ": Failed to get DC from site %s - %s\n", @@ -434,7 +478,7 @@ */ dn = r->msgs[i]->dn; - status = get_dcs_insite(subctx, ldb, dn, + status = get_dcs_insite(subctx, ldb, logon_server, dn, set_list[current_pos], need_fqdn); if (!NT_STATUS_IS_OK(status)) { @@ -534,6 +578,7 @@ */ static NTSTATUS dodc_referral(struct loadparm_context *lp_ctx, struct ldb_context *sam_ctx, + const char *logon_server, const struct tsocket_address *client, struct dfs_GetDFSReferral *r, const char *domain_name) @@ -575,7 +620,7 @@ site_name = samdb_client_site_name(sam_ctx, r, client_str, NULL); - status = get_dcs(r, sam_ctx, site_name, need_fqdn, &set, 0); + status = get_dcs(r, sam_ctx, logon_server, site_name, need_fqdn, &set, 0); if (!NT_STATUS_IS_OK(status)) { DEBUG(3,("Unable to get list of DCs - %s\n", nt_errstr(status))); @@ -648,6 +693,7 @@ static NTSTATUS dosysvol_referral(struct loadparm_context *lp_ctx, struct ldb_context *sam_ctx, const struct tsocket_address *client, + const char *logon_server, struct dfs_GetDFSReferral *r, const char *domain_name, const char *dfs_name) @@ -686,7 +732,7 @@ site_name = samdb_client_site_name(sam_ctx, r, client_str, NULL); - status = get_dcs(r, sam_ctx, site_name, need_fqdn, &set, 0); + status = get_dcs(r, sam_ctx, logon_server, site_name, need_fqdn, &set, 0); if (!NT_STATUS_IS_OK(status)) { DEBUG(3,("Unable to get list of DCs - %s\n", nt_errstr(status))); @@ -760,6 +806,7 @@ */ NTSTATUS dfs_server_ad_get_referrals(struct loadparm_context *lp_ctx, struct ldb_context *sam_ctx, + const char *logon_server, const struct tsocket_address *client, struct dfs_GetDFSReferral *r) { @@ -896,7 +943,7 @@ * be just a sysvol/netlogon referral. */ if (dfs_name == NULL) { - return dodc_referral(lp_ctx, sam_ctx, + return dodc_referral(lp_ctx, sam_ctx, logon_server, client, r, server_name); } @@ -908,7 +955,7 @@ */ if (strcasecmp(dfs_name, "sysvol") == 0 || strcasecmp(dfs_name, "netlogon") == 0) { - return dosysvol_referral(lp_ctx, sam_ctx, client, r, + return dosysvol_referral(lp_ctx, sam_ctx, client, logon_server, r, server_name, dfs_name); } diff -Nuar a/samba-4.1.0/dfs_server/dfs_server_ad.h.orig b/samba-4.1.0/dfs_server/dfs_server_ad.h --- a/samba-4.1.0/dfs_server/dfs_server_ad.h.orig 2014-01-07 16:23:00.516000000 +0100 +++ b/samba-4.1.0/dfs_server/dfs_server_ad.h 2014-01-07 20:48:40.764000000 +0100 @@ -19,5 +19,6 @@ NTSTATUS dfs_server_ad_get_referrals(struct loadparm_context *lp_ctx, struct ldb_context *sam_ctx, + const char *logon_server, const struct tsocket_address *client, struct dfs_GetDFSReferral *r); --- a/samba-4.1.0/source3/modules/vfs_dfs_samba4.c.orig 2014-01-07 16:22:59.876000000 +0100 +++ b/samba-4.1.0/source3/modules/vfs_dfs_samba4.c 2014-01-07 20:49:48.908000000 +0100 @@ -117,6 +117,7 @@ status = dfs_server_ad_get_referrals(data->lp_ctx, data->sam_ctx, + handle->conn->session_info->info->logon_server, handle->conn->sconn->remote_address, r); if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) { --- a/samba-4.1.0/source4/smb_server/smb/trans2.c.orig 2014-01-07 16:23:01.448000000 +0100 +++ b/samba-4.1.0/source4/smb_server/smb/trans2.c 2014-01-07 20:56:00.168000000 +0100 @@ -899,6 +899,7 @@ (unsigned int)strlen_m(r->in.req.servername)*2)); status = dfs_server_ad_get_referrals(lp_ctx, ldb, + NULL, req->smb_conn->connection->remote_address, r); if (!NT_STATUS_IS_OK(status)) { talloc_free(r);