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