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