s4: torture: Add an async SMB2_OP_FLUSH + SMB2_OP_CLOSE test to smb2.compound_async.
[Samba.git] / source4 / kdc / kdc-proxy.c
blobbf14ccbb8b42867767681e970ee56416c05f3201
1 /*
2 Unix SMB/CIFS implementation.
4 KDC Server request proxying
6 Copyright (C) Andrew Tridgell 2010
7 Copyright (C) Andrew Bartlett 2010
8 Copyright (C) Stefan Metzmacher 2011
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "includes.h"
25 #include "samba/process_model.h"
26 #include "lib/tsocket/tsocket.h"
27 #include "libcli/util/tstream.h"
28 #include "lib/util/tevent_ntstatus.h"
29 #include "lib/stream/packet.h"
30 #include "kdc/kdc-server.h"
31 #include "kdc/kdc-proxy.h"
32 #include "dsdb/samdb/samdb.h"
33 #include "libcli/composite/composite.h"
34 #include "libcli/resolve/resolve.h"
36 #undef DBGC_CLASS
37 #define DBGC_CLASS DBGC_KERBEROS
40 get a list of our replication partners from repsFrom, returning it in *proxy_list
42 static WERROR kdc_proxy_get_writeable_dcs(struct kdc_server *kdc, TALLOC_CTX *mem_ctx, char ***proxy_list)
44 WERROR werr;
45 uint32_t count, i;
46 struct repsFromToBlob *reps;
48 werr = dsdb_loadreps(kdc->samdb, mem_ctx, ldb_get_default_basedn(kdc->samdb), "repsFrom", &reps, &count);
49 W_ERROR_NOT_OK_RETURN(werr);
51 if (count == 0) {
52 /* we don't have any DCs to replicate with. Very
53 strange for a RODC */
54 DEBUG(1,(__location__ ": No replication sources for RODC in KDC proxy\n"));
55 talloc_free(reps);
56 return WERR_DS_DRA_NO_REPLICA;
59 (*proxy_list) = talloc_array(mem_ctx, char *, count+1);
60 W_ERROR_HAVE_NO_MEMORY_AND_FREE(*proxy_list, reps);
62 talloc_steal(*proxy_list, reps);
64 for (i=0; i<count; i++) {
65 const char *dns_name = NULL;
66 if (reps->version == 1) {
67 dns_name = reps->ctr.ctr1.other_info->dns_name;
68 } else if (reps->version == 2) {
69 dns_name = reps->ctr.ctr2.other_info->dns_name1;
71 (*proxy_list)[i] = talloc_strdup(*proxy_list, dns_name);
72 W_ERROR_HAVE_NO_MEMORY_AND_FREE((*proxy_list)[i], *proxy_list);
74 (*proxy_list)[i] = NULL;
76 talloc_free(reps);
78 return WERR_OK;
82 struct kdc_udp_proxy_state {
83 struct tevent_context *ev;
84 struct kdc_server *kdc;
85 uint16_t port;
86 DATA_BLOB in;
87 DATA_BLOB out;
88 char **proxy_list;
89 uint32_t next_proxy;
90 struct {
91 struct nbt_name name;
92 const char *ip;
93 struct tdgram_context *dgram;
94 } proxy;
98 static void kdc_udp_next_proxy(struct tevent_req *req);
100 struct tevent_req *kdc_udp_proxy_send(TALLOC_CTX *mem_ctx,
101 struct tevent_context *ev,
102 struct kdc_server *kdc,
103 uint16_t port,
104 DATA_BLOB in)
106 struct tevent_req *req;
107 struct kdc_udp_proxy_state *state;
108 WERROR werr;
110 req = tevent_req_create(mem_ctx, &state,
111 struct kdc_udp_proxy_state);
112 if (req == NULL) {
113 return NULL;
115 state->ev = ev;
116 state->kdc = kdc;
117 state->port = port;
118 state->in = in;
120 werr = kdc_proxy_get_writeable_dcs(kdc, state, &state->proxy_list);
121 if (!W_ERROR_IS_OK(werr)) {
122 NTSTATUS status = werror_to_ntstatus(werr);
123 tevent_req_nterror(req, status);
124 return tevent_req_post(req, ev);
127 kdc_udp_next_proxy(req);
128 if (!tevent_req_is_in_progress(req)) {
129 return tevent_req_post(req, ev);
132 return req;
135 static void kdc_udp_proxy_resolve_done(struct composite_context *csubreq);
138 try the next proxy in the list
140 static void kdc_udp_next_proxy(struct tevent_req *req)
142 struct kdc_udp_proxy_state *state =
143 tevent_req_data(req,
144 struct kdc_udp_proxy_state);
145 const char *proxy_dnsname = state->proxy_list[state->next_proxy];
146 struct composite_context *csubreq;
148 if (proxy_dnsname == NULL) {
149 tevent_req_nterror(req, NT_STATUS_NO_LOGON_SERVERS);
150 return;
153 state->next_proxy++;
155 /* make sure we close the socket of the last try */
156 TALLOC_FREE(state->proxy.dgram);
157 ZERO_STRUCT(state->proxy);
159 make_nbt_name(&state->proxy.name, proxy_dnsname, 0);
161 csubreq = resolve_name_ex_send(lpcfg_resolve_context(state->kdc->task->lp_ctx),
162 state,
163 RESOLVE_NAME_FLAG_FORCE_DNS,
165 &state->proxy.name,
166 state->ev);
167 if (tevent_req_nomem(csubreq, req)) {
168 return;
170 csubreq->async.fn = kdc_udp_proxy_resolve_done;
171 csubreq->async.private_data = req;
174 static void kdc_udp_proxy_sendto_done(struct tevent_req *subreq);
175 static void kdc_udp_proxy_recvfrom_done(struct tevent_req *subreq);
177 static void kdc_udp_proxy_resolve_done(struct composite_context *csubreq)
179 struct tevent_req *req =
180 talloc_get_type_abort(csubreq->async.private_data,
181 struct tevent_req);
182 struct kdc_udp_proxy_state *state =
183 tevent_req_data(req,
184 struct kdc_udp_proxy_state);
185 NTSTATUS status;
186 struct tevent_req *subreq;
187 struct tsocket_address *local_addr, *proxy_addr;
188 int ret;
189 bool ok;
191 status = resolve_name_recv(csubreq, state, &state->proxy.ip);
192 if (!NT_STATUS_IS_OK(status)) {
193 DEBUG(0,("Unable to resolve proxy[%s] - %s\n",
194 state->proxy.name.name, nt_errstr(status)));
195 kdc_udp_next_proxy(req);
196 return;
199 /* get an address for us to use locally */
200 ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0, &local_addr);
201 if (ret != 0) {
202 kdc_udp_next_proxy(req);
203 return;
206 ret = tsocket_address_inet_from_strings(state, "ip",
207 state->proxy.ip,
208 state->port,
209 &proxy_addr);
210 if (ret != 0) {
211 kdc_udp_next_proxy(req);
212 return;
215 /* create a socket for us to work on */
216 ret = tdgram_inet_udp_socket(local_addr, proxy_addr,
217 state, &state->proxy.dgram);
218 if (ret != 0) {
219 kdc_udp_next_proxy(req);
220 return;
223 subreq = tdgram_sendto_send(state,
224 state->ev,
225 state->proxy.dgram,
226 state->in.data,
227 state->in.length,
228 NULL);
229 if (tevent_req_nomem(subreq, req)) {
230 return;
232 tevent_req_set_callback(subreq, kdc_udp_proxy_sendto_done, req);
234 /* setup to receive the reply from the proxy */
235 subreq = tdgram_recvfrom_send(state, state->ev, state->proxy.dgram);
236 if (tevent_req_nomem(subreq, req)) {
237 return;
239 tevent_req_set_callback(subreq, kdc_udp_proxy_recvfrom_done, req);
241 ok = tevent_req_set_endtime(
242 subreq,
243 state->ev,
244 timeval_current_ofs(state->kdc->proxy_timeout, 0));
245 if (!ok) {
246 DBG_DEBUG("tevent_req_set_endtime failed\n");
247 return;
250 DEBUG(4,("kdc_udp_proxy: proxying request to %s[%s]\n",
251 state->proxy.name.name, state->proxy.ip));
255 called when the send of the call to the proxy is complete
256 this is used to get an errors from the sendto()
258 static void kdc_udp_proxy_sendto_done(struct tevent_req *subreq)
260 struct tevent_req *req =
261 tevent_req_callback_data(subreq,
262 struct tevent_req);
263 struct kdc_udp_proxy_state *state =
264 tevent_req_data(req,
265 struct kdc_udp_proxy_state);
266 ssize_t ret;
267 int sys_errno;
269 ret = tdgram_sendto_recv(subreq, &sys_errno);
270 TALLOC_FREE(subreq);
271 if (ret == -1) {
272 DEBUG(4,("kdc_udp_proxy: sendto for %s[%s] gave %d : %s\n",
273 state->proxy.name.name, state->proxy.ip,
274 sys_errno, strerror(sys_errno)));
275 kdc_udp_next_proxy(req);
280 called when the proxy replies
282 static void kdc_udp_proxy_recvfrom_done(struct tevent_req *subreq)
284 struct tevent_req *req =
285 tevent_req_callback_data(subreq,
286 struct tevent_req);
287 struct kdc_udp_proxy_state *state =
288 tevent_req_data(req,
289 struct kdc_udp_proxy_state);
290 int sys_errno;
291 uint8_t *buf;
292 ssize_t len;
294 len = tdgram_recvfrom_recv(subreq, &sys_errno,
295 state, &buf, NULL);
296 TALLOC_FREE(subreq);
297 if (len == -1) {
298 DEBUG(4,("kdc_udp_proxy: reply from %s[%s] gave %d : %s\n",
299 state->proxy.name.name, state->proxy.ip,
300 sys_errno, strerror(sys_errno)));
301 kdc_udp_next_proxy(req);
302 return;
306 * Check the reply came from the right IP?
307 * As we use connected udp sockets, that should not be needed...
310 state->out.length = len;
311 state->out.data = buf;
313 tevent_req_done(req);
316 NTSTATUS kdc_udp_proxy_recv(struct tevent_req *req,
317 TALLOC_CTX *mem_ctx,
318 DATA_BLOB *out)
320 struct kdc_udp_proxy_state *state =
321 tevent_req_data(req,
322 struct kdc_udp_proxy_state);
323 NTSTATUS status;
325 if (tevent_req_is_nterror(req, &status)) {
326 tevent_req_received(req);
327 return status;
330 out->data = talloc_move(mem_ctx, &state->out.data);
331 out->length = state->out.length;
333 tevent_req_received(req);
334 return NT_STATUS_OK;
337 struct kdc_tcp_proxy_state {
338 struct tevent_context *ev;
339 struct kdc_server *kdc;
340 uint16_t port;
341 DATA_BLOB in;
342 uint8_t in_hdr[4];
343 struct iovec in_iov[2];
344 DATA_BLOB out;
345 char **proxy_list;
346 uint32_t next_proxy;
347 struct {
348 struct nbt_name name;
349 const char *ip;
350 struct tstream_context *stream;
351 } proxy;
354 static void kdc_tcp_next_proxy(struct tevent_req *req);
356 struct tevent_req *kdc_tcp_proxy_send(TALLOC_CTX *mem_ctx,
357 struct tevent_context *ev,
358 struct kdc_server *kdc,
359 uint16_t port,
360 DATA_BLOB in)
362 struct tevent_req *req;
363 struct kdc_tcp_proxy_state *state;
364 WERROR werr;
366 req = tevent_req_create(mem_ctx, &state,
367 struct kdc_tcp_proxy_state);
368 if (req == NULL) {
369 return NULL;
371 state->ev = ev;
372 state->kdc = kdc;
373 state->port = port;
374 state->in = in;
376 werr = kdc_proxy_get_writeable_dcs(kdc, state, &state->proxy_list);
377 if (!W_ERROR_IS_OK(werr)) {
378 NTSTATUS status = werror_to_ntstatus(werr);
379 tevent_req_nterror(req, status);
380 return tevent_req_post(req, ev);
383 RSIVAL(state->in_hdr, 0, state->in.length);
384 state->in_iov[0].iov_base = (char *)state->in_hdr;
385 state->in_iov[0].iov_len = 4;
386 state->in_iov[1].iov_base = (char *)state->in.data;
387 state->in_iov[1].iov_len = state->in.length;
389 kdc_tcp_next_proxy(req);
390 if (!tevent_req_is_in_progress(req)) {
391 return tevent_req_post(req, ev);
394 return req;
397 static void kdc_tcp_proxy_resolve_done(struct composite_context *csubreq);
400 try the next proxy in the list
402 static void kdc_tcp_next_proxy(struct tevent_req *req)
404 struct kdc_tcp_proxy_state *state =
405 tevent_req_data(req,
406 struct kdc_tcp_proxy_state);
407 const char *proxy_dnsname = state->proxy_list[state->next_proxy];
408 struct composite_context *csubreq;
410 if (proxy_dnsname == NULL) {
411 tevent_req_nterror(req, NT_STATUS_NO_LOGON_SERVERS);
412 return;
415 state->next_proxy++;
417 /* make sure we close the socket of the last try */
418 TALLOC_FREE(state->proxy.stream);
419 ZERO_STRUCT(state->proxy);
421 make_nbt_name(&state->proxy.name, proxy_dnsname, 0);
423 csubreq = resolve_name_ex_send(lpcfg_resolve_context(state->kdc->task->lp_ctx),
424 state,
425 RESOLVE_NAME_FLAG_FORCE_DNS,
427 &state->proxy.name,
428 state->ev);
429 if (tevent_req_nomem(csubreq, req)) {
430 return;
432 csubreq->async.fn = kdc_tcp_proxy_resolve_done;
433 csubreq->async.private_data = req;
436 static void kdc_tcp_proxy_connect_done(struct tevent_req *subreq);
438 static void kdc_tcp_proxy_resolve_done(struct composite_context *csubreq)
440 struct tevent_req *req =
441 talloc_get_type_abort(csubreq->async.private_data,
442 struct tevent_req);
443 struct kdc_tcp_proxy_state *state =
444 tevent_req_data(req,
445 struct kdc_tcp_proxy_state);
446 NTSTATUS status;
447 struct tevent_req *subreq;
448 struct tsocket_address *local_addr, *proxy_addr;
449 int ret;
451 status = resolve_name_recv(csubreq, state, &state->proxy.ip);
452 if (!NT_STATUS_IS_OK(status)) {
453 DEBUG(0,("Unable to resolve proxy[%s] - %s\n",
454 state->proxy.name.name, nt_errstr(status)));
455 kdc_tcp_next_proxy(req);
456 return;
459 /* get an address for us to use locally */
460 ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0, &local_addr);
461 if (ret != 0) {
462 kdc_tcp_next_proxy(req);
463 return;
466 ret = tsocket_address_inet_from_strings(state, "ip",
467 state->proxy.ip,
468 state->port,
469 &proxy_addr);
470 if (ret != 0) {
471 kdc_tcp_next_proxy(req);
472 return;
475 subreq = tstream_inet_tcp_connect_send(state, state->ev,
476 local_addr, proxy_addr);
477 if (tevent_req_nomem(subreq, req)) {
478 return;
480 tevent_req_set_callback(subreq, kdc_tcp_proxy_connect_done, req);
481 tevent_req_set_endtime(subreq, state->ev,
482 timeval_current_ofs(state->kdc->proxy_timeout, 0));
485 static void kdc_tcp_proxy_writev_done(struct tevent_req *subreq);
486 static void kdc_tcp_proxy_read_pdu_done(struct tevent_req *subreq);
488 static void kdc_tcp_proxy_connect_done(struct tevent_req *subreq)
490 struct tevent_req *req =
491 tevent_req_callback_data(subreq,
492 struct tevent_req);
493 struct kdc_tcp_proxy_state *state =
494 tevent_req_data(req,
495 struct kdc_tcp_proxy_state);
496 int ret, sys_errno;
498 ret = tstream_inet_tcp_connect_recv(subreq, &sys_errno,
499 state, &state->proxy.stream, NULL);
500 TALLOC_FREE(subreq);
501 if (ret != 0) {
502 kdc_tcp_next_proxy(req);
503 return;
506 subreq = tstream_writev_send(state,
507 state->ev,
508 state->proxy.stream,
509 state->in_iov, 2);
510 if (tevent_req_nomem(subreq, req)) {
511 return;
513 tevent_req_set_callback(subreq, kdc_tcp_proxy_writev_done, req);
515 subreq = tstream_read_pdu_blob_send(state,
516 state->ev,
517 state->proxy.stream,
518 4, /* initial_read_size */
519 packet_full_request_u32,
520 req);
521 if (tevent_req_nomem(subreq, req)) {
522 return;
524 tevent_req_set_callback(subreq, kdc_tcp_proxy_read_pdu_done, req);
525 tevent_req_set_endtime(subreq, state->kdc->task->event_ctx,
526 timeval_current_ofs(state->kdc->proxy_timeout, 0));
528 DEBUG(4,("kdc_tcp_proxy: proxying request to %s[%s]\n",
529 state->proxy.name.name, state->proxy.ip));
532 static void kdc_tcp_proxy_writev_done(struct tevent_req *subreq)
534 struct tevent_req *req =
535 tevent_req_callback_data(subreq,
536 struct tevent_req);
537 int ret, sys_errno;
539 ret = tstream_writev_recv(subreq, &sys_errno);
540 TALLOC_FREE(subreq);
541 if (ret == -1) {
542 kdc_tcp_next_proxy(req);
546 static void kdc_tcp_proxy_read_pdu_done(struct tevent_req *subreq)
548 struct tevent_req *req =
549 tevent_req_callback_data(subreq,
550 struct tevent_req);
551 struct kdc_tcp_proxy_state *state =
552 tevent_req_data(req,
553 struct kdc_tcp_proxy_state);
554 NTSTATUS status;
555 DATA_BLOB raw;
557 status = tstream_read_pdu_blob_recv(subreq, state, &raw);
558 TALLOC_FREE(subreq);
559 if (!NT_STATUS_IS_OK(status)) {
560 kdc_tcp_next_proxy(req);
561 return;
565 * raw blob has the length in the first 4 bytes,
566 * which we do not need here.
568 state->out = data_blob_talloc(state, raw.data + 4, raw.length - 4);
569 if (state->out.length != raw.length - 4) {
570 tevent_req_oom(req);
571 return;
574 tevent_req_done(req);
577 NTSTATUS kdc_tcp_proxy_recv(struct tevent_req *req,
578 TALLOC_CTX *mem_ctx,
579 DATA_BLOB *out)
581 struct kdc_tcp_proxy_state *state =
582 tevent_req_data(req,
583 struct kdc_tcp_proxy_state);
584 NTSTATUS status;
586 if (tevent_req_is_nterror(req, &status)) {
587 tevent_req_received(req);
588 return status;
591 out->data = talloc_move(mem_ctx, &state->out.data);
592 out->length = state->out.length;
594 tevent_req_received(req);
595 return NT_STATUS_OK;