bc9f4b92c86394699892acf5d5278914ed718427
[gd/samba/.git] / source / libsmb / dsgetdcname.c
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 /****************************************************************
36 ****************************************************************/
37
38 void debug_dsdcinfo_flags(int lvl, uint32_t flags)
39 {
40         DEBUG(lvl,("debug_dsdcinfo_flags: 0x%08x\n\t", flags));
41
42         if (flags & DS_FORCE_REDISCOVERY)
43                 DEBUGADD(lvl,("DS_FORCE_REDISCOVERY "));
44         if (flags & 0x000000002)
45                 DEBUGADD(lvl,("0x00000002 "));
46         if (flags & 0x000000004)
47                 DEBUGADD(lvl,("0x00000004 "));
48         if (flags & 0x000000008)
49                 DEBUGADD(lvl,("0x00000008 "));
50         if (flags & DS_DIRECTORY_SERVICE_REQUIRED)
51                 DEBUGADD(lvl,("DS_DIRECTORY_SERVICE_REQUIRED "));
52         if (flags & DS_DIRECTORY_SERVICE_PREFERRED)
53                 DEBUGADD(lvl,("DS_DIRECTORY_SERVICE_PREFERRED "));
54         if (flags & DS_GC_SERVER_REQUIRED)
55                 DEBUGADD(lvl,("DS_GC_SERVER_REQUIRED "));
56         if (flags & DS_PDC_REQUIRED)
57                 DEBUGADD(lvl,("DS_PDC_REQUIRED "));
58         if (flags & DS_BACKGROUND_ONLY)
59                 DEBUGADD(lvl,("DS_BACKGROUND_ONLY "));
60         if (flags & DS_IP_REQUIRED)
61                 DEBUGADD(lvl,("DS_IP_REQUIRED "));
62         if (flags & DS_KDC_REQUIRED)
63                 DEBUGADD(lvl,("DS_KDC_REQUIRED "));
64         if (flags & DS_TIMESERV_REQUIRED)
65                 DEBUGADD(lvl,("DS_TIMESERV_REQUIRED "));
66         if (flags & DS_WRITABLE_REQUIRED)
67                 DEBUGADD(lvl,("DS_WRITABLE_REQUIRED "));
68         if (flags & DS_GOOD_TIMESERV_PREFERRED)
69                 DEBUGADD(lvl,("DS_GOOD_TIMESERV_PREFERRED "));
70         if (flags & DS_AVOID_SELF)
71                 DEBUGADD(lvl,("DS_AVOID_SELF "));
72         if (flags & DS_ONLY_LDAP_NEEDED)
73                 DEBUGADD(lvl,("DS_ONLY_LDAP_NEEDED "));
74         if (flags & DS_IS_FLAT_NAME)
75                 DEBUGADD(lvl,("DS_IS_FLAT_NAME "));
76         if (flags & DS_IS_DNS_NAME)
77                 DEBUGADD(lvl,("DS_IS_DNS_NAME "));
78         if (flags & 0x00040000)
79                 DEBUGADD(lvl,("0x00040000 "));
80         if (flags & 0x00080000)
81                 DEBUGADD(lvl,("0x00080000 "));
82         if (flags & 0x00100000)
83                 DEBUGADD(lvl,("0x00100000 "));
84         if (flags & 0x00200000)
85                 DEBUGADD(lvl,("0x00200000 "));
86         if (flags & 0x00400000)
87                 DEBUGADD(lvl,("0x00400000 "));
88         if (flags & 0x00800000)
89                 DEBUGADD(lvl,("0x00800000 "));
90         if (flags & 0x01000000)
91                 DEBUGADD(lvl,("0x01000000 "));
92         if (flags & 0x02000000)
93                 DEBUGADD(lvl,("0x02000000 "));
94         if (flags & 0x04000000)
95                 DEBUGADD(lvl,("0x04000000 "));
96         if (flags & 0x08000000)
97                 DEBUGADD(lvl,("0x08000000 "));
98         if (flags & 0x10000000)
99                 DEBUGADD(lvl,("0x10000000 "));
100         if (flags & 0x20000000)
101                 DEBUGADD(lvl,("0x20000000 "));
102         if (flags & DS_RETURN_DNS_NAME)
103                 DEBUGADD(lvl,("DS_RETURN_DNS_NAME "));
104         if (flags & DS_RETURN_FLAT_NAME)
105                 DEBUGADD(lvl,("DS_RETURN_FLAT_NAME "));
106         if (flags)
107                 DEBUGADD(lvl,("\n"));
108 }
109
110 /*********************************************************************
111  ********************************************************************/
112
113 static int pack_dsdcinfo(struct netr_DsRGetDCNameInfo *info,
114                          unsigned char **buf)
115 {
116         unsigned char *buffer = NULL;
117         int len = 0;
118         int buflen = 0;
119         UUID_FLAT guid_flat;
120
121         DEBUG(10,("pack_dsdcinfo: Packing dsdcinfo\n"));
122
123         ZERO_STRUCT(guid_flat);
124
125         if (!GUID_all_zero(&info->domain_guid)) {
126                 smb_uuid_pack(info->domain_guid, &guid_flat);
127         }
128
129  again:
130         len = 0;
131
132         if (buflen > 0) {
133                 DEBUG(10,("pack_dsdcinfo: Packing domain %s (%s)\n",
134                           info->domain_name, info->dc_unc));
135         }
136
137         len += tdb_pack(buffer+len, buflen-len, "ffdBffdff",
138                         info->dc_unc,
139                         info->dc_address,
140                         info->dc_address_type,
141                         UUID_FLAT_SIZE, guid_flat.info,
142                         info->domain_name,
143                         info->forest_name,
144                         info->dc_flags,
145                         info->dc_site_name,
146                         info->client_site_name);
147
148         if (buflen < len) {
149                 SAFE_FREE(buffer);
150                 if ((buffer = SMB_MALLOC_ARRAY(unsigned char, len)) == NULL ) {
151                         DEBUG(0,("pack_dsdcinfo: failed to alloc buffer!\n"));
152                         buflen = -1;
153                         goto done;
154                 }
155                 buflen = len;
156                 goto again;
157         }
158
159         *buf = buffer;
160
161  done:
162         return buflen;
163 }
164
165 /*********************************************************************
166  ********************************************************************/
167
168 static NTSTATUS unpack_dsdcinfo(TALLOC_CTX *mem_ctx,
169                                 unsigned char *buf,
170                                 int buflen,
171                                 struct netr_DsRGetDCNameInfo **info_ret)
172 {
173         int len = 0;
174         struct netr_DsRGetDCNameInfo *info = NULL;
175         uint32_t guid_len = 0;
176         unsigned char *guid_buf = NULL;
177         UUID_FLAT guid_flat;
178
179         /* forgive me 6 times */
180         fstring dc_unc;
181         fstring dc_address;
182         fstring domain_name;
183         fstring forest_name;
184         fstring dc_site_name;
185         fstring client_site_name;
186
187         info = TALLOC_ZERO_P(mem_ctx, struct netr_DsRGetDCNameInfo);
188         NT_STATUS_HAVE_NO_MEMORY(info);
189
190         len += tdb_unpack(buf+len, buflen-len, "ffdBffdff",
191                           &dc_unc,
192                           &dc_address,
193                           &info->dc_address_type,
194                           &guid_len, &guid_buf,
195                           &domain_name,
196                           &forest_name,
197                           &info->dc_flags,
198                           &dc_site_name,
199                           &client_site_name);
200         if (len == -1) {
201                 DEBUG(5,("unpack_dsdcinfo: Failed to unpack domain\n"));
202                 goto failed;
203         }
204
205         info->dc_unc =
206                 talloc_strdup(mem_ctx, dc_unc);
207         info->dc_address =
208                 talloc_strdup(mem_ctx, dc_address);
209         info->domain_name =
210                 talloc_strdup(mem_ctx, domain_name);
211         info->forest_name =
212                 talloc_strdup(mem_ctx, forest_name);
213         info->dc_site_name =
214                 talloc_strdup(mem_ctx, dc_site_name);
215         info->client_site_name =
216                 talloc_strdup(mem_ctx, client_site_name);
217
218         if (!info->dc_unc ||
219             !info->dc_address ||
220             !info->domain_name ||
221             !info->forest_name ||
222             !info->dc_site_name ||
223             !info->client_site_name) {
224                 goto failed;
225         }
226
227         if (guid_len > 0) {
228                 struct GUID guid;
229
230                 if (guid_len != UUID_FLAT_SIZE) {
231                         goto failed;
232                 }
233
234                 memcpy(&guid_flat.info, guid_buf, guid_len);
235                 smb_uuid_unpack(guid_flat, &guid);
236
237                 info->domain_guid = guid;
238                 SAFE_FREE(guid_buf);
239         }
240
241         DEBUG(10,("unpack_dcscinfo: Unpacked domain %s (%s)\n",
242                   info->domain_name, info->dc_unc));
243
244         *info_ret = info;
245
246         return NT_STATUS_OK;
247
248  failed:
249         TALLOC_FREE(info);
250         SAFE_FREE(guid_buf);
251         return NT_STATUS_NO_MEMORY;
252 }
253
254 /****************************************************************
255 ****************************************************************/
256
257 static char *dsgetdcname_cache_key(TALLOC_CTX *mem_ctx, const char *domain)
258 {
259         if (!mem_ctx || !domain) {
260                 return NULL;
261         }
262
263         return talloc_asprintf_strupper_m(mem_ctx, DSGETDCNAME_FMT, domain);
264 }
265
266 /****************************************************************
267 ****************************************************************/
268
269 static NTSTATUS dsgetdcname_cache_delete(TALLOC_CTX *mem_ctx,
270                                         const char *domain_name)
271 {
272         char *key;
273
274         if (!gencache_init()) {
275                 return NT_STATUS_INTERNAL_DB_ERROR;
276         }
277
278         key = dsgetdcname_cache_key(mem_ctx, domain_name);
279         if (!key) {
280                 return NT_STATUS_NO_MEMORY;
281         }
282
283         if (!gencache_del(key)) {
284                 return NT_STATUS_UNSUCCESSFUL;
285         }
286
287         return NT_STATUS_OK;
288 }
289
290 /****************************************************************
291 ****************************************************************/
292
293 static NTSTATUS dsgetdcname_cache_store(TALLOC_CTX *mem_ctx,
294                                         const char *domain_name,
295                                         struct netr_DsRGetDCNameInfo *info)
296 {
297         time_t expire_time;
298         char *key;
299         bool ret = false;
300         DATA_BLOB blob;
301         unsigned char *buf = NULL;
302         int len = 0;
303
304         if (!gencache_init()) {
305                 return NT_STATUS_INTERNAL_DB_ERROR;
306         }
307
308         key = dsgetdcname_cache_key(mem_ctx, domain_name);
309         if (!key) {
310                 return NT_STATUS_NO_MEMORY;
311         }
312
313         expire_time = time(NULL) + DSGETDCNAME_CACHE_TTL;
314
315         len = pack_dsdcinfo(info, &buf);
316         if (len == -1) {
317                 return NT_STATUS_UNSUCCESSFUL;
318         }
319
320         blob = data_blob(buf, len);
321         SAFE_FREE(buf);
322
323         if (gencache_lock_entry(key) != 0) {
324                 data_blob_free(&blob);
325                 return NT_STATUS_LOCK_NOT_GRANTED;
326         }
327
328         ret = gencache_set_data_blob(key, &blob, expire_time);
329         data_blob_free(&blob);
330
331         gencache_unlock_entry(key);
332
333         return ret ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
334 }
335
336 /****************************************************************
337 ****************************************************************/
338
339 static NTSTATUS dsgetdcname_cache_refresh(TALLOC_CTX *mem_ctx,
340                                           const char *domain_name,
341                                           struct GUID *domain_guid,
342                                           uint32_t flags,
343                                           const char *site_name,
344                                           struct netr_DsRGetDCNameInfo *info)
345 {
346         struct cldap_netlogon_reply r;
347
348         /* check if matching entry is older then 15 minutes, if yes, send
349          * CLDAP/MAILSLOT ping again and store the cached data */
350
351         ZERO_STRUCT(r);
352
353         if (ads_cldap_netlogon(info->dc_unc,
354                                info->domain_name, &r)) {
355
356                 dsgetdcname_cache_delete(mem_ctx, domain_name);
357
358                 return dsgetdcname_cache_store(mem_ctx,
359                                                info->domain_name,
360                                                info);
361         }
362
363         return NT_STATUS_INVALID_NETWORK_RESPONSE;
364 }
365
366 /****************************************************************
367 ****************************************************************/
368
369 #define RETURN_ON_FALSE(x) if (!x) return false;
370
371 static bool check_cldap_reply_required_flags(uint32_t ret_flags,
372                                              uint32_t req_flags)
373 {
374         if (req_flags & DS_PDC_REQUIRED)
375                 RETURN_ON_FALSE(ret_flags & ADS_PDC);
376
377         if (req_flags & DS_GC_SERVER_REQUIRED)
378                 RETURN_ON_FALSE(ret_flags & ADS_GC);
379
380         if (req_flags & DS_ONLY_LDAP_NEEDED)
381                 RETURN_ON_FALSE(ret_flags & ADS_LDAP);
382
383         if ((req_flags & DS_DIRECTORY_SERVICE_REQUIRED) ||
384             (req_flags & DS_DIRECTORY_SERVICE_PREFERRED))
385                 RETURN_ON_FALSE(ret_flags & ADS_DS);
386
387         if (req_flags & DS_KDC_REQUIRED)
388                 RETURN_ON_FALSE(ret_flags & ADS_KDC);
389
390         if (req_flags & DS_TIMESERV_REQUIRED)
391                 RETURN_ON_FALSE(ret_flags & ADS_TIMESERV);
392
393         if (req_flags & DS_WRITABLE_REQUIRED)
394                 RETURN_ON_FALSE(ret_flags & ADS_WRITABLE);
395
396         return true;
397 }
398
399 /****************************************************************
400 ****************************************************************/
401
402 static NTSTATUS dsgetdcname_cache_fetch(TALLOC_CTX *mem_ctx,
403                                         const char *domain_name,
404                                         struct GUID *domain_guid,
405                                         uint32_t flags,
406                                         const char *site_name,
407                                         struct netr_DsRGetDCNameInfo **info,
408                                         bool *expired)
409 {
410         char *key;
411         DATA_BLOB blob;
412         NTSTATUS status;
413
414         if (!gencache_init()) {
415                 return NT_STATUS_INTERNAL_DB_ERROR;
416         }
417
418         key = dsgetdcname_cache_key(mem_ctx, domain_name);
419         if (!key) {
420                 return NT_STATUS_NO_MEMORY;
421         }
422
423         if (!gencache_get_data_blob(key, &blob, expired)) {
424                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
425         }
426
427         status = unpack_dsdcinfo(mem_ctx, blob.data, blob.length, info);
428         if (!NT_STATUS_IS_OK(status)) {
429                 data_blob_free(&blob);
430                 return status;
431         }
432
433         data_blob_free(&blob);
434
435         /* check flags */
436         if (!check_cldap_reply_required_flags((*info)->dc_flags, flags)) {
437                 DEBUG(10,("invalid flags\n"));
438                 return NT_STATUS_INVALID_PARAMETER;
439         }
440
441         if ((flags & DS_IP_REQUIRED) &&
442             ((*info)->dc_address_type != DS_ADDRESS_TYPE_INET)) {
443                 return NT_STATUS_INVALID_PARAMETER_MIX;
444         }
445
446         return NT_STATUS_OK;
447 }
448
449 /****************************************************************
450 ****************************************************************/
451
452 static NTSTATUS dsgetdcname_cached(TALLOC_CTX *mem_ctx,
453                                    const char *domain_name,
454                                    struct GUID *domain_guid,
455                                    uint32_t flags,
456                                    const char *site_name,
457                                    struct netr_DsRGetDCNameInfo **info)
458 {
459         NTSTATUS status;
460         bool expired = false;
461
462         status = dsgetdcname_cache_fetch(mem_ctx, domain_name, domain_guid,
463                                          flags, site_name, info, &expired);
464         if (!NT_STATUS_IS_OK(status)) {
465                 DEBUG(10,("dsgetdcname_cached: cache fetch failed with: %s\n",
466                         nt_errstr(status)));
467                 return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
468         }
469
470         if (flags & DS_BACKGROUND_ONLY) {
471                 return status;
472         }
473
474         if (expired) {
475                 status = dsgetdcname_cache_refresh(mem_ctx, domain_name,
476                                                    domain_guid, flags,
477                                                    site_name, *info);
478                 if (!NT_STATUS_IS_OK(status)) {
479                         return status;
480                 }
481         }
482
483         return status;
484 }
485
486 /****************************************************************
487 ****************************************************************/
488
489 static bool check_allowed_required_flags(uint32_t flags)
490 {
491         uint32_t return_type = flags & (DS_RETURN_FLAT_NAME|DS_RETURN_DNS_NAME);
492         uint32_t offered_type = flags & (DS_IS_FLAT_NAME|DS_IS_DNS_NAME);
493         uint32_t query_type = flags & (DS_BACKGROUND_ONLY|DS_FORCE_REDISCOVERY);
494
495         /* FIXME: check for DSGETDC_VALID_FLAGS and check for excluse bits
496          * (DS_PDC_REQUIRED, DS_KDC_REQUIRED, DS_GC_SERVER_REQUIRED) */
497
498         debug_dsdcinfo_flags(10, flags);
499
500         if (return_type == (DS_RETURN_FLAT_NAME|DS_RETURN_DNS_NAME)) {
501                 return false;
502         }
503
504         if (offered_type == (DS_IS_DNS_NAME|DS_IS_FLAT_NAME)) {
505                 return false;
506         }
507
508         if (query_type == (DS_BACKGROUND_ONLY|DS_FORCE_REDISCOVERY)) {
509                 return false;
510         }
511
512 #if 0
513         if ((flags & DS_RETURN_DNS_NAME) && (!(flags & DS_IP_REQUIRED))) {
514                 printf("gd: here5 \n");
515                 return false;
516         }
517 #endif
518         return true;
519 }
520
521 /****************************************************************
522 ****************************************************************/
523
524 static NTSTATUS discover_dc_netbios(TALLOC_CTX *mem_ctx,
525                                     const char *domain_name,
526                                     uint32_t flags,
527                                     struct ip_service_name **returned_dclist,
528                                     int *return_count)
529 {
530         if (lp_disable_netbios()) {
531                 return NT_STATUS_NOT_SUPPORTED;
532         }
533
534         /* FIXME: code here */
535
536         return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
537 }
538
539 /****************************************************************
540 ****************************************************************/
541
542 static NTSTATUS discover_dc_dns(TALLOC_CTX *mem_ctx,
543                                 const char *domain_name,
544                                 struct GUID *domain_guid,
545                                 uint32_t flags,
546                                 const char *site_name,
547                                 struct ip_service_name **returned_dclist,
548                                 int *return_count)
549 {
550         int i, j;
551         NTSTATUS status;
552         struct dns_rr_srv *dcs = NULL;
553         int numdcs = 0;
554         int numaddrs = 0;
555
556         if ((!(flags & DS_DIRECTORY_SERVICE_REQUIRED)) &&
557             (!(flags & DS_KDC_REQUIRED)) &&
558             (!(flags & DS_GC_SERVER_REQUIRED)) &&
559             (!(flags & DS_PDC_REQUIRED))) {
560                 DEBUG(1,("discover_dc_dns: invalid flags\n"));
561                 return NT_STATUS_INVALID_PARAMETER;
562         }
563
564         if (flags & DS_PDC_REQUIRED) {
565                 status = ads_dns_query_pdc(mem_ctx, domain_name,
566                                            &dcs, &numdcs);
567         } else if (flags & DS_GC_SERVER_REQUIRED) {
568                 status = ads_dns_query_gcs(mem_ctx, domain_name, site_name,
569                                            &dcs, &numdcs);
570         } else if (flags & DS_KDC_REQUIRED) {
571                 status = ads_dns_query_kdcs(mem_ctx, domain_name, site_name,
572                                             &dcs, &numdcs);
573         } else if (flags & DS_DIRECTORY_SERVICE_REQUIRED) {
574                 status = ads_dns_query_dcs(mem_ctx, domain_name, site_name,
575                                            &dcs, &numdcs);
576         } else if (domain_guid) {
577                 status = ads_dns_query_dcs_guid(mem_ctx, domain_name,
578                                                 domain_guid, &dcs, &numdcs);
579         } else {
580                 /* FIXME: ? */
581                 DEBUG(1,("discover_dc_dns: not enough input\n"));
582                 status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
583         }
584
585         if (!NT_STATUS_IS_OK(status)) {
586                 return status;
587         }
588
589         if (numdcs == 0) {
590                 return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
591         }
592
593         for (i=0;i<numdcs;i++) {
594                 numaddrs += MAX(dcs[i].num_ips,1);
595         }
596
597         if ((*returned_dclist = TALLOC_ZERO_ARRAY(mem_ctx,
598                                                   struct ip_service_name,
599                                                   numaddrs)) == NULL) {
600                 return NT_STATUS_NO_MEMORY;
601         }
602
603         /* now unroll the list of IP addresses */
604
605         *return_count = 0;
606         i = 0;
607         j = 0;
608         while (i < numdcs && (*return_count<numaddrs)) {
609
610                 struct ip_service_name *r = &(*returned_dclist)[*return_count];
611
612                 r->port = dcs[i].port;
613                 r->hostname = dcs[i].hostname;
614
615                 if (!(flags & DS_IP_REQUIRED)) {
616                         (*return_count)++;
617                         continue;
618                 }
619
620                 /* If we don't have an IP list for a name, lookup it up */
621
622                 if (!dcs[i].ss_s) {
623                         interpret_string_addr(&r->ss, dcs[i].hostname, 0);
624                         i++;
625                         j = 0;
626                 } else {
627                         /* use the IP addresses from the SRV sresponse */
628
629                         if (j >= dcs[i].num_ips) {
630                                 i++;
631                                 j = 0;
632                                 continue;
633                         }
634
635                         r->ss = dcs[i].ss_s[j];
636                         j++;
637                 }
638
639                 /* make sure it is a valid IP.  I considered checking the
640                  * negative connection cache, but this is the wrong place for
641                  * it.  Maybe only as a hac.  After think about it, if all of
642                  * the IP addresses retuend from DNS are dead, what hope does a
643                  * netbios name lookup have?  The standard reason for falling
644                  * back to netbios lookups is that our DNS server doesn't know
645                  * anything about the DC's   -- jerry */
646
647                 if (!is_zero_addr(&r->ss)) {
648                         (*return_count)++;
649                         continue;
650                 }
651         }
652
653         return (*return_count > 0) ? NT_STATUS_OK :
654                                      NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
655 }
656
657 /****************************************************************
658 ****************************************************************/
659
660 static NTSTATUS make_domain_controller_info(TALLOC_CTX *mem_ctx,
661                                             const char *dc_unc,
662                                             const char *dc_address,
663                                             uint32_t dc_address_type,
664                                             const struct GUID *domain_guid,
665                                             const char *domain_name,
666                                             const char *forest_name,
667                                             uint32_t flags,
668                                             const char *dc_site_name,
669                                             const char *client_site_name,
670                                             struct netr_DsRGetDCNameInfo **info_out)
671 {
672         struct netr_DsRGetDCNameInfo *info;
673
674         info = TALLOC_ZERO_P(mem_ctx, struct netr_DsRGetDCNameInfo);
675         NT_STATUS_HAVE_NO_MEMORY(info);
676
677         if (dc_unc) {
678                 info->dc_unc = talloc_strdup(mem_ctx, dc_unc);
679                 NT_STATUS_HAVE_NO_MEMORY(info->dc_unc);
680         }
681
682         if (dc_address) {
683                 info->dc_address = talloc_strdup(mem_ctx, dc_address);
684                 NT_STATUS_HAVE_NO_MEMORY(info->dc_address);
685         }
686
687         info->dc_address_type = dc_address_type;
688
689         if (domain_guid) {
690                 info->domain_guid = *domain_guid;
691         }
692
693         if (domain_name) {
694                 info->domain_name = talloc_strdup(mem_ctx, domain_name);
695                 NT_STATUS_HAVE_NO_MEMORY(info->domain_name);
696         }
697
698         if (forest_name) {
699                 info->forest_name = talloc_strdup(mem_ctx, forest_name);
700                 NT_STATUS_HAVE_NO_MEMORY(info->forest_name);
701         }
702
703         info->dc_flags = flags;
704
705         if (dc_site_name) {
706                 info->dc_site_name = talloc_strdup(mem_ctx, dc_site_name);
707                 NT_STATUS_HAVE_NO_MEMORY(info->dc_site_name);
708         }
709
710         if (client_site_name) {
711                 info->client_site_name = talloc_strdup(mem_ctx,
712                                                        client_site_name);
713                 NT_STATUS_HAVE_NO_MEMORY(info->client_site_name);
714         }
715
716         *info_out = info;
717
718         return NT_STATUS_OK;
719 }
720
721 /****************************************************************
722 ****************************************************************/
723
724 static NTSTATUS process_dc_dns(TALLOC_CTX *mem_ctx,
725                                const char *domain_name,
726                                uint32_t flags,
727                                struct ip_service_name **dclist,
728                                int num_dcs,
729                                struct netr_DsRGetDCNameInfo **info)
730 {
731         int i = 0;
732         bool valid_dc = false;
733         struct cldap_netlogon_reply r;
734         const char *dc_hostname, *dc_domain_name;
735         const char *dc_address;
736         uint32_t dc_address_type;
737         uint32_t dc_flags;
738         struct GUID dc_guid;
739
740         for (i=0; i<num_dcs; i++) {
741
742                 ZERO_STRUCT(r);
743
744                 if ((ads_cldap_netlogon(dclist[i]->hostname,
745                                         domain_name, &r)) &&
746                     (check_cldap_reply_required_flags(r.flags, flags))) {
747                         valid_dc = true;
748                         break;
749                 }
750
751                 continue;
752         }
753
754         if (!valid_dc) {
755                 return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
756         }
757
758         dc_flags = r.flags;
759
760         if (flags & DS_RETURN_FLAT_NAME) {
761                 if (!strlen(r.netbios_hostname) || !strlen(r.netbios_domain)) {
762                         return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
763                 }
764                 dc_hostname = r.netbios_hostname;
765                 dc_domain_name = r.netbios_domain;
766         } else if (flags & DS_RETURN_DNS_NAME) {
767                 if (!strlen(r.hostname) || !strlen(r.domain)) {
768                         return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
769                 }
770                 dc_hostname = r.hostname;
771                 dc_domain_name = r.domain;
772                 dc_flags |= DS_DNS_DOMAIN | DS_DNS_CONTROLLER;
773         } else {
774                 /* FIXME */
775                 dc_hostname = r.hostname;
776                 dc_domain_name = r.domain;
777                 dc_flags |= DS_DNS_DOMAIN | DS_DNS_CONTROLLER;
778         }
779
780         if (flags & DS_IP_REQUIRED) {
781                 char addr[INET6_ADDRSTRLEN];
782                 print_sockaddr(addr, sizeof(addr), &dclist[i]->ss);
783                 dc_address = talloc_asprintf(mem_ctx, "\\\\%s",
784                                                 addr);
785                 dc_address_type = DS_ADDRESS_TYPE_INET;
786         } else {
787                 dc_address = talloc_asprintf(mem_ctx, "\\\\%s",
788                                              r.netbios_hostname);
789                 dc_address_type = DS_ADDRESS_TYPE_NETBIOS;
790         }
791         NT_STATUS_HAVE_NO_MEMORY(dc_address);
792         smb_uuid_unpack(r.guid, &dc_guid);
793
794         if (r.forest) {
795                 dc_flags |= DS_DNS_FOREST;
796         }
797
798         return make_domain_controller_info(mem_ctx,
799                                            dc_hostname,
800                                            dc_address,
801                                            dc_address_type,
802                                            &dc_guid,
803                                            dc_domain_name,
804                                            r.forest,
805                                            dc_flags,
806                                            r.server_site_name,
807                                            r.client_site_name,
808                                            info);
809
810 }
811
812 /****************************************************************
813 ****************************************************************/
814
815 static NTSTATUS process_dc_netbios(TALLOC_CTX *mem_ctx,
816                                    const char *domain_name,
817                                    uint32_t flags,
818                                    struct ip_service_name **dclist,
819                                    int num_dcs,
820                                    struct netr_DsRGetDCNameInfo **info)
821 {
822         /* FIXME: code here */
823
824         return NT_STATUS_NOT_SUPPORTED;
825 }
826
827 /****************************************************************
828 ****************************************************************/
829
830 static NTSTATUS dsgetdcname_rediscover(TALLOC_CTX *mem_ctx,
831                                        const char *domain_name,
832                                        struct GUID *domain_guid,
833                                        uint32_t flags,
834                                        const char *site_name,
835                                        struct netr_DsRGetDCNameInfo **info)
836 {
837         NTSTATUS status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
838         struct ip_service_name *dclist;
839         int num_dcs;
840
841         DEBUG(10,("dsgetdcname_rediscover\n"));
842
843         if (flags & DS_IS_FLAT_NAME) {
844
845                 status = discover_dc_netbios(mem_ctx, domain_name, flags,
846                                              &dclist, &num_dcs);
847                 NT_STATUS_NOT_OK_RETURN(status);
848
849                 return process_dc_netbios(mem_ctx, domain_name, flags,
850                                           &dclist, num_dcs, info);
851         }
852
853         if (flags & DS_IS_DNS_NAME) {
854
855                 status = discover_dc_dns(mem_ctx, domain_name, domain_guid,
856                                          flags, site_name, &dclist, &num_dcs);
857                 NT_STATUS_NOT_OK_RETURN(status);
858
859                 return process_dc_dns(mem_ctx, domain_name, flags,
860                                       &dclist, num_dcs, info);
861         }
862
863         status = discover_dc_dns(mem_ctx, domain_name, domain_guid, flags,
864                                  site_name, &dclist, &num_dcs);
865
866         if (NT_STATUS_IS_OK(status) && num_dcs != 0) {
867
868                 status = process_dc_dns(mem_ctx, domain_name, flags, &dclist,
869                                         num_dcs, info);
870                 if (NT_STATUS_IS_OK(status)) {
871                         return status;
872                 }
873         }
874
875         status = discover_dc_netbios(mem_ctx, domain_name, flags, &dclist,
876                                      &num_dcs);
877         NT_STATUS_NOT_OK_RETURN(status);
878
879         return process_dc_netbios(mem_ctx, domain_name, flags, &dclist,
880                                   num_dcs, info);
881 }
882
883 /********************************************************************
884  dsgetdcname.
885
886  This will be the only public function here.
887 ********************************************************************/
888
889 NTSTATUS dsgetdcname(TALLOC_CTX *mem_ctx,
890                      const char *domain_name,
891                      struct GUID *domain_guid,
892                      const char *site_name,
893                      uint32_t flags,
894                      struct netr_DsRGetDCNameInfo **info)
895 {
896         NTSTATUS status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
897         struct netr_DsRGetDCNameInfo *myinfo = NULL;
898
899         DEBUG(10,("dsgetdcname: domain_name: %s, "
900                   "domain_guid: %s, site_name: %s, flags: 0x%08x\n",
901                   domain_name,
902                   domain_guid ? GUID_string(mem_ctx, domain_guid) : "(null)",
903                   site_name, flags));
904
905         *info = NULL;
906
907         if (!check_allowed_required_flags(flags)) {
908                 DEBUG(0,("invalid flags specified\n"));
909                 return NT_STATUS_INVALID_PARAMETER;
910         }
911
912         if (flags & DS_FORCE_REDISCOVERY) {
913                 goto rediscover;
914         }
915
916         status = dsgetdcname_cached(mem_ctx, domain_name, domain_guid,
917                                     flags, site_name, &myinfo);
918         if (NT_STATUS_IS_OK(status)) {
919                 *info = myinfo;
920                 return status;
921         }
922
923         if (flags & DS_BACKGROUND_ONLY) {
924                 return status;
925         }
926
927  rediscover:
928         status = dsgetdcname_rediscover(mem_ctx, domain_name,
929                                         domain_guid, flags, site_name,
930                                         &myinfo);
931
932         if (NT_STATUS_IS_OK(status)) {
933                 dsgetdcname_cache_store(mem_ctx, domain_name, myinfo);
934                 *info = myinfo;
935         }
936
937         return status;
938 }