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/kdc-proxy.h"
32 #include "dsdb/samdb/samdb.h"
33 #include "libcli/composite/composite.h"
34 #include "libcli/resolve/resolve.h"
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
)
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
);
52 /* we don't have any DCs to replicate with. Very
54 DEBUG(1,(__location__
": No replication sources for RODC in KDC proxy\n"));
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
;
82 struct kdc_udp_proxy_state
{
83 struct tevent_context
*ev
;
84 struct kdc_server
*kdc
;
93 struct tdgram_context
*dgram
;
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
,
106 struct tevent_req
*req
;
107 struct kdc_udp_proxy_state
*state
;
110 req
= tevent_req_create(mem_ctx
, &state
,
111 struct kdc_udp_proxy_state
);
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
);
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
=
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
);
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
),
163 RESOLVE_NAME_FLAG_FORCE_DNS
,
167 if (tevent_req_nomem(csubreq
, req
)) {
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
,
182 struct kdc_udp_proxy_state
*state
=
184 struct kdc_udp_proxy_state
);
186 struct tevent_req
*subreq
;
187 struct tsocket_address
*local_addr
, *proxy_addr
;
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
);
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(req
);
206 ret
= tsocket_address_inet_from_strings(state
, "ip",
211 kdc_udp_next_proxy(req
);
215 /* create a socket for us to work on */
216 ret
= tdgram_inet_udp_socket(local_addr
, proxy_addr
,
217 state
, &state
->proxy
.dgram
);
219 kdc_udp_next_proxy(req
);
223 subreq
= tdgram_sendto_send(state
,
229 if (tevent_req_nomem(subreq
, req
)) {
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
)) {
239 tevent_req_set_callback(subreq
, kdc_udp_proxy_recvfrom_done
, req
);
241 ok
= tevent_req_set_endtime(
244 timeval_current_ofs(state
->kdc
->proxy_timeout
, 0));
246 DBG_DEBUG("tevent_req_set_endtime failed\n");
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
,
263 struct kdc_udp_proxy_state
*state
=
265 struct kdc_udp_proxy_state
);
269 ret
= tdgram_sendto_recv(subreq
, &sys_errno
);
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
,
287 struct kdc_udp_proxy_state
*state
=
289 struct kdc_udp_proxy_state
);
294 len
= tdgram_recvfrom_recv(subreq
, &sys_errno
,
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
);
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
,
320 struct kdc_udp_proxy_state
*state
=
322 struct kdc_udp_proxy_state
);
325 if (tevent_req_is_nterror(req
, &status
)) {
326 tevent_req_received(req
);
330 out
->data
= talloc_move(mem_ctx
, &state
->out
.data
);
331 out
->length
= state
->out
.length
;
333 tevent_req_received(req
);
337 struct kdc_tcp_proxy_state
{
338 struct tevent_context
*ev
;
339 struct kdc_server
*kdc
;
343 struct iovec in_iov
[2];
348 struct nbt_name name
;
350 struct tstream_context
*stream
;
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
,
362 struct tevent_req
*req
;
363 struct kdc_tcp_proxy_state
*state
;
366 req
= tevent_req_create(mem_ctx
, &state
,
367 struct kdc_tcp_proxy_state
);
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
);
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
=
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
);
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
),
425 RESOLVE_NAME_FLAG_FORCE_DNS
,
429 if (tevent_req_nomem(csubreq
, req
)) {
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
,
443 struct kdc_tcp_proxy_state
*state
=
445 struct kdc_tcp_proxy_state
);
447 struct tevent_req
*subreq
;
448 struct tsocket_address
*local_addr
, *proxy_addr
;
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
);
459 /* get an address for us to use locally */
460 ret
= tsocket_address_inet_from_strings(state
, "ip", NULL
, 0, &local_addr
);
462 kdc_tcp_next_proxy(req
);
466 ret
= tsocket_address_inet_from_strings(state
, "ip",
471 kdc_tcp_next_proxy(req
);
475 subreq
= tstream_inet_tcp_connect_send(state
, state
->ev
,
476 local_addr
, proxy_addr
);
477 if (tevent_req_nomem(subreq
, req
)) {
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
,
493 struct kdc_tcp_proxy_state
*state
=
495 struct kdc_tcp_proxy_state
);
498 ret
= tstream_inet_tcp_connect_recv(subreq
, &sys_errno
,
499 state
, &state
->proxy
.stream
, NULL
);
502 kdc_tcp_next_proxy(req
);
506 subreq
= tstream_writev_send(state
,
510 if (tevent_req_nomem(subreq
, req
)) {
513 tevent_req_set_callback(subreq
, kdc_tcp_proxy_writev_done
, req
);
515 subreq
= tstream_read_pdu_blob_send(state
,
518 4, /* initial_read_size */
519 packet_full_request_u32
,
521 if (tevent_req_nomem(subreq
, req
)) {
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
,
539 ret
= tstream_writev_recv(subreq
, &sys_errno
);
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
,
551 struct kdc_tcp_proxy_state
*state
=
553 struct kdc_tcp_proxy_state
);
557 status
= tstream_read_pdu_blob_recv(subreq
, state
, &raw
);
559 if (!NT_STATUS_IS_OK(status
)) {
560 kdc_tcp_next_proxy(req
);
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) {
574 tevent_req_done(req
);
577 NTSTATUS
kdc_tcp_proxy_recv(struct tevent_req
*req
,
581 struct kdc_tcp_proxy_state
*state
=
583 struct kdc_tcp_proxy_state
);
586 if (tevent_req_is_nterror(req
, &status
)) {
587 tevent_req_received(req
);
591 out
->data
= talloc_move(mem_ctx
, &state
->out
.data
);
592 out
->length
= state
->out
.length
;
594 tevent_req_received(req
);