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