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/>.
25 #include "smbd/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"
38 get a list of our replication partners from repsFrom, returning it in *proxy_list
40 static WERROR kdc_proxy_get_writeable_dcs(struct kdc_server *kdc, TALLOC_CTX *mem_ctx, char ***proxy_list)
44 struct repsFromToBlob *reps;
46 werr = dsdb_loadreps(kdc->samdb, mem_ctx, ldb_get_default_basedn(kdc->samdb), "repsFrom", &reps, &count);
47 W_ERROR_NOT_OK_RETURN(werr);
50 /* we don't have any DCs to replicate with. Very
52 DEBUG(1,(__location__ ": No replication sources for RODC in KDC proxy\n"));
54 return WERR_DS_DRA_NO_REPLICA;
57 (*proxy_list) = talloc_array(mem_ctx, char *, count+1);
58 W_ERROR_HAVE_NO_MEMORY_AND_FREE(*proxy_list, reps);
60 talloc_steal(*proxy_list, reps);
62 for (i=0; i<count; i++) {
63 const char *dns_name = NULL;
64 if (reps->version == 1) {
65 dns_name = reps->ctr.ctr1.other_info->dns_name;
66 } else if (reps->version == 2) {
67 dns_name = reps->ctr.ctr2.other_info->dns_name1;
69 (*proxy_list)[i] = talloc_strdup(*proxy_list, dns_name);
70 W_ERROR_HAVE_NO_MEMORY_AND_FREE((*proxy_list)[i], *proxy_list);
72 (*proxy_list)[i] = NULL;
80 struct kdc_udp_proxy_state {
81 struct tevent_context *ev;
82 struct kdc_server *kdc;
91 struct tdgram_context *dgram;
96 static void kdc_udp_next_proxy(struct tevent_req *req);
98 struct tevent_req *kdc_udp_proxy_send(TALLOC_CTX *mem_ctx,
99 struct tevent_context *ev,
100 struct kdc_server *kdc,
104 struct tevent_req *req;
105 struct kdc_udp_proxy_state *state;
108 req = tevent_req_create(mem_ctx, &state,
109 struct kdc_udp_proxy_state);
118 werr = kdc_proxy_get_writeable_dcs(kdc, state, &state->proxy_list);
119 if (!W_ERROR_IS_OK(werr)) {
120 NTSTATUS status = werror_to_ntstatus(werr);
121 tevent_req_nterror(req, status);
122 return tevent_req_post(req, ev);
125 kdc_udp_next_proxy(req);
126 if (!tevent_req_is_in_progress(req)) {
127 return tevent_req_post(req, ev);
133 static void kdc_udp_proxy_resolve_done(struct composite_context *csubreq);
136 try the next proxy in the list
138 static void kdc_udp_next_proxy(struct tevent_req *req)
140 struct kdc_udp_proxy_state *state =
142 struct kdc_udp_proxy_state);
143 const char *proxy_dnsname = state->proxy_list[state->next_proxy];
144 struct composite_context *csubreq;
146 if (proxy_dnsname == NULL) {
147 tevent_req_nterror(req, NT_STATUS_NO_LOGON_SERVERS);
153 /* make sure we close the socket of the last try */
154 TALLOC_FREE(state->proxy.dgram);
155 ZERO_STRUCT(state->proxy);
157 make_nbt_name(&state->proxy.name, proxy_dnsname, 0);
159 csubreq = resolve_name_ex_send(lpcfg_resolve_context(state->kdc->task->lp_ctx),
161 RESOLVE_NAME_FLAG_FORCE_DNS,
165 if (tevent_req_nomem(csubreq, req)) {
168 csubreq->async.fn = kdc_udp_proxy_resolve_done;
169 csubreq->async.private_data = req;
172 static void kdc_udp_proxy_sendto_done(struct tevent_req *subreq);
173 static void kdc_udp_proxy_recvfrom_done(struct tevent_req *subreq);
175 static void kdc_udp_proxy_resolve_done(struct composite_context *csubreq)
177 struct tevent_req *req =
178 talloc_get_type_abort(csubreq->async.private_data,
180 struct kdc_udp_proxy_state *state =
182 struct kdc_udp_proxy_state);
184 struct tevent_req *subreq;
185 struct tsocket_address *local_addr, *proxy_addr;
188 status = resolve_name_recv(csubreq, state, &state->proxy.ip);
189 if (!NT_STATUS_IS_OK(status)) {
190 DEBUG(0,("Unable to resolve proxy[%s] - %s\n",
191 state->proxy.name.name, nt_errstr(status)));
192 kdc_udp_next_proxy(req);
196 /* get an address for us to use locally */
197 ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0, &local_addr);
199 kdc_udp_next_proxy(req);
203 ret = tsocket_address_inet_from_strings(state, "ip",
208 kdc_udp_next_proxy(req);
212 /* create a socket for us to work on */
213 ret = tdgram_inet_udp_socket(local_addr, proxy_addr,
214 state, &state->proxy.dgram);
216 kdc_udp_next_proxy(req);
220 subreq = tdgram_sendto_send(state,
226 if (tevent_req_nomem(subreq, req)) {
229 tevent_req_set_callback(subreq, kdc_udp_proxy_sendto_done, req);
231 /* setup to receive the reply from the proxy */
232 subreq = tdgram_recvfrom_send(state, state->ev, state->proxy.dgram);
233 if (tevent_req_nomem(subreq, req)) {
236 tevent_req_set_callback(subreq, kdc_udp_proxy_recvfrom_done, req);
237 tevent_req_set_endtime(subreq, state->ev,
238 timeval_current_ofs(state->kdc->proxy_timeout, 0));
240 DEBUG(4,("kdc_udp_proxy: proxying request to %s[%s]\n",
241 state->proxy.name.name, state->proxy.ip));
245 called when the send of the call to the proxy is complete
246 this is used to get an errors from the sendto()
248 static void kdc_udp_proxy_sendto_done(struct tevent_req *subreq)
250 struct tevent_req *req =
251 tevent_req_callback_data(subreq,
253 struct kdc_udp_proxy_state *state =
255 struct kdc_udp_proxy_state);
259 ret = tdgram_sendto_recv(subreq, &sys_errno);
262 DEBUG(4,("kdc_udp_proxy: sendto for %s[%s] gave %d : %s\n",
263 state->proxy.name.name, state->proxy.ip,
264 sys_errno, strerror(sys_errno)));
265 kdc_udp_next_proxy(req);
270 called when the proxy replies
272 static void kdc_udp_proxy_recvfrom_done(struct tevent_req *subreq)
274 struct tevent_req *req =
275 tevent_req_callback_data(subreq,
277 struct kdc_udp_proxy_state *state =
279 struct kdc_udp_proxy_state);
284 len = tdgram_recvfrom_recv(subreq, &sys_errno,
288 DEBUG(4,("kdc_udp_proxy: reply from %s[%s] gave %d : %s\n",
289 state->proxy.name.name, state->proxy.ip,
290 sys_errno, strerror(sys_errno)));
291 kdc_udp_next_proxy(req);
296 * Check the reply came from the right IP?
297 * As we use connected udp sockets, that should not be needed...
300 state->out.length = len;
301 state->out.data = buf;
303 tevent_req_done(req);
306 NTSTATUS kdc_udp_proxy_recv(struct tevent_req *req,
310 struct kdc_udp_proxy_state *state =
312 struct kdc_udp_proxy_state);
315 if (tevent_req_is_nterror(req, &status)) {
316 tevent_req_received(req);
320 out->data = talloc_move(mem_ctx, &state->out.data);
321 out->length = state->out.length;
323 tevent_req_received(req);
327 struct kdc_tcp_proxy_state {
328 struct tevent_context *ev;
329 struct kdc_server *kdc;
333 struct iovec in_iov[2];
338 struct nbt_name name;
340 struct tstream_context *stream;
344 static void kdc_tcp_next_proxy(struct tevent_req *req);
346 struct tevent_req *kdc_tcp_proxy_send(TALLOC_CTX *mem_ctx,
347 struct tevent_context *ev,
348 struct kdc_server *kdc,
352 struct tevent_req *req;
353 struct kdc_tcp_proxy_state *state;
356 req = tevent_req_create(mem_ctx, &state,
357 struct kdc_tcp_proxy_state);
366 werr = kdc_proxy_get_writeable_dcs(kdc, state, &state->proxy_list);
367 if (!W_ERROR_IS_OK(werr)) {
368 NTSTATUS status = werror_to_ntstatus(werr);
369 tevent_req_nterror(req, status);
370 return tevent_req_post(req, ev);
373 RSIVAL(state->in_hdr, 0, state->in.length);
374 state->in_iov[0].iov_base = (char *)state->in_hdr;
375 state->in_iov[0].iov_len = 4;
376 state->in_iov[1].iov_base = (char *)state->in.data;
377 state->in_iov[1].iov_len = state->in.length;
379 kdc_tcp_next_proxy(req);
380 if (!tevent_req_is_in_progress(req)) {
381 return tevent_req_post(req, ev);
387 static void kdc_tcp_proxy_resolve_done(struct composite_context *csubreq);
390 try the next proxy in the list
392 static void kdc_tcp_next_proxy(struct tevent_req *req)
394 struct kdc_tcp_proxy_state *state =
396 struct kdc_tcp_proxy_state);
397 const char *proxy_dnsname = state->proxy_list[state->next_proxy];
398 struct composite_context *csubreq;
400 if (proxy_dnsname == NULL) {
401 tevent_req_nterror(req, NT_STATUS_NO_LOGON_SERVERS);
407 /* make sure we close the socket of the last try */
408 TALLOC_FREE(state->proxy.stream);
409 ZERO_STRUCT(state->proxy);
411 make_nbt_name(&state->proxy.name, proxy_dnsname, 0);
413 csubreq = resolve_name_ex_send(lpcfg_resolve_context(state->kdc->task->lp_ctx),
415 RESOLVE_NAME_FLAG_FORCE_DNS,
419 if (tevent_req_nomem(csubreq, req)) {
422 csubreq->async.fn = kdc_tcp_proxy_resolve_done;
423 csubreq->async.private_data = req;
426 static void kdc_tcp_proxy_connect_done(struct tevent_req *subreq);
428 static void kdc_tcp_proxy_resolve_done(struct composite_context *csubreq)
430 struct tevent_req *req =
431 talloc_get_type_abort(csubreq->async.private_data,
433 struct kdc_tcp_proxy_state *state =
435 struct kdc_tcp_proxy_state);
437 struct tevent_req *subreq;
438 struct tsocket_address *local_addr, *proxy_addr;
441 status = resolve_name_recv(csubreq, state, &state->proxy.ip);
442 if (!NT_STATUS_IS_OK(status)) {
443 DEBUG(0,("Unable to resolve proxy[%s] - %s\n",
444 state->proxy.name.name, nt_errstr(status)));
445 kdc_tcp_next_proxy(req);
449 /* get an address for us to use locally */
450 ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0, &local_addr);
452 kdc_tcp_next_proxy(req);
456 ret = tsocket_address_inet_from_strings(state, "ip",
461 kdc_tcp_next_proxy(req);
465 subreq = tstream_inet_tcp_connect_send(state, state->ev,
466 local_addr, proxy_addr);
467 if (tevent_req_nomem(subreq, req)) {
470 tevent_req_set_callback(subreq, kdc_tcp_proxy_connect_done, req);
471 tevent_req_set_endtime(subreq, state->ev,
472 timeval_current_ofs(state->kdc->proxy_timeout, 0));
475 static void kdc_tcp_proxy_writev_done(struct tevent_req *subreq);
476 static void kdc_tcp_proxy_read_pdu_done(struct tevent_req *subreq);
478 static void kdc_tcp_proxy_connect_done(struct tevent_req *subreq)
480 struct tevent_req *req =
481 tevent_req_callback_data(subreq,
483 struct kdc_tcp_proxy_state *state =
485 struct kdc_tcp_proxy_state);
488 ret = tstream_inet_tcp_connect_recv(subreq, &sys_errno,
489 state, &state->proxy.stream, NULL);
492 kdc_tcp_next_proxy(req);
496 subreq = tstream_writev_send(state,
500 if (tevent_req_nomem(subreq, req)) {
503 tevent_req_set_callback(subreq, kdc_tcp_proxy_writev_done, req);
505 subreq = tstream_read_pdu_blob_send(state,
508 4, /* initial_read_size */
509 packet_full_request_u32,
511 if (tevent_req_nomem(subreq, req)) {
514 tevent_req_set_callback(subreq, kdc_tcp_proxy_read_pdu_done, req);
515 tevent_req_set_endtime(subreq, state->kdc->task->event_ctx,
516 timeval_current_ofs(state->kdc->proxy_timeout, 0));
518 DEBUG(4,("kdc_tcp_proxy: proxying request to %s[%s]\n",
519 state->proxy.name.name, state->proxy.ip));
522 static void kdc_tcp_proxy_writev_done(struct tevent_req *subreq)
524 struct tevent_req *req =
525 tevent_req_callback_data(subreq,
529 ret = tstream_writev_recv(subreq, &sys_errno);
532 kdc_tcp_next_proxy(req);
536 static void kdc_tcp_proxy_read_pdu_done(struct tevent_req *subreq)
538 struct tevent_req *req =
539 tevent_req_callback_data(subreq,
541 struct kdc_tcp_proxy_state *state =
543 struct kdc_tcp_proxy_state);
547 status = tstream_read_pdu_blob_recv(subreq, state, &raw);
549 if (!NT_STATUS_IS_OK(status)) {
550 kdc_tcp_next_proxy(req);
555 * raw blob has the length in the first 4 bytes,
556 * which we do not need here.
558 state->out = data_blob_talloc(state, raw.data + 4, raw.length - 4);
559 if (state->out.length != raw.length - 4) {
564 tevent_req_done(req);
567 NTSTATUS kdc_tcp_proxy_recv(struct tevent_req *req,
571 struct kdc_tcp_proxy_state *state =
573 struct kdc_tcp_proxy_state);
576 if (tevent_req_is_nterror(req, &status)) {
577 tevent_req_received(req);
581 out->data = talloc_move(mem_ctx, &state->out.data);
582 out->length = state->out.length;
584 tevent_req_received(req);