• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/samba-3.5.8/source3/libads/
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
76static 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	char hostname[MAX_DNS_NAME_LENGTH];
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
114static 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	char hostname[MAX_DNS_NAME_LENGTH];
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
168static 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	char dcname[MAX_DNS_NAME_LENGTH];
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
207	srv->hostname = talloc_strdup( ctx, dcname );
208
209	DEBUG(10,("ads_dns_parse_rr_srv: Parsed %s [%u, %u, %u]\n",
210		  srv->hostname,
211		  srv->priority,
212		  srv->weight,
213		  srv->port));
214
215	return True;
216}
217
218/*********************************************************************
219*********************************************************************/
220
221static bool ads_dns_parse_rr_ns( TALLOC_CTX *ctx, uint8 *start, uint8 *end,
222                       uint8 **ptr, struct dns_rr_ns *nsrec )
223{
224	struct dns_rr rr;
225	uint8 *p;
226	char nsname[MAX_DNS_NAME_LENGTH];
227	int namelen;
228
229	if ( !start || !end || !nsrec || !*ptr)
230		return -1;
231
232	/* Parse the RR entry.  Coming out of the this, ptr is at the beginning
233	   of the next record */
234
235	if ( !ads_dns_parse_rr( ctx, start, end, ptr, &rr ) ) {
236		DEBUG(1,("ads_dns_parse_rr_ns: Failed to parse RR record\n"));
237		return False;
238	}
239
240	if ( rr.type != T_NS ) {
241		DEBUG(1,("ads_dns_parse_rr_ns: Bad answer type (%d)\n",
242					rr.type));
243		return False;
244	}
245
246	p = rr.rdata;
247
248	/* ame server hostname */
249
250	namelen = dn_expand( start, end, p, nsname, sizeof(nsname) );
251	if ( namelen < 0 ) {
252		DEBUG(1,("ads_dns_parse_rr_ns: Failed to uncompress name!\n"));
253		return False;
254	}
255	nsrec->hostname = talloc_strdup( ctx, nsname );
256
257	return True;
258}
259
260/*********************************************************************
261 Sort SRV record list based on weight and priority.  See RFC 2782.
262*********************************************************************/
263
264static int dnssrvcmp( struct dns_rr_srv *a, struct dns_rr_srv *b )
265{
266	if ( a->priority == b->priority ) {
267
268		/* randomize entries with an equal weight and priority */
269		if ( a->weight == b->weight )
270			return 0;
271
272		/* higher weights should be sorted lower */
273		if ( a->weight > b->weight )
274			return -1;
275		else
276			return 1;
277	}
278
279	if ( a->priority < b->priority )
280		return -1;
281
282	return 1;
283}
284
285/*********************************************************************
286 Simple wrapper for a DNS query
287*********************************************************************/
288
289#define DNS_FAILED_WAITTIME          30
290
291static NTSTATUS dns_send_req( TALLOC_CTX *ctx, const char *name, int q_type,
292                              uint8 **buf, int *resp_length )
293{
294	uint8 *buffer = NULL;
295	size_t buf_len = 0;
296	int resp_len = NS_PACKETSZ;
297	static time_t last_dns_check = 0;
298	static NTSTATUS last_dns_status = NT_STATUS_OK;
299	time_t now = time(NULL);
300
301	/* Try to prevent bursts of DNS lookups if the server is down */
302
303	/* Protect against large clock changes */
304
305	if ( last_dns_check > now )
306		last_dns_check = 0;
307
308	/* IF we had a DNS timeout or a bad server and we are still
309	   in the 30 second cache window, just return the previous
310	   status and save the network timeout. */
311
312	if ( (NT_STATUS_EQUAL(last_dns_status,NT_STATUS_IO_TIMEOUT) ||
313	      NT_STATUS_EQUAL(last_dns_status,NT_STATUS_CONNECTION_REFUSED)) &&
314	     (last_dns_check+DNS_FAILED_WAITTIME) > now )
315	{
316		DEBUG(10,("last_dns_check: Returning cached status (%s)\n",
317			  nt_errstr(last_dns_status) ));
318		return last_dns_status;
319	}
320
321	/* Send the Query */
322	do {
323		if ( buffer )
324			TALLOC_FREE( buffer );
325
326		buf_len = resp_len * sizeof(uint8);
327
328		if (buf_len) {
329			if ((buffer = TALLOC_ARRAY(ctx, uint8, buf_len))
330					== NULL ) {
331				DEBUG(0,("ads_dns_lookup_srv: "
332					"talloc() failed!\n"));
333				last_dns_status = NT_STATUS_NO_MEMORY;
334				last_dns_check = time(NULL);
335				return last_dns_status;
336			}
337		}
338
339		if ((resp_len = res_query(name, C_IN, q_type, buffer, buf_len))
340				< 0 ) {
341			DEBUG(3,("ads_dns_lookup_srv: "
342				"Failed to resolve %s (%s)\n",
343				name, strerror(errno)));
344			TALLOC_FREE( buffer );
345			last_dns_status = NT_STATUS_UNSUCCESSFUL;
346
347			if (errno == ETIMEDOUT) {
348				last_dns_status = NT_STATUS_IO_TIMEOUT;
349			}
350			if (errno == ECONNREFUSED) {
351				last_dns_status = NT_STATUS_CONNECTION_REFUSED;
352			}
353			last_dns_check = time(NULL);
354			return last_dns_status;
355		}
356
357		/* On AIX, Solaris, and possibly some older glibc systems (e.g. SLES8)
358		   truncated replies never give back a resp_len > buflen
359		   which ends up causing DNS resolve failures on large tcp DNS replies */
360
361		if (buf_len == resp_len) {
362			if (resp_len == MAX_DNS_PACKET_SIZE) {
363				DEBUG(1,("dns_send_req: DNS reply too large when resolving %s\n",
364					name));
365				TALLOC_FREE( buffer );
366				last_dns_status = NT_STATUS_BUFFER_TOO_SMALL;
367				last_dns_check = time(NULL);
368				return last_dns_status;
369			}
370
371			resp_len = MIN(resp_len*2, MAX_DNS_PACKET_SIZE);
372		}
373
374
375	} while ( buf_len < resp_len && resp_len <= MAX_DNS_PACKET_SIZE );
376
377	*buf = buffer;
378	*resp_length = resp_len;
379
380	last_dns_check = time(NULL);
381	last_dns_status = NT_STATUS_OK;
382	return last_dns_status;
383}
384
385/*********************************************************************
386 Simple wrapper for a DNS SRV query
387*********************************************************************/
388
389static NTSTATUS ads_dns_lookup_srv( TALLOC_CTX *ctx,
390				const char *name,
391				struct dns_rr_srv **dclist,
392				int *numdcs)
393{
394	uint8 *buffer = NULL;
395	int resp_len = 0;
396	struct dns_rr_srv *dcs = NULL;
397	int query_count, answer_count, auth_count, additional_count;
398	uint8 *p = buffer;
399	int rrnum;
400	int idx = 0;
401	NTSTATUS status;
402
403	if ( !ctx || !name || !dclist ) {
404		return NT_STATUS_INVALID_PARAMETER;
405	}
406
407	/* Send the request.  May have to loop several times in case
408	   of large replies */
409
410	status = dns_send_req( ctx, name, T_SRV, &buffer, &resp_len );
411	if ( !NT_STATUS_IS_OK(status) ) {
412		DEBUG(3,("ads_dns_lookup_srv: Failed to send DNS query (%s)\n",
413			nt_errstr(status)));
414		return status;
415	}
416	p = buffer;
417
418	/* For some insane reason, the ns_initparse() et. al. routines are only
419	   available in libresolv.a, and not the shared lib.  Who knows why....
420	   So we have to parse the DNS reply ourselves */
421
422	/* Pull the answer RR's count from the header.
423	 * Use the NMB ordering macros */
424
425	query_count      = RSVAL( p, 4 );
426	answer_count     = RSVAL( p, 6 );
427	auth_count       = RSVAL( p, 8 );
428	additional_count = RSVAL( p, 10 );
429
430	DEBUG(4,("ads_dns_lookup_srv: "
431		"%d records returned in the answer section.\n",
432		answer_count));
433
434	if (answer_count) {
435		if ((dcs = TALLOC_ZERO_ARRAY(ctx, struct dns_rr_srv,
436						answer_count)) == NULL ) {
437			DEBUG(0,("ads_dns_lookup_srv: "
438				"talloc() failure for %d char*'s\n",
439				answer_count));
440			return NT_STATUS_NO_MEMORY;
441		}
442	} else {
443		dcs = NULL;
444	}
445
446	/* now skip the header */
447
448	p += NS_HFIXEDSZ;
449
450	/* parse the query section */
451
452	for ( rrnum=0; rrnum<query_count; rrnum++ ) {
453		struct dns_query q;
454
455		if (!ads_dns_parse_query(ctx, buffer,
456					buffer+resp_len, &p, &q)) {
457			DEBUG(1,("ads_dns_lookup_srv: "
458				 "Failed to parse query record [%d]!\n", rrnum));
459			return NT_STATUS_UNSUCCESSFUL;
460		}
461	}
462
463	/* now we are at the answer section */
464
465	for ( rrnum=0; rrnum<answer_count; rrnum++ ) {
466		if (!ads_dns_parse_rr_srv(ctx, buffer, buffer+resp_len,
467					&p, &dcs[rrnum])) {
468			DEBUG(1,("ads_dns_lookup_srv: "
469				 "Failed to parse answer recordi [%d]!\n", rrnum));
470			return NT_STATUS_UNSUCCESSFUL;
471		}
472	}
473	idx = rrnum;
474
475	/* Parse the authority section */
476	/* just skip these for now */
477
478	for ( rrnum=0; rrnum<auth_count; rrnum++ ) {
479		struct dns_rr rr;
480
481		if (!ads_dns_parse_rr( ctx, buffer,
482					buffer+resp_len, &p, &rr)) {
483			DEBUG(1,("ads_dns_lookup_srv: "
484				 "Failed to parse authority record! [%d]\n", rrnum));
485			return NT_STATUS_UNSUCCESSFUL;
486		}
487	}
488
489	/* Parse the additional records section */
490
491	for ( rrnum=0; rrnum<additional_count; rrnum++ ) {
492		struct dns_rr rr;
493		int i;
494
495		if (!ads_dns_parse_rr(ctx, buffer, buffer+resp_len,
496					&p, &rr)) {
497			DEBUG(1,("ads_dns_lookup_srv: Failed "
498				 "to parse additional records section! [%d]\n", rrnum));
499			return NT_STATUS_UNSUCCESSFUL;
500		}
501
502		/* Only interested in A or AAAA records as a shortcut for having
503		 * to come back later and lookup the name. For multi-homed
504		 * hosts, the number of additional records and exceed the
505		 * number of answer records. */
506
507		if (rr.type != T_A || rr.rdatalen != 4) {
508#if defined(HAVE_IPV6)
509			/* RFC2874 defines A6 records. This
510			 * requires recusive and horribly complex lookups.
511			 * Bastards. Ignore this for now.... JRA.
512			 * Luckily RFC3363 reprecates A6 records.
513			 */
514			if (rr.type != T_AAAA || rr.rdatalen != 16)
515#endif
516				continue;
517		}
518
519		for ( i=0; i<idx; i++ ) {
520			if ( strcmp( rr.hostname, dcs[i].hostname ) == 0 ) {
521				int num_ips = dcs[i].num_ips;
522				struct sockaddr_storage *tmp_ss_s;
523
524				/* allocate new memory */
525
526				if (dcs[i].num_ips == 0) {
527					if ((dcs[i].ss_s = TALLOC_ARRAY(dcs,
528						struct sockaddr_storage, 1 ))
529							== NULL ) {
530						return NT_STATUS_NO_MEMORY;
531					}
532				} else {
533					if ((tmp_ss_s = TALLOC_REALLOC_ARRAY(dcs,
534							dcs[i].ss_s,
535							struct sockaddr_storage,
536							dcs[i].num_ips+1))
537								== NULL ) {
538						return NT_STATUS_NO_MEMORY;
539					}
540
541					dcs[i].ss_s = tmp_ss_s;
542				}
543				dcs[i].num_ips++;
544
545				/* copy the new IP address */
546				if (rr.type == T_A) {
547					struct in_addr ip;
548					memcpy(&ip, rr.rdata, 4);
549					in_addr_to_sockaddr_storage(
550							&dcs[i].ss_s[num_ips],
551							ip);
552				}
553#if defined(HAVE_IPV6)
554				if (rr.type == T_AAAA) {
555					struct in6_addr ip6;
556					memcpy(&ip6, rr.rdata, rr.rdatalen);
557					in6_addr_to_sockaddr_storage(
558							&dcs[i].ss_s[num_ips],
559							ip6);
560				}
561#endif
562			}
563		}
564	}
565
566	qsort( dcs, idx, sizeof(struct dns_rr_srv), QSORT_CAST dnssrvcmp );
567
568	*dclist = dcs;
569	*numdcs = idx;
570
571	return NT_STATUS_OK;
572}
573
574/*********************************************************************
575 Simple wrapper for a DNS NS query
576*********************************************************************/
577
578NTSTATUS ads_dns_lookup_ns(TALLOC_CTX *ctx,
579				const char *dnsdomain,
580				struct dns_rr_ns **nslist,
581				int *numns)
582{
583	uint8 *buffer = NULL;
584	int resp_len = 0;
585	struct dns_rr_ns *nsarray = NULL;
586	int query_count, answer_count, auth_count, additional_count;
587	uint8 *p;
588	int rrnum;
589	int idx = 0;
590	NTSTATUS status;
591
592	if ( !ctx || !dnsdomain || !nslist ) {
593		return NT_STATUS_INVALID_PARAMETER;
594	}
595
596	/* Send the request.  May have to loop several times in case
597	   of large replies */
598
599	status = dns_send_req( ctx, dnsdomain, T_NS, &buffer, &resp_len );
600	if ( !NT_STATUS_IS_OK(status) ) {
601		DEBUG(3,("ads_dns_lookup_ns: Failed to send DNS query (%s)\n",
602			nt_errstr(status)));
603		return status;
604	}
605	p = buffer;
606
607	/* For some insane reason, the ns_initparse() et. al. routines are only
608	   available in libresolv.a, and not the shared lib.  Who knows why....
609	   So we have to parse the DNS reply ourselves */
610
611	/* Pull the answer RR's count from the header.
612	 * Use the NMB ordering macros */
613
614	query_count      = RSVAL( p, 4 );
615	answer_count     = RSVAL( p, 6 );
616	auth_count       = RSVAL( p, 8 );
617	additional_count = RSVAL( p, 10 );
618
619	DEBUG(4,("ads_dns_lookup_ns: "
620		"%d records returned in the answer section.\n",
621		answer_count));
622
623	if (answer_count) {
624		if ((nsarray = TALLOC_ARRAY(ctx, struct dns_rr_ns,
625						answer_count)) == NULL ) {
626			DEBUG(0,("ads_dns_lookup_ns: "
627				"talloc() failure for %d char*'s\n",
628				answer_count));
629			return NT_STATUS_NO_MEMORY;
630		}
631	} else {
632		nsarray = NULL;
633	}
634
635	/* now skip the header */
636
637	p += NS_HFIXEDSZ;
638
639	/* parse the query section */
640
641	for ( rrnum=0; rrnum<query_count; rrnum++ ) {
642		struct dns_query q;
643
644		if (!ads_dns_parse_query(ctx, buffer, buffer+resp_len,
645					&p, &q)) {
646			DEBUG(1,("ads_dns_lookup_ns: "
647				" Failed to parse query record!\n"));
648			return NT_STATUS_UNSUCCESSFUL;
649		}
650	}
651
652	/* now we are at the answer section */
653
654	for ( rrnum=0; rrnum<answer_count; rrnum++ ) {
655		if (!ads_dns_parse_rr_ns(ctx, buffer, buffer+resp_len,
656					&p, &nsarray[rrnum])) {
657			DEBUG(1,("ads_dns_lookup_ns: "
658				"Failed to parse answer record!\n"));
659			return NT_STATUS_UNSUCCESSFUL;
660		}
661	}
662	idx = rrnum;
663
664	/* Parse the authority section */
665	/* just skip these for now */
666
667	for ( rrnum=0; rrnum<auth_count; rrnum++ ) {
668		struct dns_rr rr;
669
670		if ( !ads_dns_parse_rr(ctx, buffer, buffer+resp_len,
671					&p, &rr)) {
672			DEBUG(1,("ads_dns_lookup_ns: "
673				"Failed to parse authority record!\n"));
674			return NT_STATUS_UNSUCCESSFUL;
675		}
676	}
677
678	/* Parse the additional records section */
679
680	for ( rrnum=0; rrnum<additional_count; rrnum++ ) {
681		struct dns_rr rr;
682		int i;
683
684		if (!ads_dns_parse_rr(ctx, buffer, buffer+resp_len,
685					&p, &rr)) {
686			DEBUG(1,("ads_dns_lookup_ns: Failed "
687				"to parse additional records section!\n"));
688			return NT_STATUS_UNSUCCESSFUL;
689		}
690
691		/* only interested in A records as a shortcut for having to come
692		   back later and lookup the name */
693
694		if (rr.type != T_A || rr.rdatalen != 4) {
695#if defined(HAVE_IPV6)
696			if (rr.type != T_AAAA || rr.rdatalen != 16)
697#endif
698				continue;
699		}
700
701		for ( i=0; i<idx; i++ ) {
702			if (strcmp(rr.hostname, nsarray[i].hostname) == 0) {
703				if (rr.type == T_A) {
704					struct in_addr ip;
705					memcpy(&ip, rr.rdata, 4);
706					in_addr_to_sockaddr_storage(
707							&nsarray[i].ss,
708							ip);
709				}
710#if defined(HAVE_IPV6)
711				if (rr.type == T_AAAA) {
712					struct in6_addr ip6;
713					memcpy(&ip6, rr.rdata, rr.rdatalen);
714					in6_addr_to_sockaddr_storage(
715							&nsarray[i].ss,
716							ip6);
717				}
718#endif
719			}
720		}
721	}
722
723	*nslist = nsarray;
724	*numns = idx;
725
726	return NT_STATUS_OK;
727}
728
729/****************************************************************************
730 Store and fetch the AD client sitename.
731****************************************************************************/
732
733#define SITENAME_KEY	"AD_SITENAME/DOMAIN/%s"
734
735static char *sitename_key(const char *realm)
736{
737	char *keystr;
738
739	if (asprintf_strupper_m(&keystr, SITENAME_KEY, realm) == -1) {
740		return NULL;
741	}
742
743	return keystr;
744}
745
746
747/****************************************************************************
748 Store the AD client sitename.
749 We store indefinately as every new CLDAP query will re-write this.
750****************************************************************************/
751
752bool sitename_store(const char *realm, const char *sitename)
753{
754	time_t expire;
755	bool ret = False;
756	char *key;
757
758	if (!realm || (strlen(realm) == 0)) {
759		DEBUG(0,("sitename_store: no realm\n"));
760		return False;
761	}
762
763	key = sitename_key(realm);
764
765	if (!sitename || (sitename && !*sitename)) {
766		DEBUG(5,("sitename_store: deleting empty sitename!\n"));
767		ret = gencache_del(key);
768		SAFE_FREE(key);
769		return ret;
770	}
771
772	expire = get_time_t_max(); /* Store indefinately. */
773
774	DEBUG(10,("sitename_store: realm = [%s], sitename = [%s], expire = [%u]\n",
775		realm, sitename, (unsigned int)expire ));
776
777	ret = gencache_set( key, sitename, expire );
778	SAFE_FREE(key);
779	return ret;
780}
781
782/****************************************************************************
783 Fetch the AD client sitename.
784 Caller must free.
785****************************************************************************/
786
787char *sitename_fetch(const char *realm)
788{
789	char *sitename = NULL;
790	time_t timeout;
791	bool ret = False;
792	const char *query_realm;
793	char *key;
794
795	if (!realm || (strlen(realm) == 0)) {
796		query_realm = lp_realm();
797	} else {
798		query_realm = realm;
799	}
800
801	key = sitename_key(query_realm);
802
803	ret = gencache_get( key, &sitename, &timeout );
804	SAFE_FREE(key);
805	if ( !ret ) {
806		DEBUG(5,("sitename_fetch: No stored sitename for %s\n",
807			query_realm));
808	} else {
809		DEBUG(5,("sitename_fetch: Returning sitename for %s: \"%s\"\n",
810			query_realm, sitename ));
811	}
812	return sitename;
813}
814
815/****************************************************************************
816 Did the sitename change ?
817****************************************************************************/
818
819bool stored_sitename_changed(const char *realm, const char *sitename)
820{
821	bool ret = False;
822
823	char *new_sitename;
824
825	if (!realm || (strlen(realm) == 0)) {
826		DEBUG(0,("stored_sitename_changed: no realm\n"));
827		return False;
828	}
829
830	new_sitename = sitename_fetch(realm);
831
832	if (sitename && new_sitename && !strequal(sitename, new_sitename)) {
833		ret = True;
834	} else if ((sitename && !new_sitename) ||
835			(!sitename && new_sitename)) {
836		ret = True;
837	}
838	SAFE_FREE(new_sitename);
839	return ret;
840}
841
842/********************************************************************
843 Query with optional sitename.
844********************************************************************/
845
846static NTSTATUS ads_dns_query_internal(TALLOC_CTX *ctx,
847				       const char *servicename,
848				       const char *dc_pdc_gc_domains,
849				       const char *realm,
850				       const char *sitename,
851				       struct dns_rr_srv **dclist,
852				       int *numdcs )
853{
854	char *name;
855	if (sitename) {
856		name = talloc_asprintf(ctx, "%s._tcp.%s._sites.%s._msdcs.%s",
857				       servicename, sitename,
858				       dc_pdc_gc_domains, realm);
859  	} else {
860		name = talloc_asprintf(ctx, "%s._tcp.%s._msdcs.%s",
861				servicename, dc_pdc_gc_domains, realm);
862  	}
863	if (!name) {
864		return NT_STATUS_NO_MEMORY;
865	}
866	return ads_dns_lookup_srv( ctx, name, dclist, numdcs );
867}
868
869/********************************************************************
870 Query for AD DC's.
871********************************************************************/
872
873NTSTATUS ads_dns_query_dcs(TALLOC_CTX *ctx,
874			   const char *realm,
875			   const char *sitename,
876			   struct dns_rr_srv **dclist,
877			   int *numdcs )
878{
879	NTSTATUS status;
880
881	status = ads_dns_query_internal(ctx, "_ldap", "dc", realm, sitename,
882					dclist, numdcs);
883
884	if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
885	    NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_REFUSED)) {
886		return status;
887	}
888
889	if (sitename &&
890	    ((!NT_STATUS_IS_OK(status)) ||
891	     (NT_STATUS_IS_OK(status) && (numdcs == 0)))) {
892		/* Sitename DNS query may have failed. Try without. */
893		status = ads_dns_query_internal(ctx, "_ldap", "dc", realm,
894						NULL, dclist, numdcs);
895	}
896	return status;
897}
898
899/********************************************************************
900 Query for AD GC's.
901********************************************************************/
902
903NTSTATUS ads_dns_query_gcs(TALLOC_CTX *ctx,
904			   const char *realm,
905			   const char *sitename,
906			   struct dns_rr_srv **dclist,
907			   int *numdcs )
908{
909	NTSTATUS status;
910
911	status = ads_dns_query_internal(ctx, "_ldap", "gc", realm, sitename,
912					dclist, numdcs);
913
914	if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
915	    NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_REFUSED)) {
916		return status;
917	}
918
919	if (sitename &&
920	    ((!NT_STATUS_IS_OK(status)) ||
921	     (NT_STATUS_IS_OK(status) && (numdcs == 0)))) {
922		/* Sitename DNS query may have failed. Try without. */
923		status = ads_dns_query_internal(ctx, "_ldap", "gc", realm,
924						NULL, dclist, numdcs);
925	}
926	return status;
927}
928
929/********************************************************************
930 Query for AD KDC's.
931 Even if our underlying kerberos libraries are UDP only, this
932 is pretty safe as it's unlikely that a KDC supports TCP and not UDP.
933********************************************************************/
934
935NTSTATUS ads_dns_query_kdcs(TALLOC_CTX *ctx,
936			    const char *dns_forest_name,
937			    const char *sitename,
938			    struct dns_rr_srv **dclist,
939			    int *numdcs )
940{
941	NTSTATUS status;
942
943	status = ads_dns_query_internal(ctx, "_kerberos", "dc",
944					dns_forest_name, sitename, dclist,
945					numdcs);
946
947	if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
948	    NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_REFUSED)) {
949		return status;
950	}
951
952	if (sitename &&
953	    ((!NT_STATUS_IS_OK(status)) ||
954	     (NT_STATUS_IS_OK(status) && (numdcs == 0)))) {
955		/* Sitename DNS query may have failed. Try without. */
956		status = ads_dns_query_internal(ctx, "_kerberos", "dc",
957						dns_forest_name, NULL,
958						dclist, numdcs);
959	}
960	return status;
961}
962
963/********************************************************************
964 Query for AD PDC. Sitename is obsolete here.
965********************************************************************/
966
967NTSTATUS ads_dns_query_pdc(TALLOC_CTX *ctx,
968			   const char *dns_domain_name,
969			   struct dns_rr_srv **dclist,
970			   int *numdcs )
971{
972	return ads_dns_query_internal(ctx, "_ldap", "pdc", dns_domain_name,
973				      NULL, dclist, numdcs);
974}
975
976/********************************************************************
977 Query for AD DC by guid. Sitename is obsolete here.
978********************************************************************/
979
980NTSTATUS ads_dns_query_dcs_guid(TALLOC_CTX *ctx,
981				const char *dns_forest_name,
982				const struct GUID *domain_guid,
983				struct dns_rr_srv **dclist,
984				int *numdcs )
985{
986	/*_ldap._tcp.DomainGuid.domains._msdcs.DnsForestName */
987
988	const char *domains;
989	char *guid_string;
990
991	guid_string = GUID_string(ctx, domain_guid);
992	if (!guid_string) {
993		return NT_STATUS_NO_MEMORY;
994	}
995
996	/* little hack */
997	domains = talloc_asprintf(ctx, "%s.domains", guid_string);
998	if (!domains) {
999		return NT_STATUS_NO_MEMORY;
1000	}
1001	TALLOC_FREE(guid_string);
1002
1003	return ads_dns_query_internal(ctx, "_ldap", domains, dns_forest_name,
1004				      NULL, dclist, numdcs);
1005}
1006