vfs_aixacl2: Fix "mem_ctx" and "ppdesc" smb_fget_nt_acl_nfs4 args
[samba.git] / libcli / dns / dns.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Small async DNS library for Samba with socketwrapper support
5
6    Copyright (C) 2010 Kai Blin  <kai@samba.org>
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "replace.h"
23 #include "system/network.h"
24 #include <tevent.h>
25 #include "lib/tsocket/tsocket.h"
26 #include "libcli/dns/libdns.h"
27 #include "lib/util/tevent_unix.h"
28 #include "lib/util/samba_util.h"
29 #include "lib/util/debug.h"
30 #include "libcli/util/error.h"
31 #include "librpc/ndr/libndr.h"
32 #include "librpc/gen_ndr/ndr_dns.h"
33
34 struct dns_udp_request_state {
35         struct tevent_context *ev;
36         struct tdgram_context *dgram;
37         size_t query_len;
38         uint8_t *reply;
39         size_t reply_len;
40 };
41
42 #define DNS_REQUEST_TIMEOUT 10
43
44 /* Declare callback functions used below. */
45 static void dns_udp_request_get_reply(struct tevent_req *subreq);
46 static void dns_udp_request_done(struct tevent_req *subreq);
47
48 static struct tevent_req *dns_udp_request_send(TALLOC_CTX *mem_ctx,
49                                                struct tevent_context *ev,
50                                                const char *server_addr_string,
51                                                const uint8_t *query,
52                                                size_t query_len)
53 {
54         struct tevent_req *req, *subreq;
55         struct dns_udp_request_state *state;
56         struct tsocket_address *local_addr, *server_addr;
57         struct tdgram_context *dgram;
58         int ret;
59
60         req = tevent_req_create(mem_ctx, &state, struct dns_udp_request_state);
61         if (req == NULL) {
62                 return NULL;
63         }
64
65         state->ev = ev;
66
67         /* Use connected UDP sockets */
68         ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0,
69                                                 &local_addr);
70         if (ret != 0) {
71                 tevent_req_error(req, errno);
72                 return tevent_req_post(req, ev);
73         }
74
75         ret = tsocket_address_inet_from_strings(state, "ip", server_addr_string,
76                                                 DNS_SERVICE_PORT, &server_addr);
77         if (ret != 0) {
78                 tevent_req_error(req, errno);
79                 return tevent_req_post(req, ev);
80         }
81
82         ret = tdgram_inet_udp_socket(local_addr, server_addr, state, &dgram);
83         if (ret != 0) {
84                 tevent_req_error(req, errno);
85                 return tevent_req_post(req, ev);
86         }
87
88         state->dgram = dgram;
89         state->query_len = query_len;
90
91         dump_data(10, query, query_len);
92
93         subreq = tdgram_sendto_send(state, ev, dgram, query, query_len, NULL);
94         if (tevent_req_nomem(subreq, req)) {
95                 return tevent_req_post(req, ev);
96         }
97
98         if (!tevent_req_set_endtime(req, ev,
99                                 timeval_current_ofs(DNS_REQUEST_TIMEOUT, 0))) {
100                 return tevent_req_post(req, ev);
101         }
102
103         tevent_req_set_callback(subreq, dns_udp_request_get_reply, req);
104         return req;
105 }
106
107 static void dns_udp_request_get_reply(struct tevent_req *subreq)
108 {
109         struct tevent_req *req = tevent_req_callback_data(subreq,
110                                                 struct tevent_req);
111         struct dns_udp_request_state *state = tevent_req_data(req,
112                                                 struct dns_udp_request_state);
113         ssize_t len;
114         int err = 0;
115
116         len = tdgram_sendto_recv(subreq, &err);
117         TALLOC_FREE(subreq);
118
119         if (len == -1 && err != 0) {
120                 tevent_req_error(req, err);
121                 return;
122         }
123
124         if (len != state->query_len) {
125                 tevent_req_error(req, EIO);
126                 return;
127         }
128
129         subreq = tdgram_recvfrom_send(state, state->ev, state->dgram);
130         if (tevent_req_nomem(subreq, req)) {
131                 return;
132         }
133
134         tevent_req_set_callback(subreq, dns_udp_request_done, req);
135 }
136
137 static void dns_udp_request_done(struct tevent_req *subreq)
138 {
139         struct tevent_req *req = tevent_req_callback_data(subreq,
140                                                 struct tevent_req);
141         struct dns_udp_request_state *state = tevent_req_data(req,
142                                                 struct dns_udp_request_state);
143
144         ssize_t len;
145         int err = 0;
146
147         len = tdgram_recvfrom_recv(subreq, &err, state, &state->reply, NULL);
148         TALLOC_FREE(subreq);
149
150         if (len == -1 && err != 0) {
151                 tevent_req_error(req, err);
152                 return;
153         }
154
155         state->reply_len = len;
156         dump_data(10, state->reply, state->reply_len);
157         tevent_req_done(req);
158 }
159
160 static int dns_udp_request_recv(struct tevent_req *req,
161                                 TALLOC_CTX *mem_ctx,
162                                 uint8_t **reply,
163                                 size_t *reply_len)
164 {
165         struct dns_udp_request_state *state = tevent_req_data(req,
166                         struct dns_udp_request_state);
167         int err;
168
169         if (tevent_req_is_unix_error(req, &err)) {
170                 tevent_req_received(req);
171                 return err;
172         }
173
174         *reply = talloc_move(mem_ctx, &state->reply);
175         *reply_len = state->reply_len;
176         tevent_req_received(req);
177
178         return 0;
179 }
180
181 struct dns_tcp_request_state {
182         struct tevent_context *ev;
183         struct tstream_context *stream;
184         const uint8_t *query;
185         size_t query_len;
186
187         uint8_t dns_msglen_hdr[2];
188         struct iovec iov[2];
189
190         size_t nread;
191         uint8_t *reply;
192 };
193
194 static void dns_tcp_request_connected(struct tevent_req *subreq);
195 static void dns_tcp_request_sent(struct tevent_req *subreq);
196 static int dns_tcp_request_next_vector(struct tstream_context *stream,
197                                        void *private_data,
198                                        TALLOC_CTX *mem_ctx,
199                                        struct iovec **_vector,
200                                        size_t *_count);
201 static void dns_tcp_request_received(struct tevent_req *subreq);
202
203 static struct tevent_req *dns_tcp_request_send(TALLOC_CTX *mem_ctx,
204                                                struct tevent_context *ev,
205                                                const char *server_addr_string,
206                                                const uint8_t *query,
207                                                size_t query_len)
208 {
209         struct tevent_req *req, *subreq;
210         struct dns_tcp_request_state *state;
211         struct tsocket_address *local, *remote;
212         int ret;
213
214         req = tevent_req_create(mem_ctx, &state,
215                                 struct dns_tcp_request_state);
216         if (req == NULL) {
217                 return NULL;
218         }
219         state->ev = ev;
220         state->query = query;
221         state->query_len = query_len;
222
223         if (query_len > UINT16_MAX) {
224                 tevent_req_error(req, EMSGSIZE);
225                 return tevent_req_post(req, ev);
226         }
227
228         ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0, &local);
229         if (ret != 0) {
230                 tevent_req_error(req, errno);
231                 return tevent_req_post(req, ev);
232         }
233
234         ret = tsocket_address_inet_from_strings(
235                 state, "ip", server_addr_string, DNS_SERVICE_PORT, &remote);
236         if (ret != 0) {
237                 tevent_req_error(req, errno);
238                 return tevent_req_post(req, ev);
239         }
240
241         subreq = tstream_inet_tcp_connect_send(state, state->ev,
242                                                local, remote);
243         if (tevent_req_nomem(subreq, req)) {
244                 return tevent_req_post(req, ev);
245         }
246         tevent_req_set_callback(subreq, dns_tcp_request_connected, req);
247
248         return req;
249 }
250
251 static void dns_tcp_request_connected(struct tevent_req *subreq)
252 {
253         struct tevent_req *req = tevent_req_callback_data(
254                 subreq, struct tevent_req);
255         struct dns_tcp_request_state *state = tevent_req_data(
256                 req, struct dns_tcp_request_state);
257         int ret, err;
258
259         ret = tstream_inet_tcp_connect_recv(subreq, &err, state,
260                                             &state->stream, NULL);
261         TALLOC_FREE(subreq);
262         if (ret == -1) {
263                 tevent_req_error(req, err);
264                 return;
265         }
266
267         RSSVAL(state->dns_msglen_hdr, 0, state->query_len);
268         state->iov[0] = (struct iovec) {
269                 .iov_base = state->dns_msglen_hdr,
270                 .iov_len = sizeof(state->dns_msglen_hdr)
271         };
272         state->iov[1] = (struct iovec) {
273                 .iov_base = discard_const_p(void, state->query),
274                 .iov_len = state->query_len
275         };
276
277         subreq = tstream_writev_send(state, state->ev, state->stream,
278                                      state->iov, ARRAY_SIZE(state->iov));
279         if (tevent_req_nomem(subreq, req)) {
280                 return;
281         }
282         tevent_req_set_callback(subreq, dns_tcp_request_sent, req);
283 }
284
285 static void dns_tcp_request_sent(struct tevent_req *subreq)
286 {
287         struct tevent_req *req = tevent_req_callback_data(
288                 subreq, struct tevent_req);
289         struct dns_tcp_request_state *state = tevent_req_data(
290                 req, struct dns_tcp_request_state);
291         int ret, err;
292
293         ret = tstream_writev_recv(subreq, &err);
294         TALLOC_FREE(subreq);
295         if (ret == -1) {
296                 tevent_req_error(req, err);
297                 return;
298         }
299
300         subreq = tstream_readv_pdu_send(state, state->ev, state->stream,
301                                         dns_tcp_request_next_vector, state);
302         if (tevent_req_nomem(subreq, req)) {
303                 return;
304         }
305         tevent_req_set_callback(subreq, dns_tcp_request_received, req);
306 }
307
308 static int dns_tcp_request_next_vector(struct tstream_context *stream,
309                                        void *private_data,
310                                        TALLOC_CTX *mem_ctx,
311                                        struct iovec **_vector,
312                                        size_t *_count)
313 {
314         struct dns_tcp_request_state *state = talloc_get_type_abort(
315                 private_data, struct dns_tcp_request_state);
316         struct iovec *vector;
317         uint16_t msglen;
318
319         if (state->nread == 0) {
320                 vector = talloc_array(mem_ctx, struct iovec, 1);
321                 if (vector == NULL) {
322                         return -1;
323                 }
324                 vector[0] = (struct iovec) {
325                         .iov_base = state->dns_msglen_hdr,
326                         .iov_len = sizeof(state->dns_msglen_hdr)
327                 };
328                 state->nread = sizeof(state->dns_msglen_hdr);
329
330                 *_vector = vector;
331                 *_count = 1;
332                 return 0;
333         }
334
335         if (state->nread == sizeof(state->dns_msglen_hdr)) {
336                 msglen = RSVAL(state->dns_msglen_hdr, 0);
337
338                 state->reply = talloc_array(state, uint8_t, msglen);
339                 if (state->reply == NULL) {
340                         return -1;
341                 }
342
343                 vector = talloc_array(mem_ctx, struct iovec, 1);
344                 if (vector == NULL) {
345                         return -1;
346                 }
347                 vector[0] = (struct iovec) {
348                         .iov_base = state->reply,
349                         .iov_len = msglen
350                 };
351                 state->nread += msglen;
352
353                 *_vector = vector;
354                 *_count = 1;
355                 return 0;
356         }
357
358         *_vector = NULL;
359         *_count = 0;
360         return 0;
361 }
362
363 static void dns_tcp_request_received(struct tevent_req *subreq)
364 {
365         struct tevent_req *req = tevent_req_callback_data(
366                 subreq, struct tevent_req);
367         int ret, err;
368
369         ret = tstream_readv_pdu_recv(subreq, &err);
370         TALLOC_FREE(subreq);
371         if (ret == -1) {
372                 tevent_req_error(req, err);
373                 return;
374         }
375
376         tevent_req_done(req);
377 }
378
379 static int dns_tcp_request_recv(struct tevent_req *req,
380                                 TALLOC_CTX *mem_ctx,
381                                 uint8_t **reply,
382                                 size_t *reply_len)
383 {
384         struct dns_tcp_request_state *state = tevent_req_data(
385                 req, struct dns_tcp_request_state);
386         int err;
387
388         if (tevent_req_is_unix_error(req, &err)) {
389                 tevent_req_received(req);
390                 return err;
391         }
392
393         *reply_len = talloc_array_length(state->reply);
394         *reply = talloc_move(mem_ctx, &state->reply);
395         tevent_req_received(req);
396
397         return 0;
398 }
399
400 struct dns_cli_request_state {
401         struct tevent_context *ev;
402         const char *nameserver;
403
404         uint16_t req_id;
405
406         DATA_BLOB query;
407
408         struct dns_name_packet *reply;
409 };
410
411 static void dns_cli_request_udp_done(struct tevent_req *subreq);
412 static void dns_cli_request_tcp_done(struct tevent_req *subreq);
413
414 struct tevent_req *dns_cli_request_send(TALLOC_CTX *mem_ctx,
415                                         struct tevent_context *ev,
416                                         const char *nameserver,
417                                         const char *name,
418                                         enum dns_qclass qclass,
419                                         enum dns_qtype qtype)
420 {
421         struct tevent_req *req, *subreq;
422         struct dns_cli_request_state *state;
423         struct dns_name_question question;
424         struct dns_name_packet out_packet;
425         enum ndr_err_code ndr_err;
426
427         req = tevent_req_create(mem_ctx, &state,
428                                 struct dns_cli_request_state);
429         if (req == NULL) {
430                 return NULL;
431         }
432         state->ev = ev;
433         state->nameserver = nameserver;
434
435         DBG_DEBUG("Asking %s for %s/%d/%d via UDP\n", nameserver,
436                   name, (int)qclass, (int)qtype);
437
438         generate_random_buffer((uint8_t *)&state->req_id,
439                                sizeof(state->req_id));
440
441         question = (struct dns_name_question) {
442                 .name = discard_const_p(char, name),
443                 .question_type = qtype, .question_class = qclass
444         };
445
446         out_packet = (struct dns_name_packet) {
447                 .id = state->req_id,
448                 .operation = DNS_OPCODE_QUERY | DNS_FLAG_RECURSION_DESIRED,
449                 .qdcount = 1,
450                 .questions = &question
451         };
452
453         ndr_err = ndr_push_struct_blob(
454                 &state->query, state, &out_packet,
455                 (ndr_push_flags_fn_t)ndr_push_dns_name_packet);
456         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
457                 tevent_req_error(req, ndr_map_error2errno(ndr_err));
458                 return tevent_req_post(req, ev);
459         }
460
461         subreq = dns_udp_request_send(state, state->ev, state->nameserver,
462                                       state->query.data, state->query.length);
463         if (tevent_req_nomem(subreq, req)) {
464                 return tevent_req_post(req, ev);
465         }
466         tevent_req_set_callback(subreq, dns_cli_request_udp_done, req);
467         return req;
468 }
469
470 static void dns_cli_request_udp_done(struct tevent_req *subreq)
471 {
472         struct tevent_req *req = tevent_req_callback_data(
473                 subreq, struct tevent_req);
474         struct dns_cli_request_state *state = tevent_req_data(
475                 req, struct dns_cli_request_state);
476         DATA_BLOB reply;
477         enum ndr_err_code ndr_err;
478         int ret;
479
480         ret = dns_udp_request_recv(subreq, state, &reply.data, &reply.length);
481         TALLOC_FREE(subreq);
482         if (tevent_req_error(req, ret)) {
483                 return;
484         }
485
486         state->reply = talloc(state, struct dns_name_packet);
487         if (tevent_req_nomem(state->reply, req)) {
488                 return;
489         }
490
491         ndr_err = ndr_pull_struct_blob(
492                 &reply, state->reply, state->reply,
493                 (ndr_pull_flags_fn_t)ndr_pull_dns_name_packet);
494         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
495                 tevent_req_error(req, ndr_map_error2errno(ndr_err));
496                 return;
497         }
498         TALLOC_FREE(reply.data);
499
500         if (state->reply->id != state->req_id) {
501                 DBG_DEBUG("Got id %"PRIu16", expected %"PRIu16"\n",
502                           state->reply->id, state->req_id);
503                 tevent_req_error(req, ENOMSG);
504                 return;
505         }
506
507         if ((state->reply->operation & DNS_FLAG_TRUNCATION) == 0) {
508                 DBG_DEBUG("Got op=%x %"PRIu16"/%"PRIu16"/%"PRIu16"/%"PRIu16
509                           " recs\n", (int)state->reply->operation,
510                           state->reply->qdcount, state->reply->ancount,
511                           state->reply->nscount, state->reply->nscount);
512                 tevent_req_done(req);
513                 return;
514         }
515
516         DBG_DEBUG("Reply was truncated, retrying TCP\n");
517
518         TALLOC_FREE(state->reply);
519
520         subreq = dns_tcp_request_send(state, state->ev, state->nameserver,
521                                       state->query.data, state->query.length);
522         if (tevent_req_nomem(subreq, req)) {
523                 return;
524         }
525         tevent_req_set_callback(subreq, dns_cli_request_tcp_done, req);
526 }
527
528 static void dns_cli_request_tcp_done(struct tevent_req *subreq)
529 {
530         struct tevent_req *req = tevent_req_callback_data(
531                 subreq, struct tevent_req);
532         struct dns_cli_request_state *state = tevent_req_data(
533                 req, struct dns_cli_request_state);
534         DATA_BLOB reply;
535         enum ndr_err_code ndr_err;
536         int ret;
537
538         ret = dns_tcp_request_recv(subreq, state, &reply.data, &reply.length);
539         TALLOC_FREE(subreq);
540         if (tevent_req_error(req, ret)) {
541                 return;
542         }
543
544         state->reply = talloc(state, struct dns_name_packet);
545         if (tevent_req_nomem(state->reply, req)) {
546                 return;
547         }
548
549         ndr_err = ndr_pull_struct_blob(
550                 &reply, state->reply, state->reply,
551                 (ndr_pull_flags_fn_t)ndr_pull_dns_name_packet);
552         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
553                 tevent_req_error(req, ndr_map_error2errno(ndr_err));
554                 return;
555         }
556         TALLOC_FREE(reply.data);
557
558         if (state->reply->id != state->req_id) {
559                 DBG_DEBUG("Got id %"PRIu16", expected %"PRIu16"\n",
560                           state->reply->id, state->req_id);
561                 tevent_req_error(req, ENOMSG);
562                 return;
563         }
564
565         DBG_DEBUG("Got op=%x %"PRIu16"/%"PRIu16"/%"PRIu16"/%"PRIu16
566                   " recs\n", (int)state->reply->operation,
567                   state->reply->qdcount, state->reply->ancount,
568                   state->reply->nscount, state->reply->nscount);
569
570         tevent_req_done(req);
571 }
572
573 int dns_cli_request_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
574                          struct dns_name_packet **reply)
575 {
576         struct dns_cli_request_state *state = tevent_req_data(
577                 req, struct dns_cli_request_state);
578         int err;
579
580         if (tevent_req_is_unix_error(req, &err)) {
581                 return err;
582         }
583         *reply = talloc_move(mem_ctx, &state->reply);
584         return 0;
585 }