1 /*
2    Unix SMB/CIFS implementation.
3    DNS utility library
4    Copyright (C) Gerald (Jerry) Carter           2006.
5    Copyright (C) Jeremy Allison                  2007.
6 
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11 
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20 
21 #include "includes.h"
22 #include "lib/util/util_net.h"
23 #include "lib/util/tsort.h"
24 #include "librpc/gen_ndr/dns.h"
25 #include "libcli/dns/dns_lookup.h"
26 #include "lib/util/tevent_ntstatus.h"
27 #include "dnsquery.h"
28 
29 /*********************************************************************
30  Sort SRV record list based on weight and priority.  See RFC 2782.
31 *********************************************************************/
32 
dnssrvcmp(struct dns_rr_srv * a,struct dns_rr_srv * b)33 static int dnssrvcmp( struct dns_rr_srv *a, struct dns_rr_srv *b )
34 {
35 	if ( a->priority == b->priority ) {
36 
37 		/* randomize entries with an equal weight and priority */
38 		if ( a->weight == b->weight )
39 			return 0;
40 
41 		/* higher weights should be sorted lower */
42 		if ( a->weight > b->weight )
43 			return -1;
44 		else
45 			return 1;
46 	}
47 
48 	if ( a->priority < b->priority )
49 		return -1;
50 
51 	return 1;
52 }
53 
54 struct ads_dns_lookup_srv_state {
55 	struct dns_rr_srv *srvs;
56 	size_t num_srvs;
57 };
58 
59 static void ads_dns_lookup_srv_done(struct tevent_req *subreq);
60 
ads_dns_lookup_srv_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,const char * name)61 struct tevent_req *ads_dns_lookup_srv_send(TALLOC_CTX *mem_ctx,
62 					   struct tevent_context *ev,
63 					   const char *name)
64 {
65 	struct tevent_req *req, *subreq;
66 	struct ads_dns_lookup_srv_state *state;
67 
68 	req = tevent_req_create(mem_ctx, &state,
69 				struct ads_dns_lookup_srv_state);
70 	if (req == NULL) {
71 		return NULL;
72 	}
73 
74 	subreq = dns_lookup_send(
75 		state,
76 		ev,
77 		NULL,
78 		name,
79 		DNS_QCLASS_IN,
80 		DNS_QTYPE_SRV);
81 
82 	if (tevent_req_nomem(subreq, req)) {
83 		return tevent_req_post(req, ev);
84 	}
85 	tevent_req_set_callback(subreq, ads_dns_lookup_srv_done, req);
86 	return req;
87 }
88 
ads_dns_lookup_srv_done(struct tevent_req * subreq)89 static void ads_dns_lookup_srv_done(struct tevent_req *subreq)
90 {
91 	struct tevent_req *req = tevent_req_callback_data(
92 		subreq, struct tevent_req);
93 	struct ads_dns_lookup_srv_state *state = tevent_req_data(
94 		req, struct ads_dns_lookup_srv_state);
95 	int ret;
96 	struct dns_name_packet *reply;
97 	uint16_t i, idx;
98 
99 	ret = dns_lookup_recv(subreq, state, &reply);
100 	TALLOC_FREE(subreq);
101 	if (ret != 0) {
102 		tevent_req_nterror(req, map_nt_error_from_unix_common(ret));
103 		return;
104 	}
105 
106 	for (i=0; i<reply->ancount; i++) {
107 		if (reply->answers[i].rr_type == DNS_QTYPE_SRV) {
108 			state->num_srvs += 1;
109 		}
110 	}
111 
112 	state->srvs = talloc_array(state, struct dns_rr_srv, state->num_srvs);
113 	if (tevent_req_nomem(state->srvs, req)) {
114 		return;
115 	}
116 
117 	idx = 0;
118 
119 	for (i=0; i<reply->ancount; i++) {
120 		struct dns_res_rec *an = &reply->answers[i];
121 		struct dns_rr_srv *dst = &state->srvs[idx];
122 		struct dns_srv_record *src;
123 
124 		if (an->rr_type != DNS_QTYPE_SRV) {
125 			continue;
126 		}
127 		src = &an->rdata.srv_record;
128 
129 		*dst = (struct dns_rr_srv) {
130 			.hostname = talloc_move(state->srvs, &src->target),
131 			.priority = src->priority,
132 			.weight = src->weight,
133 			.port = src->port,
134 		};
135 		idx += 1;
136 	}
137 
138 	for (i=0; i<reply->arcount; i++) {
139 		struct dns_res_rec *ar = &reply->additional[i];
140 		struct sockaddr_storage addr;
141 		bool ok;
142 		size_t j;
143 
144 		ok = dns_res_rec_get_sockaddr(ar, &addr);
145 		if (!ok) {
146 			continue;
147 		}
148 
149 		for (j=0; j<state->num_srvs; j++) {
150 			struct dns_rr_srv *srv = &state->srvs[j];
151 			struct sockaddr_storage *tmp;
152 
153 			if (strcmp(srv->hostname, ar->name) != 0) {
154 				continue;
155 			}
156 
157 			tmp = talloc_realloc(
158 				state->srvs,
159 				srv->ss_s,
160 				struct sockaddr_storage,
161 				srv->num_ips+1);
162 
163 			if (tevent_req_nomem(tmp, req)) {
164 				return;
165 			}
166 			srv->ss_s = tmp;
167 
168 			srv->ss_s[srv->num_ips] = addr;
169 			srv->num_ips += 1;
170 		}
171 	}
172 
173 	TYPESAFE_QSORT(state->srvs, state->num_srvs, dnssrvcmp);
174 
175 	tevent_req_done(req);
176 }
177 
ads_dns_lookup_srv_recv(struct tevent_req * req,TALLOC_CTX * mem_ctx,struct dns_rr_srv ** srvs,size_t * num_srvs)178 NTSTATUS ads_dns_lookup_srv_recv(struct tevent_req *req,
179 				 TALLOC_CTX *mem_ctx,
180 				 struct dns_rr_srv **srvs,
181 				 size_t *num_srvs)
182 {
183 	struct ads_dns_lookup_srv_state *state = tevent_req_data(
184 		req, struct ads_dns_lookup_srv_state);
185 	NTSTATUS status;
186 
187 	if (tevent_req_is_nterror(req, &status)) {
188 		return status;
189 	}
190 	*srvs = talloc_move(mem_ctx, &state->srvs);
191 	*num_srvs = state->num_srvs;
192 	tevent_req_received(req);
193 	return NT_STATUS_OK;
194 }
195 
196 /*********************************************************************
197  Simple wrapper for a DNS SRV query
198 *********************************************************************/
199 
ads_dns_lookup_srv(TALLOC_CTX * ctx,const char * name,struct dns_rr_srv ** dclist,int * numdcs)200 NTSTATUS ads_dns_lookup_srv(TALLOC_CTX *ctx,
201 				const char *name,
202 				struct dns_rr_srv **dclist,
203 				int *numdcs)
204 {
205 	struct tevent_context *ev;
206 	struct tevent_req *req;
207 	NTSTATUS status = NT_STATUS_NO_MEMORY;
208 	size_t num_srvs = 0;
209 
210 	ev = samba_tevent_context_init(ctx);
211 	if (ev == NULL) {
212 		goto fail;
213 	}
214 	req = ads_dns_lookup_srv_send(ev, ev, name);
215 	if (req == NULL) {
216 		goto fail;
217 	}
218 	if (!tevent_req_poll_ntstatus(req, ev, &status)) {
219 		goto fail;
220 	}
221 	status = ads_dns_lookup_srv_recv(req, ctx, dclist, &num_srvs);
222 	if (NT_STATUS_IS_OK(status)) {
223 		*numdcs = num_srvs;	/* size_t->int */
224 	}
225 fail:
226 	TALLOC_FREE(ev);
227 	return status;
228 }
229 
230 struct ads_dns_lookup_ns_state {
231 	struct dns_rr_ns *nss;
232 	size_t num_nss;
233 };
234 
235 static void ads_dns_lookup_ns_done(struct tevent_req *subreq);
236 
ads_dns_lookup_ns_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,const char * name)237 struct tevent_req *ads_dns_lookup_ns_send(TALLOC_CTX *mem_ctx,
238 					  struct tevent_context *ev,
239 					  const char *name)
240 {
241 	struct tevent_req *req, *subreq;
242 	struct ads_dns_lookup_ns_state *state;
243 
244 	req = tevent_req_create(mem_ctx, &state,
245 				struct ads_dns_lookup_ns_state);
246 	if (req == NULL) {
247 		return NULL;
248 	}
249 
250 	subreq = dns_lookup_send(state, ev, NULL, name, DNS_QCLASS_IN,
251 				 DNS_QTYPE_NS);
252 	if (tevent_req_nomem(subreq, req)) {
253 		return tevent_req_post(req, ev);
254 	}
255 	tevent_req_set_callback(subreq, ads_dns_lookup_ns_done, req);
256 	return req;
257 }
258 
ads_dns_lookup_ns_done(struct tevent_req * subreq)259 static void ads_dns_lookup_ns_done(struct tevent_req *subreq)
260 {
261 	struct tevent_req *req = tevent_req_callback_data(
262 		subreq, struct tevent_req);
263 	struct ads_dns_lookup_ns_state *state = tevent_req_data(
264 		req, struct ads_dns_lookup_ns_state);
265 	int ret;
266 	struct dns_name_packet *reply;
267 	uint16_t i, idx;
268 
269 	ret = dns_lookup_recv(subreq, state, &reply);
270 	TALLOC_FREE(subreq);
271 	if (ret != 0) {
272 		tevent_req_nterror(req, map_nt_error_from_unix_common(ret));
273 		return;
274 	}
275 
276 	for (i=0; i<reply->ancount; i++) {
277 		if (reply->answers[i].rr_type == DNS_QTYPE_NS) {
278 			state->num_nss += 1;
279 		}
280 	}
281 
282 	state->nss = talloc_array(state, struct dns_rr_ns, state->num_nss);
283 	if (tevent_req_nomem(state->nss, req)) {
284 		return;
285 	}
286 
287 	idx = 0;
288 
289 	for (i=0; i<reply->ancount; i++) {
290 		struct dns_res_rec *an = &reply->answers[i];
291 
292 		if (an->rr_type != DNS_QTYPE_NS) {
293 			continue;
294 		}
295 
296 		state->nss[idx].hostname = talloc_move(state->nss,
297 						       &an->rdata.ns_record);
298 		idx += 1;
299 	}
300 
301 	for (i=0; i<reply->arcount; i++) {
302 		struct dns_res_rec *ar = &reply->additional[i];
303 		struct sockaddr_storage addr;
304 		bool ok;
305 		size_t j;
306 
307 		ok = dns_res_rec_get_sockaddr(ar, &addr);
308 		if (!ok) {
309 			continue;
310 		}
311 
312 		for (j=0; j<state->num_nss; j++) {
313 			struct dns_rr_ns *ns = &state->nss[j];
314 
315 			if (strcmp(ns->hostname, ar->name) == 0) {
316 				ns->ss = addr;
317 			}
318 		}
319 	}
320 
321 	tevent_req_done(req);
322 }
323 
ads_dns_lookup_ns_recv(struct tevent_req * req,TALLOC_CTX * mem_ctx,struct dns_rr_ns ** nss,size_t * num_nss)324 NTSTATUS ads_dns_lookup_ns_recv(struct tevent_req *req,
325 				TALLOC_CTX *mem_ctx,
326 				struct dns_rr_ns **nss,
327 				size_t *num_nss)
328 {
329 	struct ads_dns_lookup_ns_state *state = tevent_req_data(
330 		req, struct ads_dns_lookup_ns_state);
331 	NTSTATUS status;
332 
333 	if (tevent_req_is_nterror(req, &status)) {
334 		return status;
335 	}
336 	*nss = talloc_move(mem_ctx, &state->nss);
337 	*num_nss = state->num_nss;
338 	tevent_req_received(req);
339 	return NT_STATUS_OK;
340 }
341 
342 /*********************************************************************
343  Simple wrapper for a DNS NS query
344 *********************************************************************/
345 
ads_dns_lookup_ns(TALLOC_CTX * ctx,const char * dnsdomain,struct dns_rr_ns ** nslist,int * numns)346 NTSTATUS ads_dns_lookup_ns(TALLOC_CTX *ctx,
347 				const char *dnsdomain,
348 				struct dns_rr_ns **nslist,
349 				int *numns)
350 {
351 	struct tevent_context *ev;
352 	struct tevent_req *req;
353 	NTSTATUS status = NT_STATUS_NO_MEMORY;
354 	size_t num_ns = 0;
355 
356 	ev = samba_tevent_context_init(ctx);
357 	if (ev == NULL) {
358 		goto fail;
359 	}
360 	req = ads_dns_lookup_ns_send(ev, ev, dnsdomain);
361 	if (req == NULL) {
362 		goto fail;
363 	}
364 	if (!tevent_req_poll_ntstatus(req, ev, &status)) {
365 		goto fail;
366 	}
367 	status = ads_dns_lookup_ns_recv(req, ctx, nslist, &num_ns);
368 	*numns = num_ns;
369 fail:
370 	TALLOC_FREE(ev);
371 	return status;
372 }
373 
374 
375 /********************************************************************
376  Query with optional sitename.
377 ********************************************************************/
378 
ads_dns_query_internal(TALLOC_CTX * ctx,const char * servicename,const char * dc_pdc_gc_domains,const char * realm,const char * sitename,struct dns_rr_srv ** dclist,int * numdcs)379 static NTSTATUS ads_dns_query_internal(TALLOC_CTX *ctx,
380 				       const char *servicename,
381 				       const char *dc_pdc_gc_domains,
382 				       const char *realm,
383 				       const char *sitename,
384 				       struct dns_rr_srv **dclist,
385 				       int *numdcs )
386 {
387 	char *name;
388 	NTSTATUS status;
389 	int num_srvs = 0;
390 
391 	if ((sitename != NULL) && (strlen(sitename) != 0)) {
392 		name = talloc_asprintf(ctx, "%s._tcp.%s._sites.%s._msdcs.%s",
393 				       servicename, sitename,
394 				       dc_pdc_gc_domains, realm);
395 		if (name == NULL) {
396 			return NT_STATUS_NO_MEMORY;
397 		}
398 
399 		status = ads_dns_lookup_srv(ctx, name, dclist, &num_srvs);
400 
401 		TALLOC_FREE(name);
402 
403 		if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
404 		    NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_REFUSED)) {
405 			return status;
406 		}
407 
408 		if (NT_STATUS_IS_OK(status) && (num_srvs != 0)) {
409 			goto done;
410 		}
411 	}
412 
413 	name = talloc_asprintf(ctx, "%s._tcp.%s._msdcs.%s",
414 			       servicename, dc_pdc_gc_domains, realm);
415 	if (name == NULL) {
416 		return NT_STATUS_NO_MEMORY;
417 	}
418 	status = ads_dns_lookup_srv(ctx, name, dclist, &num_srvs);
419 
420 done:
421 	*numdcs = num_srvs; /* automatic conversion size_t->int */
422 	return status;
423 }
424 
425 /********************************************************************
426  Query for AD DC's.
427 ********************************************************************/
428 
ads_dns_query_dcs(TALLOC_CTX * ctx,const char * realm,const char * sitename,struct dns_rr_srv ** dclist,int * numdcs)429 NTSTATUS ads_dns_query_dcs(TALLOC_CTX *ctx,
430 			   const char *realm,
431 			   const char *sitename,
432 			   struct dns_rr_srv **dclist,
433 			   int *numdcs )
434 {
435 	NTSTATUS status;
436 
437 	status = ads_dns_query_internal(ctx,
438 					"_ldap",
439 					"dc",
440 					realm,
441 					sitename,
442 					dclist,
443 					numdcs);
444 	return status;
445 }
446 
447 /********************************************************************
448  Query for AD GC's.
449 ********************************************************************/
450 
ads_dns_query_gcs(TALLOC_CTX * ctx,const char * realm,const char * sitename,struct dns_rr_srv ** dclist,int * numdcs)451 NTSTATUS ads_dns_query_gcs(TALLOC_CTX *ctx,
452 			   const char *realm,
453 			   const char *sitename,
454 			   struct dns_rr_srv **dclist,
455 			   int *numdcs )
456 {
457 	NTSTATUS status;
458 
459 	status = ads_dns_query_internal(ctx,
460 					"_ldap",
461 					"gc",
462 					realm,
463 					sitename,
464 					dclist,
465 					numdcs);
466 	return status;
467 }
468 
469 /********************************************************************
470  Query for AD KDC's.
471  Even if our underlying kerberos libraries are UDP only, this
472  is pretty safe as it's unlikely that a KDC supports TCP and not UDP.
473 ********************************************************************/
474 
ads_dns_query_kdcs(TALLOC_CTX * ctx,const char * dns_forest_name,const char * sitename,struct dns_rr_srv ** dclist,int * numdcs)475 NTSTATUS ads_dns_query_kdcs(TALLOC_CTX *ctx,
476 			    const char *dns_forest_name,
477 			    const char *sitename,
478 			    struct dns_rr_srv **dclist,
479 			    int *numdcs )
480 {
481 	NTSTATUS status;
482 
483 	status = ads_dns_query_internal(ctx,
484 					"_kerberos",
485 					"dc",
486 					dns_forest_name,
487 					sitename,
488 					dclist,
489 					numdcs);
490 	return status;
491 }
492 
493 /********************************************************************
494  Query for AD PDC. Sitename is obsolete here.
495 ********************************************************************/
496 
ads_dns_query_pdc(TALLOC_CTX * ctx,const char * dns_domain_name,struct dns_rr_srv ** dclist,int * numdcs)497 NTSTATUS ads_dns_query_pdc(TALLOC_CTX *ctx,
498 			   const char *dns_domain_name,
499 			   struct dns_rr_srv **dclist,
500 			   int *numdcs )
501 {
502 	return ads_dns_query_internal(ctx,
503 				      "_ldap",
504 				      "pdc",
505 				      dns_domain_name,
506 				      NULL,
507 				      dclist,
508 				      numdcs);
509 }
510 
511 /********************************************************************
512  Query for AD DC by guid. Sitename is obsolete here.
513 ********************************************************************/
514 
ads_dns_query_dcs_guid(TALLOC_CTX * ctx,const char * dns_forest_name,const char * domain_guid,struct dns_rr_srv ** dclist,int * numdcs)515 NTSTATUS ads_dns_query_dcs_guid(TALLOC_CTX *ctx,
516 				const char *dns_forest_name,
517 				const char *domain_guid,
518 				struct dns_rr_srv **dclist,
519 				int *numdcs )
520 {
521 	/*_ldap._tcp.DomainGuid.domains._msdcs.DnsForestName */
522 
523 	const char *domains;
524 
525 	/* little hack */
526 	domains = talloc_asprintf(ctx, "%s.domains", domain_guid);
527 	if (!domains) {
528 		return NT_STATUS_NO_MEMORY;
529 	}
530 
531 	return ads_dns_query_internal(ctx,
532 				      "_ldap",
533 				      domains,
534 				      dns_forest_name,
535 				      NULL,
536 				      dclist,
537 				      numdcs);
538 }
539