diff -rup samba-4.2.2.orig/source3/libsmb/clidfs.c samba-4.2.2/source3/libsmb/clidfs.c --- samba-4.2.2.orig/source3/libsmb/clidfs.c 2015-02-24 10:59:51.000000000 -0800 +++ samba-4.2.2/source3/libsmb/clidfs.c 2015-06-16 17:20:08.247914441 -0700 @@ -106,14 +106,17 @@ static NTSTATUS do_connect(TALLOC_CTX *c struct cli_state **pcli) { struct cli_state *c = NULL; + fstring dc_name; char *servicename; char *sharename; char *newserver, *newshare; const char *username; const char *password; const char *domain; + const char *realm; NTSTATUS status; int flags = 0; + bool require_msdfs_proxy = false; /* make a copy so we don't modify the global string 'service' */ servicename = talloc_strdup(ctx,share); @@ -137,6 +140,43 @@ static NTSTATUS do_connect(TALLOC_CTX *c return NT_STATUS_INVALID_PARAMETER; } + domain = get_cmdline_auth_info_domain(auth_info); + if ((domain == NULL) || (domain[0] == '\0')) { + domain = lp_workgroup(); + } + + realm = lp_realm(); + + // For domain-based DFS, if the domain or realm name is given as + // the server, the initial connection should be to one of the + // domain controllers. Assuming we can find a domain controller, + // require that the cli_check_msdfs_proxy call succeeds below. + if (strequal(server, domain) || strequal(server, realm)) { + struct ip_service *ip_list = NULL; + int count = 0; + int i; + + // is there a better way to get the nearest/best domain controller? + status = get_sorted_dc_list(domain, NULL, + &ip_list, &count, + false); + if (NT_STATUS_IS_OK(status)) { + for (i = 0; i < count; ++i) { + // We need the name for kerberos auth to trigger/work, as + // we need the server principal name during spnego + if (name_status_find("*", 0, 0, &ip_list[i].ss, dc_name)) { + DEBUG(4,("Using DC=%s for initial msdfs proxy get referrals\n", dc_name)); + server = dc_name; + require_msdfs_proxy = true; + break; + } + } + + SAFE_FREE(ip_list); + count = 0; + } + } + if (get_cmdline_auth_info_use_kerberos(auth_info)) { flags |= CLI_FULL_CONNECTION_USE_KERBEROS; } @@ -185,10 +225,6 @@ static NTSTATUS do_connect(TALLOC_CTX *c username = get_cmdline_auth_info_username(auth_info); password = get_cmdline_auth_info_password(auth_info); - domain = get_cmdline_auth_info_domain(auth_info); - if ((domain == NULL) || (domain[0] == '\0')) { - domain = lp_workgroup(); - } status = cli_session_setup(c, username, password, strlen(password), @@ -251,6 +287,8 @@ static NTSTATUS do_connect(TALLOC_CTX *c newshare, auth_info, false, force_encrypt, max_protocol, port, name_type, pcli); + } else if (require_msdfs_proxy) { + return NT_STATUS_NOT_FOUND; } /* must be a normal share */