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-glue.h"
31 #include "dsdb/samdb/samdb.h"
32 #include "libcli/composite/composite.h"
33 #include "libcli/resolve/resolve.h"
37 get a list of our replication partners from repsFrom, returning it in *proxy_list
39 static WERROR
kdc_proxy_get_writeable_dcs(struct kdc_server
*kdc
, TALLOC_CTX
*mem_ctx
, char ***proxy_list
)
43 struct repsFromToBlob
*reps
;
45 werr
= dsdb_loadreps(kdc
->samdb
, mem_ctx
, ldb_get_default_basedn(kdc
->samdb
), "repsFrom", &reps
, &count
);
46 W_ERROR_NOT_OK_RETURN(werr
);
49 /* we don't have any DCs to replicate with. Very
51 DEBUG(1,(__location__
": No replication sources for RODC in KDC proxy\n"));
53 return WERR_DS_DRA_NO_REPLICA
;
56 (*proxy_list
) = talloc_array(mem_ctx
, char *, count
+1);
57 W_ERROR_HAVE_NO_MEMORY_AND_FREE(*proxy_list
, reps
);
59 talloc_steal(*proxy_list
, reps
);
61 for (i
=0; i
<count
; i
++) {
62 const char *dns_name
= NULL
;
63 if (reps
->version
== 1) {
64 dns_name
= reps
->ctr
.ctr1
.other_info
->dns_name
;
65 } else if (reps
->version
== 2) {
66 dns_name
= reps
->ctr
.ctr2
.other_info
->dns_name1
;
68 (*proxy_list
)[i
] = talloc_strdup(*proxy_list
, dns_name
);
69 W_ERROR_HAVE_NO_MEMORY_AND_FREE((*proxy_list
)[i
], *proxy_list
);
71 (*proxy_list
)[i
] = NULL
;
79 struct kdc_udp_proxy_state
{
80 struct tevent_context
*ev
;
81 struct kdc_server
*kdc
;
90 struct tdgram_context
*dgram
;
95 static void kdc_udp_next_proxy(struct tevent_req
*req
);
97 struct tevent_req
*kdc_udp_proxy_send(TALLOC_CTX
*mem_ctx
,
98 struct tevent_context
*ev
,
99 struct kdc_server
*kdc
,
103 struct tevent_req
*req
;
104 struct kdc_udp_proxy_state
*state
;
107 req
= tevent_req_create(mem_ctx
, &state
,
108 struct kdc_udp_proxy_state
);
117 werr
= kdc_proxy_get_writeable_dcs(kdc
, state
, &state
->proxy_list
);
118 if (!W_ERROR_IS_OK(werr
)) {
119 NTSTATUS status
= werror_to_ntstatus(werr
);
120 tevent_req_nterror(req
, status
);
121 return tevent_req_post(req
, ev
);
124 kdc_udp_next_proxy(req
);
125 if (!tevent_req_is_in_progress(req
)) {
126 return tevent_req_post(req
, ev
);
132 static void kdc_udp_proxy_resolve_done(struct composite_context
*csubreq
);
135 try the next proxy in the list
137 static void kdc_udp_next_proxy(struct tevent_req
*req
)
139 struct kdc_udp_proxy_state
*state
=
141 struct kdc_udp_proxy_state
);
142 const char *proxy_dnsname
= state
->proxy_list
[state
->next_proxy
];
143 struct composite_context
*csubreq
;
145 if (proxy_dnsname
== NULL
) {
146 tevent_req_nterror(req
, NT_STATUS_NO_LOGON_SERVERS
);
152 /* make sure we close the socket of the last try */
153 TALLOC_FREE(state
->proxy
.dgram
);
154 ZERO_STRUCT(state
->proxy
);
156 make_nbt_name(&state
->proxy
.name
, proxy_dnsname
, 0);
158 csubreq
= resolve_name_ex_send(lpcfg_resolve_context(state
->kdc
->task
->lp_ctx
),
160 RESOLVE_NAME_FLAG_FORCE_DNS
,
164 if (tevent_req_nomem(csubreq
, req
)) {
167 csubreq
->async
.fn
= kdc_udp_proxy_resolve_done
;
168 csubreq
->async
.private_data
= req
;
171 static void kdc_udp_proxy_sendto_done(struct tevent_req
*subreq
);
172 static void kdc_udp_proxy_recvfrom_done(struct tevent_req
*subreq
);
174 static void kdc_udp_proxy_resolve_done(struct composite_context
*csubreq
)
176 struct tevent_req
*req
=
177 talloc_get_type_abort(csubreq
->async
.private_data
,
179 struct kdc_udp_proxy_state
*state
=
181 struct kdc_udp_proxy_state
);
183 struct tevent_req
*subreq
;
184 struct tsocket_address
*local_addr
, *proxy_addr
;
187 status
= resolve_name_recv(csubreq
, state
, &state
->proxy
.ip
);
188 if (!NT_STATUS_IS_OK(status
)) {
189 DEBUG(0,("Unable to resolve proxy[%s] - %s\n",
190 state
->proxy
.name
.name
, nt_errstr(status
)));
191 kdc_udp_next_proxy(req
);
195 /* get an address for us to use locally */
196 ret
= tsocket_address_inet_from_strings(state
, "ip", NULL
, 0, &local_addr
);
198 kdc_udp_next_proxy(req
);
202 ret
= tsocket_address_inet_from_strings(state
, "ip",
207 kdc_udp_next_proxy(req
);
211 /* create a socket for us to work on */
212 ret
= tdgram_inet_udp_socket(local_addr
, proxy_addr
,
213 state
, &state
->proxy
.dgram
);
215 kdc_udp_next_proxy(req
);
219 subreq
= tdgram_sendto_send(state
,
225 if (tevent_req_nomem(subreq
, req
)) {
228 tevent_req_set_callback(subreq
, kdc_udp_proxy_sendto_done
, req
);
230 /* setup to receive the reply from the proxy */
231 subreq
= tdgram_recvfrom_send(state
, state
->ev
, state
->proxy
.dgram
);
232 if (tevent_req_nomem(subreq
, req
)) {
235 tevent_req_set_callback(subreq
, kdc_udp_proxy_recvfrom_done
, req
);
236 tevent_req_set_endtime(subreq
, state
->ev
,
237 timeval_current_ofs(state
->kdc
->proxy_timeout
, 0));
239 DEBUG(4,("kdc_udp_proxy: proxying request to %s[%s]\n",
240 state
->proxy
.name
.name
, state
->proxy
.ip
));
244 called when the send of the call to the proxy is complete
245 this is used to get an errors from the sendto()
247 static void kdc_udp_proxy_sendto_done(struct tevent_req
*subreq
)
249 struct tevent_req
*req
=
250 tevent_req_callback_data(subreq
,
252 struct kdc_udp_proxy_state
*state
=
254 struct kdc_udp_proxy_state
);
258 ret
= tdgram_sendto_recv(subreq
, &sys_errno
);
261 DEBUG(4,("kdc_udp_proxy: sendto for %s[%s] gave %d : %s\n",
262 state
->proxy
.name
.name
, state
->proxy
.ip
,
263 sys_errno
, strerror(sys_errno
)));
264 kdc_udp_next_proxy(req
);
269 called when the proxy replies
271 static void kdc_udp_proxy_recvfrom_done(struct tevent_req
*subreq
)
273 struct tevent_req
*req
=
274 tevent_req_callback_data(subreq
,
276 struct kdc_udp_proxy_state
*state
=
278 struct kdc_udp_proxy_state
);
283 len
= tdgram_recvfrom_recv(subreq
, &sys_errno
,
287 DEBUG(4,("kdc_udp_proxy: reply from %s[%s] gave %d : %s\n",
288 state
->proxy
.name
.name
, state
->proxy
.ip
,
289 sys_errno
, strerror(sys_errno
)));
290 kdc_udp_next_proxy(req
);
295 * Check the reply came from the right IP?
296 * As we use connected udp sockets, that should not be needed...
299 state
->out
.length
= len
;
300 state
->out
.data
= buf
;
302 tevent_req_done(req
);
305 NTSTATUS
kdc_udp_proxy_recv(struct tevent_req
*req
,
309 struct kdc_udp_proxy_state
*state
=
311 struct kdc_udp_proxy_state
);
314 if (tevent_req_is_nterror(req
, &status
)) {
315 tevent_req_received(req
);
319 out
->data
= talloc_move(mem_ctx
, &state
->out
.data
);
320 out
->length
= state
->out
.length
;
322 tevent_req_received(req
);
326 struct kdc_tcp_proxy_state
{
327 struct kdc_tcp_call
*call
;
328 struct kdc_tcp_connection
*kdc_conn
;
329 struct kdc_server
*kdc
;
333 const char *proxy_ip
;
336 static void kdc_tcp_next_proxy(struct kdc_tcp_proxy_state
*state
);
339 called when the send of the proxied reply to the client is done
341 static void kdc_tcp_proxy_reply_done(struct tevent_req
*req
)
343 struct kdc_tcp_proxy_state
*state
= tevent_req_callback_data(req
,
344 struct kdc_tcp_proxy_state
);
347 ret
= tstream_writev_queue_recv(req
, &sys_errno
);
349 DEBUG(4,("kdc_tcp_proxy: writev of reply gave %d : %s\n",
350 sys_errno
, strerror(sys_errno
)));
357 called when the recv of the proxied reply is done
359 static void kdc_tcp_proxy_recv_done(struct tevent_req
*req
)
361 struct kdc_tcp_proxy_state
*state
= tevent_req_callback_data(req
,
362 struct kdc_tcp_proxy_state
);
365 status
= tstream_read_pdu_blob_recv(req
,
370 if (!NT_STATUS_IS_OK(status
)) {
371 kdc_tcp_next_proxy(state
);
376 /* send the reply to the original caller */
378 state
->call
->out_iov
[0].iov_base
= (char *)state
->call
->out
.data
;
379 state
->call
->out_iov
[0].iov_len
= state
->call
->out
.length
;
381 req
= tstream_writev_queue_send(state
,
382 state
->kdc_conn
->conn
->event
.ctx
,
383 state
->kdc_conn
->tstream
,
384 state
->kdc_conn
->send_queue
,
385 state
->call
->out_iov
, 1);
387 kdc_tcp_next_proxy(state
);
391 tevent_req_set_callback(req
, kdc_tcp_proxy_reply_done
, state
);
395 called when the send of the proxied packet is done
397 static void kdc_tcp_proxy_send_done(struct tevent_req
*req
)
399 struct kdc_tcp_proxy_state
*state
= tevent_req_callback_data(req
,
400 struct kdc_tcp_proxy_state
);
403 ret
= tstream_writev_queue_recv(req
, &sys_errno
);
406 kdc_tcp_next_proxy(state
);
411 called when we've connected to the proxy
413 static void kdc_tcp_proxy_connect_done(struct tevent_req
*req
)
415 struct kdc_tcp_proxy_state
*state
= tevent_req_callback_data(req
,
416 struct kdc_tcp_proxy_state
);
418 struct tstream_context
*stream
;
419 struct tevent_queue
*send_queue
;
422 ret
= tstream_inet_tcp_connect_recv(req
, &sys_errno
, state
, &stream
, NULL
);
426 kdc_tcp_next_proxy(state
);
430 RSIVAL(state
->call
->out_hdr
, 0, state
->call
->in
.length
);
431 state
->call
->out_iov
[0].iov_base
= (char *)state
->call
->out_hdr
;
432 state
->call
->out_iov
[0].iov_len
= 4;
433 state
->call
->out_iov
[1].iov_base
= (char *) state
->call
->in
.data
;
434 state
->call
->out_iov
[1].iov_len
= state
->call
->in
.length
;
436 send_queue
= tevent_queue_create(state
, "kdc_tcp_proxy");
437 if (send_queue
== NULL
) {
438 kdc_tcp_next_proxy(state
);
442 req
= tstream_writev_queue_send(state
,
443 state
->kdc_conn
->conn
->event
.ctx
,
446 state
->call
->out_iov
, 2);
448 kdc_tcp_next_proxy(state
);
452 tevent_req_set_callback(req
, kdc_tcp_proxy_send_done
, state
);
454 req
= tstream_read_pdu_blob_send(state
,
455 state
->kdc_conn
->conn
->event
.ctx
,
457 4, /* initial_read_size */
458 packet_full_request_u32
,
461 kdc_tcp_next_proxy(state
);
465 tevent_req_set_callback(req
, kdc_tcp_proxy_recv_done
, state
);
466 tevent_req_set_endtime(req
, state
->kdc
->task
->event_ctx
,
467 timeval_current_ofs(state
->kdc
->proxy_timeout
, 0));
473 called when name resolution for a proxy is done
475 static void kdc_tcp_proxy_resolve_done(struct composite_context
*c
)
477 struct kdc_tcp_proxy_state
*state
;
479 struct tevent_req
*req
;
480 struct tsocket_address
*local_addr
, *proxy_addr
;
483 state
= talloc_get_type(c
->async
.private_data
, struct kdc_tcp_proxy_state
);
485 status
= resolve_name_recv(c
, state
, &state
->proxy_ip
);
486 if (!NT_STATUS_IS_OK(status
)) {
487 kdc_tcp_next_proxy(state
);
491 /* get an address for us to use locally */
492 ret
= tsocket_address_inet_from_strings(state
, "ip", NULL
, 0, &local_addr
);
494 kdc_tcp_next_proxy(state
);
498 ret
= tsocket_address_inet_from_strings(state
, "ip",
499 state
->proxy_ip
, state
->port
, &proxy_addr
);
501 kdc_tcp_next_proxy(state
);
505 /* connect to the proxy */
506 req
= tstream_inet_tcp_connect_send(state
, state
->kdc
->task
->event_ctx
, local_addr
, proxy_addr
);
508 kdc_tcp_next_proxy(state
);
512 tevent_req_set_callback(req
, kdc_tcp_proxy_connect_done
, state
);
514 tevent_req_set_endtime(req
, state
->kdc
->task
->event_ctx
,
515 timeval_current_ofs(state
->kdc
->proxy_timeout
, 0));
517 DEBUG(4,("kdc_tcp_proxy: proxying request to %s\n", state
->proxy_ip
));
522 called when our proxies are not available
524 static void kdc_tcp_proxy_unavailable(struct kdc_tcp_proxy_state
*state
)
527 krb5_data k5_error_blob
;
528 struct tevent_req
*req
;
530 kret
= krb5_mk_error(state
->kdc
->smb_krb5_context
->krb5_context
,
531 KRB5KDC_ERR_SVC_UNAVAILABLE
, NULL
, NULL
,
532 NULL
, NULL
, NULL
, NULL
, &k5_error_blob
);
534 DEBUG(2,(__location__
": Unable to form krb5 error reply\n"));
540 state
->call
->out
= data_blob_talloc(state
, k5_error_blob
.data
, k5_error_blob
.length
);
541 krb5_data_free(&k5_error_blob
);
542 if (!state
->call
->out
.data
) {
547 state
->call
->out_iov
[0].iov_base
= (char *)state
->call
->out
.data
;
548 state
->call
->out_iov
[0].iov_len
= state
->call
->out
.length
;
550 req
= tstream_writev_queue_send(state
,
551 state
->kdc_conn
->conn
->event
.ctx
,
552 state
->kdc_conn
->tstream
,
553 state
->kdc_conn
->send_queue
,
554 state
->call
->out_iov
, 1);
560 tevent_req_set_callback(req
, kdc_tcp_proxy_reply_done
, state
);
564 try the next proxy in the list
566 static void kdc_tcp_next_proxy(struct kdc_tcp_proxy_state
*state
)
568 const char *proxy_dnsname
= state
->proxy_list
[state
->next_proxy
];
569 struct nbt_name name
;
570 struct composite_context
*c
;
572 if (proxy_dnsname
== NULL
) {
573 kdc_tcp_proxy_unavailable(state
);
579 make_nbt_name(&name
, proxy_dnsname
, 0);
581 c
= resolve_name_ex_send(lpcfg_resolve_context(state
->kdc
->task
->lp_ctx
),
583 RESOLVE_NAME_FLAG_FORCE_DNS
,
586 state
->kdc
->task
->event_ctx
);
588 kdc_tcp_next_proxy(state
);
591 c
->async
.fn
= kdc_tcp_proxy_resolve_done
;
592 c
->async
.private_data
= state
;
597 proxy a TCP kdc request to a writeable DC
599 void kdc_tcp_proxy(struct kdc_server
*kdc
, struct kdc_tcp_connection
*kdc_conn
,
600 struct kdc_tcp_call
*call
, uint16_t port
)
602 struct kdc_tcp_proxy_state
*state
;
605 state
= talloc_zero(kdc_conn
, struct kdc_tcp_proxy_state
);
607 state
->call
= talloc_steal(state
, call
);
608 state
->kdc_conn
= kdc_conn
;
612 werr
= kdc_proxy_get_writeable_dcs(kdc
, state
, &state
->proxy_list
);
613 if (!W_ERROR_IS_OK(werr
)) {
614 kdc_tcp_proxy_unavailable(state
);
618 kdc_tcp_next_proxy(state
);