Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : dsgetdcname
5 :
6 : Copyright (C) Gerald Carter 2006
7 : Copyright (C) Guenther Deschner 2007-2008
8 :
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.
13 :
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.
18 :
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/>.
21 : */
22 :
23 : #include "includes.h"
24 : #include "libsmb/dsgetdcname.h"
25 : #include "libsmb/namequery.h"
26 : #include "libads/sitename_cache.h"
27 : #include "../librpc/gen_ndr/ndr_netlogon.h"
28 : #include "libads/cldap.h"
29 : #include "lib/addns/dnsquery_srv.h"
30 : #include "libsmb/clidgram.h"
31 : #include "lib/gencache.h"
32 : #include "lib/util/util_net.h"
33 :
34 : /* 15 minutes */
35 : #define DSGETDCNAME_CACHE_TTL 60*15
36 :
37 : struct ip_service_name {
38 : struct samba_sockaddr sa;
39 : const char *hostname;
40 : };
41 :
42 : static NTSTATUS make_dc_info_from_cldap_reply(
43 : TALLOC_CTX *mem_ctx,
44 : uint32_t flags,
45 : const struct samba_sockaddr *sa,
46 : struct NETLOGON_SAM_LOGON_RESPONSE_EX *r,
47 : struct netr_DsRGetDCNameInfo **info);
48 :
49 : /****************************************************************
50 : ****************************************************************/
51 :
52 37 : static void debug_dsdcinfo_flags(int lvl, uint32_t flags)
53 : {
54 37 : DEBUG(lvl,("debug_dsdcinfo_flags: 0x%08x\n\t", flags));
55 :
56 37 : if (flags & DS_FORCE_REDISCOVERY)
57 31 : DEBUGADD(lvl,("DS_FORCE_REDISCOVERY "));
58 37 : if (flags & 0x000000002)
59 0 : DEBUGADD(lvl,("0x00000002 "));
60 37 : if (flags & 0x000000004)
61 0 : DEBUGADD(lvl,("0x00000004 "));
62 37 : if (flags & 0x000000008)
63 0 : DEBUGADD(lvl,("0x00000008 "));
64 37 : if (flags & DS_DIRECTORY_SERVICE_REQUIRED)
65 30 : DEBUGADD(lvl,("DS_DIRECTORY_SERVICE_REQUIRED "));
66 37 : if (flags & DS_DIRECTORY_SERVICE_PREFERRED)
67 0 : DEBUGADD(lvl,("DS_DIRECTORY_SERVICE_PREFERRED "));
68 37 : if (flags & DS_GC_SERVER_REQUIRED)
69 0 : DEBUGADD(lvl,("DS_GC_SERVER_REQUIRED "));
70 37 : if (flags & DS_PDC_REQUIRED)
71 0 : DEBUGADD(lvl,("DS_PDC_REQUIRED "));
72 37 : if (flags & DS_BACKGROUND_ONLY)
73 0 : DEBUGADD(lvl,("DS_BACKGROUND_ONLY "));
74 37 : if (flags & DS_IP_REQUIRED)
75 0 : DEBUGADD(lvl,("DS_IP_REQUIRED "));
76 37 : if (flags & DS_KDC_REQUIRED)
77 0 : DEBUGADD(lvl,("DS_KDC_REQUIRED "));
78 37 : if (flags & DS_TIMESERV_REQUIRED)
79 0 : DEBUGADD(lvl,("DS_TIMESERV_REQUIRED "));
80 37 : if (flags & DS_WRITABLE_REQUIRED)
81 30 : DEBUGADD(lvl,("DS_WRITABLE_REQUIRED "));
82 37 : if (flags & DS_GOOD_TIMESERV_PREFERRED)
83 0 : DEBUGADD(lvl,("DS_GOOD_TIMESERV_PREFERRED "));
84 37 : if (flags & DS_AVOID_SELF)
85 0 : DEBUGADD(lvl,("DS_AVOID_SELF "));
86 37 : if (flags & DS_ONLY_LDAP_NEEDED)
87 0 : DEBUGADD(lvl,("DS_ONLY_LDAP_NEEDED "));
88 37 : if (flags & DS_IS_FLAT_NAME)
89 1 : DEBUGADD(lvl,("DS_IS_FLAT_NAME "));
90 37 : if (flags & DS_IS_DNS_NAME)
91 27 : DEBUGADD(lvl,("DS_IS_DNS_NAME "));
92 37 : if (flags & DS_TRY_NEXTCLOSEST_SITE)
93 0 : DEBUGADD(lvl,("DS_TRY_NEXTCLOSEST_SITE "));
94 37 : if (flags & DS_DIRECTORY_SERVICE_6_REQUIRED)
95 0 : DEBUGADD(lvl,("DS_DIRECTORY_SERVICE_6_REQUIRED "));
96 37 : if (flags & DS_WEB_SERVICE_REQUIRED)
97 0 : DEBUGADD(lvl,("DS_WEB_SERVICE_REQUIRED "));
98 37 : if (flags & DS_DIRECTORY_SERVICE_8_REQUIRED)
99 0 : DEBUGADD(lvl,("DS_DIRECTORY_SERVICE_8_REQUIRED "));
100 37 : if (flags & DS_DIRECTORY_SERVICE_9_REQUIRED)
101 0 : DEBUGADD(lvl,("DS_DIRECTORY_SERVICE_9_REQUIRED "));
102 37 : if (flags & DS_DIRECTORY_SERVICE_10_REQUIRED)
103 0 : DEBUGADD(lvl,("DS_DIRECTORY_SERVICE_10_REQUIRED "));
104 37 : if (flags & 0x01000000)
105 0 : DEBUGADD(lvl,("0x01000000 "));
106 37 : if (flags & 0x02000000)
107 0 : DEBUGADD(lvl,("0x02000000 "));
108 37 : if (flags & 0x04000000)
109 0 : DEBUGADD(lvl,("0x04000000 "));
110 37 : if (flags & 0x08000000)
111 0 : DEBUGADD(lvl,("0x08000000 "));
112 37 : if (flags & 0x10000000)
113 0 : DEBUGADD(lvl,("0x10000000 "));
114 37 : if (flags & 0x20000000)
115 0 : DEBUGADD(lvl,("0x20000000 "));
116 37 : if (flags & DS_RETURN_DNS_NAME)
117 37 : DEBUGADD(lvl,("DS_RETURN_DNS_NAME "));
118 37 : if (flags & DS_RETURN_FLAT_NAME)
119 0 : DEBUGADD(lvl,("DS_RETURN_FLAT_NAME "));
120 37 : if (flags)
121 37 : DEBUGADD(lvl,("\n"));
122 37 : }
123 :
124 : /****************************************************************
125 : ****************************************************************/
126 :
127 57 : static char *dsgetdcname_cache_key(TALLOC_CTX *mem_ctx, const char *domain)
128 : {
129 57 : if (!domain) {
130 0 : return NULL;
131 : }
132 :
133 57 : return talloc_asprintf_strupper_m(mem_ctx, "DSGETDCNAME/DOMAIN/%s",
134 : domain);
135 : }
136 :
137 : /****************************************************************
138 : ****************************************************************/
139 :
140 0 : static NTSTATUS dsgetdcname_cache_delete(TALLOC_CTX *mem_ctx,
141 : const char *domain_name)
142 : {
143 : char *key;
144 :
145 0 : key = dsgetdcname_cache_key(mem_ctx, domain_name);
146 0 : if (!key) {
147 0 : return NT_STATUS_NO_MEMORY;
148 : }
149 :
150 0 : if (!gencache_del(key)) {
151 0 : return NT_STATUS_UNSUCCESSFUL;
152 : }
153 :
154 0 : return NT_STATUS_OK;
155 : }
156 :
157 : /****************************************************************
158 : ****************************************************************/
159 :
160 51 : static NTSTATUS dsgetdcname_cache_store(TALLOC_CTX *mem_ctx,
161 : const char *domain_name,
162 : DATA_BLOB blob)
163 : {
164 : time_t expire_time;
165 : char *key;
166 51 : bool ret = false;
167 :
168 51 : key = dsgetdcname_cache_key(mem_ctx, domain_name);
169 51 : if (!key) {
170 0 : return NT_STATUS_NO_MEMORY;
171 : }
172 :
173 51 : expire_time = time(NULL) + DSGETDCNAME_CACHE_TTL;
174 :
175 51 : ret = gencache_set_data_blob(key, blob, expire_time);
176 :
177 51 : return ret ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
178 : }
179 :
180 : /****************************************************************
181 : ****************************************************************/
182 :
183 26 : static NTSTATUS store_cldap_reply(TALLOC_CTX *mem_ctx,
184 : uint32_t flags,
185 : struct samba_sockaddr *sa,
186 : uint32_t nt_version,
187 : struct NETLOGON_SAM_LOGON_RESPONSE_EX *r)
188 : {
189 : DATA_BLOB blob;
190 : enum ndr_err_code ndr_err;
191 : NTSTATUS status;
192 : char addr[INET6_ADDRSTRLEN];
193 :
194 26 : print_sockaddr(addr, sizeof(addr), &sa->u.ss);
195 :
196 : /* FIXME */
197 26 : r->sockaddr_size = 0x10; /* the w32 winsock addr size */
198 26 : r->sockaddr.sockaddr_family = 2; /* AF_INET */
199 26 : if (is_ipaddress_v4(addr)) {
200 26 : r->sockaddr.pdc_ip = talloc_strdup(mem_ctx, addr);
201 26 : if (r->sockaddr.pdc_ip == NULL) {
202 0 : return NT_STATUS_NO_MEMORY;
203 : }
204 : } else {
205 : /*
206 : * ndr_push_NETLOGON_SAM_LOGON_RESPONSE_EX will
207 : * fail with an ipv6 address.
208 : *
209 : * This matches windows behaviour in the CLDAP
210 : * response when NETLOGON_NT_VERSION_5EX_WITH_IP
211 : * is used.
212 : *
213 : * Windows returns the ipv4 address of the ipv6
214 : * server interface and falls back to 127.0.0.1
215 : * if there's no ipv4 address.
216 : */
217 0 : r->sockaddr.pdc_ip = talloc_strdup(mem_ctx, "127.0.0.1");
218 0 : if (r->sockaddr.pdc_ip == NULL) {
219 0 : return NT_STATUS_NO_MEMORY;
220 : }
221 : }
222 :
223 26 : ndr_err = ndr_push_struct_blob(&blob, mem_ctx, r,
224 : (ndr_push_flags_fn_t)ndr_push_NETLOGON_SAM_LOGON_RESPONSE_EX);
225 26 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
226 0 : return ndr_map_error2ntstatus(ndr_err);
227 : }
228 :
229 26 : if (r->domain_name) {
230 26 : status = dsgetdcname_cache_store(mem_ctx, r->domain_name,
231 : blob);
232 26 : if (!NT_STATUS_IS_OK(status)) {
233 0 : goto done;
234 : }
235 26 : if (r->client_site) {
236 25 : sitename_store(r->domain_name, r->client_site);
237 : }
238 : }
239 26 : if (r->dns_domain) {
240 25 : status = dsgetdcname_cache_store(mem_ctx, r->dns_domain, blob);
241 25 : if (!NT_STATUS_IS_OK(status)) {
242 0 : goto done;
243 : }
244 25 : if (r->client_site) {
245 25 : sitename_store(r->dns_domain, r->client_site);
246 : }
247 : }
248 :
249 26 : status = NT_STATUS_OK;
250 :
251 26 : done:
252 26 : data_blob_free(&blob);
253 :
254 26 : return status;
255 : }
256 :
257 : /****************************************************************
258 : ****************************************************************/
259 :
260 25 : static uint32_t get_cldap_reply_server_flags(struct netlogon_samlogon_response *r,
261 : uint32_t nt_version)
262 : {
263 25 : switch (nt_version & 0x0000001f) {
264 0 : case 0:
265 : case 1:
266 : case 16:
267 : case 17:
268 0 : return 0;
269 0 : case 2:
270 : case 3:
271 : case 18:
272 : case 19:
273 0 : return r->data.nt5.server_type;
274 25 : case 4:
275 : case 5:
276 : case 6:
277 : case 7:
278 25 : return r->data.nt5_ex.server_type;
279 0 : case 8:
280 : case 9:
281 : case 10:
282 : case 11:
283 : case 12:
284 : case 13:
285 : case 14:
286 : case 15:
287 0 : return r->data.nt5_ex.server_type;
288 0 : case 20:
289 : case 21:
290 : case 22:
291 : case 23:
292 : case 24:
293 : case 25:
294 : case 26:
295 : case 27:
296 : case 28:
297 0 : return r->data.nt5_ex.server_type;
298 0 : case 29:
299 : case 30:
300 : case 31:
301 0 : return r->data.nt5_ex.server_type;
302 0 : default:
303 0 : return 0;
304 : }
305 : }
306 :
307 : /****************************************************************
308 : ****************************************************************/
309 :
310 6 : static NTSTATUS dsgetdcname_cache_fetch(TALLOC_CTX *mem_ctx,
311 : const char *domain_name,
312 : const struct GUID *domain_guid,
313 : uint32_t flags,
314 : struct netr_DsRGetDCNameInfo **info_p)
315 : {
316 : char *key;
317 : DATA_BLOB blob;
318 : enum ndr_err_code ndr_err;
319 : struct netr_DsRGetDCNameInfo *info;
320 : struct NETLOGON_SAM_LOGON_RESPONSE_EX r;
321 : NTSTATUS status;
322 :
323 6 : key = dsgetdcname_cache_key(mem_ctx, domain_name);
324 6 : if (!key) {
325 0 : return NT_STATUS_NO_MEMORY;
326 : }
327 :
328 6 : if (!gencache_get_data_blob(key, NULL, &blob, NULL, NULL)) {
329 1 : return NT_STATUS_NOT_FOUND;
330 : }
331 :
332 5 : info = talloc_zero(mem_ctx, struct netr_DsRGetDCNameInfo);
333 5 : if (!info) {
334 0 : data_blob_free(&blob);
335 0 : return NT_STATUS_NO_MEMORY;
336 : }
337 :
338 5 : ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
339 : (ndr_pull_flags_fn_t)ndr_pull_NETLOGON_SAM_LOGON_RESPONSE_EX);
340 :
341 5 : data_blob_free(&blob);
342 5 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
343 0 : dsgetdcname_cache_delete(mem_ctx, domain_name);
344 0 : return ndr_map_error2ntstatus(ndr_err);
345 : }
346 :
347 5 : status = make_dc_info_from_cldap_reply(mem_ctx, flags, NULL,
348 : &r, &info);
349 5 : if (!NT_STATUS_IS_OK(status)) {
350 0 : return status;
351 : }
352 :
353 5 : if (DEBUGLEVEL >= 10) {
354 0 : NDR_PRINT_DEBUG(netr_DsRGetDCNameInfo, info);
355 : }
356 :
357 : /* check flags */
358 5 : if (!check_cldap_reply_required_flags(info->dc_flags, flags)) {
359 0 : DEBUG(10,("invalid flags\n"));
360 0 : return NT_STATUS_INVALID_PARAMETER;
361 : }
362 :
363 5 : if ((flags & DS_IP_REQUIRED) &&
364 0 : (info->dc_address_type != DS_ADDRESS_TYPE_INET)) {
365 0 : return NT_STATUS_INVALID_PARAMETER_MIX;
366 : }
367 :
368 5 : *info_p = info;
369 :
370 5 : return NT_STATUS_OK;
371 : }
372 :
373 : /****************************************************************
374 : ****************************************************************/
375 :
376 6 : static NTSTATUS dsgetdcname_cached(TALLOC_CTX *mem_ctx,
377 : struct messaging_context *msg_ctx,
378 : const char *domain_name,
379 : const struct GUID *domain_guid,
380 : uint32_t flags,
381 : const char *site_name,
382 : struct netr_DsRGetDCNameInfo **info)
383 : {
384 : NTSTATUS status;
385 :
386 6 : status = dsgetdcname_cache_fetch(mem_ctx, domain_name, domain_guid,
387 : flags, info);
388 6 : if (!NT_STATUS_IS_OK(status)
389 1 : && !NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
390 0 : DEBUG(10,("dsgetdcname_cached: cache fetch failed with: %s\n",
391 : nt_errstr(status)));
392 0 : return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
393 : }
394 :
395 6 : if (flags & DS_BACKGROUND_ONLY) {
396 0 : return status;
397 : }
398 :
399 6 : if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
400 : struct netr_DsRGetDCNameInfo *dc_info;
401 :
402 1 : status = dsgetdcname(mem_ctx, msg_ctx, domain_name,
403 : domain_guid, site_name,
404 : flags | DS_FORCE_REDISCOVERY,
405 : &dc_info);
406 :
407 1 : if (!NT_STATUS_IS_OK(status)) {
408 0 : return status;
409 : }
410 :
411 1 : *info = dc_info;
412 : }
413 :
414 6 : return status;
415 : }
416 :
417 : /****************************************************************
418 : ****************************************************************/
419 :
420 37 : static bool check_allowed_required_flags(uint32_t flags,
421 : const char *site_name)
422 : {
423 37 : uint32_t return_type = flags & (DS_RETURN_FLAT_NAME|DS_RETURN_DNS_NAME);
424 37 : uint32_t offered_type = flags & (DS_IS_FLAT_NAME|DS_IS_DNS_NAME);
425 37 : uint32_t query_type = flags & (DS_BACKGROUND_ONLY|DS_FORCE_REDISCOVERY);
426 :
427 : /* FIXME: check for DSGETDC_VALID_FLAGS and check for excluse bits
428 : * (DS_PDC_REQUIRED, DS_KDC_REQUIRED, DS_GC_SERVER_REQUIRED) */
429 :
430 37 : debug_dsdcinfo_flags(10, flags);
431 :
432 37 : if ((flags & DS_TRY_NEXTCLOSEST_SITE) && site_name) {
433 0 : return false;
434 : }
435 :
436 37 : if (return_type == (DS_RETURN_FLAT_NAME|DS_RETURN_DNS_NAME)) {
437 0 : return false;
438 : }
439 :
440 37 : if (offered_type == (DS_IS_DNS_NAME|DS_IS_FLAT_NAME)) {
441 0 : return false;
442 : }
443 :
444 37 : if (query_type == (DS_BACKGROUND_ONLY|DS_FORCE_REDISCOVERY)) {
445 0 : return false;
446 : }
447 :
448 : #if 0
449 : if ((flags & DS_RETURN_DNS_NAME) && (!(flags & DS_IP_REQUIRED))) {
450 : printf("gd: here5 \n");
451 : return false;
452 : }
453 : #endif
454 37 : return true;
455 : }
456 :
457 : /****************************************************************
458 : ****************************************************************/
459 :
460 4 : static NTSTATUS discover_dc_netbios(TALLOC_CTX *mem_ctx,
461 : const char *domain_name,
462 : uint32_t flags,
463 : struct ip_service_name **returned_dclist,
464 : size_t *returned_count)
465 : {
466 : NTSTATUS status;
467 4 : enum nbt_name_type name_type = NBT_NAME_LOGON;
468 4 : struct samba_sockaddr *salist = NULL;
469 : size_t i;
470 4 : struct ip_service_name *dclist = NULL;
471 4 : size_t count = 0;
472 : static const char *resolve_order[] = { "lmhosts", "wins", "bcast", NULL };
473 :
474 4 : if (flags & DS_PDC_REQUIRED) {
475 0 : name_type = NBT_NAME_PDC;
476 : }
477 :
478 4 : status = internal_resolve_name(mem_ctx,
479 : domain_name,
480 : name_type,
481 : NULL,
482 : &salist,
483 : &count,
484 : resolve_order);
485 4 : if (!NT_STATUS_IS_OK(status)) {
486 0 : NTSTATUS raw_status = status;
487 :
488 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
489 0 : status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
490 : }
491 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_ADDRESS)) {
492 0 : status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
493 : }
494 :
495 0 : DBG_DEBUG("failed to find DC for %s: %s => %s\n",
496 : domain_name,
497 : nt_errstr(raw_status),
498 : nt_errstr(status));
499 0 : return status;
500 : }
501 :
502 4 : dclist = talloc_zero_array(mem_ctx, struct ip_service_name, count);
503 4 : if (!dclist) {
504 0 : TALLOC_FREE(salist);
505 0 : return NT_STATUS_NO_MEMORY;
506 : }
507 :
508 8 : for (i=0; i<count; i++) {
509 : char addr[INET6_ADDRSTRLEN];
510 4 : struct ip_service_name *r = &dclist[i];
511 :
512 4 : print_sockaddr(addr, sizeof(addr),
513 4 : &salist[i].u.ss);
514 :
515 4 : r->sa = salist[i];
516 4 : r->hostname = talloc_strdup(mem_ctx, addr);
517 4 : if (!r->hostname) {
518 0 : TALLOC_FREE(salist);
519 0 : TALLOC_FREE(dclist);
520 0 : return NT_STATUS_NO_MEMORY;
521 : }
522 :
523 : }
524 :
525 4 : TALLOC_FREE(salist);
526 :
527 4 : *returned_dclist = dclist;
528 4 : *returned_count = count;
529 :
530 4 : return NT_STATUS_OK;
531 : }
532 :
533 : /****************************************************************
534 : ****************************************************************/
535 :
536 30 : static NTSTATUS discover_dc_dns(TALLOC_CTX *mem_ctx,
537 : const char *domain_name,
538 : const struct GUID *domain_guid,
539 : uint32_t flags,
540 : const char *site_name,
541 : struct ip_service_name **returned_dclist,
542 : size_t *return_count)
543 : {
544 : size_t i;
545 : NTSTATUS status;
546 30 : struct dns_rr_srv *dcs = NULL;
547 30 : size_t numdcs = 0;
548 30 : struct ip_service_name *dclist = NULL;
549 30 : size_t ret_count = 0;
550 30 : char *query = NULL;
551 :
552 30 : if (flags & DS_PDC_REQUIRED) {
553 0 : query = ads_dns_query_string_pdc(mem_ctx, domain_name);
554 30 : } else if (flags & DS_GC_SERVER_REQUIRED) {
555 0 : query = ads_dns_query_string_gcs(mem_ctx, domain_name);
556 30 : } else if (flags & DS_KDC_REQUIRED) {
557 0 : query = ads_dns_query_string_kdcs(mem_ctx, domain_name);
558 30 : } else if (flags & DS_DIRECTORY_SERVICE_REQUIRED) {
559 29 : query = ads_dns_query_string_dcs(mem_ctx, domain_name);
560 1 : } else if (domain_guid) {
561 0 : query = ads_dns_query_string_dcs_guid(
562 : mem_ctx, domain_guid, domain_name);
563 : } else {
564 1 : query = ads_dns_query_string_dcs(mem_ctx, domain_name);
565 : }
566 :
567 30 : if (query == NULL) {
568 0 : return NT_STATUS_NO_MEMORY;
569 : }
570 :
571 30 : status = ads_dns_query_srv(
572 : mem_ctx,
573 : lp_get_async_dns_timeout(),
574 : site_name,
575 : query,
576 : &dcs,
577 : &numdcs);
578 30 : TALLOC_FREE(query);
579 30 : if (!NT_STATUS_IS_OK(status)) {
580 3 : return status;
581 : }
582 :
583 27 : if (numdcs == 0) {
584 2 : TALLOC_FREE(dcs);
585 2 : return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
586 : }
587 :
588 : /* Check for integer wrap. */
589 25 : if (numdcs + numdcs < numdcs) {
590 0 : TALLOC_FREE(dcs);
591 0 : return NT_STATUS_INVALID_PARAMETER;
592 : }
593 :
594 : /*
595 : * We're only returning up to 2 addresses per
596 : * DC name, so just allocate size numdcs x 2.
597 : */
598 :
599 25 : dclist = talloc_zero_array(mem_ctx,
600 : struct ip_service_name,
601 : numdcs * 2);
602 25 : if (!dclist) {
603 0 : TALLOC_FREE(dcs);
604 0 : return NT_STATUS_NO_MEMORY;
605 : }
606 :
607 : /*
608 : * First, copy the SRV record replies that
609 : * have IP addresses returned with them.
610 : */
611 25 : ret_count = 0;
612 50 : for (i = 0; i < numdcs; i++) {
613 : size_t j;
614 25 : bool have_v4_addr = false;
615 25 : bool have_v6_addr = false;
616 :
617 25 : if (dcs[i].num_ips == 0) {
618 0 : continue;
619 : }
620 :
621 : /*
622 : * Pick up to 1 address from each address
623 : * family (IPv4, IPv6).
624 : *
625 : * This is different from the previous
626 : * code which picked a 'next ip' address
627 : * each time, incrementing an index.
628 : * Too complex to maintain :-(.
629 : */
630 50 : for (j = 0; j < dcs[i].num_ips; j++) {
631 65 : if ((dcs[i].ss_s[j].ss_family == AF_INET && !have_v4_addr) ||
632 40 : (dcs[i].ss_s[j].ss_family == AF_INET6 && !have_v6_addr)) {
633 : bool ok;
634 100 : dclist[ret_count].hostname =
635 80 : talloc_strdup(dclist, dcs[i].hostname);
636 50 : ok = sockaddr_storage_to_samba_sockaddr(
637 50 : &dclist[ret_count].sa,
638 50 : &dcs[i].ss_s[j]);
639 50 : if (!ok) {
640 0 : TALLOC_FREE(dcs);
641 0 : TALLOC_FREE(dclist);
642 0 : return NT_STATUS_INVALID_PARAMETER;
643 : }
644 50 : ret_count++;
645 50 : if (dcs[i].ss_s[j].ss_family == AF_INET) {
646 25 : have_v4_addr = true;
647 : } else {
648 25 : have_v6_addr = true;
649 : }
650 50 : if (have_v4_addr && have_v6_addr) {
651 25 : break;
652 : }
653 : }
654 : }
655 : }
656 :
657 25 : TALLOC_FREE(dcs);
658 :
659 25 : if (ret_count == 0) {
660 0 : TALLOC_FREE(dclist);
661 0 : return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
662 : }
663 :
664 25 : *returned_dclist = dclist;
665 25 : *return_count = ret_count;
666 25 : return NT_STATUS_OK;
667 : }
668 :
669 : /****************************************************************
670 : ****************************************************************/
671 :
672 34 : static NTSTATUS make_domain_controller_info(TALLOC_CTX *mem_ctx,
673 : const char *dc_unc,
674 : const char *dc_address,
675 : uint32_t dc_address_type,
676 : const struct GUID *domain_guid,
677 : const char *domain_name,
678 : const char *forest_name,
679 : uint32_t flags,
680 : const char *dc_site_name,
681 : const char *client_site_name,
682 : struct netr_DsRGetDCNameInfo **info_out)
683 : {
684 : struct netr_DsRGetDCNameInfo *info;
685 :
686 34 : info = talloc_zero(mem_ctx, struct netr_DsRGetDCNameInfo);
687 34 : NT_STATUS_HAVE_NO_MEMORY(info);
688 :
689 34 : if (dc_unc) {
690 34 : if (!(dc_unc[0] == '\\' && dc_unc[1] == '\\')) {
691 32 : info->dc_unc = talloc_asprintf(mem_ctx, "\\\\%s",
692 : dc_unc);
693 : } else {
694 2 : info->dc_unc = talloc_strdup(mem_ctx, dc_unc);
695 : }
696 34 : NT_STATUS_HAVE_NO_MEMORY(info->dc_unc);
697 : }
698 :
699 34 : if (dc_address) {
700 34 : if (!(dc_address[0] == '\\' && dc_address[1] == '\\')) {
701 34 : info->dc_address = talloc_asprintf(mem_ctx, "\\\\%s",
702 : dc_address);
703 : } else {
704 0 : info->dc_address = talloc_strdup(mem_ctx, dc_address);
705 : }
706 34 : NT_STATUS_HAVE_NO_MEMORY(info->dc_address);
707 : }
708 :
709 34 : info->dc_address_type = dc_address_type;
710 :
711 34 : if (domain_guid) {
712 34 : info->domain_guid = *domain_guid;
713 : }
714 :
715 34 : if (domain_name) {
716 34 : info->domain_name = talloc_strdup(mem_ctx, domain_name);
717 34 : NT_STATUS_HAVE_NO_MEMORY(info->domain_name);
718 : }
719 :
720 34 : if (forest_name && *forest_name) {
721 29 : info->forest_name = talloc_strdup(mem_ctx, forest_name);
722 29 : NT_STATUS_HAVE_NO_MEMORY(info->forest_name);
723 29 : flags |= DS_DNS_FOREST_ROOT;
724 : }
725 :
726 34 : info->dc_flags = flags;
727 :
728 34 : if (dc_site_name) {
729 30 : info->dc_site_name = talloc_strdup(mem_ctx, dc_site_name);
730 30 : NT_STATUS_HAVE_NO_MEMORY(info->dc_site_name);
731 : }
732 :
733 34 : if (client_site_name) {
734 30 : info->client_site_name = talloc_strdup(mem_ctx,
735 : client_site_name);
736 30 : NT_STATUS_HAVE_NO_MEMORY(info->client_site_name);
737 : }
738 :
739 34 : *info_out = info;
740 :
741 34 : return NT_STATUS_OK;
742 : }
743 :
744 : /****************************************************************
745 : ****************************************************************/
746 :
747 34 : static void map_dc_and_domain_names(uint32_t flags,
748 : const char *dc_name,
749 : const char *domain_name,
750 : const char *dns_dc_name,
751 : const char *dns_domain_name,
752 : uint32_t *dc_flags,
753 : const char **hostname_p,
754 : const char **domain_p)
755 : {
756 34 : switch (flags & 0xf0000000) {
757 0 : case DS_RETURN_FLAT_NAME:
758 0 : if (dc_name && domain_name &&
759 0 : *dc_name && *domain_name) {
760 0 : *hostname_p = dc_name;
761 0 : *domain_p = domain_name;
762 0 : break;
763 : }
764 :
765 : FALL_THROUGH;
766 : case DS_RETURN_DNS_NAME:
767 : default:
768 52 : if (dns_dc_name && dns_domain_name &&
769 47 : *dns_dc_name && *dns_domain_name) {
770 29 : *hostname_p = dns_dc_name;
771 29 : *domain_p = dns_domain_name;
772 29 : *dc_flags |= DS_DNS_DOMAIN | DS_DNS_CONTROLLER;
773 29 : break;
774 : }
775 9 : if (dc_name && domain_name &&
776 9 : *dc_name && *domain_name) {
777 5 : *hostname_p = dc_name;
778 5 : *domain_p = domain_name;
779 5 : break;
780 : }
781 : }
782 34 : }
783 :
784 : /****************************************************************
785 : ****************************************************************/
786 :
787 34 : static NTSTATUS make_dc_info_from_cldap_reply(
788 : TALLOC_CTX *mem_ctx,
789 : uint32_t flags,
790 : const struct samba_sockaddr *sa,
791 : struct NETLOGON_SAM_LOGON_RESPONSE_EX *r,
792 : struct netr_DsRGetDCNameInfo **info)
793 : {
794 34 : const char *dc_hostname = NULL;
795 34 : const char *dc_domain_name = NULL;
796 34 : const char *dc_address = NULL;
797 34 : const char *dc_forest = NULL;
798 34 : uint32_t dc_address_type = 0;
799 34 : uint32_t dc_flags = 0;
800 34 : struct GUID *dc_domain_guid = NULL;
801 34 : const char *dc_server_site = NULL;
802 34 : const char *dc_client_site = NULL;
803 :
804 : char addr[INET6_ADDRSTRLEN];
805 :
806 34 : if (sa != NULL) {
807 29 : print_sockaddr(addr, sizeof(addr), &sa->u.ss);
808 29 : dc_address = addr;
809 29 : dc_address_type = DS_ADDRESS_TYPE_INET;
810 : } else {
811 5 : if (r->sockaddr.pdc_ip) {
812 5 : dc_address = r->sockaddr.pdc_ip;
813 5 : dc_address_type = DS_ADDRESS_TYPE_INET;
814 : } else {
815 0 : dc_address = r->pdc_name;
816 0 : dc_address_type = DS_ADDRESS_TYPE_NETBIOS;
817 : }
818 : }
819 :
820 34 : map_dc_and_domain_names(flags,
821 : r->pdc_name,
822 : r->domain_name,
823 : r->pdc_dns_name,
824 : r->dns_domain,
825 : &dc_flags,
826 : &dc_hostname,
827 : &dc_domain_name);
828 :
829 34 : dc_flags |= r->server_type;
830 34 : dc_forest = r->forest;
831 34 : dc_domain_guid = &r->domain_uuid;
832 34 : dc_server_site = r->server_site;
833 34 : dc_client_site = r->client_site;
834 :
835 34 : return make_domain_controller_info(mem_ctx,
836 : dc_hostname,
837 : dc_address,
838 : dc_address_type,
839 : dc_domain_guid,
840 : dc_domain_name,
841 : dc_forest,
842 : dc_flags,
843 : dc_server_site,
844 : dc_client_site,
845 : info);
846 : }
847 :
848 : /****************************************************************
849 : ****************************************************************/
850 :
851 29 : static uint32_t map_ds_flags_to_nt_version(uint32_t flags)
852 : {
853 29 : uint32_t nt_version = 0;
854 :
855 29 : if (flags & DS_PDC_REQUIRED) {
856 0 : nt_version |= NETLOGON_NT_VERSION_PDC;
857 : }
858 :
859 29 : if (flags & DS_GC_SERVER_REQUIRED) {
860 0 : nt_version |= NETLOGON_NT_VERSION_GC;
861 : }
862 :
863 29 : if (flags & DS_TRY_NEXTCLOSEST_SITE) {
864 0 : nt_version |= NETLOGON_NT_VERSION_WITH_CLOSEST_SITE;
865 : }
866 :
867 29 : if (flags & DS_IP_REQUIRED) {
868 0 : nt_version |= NETLOGON_NT_VERSION_IP;
869 : }
870 :
871 29 : return nt_version;
872 : }
873 :
874 : /****************************************************************
875 : ****************************************************************/
876 :
877 25 : static NTSTATUS process_dc_dns(TALLOC_CTX *mem_ctx,
878 : const char *domain_name,
879 : uint32_t flags,
880 : struct ip_service_name *dclist,
881 : size_t num_dcs,
882 : struct netr_DsRGetDCNameInfo **info)
883 : {
884 25 : size_t i = 0;
885 25 : bool valid_dc = false;
886 25 : struct netlogon_samlogon_response *r = NULL;
887 25 : uint32_t nt_version = NETLOGON_NT_VERSION_5 |
888 : NETLOGON_NT_VERSION_5EX;
889 25 : uint32_t ret_flags = 0;
890 : NTSTATUS status;
891 :
892 25 : nt_version |= map_ds_flags_to_nt_version(flags);
893 :
894 25 : for (i=0; i<num_dcs; i++) {
895 : char addr[INET6_ADDRSTRLEN];
896 :
897 25 : print_sockaddr(addr, sizeof(addr), &dclist[i].sa.u.ss);
898 :
899 25 : DEBUG(10,("LDAP ping to %s (%s)\n", dclist[i].hostname, addr));
900 :
901 25 : if (ads_cldap_netlogon(mem_ctx, &dclist[i].sa.u.ss,
902 : domain_name,
903 : nt_version,
904 : &r))
905 : {
906 25 : nt_version = r->ntver;
907 25 : ret_flags = get_cldap_reply_server_flags(r, nt_version);
908 :
909 25 : if (check_cldap_reply_required_flags(ret_flags, flags)) {
910 25 : valid_dc = true;
911 25 : break;
912 : }
913 : }
914 :
915 0 : continue;
916 : }
917 :
918 25 : if (!valid_dc) {
919 0 : return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
920 : }
921 :
922 25 : status = make_dc_info_from_cldap_reply(mem_ctx, flags, &dclist[i].sa,
923 25 : &r->data.nt5_ex, info);
924 25 : if (NT_STATUS_IS_OK(status)) {
925 25 : return store_cldap_reply(mem_ctx, flags, &dclist[i].sa,
926 25 : nt_version, &r->data.nt5_ex);
927 : }
928 :
929 0 : return status;
930 : }
931 :
932 : /****************************************************************
933 : ****************************************************************/
934 :
935 : /****************************************************************
936 : ****************************************************************/
937 :
938 4 : static NTSTATUS process_dc_netbios(TALLOC_CTX *mem_ctx,
939 : struct messaging_context *msg_ctx,
940 : const char *domain_name,
941 : uint32_t flags,
942 : struct ip_service_name *dclist,
943 : size_t num_dcs,
944 : struct netr_DsRGetDCNameInfo **info)
945 4 : {
946 4 : enum nbt_name_type name_type = NBT_NAME_LOGON;
947 : NTSTATUS status;
948 : size_t i;
949 4 : const char *dc_name = NULL;
950 : fstring tmp_dc_name;
951 4 : struct netlogon_samlogon_response *r = NULL;
952 4 : bool store_cache = false;
953 4 : uint32_t nt_version = NETLOGON_NT_VERSION_1 |
954 : NETLOGON_NT_VERSION_5 |
955 : NETLOGON_NT_VERSION_5EX_WITH_IP;
956 4 : size_t len = strlen(lp_netbios_name());
957 4 : char my_acct_name[len+2];
958 :
959 4 : if (msg_ctx == NULL) {
960 0 : return NT_STATUS_INVALID_PARAMETER;
961 : }
962 :
963 4 : if (flags & DS_PDC_REQUIRED) {
964 0 : name_type = NBT_NAME_PDC;
965 : }
966 :
967 : /*
968 : * It's 2024 we always want an AD style response!
969 : */
970 4 : nt_version |= NETLOGON_NT_VERSION_AVOID_NT4EMUL;
971 :
972 4 : nt_version |= map_ds_flags_to_nt_version(flags);
973 :
974 4 : snprintf(my_acct_name,
975 : sizeof(my_acct_name),
976 : "%s$",
977 : lp_netbios_name());
978 :
979 4 : DEBUG(10,("process_dc_netbios\n"));
980 :
981 7 : for (i=0; i<num_dcs; i++) {
982 : uint16_t val;
983 :
984 4 : generate_random_buffer((uint8_t *)&val, 2);
985 :
986 4 : status = nbt_getdc(msg_ctx, 10, &dclist[i].sa.u.ss, domain_name,
987 : NULL, my_acct_name, ACB_WSTRUST, nt_version,
988 : mem_ctx, &nt_version, &dc_name, &r);
989 4 : if (NT_STATUS_IS_OK(status)) {
990 1 : store_cache = true;
991 1 : namecache_store(dc_name,
992 : NBT_NAME_SERVER,
993 : 1,
994 1 : &dclist[i].sa);
995 2 : goto make_reply;
996 : }
997 :
998 3 : if (name_status_find(domain_name,
999 : name_type,
1000 : NBT_NAME_SERVER,
1001 3 : &dclist[i].sa.u.ss,
1002 : tmp_dc_name))
1003 : {
1004 : struct NETLOGON_SAM_LOGON_RESPONSE_NT40 logon1;
1005 :
1006 3 : r = talloc_zero(mem_ctx, struct netlogon_samlogon_response);
1007 3 : NT_STATUS_HAVE_NO_MEMORY(r);
1008 :
1009 3 : ZERO_STRUCT(logon1);
1010 :
1011 3 : nt_version = NETLOGON_NT_VERSION_1;
1012 :
1013 3 : logon1.nt_version = nt_version;
1014 3 : logon1.pdc_name = tmp_dc_name;
1015 3 : logon1.domain_name = talloc_strdup_upper(mem_ctx, domain_name);
1016 3 : NT_STATUS_HAVE_NO_MEMORY(logon1.domain_name);
1017 :
1018 3 : r->data.nt4 = logon1;
1019 3 : r->ntver = nt_version;
1020 :
1021 3 : map_netlogon_samlogon_response(r);
1022 :
1023 3 : namecache_store(tmp_dc_name,
1024 : NBT_NAME_SERVER,
1025 : 1,
1026 3 : &dclist[i].sa);
1027 :
1028 3 : goto make_reply;
1029 : }
1030 : }
1031 :
1032 0 : return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
1033 :
1034 4 : make_reply:
1035 :
1036 4 : status = make_dc_info_from_cldap_reply(mem_ctx, flags, &dclist[i].sa,
1037 4 : &r->data.nt5_ex, info);
1038 4 : if (NT_STATUS_IS_OK(status) && store_cache) {
1039 1 : return store_cldap_reply(mem_ctx, flags, &dclist[i].sa,
1040 1 : nt_version, &r->data.nt5_ex);
1041 : }
1042 :
1043 3 : return status;
1044 : }
1045 :
1046 : /****************************************************************
1047 : ****************************************************************/
1048 :
1049 31 : static NTSTATUS dsgetdcname_rediscover(TALLOC_CTX *mem_ctx,
1050 : struct messaging_context *msg_ctx,
1051 : const char *domain_name,
1052 : const struct GUID *domain_guid,
1053 : uint32_t flags,
1054 : const char *site_name,
1055 : struct netr_DsRGetDCNameInfo **info)
1056 : {
1057 : NTSTATUS status;
1058 31 : struct ip_service_name *dclist = NULL;
1059 31 : size_t num_dcs = 0;
1060 :
1061 31 : DEBUG(10,("dsgetdcname_rediscover\n"));
1062 :
1063 31 : if (flags & DS_IS_FLAT_NAME) {
1064 :
1065 1 : if (lp_disable_netbios()) {
1066 0 : return NT_STATUS_NOT_SUPPORTED;
1067 : }
1068 :
1069 1 : status = discover_dc_netbios(mem_ctx, domain_name, flags,
1070 : &dclist, &num_dcs);
1071 1 : NT_STATUS_NOT_OK_RETURN(status);
1072 :
1073 1 : return process_dc_netbios(mem_ctx, msg_ctx, domain_name, flags,
1074 : dclist, num_dcs, info);
1075 : }
1076 :
1077 30 : if (flags & DS_IS_DNS_NAME) {
1078 :
1079 27 : status = discover_dc_dns(mem_ctx, domain_name, domain_guid,
1080 : flags, site_name, &dclist, &num_dcs);
1081 27 : NT_STATUS_NOT_OK_RETURN(status);
1082 :
1083 25 : return process_dc_dns(mem_ctx, domain_name, flags,
1084 : dclist, num_dcs, info);
1085 : }
1086 :
1087 3 : status = discover_dc_dns(mem_ctx, domain_name, domain_guid, flags,
1088 : site_name, &dclist, &num_dcs);
1089 :
1090 3 : if (NT_STATUS_IS_OK(status) && num_dcs != 0) {
1091 :
1092 0 : status = process_dc_dns(mem_ctx, domain_name, flags, dclist,
1093 : num_dcs, info);
1094 0 : if (NT_STATUS_IS_OK(status)) {
1095 0 : return status;
1096 : }
1097 : }
1098 :
1099 3 : if (lp_disable_netbios()) {
1100 0 : return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
1101 : }
1102 :
1103 3 : status = discover_dc_netbios(mem_ctx, domain_name, flags, &dclist,
1104 : &num_dcs);
1105 3 : NT_STATUS_NOT_OK_RETURN(status);
1106 :
1107 3 : return process_dc_netbios(mem_ctx, msg_ctx, domain_name, flags, dclist,
1108 : num_dcs, info);
1109 : }
1110 :
1111 35 : static bool is_closest_site(struct netr_DsRGetDCNameInfo *info)
1112 : {
1113 35 : if (info->dc_flags & DS_SERVER_CLOSEST) {
1114 29 : return true;
1115 : }
1116 :
1117 6 : if (!info->client_site_name) {
1118 5 : return true;
1119 : }
1120 :
1121 1 : if (!info->dc_site_name) {
1122 0 : return false;
1123 : }
1124 :
1125 1 : if (strcmp(info->client_site_name, info->dc_site_name) == 0) {
1126 1 : return true;
1127 : }
1128 :
1129 0 : return false;
1130 : }
1131 :
1132 : /********************************************************************
1133 : Internal dsgetdcname.
1134 : ********************************************************************/
1135 :
1136 37 : static NTSTATUS dsgetdcname_internal(TALLOC_CTX *mem_ctx,
1137 : struct messaging_context *msg_ctx,
1138 : const char *domain_name,
1139 : const struct GUID *domain_guid,
1140 : const char *site_name,
1141 : uint32_t flags,
1142 : struct netr_DsRGetDCNameInfo **info)
1143 : {
1144 : NTSTATUS status;
1145 37 : struct netr_DsRGetDCNameInfo *myinfo = NULL;
1146 37 : bool first = true;
1147 37 : struct netr_DsRGetDCNameInfo *first_info = NULL;
1148 :
1149 37 : DEBUG(10,("dsgetdcname_internal: domain_name: %s, "
1150 : "domain_guid: %s, site_name: %s, flags: 0x%08x\n",
1151 : domain_name,
1152 : domain_guid ? GUID_string(mem_ctx, domain_guid) : "(null)",
1153 : site_name ? site_name : "(null)", flags));
1154 :
1155 37 : *info = NULL;
1156 :
1157 37 : if (!check_allowed_required_flags(flags, site_name)) {
1158 0 : DEBUG(0,("invalid flags specified\n"));
1159 0 : return NT_STATUS_INVALID_PARAMETER;
1160 : }
1161 :
1162 37 : if (flags & DS_FORCE_REDISCOVERY) {
1163 31 : goto rediscover;
1164 : }
1165 :
1166 6 : status = dsgetdcname_cached(mem_ctx, msg_ctx, domain_name, domain_guid,
1167 : flags, site_name, &myinfo);
1168 6 : if (NT_STATUS_IS_OK(status)) {
1169 6 : *info = myinfo;
1170 6 : goto done;
1171 : }
1172 :
1173 0 : if (flags & DS_BACKGROUND_ONLY) {
1174 0 : goto done;
1175 : }
1176 :
1177 0 : rediscover:
1178 31 : status = dsgetdcname_rediscover(mem_ctx, msg_ctx, domain_name,
1179 : domain_guid, flags, site_name,
1180 : &myinfo);
1181 :
1182 37 : done:
1183 37 : if (!NT_STATUS_IS_OK(status)) {
1184 2 : if (!first) {
1185 0 : *info = first_info;
1186 0 : return NT_STATUS_OK;
1187 : }
1188 2 : return status;
1189 : }
1190 :
1191 35 : if (!first) {
1192 0 : TALLOC_FREE(first_info);
1193 35 : } else if (!is_closest_site(myinfo)) {
1194 0 : first = false;
1195 0 : first_info = myinfo;
1196 : /* TODO: may use the next_closest_site here */
1197 0 : site_name = myinfo->client_site_name;
1198 0 : goto rediscover;
1199 : }
1200 :
1201 35 : *info = myinfo;
1202 35 : return NT_STATUS_OK;
1203 : }
1204 :
1205 : /********************************************************************
1206 : dsgetdcname.
1207 :
1208 : This will be the only public function here.
1209 : ********************************************************************/
1210 :
1211 36 : NTSTATUS dsgetdcname(TALLOC_CTX *mem_ctx,
1212 : struct messaging_context *msg_ctx,
1213 : const char *domain_name,
1214 : const struct GUID *domain_guid,
1215 : const char *site_name,
1216 : uint32_t flags,
1217 : struct netr_DsRGetDCNameInfo **info)
1218 : {
1219 : NTSTATUS status;
1220 36 : const char *query_site = NULL;
1221 36 : char *ptr_to_free = NULL;
1222 36 : bool retry_query_with_null = false;
1223 :
1224 36 : if ((site_name == NULL) || (site_name[0] == '\0')) {
1225 36 : ptr_to_free = sitename_fetch(mem_ctx, domain_name);
1226 36 : if (ptr_to_free != NULL) {
1227 30 : retry_query_with_null = true;
1228 : }
1229 36 : query_site = ptr_to_free;
1230 : } else {
1231 0 : query_site = site_name;
1232 : }
1233 :
1234 36 : status = dsgetdcname_internal(mem_ctx,
1235 : msg_ctx,
1236 : domain_name,
1237 : domain_guid,
1238 : query_site,
1239 : flags,
1240 : info);
1241 :
1242 36 : TALLOC_FREE(ptr_to_free);
1243 :
1244 36 : if (!NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1245 35 : return status;
1246 : }
1247 :
1248 : /* Should we try again with site_name == NULL ? */
1249 1 : if (retry_query_with_null) {
1250 1 : status = dsgetdcname_internal(mem_ctx,
1251 : msg_ctx,
1252 : domain_name,
1253 : domain_guid,
1254 : NULL,
1255 : flags,
1256 : info);
1257 : }
1258 :
1259 1 : return status;
1260 : }
1261 :
1262 0 : NTSTATUS dsgetonedcname(TALLOC_CTX *mem_ctx,
1263 : struct messaging_context *msg_ctx,
1264 : const char *domain_name,
1265 : const char *dcname,
1266 : uint32_t flags,
1267 : struct netr_DsRGetDCNameInfo **info)
1268 : {
1269 : NTSTATUS status;
1270 : struct sockaddr_storage *addrs;
1271 : unsigned int num_addrs, i;
1272 0 : const char *hostname = strip_hostname(dcname);
1273 :
1274 0 : status = resolve_name_list(mem_ctx, hostname, 0x20,
1275 : &addrs, &num_addrs);
1276 0 : if (!NT_STATUS_IS_OK(status)) {
1277 0 : return status;
1278 : }
1279 :
1280 0 : for (i = 0; i < num_addrs; i++) {
1281 :
1282 : bool ok;
1283 : struct ip_service_name dclist;
1284 :
1285 0 : dclist.hostname = hostname;
1286 0 : ok = sockaddr_storage_to_samba_sockaddr(&dclist.sa, &addrs[i]);
1287 0 : if (!ok) {
1288 0 : TALLOC_FREE(addrs);
1289 0 : return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
1290 : }
1291 :
1292 0 : status = process_dc_dns(mem_ctx, domain_name, flags,
1293 : &dclist, 1, info);
1294 0 : if (NT_STATUS_IS_OK(status)) {
1295 0 : TALLOC_FREE(addrs);
1296 0 : return NT_STATUS_OK;
1297 : }
1298 :
1299 0 : if (lp_disable_netbios()) {
1300 0 : continue;
1301 : }
1302 :
1303 0 : status = process_dc_netbios(mem_ctx, msg_ctx, domain_name, flags,
1304 : &dclist, 1, info);
1305 0 : if (NT_STATUS_IS_OK(status)) {
1306 0 : TALLOC_FREE(addrs);
1307 0 : return NT_STATUS_OK;
1308 : }
1309 : }
1310 :
1311 0 : TALLOC_FREE(addrs);
1312 0 : return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
1313 : }
|