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