addns: Async ads_dns_lookup_srv
[nivanova/samba-autobuild/.git] / lib / addns / dnsquery.c
1 /*
2    Unix SMB/CIFS implementation.
3    DNS utility library
4    Copyright (C) Gerald (Jerry) Carter           2006.
5    Copyright (C) Jeremy Allison                  2007.
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "lib/util/util_net.h"
23 #include "lib/util/tsort.h"
24 #include "librpc/gen_ndr/dns.h"
25 #include "libcli/dns/dns_lookup.h"
26 #include "lib/util/tevent_ntstatus.h"
27 #include "dnsquery.h"
28
29 /* AIX resolv.h uses 'class' in struct ns_rr */
30
31 #if defined(AIX)
32 #  if defined(class)
33 #    undef class
34 #  endif
35 #endif  /* AIX */
36
37 /* resolver headers */
38
39 #include <sys/types.h>
40 #include <netinet/in.h>
41 #include <arpa/nameser.h>
42 #include <resolv.h>
43 #include <netdb.h>
44
45 #define MAX_DNS_PACKET_SIZE 0xffff
46
47 #ifdef NS_HFIXEDSZ      /* Bind 8/9 interface */
48 #if !defined(C_IN)      /* AIX 5.3 already defines C_IN */
49 #  define C_IN          ns_c_in
50 #endif
51 #if !defined(T_A)       /* AIX 5.3 already defines T_A */
52 #  define T_A           ns_t_a
53 #endif
54
55 #if defined(HAVE_IPV6)
56 #if !defined(T_AAAA)
57 #  define T_AAAA        ns_t_aaaa
58 #endif
59 #endif
60
61 #  define T_SRV         ns_t_srv
62 #if !defined(T_NS)      /* AIX 5.3 already defines T_NS */
63 #  define T_NS          ns_t_ns
64 #endif
65 #else
66 #  ifdef HFIXEDSZ
67 #    define NS_HFIXEDSZ HFIXEDSZ
68 #  else
69 #    define NS_HFIXEDSZ sizeof(HEADER)
70 #  endif        /* HFIXEDSZ */
71 #  ifdef PACKETSZ
72 #    define NS_PACKETSZ PACKETSZ
73 #  else /* 512 is usually the default */
74 #    define NS_PACKETSZ 512
75 #  endif        /* PACKETSZ */
76 #  define T_SRV         33
77 #endif
78
79 /*********************************************************************
80 *********************************************************************/
81
82 static bool ads_dns_parse_query( TALLOC_CTX *ctx, uint8_t *start, uint8_t *end,
83                           uint8_t **ptr, struct dns_query *q )
84 {
85         uint8_t *p = *ptr;
86         char hostname[MAX_DNS_NAME_LENGTH];
87         int namelen;
88
89         ZERO_STRUCTP( q );
90
91         if ( !start || !end || !q || !*ptr)
92                 return false;
93
94         /* See RFC 1035 for details. If this fails, then return. */
95
96         namelen = dn_expand( start, end, p, hostname, sizeof(hostname) );
97         if ( namelen < 0 ) {
98                 return false;
99         }
100         p += namelen;
101         q->hostname = talloc_strdup( ctx, hostname );
102
103         /* check that we have space remaining */
104
105         if ( PTR_DIFF(p+4, end) > 0 )
106                 return false;
107
108         q->type     = RSVAL( p, 0 );
109         q->in_class = RSVAL( p, 2 );
110         p += 4;
111
112         *ptr = p;
113
114         return true;
115 }
116
117 /*********************************************************************
118 *********************************************************************/
119
120 static bool ads_dns_parse_rr( TALLOC_CTX *ctx, uint8_t *start, uint8_t *end,
121                        uint8_t **ptr, struct dns_rr *rr )
122 {
123         uint8_t *p = *ptr;
124         char hostname[MAX_DNS_NAME_LENGTH];
125         int namelen;
126
127         if ( !start || !end || !rr || !*ptr)
128                 return -1;
129
130         ZERO_STRUCTP( rr );
131         /* pull the name from the answer */
132
133         namelen = dn_expand( start, end, p, hostname, sizeof(hostname) );
134         if ( namelen < 0 ) {
135                 return -1;
136         }
137         p += namelen;
138         rr->hostname = talloc_strdup( ctx, hostname );
139
140         /* check that we have space remaining */
141
142         if ( PTR_DIFF(p+10, end) > 0 )
143                 return false;
144
145         /* pull some values and then skip onto the string */
146
147         rr->type     = RSVAL(p, 0);
148         rr->in_class = RSVAL(p, 2);
149         rr->ttl      = RIVAL(p, 4);
150         rr->rdatalen = RSVAL(p, 8);
151
152         p += 10;
153
154         /* sanity check the available space */
155
156         if ( PTR_DIFF(p+rr->rdatalen, end ) > 0 ) {
157                 return false;
158
159         }
160
161         /* save a point to the rdata for this section */
162
163         rr->rdata = p;
164         p += rr->rdatalen;
165
166         *ptr = p;
167
168         return true;
169 }
170
171 /*********************************************************************
172 *********************************************************************/
173
174 static bool ads_dns_parse_rr_ns( TALLOC_CTX *ctx, uint8_t *start, uint8_t *end,
175                        uint8_t **ptr, struct dns_rr_ns *nsrec )
176 {
177         struct dns_rr rr;
178         uint8_t *p;
179         char nsname[MAX_DNS_NAME_LENGTH];
180         int namelen;
181
182         if ( !start || !end || !nsrec || !*ptr)
183                 return -1;
184
185         /* Parse the RR entry.  Coming out of the this, ptr is at the beginning
186            of the next record */
187
188         if ( !ads_dns_parse_rr( ctx, start, end, ptr, &rr ) ) {
189                 DEBUG(1,("ads_dns_parse_rr_ns: Failed to parse RR record\n"));
190                 return false;
191         }
192
193         if ( rr.type != T_NS ) {
194                 DEBUG(1,("ads_dns_parse_rr_ns: Bad answer type (%d)\n",
195                                         rr.type));
196                 return false;
197         }
198
199         p = rr.rdata;
200
201         /* ame server hostname */
202
203         namelen = dn_expand( start, end, p, nsname, sizeof(nsname) );
204         if ( namelen < 0 ) {
205                 DEBUG(1,("ads_dns_parse_rr_ns: Failed to uncompress name!\n"));
206                 return false;
207         }
208         nsrec->hostname = talloc_strdup( ctx, nsname );
209
210         return true;
211 }
212
213 /*********************************************************************
214  Sort SRV record list based on weight and priority.  See RFC 2782.
215 *********************************************************************/
216
217 static int dnssrvcmp( struct dns_rr_srv *a, struct dns_rr_srv *b )
218 {
219         if ( a->priority == b->priority ) {
220
221                 /* randomize entries with an equal weight and priority */
222                 if ( a->weight == b->weight )
223                         return 0;
224
225                 /* higher weights should be sorted lower */
226                 if ( a->weight > b->weight )
227                         return -1;
228                 else
229                         return 1;
230         }
231
232         if ( a->priority < b->priority )
233                 return -1;
234
235         return 1;
236 }
237
238 /*********************************************************************
239  Simple wrapper for a DNS query
240 *********************************************************************/
241
242 #define DNS_FAILED_WAITTIME          30
243
244 static NTSTATUS dns_send_req( TALLOC_CTX *ctx, const char *name, int q_type,
245                               uint8_t **buf, int *resp_length )
246 {
247         uint8_t *buffer = NULL;
248         size_t buf_len = 0;
249         int resp_len = NS_PACKETSZ;
250         static time_t last_dns_check = 0;
251         static NTSTATUS last_dns_status = NT_STATUS_OK;
252         time_t now = time_mono(NULL);
253
254         /* Try to prevent bursts of DNS lookups if the server is down */
255
256         /* Protect against large clock changes */
257
258         if ( last_dns_check > now )
259                 last_dns_check = 0;
260
261         /* IF we had a DNS timeout or a bad server and we are still
262            in the 30 second cache window, just return the previous
263            status and save the network timeout. */
264
265         if ( (NT_STATUS_EQUAL(last_dns_status,NT_STATUS_IO_TIMEOUT) ||
266               NT_STATUS_EQUAL(last_dns_status,NT_STATUS_CONNECTION_REFUSED)) &&
267              (last_dns_check+DNS_FAILED_WAITTIME) > now )
268         {
269                 DEBUG(10,("dns_send_req: last dns check returning cached status (%s)\n",
270                           nt_errstr(last_dns_status) ));
271                 return last_dns_status;
272         }
273
274         /* Send the Query */
275         do {
276                 if ( buffer )
277                         TALLOC_FREE( buffer );
278
279                 buf_len = resp_len * sizeof(uint8_t);
280
281                 if (buf_len) {
282                         if ((buffer = talloc_array(ctx, uint8_t, buf_len))
283                                         == NULL ) {
284                                 DEBUG(0,("dns_send_req: "
285                                         "talloc() failed!\n"));
286                                 last_dns_status = NT_STATUS_NO_MEMORY;
287                                 last_dns_check = time_mono(NULL);
288                                 return last_dns_status;
289                         }
290                 }
291
292                 if ((resp_len = res_query(name, C_IN, q_type, buffer, buf_len))
293                                 < 0 ) {
294                         DEBUG(3,("dns_send_req: "
295                                 "Failed to resolve %s (%s)\n",
296                                 name, strerror(errno)));
297                         TALLOC_FREE( buffer );
298                         last_dns_status = NT_STATUS_UNSUCCESSFUL;
299
300                         if (errno == ETIMEDOUT) {
301                                 last_dns_status = NT_STATUS_IO_TIMEOUT;
302                         }
303                         if (errno == ECONNREFUSED) {
304                                 last_dns_status = NT_STATUS_CONNECTION_REFUSED;
305                         }
306                         last_dns_check = time_mono(NULL);
307                         return last_dns_status;
308                 }
309
310                 /* On AIX, Solaris, and possibly some older glibc systems (e.g. SLES8)
311                    truncated replies never give back a resp_len > buflen
312                    which ends up causing DNS resolve failures on large tcp DNS replies */
313
314                 if (buf_len == resp_len) {
315                         if (resp_len == MAX_DNS_PACKET_SIZE) {
316                                 DEBUG(1,("dns_send_req: DNS reply too large when resolving %s\n",
317                                         name));
318                                 TALLOC_FREE( buffer );
319                                 last_dns_status = NT_STATUS_BUFFER_TOO_SMALL;
320                                 last_dns_check = time_mono(NULL);
321                                 return last_dns_status;
322                         }
323
324                         resp_len = MIN(resp_len*2, MAX_DNS_PACKET_SIZE);
325                 }
326
327
328         } while ( buf_len < resp_len && resp_len <= MAX_DNS_PACKET_SIZE );
329
330         *buf = buffer;
331         *resp_length = resp_len;
332
333         last_dns_check = time_mono(NULL);
334         last_dns_status = NT_STATUS_OK;
335         return last_dns_status;
336 }
337
338 struct ads_dns_lookup_srv_state {
339         struct dns_rr_srv *srvs;
340         size_t num_srvs;
341 };
342
343 static void ads_dns_lookup_srv_done(struct tevent_req *subreq);
344
345 struct tevent_req *ads_dns_lookup_srv_send(TALLOC_CTX *mem_ctx,
346                                            struct tevent_context *ev,
347                                            const char *name)
348 {
349         struct tevent_req *req, *subreq;
350         struct ads_dns_lookup_srv_state *state;
351
352         req = tevent_req_create(mem_ctx, &state,
353                                 struct ads_dns_lookup_srv_state);
354         if (req == NULL) {
355                 return NULL;
356         }
357
358         subreq = dns_lookup_send(
359                 state,
360                 ev,
361                 NULL,
362                 name,
363                 DNS_QCLASS_IN,
364                 DNS_QTYPE_SRV);
365
366         if (tevent_req_nomem(subreq, req)) {
367                 return tevent_req_post(req, ev);
368         }
369         tevent_req_set_callback(subreq, ads_dns_lookup_srv_done, req);
370         return req;
371 }
372
373 static void ads_dns_lookup_srv_done(struct tevent_req *subreq)
374 {
375         struct tevent_req *req = tevent_req_callback_data(
376                 subreq, struct tevent_req);
377         struct ads_dns_lookup_srv_state *state = tevent_req_data(
378                 req, struct ads_dns_lookup_srv_state);
379         int ret;
380         struct dns_name_packet *reply;
381         uint16_t i, idx;
382
383         ret = dns_lookup_recv(subreq, state, &reply);
384         TALLOC_FREE(subreq);
385         if (ret != 0) {
386                 tevent_req_nterror(req, map_nt_error_from_unix_common(ret));
387                 return;
388         }
389
390         for (i=0; i<reply->ancount; i++) {
391                 if (reply->answers[i].rr_type == DNS_QTYPE_SRV) {
392                         state->num_srvs += 1;
393                 }
394         }
395
396         state->srvs = talloc_array(state, struct dns_rr_srv, state->num_srvs);
397         if (tevent_req_nomem(state->srvs, req)) {
398                 return;
399         }
400
401         idx = 0;
402
403         for (i=0; i<reply->ancount; i++) {
404                 struct dns_res_rec *an = &reply->answers[i];
405                 struct dns_rr_srv *dst = &state->srvs[idx];
406                 struct dns_srv_record *src;
407
408                 if (an->rr_type != DNS_QTYPE_SRV) {
409                         continue;
410                 }
411                 src = &an->rdata.srv_record;
412
413                 *dst = (struct dns_rr_srv) {
414                         .hostname = talloc_move(state->srvs, &src->target),
415                         .priority = src->priority,
416                         .weight = src->weight,
417                         .port = src->port,
418                 };
419                 idx += 1;
420         }
421
422         for (i=0; i<reply->arcount; i++) {
423                 struct dns_res_rec *ar = &reply->additional[i];
424                 struct sockaddr_storage addr;
425                 bool ok;
426                 size_t j;
427
428                 ok = dns_res_rec_get_sockaddr(ar, &addr);
429                 if (!ok) {
430                         continue;
431                 }
432
433                 for (j=0; j<state->num_srvs; j++) {
434                         struct dns_rr_srv *srv = &state->srvs[j];
435                         struct sockaddr_storage *tmp;
436
437                         if (strcmp(srv->hostname, ar->name) != 0) {
438                                 continue;
439                         }
440
441                         tmp = talloc_realloc(
442                                 state->srvs,
443                                 srv->ss_s,
444                                 struct sockaddr_storage,
445                                 srv->num_ips+1);
446
447                         if (tevent_req_nomem(tmp, req)) {
448                                 return;
449                         }
450                         srv->ss_s = tmp;
451
452                         srv->ss_s[srv->num_ips] = addr;
453                         srv->num_ips += 1;
454                 }
455         }
456
457         TYPESAFE_QSORT(state->srvs, state->num_srvs, dnssrvcmp);
458
459         tevent_req_done(req);
460 }
461
462 NTSTATUS ads_dns_lookup_srv_recv(struct tevent_req *req,
463                                  TALLOC_CTX *mem_ctx,
464                                  struct dns_rr_srv **srvs,
465                                  size_t *num_srvs)
466 {
467         struct ads_dns_lookup_srv_state *state = tevent_req_data(
468                 req, struct ads_dns_lookup_srv_state);
469         NTSTATUS status;
470
471         if (tevent_req_is_nterror(req, &status)) {
472                 return status;
473         }
474         *srvs = talloc_move(mem_ctx, &state->srvs);
475         *num_srvs = state->num_srvs;
476         tevent_req_received(req);
477         return NT_STATUS_OK;
478 }
479
480 /*********************************************************************
481  Simple wrapper for a DNS SRV query
482 *********************************************************************/
483
484 NTSTATUS ads_dns_lookup_srv(TALLOC_CTX *ctx,
485                                 const char *name,
486                                 struct dns_rr_srv **dclist,
487                                 int *numdcs)
488 {
489         struct tevent_context *ev;
490         struct tevent_req *req;
491         NTSTATUS status = NT_STATUS_NO_MEMORY;
492         size_t num_srvs;
493
494         ev = samba_tevent_context_init(ctx);
495         if (ev == NULL) {
496                 goto fail;
497         }
498         req = ads_dns_lookup_srv_send(ev, ev, name);
499         if (req == NULL) {
500                 goto fail;
501         }
502         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
503                 goto fail;
504         }
505         status = ads_dns_lookup_srv_recv(req, ctx, dclist, &num_srvs);
506         *numdcs = num_srvs;     /* size_t->int */
507 fail:
508         TALLOC_FREE(ev);
509         return status;
510 }
511
512 /*********************************************************************
513  Simple wrapper for a DNS NS query
514 *********************************************************************/
515
516 NTSTATUS ads_dns_lookup_ns(TALLOC_CTX *ctx,
517                                 const char *dnsdomain,
518                                 struct dns_rr_ns **nslist,
519                                 int *numns)
520 {
521         uint8_t *buffer = NULL;
522         int resp_len = 0;
523         struct dns_rr_ns *nsarray = NULL;
524         int query_count, answer_count, auth_count, additional_count;
525         uint8_t *p;
526         int rrnum;
527         int idx = 0;
528         NTSTATUS status;
529
530         if ( !ctx || !dnsdomain || !nslist ) {
531                 return NT_STATUS_INVALID_PARAMETER;
532         }
533
534         /* Send the request.  May have to loop several times in case
535            of large replies */
536
537         status = dns_send_req( ctx, dnsdomain, T_NS, &buffer, &resp_len );
538         if ( !NT_STATUS_IS_OK(status) ) {
539                 DEBUG(3,("ads_dns_lookup_ns: Failed to send DNS query (%s)\n",
540                         nt_errstr(status)));
541                 return status;
542         }
543         p = buffer;
544
545         /* For some insane reason, the ns_initparse() et. al. routines are only
546            available in libresolv.a, and not the shared lib.  Who knows why....
547            So we have to parse the DNS reply ourselves */
548
549         /* Pull the answer RR's count from the header.
550          * Use the NMB ordering macros */
551
552         query_count      = RSVAL( p, 4 );
553         answer_count     = RSVAL( p, 6 );
554         auth_count       = RSVAL( p, 8 );
555         additional_count = RSVAL( p, 10 );
556
557         DEBUG(4,("ads_dns_lookup_ns: "
558                 "%d records returned in the answer section.\n",
559                 answer_count));
560
561         if (answer_count) {
562                 if ((nsarray = talloc_array(ctx, struct dns_rr_ns,
563                                                 answer_count)) == NULL ) {
564                         DEBUG(0,("ads_dns_lookup_ns: "
565                                 "talloc() failure for %d char*'s\n",
566                                 answer_count));
567                         return NT_STATUS_NO_MEMORY;
568                 }
569         } else {
570                 nsarray = NULL;
571         }
572
573         /* now skip the header */
574
575         p += NS_HFIXEDSZ;
576
577         /* parse the query section */
578
579         for ( rrnum=0; rrnum<query_count; rrnum++ ) {
580                 struct dns_query q;
581
582                 if (!ads_dns_parse_query(ctx, buffer, buffer+resp_len,
583                                         &p, &q)) {
584                         DEBUG(1,("ads_dns_lookup_ns: "
585                                 " Failed to parse query record!\n"));
586                         return NT_STATUS_UNSUCCESSFUL;
587                 }
588         }
589
590         /* now we are at the answer section */
591
592         for ( rrnum=0; rrnum<answer_count; rrnum++ ) {
593                 if (!ads_dns_parse_rr_ns(ctx, buffer, buffer+resp_len,
594                                         &p, &nsarray[rrnum])) {
595                         DEBUG(1,("ads_dns_lookup_ns: "
596                                 "Failed to parse answer record!\n"));
597                         return NT_STATUS_UNSUCCESSFUL;
598                 }
599         }
600         idx = rrnum;
601
602         /* Parse the authority section */
603         /* just skip these for now */
604
605         for ( rrnum=0; rrnum<auth_count; rrnum++ ) {
606                 struct dns_rr rr;
607
608                 if ( !ads_dns_parse_rr(ctx, buffer, buffer+resp_len,
609                                         &p, &rr)) {
610                         DEBUG(1,("ads_dns_lookup_ns: "
611                                 "Failed to parse authority record!\n"));
612                         return NT_STATUS_UNSUCCESSFUL;
613                 }
614         }
615
616         /* Parse the additional records section */
617
618         for ( rrnum=0; rrnum<additional_count; rrnum++ ) {
619                 struct dns_rr rr;
620                 int i;
621
622                 if (!ads_dns_parse_rr(ctx, buffer, buffer+resp_len,
623                                         &p, &rr)) {
624                         DEBUG(1,("ads_dns_lookup_ns: Failed "
625                                 "to parse additional records section!\n"));
626                         return NT_STATUS_UNSUCCESSFUL;
627                 }
628
629                 /* only interested in A records as a shortcut for having to come
630                    back later and lookup the name */
631
632                 if (rr.type != T_A || rr.rdatalen != 4) {
633 #if defined(HAVE_IPV6)
634                         if (rr.type != T_AAAA || rr.rdatalen != 16)
635 #endif
636                                 continue;
637                 }
638
639                 for ( i=0; i<idx; i++ ) {
640                         if (strcmp(rr.hostname, nsarray[i].hostname) == 0) {
641                                 if (rr.type == T_A) {
642                                         struct in_addr ip;
643                                         memcpy(&ip, rr.rdata, 4);
644                                         in_addr_to_sockaddr_storage(
645                                                         &nsarray[i].ss,
646                                                         ip);
647                                 }
648 #if defined(HAVE_IPV6)
649                                 if (rr.type == T_AAAA) {
650                                         struct in6_addr ip6;
651                                         memcpy(&ip6, rr.rdata, rr.rdatalen);
652                                         in6_addr_to_sockaddr_storage(
653                                                         &nsarray[i].ss,
654                                                         ip6);
655                                 }
656 #endif
657                         }
658                 }
659         }
660
661         *nslist = nsarray;
662         *numns = idx;
663
664         return NT_STATUS_OK;
665 }
666
667 /********************************************************************
668  Query with optional sitename.
669 ********************************************************************/
670
671 static NTSTATUS ads_dns_query_internal(TALLOC_CTX *ctx,
672                                        const char *servicename,
673                                        const char *dc_pdc_gc_domains,
674                                        const char *realm,
675                                        const char *sitename,
676                                        struct dns_rr_srv **dclist,
677                                        int *numdcs )
678 {
679         char *name;
680         NTSTATUS status;
681         int num_srvs = 0;
682
683         if ((sitename != NULL) && (strlen(sitename) != 0)) {
684                 name = talloc_asprintf(ctx, "%s._tcp.%s._sites.%s._msdcs.%s",
685                                        servicename, sitename,
686                                        dc_pdc_gc_domains, realm);
687                 if (name == NULL) {
688                         return NT_STATUS_NO_MEMORY;
689                 }
690
691                 status = ads_dns_lookup_srv(ctx, name, dclist, &num_srvs);
692
693                 TALLOC_FREE(name);
694
695                 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
696                     NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_REFUSED)) {
697                         return status;
698                 }
699
700                 if (NT_STATUS_IS_OK(status) && (num_srvs != 0)) {
701                         goto done;
702                 }
703         }
704
705         name = talloc_asprintf(ctx, "%s._tcp.%s._msdcs.%s",
706                                servicename, dc_pdc_gc_domains, realm);
707         if (name == NULL) {
708                 return NT_STATUS_NO_MEMORY;
709         }
710         status = ads_dns_lookup_srv(ctx, name, dclist, &num_srvs);
711
712 done:
713         *numdcs = num_srvs; /* automatic conversion size_t->int */
714         return status;
715 }
716
717 /********************************************************************
718  Query for AD DC's.
719 ********************************************************************/
720
721 NTSTATUS ads_dns_query_dcs(TALLOC_CTX *ctx,
722                            const char *realm,
723                            const char *sitename,
724                            struct dns_rr_srv **dclist,
725                            int *numdcs )
726 {
727         NTSTATUS status;
728
729         status = ads_dns_query_internal(ctx,
730                                         "_ldap",
731                                         "dc",
732                                         realm,
733                                         sitename,
734                                         dclist,
735                                         numdcs);
736         return status;
737 }
738
739 /********************************************************************
740  Query for AD GC's.
741 ********************************************************************/
742
743 NTSTATUS ads_dns_query_gcs(TALLOC_CTX *ctx,
744                            const char *realm,
745                            const char *sitename,
746                            struct dns_rr_srv **dclist,
747                            int *numdcs )
748 {
749         NTSTATUS status;
750
751         status = ads_dns_query_internal(ctx,
752                                         "_ldap",
753                                         "gc",
754                                         realm,
755                                         sitename,
756                                         dclist,
757                                         numdcs);
758         return status;
759 }
760
761 /********************************************************************
762  Query for AD KDC's.
763  Even if our underlying kerberos libraries are UDP only, this
764  is pretty safe as it's unlikely that a KDC supports TCP and not UDP.
765 ********************************************************************/
766
767 NTSTATUS ads_dns_query_kdcs(TALLOC_CTX *ctx,
768                             const char *dns_forest_name,
769                             const char *sitename,
770                             struct dns_rr_srv **dclist,
771                             int *numdcs )
772 {
773         NTSTATUS status;
774
775         status = ads_dns_query_internal(ctx,
776                                         "_kerberos",
777                                         "dc",
778                                         dns_forest_name,
779                                         sitename,
780                                         dclist,
781                                         numdcs);
782         return status;
783 }
784
785 /********************************************************************
786  Query for AD PDC. Sitename is obsolete here.
787 ********************************************************************/
788
789 NTSTATUS ads_dns_query_pdc(TALLOC_CTX *ctx,
790                            const char *dns_domain_name,
791                            struct dns_rr_srv **dclist,
792                            int *numdcs )
793 {
794         return ads_dns_query_internal(ctx,
795                                       "_ldap",
796                                       "pdc",
797                                       dns_domain_name,
798                                       NULL,
799                                       dclist,
800                                       numdcs);
801 }
802
803 /********************************************************************
804  Query for AD DC by guid. Sitename is obsolete here.
805 ********************************************************************/
806
807 NTSTATUS ads_dns_query_dcs_guid(TALLOC_CTX *ctx,
808                                 const char *dns_forest_name,
809                                 const char *domain_guid,
810                                 struct dns_rr_srv **dclist,
811                                 int *numdcs )
812 {
813         /*_ldap._tcp.DomainGuid.domains._msdcs.DnsForestName */
814
815         const char *domains;
816
817         /* little hack */
818         domains = talloc_asprintf(ctx, "%s.domains", domain_guid);
819         if (!domains) {
820                 return NT_STATUS_NO_MEMORY;
821         }
822
823         return ads_dns_query_internal(ctx,
824                                       "_ldap",
825                                       domains,
826                                       dns_forest_name,
827                                       NULL,
828                                       dclist,
829                                       numdcs);
830 }