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