8aca5b083e52a11db8395ea41d75b468c78efd8c
[ira/wip.git] / source3 / libads / dns.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
23 /* AIX resolv.h uses 'class' in struct ns_rr */
24
25 #if defined(AIX)
26 #  if defined(class)
27 #    undef class
28 #  endif
29 #endif  /* AIX */
30
31 /* resolver headers */
32
33 #include <sys/types.h>
34 #include <netinet/in.h>
35 #include <arpa/nameser.h>
36 #include <resolv.h>
37 #include <netdb.h>
38
39 #define MAX_DNS_PACKET_SIZE 0xffff
40
41 #ifdef NS_HFIXEDSZ      /* Bind 8/9 interface */
42 #if !defined(C_IN)      /* AIX 5.3 already defines C_IN */
43 #  define C_IN          ns_c_in
44 #endif
45 #if !defined(T_A)       /* AIX 5.3 already defines T_A */
46 #  define T_A           ns_t_a
47 #endif
48
49 #if defined(HAVE_IPV6)
50 #if !defined(T_AAAA)
51 #  define T_AAAA        ns_t_aaaa
52 #endif
53 #endif
54
55 #  define T_SRV         ns_t_srv
56 #if !defined(T_NS)      /* AIX 5.3 already defines T_NS */
57 #  define T_NS          ns_t_ns
58 #endif
59 #else
60 #  ifdef HFIXEDSZ
61 #    define NS_HFIXEDSZ HFIXEDSZ
62 #  else
63 #    define NS_HFIXEDSZ sizeof(HEADER)
64 #  endif        /* HFIXEDSZ */
65 #  ifdef PACKETSZ
66 #    define NS_PACKETSZ PACKETSZ
67 #  else /* 512 is usually the default */
68 #    define NS_PACKETSZ 512
69 #  endif        /* PACKETSZ */
70 #  define T_SRV         33
71 #endif
72
73 /*********************************************************************
74 *********************************************************************/
75
76 static bool ads_dns_parse_query( TALLOC_CTX *ctx, uint8 *start, uint8 *end,
77                           uint8 **ptr, struct dns_query *q )
78 {
79         uint8 *p = *ptr;
80         pstring hostname;
81         int namelen;
82
83         ZERO_STRUCTP( q );
84
85         if ( !start || !end || !q || !*ptr)
86                 return False;
87
88         /* See RFC 1035 for details. If this fails, then return. */
89
90         namelen = dn_expand( start, end, p, hostname, sizeof(hostname) );
91         if ( namelen < 0 ) {
92                 return False;
93         }
94         p += namelen;
95         q->hostname = talloc_strdup( ctx, hostname );
96
97         /* check that we have space remaining */
98
99         if ( PTR_DIFF(p+4, end) > 0 )
100                 return False;
101
102         q->type     = RSVAL( p, 0 );
103         q->in_class = RSVAL( p, 2 );
104         p += 4;
105
106         *ptr = p;
107
108         return True;
109 }
110
111 /*********************************************************************
112 *********************************************************************/
113
114 static bool ads_dns_parse_rr( TALLOC_CTX *ctx, uint8 *start, uint8 *end,
115                        uint8 **ptr, struct dns_rr *rr )
116 {
117         uint8 *p = *ptr;
118         pstring hostname;
119         int namelen;
120
121         if ( !start || !end || !rr || !*ptr)
122                 return -1;
123
124         ZERO_STRUCTP( rr );
125         /* pull the name from the answer */
126
127         namelen = dn_expand( start, end, p, hostname, sizeof(hostname) );
128         if ( namelen < 0 ) {
129                 return -1;
130         }
131         p += namelen;
132         rr->hostname = talloc_strdup( ctx, hostname );
133
134         /* check that we have space remaining */
135
136         if ( PTR_DIFF(p+10, end) > 0 )
137                 return False;
138
139         /* pull some values and then skip onto the string */
140
141         rr->type     = RSVAL(p, 0);
142         rr->in_class = RSVAL(p, 2);
143         rr->ttl      = RIVAL(p, 4);
144         rr->rdatalen = RSVAL(p, 8);
145
146         p += 10;
147
148         /* sanity check the available space */
149
150         if ( PTR_DIFF(p+rr->rdatalen, end ) > 0 ) {
151                 return False;
152
153         }
154
155         /* save a point to the rdata for this section */
156
157         rr->rdata = p;
158         p += rr->rdatalen;
159
160         *ptr = p;
161
162         return True;
163 }
164
165 /*********************************************************************
166 *********************************************************************/
167
168 static bool ads_dns_parse_rr_srv( TALLOC_CTX *ctx, uint8 *start, uint8 *end,
169                        uint8 **ptr, struct dns_rr_srv *srv )
170 {
171         struct dns_rr rr;
172         uint8 *p;
173         pstring dcname;
174         int namelen;
175
176         if ( !start || !end || !srv || !*ptr)
177                 return -1;
178
179         /* Parse the RR entry.  Coming out of the this, ptr is at the beginning
180            of the next record */
181
182         if ( !ads_dns_parse_rr( ctx, start, end, ptr, &rr ) ) {
183                 DEBUG(1,("ads_dns_parse_rr_srv: Failed to parse RR record\n"));
184                 return False;
185         }
186
187         if ( rr.type != T_SRV ) {
188                 DEBUG(1,("ads_dns_parse_rr_srv: Bad answer type (%d)\n",
189                                         rr.type));
190                 return False;
191         }
192
193         p = rr.rdata;
194
195         srv->priority = RSVAL(p, 0);
196         srv->weight   = RSVAL(p, 2);
197         srv->port     = RSVAL(p, 4);
198
199         p += 6;
200
201         namelen = dn_expand( start, end, p, dcname, sizeof(dcname) );
202         if ( namelen < 0 ) {
203                 DEBUG(1,("ads_dns_parse_rr_srv: Failed to uncompress name!\n"));
204                 return False;
205         }
206         srv->hostname = talloc_strdup( ctx, dcname );
207
208         return True;
209 }
210
211 /*********************************************************************
212 *********************************************************************/
213
214 static bool ads_dns_parse_rr_ns( TALLOC_CTX *ctx, uint8 *start, uint8 *end,
215                        uint8 **ptr, struct dns_rr_ns *nsrec )
216 {
217         struct dns_rr rr;
218         uint8 *p;
219         pstring nsname;
220         int namelen;
221
222         if ( !start || !end || !nsrec || !*ptr)
223                 return -1;
224
225         /* Parse the RR entry.  Coming out of the this, ptr is at the beginning
226            of the next record */
227
228         if ( !ads_dns_parse_rr( ctx, start, end, ptr, &rr ) ) {
229                 DEBUG(1,("ads_dns_parse_rr_ns: Failed to parse RR record\n"));
230                 return False;
231         }
232
233         if ( rr.type != T_NS ) {
234                 DEBUG(1,("ads_dns_parse_rr_ns: Bad answer type (%d)\n",
235                                         rr.type));
236                 return False;
237         }
238
239         p = rr.rdata;
240
241         /* ame server hostname */
242
243         namelen = dn_expand( start, end, p, nsname, sizeof(nsname) );
244         if ( namelen < 0 ) {
245                 DEBUG(1,("ads_dns_parse_rr_ns: Failed to uncompress name!\n"));
246                 return False;
247         }
248         nsrec->hostname = talloc_strdup( ctx, nsname );
249
250         return True;
251 }
252
253 /*********************************************************************
254  Sort SRV record list based on weight and priority.  See RFC 2782.
255 *********************************************************************/
256
257 static int dnssrvcmp( struct dns_rr_srv *a, struct dns_rr_srv *b )
258 {
259         if ( a->priority == b->priority ) {
260
261                 /* randomize entries with an equal weight and priority */
262                 if ( a->weight == b->weight )
263                         return 0;
264
265                 /* higher weights should be sorted lower */
266                 if ( a->weight > b->weight )
267                         return -1;
268                 else
269                         return 1;
270         }
271
272         if ( a->priority < b->priority )
273                 return -1;
274
275         return 1;
276 }
277
278 /*********************************************************************
279  Simple wrapper for a DNS query
280 *********************************************************************/
281
282 #define DNS_FAILED_WAITTIME          30
283
284 static NTSTATUS dns_send_req( TALLOC_CTX *ctx, const char *name, int q_type,
285                               uint8 **buf, int *resp_length )
286 {
287         uint8 *buffer = NULL;
288         size_t buf_len;
289         int resp_len = NS_PACKETSZ;
290         static time_t last_dns_check = 0;
291         static NTSTATUS last_dns_status = NT_STATUS_OK;
292         time_t now = time(NULL);
293
294         /* Try to prevent bursts of DNS lookups if the server is down */
295
296         /* Protect against large clock changes */
297
298         if ( last_dns_check > now )
299                 last_dns_check = 0;
300
301         /* IF we had a DNS timeout or a bad server and we are still
302            in the 30 second cache window, just return the previous
303            status and save the network timeout. */
304
305         if ( (NT_STATUS_EQUAL(last_dns_status,NT_STATUS_IO_TIMEOUT) ||
306               NT_STATUS_EQUAL(last_dns_status,NT_STATUS_CONNECTION_REFUSED)) &&
307              (last_dns_check+DNS_FAILED_WAITTIME) > now )
308         {
309                 DEBUG(10,("last_dns_check: Returning cached status (%s)\n",
310                           nt_errstr(last_dns_status) ));
311                 return last_dns_status;
312         }
313
314         /* Send the Query */
315         do {
316                 if ( buffer )
317                         TALLOC_FREE( buffer );
318
319                 buf_len = resp_len * sizeof(uint8);
320
321                 if (buf_len) {
322                         if ((buffer = TALLOC_ARRAY(ctx, uint8, buf_len))
323                                         == NULL ) {
324                                 DEBUG(0,("ads_dns_lookup_srv: "
325                                         "talloc() failed!\n"));
326                                 last_dns_status = NT_STATUS_NO_MEMORY;
327                                 last_dns_check = time(NULL);
328                                 return last_dns_status;
329                         }
330                 }
331
332                 if ((resp_len = res_query(name, C_IN, q_type, buffer, buf_len))
333                                 < 0 ) {
334                         DEBUG(3,("ads_dns_lookup_srv: "
335                                 "Failed to resolve %s (%s)\n",
336                                 name, strerror(errno)));
337                         TALLOC_FREE( buffer );
338                         last_dns_status = NT_STATUS_UNSUCCESSFUL;
339
340                         if (errno == ETIMEDOUT) {
341                                 last_dns_status = NT_STATUS_IO_TIMEOUT;
342                         }
343                         if (errno == ECONNREFUSED) {
344                                 last_dns_status = NT_STATUS_CONNECTION_REFUSED;
345                         }
346                         last_dns_check = time(NULL);
347                         return last_dns_status;
348                 }
349         } while ( buf_len < resp_len && resp_len < MAX_DNS_PACKET_SIZE );
350
351         *buf = buffer;
352         *resp_length = resp_len;
353
354         last_dns_check = time(NULL);
355         last_dns_status = NT_STATUS_OK;
356         return last_dns_status;
357 }
358
359 /*********************************************************************
360  Simple wrapper for a DNS SRV query
361 *********************************************************************/
362
363 static NTSTATUS ads_dns_lookup_srv( TALLOC_CTX *ctx,
364                                 const char *name,
365                                 struct dns_rr_srv **dclist,
366                                 int *numdcs)
367 {
368         uint8 *buffer = NULL;
369         int resp_len = 0;
370         struct dns_rr_srv *dcs = NULL;
371         int query_count, answer_count, auth_count, additional_count;
372         uint8 *p = buffer;
373         int rrnum;
374         int idx = 0;
375         NTSTATUS status;
376
377         if ( !ctx || !name || !dclist ) {
378                 return NT_STATUS_INVALID_PARAMETER;
379         }
380
381         /* Send the request.  May have to loop several times in case
382            of large replies */
383
384         status = dns_send_req( ctx, name, T_SRV, &buffer, &resp_len );
385         if ( !NT_STATUS_IS_OK(status) ) {
386                 DEBUG(3,("ads_dns_lookup_srv: Failed to send DNS query (%s)\n",
387                         nt_errstr(status)));
388                 return status;
389         }
390         p = buffer;
391
392         /* For some insane reason, the ns_initparse() et. al. routines are only
393            available in libresolv.a, and not the shared lib.  Who knows why....
394            So we have to parse the DNS reply ourselves */
395
396         /* Pull the answer RR's count from the header.
397          * Use the NMB ordering macros */
398
399         query_count      = RSVAL( p, 4 );
400         answer_count     = RSVAL( p, 6 );
401         auth_count       = RSVAL( p, 8 );
402         additional_count = RSVAL( p, 10 );
403
404         DEBUG(4,("ads_dns_lookup_srv: "
405                 "%d records returned in the answer section.\n",
406                 answer_count));
407
408         if (answer_count) {
409                 if ((dcs = TALLOC_ZERO_ARRAY(ctx, struct dns_rr_srv,
410                                                 answer_count)) == NULL ) {
411                         DEBUG(0,("ads_dns_lookup_srv: "
412                                 "talloc() failure for %d char*'s\n",
413                                 answer_count));
414                         return NT_STATUS_NO_MEMORY;
415                 }
416         } else {
417                 dcs = NULL;
418         }
419
420         /* now skip the header */
421
422         p += NS_HFIXEDSZ;
423
424         /* parse the query section */
425
426         for ( rrnum=0; rrnum<query_count; rrnum++ ) {
427                 struct dns_query q;
428
429                 if (!ads_dns_parse_query(ctx, buffer,
430                                         buffer+resp_len, &p, &q)) {
431                         DEBUG(1,("ads_dns_lookup_srv: "
432                                 "Failed to parse query record!\n"));
433                         return NT_STATUS_UNSUCCESSFUL;
434                 }
435         }
436
437         /* now we are at the answer section */
438
439         for ( rrnum=0; rrnum<answer_count; rrnum++ ) {
440                 if (!ads_dns_parse_rr_srv(ctx, buffer, buffer+resp_len,
441                                         &p, &dcs[rrnum])) {
442                         DEBUG(1,("ads_dns_lookup_srv: "
443                                 "Failed to parse answer record!\n"));
444                         return NT_STATUS_UNSUCCESSFUL;
445                 }
446         }
447         idx = rrnum;
448
449         /* Parse the authority section */
450         /* just skip these for now */
451
452         for ( rrnum=0; rrnum<auth_count; rrnum++ ) {
453                 struct dns_rr rr;
454
455                 if (!ads_dns_parse_rr( ctx, buffer,
456                                         buffer+resp_len, &p, &rr)) {
457                         DEBUG(1,("ads_dns_lookup_srv: "
458                                 "Failed to parse authority record!\n"));
459                         return NT_STATUS_UNSUCCESSFUL;
460                 }
461         }
462
463         /* Parse the additional records section */
464
465         for ( rrnum=0; rrnum<additional_count; rrnum++ ) {
466                 struct dns_rr rr;
467                 int i;
468
469                 if (!ads_dns_parse_rr(ctx, buffer, buffer+resp_len,
470                                         &p, &rr)) {
471                         DEBUG(1,("ads_dns_lookup_srv: Failed "
472                                 "to parse additional records section!\n"));
473                         return NT_STATUS_UNSUCCESSFUL;
474                 }
475
476                 /* Only interested in A or AAAA records as a shortcut for having
477                  * to come back later and lookup the name. For multi-homed
478                  * hosts, the number of additional records and exceed the
479                  * number of answer records. */
480
481                 if (rr.type != T_A || rr.rdatalen != 4) {
482 #if defined(HAVE_IPV6)
483                         /* FIXME. RFC2874 defines A6 records. This
484                          * requires recusive and horribly complex lookups.
485                          * Bastards. Ignore this for now.... JRA.
486                          */
487                         if (rr.type != T_AAAA || rr.rdatalen != 16)
488 #endif
489                                 continue;
490                 }
491
492                 for ( i=0; i<idx; i++ ) {
493                         if ( strcmp( rr.hostname, dcs[i].hostname ) == 0 ) {
494                                 int num_ips = dcs[i].num_ips;
495                                 struct sockaddr_storage *tmp_ss_s;
496
497                                 /* allocate new memory */
498
499                                 if (dcs[i].num_ips == 0) {
500                                         if ((dcs[i].ss_s = TALLOC_ARRAY(dcs,
501                                                 struct sockaddr_storage, 1 ))
502                                                         == NULL ) {
503                                                 return NT_STATUS_NO_MEMORY;
504                                         }
505                                 } else {
506                                         if ((tmp_ss_s = TALLOC_REALLOC_ARRAY(dcs,
507                                                         dcs[i].ss_s,
508                                                         struct sockaddr_storage,
509                                                         dcs[i].num_ips+1))
510                                                                 == NULL ) {
511                                                 return NT_STATUS_NO_MEMORY;
512                                         }
513
514                                         dcs[i].ss_s = tmp_ss_s;
515                                 }
516                                 dcs[i].num_ips++;
517
518                                 /* copy the new IP address */
519                                 if (rr.type == T_A) {
520                                         struct in_addr ip;
521                                         memcpy(&ip, rr.rdata, 4);
522                                         in_addr_to_sockaddr_storage(
523                                                         &dcs[i].ss_s[num_ips],
524                                                         ip);
525                                 }
526 #if defined(HAVE_IPV6)
527                                 if (rr.type == T_AAAA) {
528                                         struct in6_addr ip6;
529                                         memcpy(&ip6, rr.rdata, rr.rdatalen);
530                                         in6_addr_to_sockaddr_storage(
531                                                         &dcs[i].ss_s[num_ips],
532                                                         ip6);
533                                 }
534 #endif
535                         }
536                 }
537         }
538
539         qsort( dcs, idx, sizeof(struct dns_rr_srv), QSORT_CAST dnssrvcmp );
540
541         *dclist = dcs;
542         *numdcs = idx;
543
544         return NT_STATUS_OK;
545 }
546
547 /*********************************************************************
548  Simple wrapper for a DNS NS query
549 *********************************************************************/
550
551 NTSTATUS ads_dns_lookup_ns(TALLOC_CTX *ctx,
552                                 const char *dnsdomain,
553                                 struct dns_rr_ns **nslist,
554                                 int *numns)
555 {
556         uint8 *buffer = NULL;
557         int resp_len = 0;
558         struct dns_rr_ns *nsarray = NULL;
559         int query_count, answer_count, auth_count, additional_count;
560         uint8 *p;
561         int rrnum;
562         int idx = 0;
563         NTSTATUS status;
564
565         if ( !ctx || !dnsdomain || !nslist ) {
566                 return NT_STATUS_INVALID_PARAMETER;
567         }
568
569         /* Send the request.  May have to loop several times in case
570            of large replies */
571
572         status = dns_send_req( ctx, dnsdomain, T_NS, &buffer, &resp_len );
573         if ( !NT_STATUS_IS_OK(status) ) {
574                 DEBUG(3,("ads_dns_lookup_ns: Failed to send DNS query (%s)\n",
575                         nt_errstr(status)));
576                 return status;
577         }
578         p = buffer;
579
580         /* For some insane reason, the ns_initparse() et. al. routines are only
581            available in libresolv.a, and not the shared lib.  Who knows why....
582            So we have to parse the DNS reply ourselves */
583
584         /* Pull the answer RR's count from the header.
585          * Use the NMB ordering macros */
586
587         query_count      = RSVAL( p, 4 );
588         answer_count     = RSVAL( p, 6 );
589         auth_count       = RSVAL( p, 8 );
590         additional_count = RSVAL( p, 10 );
591
592         DEBUG(4,("ads_dns_lookup_ns: "
593                 "%d records returned in the answer section.\n",
594                 answer_count));
595
596         if (answer_count) {
597                 if ((nsarray = TALLOC_ARRAY(ctx, struct dns_rr_ns,
598                                                 answer_count)) == NULL ) {
599                         DEBUG(0,("ads_dns_lookup_ns: "
600                                 "talloc() failure for %d char*'s\n",
601                                 answer_count));
602                         return NT_STATUS_NO_MEMORY;
603                 }
604         } else {
605                 nsarray = NULL;
606         }
607
608         /* now skip the header */
609
610         p += NS_HFIXEDSZ;
611
612         /* parse the query section */
613
614         for ( rrnum=0; rrnum<query_count; rrnum++ ) {
615                 struct dns_query q;
616
617                 if (!ads_dns_parse_query(ctx, buffer, buffer+resp_len,
618                                         &p, &q)) {
619                         DEBUG(1,("ads_dns_lookup_ns: "
620                                 " Failed to parse query record!\n"));
621                         return NT_STATUS_UNSUCCESSFUL;
622                 }
623         }
624
625         /* now we are at the answer section */
626
627         for ( rrnum=0; rrnum<answer_count; rrnum++ ) {
628                 if (!ads_dns_parse_rr_ns(ctx, buffer, buffer+resp_len,
629                                         &p, &nsarray[rrnum])) {
630                         DEBUG(1,("ads_dns_lookup_ns: "
631                                 "Failed to parse answer record!\n"));
632                         return NT_STATUS_UNSUCCESSFUL;
633                 }
634         }
635         idx = rrnum;
636
637         /* Parse the authority section */
638         /* just skip these for now */
639
640         for ( rrnum=0; rrnum<auth_count; rrnum++ ) {
641                 struct dns_rr rr;
642
643                 if ( !ads_dns_parse_rr(ctx, buffer, buffer+resp_len,
644                                         &p, &rr)) {
645                         DEBUG(1,("ads_dns_lookup_ns: "
646                                 "Failed to parse authority record!\n"));
647                         return NT_STATUS_UNSUCCESSFUL;
648                 }
649         }
650
651         /* Parse the additional records section */
652
653         for ( rrnum=0; rrnum<additional_count; rrnum++ ) {
654                 struct dns_rr rr;
655                 int i;
656
657                 if (!ads_dns_parse_rr(ctx, buffer, buffer+resp_len,
658                                         &p, &rr)) {
659                         DEBUG(1,("ads_dns_lookup_ns: Failed "
660                                 "to parse additional records section!\n"));
661                         return NT_STATUS_UNSUCCESSFUL;
662                 }
663
664                 /* only interested in A records as a shortcut for having to come
665                    back later and lookup the name */
666
667                 if (rr.type != T_A || rr.rdatalen != 4) {
668 #if defined(HAVE_IPV6)
669                         if (rr.type != T_AAAA || rr.rdatalen != 16)
670 #endif
671                                 continue;
672                 }
673
674                 for ( i=0; i<idx; i++ ) {
675                         if (strcmp(rr.hostname, nsarray[i].hostname) == 0) {
676                                 if (rr.type == T_A) {
677                                         struct in_addr ip;
678                                         memcpy(&ip, rr.rdata, 4);
679                                         in_addr_to_sockaddr_storage(
680                                                         &nsarray[i].ss,
681                                                         ip);
682                                 }
683 #if defined(HAVE_IPV6)
684                                 if (rr.type == T_AAAA) {
685                                         struct in6_addr ip6;
686                                         memcpy(&ip6, rr.rdata, rr.rdatalen);
687                                         in6_addr_to_sockaddr_storage(
688                                                         &nsarray[i].ss,
689                                                         ip6);
690                                 }
691 #endif
692                         }
693                 }
694         }
695
696         *nslist = nsarray;
697         *numns = idx;
698
699         return NT_STATUS_OK;
700 }
701
702 /****************************************************************************
703  Store and fetch the AD client sitename.
704 ****************************************************************************/
705
706 #define SITENAME_KEY    "AD_SITENAME/DOMAIN/%s"
707
708 static char *sitename_key(const char *realm)
709 {
710         char *keystr;
711
712         if (asprintf(&keystr, SITENAME_KEY, strupper_static(realm)) == -1) {
713                 return NULL;
714         }
715
716         return keystr;
717 }
718
719
720 /****************************************************************************
721  Store the AD client sitename.
722  We store indefinately as every new CLDAP query will re-write this.
723 ****************************************************************************/
724
725 bool sitename_store(const char *realm, const char *sitename)
726 {
727         time_t expire;
728         bool ret = False;
729         char *key;
730
731         if (!gencache_init()) {
732                 return False;
733         }
734
735         if (!realm || (strlen(realm) == 0)) {
736                 DEBUG(0,("sitename_store: no realm\n"));
737                 return False;
738         }
739
740         key = sitename_key(realm);
741
742         if (!sitename || (sitename && !*sitename)) {
743                 DEBUG(5,("sitename_store: deleting empty sitename!\n"));
744                 ret = gencache_del(key);
745                 SAFE_FREE(key);
746                 return ret;
747         }
748
749         expire = get_time_t_max(); /* Store indefinately. */
750
751         DEBUG(10,("sitename_store: realm = [%s], sitename = [%s], expire = [%u]\n",
752                 realm, sitename, (unsigned int)expire ));
753
754         ret = gencache_set( key, sitename, expire );
755         SAFE_FREE(key);
756         return ret;
757 }
758
759 /****************************************************************************
760  Fetch the AD client sitename.
761  Caller must free.
762 ****************************************************************************/
763
764 char *sitename_fetch(const char *realm)
765 {
766         char *sitename = NULL;
767         time_t timeout;
768         bool ret = False;
769         const char *query_realm;
770         char *key;
771
772         if (!gencache_init()) {
773                 return False;
774         }
775
776         if (!realm || (strlen(realm) == 0)) {
777                 query_realm = lp_realm();
778         } else {
779                 query_realm = realm;
780         }
781
782         key = sitename_key(query_realm);
783
784         ret = gencache_get( key, &sitename, &timeout );
785         SAFE_FREE(key);
786         if ( !ret ) {
787                 DEBUG(5,("sitename_fetch: No stored sitename for %s\n",
788                         query_realm));
789         } else {
790                 DEBUG(5,("sitename_fetch: Returning sitename for %s: \"%s\"\n",
791                         query_realm, sitename ));
792         }
793         return sitename;
794 }
795
796 /****************************************************************************
797  Did the sitename change ?
798 ****************************************************************************/
799
800 bool stored_sitename_changed(const char *realm, const char *sitename)
801 {
802         bool ret = False;
803
804         char *new_sitename;
805
806         if (!realm || (strlen(realm) == 0)) {
807                 DEBUG(0,("stored_sitename_changed: no realm\n"));
808                 return False;
809         }
810
811         new_sitename = sitename_fetch(realm);
812
813         if (sitename && new_sitename && !strequal(sitename, new_sitename)) {
814                 ret = True;
815         } else if ((sitename && !new_sitename) ||
816                         (!sitename && new_sitename)) {
817                 ret = True;
818         }
819         SAFE_FREE(new_sitename);
820         return ret;
821 }
822
823 /********************************************************************
824  Query with optional sitename.
825 ********************************************************************/
826
827 static NTSTATUS ads_dns_query_internal(TALLOC_CTX *ctx,
828                                        const char *servicename,
829                                        const char *dc_pdc_gc_domains,
830                                        const char *realm,
831                                        const char *sitename,
832                                        struct dns_rr_srv **dclist,
833                                        int *numdcs )
834 {
835         char *name;
836         if (sitename) {
837                 name = talloc_asprintf(ctx, "%s._tcp.%s._sites.%s._msdcs.%s",
838                                        servicename, sitename,
839                                        dc_pdc_gc_domains, realm);
840         } else {
841                 name = talloc_asprintf(ctx, "%s._tcp.%s._msdcs.%s",
842                                 servicename, dc_pdc_gc_domains, realm);
843         }
844         if (!name) {
845                 return NT_STATUS_NO_MEMORY;
846         }
847         return ads_dns_lookup_srv( ctx, name, dclist, numdcs );
848 }
849
850 /********************************************************************
851  Query for AD DC's.
852 ********************************************************************/
853
854 NTSTATUS ads_dns_query_dcs(TALLOC_CTX *ctx,
855                            const char *realm,
856                            const char *sitename,
857                            struct dns_rr_srv **dclist,
858                            int *numdcs )
859 {
860         NTSTATUS status;
861
862         status = ads_dns_query_internal(ctx, "_ldap", "dc", realm, sitename,
863                                         dclist, numdcs);
864
865         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
866             NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_REFUSED)) {
867                 return status;
868         }
869
870         if (sitename &&
871             ((!NT_STATUS_IS_OK(status)) ||
872              (NT_STATUS_IS_OK(status) && (numdcs == 0)))) {
873                 /* Sitename DNS query may have failed. Try without. */
874                 status = ads_dns_query_internal(ctx, "_ldap", "dc", realm,
875                                                 NULL, dclist, numdcs);
876         }
877         return status;
878 }
879
880 /********************************************************************
881  Query for AD GC's.
882 ********************************************************************/
883
884 NTSTATUS ads_dns_query_gcs(TALLOC_CTX *ctx,
885                            const char *realm,
886                            const char *sitename,
887                            struct dns_rr_srv **dclist,
888                            int *numdcs )
889 {
890         NTSTATUS status;
891
892         status = ads_dns_query_internal(ctx, "_ldap", "gc", realm, sitename,
893                                         dclist, numdcs);
894
895         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
896             NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_REFUSED)) {
897                 return status;
898         }
899
900         if (sitename &&
901             ((!NT_STATUS_IS_OK(status)) ||
902              (NT_STATUS_IS_OK(status) && (numdcs == 0)))) {
903                 /* Sitename DNS query may have failed. Try without. */
904                 status = ads_dns_query_internal(ctx, "_ldap", "gc", realm,
905                                                 NULL, dclist, numdcs);
906         }
907         return status;
908 }
909
910 /********************************************************************
911  Query for AD KDC's.
912  Even if our underlying kerberos libraries are UDP only, this
913  is pretty safe as it's unlikely that a KDC supports TCP and not UDP.
914 ********************************************************************/
915
916 NTSTATUS ads_dns_query_kdcs(TALLOC_CTX *ctx,
917                             const char *dns_forest_name,
918                             const char *sitename,
919                             struct dns_rr_srv **dclist,
920                             int *numdcs )
921 {
922         NTSTATUS status;
923
924         status = ads_dns_query_internal(ctx, "_kerberos", "dc",
925                                         dns_forest_name, sitename, dclist,
926                                         numdcs);
927
928         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
929             NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_REFUSED)) {
930                 return status;
931         }
932
933         if (sitename &&
934             ((!NT_STATUS_IS_OK(status)) ||
935              (NT_STATUS_IS_OK(status) && (numdcs == 0)))) {
936                 /* Sitename DNS query may have failed. Try without. */
937                 status = ads_dns_query_internal(ctx, "_kerberos", "dc",
938                                                 dns_forest_name, NULL,
939                                                 dclist, numdcs);
940         }
941         return status;
942 }
943
944 /********************************************************************
945  Query for AD PDC. Sitename is obsolete here.
946 ********************************************************************/
947
948 NTSTATUS ads_dns_query_pdc(TALLOC_CTX *ctx,
949                            const char *dns_domain_name,
950                            struct dns_rr_srv **dclist,
951                            int *numdcs )
952 {
953         return ads_dns_query_internal(ctx, "_ldap", "pdc", dns_domain_name,
954                                       NULL, dclist, numdcs);
955 }
956
957 /********************************************************************
958  Query for AD DC by guid. Sitename is obsolete here.
959 ********************************************************************/
960
961 NTSTATUS ads_dns_query_dcs_guid(TALLOC_CTX *ctx,
962                                 const char *dns_forest_name,
963                                 const struct GUID *domain_guid,
964                                 struct dns_rr_srv **dclist,
965                                 int *numdcs )
966 {
967         /*_ldap._tcp.DomainGuid.domains._msdcs.DnsForestName */
968
969         const char *domains;
970         const char *guid_string;
971
972         guid_string = GUID_string(ctx, domain_guid);
973         if (!guid_string) {
974                 return NT_STATUS_NO_MEMORY;
975         }
976
977         /* little hack */
978         domains = talloc_asprintf(ctx, "%s.domains", guid_string);
979         if (!domains) {
980                 return NT_STATUS_NO_MEMORY;
981         }
982
983         return ads_dns_query_internal(ctx, "_ldap", domains, dns_forest_name,
984                                       NULL, dclist, numdcs);
985 }