~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source3/libsmb/dsgetdcname.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

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