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 "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/samba_kdc.h"
32 #include "kdc/kdc-proxy.h"
33 #include "dsdb/samdb/samdb.h"
34 #include "libcli/composite/composite.h"
35 #include "libcli/resolve/resolve.h"
38 #define DBGC_CLASS DBGC_KERBEROS
41 get a list of our replication partners from repsFrom, returning it in *proxy_list
43 static WERROR
kdc_proxy_get_writeable_dcs(struct kdc_server
*kdc
, TALLOC_CTX
*mem_ctx
, char ***proxy_list
)
47 struct repsFromToBlob
*reps
;
49 werr
= dsdb_loadreps(kdc
->kdc_db_ctx
->samdb
,
51 ldb_get_default_basedn(kdc
->kdc_db_ctx
->samdb
),
55 W_ERROR_NOT_OK_RETURN(werr
);
58 /* we don't have any DCs to replicate with. Very
60 DBG_WARNING("No replication sources for RODC in KDC proxy\n");
62 return WERR_DS_DRA_NO_REPLICA
;
65 (*proxy_list
) = talloc_array(mem_ctx
, char *, count
+1);
66 W_ERROR_HAVE_NO_MEMORY_AND_FREE(*proxy_list
, reps
);
68 talloc_steal(*proxy_list
, reps
);
70 for (i
=0; i
<count
; i
++) {
71 const char *dns_name
= NULL
;
72 if (reps
->version
== 1) {
73 dns_name
= reps
->ctr
.ctr1
.other_info
->dns_name
;
74 } else if (reps
->version
== 2) {
75 dns_name
= reps
->ctr
.ctr2
.other_info
->dns_name1
;
77 (*proxy_list
)[i
] = talloc_strdup(*proxy_list
, dns_name
);
78 W_ERROR_HAVE_NO_MEMORY_AND_FREE((*proxy_list
)[i
], *proxy_list
);
80 (*proxy_list
)[i
] = NULL
;
88 struct kdc_udp_proxy_state
{
89 struct tevent_context
*ev
;
90 struct kdc_server
*kdc
;
99 struct tdgram_context
*dgram
;
104 static void kdc_udp_next_proxy(struct tevent_req
*req
);
106 struct tevent_req
*kdc_udp_proxy_send(TALLOC_CTX
*mem_ctx
,
107 struct tevent_context
*ev
,
108 struct kdc_server
*kdc
,
112 struct tevent_req
*req
;
113 struct kdc_udp_proxy_state
*state
;
116 req
= tevent_req_create(mem_ctx
, &state
,
117 struct kdc_udp_proxy_state
);
126 werr
= kdc_proxy_get_writeable_dcs(kdc
, state
, &state
->proxy_list
);
127 if (!W_ERROR_IS_OK(werr
)) {
128 NTSTATUS status
= werror_to_ntstatus(werr
);
129 tevent_req_nterror(req
, status
);
130 return tevent_req_post(req
, ev
);
133 kdc_udp_next_proxy(req
);
134 if (!tevent_req_is_in_progress(req
)) {
135 return tevent_req_post(req
, ev
);
141 static void kdc_udp_proxy_resolve_done(struct composite_context
*csubreq
);
144 try the next proxy in the list
146 static void kdc_udp_next_proxy(struct tevent_req
*req
)
148 struct kdc_udp_proxy_state
*state
=
150 struct kdc_udp_proxy_state
);
151 const char *proxy_dnsname
= state
->proxy_list
[state
->next_proxy
];
152 struct composite_context
*csubreq
;
154 if (proxy_dnsname
== NULL
) {
155 tevent_req_nterror(req
, NT_STATUS_NO_LOGON_SERVERS
);
161 /* make sure we close the socket of the last try */
162 TALLOC_FREE(state
->proxy
.dgram
);
163 ZERO_STRUCT(state
->proxy
);
165 make_nbt_name(&state
->proxy
.name
, proxy_dnsname
, 0);
167 csubreq
= resolve_name_ex_send(lpcfg_resolve_context(state
->kdc
->task
->lp_ctx
),
169 RESOLVE_NAME_FLAG_FORCE_DNS
,
173 if (tevent_req_nomem(csubreq
, req
)) {
176 csubreq
->async
.fn
= kdc_udp_proxy_resolve_done
;
177 csubreq
->async
.private_data
= req
;
180 static void kdc_udp_proxy_sendto_done(struct tevent_req
*subreq
);
181 static void kdc_udp_proxy_recvfrom_done(struct tevent_req
*subreq
);
183 static void kdc_udp_proxy_resolve_done(struct composite_context
*csubreq
)
185 struct tevent_req
*req
=
186 talloc_get_type_abort(csubreq
->async
.private_data
,
188 struct kdc_udp_proxy_state
*state
=
190 struct kdc_udp_proxy_state
);
192 struct tevent_req
*subreq
;
193 struct tsocket_address
*local_addr
, *proxy_addr
;
197 status
= resolve_name_recv(csubreq
, state
, &state
->proxy
.ip
);
198 if (!NT_STATUS_IS_OK(status
)) {
199 DBG_ERR("Unable to resolve proxy[%s] - %s\n",
200 state
->proxy
.name
.name
, nt_errstr(status
));
201 kdc_udp_next_proxy(req
);
205 /* get an address for us to use locally */
206 ret
= tsocket_address_inet_from_strings(state
, "ip", NULL
, 0, &local_addr
);
208 kdc_udp_next_proxy(req
);
212 ret
= tsocket_address_inet_from_strings(state
, "ip",
217 kdc_udp_next_proxy(req
);
221 /* create a socket for us to work on */
222 ret
= tdgram_inet_udp_socket(local_addr
, proxy_addr
,
223 state
, &state
->proxy
.dgram
);
225 kdc_udp_next_proxy(req
);
229 subreq
= tdgram_sendto_send(state
,
235 if (tevent_req_nomem(subreq
, req
)) {
238 tevent_req_set_callback(subreq
, kdc_udp_proxy_sendto_done
, req
);
240 /* setup to receive the reply from the proxy */
241 subreq
= tdgram_recvfrom_send(state
, state
->ev
, state
->proxy
.dgram
);
242 if (tevent_req_nomem(subreq
, req
)) {
245 tevent_req_set_callback(subreq
, kdc_udp_proxy_recvfrom_done
, req
);
247 ok
= tevent_req_set_endtime(
250 timeval_current_ofs(state
->kdc
->proxy_timeout
, 0));
252 DBG_DEBUG("tevent_req_set_endtime failed\n");
256 DEBUG(4,("kdc_udp_proxy: proxying request to %s[%s]\n",
257 state
->proxy
.name
.name
, state
->proxy
.ip
));
261 called when the send of the call to the proxy is complete
262 this is used to get an errors from the sendto()
264 static void kdc_udp_proxy_sendto_done(struct tevent_req
*subreq
)
266 struct tevent_req
*req
=
267 tevent_req_callback_data(subreq
,
269 struct kdc_udp_proxy_state
*state
=
271 struct kdc_udp_proxy_state
);
275 ret
= tdgram_sendto_recv(subreq
, &sys_errno
);
278 DEBUG(4,("kdc_udp_proxy: sendto for %s[%s] gave %d : %s\n",
279 state
->proxy
.name
.name
, state
->proxy
.ip
,
280 sys_errno
, strerror(sys_errno
)));
281 kdc_udp_next_proxy(req
);
286 called when the proxy replies
288 static void kdc_udp_proxy_recvfrom_done(struct tevent_req
*subreq
)
290 struct tevent_req
*req
=
291 tevent_req_callback_data(subreq
,
293 struct kdc_udp_proxy_state
*state
=
295 struct kdc_udp_proxy_state
);
300 len
= tdgram_recvfrom_recv(subreq
, &sys_errno
,
304 DEBUG(4,("kdc_udp_proxy: reply from %s[%s] gave %d : %s\n",
305 state
->proxy
.name
.name
, state
->proxy
.ip
,
306 sys_errno
, strerror(sys_errno
)));
307 kdc_udp_next_proxy(req
);
312 * Check the reply came from the right IP?
313 * As we use connected udp sockets, that should not be needed...
316 state
->out
.length
= len
;
317 state
->out
.data
= buf
;
319 tevent_req_done(req
);
322 NTSTATUS
kdc_udp_proxy_recv(struct tevent_req
*req
,
326 struct kdc_udp_proxy_state
*state
=
328 struct kdc_udp_proxy_state
);
331 if (tevent_req_is_nterror(req
, &status
)) {
332 tevent_req_received(req
);
336 out
->data
= talloc_move(mem_ctx
, &state
->out
.data
);
337 out
->length
= state
->out
.length
;
339 tevent_req_received(req
);
343 struct kdc_tcp_proxy_state
{
344 struct tevent_context
*ev
;
345 struct kdc_server
*kdc
;
349 struct iovec in_iov
[2];
354 struct nbt_name name
;
356 struct tstream_context
*stream
;
360 static void kdc_tcp_next_proxy(struct tevent_req
*req
);
362 struct tevent_req
*kdc_tcp_proxy_send(TALLOC_CTX
*mem_ctx
,
363 struct tevent_context
*ev
,
364 struct kdc_server
*kdc
,
368 struct tevent_req
*req
;
369 struct kdc_tcp_proxy_state
*state
;
372 req
= tevent_req_create(mem_ctx
, &state
,
373 struct kdc_tcp_proxy_state
);
382 werr
= kdc_proxy_get_writeable_dcs(kdc
, state
, &state
->proxy_list
);
383 if (!W_ERROR_IS_OK(werr
)) {
384 NTSTATUS status
= werror_to_ntstatus(werr
);
385 tevent_req_nterror(req
, status
);
386 return tevent_req_post(req
, ev
);
389 RSIVAL(state
->in_hdr
, 0, state
->in
.length
);
390 state
->in_iov
[0].iov_base
= (char *)state
->in_hdr
;
391 state
->in_iov
[0].iov_len
= 4;
392 state
->in_iov
[1].iov_base
= (char *)state
->in
.data
;
393 state
->in_iov
[1].iov_len
= state
->in
.length
;
395 kdc_tcp_next_proxy(req
);
396 if (!tevent_req_is_in_progress(req
)) {
397 return tevent_req_post(req
, ev
);
403 static void kdc_tcp_proxy_resolve_done(struct composite_context
*csubreq
);
406 try the next proxy in the list
408 static void kdc_tcp_next_proxy(struct tevent_req
*req
)
410 struct kdc_tcp_proxy_state
*state
=
412 struct kdc_tcp_proxy_state
);
413 const char *proxy_dnsname
= state
->proxy_list
[state
->next_proxy
];
414 struct composite_context
*csubreq
;
416 if (proxy_dnsname
== NULL
) {
417 tevent_req_nterror(req
, NT_STATUS_NO_LOGON_SERVERS
);
423 /* make sure we close the socket of the last try */
424 TALLOC_FREE(state
->proxy
.stream
);
425 ZERO_STRUCT(state
->proxy
);
427 make_nbt_name(&state
->proxy
.name
, proxy_dnsname
, 0);
429 csubreq
= resolve_name_ex_send(lpcfg_resolve_context(state
->kdc
->task
->lp_ctx
),
431 RESOLVE_NAME_FLAG_FORCE_DNS
,
435 if (tevent_req_nomem(csubreq
, req
)) {
438 csubreq
->async
.fn
= kdc_tcp_proxy_resolve_done
;
439 csubreq
->async
.private_data
= req
;
442 static void kdc_tcp_proxy_connect_done(struct tevent_req
*subreq
);
444 static void kdc_tcp_proxy_resolve_done(struct composite_context
*csubreq
)
446 struct tevent_req
*req
=
447 talloc_get_type_abort(csubreq
->async
.private_data
,
449 struct kdc_tcp_proxy_state
*state
=
451 struct kdc_tcp_proxy_state
);
453 struct tevent_req
*subreq
;
454 struct tsocket_address
*local_addr
, *proxy_addr
;
457 status
= resolve_name_recv(csubreq
, state
, &state
->proxy
.ip
);
458 if (!NT_STATUS_IS_OK(status
)) {
459 DBG_ERR("Unable to resolve proxy[%s] - %s\n",
460 state
->proxy
.name
.name
, nt_errstr(status
));
461 kdc_tcp_next_proxy(req
);
465 /* get an address for us to use locally */
466 ret
= tsocket_address_inet_from_strings(state
, "ip", NULL
, 0, &local_addr
);
468 kdc_tcp_next_proxy(req
);
472 ret
= tsocket_address_inet_from_strings(state
, "ip",
477 kdc_tcp_next_proxy(req
);
481 subreq
= tstream_inet_tcp_connect_send(state
, state
->ev
,
482 local_addr
, proxy_addr
);
483 if (tevent_req_nomem(subreq
, req
)) {
486 tevent_req_set_callback(subreq
, kdc_tcp_proxy_connect_done
, req
);
487 tevent_req_set_endtime(subreq
, state
->ev
,
488 timeval_current_ofs(state
->kdc
->proxy_timeout
, 0));
491 static void kdc_tcp_proxy_writev_done(struct tevent_req
*subreq
);
492 static void kdc_tcp_proxy_read_pdu_done(struct tevent_req
*subreq
);
494 static void kdc_tcp_proxy_connect_done(struct tevent_req
*subreq
)
496 struct tevent_req
*req
=
497 tevent_req_callback_data(subreq
,
499 struct kdc_tcp_proxy_state
*state
=
501 struct kdc_tcp_proxy_state
);
504 ret
= tstream_inet_tcp_connect_recv(subreq
, &sys_errno
,
505 state
, &state
->proxy
.stream
, NULL
);
508 kdc_tcp_next_proxy(req
);
512 subreq
= tstream_writev_send(state
,
516 if (tevent_req_nomem(subreq
, req
)) {
519 tevent_req_set_callback(subreq
, kdc_tcp_proxy_writev_done
, req
);
521 subreq
= tstream_read_pdu_blob_send(state
,
524 4, /* initial_read_size */
525 tstream_full_request_u32
,
527 if (tevent_req_nomem(subreq
, req
)) {
530 tevent_req_set_callback(subreq
, kdc_tcp_proxy_read_pdu_done
, req
);
531 tevent_req_set_endtime(subreq
, state
->kdc
->task
->event_ctx
,
532 timeval_current_ofs(state
->kdc
->proxy_timeout
, 0));
534 DEBUG(4,("kdc_tcp_proxy: proxying request to %s[%s]\n",
535 state
->proxy
.name
.name
, state
->proxy
.ip
));
538 static void kdc_tcp_proxy_writev_done(struct tevent_req
*subreq
)
540 struct tevent_req
*req
=
541 tevent_req_callback_data(subreq
,
545 ret
= tstream_writev_recv(subreq
, &sys_errno
);
548 kdc_tcp_next_proxy(req
);
552 static void kdc_tcp_proxy_read_pdu_done(struct tevent_req
*subreq
)
554 struct tevent_req
*req
=
555 tevent_req_callback_data(subreq
,
557 struct kdc_tcp_proxy_state
*state
=
559 struct kdc_tcp_proxy_state
);
563 status
= tstream_read_pdu_blob_recv(subreq
, state
, &raw
);
565 if (!NT_STATUS_IS_OK(status
)) {
566 kdc_tcp_next_proxy(req
);
571 * raw blob has the length in the first 4 bytes,
572 * which we do not need here.
574 state
->out
= data_blob_talloc(state
, raw
.data
+ 4, raw
.length
- 4);
575 if (state
->out
.length
!= raw
.length
- 4) {
580 tevent_req_done(req
);
583 NTSTATUS
kdc_tcp_proxy_recv(struct tevent_req
*req
,
587 struct kdc_tcp_proxy_state
*state
=
589 struct kdc_tcp_proxy_state
);
592 if (tevent_req_is_nterror(req
, &status
)) {
593 tevent_req_received(req
);
597 out
->data
= talloc_move(mem_ctx
, &state
->out
.data
);
598 out
->length
= state
->out
.length
;
600 tevent_req_received(req
);