Fix some C++ warnings
[Samba.git] / source / libsmb / dsgetdcname.c
blob19c83600d24b976ecd9cef42ddd7f2bc66ceff6a
1 /*
2 Unix SMB/CIFS implementation.
4 dsgetdcname
6 Copyright (C) Gerald Carter 2006
7 Copyright (C) Guenther Deschner 2007-2008
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
25 #define DSGETDCNAME_FMT "DSGETDCNAME/DOMAIN/%s"
26 /* 15 minutes */
27 #define DSGETDCNAME_CACHE_TTL 60*15
29 struct ip_service_name {
30 struct sockaddr_storage ss;
31 unsigned port;
32 const char *hostname;
35 static NTSTATUS make_dc_info_from_cldap_reply(TALLOC_CTX *mem_ctx,
36 uint32_t flags,
37 struct sockaddr_storage *ss,
38 struct NETLOGON_SAM_LOGON_RESPONSE_EX *r,
39 struct netr_DsRGetDCNameInfo **info);
41 /****************************************************************
42 ****************************************************************/
44 void debug_dsdcinfo_flags(int lvl, uint32_t flags)
46 DEBUG(lvl,("debug_dsdcinfo_flags: 0x%08x\n\t", flags));
48 if (flags & DS_FORCE_REDISCOVERY)
49 DEBUGADD(lvl,("DS_FORCE_REDISCOVERY "));
50 if (flags & 0x000000002)
51 DEBUGADD(lvl,("0x00000002 "));
52 if (flags & 0x000000004)
53 DEBUGADD(lvl,("0x00000004 "));
54 if (flags & 0x000000008)
55 DEBUGADD(lvl,("0x00000008 "));
56 if (flags & DS_DIRECTORY_SERVICE_REQUIRED)
57 DEBUGADD(lvl,("DS_DIRECTORY_SERVICE_REQUIRED "));
58 if (flags & DS_DIRECTORY_SERVICE_PREFERRED)
59 DEBUGADD(lvl,("DS_DIRECTORY_SERVICE_PREFERRED "));
60 if (flags & DS_GC_SERVER_REQUIRED)
61 DEBUGADD(lvl,("DS_GC_SERVER_REQUIRED "));
62 if (flags & DS_PDC_REQUIRED)
63 DEBUGADD(lvl,("DS_PDC_REQUIRED "));
64 if (flags & DS_BACKGROUND_ONLY)
65 DEBUGADD(lvl,("DS_BACKGROUND_ONLY "));
66 if (flags & DS_IP_REQUIRED)
67 DEBUGADD(lvl,("DS_IP_REQUIRED "));
68 if (flags & DS_KDC_REQUIRED)
69 DEBUGADD(lvl,("DS_KDC_REQUIRED "));
70 if (flags & DS_TIMESERV_REQUIRED)
71 DEBUGADD(lvl,("DS_TIMESERV_REQUIRED "));
72 if (flags & DS_WRITABLE_REQUIRED)
73 DEBUGADD(lvl,("DS_WRITABLE_REQUIRED "));
74 if (flags & DS_GOOD_TIMESERV_PREFERRED)
75 DEBUGADD(lvl,("DS_GOOD_TIMESERV_PREFERRED "));
76 if (flags & DS_AVOID_SELF)
77 DEBUGADD(lvl,("DS_AVOID_SELF "));
78 if (flags & DS_ONLY_LDAP_NEEDED)
79 DEBUGADD(lvl,("DS_ONLY_LDAP_NEEDED "));
80 if (flags & DS_IS_FLAT_NAME)
81 DEBUGADD(lvl,("DS_IS_FLAT_NAME "));
82 if (flags & DS_IS_DNS_NAME)
83 DEBUGADD(lvl,("DS_IS_DNS_NAME "));
84 if (flags & 0x00040000)
85 DEBUGADD(lvl,("0x00040000 "));
86 if (flags & 0x00080000)
87 DEBUGADD(lvl,("0x00080000 "));
88 if (flags & 0x00100000)
89 DEBUGADD(lvl,("0x00100000 "));
90 if (flags & 0x00200000)
91 DEBUGADD(lvl,("0x00200000 "));
92 if (flags & 0x00400000)
93 DEBUGADD(lvl,("0x00400000 "));
94 if (flags & 0x00800000)
95 DEBUGADD(lvl,("0x00800000 "));
96 if (flags & 0x01000000)
97 DEBUGADD(lvl,("0x01000000 "));
98 if (flags & 0x02000000)
99 DEBUGADD(lvl,("0x02000000 "));
100 if (flags & 0x04000000)
101 DEBUGADD(lvl,("0x04000000 "));
102 if (flags & 0x08000000)
103 DEBUGADD(lvl,("0x08000000 "));
104 if (flags & 0x10000000)
105 DEBUGADD(lvl,("0x10000000 "));
106 if (flags & 0x20000000)
107 DEBUGADD(lvl,("0x20000000 "));
108 if (flags & DS_RETURN_DNS_NAME)
109 DEBUGADD(lvl,("DS_RETURN_DNS_NAME "));
110 if (flags & DS_RETURN_FLAT_NAME)
111 DEBUGADD(lvl,("DS_RETURN_FLAT_NAME "));
112 if (flags)
113 DEBUGADD(lvl,("\n"));
116 /****************************************************************
117 ****************************************************************/
119 static char *dsgetdcname_cache_key(TALLOC_CTX *mem_ctx, const char *domain)
121 if (!domain) {
122 return NULL;
125 return talloc_asprintf_strupper_m(mem_ctx, DSGETDCNAME_FMT, domain);
128 /****************************************************************
129 ****************************************************************/
131 static NTSTATUS dsgetdcname_cache_delete(TALLOC_CTX *mem_ctx,
132 const char *domain_name)
134 char *key;
136 if (!gencache_init()) {
137 return NT_STATUS_INTERNAL_DB_ERROR;
140 key = dsgetdcname_cache_key(mem_ctx, domain_name);
141 if (!key) {
142 return NT_STATUS_NO_MEMORY;
145 if (!gencache_del(key)) {
146 return NT_STATUS_UNSUCCESSFUL;
149 return NT_STATUS_OK;
152 /****************************************************************
153 ****************************************************************/
155 static NTSTATUS dsgetdcname_cache_store(TALLOC_CTX *mem_ctx,
156 const char *domain_name,
157 const DATA_BLOB *blob)
159 time_t expire_time;
160 char *key;
161 bool ret = false;
163 if (!gencache_init()) {
164 return NT_STATUS_INTERNAL_DB_ERROR;
167 key = dsgetdcname_cache_key(mem_ctx, domain_name);
168 if (!key) {
169 return NT_STATUS_NO_MEMORY;
172 expire_time = time(NULL) + DSGETDCNAME_CACHE_TTL;
174 if (gencache_lock_entry(key) != 0) {
175 return NT_STATUS_LOCK_NOT_GRANTED;
178 ret = gencache_set_data_blob(key, blob, expire_time);
180 gencache_unlock_entry(key);
182 return ret ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
185 /****************************************************************
186 ****************************************************************/
188 static NTSTATUS store_cldap_reply(TALLOC_CTX *mem_ctx,
189 uint32_t flags,
190 struct sockaddr_storage *ss,
191 uint32_t nt_version,
192 struct NETLOGON_SAM_LOGON_RESPONSE_EX *r)
194 DATA_BLOB blob;
195 enum ndr_err_code ndr_err;
196 NTSTATUS status;
197 char addr[INET6_ADDRSTRLEN];
199 print_sockaddr(addr, sizeof(addr), ss);
201 /* FIXME */
202 r->sockaddr_size = 0x10; /* the w32 winsock addr size */
203 r->sockaddr.sa_family = 2; /* AF_INET */
204 r->sockaddr.pdc_ip = talloc_strdup(mem_ctx, addr);
206 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, r,
207 (ndr_push_flags_fn_t)ndr_push_NETLOGON_SAM_LOGON_RESPONSE_EX);
208 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
209 return ndr_map_error2ntstatus(ndr_err);
212 if (r->domain) {
213 status = dsgetdcname_cache_store(mem_ctx, r->domain, &blob);
214 if (!NT_STATUS_IS_OK(status)) {
215 goto done;
217 if (r->client_site) {
218 sitename_store(r->domain, r->client_site);
221 if (r->dns_domain) {
222 status = dsgetdcname_cache_store(mem_ctx, r->dns_domain, &blob);
223 if (!NT_STATUS_IS_OK(status)) {
224 goto done;
226 if (r->client_site) {
227 sitename_store(r->dns_domain, r->client_site);
231 status = NT_STATUS_OK;
233 done:
234 data_blob_free(&blob);
236 return status;
239 /****************************************************************
240 ****************************************************************/
242 static NTSTATUS dsgetdcname_cache_refresh(TALLOC_CTX *mem_ctx,
243 struct messaging_context *msg_ctx,
244 const char *domain_name,
245 struct GUID *domain_guid,
246 uint32_t flags,
247 const char *site_name,
248 struct netr_DsRGetDCNameInfo *info)
250 struct netr_DsRGetDCNameInfo *dc_info;
252 return dsgetdcname(mem_ctx,
253 msg_ctx,
254 domain_name,
255 domain_guid,
256 site_name,
257 flags | DS_FORCE_REDISCOVERY,
258 &dc_info);
261 /****************************************************************
262 ****************************************************************/
264 static uint32_t get_cldap_reply_server_flags(struct netlogon_samlogon_response *r,
265 uint32_t nt_version)
267 switch (nt_version & 0x0000001f) {
268 case 0:
269 case 1:
270 case 16:
271 case 17:
272 return 0;
273 case 2:
274 case 3:
275 case 18:
276 case 19:
277 return r->data.nt5.server_type;
278 case 4:
279 case 5:
280 case 6:
281 case 7:
282 return r->data.nt5_ex.server_type;
283 case 8:
284 case 9:
285 case 10:
286 case 11:
287 case 12:
288 case 13:
289 case 14:
290 case 15:
291 return r->data.nt5_ex.server_type;
292 case 20:
293 case 21:
294 case 22:
295 case 23:
296 case 24:
297 case 25:
298 case 26:
299 case 27:
300 case 28:
301 return r->data.nt5_ex.server_type;
302 case 29:
303 case 30:
304 case 31:
305 return r->data.nt5_ex.server_type;
306 default:
307 return 0;
311 /****************************************************************
312 ****************************************************************/
314 #define RETURN_ON_FALSE(x) if (!x) return false;
316 static bool check_cldap_reply_required_flags(uint32_t ret_flags,
317 uint32_t req_flags)
319 if (ret_flags == 0) {
320 return true;
323 if (req_flags & DS_PDC_REQUIRED)
324 RETURN_ON_FALSE(ret_flags & NBT_SERVER_PDC);
326 if (req_flags & DS_GC_SERVER_REQUIRED)
327 RETURN_ON_FALSE(ret_flags & NBT_SERVER_GC);
329 if (req_flags & DS_ONLY_LDAP_NEEDED)
330 RETURN_ON_FALSE(ret_flags & NBT_SERVER_LDAP);
332 if ((req_flags & DS_DIRECTORY_SERVICE_REQUIRED) ||
333 (req_flags & DS_DIRECTORY_SERVICE_PREFERRED))
334 RETURN_ON_FALSE(ret_flags & NBT_SERVER_DS);
336 if (req_flags & DS_KDC_REQUIRED)
337 RETURN_ON_FALSE(ret_flags & NBT_SERVER_KDC);
339 if (req_flags & DS_TIMESERV_REQUIRED)
340 RETURN_ON_FALSE(ret_flags & NBT_SERVER_TIMESERV);
342 if (req_flags & DS_WRITABLE_REQUIRED)
343 RETURN_ON_FALSE(ret_flags & NBT_SERVER_WRITABLE);
345 return true;
348 /****************************************************************
349 ****************************************************************/
351 static NTSTATUS dsgetdcname_cache_fetch(TALLOC_CTX *mem_ctx,
352 const char *domain_name,
353 struct GUID *domain_guid,
354 uint32_t flags,
355 const char *site_name,
356 struct netr_DsRGetDCNameInfo **info_p,
357 bool *expired)
359 char *key;
360 DATA_BLOB blob;
361 enum ndr_err_code ndr_err;
362 struct netr_DsRGetDCNameInfo *info;
363 struct NETLOGON_SAM_LOGON_RESPONSE_EX r;
364 NTSTATUS status;
366 if (!gencache_init()) {
367 return NT_STATUS_INTERNAL_DB_ERROR;
370 key = dsgetdcname_cache_key(mem_ctx, domain_name);
371 if (!key) {
372 return NT_STATUS_NO_MEMORY;
375 if (!gencache_get_data_blob(key, &blob, expired)) {
376 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
379 info = TALLOC_ZERO_P(mem_ctx, struct netr_DsRGetDCNameInfo);
380 if (!info) {
381 return NT_STATUS_NO_MEMORY;
384 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
385 (ndr_pull_flags_fn_t)ndr_pull_NETLOGON_SAM_LOGON_RESPONSE_EX);
387 data_blob_free(&blob);
388 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
389 dsgetdcname_cache_delete(mem_ctx, domain_name);
390 return ndr_map_error2ntstatus(ndr_err);
393 status = make_dc_info_from_cldap_reply(mem_ctx, flags, NULL,
394 &r, &info);
395 if (!NT_STATUS_IS_OK(status)) {
396 return status;
399 if (DEBUGLEVEL >= 10) {
400 NDR_PRINT_DEBUG(netr_DsRGetDCNameInfo, info);
403 /* check flags */
404 if (!check_cldap_reply_required_flags(info->dc_flags, flags)) {
405 DEBUG(10,("invalid flags\n"));
406 return NT_STATUS_INVALID_PARAMETER;
409 if ((flags & DS_IP_REQUIRED) &&
410 (info->dc_address_type != DS_ADDRESS_TYPE_INET)) {
411 return NT_STATUS_INVALID_PARAMETER_MIX;
414 *info_p = info;
416 return NT_STATUS_OK;
419 /****************************************************************
420 ****************************************************************/
422 static NTSTATUS dsgetdcname_cached(TALLOC_CTX *mem_ctx,
423 struct messaging_context *msg_ctx,
424 const char *domain_name,
425 struct GUID *domain_guid,
426 uint32_t flags,
427 const char *site_name,
428 struct netr_DsRGetDCNameInfo **info)
430 NTSTATUS status;
431 bool expired = false;
433 status = dsgetdcname_cache_fetch(mem_ctx, domain_name, domain_guid,
434 flags, site_name, info, &expired);
435 if (!NT_STATUS_IS_OK(status)) {
436 DEBUG(10,("dsgetdcname_cached: cache fetch failed with: %s\n",
437 nt_errstr(status)));
438 return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
441 if (flags & DS_BACKGROUND_ONLY) {
442 return status;
445 if (expired) {
446 status = dsgetdcname_cache_refresh(mem_ctx, msg_ctx,
447 domain_name,
448 domain_guid, flags,
449 site_name, *info);
450 if (!NT_STATUS_IS_OK(status)) {
451 return status;
455 return status;
458 /****************************************************************
459 ****************************************************************/
461 static bool check_allowed_required_flags(uint32_t flags,
462 const char *site_name)
464 uint32_t return_type = flags & (DS_RETURN_FLAT_NAME|DS_RETURN_DNS_NAME);
465 uint32_t offered_type = flags & (DS_IS_FLAT_NAME|DS_IS_DNS_NAME);
466 uint32_t query_type = flags & (DS_BACKGROUND_ONLY|DS_FORCE_REDISCOVERY);
468 /* FIXME: check for DSGETDC_VALID_FLAGS and check for excluse bits
469 * (DS_PDC_REQUIRED, DS_KDC_REQUIRED, DS_GC_SERVER_REQUIRED) */
471 debug_dsdcinfo_flags(10, flags);
473 if ((flags & DS_TRY_NEXTCLOSEST_SITE) && site_name) {
474 return false;
477 if (return_type == (DS_RETURN_FLAT_NAME|DS_RETURN_DNS_NAME)) {
478 return false;
481 if (offered_type == (DS_IS_DNS_NAME|DS_IS_FLAT_NAME)) {
482 return false;
485 if (query_type == (DS_BACKGROUND_ONLY|DS_FORCE_REDISCOVERY)) {
486 return false;
489 #if 0
490 if ((flags & DS_RETURN_DNS_NAME) && (!(flags & DS_IP_REQUIRED))) {
491 printf("gd: here5 \n");
492 return false;
494 #endif
495 return true;
498 /****************************************************************
499 ****************************************************************/
501 static NTSTATUS discover_dc_netbios(TALLOC_CTX *mem_ctx,
502 const char *domain_name,
503 uint32_t flags,
504 struct ip_service_name **returned_dclist,
505 int *returned_count)
507 NTSTATUS status;
508 enum nbt_name_type name_type = NBT_NAME_LOGON;
509 struct ip_service *iplist;
510 int i;
511 struct ip_service_name *dclist = NULL;
512 int count;
514 *returned_dclist = NULL;
515 *returned_count = 0;
517 if (lp_disable_netbios()) {
518 return NT_STATUS_NOT_SUPPORTED;
521 if (flags & DS_PDC_REQUIRED) {
522 name_type = NBT_NAME_PDC;
525 status = internal_resolve_name(domain_name, name_type, NULL,
526 &iplist, &count,
527 "lmhosts wins bcast");
528 if (!NT_STATUS_IS_OK(status)) {
529 DEBUG(10,("discover_dc_netbios: failed to find DC\n"));
530 return status;
533 dclist = TALLOC_ZERO_ARRAY(mem_ctx, struct ip_service_name, count);
534 if (!dclist) {
535 return NT_STATUS_NO_MEMORY;
538 for (i=0; i<count; i++) {
540 char addr[INET6_ADDRSTRLEN];
541 struct ip_service_name *r = &dclist[i];
543 print_sockaddr(addr, sizeof(addr),
544 &iplist[i].ss);
546 r->ss = iplist[i].ss;
547 r->port = iplist[i].port;
548 r->hostname = talloc_strdup(mem_ctx, addr);
549 if (!r->hostname) {
550 return NT_STATUS_NO_MEMORY;
555 *returned_dclist = dclist;
556 *returned_count = count;
558 return NT_STATUS_OK;
561 /****************************************************************
562 ****************************************************************/
564 static NTSTATUS discover_dc_dns(TALLOC_CTX *mem_ctx,
565 const char *domain_name,
566 struct GUID *domain_guid,
567 uint32_t flags,
568 const char *site_name,
569 struct ip_service_name **returned_dclist,
570 int *return_count)
572 int i, j;
573 NTSTATUS status;
574 struct dns_rr_srv *dcs = NULL;
575 int numdcs = 0;
576 int numaddrs = 0;
577 struct ip_service_name *dclist = NULL;
578 int count = 0;
580 if (flags & DS_PDC_REQUIRED) {
581 status = ads_dns_query_pdc(mem_ctx, domain_name,
582 &dcs, &numdcs);
583 } else if (flags & DS_GC_SERVER_REQUIRED) {
584 status = ads_dns_query_gcs(mem_ctx, domain_name, site_name,
585 &dcs, &numdcs);
586 } else if (flags & DS_KDC_REQUIRED) {
587 status = ads_dns_query_kdcs(mem_ctx, domain_name, site_name,
588 &dcs, &numdcs);
589 } else if (flags & DS_DIRECTORY_SERVICE_REQUIRED) {
590 status = ads_dns_query_dcs(mem_ctx, domain_name, site_name,
591 &dcs, &numdcs);
592 } else if (domain_guid) {
593 status = ads_dns_query_dcs_guid(mem_ctx, domain_name,
594 domain_guid, &dcs, &numdcs);
595 } else {
596 status = ads_dns_query_dcs(mem_ctx, domain_name, site_name,
597 &dcs, &numdcs);
600 if (!NT_STATUS_IS_OK(status)) {
601 return status;
604 if (numdcs == 0) {
605 return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
608 for (i=0;i<numdcs;i++) {
609 numaddrs += MAX(dcs[i].num_ips,1);
612 dclist = TALLOC_ZERO_ARRAY(mem_ctx,
613 struct ip_service_name,
614 numaddrs);
615 if (!dclist) {
616 return NT_STATUS_NO_MEMORY;
619 /* now unroll the list of IP addresses */
621 *return_count = 0;
622 i = 0;
623 j = 0;
625 while ((i < numdcs) && (count < numaddrs)) {
627 struct ip_service_name *r = &dclist[count];
629 r->port = dcs[count].port;
630 r->hostname = dcs[count].hostname;
632 /* If we don't have an IP list for a name, lookup it up */
634 if (!dcs[i].ss_s) {
635 interpret_string_addr(&r->ss, dcs[i].hostname, 0);
636 i++;
637 j = 0;
638 } else {
639 /* use the IP addresses from the SRV sresponse */
641 if (j >= dcs[i].num_ips) {
642 i++;
643 j = 0;
644 continue;
647 r->ss = dcs[i].ss_s[j];
648 j++;
651 /* make sure it is a valid IP. I considered checking the
652 * negative connection cache, but this is the wrong place for
653 * it. Maybe only as a hac. After think about it, if all of
654 * the IP addresses retuend from DNS are dead, what hope does a
655 * netbios name lookup have? The standard reason for falling
656 * back to netbios lookups is that our DNS server doesn't know
657 * anything about the DC's -- jerry */
659 if (!is_zero_addr(&r->ss)) {
660 count++;
661 continue;
665 *returned_dclist = dclist;
666 *return_count = count;
668 if (count > 0) {
669 return NT_STATUS_OK;
672 return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
675 /****************************************************************
676 ****************************************************************/
678 static NTSTATUS make_domain_controller_info(TALLOC_CTX *mem_ctx,
679 const char *dc_unc,
680 const char *dc_address,
681 uint32_t dc_address_type,
682 const struct GUID *domain_guid,
683 const char *domain_name,
684 const char *forest_name,
685 uint32_t flags,
686 const char *dc_site_name,
687 const char *client_site_name,
688 struct netr_DsRGetDCNameInfo **info_out)
690 struct netr_DsRGetDCNameInfo *info;
692 info = TALLOC_ZERO_P(mem_ctx, struct netr_DsRGetDCNameInfo);
693 NT_STATUS_HAVE_NO_MEMORY(info);
695 if (dc_unc) {
696 info->dc_unc = talloc_strdup(mem_ctx, dc_unc);
697 NT_STATUS_HAVE_NO_MEMORY(info->dc_unc);
700 if (dc_address) {
701 if (!(dc_address[0] == '\\' && dc_address[1] == '\\')) {
702 info->dc_address = talloc_asprintf(mem_ctx, "\\\\%s",
703 dc_address);
704 } else {
705 info->dc_address = talloc_strdup(mem_ctx, dc_address);
707 NT_STATUS_HAVE_NO_MEMORY(info->dc_address);
710 info->dc_address_type = dc_address_type;
712 if (domain_guid) {
713 info->domain_guid = *domain_guid;
716 if (domain_name) {
717 info->domain_name = talloc_strdup(mem_ctx, domain_name);
718 NT_STATUS_HAVE_NO_MEMORY(info->domain_name);
721 if (forest_name && *forest_name) {
722 info->forest_name = talloc_strdup(mem_ctx, forest_name);
723 NT_STATUS_HAVE_NO_MEMORY(info->forest_name);
724 flags |= DS_DNS_FOREST;
727 info->dc_flags = flags;
729 if (dc_site_name) {
730 info->dc_site_name = talloc_strdup(mem_ctx, dc_site_name);
731 NT_STATUS_HAVE_NO_MEMORY(info->dc_site_name);
734 if (client_site_name) {
735 info->client_site_name = talloc_strdup(mem_ctx,
736 client_site_name);
737 NT_STATUS_HAVE_NO_MEMORY(info->client_site_name);
740 *info_out = info;
742 return NT_STATUS_OK;
745 /****************************************************************
746 ****************************************************************/
748 static void map_dc_and_domain_names(uint32_t flags,
749 const char *dc_name,
750 const char *domain_name,
751 const char *dns_dc_name,
752 const char *dns_domain_name,
753 uint32_t *dc_flags,
754 const char **hostname_p,
755 const char **domain_p)
757 switch (flags & 0xf0000000) {
758 case DS_RETURN_FLAT_NAME:
759 if (dc_name && domain_name &&
760 *dc_name && *domain_name) {
761 *hostname_p = dc_name;
762 *domain_p = domain_name;
763 break;
765 case DS_RETURN_DNS_NAME:
766 default:
767 if (dns_dc_name && dns_domain_name &&
768 *dns_dc_name && *dns_domain_name) {
769 *hostname_p = dns_dc_name;
770 *domain_p = dns_domain_name;
771 *dc_flags |= DS_DNS_DOMAIN | DS_DNS_CONTROLLER;
772 break;
774 if (dc_name && domain_name &&
775 *dc_name && *domain_name) {
776 *hostname_p = dc_name;
777 *domain_p = domain_name;
778 break;
783 /****************************************************************
784 ****************************************************************/
786 static NTSTATUS make_dc_info_from_cldap_reply(TALLOC_CTX *mem_ctx,
787 uint32_t flags,
788 struct sockaddr_storage *ss,
789 struct NETLOGON_SAM_LOGON_RESPONSE_EX *r,
790 struct netr_DsRGetDCNameInfo **info)
792 const char *dc_hostname = NULL;
793 const char *dc_domain_name = NULL;
794 const char *dc_address = NULL;
795 const char *dc_forest = NULL;
796 uint32_t dc_address_type = 0;
797 uint32_t dc_flags = 0;
798 struct GUID *dc_domain_guid = NULL;
799 const char *dc_server_site = NULL;
800 const char *dc_client_site = NULL;
802 char addr[INET6_ADDRSTRLEN];
804 if (ss) {
805 print_sockaddr(addr, sizeof(addr), ss);
806 dc_address = addr;
807 dc_address_type = DS_ADDRESS_TYPE_INET;
810 if (!ss && r->sockaddr.pdc_ip) {
811 dc_address = r->sockaddr.pdc_ip;
812 dc_address_type = DS_ADDRESS_TYPE_INET;
813 } else {
814 dc_address = r->pdc_name;
815 dc_address_type = DS_ADDRESS_TYPE_NETBIOS;
818 map_dc_and_domain_names(flags,
819 r->pdc_name,
820 r->domain,
821 r->pdc_dns_name,
822 r->dns_domain,
823 &dc_flags,
824 &dc_hostname,
825 &dc_domain_name);
827 dc_flags |= r->server_type;
828 dc_forest = r->forest;
829 dc_domain_guid = &r->domain_uuid;
830 dc_server_site = r->server_site;
831 dc_client_site = r->client_site;
833 return make_domain_controller_info(mem_ctx,
834 dc_hostname,
835 dc_address,
836 dc_address_type,
837 dc_domain_guid,
838 dc_domain_name,
839 dc_forest,
840 dc_flags,
841 dc_server_site,
842 dc_client_site,
843 info);
846 /****************************************************************
847 ****************************************************************/
849 static uint32_t map_ds_flags_to_nt_version(uint32_t flags)
851 uint32_t nt_version = 0;
853 if (flags & DS_PDC_REQUIRED) {
854 nt_version |= NETLOGON_NT_VERSION_PDC;
857 if (flags & DS_GC_SERVER_REQUIRED) {
858 nt_version |= NETLOGON_NT_VERSION_GC;
861 if (flags & DS_TRY_NEXTCLOSEST_SITE) {
862 nt_version |= NETLOGON_NT_VERSION_WITH_CLOSEST_SITE;
865 if (flags & DS_IP_REQUIRED) {
866 nt_version |= NETLOGON_NT_VERSION_IP;
869 return nt_version;
872 /****************************************************************
873 ****************************************************************/
875 static NTSTATUS process_dc_dns(TALLOC_CTX *mem_ctx,
876 const char *domain_name,
877 uint32_t flags,
878 struct ip_service_name *dclist,
879 int num_dcs,
880 struct netr_DsRGetDCNameInfo **info)
882 int i = 0;
883 bool valid_dc = false;
884 struct netlogon_samlogon_response *r = NULL;
885 uint32_t nt_version = NETLOGON_NT_VERSION_5 |
886 NETLOGON_NT_VERSION_5EX;
887 uint32_t ret_flags = 0;
888 NTSTATUS status;
890 nt_version |= map_ds_flags_to_nt_version(flags);
892 for (i=0; i<num_dcs; i++) {
894 DEBUG(10,("LDAP ping to %s\n", dclist[i].hostname));
896 if (ads_cldap_netlogon(mem_ctx, dclist[i].hostname,
897 domain_name,
898 nt_version,
899 &r))
901 nt_version = r->ntver;
902 ret_flags = get_cldap_reply_server_flags(r, nt_version);
904 if (check_cldap_reply_required_flags(ret_flags, flags)) {
905 valid_dc = true;
906 break;
910 continue;
913 if (!valid_dc) {
914 return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
917 status = make_dc_info_from_cldap_reply(mem_ctx, flags, &dclist[i].ss,
918 &r->data.nt5_ex, info);
919 if (NT_STATUS_IS_OK(status)) {
920 return store_cldap_reply(mem_ctx, flags, &dclist[i].ss,
921 nt_version, &r->data.nt5_ex);
924 return status;
927 /****************************************************************
928 ****************************************************************/
930 static struct event_context *ev_context(void)
932 static struct event_context *ctx;
934 if (!ctx && !(ctx = event_context_init(NULL))) {
935 smb_panic("Could not init event context");
937 return ctx;
940 /****************************************************************
941 ****************************************************************/
943 static struct messaging_context *msg_context(TALLOC_CTX *mem_ctx)
945 static struct messaging_context *ctx;
947 if (!ctx && !(ctx = messaging_init(mem_ctx, server_id_self(),
948 ev_context()))) {
949 smb_panic("Could not init messaging context");
951 return ctx;
954 /****************************************************************
955 ****************************************************************/
957 static NTSTATUS process_dc_netbios(TALLOC_CTX *mem_ctx,
958 struct messaging_context *msg_ctx,
959 const char *domain_name,
960 uint32_t flags,
961 struct ip_service_name *dclist,
962 int num_dcs,
963 struct netr_DsRGetDCNameInfo **info)
965 struct sockaddr_storage ss;
966 struct ip_service ip_list;
967 enum nbt_name_type name_type = NBT_NAME_LOGON;
968 NTSTATUS status;
969 int i;
970 const char *dc_name = NULL;
971 fstring tmp_dc_name;
972 struct netlogon_samlogon_response *r = NULL;
973 bool store_cache = false;
974 uint32_t nt_version = NETLOGON_NT_VERSION_1 |
975 NETLOGON_NT_VERSION_5 |
976 NETLOGON_NT_VERSION_5EX_WITH_IP;
978 if (!msg_ctx) {
979 msg_ctx = msg_context(mem_ctx);
982 if (flags & DS_PDC_REQUIRED) {
983 name_type = NBT_NAME_PDC;
986 nt_version |= map_ds_flags_to_nt_version(flags);
988 DEBUG(10,("process_dc_netbios\n"));
990 for (i=0; i<num_dcs; i++) {
992 ip_list.ss = dclist[i].ss;
993 ip_list.port = 0;
995 if (!interpret_string_addr(&ss, dclist[i].hostname, AI_NUMERICHOST)) {
996 return NT_STATUS_UNSUCCESSFUL;
999 if (send_getdc_request(mem_ctx, msg_ctx,
1000 &dclist[i].ss, domain_name,
1001 NULL, nt_version))
1003 int k;
1004 smb_msleep(300);
1005 for (k=0; k<5; k++) {
1006 if (receive_getdc_response(mem_ctx,
1007 &dclist[i].ss,
1008 domain_name,
1009 &nt_version,
1010 &dc_name,
1011 &r)) {
1012 store_cache = true;
1013 namecache_store(dc_name, NBT_NAME_SERVER, 1, &ip_list);
1014 goto make_reply;
1016 smb_msleep(1500);
1020 if (name_status_find(domain_name,
1021 name_type,
1022 NBT_NAME_SERVER,
1023 &dclist[i].ss,
1024 tmp_dc_name))
1026 struct NETLOGON_SAM_LOGON_RESPONSE_NT40 logon1;
1028 r = TALLOC_ZERO_P(mem_ctx, struct netlogon_samlogon_response);
1029 NT_STATUS_HAVE_NO_MEMORY(r);
1031 ZERO_STRUCT(logon1);
1033 nt_version = NETLOGON_NT_VERSION_1;
1035 logon1.nt_version = nt_version;
1036 logon1.server = tmp_dc_name;
1037 logon1.domain = talloc_strdup_upper(mem_ctx, domain_name);
1038 NT_STATUS_HAVE_NO_MEMORY(logon1.domain);
1040 r->data.nt4 = logon1;
1041 r->ntver = nt_version;
1043 map_netlogon_samlogon_response(r);
1045 namecache_store(tmp_dc_name, NBT_NAME_SERVER, 1, &ip_list);
1047 goto make_reply;
1051 return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
1053 make_reply:
1055 status = make_dc_info_from_cldap_reply(mem_ctx, flags, &dclist[i].ss,
1056 &r->data.nt5_ex, info);
1057 if (NT_STATUS_IS_OK(status) && store_cache) {
1058 return store_cldap_reply(mem_ctx, flags, &dclist[i].ss,
1059 nt_version, &r->data.nt5_ex);
1062 return status;
1065 /****************************************************************
1066 ****************************************************************/
1068 static NTSTATUS dsgetdcname_rediscover(TALLOC_CTX *mem_ctx,
1069 struct messaging_context *msg_ctx,
1070 const char *domain_name,
1071 struct GUID *domain_guid,
1072 uint32_t flags,
1073 const char *site_name,
1074 struct netr_DsRGetDCNameInfo **info)
1076 NTSTATUS status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
1077 struct ip_service_name *dclist = NULL;
1078 int num_dcs;
1080 DEBUG(10,("dsgetdcname_rediscover\n"));
1082 if (flags & DS_IS_FLAT_NAME) {
1084 status = discover_dc_netbios(mem_ctx, domain_name, flags,
1085 &dclist, &num_dcs);
1086 NT_STATUS_NOT_OK_RETURN(status);
1088 return process_dc_netbios(mem_ctx, msg_ctx, domain_name, flags,
1089 dclist, num_dcs, info);
1092 if (flags & DS_IS_DNS_NAME) {
1094 status = discover_dc_dns(mem_ctx, domain_name, domain_guid,
1095 flags, site_name, &dclist, &num_dcs);
1096 NT_STATUS_NOT_OK_RETURN(status);
1098 return process_dc_dns(mem_ctx, domain_name, flags,
1099 dclist, num_dcs, info);
1102 status = discover_dc_dns(mem_ctx, domain_name, domain_guid, flags,
1103 site_name, &dclist, &num_dcs);
1105 if (NT_STATUS_IS_OK(status) && num_dcs != 0) {
1107 status = process_dc_dns(mem_ctx, domain_name, flags, dclist,
1108 num_dcs, info);
1109 if (NT_STATUS_IS_OK(status)) {
1110 return status;
1114 status = discover_dc_netbios(mem_ctx, domain_name, flags, &dclist,
1115 &num_dcs);
1116 NT_STATUS_NOT_OK_RETURN(status);
1118 return process_dc_netbios(mem_ctx, msg_ctx, domain_name, flags, dclist,
1119 num_dcs, info);
1122 static bool is_closest_site(struct netr_DsRGetDCNameInfo *info)
1124 if (info->dc_flags & DS_SERVER_CLOSEST) {
1125 return true;
1128 if (!info->client_site_name) {
1129 return true;
1132 if (!info->dc_site_name) {
1133 return false;
1136 if (strcmp(info->client_site_name, info->dc_site_name) == 0) {
1137 return true;
1140 return false;
1143 /********************************************************************
1144 dsgetdcname.
1146 This will be the only public function here.
1147 ********************************************************************/
1149 NTSTATUS dsgetdcname(TALLOC_CTX *mem_ctx,
1150 struct messaging_context *msg_ctx,
1151 const char *domain_name,
1152 struct GUID *domain_guid,
1153 const char *site_name,
1154 uint32_t flags,
1155 struct netr_DsRGetDCNameInfo **info)
1157 NTSTATUS status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
1158 struct netr_DsRGetDCNameInfo *myinfo = NULL;
1159 char *query_site = NULL;
1160 bool first = true;
1161 struct netr_DsRGetDCNameInfo *first_info = NULL;
1163 DEBUG(10,("dsgetdcname: domain_name: %s, "
1164 "domain_guid: %s, site_name: %s, flags: 0x%08x\n",
1165 domain_name,
1166 domain_guid ? GUID_string(mem_ctx, domain_guid) : "(null)",
1167 site_name, flags));
1169 *info = NULL;
1171 if (!check_allowed_required_flags(flags, site_name)) {
1172 DEBUG(0,("invalid flags specified\n"));
1173 return NT_STATUS_INVALID_PARAMETER;
1176 if (!site_name) {
1177 query_site = sitename_fetch(domain_name);
1178 } else {
1179 query_site = SMB_STRDUP(site_name);
1182 if (flags & DS_FORCE_REDISCOVERY) {
1183 goto rediscover;
1186 status = dsgetdcname_cached(mem_ctx, msg_ctx, domain_name, domain_guid,
1187 flags, query_site, &myinfo);
1188 if (NT_STATUS_IS_OK(status)) {
1189 goto done;
1192 if (flags & DS_BACKGROUND_ONLY) {
1193 goto done;
1196 rediscover:
1197 status = dsgetdcname_rediscover(mem_ctx, msg_ctx, domain_name,
1198 domain_guid, flags, query_site,
1199 &myinfo);
1201 done:
1202 SAFE_FREE(query_site);
1204 if (!NT_STATUS_IS_OK(status)) {
1205 if (!first) {
1206 *info = first_info;
1207 return NT_STATUS_OK;
1209 return status;
1212 if (!first) {
1213 TALLOC_FREE(first_info);
1214 } else if (!is_closest_site(myinfo)) {
1215 first = false;
1216 first_info = myinfo;
1217 /* TODO: may use the next_closest_site here */
1218 query_site = SMB_STRDUP(myinfo->client_site_name);
1219 goto rediscover;
1222 *info = myinfo;
1223 return NT_STATUS_OK;