Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : KDC Server request proxying
5 :
6 : Copyright (C) Andrew Tridgell 2010
7 : Copyright (C) Andrew Bartlett 2010
8 : Copyright (C) Stefan Metzmacher 2011
9 :
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.
14 :
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.
19 :
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/>.
22 : */
23 :
24 : #include "includes.h"
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"
35 :
36 :
37 : /*
38 : get a list of our replication partners from repsFrom, returning it in *proxy_list
39 : */
40 3053 : static WERROR kdc_proxy_get_writeable_dcs(struct kdc_server *kdc, TALLOC_CTX *mem_ctx, char ***proxy_list)
41 : {
42 : WERROR werr;
43 : uint32_t count, i;
44 : struct repsFromToBlob *reps;
45 :
46 3053 : werr = dsdb_loadreps(kdc->samdb, mem_ctx, ldb_get_default_basedn(kdc->samdb), "repsFrom", &reps, &count);
47 3053 : W_ERROR_NOT_OK_RETURN(werr);
48 :
49 3053 : if (count == 0) {
50 : /* we don't have any DCs to replicate with. Very
51 : strange for a RODC */
52 0 : DEBUG(1,(__location__ ": No replication sources for RODC in KDC proxy\n"));
53 0 : talloc_free(reps);
54 0 : return WERR_DS_DRA_NO_REPLICA;
55 : }
56 :
57 3053 : (*proxy_list) = talloc_array(mem_ctx, char *, count+1);
58 3053 : W_ERROR_HAVE_NO_MEMORY_AND_FREE(*proxy_list, reps);
59 :
60 3053 : talloc_steal(*proxy_list, reps);
61 :
62 6106 : for (i=0; i<count; i++) {
63 3053 : const char *dns_name = NULL;
64 3053 : if (reps->version == 1) {
65 3053 : dns_name = reps->ctr.ctr1.other_info->dns_name;
66 0 : } else if (reps->version == 2) {
67 0 : dns_name = reps->ctr.ctr2.other_info->dns_name1;
68 : }
69 3053 : (*proxy_list)[i] = talloc_strdup(*proxy_list, dns_name);
70 3053 : W_ERROR_HAVE_NO_MEMORY_AND_FREE((*proxy_list)[i], *proxy_list);
71 : }
72 3053 : (*proxy_list)[i] = NULL;
73 :
74 3053 : talloc_free(reps);
75 :
76 3053 : return WERR_OK;
77 : }
78 :
79 :
80 : struct kdc_udp_proxy_state {
81 : struct tevent_context *ev;
82 : struct kdc_server *kdc;
83 : uint16_t port;
84 : DATA_BLOB in;
85 : DATA_BLOB out;
86 : char **proxy_list;
87 : uint32_t next_proxy;
88 : struct {
89 : struct nbt_name name;
90 : const char *ip;
91 : struct tdgram_context *dgram;
92 : } proxy;
93 : };
94 :
95 :
96 : static void kdc_udp_next_proxy(struct tevent_req *req);
97 :
98 939 : struct tevent_req *kdc_udp_proxy_send(TALLOC_CTX *mem_ctx,
99 : struct tevent_context *ev,
100 : struct kdc_server *kdc,
101 : uint16_t port,
102 : DATA_BLOB in)
103 : {
104 : struct tevent_req *req;
105 : struct kdc_udp_proxy_state *state;
106 : WERROR werr;
107 :
108 939 : req = tevent_req_create(mem_ctx, &state,
109 : struct kdc_udp_proxy_state);
110 939 : if (req == NULL) {
111 0 : return NULL;
112 : }
113 939 : state->ev = ev;
114 939 : state->kdc = kdc;
115 939 : state->port = port;
116 939 : state->in = in;
117 :
118 939 : werr = kdc_proxy_get_writeable_dcs(kdc, state, &state->proxy_list);
119 939 : if (!W_ERROR_IS_OK(werr)) {
120 0 : NTSTATUS status = werror_to_ntstatus(werr);
121 0 : tevent_req_nterror(req, status);
122 0 : return tevent_req_post(req, ev);
123 : }
124 :
125 939 : kdc_udp_next_proxy(req);
126 939 : if (!tevent_req_is_in_progress(req)) {
127 0 : return tevent_req_post(req, ev);
128 : }
129 :
130 939 : return req;
131 : }
132 :
133 : static void kdc_udp_proxy_resolve_done(struct composite_context *csubreq);
134 :
135 : /*
136 : try the next proxy in the list
137 : */
138 939 : static void kdc_udp_next_proxy(struct tevent_req *req)
139 : {
140 939 : struct kdc_udp_proxy_state *state =
141 939 : tevent_req_data(req,
142 : struct kdc_udp_proxy_state);
143 939 : const char *proxy_dnsname = state->proxy_list[state->next_proxy];
144 : struct composite_context *csubreq;
145 :
146 939 : if (proxy_dnsname == NULL) {
147 0 : tevent_req_nterror(req, NT_STATUS_NO_LOGON_SERVERS);
148 0 : return;
149 : }
150 :
151 939 : state->next_proxy++;
152 :
153 : /* make sure we close the socket of the last try */
154 939 : TALLOC_FREE(state->proxy.dgram);
155 939 : ZERO_STRUCT(state->proxy);
156 :
157 939 : make_nbt_name(&state->proxy.name, proxy_dnsname, 0);
158 :
159 939 : csubreq = resolve_name_ex_send(lpcfg_resolve_context(state->kdc->task->lp_ctx),
160 : state,
161 : RESOLVE_NAME_FLAG_FORCE_DNS,
162 : 0,
163 : &state->proxy.name,
164 : state->ev);
165 939 : if (tevent_req_nomem(csubreq, req)) {
166 0 : return;
167 : }
168 939 : csubreq->async.fn = kdc_udp_proxy_resolve_done;
169 939 : csubreq->async.private_data = req;
170 : }
171 :
172 : static void kdc_udp_proxy_sendto_done(struct tevent_req *subreq);
173 : static void kdc_udp_proxy_recvfrom_done(struct tevent_req *subreq);
174 :
175 939 : static void kdc_udp_proxy_resolve_done(struct composite_context *csubreq)
176 : {
177 939 : struct tevent_req *req =
178 939 : talloc_get_type_abort(csubreq->async.private_data,
179 : struct tevent_req);
180 939 : struct kdc_udp_proxy_state *state =
181 939 : tevent_req_data(req,
182 : struct kdc_udp_proxy_state);
183 : NTSTATUS status;
184 : struct tevent_req *subreq;
185 : struct tsocket_address *local_addr, *proxy_addr;
186 : int ret;
187 : bool ok;
188 :
189 939 : status = resolve_name_recv(csubreq, state, &state->proxy.ip);
190 939 : if (!NT_STATUS_IS_OK(status)) {
191 0 : DEBUG(0,("Unable to resolve proxy[%s] - %s\n",
192 : state->proxy.name.name, nt_errstr(status)));
193 0 : kdc_udp_next_proxy(req);
194 0 : return;
195 : }
196 :
197 : /* get an address for us to use locally */
198 939 : ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0, &local_addr);
199 939 : if (ret != 0) {
200 0 : kdc_udp_next_proxy(req);
201 0 : return;
202 : }
203 :
204 939 : ret = tsocket_address_inet_from_strings(state, "ip",
205 : state->proxy.ip,
206 : state->port,
207 : &proxy_addr);
208 939 : if (ret != 0) {
209 0 : kdc_udp_next_proxy(req);
210 0 : return;
211 : }
212 :
213 : /* create a socket for us to work on */
214 939 : ret = tdgram_inet_udp_socket(local_addr, proxy_addr,
215 : state, &state->proxy.dgram);
216 939 : if (ret != 0) {
217 0 : kdc_udp_next_proxy(req);
218 0 : return;
219 : }
220 :
221 1878 : subreq = tdgram_sendto_send(state,
222 : state->ev,
223 : state->proxy.dgram,
224 939 : state->in.data,
225 : state->in.length,
226 : NULL);
227 939 : if (tevent_req_nomem(subreq, req)) {
228 0 : return;
229 : }
230 939 : tevent_req_set_callback(subreq, kdc_udp_proxy_sendto_done, req);
231 :
232 : /* setup to receive the reply from the proxy */
233 939 : subreq = tdgram_recvfrom_send(state, state->ev, state->proxy.dgram);
234 939 : if (tevent_req_nomem(subreq, req)) {
235 0 : return;
236 : }
237 939 : tevent_req_set_callback(subreq, kdc_udp_proxy_recvfrom_done, req);
238 :
239 939 : ok = tevent_req_set_endtime(
240 : subreq,
241 : state->ev,
242 939 : timeval_current_ofs(state->kdc->proxy_timeout, 0));
243 939 : if (!ok) {
244 0 : DBG_DEBUG("tevent_req_set_endtime failed\n");
245 0 : return;
246 : }
247 :
248 939 : DEBUG(4,("kdc_udp_proxy: proxying request to %s[%s]\n",
249 : state->proxy.name.name, state->proxy.ip));
250 : }
251 :
252 : /*
253 : called when the send of the call to the proxy is complete
254 : this is used to get an errors from the sendto()
255 : */
256 939 : static void kdc_udp_proxy_sendto_done(struct tevent_req *subreq)
257 : {
258 939 : struct tevent_req *req =
259 939 : tevent_req_callback_data(subreq,
260 : struct tevent_req);
261 939 : struct kdc_udp_proxy_state *state =
262 939 : tevent_req_data(req,
263 : struct kdc_udp_proxy_state);
264 : ssize_t ret;
265 : int sys_errno;
266 :
267 939 : ret = tdgram_sendto_recv(subreq, &sys_errno);
268 939 : TALLOC_FREE(subreq);
269 939 : if (ret == -1) {
270 0 : DEBUG(4,("kdc_udp_proxy: sendto for %s[%s] gave %d : %s\n",
271 : state->proxy.name.name, state->proxy.ip,
272 : sys_errno, strerror(sys_errno)));
273 0 : kdc_udp_next_proxy(req);
274 : }
275 939 : }
276 :
277 : /*
278 : called when the proxy replies
279 : */
280 939 : static void kdc_udp_proxy_recvfrom_done(struct tevent_req *subreq)
281 : {
282 939 : struct tevent_req *req =
283 939 : tevent_req_callback_data(subreq,
284 : struct tevent_req);
285 939 : struct kdc_udp_proxy_state *state =
286 939 : tevent_req_data(req,
287 : struct kdc_udp_proxy_state);
288 : int sys_errno;
289 : uint8_t *buf;
290 : ssize_t len;
291 :
292 939 : len = tdgram_recvfrom_recv(subreq, &sys_errno,
293 : state, &buf, NULL);
294 939 : TALLOC_FREE(subreq);
295 939 : if (len == -1) {
296 0 : DEBUG(4,("kdc_udp_proxy: reply from %s[%s] gave %d : %s\n",
297 : state->proxy.name.name, state->proxy.ip,
298 : sys_errno, strerror(sys_errno)));
299 0 : kdc_udp_next_proxy(req);
300 0 : return;
301 : }
302 :
303 : /*
304 : * Check the reply came from the right IP?
305 : * As we use connected udp sockets, that should not be needed...
306 : */
307 :
308 939 : state->out.length = len;
309 939 : state->out.data = buf;
310 :
311 939 : tevent_req_done(req);
312 : }
313 :
314 939 : NTSTATUS kdc_udp_proxy_recv(struct tevent_req *req,
315 : TALLOC_CTX *mem_ctx,
316 : DATA_BLOB *out)
317 : {
318 939 : struct kdc_udp_proxy_state *state =
319 939 : tevent_req_data(req,
320 : struct kdc_udp_proxy_state);
321 : NTSTATUS status;
322 :
323 939 : if (tevent_req_is_nterror(req, &status)) {
324 0 : tevent_req_received(req);
325 0 : return status;
326 : }
327 :
328 939 : out->data = talloc_move(mem_ctx, &state->out.data);
329 939 : out->length = state->out.length;
330 :
331 939 : tevent_req_received(req);
332 939 : return NT_STATUS_OK;
333 : }
334 :
335 : struct kdc_tcp_proxy_state {
336 : struct tevent_context *ev;
337 : struct kdc_server *kdc;
338 : uint16_t port;
339 : DATA_BLOB in;
340 : uint8_t in_hdr[4];
341 : struct iovec in_iov[2];
342 : DATA_BLOB out;
343 : char **proxy_list;
344 : uint32_t next_proxy;
345 : struct {
346 : struct nbt_name name;
347 : const char *ip;
348 : struct tstream_context *stream;
349 : } proxy;
350 : };
351 :
352 : static void kdc_tcp_next_proxy(struct tevent_req *req);
353 :
354 2114 : struct tevent_req *kdc_tcp_proxy_send(TALLOC_CTX *mem_ctx,
355 : struct tevent_context *ev,
356 : struct kdc_server *kdc,
357 : uint16_t port,
358 : DATA_BLOB in)
359 : {
360 : struct tevent_req *req;
361 : struct kdc_tcp_proxy_state *state;
362 : WERROR werr;
363 :
364 2114 : req = tevent_req_create(mem_ctx, &state,
365 : struct kdc_tcp_proxy_state);
366 2114 : if (req == NULL) {
367 0 : return NULL;
368 : }
369 2114 : state->ev = ev;
370 2114 : state->kdc = kdc;
371 2114 : state->port = port;
372 2114 : state->in = in;
373 :
374 2114 : werr = kdc_proxy_get_writeable_dcs(kdc, state, &state->proxy_list);
375 2114 : if (!W_ERROR_IS_OK(werr)) {
376 0 : NTSTATUS status = werror_to_ntstatus(werr);
377 0 : tevent_req_nterror(req, status);
378 0 : return tevent_req_post(req, ev);
379 : }
380 :
381 2114 : RSIVAL(state->in_hdr, 0, state->in.length);
382 2114 : state->in_iov[0].iov_base = (char *)state->in_hdr;
383 2114 : state->in_iov[0].iov_len = 4;
384 2114 : state->in_iov[1].iov_base = (char *)state->in.data;
385 2114 : state->in_iov[1].iov_len = state->in.length;
386 :
387 2114 : kdc_tcp_next_proxy(req);
388 2114 : if (!tevent_req_is_in_progress(req)) {
389 0 : return tevent_req_post(req, ev);
390 : }
391 :
392 2114 : return req;
393 : }
394 :
395 : static void kdc_tcp_proxy_resolve_done(struct composite_context *csubreq);
396 :
397 : /*
398 : try the next proxy in the list
399 : */
400 2114 : static void kdc_tcp_next_proxy(struct tevent_req *req)
401 : {
402 2114 : struct kdc_tcp_proxy_state *state =
403 2114 : tevent_req_data(req,
404 : struct kdc_tcp_proxy_state);
405 2114 : const char *proxy_dnsname = state->proxy_list[state->next_proxy];
406 : struct composite_context *csubreq;
407 :
408 2114 : if (proxy_dnsname == NULL) {
409 0 : tevent_req_nterror(req, NT_STATUS_NO_LOGON_SERVERS);
410 0 : return;
411 : }
412 :
413 2114 : state->next_proxy++;
414 :
415 : /* make sure we close the socket of the last try */
416 2114 : TALLOC_FREE(state->proxy.stream);
417 2114 : ZERO_STRUCT(state->proxy);
418 :
419 2114 : make_nbt_name(&state->proxy.name, proxy_dnsname, 0);
420 :
421 2114 : csubreq = resolve_name_ex_send(lpcfg_resolve_context(state->kdc->task->lp_ctx),
422 : state,
423 : RESOLVE_NAME_FLAG_FORCE_DNS,
424 : 0,
425 : &state->proxy.name,
426 : state->ev);
427 2114 : if (tevent_req_nomem(csubreq, req)) {
428 0 : return;
429 : }
430 2114 : csubreq->async.fn = kdc_tcp_proxy_resolve_done;
431 2114 : csubreq->async.private_data = req;
432 : }
433 :
434 : static void kdc_tcp_proxy_connect_done(struct tevent_req *subreq);
435 :
436 2114 : static void kdc_tcp_proxy_resolve_done(struct composite_context *csubreq)
437 : {
438 2114 : struct tevent_req *req =
439 2114 : talloc_get_type_abort(csubreq->async.private_data,
440 : struct tevent_req);
441 2114 : struct kdc_tcp_proxy_state *state =
442 2114 : tevent_req_data(req,
443 : struct kdc_tcp_proxy_state);
444 : NTSTATUS status;
445 : struct tevent_req *subreq;
446 : struct tsocket_address *local_addr, *proxy_addr;
447 : int ret;
448 :
449 2114 : status = resolve_name_recv(csubreq, state, &state->proxy.ip);
450 2114 : if (!NT_STATUS_IS_OK(status)) {
451 0 : DEBUG(0,("Unable to resolve proxy[%s] - %s\n",
452 : state->proxy.name.name, nt_errstr(status)));
453 0 : kdc_tcp_next_proxy(req);
454 0 : return;
455 : }
456 :
457 : /* get an address for us to use locally */
458 2114 : ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0, &local_addr);
459 2114 : if (ret != 0) {
460 0 : kdc_tcp_next_proxy(req);
461 0 : return;
462 : }
463 :
464 2114 : ret = tsocket_address_inet_from_strings(state, "ip",
465 : state->proxy.ip,
466 : state->port,
467 : &proxy_addr);
468 2114 : if (ret != 0) {
469 0 : kdc_tcp_next_proxy(req);
470 0 : return;
471 : }
472 :
473 2114 : subreq = tstream_inet_tcp_connect_send(state, state->ev,
474 : local_addr, proxy_addr);
475 2114 : if (tevent_req_nomem(subreq, req)) {
476 0 : return;
477 : }
478 2114 : tevent_req_set_callback(subreq, kdc_tcp_proxy_connect_done, req);
479 2114 : tevent_req_set_endtime(subreq, state->ev,
480 2114 : timeval_current_ofs(state->kdc->proxy_timeout, 0));
481 : }
482 :
483 : static void kdc_tcp_proxy_writev_done(struct tevent_req *subreq);
484 : static void kdc_tcp_proxy_read_pdu_done(struct tevent_req *subreq);
485 :
486 2114 : static void kdc_tcp_proxy_connect_done(struct tevent_req *subreq)
487 : {
488 2114 : struct tevent_req *req =
489 2114 : tevent_req_callback_data(subreq,
490 : struct tevent_req);
491 2114 : struct kdc_tcp_proxy_state *state =
492 2114 : tevent_req_data(req,
493 : struct kdc_tcp_proxy_state);
494 : int ret, sys_errno;
495 :
496 2114 : ret = tstream_inet_tcp_connect_recv(subreq, &sys_errno,
497 : state, &state->proxy.stream, NULL);
498 2114 : TALLOC_FREE(subreq);
499 2114 : if (ret != 0) {
500 0 : kdc_tcp_next_proxy(req);
501 0 : return;
502 : }
503 :
504 2114 : subreq = tstream_writev_send(state,
505 : state->ev,
506 : state->proxy.stream,
507 2114 : state->in_iov, 2);
508 2114 : if (tevent_req_nomem(subreq, req)) {
509 0 : return;
510 : }
511 2114 : tevent_req_set_callback(subreq, kdc_tcp_proxy_writev_done, req);
512 :
513 2114 : subreq = tstream_read_pdu_blob_send(state,
514 : state->ev,
515 : state->proxy.stream,
516 : 4, /* initial_read_size */
517 : packet_full_request_u32,
518 : req);
519 2114 : if (tevent_req_nomem(subreq, req)) {
520 0 : return;
521 : }
522 2114 : tevent_req_set_callback(subreq, kdc_tcp_proxy_read_pdu_done, req);
523 2114 : tevent_req_set_endtime(subreq, state->kdc->task->event_ctx,
524 2114 : timeval_current_ofs(state->kdc->proxy_timeout, 0));
525 :
526 2114 : DEBUG(4,("kdc_tcp_proxy: proxying request to %s[%s]\n",
527 : state->proxy.name.name, state->proxy.ip));
528 : }
529 :
530 2114 : static void kdc_tcp_proxy_writev_done(struct tevent_req *subreq)
531 : {
532 2114 : struct tevent_req *req =
533 2114 : tevent_req_callback_data(subreq,
534 : struct tevent_req);
535 : int ret, sys_errno;
536 :
537 2114 : ret = tstream_writev_recv(subreq, &sys_errno);
538 2114 : TALLOC_FREE(subreq);
539 2114 : if (ret == -1) {
540 0 : kdc_tcp_next_proxy(req);
541 : }
542 2114 : }
543 :
544 2114 : static void kdc_tcp_proxy_read_pdu_done(struct tevent_req *subreq)
545 : {
546 2114 : struct tevent_req *req =
547 2114 : tevent_req_callback_data(subreq,
548 : struct tevent_req);
549 2114 : struct kdc_tcp_proxy_state *state =
550 2114 : tevent_req_data(req,
551 : struct kdc_tcp_proxy_state);
552 : NTSTATUS status;
553 : DATA_BLOB raw;
554 :
555 2114 : status = tstream_read_pdu_blob_recv(subreq, state, &raw);
556 2114 : TALLOC_FREE(subreq);
557 2114 : if (!NT_STATUS_IS_OK(status)) {
558 0 : kdc_tcp_next_proxy(req);
559 0 : return;
560 : }
561 :
562 : /*
563 : * raw blob has the length in the first 4 bytes,
564 : * which we do not need here.
565 : */
566 2114 : state->out = data_blob_talloc(state, raw.data + 4, raw.length - 4);
567 2114 : if (state->out.length != raw.length - 4) {
568 0 : tevent_req_oom(req);
569 0 : return;
570 : }
571 :
572 2114 : tevent_req_done(req);
573 : }
574 :
575 2114 : NTSTATUS kdc_tcp_proxy_recv(struct tevent_req *req,
576 : TALLOC_CTX *mem_ctx,
577 : DATA_BLOB *out)
578 : {
579 2114 : struct kdc_tcp_proxy_state *state =
580 2114 : tevent_req_data(req,
581 : struct kdc_tcp_proxy_state);
582 : NTSTATUS status;
583 :
584 2114 : if (tevent_req_is_nterror(req, &status)) {
585 0 : tevent_req_received(req);
586 0 : return status;
587 : }
588 :
589 2114 : out->data = talloc_move(mem_ctx, &state->out.data);
590 2114 : out->length = state->out.length;
591 :
592 2114 : tevent_req_received(req);
593 2114 : return NT_STATUS_OK;
594 : }
|