Coverage Report

Created: 2025-12-31 06:20

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