2 Unix SMB/CIFS implementation.
4 KDC Server request proxying
6 Copyright (C) Andrew Tridgell 2010
7 Copyright (C) Andrew Bartlett 2010
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "smbd/process_model.h"
25 #include "lib/tsocket/tsocket.h"
26 #include "libcli/util/tstream.h"
27 #include "lib/stream/packet.h"
28 #include "kdc/kdc-glue.h"
29 #include "dsdb/samdb/samdb.h"
30 #include "libcli/composite/composite.h"
31 #include "libcli/resolve/resolve.h"
35 get a list of our replication partners from repsFrom, returning it in *proxy_list
37 static WERROR
kdc_proxy_get_writeable_dcs(struct kdc_server
*kdc
, TALLOC_CTX
*mem_ctx
, char ***proxy_list
)
41 struct repsFromToBlob
*reps
;
43 werr
= dsdb_loadreps(kdc
->samdb
, mem_ctx
, ldb_get_default_basedn(kdc
->samdb
), "repsFrom", &reps
, &count
);
44 W_ERROR_NOT_OK_RETURN(werr
);
47 /* we don't have any DCs to replicate with. Very
49 DEBUG(1,(__location__
": No replication sources for RODC in KDC proxy\n"));
51 return WERR_DS_DRA_NO_REPLICA
;
54 (*proxy_list
) = talloc_array(mem_ctx
, char *, count
+1);
55 W_ERROR_HAVE_NO_MEMORY_AND_FREE(*proxy_list
, reps
);
57 talloc_steal(*proxy_list
, reps
);
59 for (i
=0; i
<count
; i
++) {
60 const char *dns_name
= NULL
;
61 if (reps
->version
== 1) {
62 dns_name
= reps
->ctr
.ctr1
.other_info
->dns_name
;
63 } else if (reps
->version
== 2) {
64 dns_name
= reps
->ctr
.ctr2
.other_info
->dns_name1
;
66 (*proxy_list
)[i
] = talloc_strdup(*proxy_list
, dns_name
);
67 W_ERROR_HAVE_NO_MEMORY_AND_FREE((*proxy_list
)[i
], *proxy_list
);
69 (*proxy_list
)[i
] = NULL
;
77 struct kdc_udp_proxy_state
{
78 struct kdc_udp_call
*call
;
79 struct kdc_udp_socket
*sock
;
80 struct kdc_server
*kdc
;
88 static void kdc_udp_next_proxy(struct kdc_udp_proxy_state
*state
);
91 called when the send of the call to the proxy is complete
92 this is used to get an errors from the sendto()
94 static void kdc_udp_proxy_sendto_done(struct tevent_req
*req
)
96 struct kdc_udp_proxy_state
*state
= tevent_req_callback_data(req
,
97 struct kdc_udp_proxy_state
);
101 ret
= tdgram_sendto_queue_recv(req
, &sys_errno
);
105 DEBUG(4,("kdc_udp_proxy: sendto for %s gave %d : %s\n",
106 state
->proxy_ip
, sys_errno
, strerror(sys_errno
)));
107 kdc_udp_next_proxy(state
);
112 called when the send of the reply to the client is complete
113 this is used to get an errors from the sendto()
115 static void kdc_udp_proxy_reply_done(struct tevent_req
*req
)
117 struct kdc_udp_proxy_state
*state
= tevent_req_callback_data(req
,
118 struct kdc_udp_proxy_state
);
122 ret
= tdgram_sendto_queue_recv(req
, &sys_errno
);
124 DEBUG(3,("kdc_udp_proxy: reply sendto gave %d : %s\n",
125 sys_errno
, strerror(sys_errno
)));
128 /* all done - we can destroy the proxy state */
135 called when the proxy replies
137 static void kdc_udp_proxy_reply(struct tevent_req
*req
)
139 struct kdc_udp_proxy_state
*state
= tevent_req_callback_data(req
,
140 struct kdc_udp_proxy_state
);
143 struct tsocket_address
*src
;
146 len
= tdgram_recvfrom_recv(req
, &sys_errno
,
150 DEBUG(4,("kdc_udp_proxy: reply from %s gave %d : %s\n",
151 state
->proxy_ip
, sys_errno
, strerror(sys_errno
)));
152 kdc_udp_next_proxy(state
);
156 state
->call
->out
.length
= len
;
157 state
->call
->out
.data
= buf
;
159 /* TODO: check the reply came from the right IP? */
161 req
= tdgram_sendto_queue_send(state
,
162 state
->kdc
->task
->event_ctx
,
164 state
->sock
->send_queue
,
165 state
->call
->out
.data
,
166 state
->call
->out
.length
,
169 kdc_udp_next_proxy(state
);
173 tevent_req_set_callback(req
, kdc_udp_proxy_reply_done
, state
);
178 called when we've resolved the name of a proxy
180 static void kdc_udp_proxy_resolve_done(struct composite_context
*c
)
182 struct kdc_udp_proxy_state
*state
;
184 struct tevent_req
*req
;
185 struct tsocket_address
*local_addr
, *proxy_addr
;
187 struct tdgram_context
*dgram
;
188 struct tevent_queue
*send_queue
;
190 state
= talloc_get_type(c
->async
.private_data
, struct kdc_udp_proxy_state
);
192 status
= resolve_name_recv(c
, state
, &state
->proxy_ip
);
193 if (!NT_STATUS_IS_OK(status
)) {
194 DEBUG(0,("Unable to resolve proxy\n"));
195 kdc_udp_next_proxy(state
);
199 /* get an address for us to use locally */
200 ret
= tsocket_address_inet_from_strings(state
, "ip", NULL
, 0, &local_addr
);
202 kdc_udp_next_proxy(state
);
206 ret
= tsocket_address_inet_from_strings(state
, "ip",
207 state
->proxy_ip
, state
->port
, &proxy_addr
);
209 kdc_udp_next_proxy(state
);
213 /* create a socket for us to work on */
214 ret
= tdgram_inet_udp_socket(local_addr
, proxy_addr
, state
, &dgram
);
216 kdc_udp_next_proxy(state
);
220 send_queue
= tevent_queue_create(state
, "kdc_udp_proxy");
221 if (send_queue
== NULL
) {
222 kdc_udp_next_proxy(state
);
226 req
= tdgram_sendto_queue_send(state
,
227 state
->kdc
->task
->event_ctx
,
230 state
->call
->in
.data
,
231 state
->call
->in
.length
,
234 kdc_udp_next_proxy(state
);
238 tevent_req_set_callback(req
, kdc_udp_proxy_sendto_done
, state
);
240 /* setup to receive the reply from the proxy */
241 req
= tdgram_recvfrom_send(state
, state
->kdc
->task
->event_ctx
, dgram
);
243 kdc_udp_next_proxy(state
);
247 tevent_req_set_callback(req
, kdc_udp_proxy_reply
, state
);
249 tevent_req_set_endtime(req
, state
->kdc
->task
->event_ctx
,
250 timeval_current_ofs(state
->kdc
->proxy_timeout
, 0));
252 DEBUG(4,("kdc_udp_proxy: proxying request to %s\n", state
->proxy_ip
));
257 called when our proxies are not available
259 static void kdc_udp_proxy_unavailable(struct kdc_udp_proxy_state
*state
)
262 krb5_data k5_error_blob
;
263 struct tevent_req
*req
;
265 kret
= krb5_mk_error(state
->kdc
->smb_krb5_context
->krb5_context
,
266 KRB5KDC_ERR_SVC_UNAVAILABLE
, NULL
, NULL
,
267 NULL
, NULL
, NULL
, NULL
, &k5_error_blob
);
269 DEBUG(2,(__location__
": Unable to form krb5 error reply\n"));
274 state
->call
->out
= data_blob_talloc(state
, k5_error_blob
.data
, k5_error_blob
.length
);
275 krb5_data_free(&k5_error_blob
);
276 if (!state
->call
->out
.data
) {
281 req
= tdgram_sendto_queue_send(state
,
282 state
->kdc
->task
->event_ctx
,
284 state
->sock
->send_queue
,
285 state
->call
->out
.data
,
286 state
->call
->out
.length
,
293 tevent_req_set_callback(req
, kdc_udp_proxy_reply_done
, state
);
297 try the next proxy in the list
299 static void kdc_udp_next_proxy(struct kdc_udp_proxy_state
*state
)
301 const char *proxy_dnsname
= state
->proxy_list
[state
->next_proxy
];
302 struct nbt_name name
;
303 struct composite_context
*c
;
305 if (proxy_dnsname
== NULL
) {
306 kdc_udp_proxy_unavailable(state
);
312 make_nbt_name(&name
, proxy_dnsname
, 0);
314 c
= resolve_name_ex_send(lpcfg_resolve_context(state
->kdc
->task
->lp_ctx
),
316 RESOLVE_NAME_FLAG_FORCE_DNS
,
319 state
->kdc
->task
->event_ctx
);
321 kdc_udp_next_proxy(state
);
324 c
->async
.fn
= kdc_udp_proxy_resolve_done
;
325 c
->async
.private_data
= state
;
330 proxy a UDP kdc request to a writeable DC
332 void kdc_udp_proxy(struct kdc_server
*kdc
, struct kdc_udp_socket
*sock
,
333 struct kdc_udp_call
*call
, uint16_t port
)
335 struct kdc_udp_proxy_state
*state
;
338 state
= talloc_zero(kdc
, struct kdc_udp_proxy_state
);
344 state
->call
= talloc_steal(state
, call
);
349 werr
= kdc_proxy_get_writeable_dcs(kdc
, state
, &state
->proxy_list
);
350 if (!W_ERROR_IS_OK(werr
)) {
351 kdc_udp_proxy_unavailable(state
);
355 kdc_udp_next_proxy(state
);
359 struct kdc_tcp_proxy_state
{
360 struct kdc_tcp_call
*call
;
361 struct kdc_tcp_connection
*kdc_conn
;
362 struct kdc_server
*kdc
;
366 const char *proxy_ip
;
369 static void kdc_tcp_next_proxy(struct kdc_tcp_proxy_state
*state
);
372 called when the send of the proxied reply to the client is done
374 static void kdc_tcp_proxy_reply_done(struct tevent_req
*req
)
376 struct kdc_tcp_proxy_state
*state
= tevent_req_callback_data(req
,
377 struct kdc_tcp_proxy_state
);
380 ret
= tstream_writev_queue_recv(req
, &sys_errno
);
382 DEBUG(4,("kdc_tcp_proxy: writev of reply gave %d : %s\n",
383 sys_errno
, strerror(sys_errno
)));
390 called when the recv of the proxied reply is done
392 static void kdc_tcp_proxy_recv_done(struct tevent_req
*req
)
394 struct kdc_tcp_proxy_state
*state
= tevent_req_callback_data(req
,
395 struct kdc_tcp_proxy_state
);
398 status
= tstream_read_pdu_blob_recv(req
,
403 if (!NT_STATUS_IS_OK(status
)) {
404 kdc_tcp_next_proxy(state
);
409 /* send the reply to the original caller */
411 state
->call
->out_iov
[0].iov_base
= (char *)state
->call
->out
.data
;
412 state
->call
->out_iov
[0].iov_len
= state
->call
->out
.length
;
414 req
= tstream_writev_queue_send(state
,
415 state
->kdc_conn
->conn
->event
.ctx
,
416 state
->kdc_conn
->tstream
,
417 state
->kdc_conn
->send_queue
,
418 state
->call
->out_iov
, 1);
420 kdc_tcp_next_proxy(state
);
424 tevent_req_set_callback(req
, kdc_tcp_proxy_reply_done
, state
);
428 called when the send of the proxied packet is done
430 static void kdc_tcp_proxy_send_done(struct tevent_req
*req
)
432 struct kdc_tcp_proxy_state
*state
= tevent_req_callback_data(req
,
433 struct kdc_tcp_proxy_state
);
436 ret
= tstream_writev_queue_recv(req
, &sys_errno
);
439 kdc_tcp_next_proxy(state
);
444 called when we've connected to the proxy
446 static void kdc_tcp_proxy_connect_done(struct tevent_req
*req
)
448 struct kdc_tcp_proxy_state
*state
= tevent_req_callback_data(req
,
449 struct kdc_tcp_proxy_state
);
451 struct tstream_context
*stream
;
452 struct tevent_queue
*send_queue
;
455 ret
= tstream_inet_tcp_connect_recv(req
, &sys_errno
, state
, &stream
, NULL
);
459 kdc_tcp_next_proxy(state
);
463 RSIVAL(state
->call
->out_hdr
, 0, state
->call
->in
.length
);
464 state
->call
->out_iov
[0].iov_base
= (char *)state
->call
->out_hdr
;
465 state
->call
->out_iov
[0].iov_len
= 4;
466 state
->call
->out_iov
[1].iov_base
= (char *) state
->call
->in
.data
;
467 state
->call
->out_iov
[1].iov_len
= state
->call
->in
.length
;
469 send_queue
= tevent_queue_create(state
, "kdc_tcp_proxy");
470 if (send_queue
== NULL
) {
471 kdc_tcp_next_proxy(state
);
475 req
= tstream_writev_queue_send(state
,
476 state
->kdc_conn
->conn
->event
.ctx
,
479 state
->call
->out_iov
, 2);
481 kdc_tcp_next_proxy(state
);
485 tevent_req_set_callback(req
, kdc_tcp_proxy_send_done
, state
);
487 req
= tstream_read_pdu_blob_send(state
,
488 state
->kdc_conn
->conn
->event
.ctx
,
490 4, /* initial_read_size */
491 packet_full_request_u32
,
494 kdc_tcp_next_proxy(state
);
498 tevent_req_set_callback(req
, kdc_tcp_proxy_recv_done
, state
);
499 tevent_req_set_endtime(req
, state
->kdc
->task
->event_ctx
,
500 timeval_current_ofs(state
->kdc
->proxy_timeout
, 0));
506 called when name resolution for a proxy is done
508 static void kdc_tcp_proxy_resolve_done(struct composite_context
*c
)
510 struct kdc_tcp_proxy_state
*state
;
512 struct tevent_req
*req
;
513 struct tsocket_address
*local_addr
, *proxy_addr
;
516 state
= talloc_get_type(c
->async
.private_data
, struct kdc_tcp_proxy_state
);
518 status
= resolve_name_recv(c
, state
, &state
->proxy_ip
);
519 if (!NT_STATUS_IS_OK(status
)) {
520 kdc_tcp_next_proxy(state
);
524 /* get an address for us to use locally */
525 ret
= tsocket_address_inet_from_strings(state
, "ip", NULL
, 0, &local_addr
);
527 kdc_tcp_next_proxy(state
);
531 ret
= tsocket_address_inet_from_strings(state
, "ip",
532 state
->proxy_ip
, state
->port
, &proxy_addr
);
534 kdc_tcp_next_proxy(state
);
538 /* connect to the proxy */
539 req
= tstream_inet_tcp_connect_send(state
, state
->kdc
->task
->event_ctx
, local_addr
, proxy_addr
);
541 kdc_tcp_next_proxy(state
);
545 tevent_req_set_callback(req
, kdc_tcp_proxy_connect_done
, state
);
547 tevent_req_set_endtime(req
, state
->kdc
->task
->event_ctx
,
548 timeval_current_ofs(state
->kdc
->proxy_timeout
, 0));
550 DEBUG(4,("kdc_tcp_proxy: proxying request to %s\n", state
->proxy_ip
));
555 called when our proxies are not available
557 static void kdc_tcp_proxy_unavailable(struct kdc_tcp_proxy_state
*state
)
560 krb5_data k5_error_blob
;
561 struct tevent_req
*req
;
563 kret
= krb5_mk_error(state
->kdc
->smb_krb5_context
->krb5_context
,
564 KRB5KDC_ERR_SVC_UNAVAILABLE
, NULL
, NULL
,
565 NULL
, NULL
, NULL
, NULL
, &k5_error_blob
);
567 DEBUG(2,(__location__
": Unable to form krb5 error reply\n"));
573 state
->call
->out
= data_blob_talloc(state
, k5_error_blob
.data
, k5_error_blob
.length
);
574 krb5_data_free(&k5_error_blob
);
575 if (!state
->call
->out
.data
) {
580 state
->call
->out_iov
[0].iov_base
= (char *)state
->call
->out
.data
;
581 state
->call
->out_iov
[0].iov_len
= state
->call
->out
.length
;
583 req
= tstream_writev_queue_send(state
,
584 state
->kdc_conn
->conn
->event
.ctx
,
585 state
->kdc_conn
->tstream
,
586 state
->kdc_conn
->send_queue
,
587 state
->call
->out_iov
, 1);
593 tevent_req_set_callback(req
, kdc_tcp_proxy_reply_done
, state
);
597 try the next proxy in the list
599 static void kdc_tcp_next_proxy(struct kdc_tcp_proxy_state
*state
)
601 const char *proxy_dnsname
= state
->proxy_list
[state
->next_proxy
];
602 struct nbt_name name
;
603 struct composite_context
*c
;
605 if (proxy_dnsname
== NULL
) {
606 kdc_tcp_proxy_unavailable(state
);
612 make_nbt_name(&name
, proxy_dnsname
, 0);
614 c
= resolve_name_ex_send(lpcfg_resolve_context(state
->kdc
->task
->lp_ctx
),
616 RESOLVE_NAME_FLAG_FORCE_DNS
,
619 state
->kdc
->task
->event_ctx
);
621 kdc_tcp_next_proxy(state
);
624 c
->async
.fn
= kdc_tcp_proxy_resolve_done
;
625 c
->async
.private_data
= state
;
630 proxy a TCP kdc request to a writeable DC
632 void kdc_tcp_proxy(struct kdc_server
*kdc
, struct kdc_tcp_connection
*kdc_conn
,
633 struct kdc_tcp_call
*call
, uint16_t port
)
635 struct kdc_tcp_proxy_state
*state
;
638 state
= talloc_zero(kdc_conn
, struct kdc_tcp_proxy_state
);
640 state
->call
= talloc_steal(state
, call
);
641 state
->kdc_conn
= kdc_conn
;
645 werr
= kdc_proxy_get_writeable_dcs(kdc
, state
, &state
->proxy_list
);
646 if (!W_ERROR_IS_OK(werr
)) {
647 kdc_tcp_proxy_unavailable(state
);
651 kdc_tcp_next_proxy(state
);