*/
#include "includes.h"
+#include "libads/sitename_cache.h"
+#include "../librpc/gen_ndr/ndr_netlogon.h"
+#include "libads/cldap.h"
+#include "libads/dns.h"
+#include "libsmb/clidgram.h"
-#define DSGETDCNAME_FMT "DSGETDCNAME/DOMAIN/%s"
/* 15 minutes */
#define DSGETDCNAME_CACHE_TTL 60*15
return NULL;
}
- return talloc_asprintf_strupper_m(mem_ctx, DSGETDCNAME_FMT, domain);
+ return talloc_asprintf_strupper_m(mem_ctx, "DSGETDCNAME/DOMAIN/%s",
+ domain);
}
/****************************************************************
{
char *key;
- if (!gencache_init()) {
- return NT_STATUS_INTERNAL_DB_ERROR;
- }
-
key = dsgetdcname_cache_key(mem_ctx, domain_name);
if (!key) {
return NT_STATUS_NO_MEMORY;
char *key;
bool ret = false;
- if (!gencache_init()) {
- return NT_STATUS_INTERNAL_DB_ERROR;
- }
-
key = dsgetdcname_cache_key(mem_ctx, domain_name);
if (!key) {
return NT_STATUS_NO_MEMORY;
expire_time = time(NULL) + DSGETDCNAME_CACHE_TTL;
- if (gencache_lock_entry(key) != 0) {
- return NT_STATUS_LOCK_NOT_GRANTED;
- }
-
ret = gencache_set_data_blob(key, blob, expire_time);
- gencache_unlock_entry(key);
-
return ret ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
}
r->sockaddr.sockaddr_family = 2; /* AF_INET */
r->sockaddr.pdc_ip = talloc_strdup(mem_ctx, addr);
- ndr_err = ndr_push_struct_blob(&blob, mem_ctx, NULL, r,
+ ndr_err = ndr_push_struct_blob(&blob, mem_ctx, r,
(ndr_push_flags_fn_t)ndr_push_NETLOGON_SAM_LOGON_RESPONSE_EX);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
return ndr_map_error2ntstatus(ndr_err);
}
- if (r->domain) {
- status = dsgetdcname_cache_store(mem_ctx, r->domain, &blob);
+ if (r->domain_name) {
+ status = dsgetdcname_cache_store(mem_ctx, r->domain_name, &blob);
if (!NT_STATUS_IS_OK(status)) {
goto done;
}
if (r->client_site) {
- sitename_store(r->domain, r->client_site);
+ sitename_store(r->domain_name, r->client_site);
}
}
if (r->dns_domain) {
/****************************************************************
****************************************************************/
-static NTSTATUS dsgetdcname_cache_refresh(TALLOC_CTX *mem_ctx,
- struct messaging_context *msg_ctx,
- const char *domain_name,
- struct GUID *domain_guid,
- uint32_t flags,
- const char *site_name,
- struct netr_DsRGetDCNameInfo *info)
-{
- struct netr_DsRGetDCNameInfo *dc_info;
-
- return dsgetdcname(mem_ctx,
- msg_ctx,
- domain_name,
- domain_guid,
- site_name,
- flags | DS_FORCE_REDISCOVERY,
- &dc_info);
-}
-
-/****************************************************************
-****************************************************************/
-
static uint32_t get_cldap_reply_server_flags(struct netlogon_samlogon_response *r,
uint32_t nt_version)
{
/****************************************************************
****************************************************************/
-#define RETURN_ON_FALSE(x) if (!x) return false;
+#define RETURN_ON_FALSE(x) if (!(x)) return false;
static bool check_cldap_reply_required_flags(uint32_t ret_flags,
uint32_t req_flags)
static NTSTATUS dsgetdcname_cache_fetch(TALLOC_CTX *mem_ctx,
const char *domain_name,
- struct GUID *domain_guid,
+ const struct GUID *domain_guid,
uint32_t flags,
const char *site_name,
- struct netr_DsRGetDCNameInfo **info_p,
- bool *expired)
+ struct netr_DsRGetDCNameInfo **info_p)
{
char *key;
DATA_BLOB blob;
struct NETLOGON_SAM_LOGON_RESPONSE_EX r;
NTSTATUS status;
- if (!gencache_init()) {
- return NT_STATUS_INTERNAL_DB_ERROR;
- }
-
key = dsgetdcname_cache_key(mem_ctx, domain_name);
if (!key) {
return NT_STATUS_NO_MEMORY;
}
- if (!gencache_get_data_blob(key, &blob, expired)) {
- return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ if (!gencache_get_data_blob(key, &blob, NULL, NULL)) {
+ return NT_STATUS_NOT_FOUND;
}
info = TALLOC_ZERO_P(mem_ctx, struct netr_DsRGetDCNameInfo);
return NT_STATUS_NO_MEMORY;
}
- ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, NULL, &r,
+ ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
(ndr_pull_flags_fn_t)ndr_pull_NETLOGON_SAM_LOGON_RESPONSE_EX);
data_blob_free(&blob);
static NTSTATUS dsgetdcname_cached(TALLOC_CTX *mem_ctx,
struct messaging_context *msg_ctx,
const char *domain_name,
- struct GUID *domain_guid,
+ const struct GUID *domain_guid,
uint32_t flags,
const char *site_name,
struct netr_DsRGetDCNameInfo **info)
{
NTSTATUS status;
- bool expired = false;
status = dsgetdcname_cache_fetch(mem_ctx, domain_name, domain_guid,
- flags, site_name, info, &expired);
- if (!NT_STATUS_IS_OK(status)) {
+ flags, site_name, info);
+ if (!NT_STATUS_IS_OK(status)
+ && !NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
DEBUG(10,("dsgetdcname_cached: cache fetch failed with: %s\n",
nt_errstr(status)));
return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
return status;
}
- if (expired) {
- status = dsgetdcname_cache_refresh(mem_ctx, msg_ctx,
- domain_name,
- domain_guid, flags,
- site_name, *info);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
+ struct netr_DsRGetDCNameInfo *dc_info;
+
+ status = dsgetdcname(mem_ctx, msg_ctx, domain_name,
+ domain_guid, site_name,
+ flags | DS_FORCE_REDISCOVERY,
+ &dc_info);
+
if (!NT_STATUS_IS_OK(status)) {
return status;
}
+
+ *info = dc_info;
}
return status;
dclist = TALLOC_ZERO_ARRAY(mem_ctx, struct ip_service_name, count);
if (!dclist) {
+ SAFE_FREE(iplist);
return NT_STATUS_NO_MEMORY;
}
r->port = iplist[i].port;
r->hostname = talloc_strdup(mem_ctx, addr);
if (!r->hostname) {
+ SAFE_FREE(iplist);
return NT_STATUS_NO_MEMORY;
}
*returned_dclist = dclist;
*returned_count = count;
+ SAFE_FREE(iplist);
return NT_STATUS_OK;
}
static NTSTATUS discover_dc_dns(TALLOC_CTX *mem_ctx,
const char *domain_name,
- struct GUID *domain_guid,
+ const struct GUID *domain_guid,
uint32_t flags,
const char *site_name,
struct ip_service_name **returned_dclist,
struct ip_service_name *r = &dclist[count];
- r->port = dcs[count].port;
- r->hostname = dcs[count].hostname;
+ r->port = dcs[i].port;
+ r->hostname = dcs[i].hostname;
/* If we don't have an IP list for a name, lookup it up */
if (!dcs[i].ss_s) {
- interpret_string_addr(&r->ss, dcs[i].hostname, 0);
+ interpret_string_addr_prefer_ipv4(&r->ss,
+ dcs[i].hostname, 0);
i++;
j = 0;
} else {
* back to netbios lookups is that our DNS server doesn't know
* anything about the DC's -- jerry */
- if (!is_zero_addr(&r->ss)) {
+ if (!is_zero_addr((struct sockaddr *)(void *)&r->ss)) {
count++;
continue;
}
if (forest_name && *forest_name) {
info->forest_name = talloc_strdup(mem_ctx, forest_name);
NT_STATUS_HAVE_NO_MEMORY(info->forest_name);
- flags |= DS_DNS_FOREST;
+ flags |= DS_DNS_FOREST_ROOT;
}
info->dc_flags = flags;
map_dc_and_domain_names(flags,
r->pdc_name,
- r->domain,
+ r->domain_name,
r->pdc_dns_name,
r->dns_domain,
&dc_flags,
/****************************************************************
****************************************************************/
-static struct event_context *ev_context(void)
-{
- static struct event_context *ctx;
-
- if (!ctx && !(ctx = event_context_init(NULL))) {
- smb_panic("Could not init event context");
- }
- return ctx;
-}
-
-/****************************************************************
-****************************************************************/
-
-static struct messaging_context *msg_context(TALLOC_CTX *mem_ctx)
-{
- static struct messaging_context *ctx;
-
- if (!ctx && !(ctx = messaging_init(mem_ctx, server_id_self(),
- ev_context()))) {
- smb_panic("Could not init messaging context");
- }
- return ctx;
-}
-
/****************************************************************
****************************************************************/
NETLOGON_NT_VERSION_5 |
NETLOGON_NT_VERSION_5EX_WITH_IP;
- if (!msg_ctx) {
- msg_ctx = msg_context(mem_ctx);
+ if (msg_ctx == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
}
if (flags & DS_PDC_REQUIRED) {
DEBUG(10,("process_dc_netbios\n"));
for (i=0; i<num_dcs; i++) {
+ uint16_t val;
+ int dgm_id;
+
+ generate_random_buffer((uint8_t *)&val, 2);
+ dgm_id = val;
ip_list.ss = dclist[i].ss;
ip_list.port = 0;
- if (!interpret_string_addr(&ss, dclist[i].hostname, AI_NUMERICHOST)) {
+ if (!interpret_string_addr_prefer_ipv4(&ss, dclist[i].hostname, AI_NUMERICHOST)) {
return NT_STATUS_UNSUCCESSFUL;
}
- if (send_getdc_request(mem_ctx, msg_ctx,
+ if (send_getdc_request(msg_ctx,
&dclist[i].ss, domain_name,
- NULL, nt_version))
+ NULL, nt_version, dgm_id))
{
int k;
smb_msleep(300);
if (receive_getdc_response(mem_ctx,
&dclist[i].ss,
domain_name,
+ dgm_id,
&nt_version,
&dc_name,
&r)) {
nt_version = NETLOGON_NT_VERSION_1;
logon1.nt_version = nt_version;
- logon1.server = tmp_dc_name;
- logon1.domain = talloc_strdup_upper(mem_ctx, domain_name);
- NT_STATUS_HAVE_NO_MEMORY(logon1.domain);
+ logon1.pdc_name = tmp_dc_name;
+ logon1.domain_name = talloc_strdup_upper(mem_ctx, domain_name);
+ NT_STATUS_HAVE_NO_MEMORY(logon1.domain_name);
r->data.nt4 = logon1;
r->ntver = nt_version;
+ map_netlogon_samlogon_response(r);
+
namecache_store(tmp_dc_name, NBT_NAME_SERVER, 1, &ip_list);
goto make_reply;
static NTSTATUS dsgetdcname_rediscover(TALLOC_CTX *mem_ctx,
struct messaging_context *msg_ctx,
const char *domain_name,
- struct GUID *domain_guid,
+ const struct GUID *domain_guid,
uint32_t flags,
const char *site_name,
struct netr_DsRGetDCNameInfo **info)
num_dcs, info);
}
+static bool is_closest_site(struct netr_DsRGetDCNameInfo *info)
+{
+ if (info->dc_flags & DS_SERVER_CLOSEST) {
+ return true;
+ }
+
+ if (!info->client_site_name) {
+ return true;
+ }
+
+ if (!info->dc_site_name) {
+ return false;
+ }
+
+ if (strcmp(info->client_site_name, info->dc_site_name) == 0) {
+ return true;
+ }
+
+ return false;
+}
+
/********************************************************************
dsgetdcname.
NTSTATUS dsgetdcname(TALLOC_CTX *mem_ctx,
struct messaging_context *msg_ctx,
const char *domain_name,
- struct GUID *domain_guid,
+ const struct GUID *domain_guid,
const char *site_name,
uint32_t flags,
struct netr_DsRGetDCNameInfo **info)
NTSTATUS status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
struct netr_DsRGetDCNameInfo *myinfo = NULL;
char *query_site = NULL;
+ bool first = true;
+ struct netr_DsRGetDCNameInfo *first_info = NULL;
DEBUG(10,("dsgetdcname: domain_name: %s, "
"domain_guid: %s, site_name: %s, flags: 0x%08x\n",
return NT_STATUS_INVALID_PARAMETER;
}
- if (!site_name) {
+ if ((site_name == NULL) || (site_name[0] == '\0')) {
query_site = sitename_fetch(domain_name);
} else {
query_site = SMB_STRDUP(site_name);
status = dsgetdcname_cached(mem_ctx, msg_ctx, domain_name, domain_guid,
flags, query_site, &myinfo);
if (NT_STATUS_IS_OK(status)) {
- *info = myinfo;
goto done;
}
domain_guid, flags, query_site,
&myinfo);
- if (NT_STATUS_IS_OK(status)) {
- *info = myinfo;
- }
-
done:
SAFE_FREE(query_site);
- return status;
+ if (!NT_STATUS_IS_OK(status)) {
+ if (!first) {
+ *info = first_info;
+ return NT_STATUS_OK;
+ }
+ return status;
+ }
+
+ if (!first) {
+ TALLOC_FREE(first_info);
+ } else if (!is_closest_site(myinfo)) {
+ first = false;
+ first_info = myinfo;
+ /* TODO: may use the next_closest_site here */
+ query_site = SMB_STRDUP(myinfo->client_site_name);
+ goto rediscover;
+ }
+
+ *info = myinfo;
+ return NT_STATUS_OK;
}