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 "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-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 */
kdc_proxy_get_writeable_dcs(struct kdc_server * kdc,TALLOC_CTX * mem_ctx,char *** proxy_list)40 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 werr = dsdb_loadreps(kdc->samdb, mem_ctx, ldb_get_default_basedn(kdc->samdb), "repsFrom", &reps, &count);
47 W_ERROR_NOT_OK_RETURN(werr);
48
49 if (count == 0) {
50 /* we don't have any DCs to replicate with. Very
51 strange for a RODC */
52 DEBUG(1,(__location__ ": No replication sources for RODC in KDC proxy\n"));
53 talloc_free(reps);
54 return WERR_DS_DRA_NO_REPLICA;
55 }
56
57 (*proxy_list) = talloc_array(mem_ctx, char *, count+1);
58 W_ERROR_HAVE_NO_MEMORY_AND_FREE(*proxy_list, reps);
59
60 talloc_steal(*proxy_list, reps);
61
62 for (i=0; i<count; i++) {
63 const char *dns_name = NULL;
64 if (reps->version == 1) {
65 dns_name = reps->ctr.ctr1.other_info->dns_name;
66 } else if (reps->version == 2) {
67 dns_name = reps->ctr.ctr2.other_info->dns_name1;
68 }
69 (*proxy_list)[i] = talloc_strdup(*proxy_list, dns_name);
70 W_ERROR_HAVE_NO_MEMORY_AND_FREE((*proxy_list)[i], *proxy_list);
71 }
72 (*proxy_list)[i] = NULL;
73
74 talloc_free(reps);
75
76 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
kdc_udp_proxy_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct kdc_server * kdc,uint16_t port,DATA_BLOB in)98 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 req = tevent_req_create(mem_ctx, &state,
109 struct kdc_udp_proxy_state);
110 if (req == NULL) {
111 return NULL;
112 }
113 state->ev = ev;
114 state->kdc = kdc;
115 state->port = port;
116 state->in = in;
117
118 werr = kdc_proxy_get_writeable_dcs(kdc, state, &state->proxy_list);
119 if (!W_ERROR_IS_OK(werr)) {
120 NTSTATUS status = werror_to_ntstatus(werr);
121 tevent_req_nterror(req, status);
122 return tevent_req_post(req, ev);
123 }
124
125 kdc_udp_next_proxy(req);
126 if (!tevent_req_is_in_progress(req)) {
127 return tevent_req_post(req, ev);
128 }
129
130 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 */
kdc_udp_next_proxy(struct tevent_req * req)138 static void kdc_udp_next_proxy(struct tevent_req *req)
139 {
140 struct kdc_udp_proxy_state *state =
141 tevent_req_data(req,
142 struct kdc_udp_proxy_state);
143 const char *proxy_dnsname = state->proxy_list[state->next_proxy];
144 struct composite_context *csubreq;
145
146 if (proxy_dnsname == NULL) {
147 tevent_req_nterror(req, NT_STATUS_NO_LOGON_SERVERS);
148 return;
149 }
150
151 state->next_proxy++;
152
153 /* make sure we close the socket of the last try */
154 TALLOC_FREE(state->proxy.dgram);
155 ZERO_STRUCT(state->proxy);
156
157 make_nbt_name(&state->proxy.name, proxy_dnsname, 0);
158
159 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 if (tevent_req_nomem(csubreq, req)) {
166 return;
167 }
168 csubreq->async.fn = kdc_udp_proxy_resolve_done;
169 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
kdc_udp_proxy_resolve_done(struct composite_context * csubreq)175 static void kdc_udp_proxy_resolve_done(struct composite_context *csubreq)
176 {
177 struct tevent_req *req =
178 talloc_get_type_abort(csubreq->async.private_data,
179 struct tevent_req);
180 struct kdc_udp_proxy_state *state =
181 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 status = resolve_name_recv(csubreq, state, &state->proxy.ip);
190 if (!NT_STATUS_IS_OK(status)) {
191 DEBUG(0,("Unable to resolve proxy[%s] - %s\n",
192 state->proxy.name.name, nt_errstr(status)));
193 kdc_udp_next_proxy(req);
194 return;
195 }
196
197 /* get an address for us to use locally */
198 ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0, &local_addr);
199 if (ret != 0) {
200 kdc_udp_next_proxy(req);
201 return;
202 }
203
204 ret = tsocket_address_inet_from_strings(state, "ip",
205 state->proxy.ip,
206 state->port,
207 &proxy_addr);
208 if (ret != 0) {
209 kdc_udp_next_proxy(req);
210 return;
211 }
212
213 /* create a socket for us to work on */
214 ret = tdgram_inet_udp_socket(local_addr, proxy_addr,
215 state, &state->proxy.dgram);
216 if (ret != 0) {
217 kdc_udp_next_proxy(req);
218 return;
219 }
220
221 subreq = tdgram_sendto_send(state,
222 state->ev,
223 state->proxy.dgram,
224 state->in.data,
225 state->in.length,
226 NULL);
227 if (tevent_req_nomem(subreq, req)) {
228 return;
229 }
230 tevent_req_set_callback(subreq, kdc_udp_proxy_sendto_done, req);
231
232 /* setup to receive the reply from the proxy */
233 subreq = tdgram_recvfrom_send(state, state->ev, state->proxy.dgram);
234 if (tevent_req_nomem(subreq, req)) {
235 return;
236 }
237 tevent_req_set_callback(subreq, kdc_udp_proxy_recvfrom_done, req);
238
239 ok = tevent_req_set_endtime(
240 subreq,
241 state->ev,
242 timeval_current_ofs(state->kdc->proxy_timeout, 0));
243 if (!ok) {
244 DBG_DEBUG("tevent_req_set_endtime failed\n");
245 return;
246 }
247
248 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 */
kdc_udp_proxy_sendto_done(struct tevent_req * subreq)256 static void kdc_udp_proxy_sendto_done(struct tevent_req *subreq)
257 {
258 struct tevent_req *req =
259 tevent_req_callback_data(subreq,
260 struct tevent_req);
261 struct kdc_udp_proxy_state *state =
262 tevent_req_data(req,
263 struct kdc_udp_proxy_state);
264 ssize_t ret;
265 int sys_errno;
266
267 ret = tdgram_sendto_recv(subreq, &sys_errno);
268 TALLOC_FREE(subreq);
269 if (ret == -1) {
270 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 kdc_udp_next_proxy(req);
274 }
275 }
276
277 /*
278 called when the proxy replies
279 */
kdc_udp_proxy_recvfrom_done(struct tevent_req * subreq)280 static void kdc_udp_proxy_recvfrom_done(struct tevent_req *subreq)
281 {
282 struct tevent_req *req =
283 tevent_req_callback_data(subreq,
284 struct tevent_req);
285 struct kdc_udp_proxy_state *state =
286 tevent_req_data(req,
287 struct kdc_udp_proxy_state);
288 int sys_errno;
289 uint8_t *buf;
290 ssize_t len;
291
292 len = tdgram_recvfrom_recv(subreq, &sys_errno,
293 state, &buf, NULL);
294 TALLOC_FREE(subreq);
295 if (len == -1) {
296 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 kdc_udp_next_proxy(req);
300 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 state->out.length = len;
309 state->out.data = buf;
310
311 tevent_req_done(req);
312 }
313
kdc_udp_proxy_recv(struct tevent_req * req,TALLOC_CTX * mem_ctx,DATA_BLOB * out)314 NTSTATUS kdc_udp_proxy_recv(struct tevent_req *req,
315 TALLOC_CTX *mem_ctx,
316 DATA_BLOB *out)
317 {
318 struct kdc_udp_proxy_state *state =
319 tevent_req_data(req,
320 struct kdc_udp_proxy_state);
321 NTSTATUS status;
322
323 if (tevent_req_is_nterror(req, &status)) {
324 tevent_req_received(req);
325 return status;
326 }
327
328 out->data = talloc_move(mem_ctx, &state->out.data);
329 out->length = state->out.length;
330
331 tevent_req_received(req);
332 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
kdc_tcp_proxy_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct kdc_server * kdc,uint16_t port,DATA_BLOB in)354 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 req = tevent_req_create(mem_ctx, &state,
365 struct kdc_tcp_proxy_state);
366 if (req == NULL) {
367 return NULL;
368 }
369 state->ev = ev;
370 state->kdc = kdc;
371 state->port = port;
372 state->in = in;
373
374 werr = kdc_proxy_get_writeable_dcs(kdc, state, &state->proxy_list);
375 if (!W_ERROR_IS_OK(werr)) {
376 NTSTATUS status = werror_to_ntstatus(werr);
377 tevent_req_nterror(req, status);
378 return tevent_req_post(req, ev);
379 }
380
381 RSIVAL(state->in_hdr, 0, state->in.length);
382 state->in_iov[0].iov_base = (char *)state->in_hdr;
383 state->in_iov[0].iov_len = 4;
384 state->in_iov[1].iov_base = (char *)state->in.data;
385 state->in_iov[1].iov_len = state->in.length;
386
387 kdc_tcp_next_proxy(req);
388 if (!tevent_req_is_in_progress(req)) {
389 return tevent_req_post(req, ev);
390 }
391
392 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 */
kdc_tcp_next_proxy(struct tevent_req * req)400 static void kdc_tcp_next_proxy(struct tevent_req *req)
401 {
402 struct kdc_tcp_proxy_state *state =
403 tevent_req_data(req,
404 struct kdc_tcp_proxy_state);
405 const char *proxy_dnsname = state->proxy_list[state->next_proxy];
406 struct composite_context *csubreq;
407
408 if (proxy_dnsname == NULL) {
409 tevent_req_nterror(req, NT_STATUS_NO_LOGON_SERVERS);
410 return;
411 }
412
413 state->next_proxy++;
414
415 /* make sure we close the socket of the last try */
416 TALLOC_FREE(state->proxy.stream);
417 ZERO_STRUCT(state->proxy);
418
419 make_nbt_name(&state->proxy.name, proxy_dnsname, 0);
420
421 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 if (tevent_req_nomem(csubreq, req)) {
428 return;
429 }
430 csubreq->async.fn = kdc_tcp_proxy_resolve_done;
431 csubreq->async.private_data = req;
432 }
433
434 static void kdc_tcp_proxy_connect_done(struct tevent_req *subreq);
435
kdc_tcp_proxy_resolve_done(struct composite_context * csubreq)436 static void kdc_tcp_proxy_resolve_done(struct composite_context *csubreq)
437 {
438 struct tevent_req *req =
439 talloc_get_type_abort(csubreq->async.private_data,
440 struct tevent_req);
441 struct kdc_tcp_proxy_state *state =
442 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 status = resolve_name_recv(csubreq, state, &state->proxy.ip);
450 if (!NT_STATUS_IS_OK(status)) {
451 DEBUG(0,("Unable to resolve proxy[%s] - %s\n",
452 state->proxy.name.name, nt_errstr(status)));
453 kdc_tcp_next_proxy(req);
454 return;
455 }
456
457 /* get an address for us to use locally */
458 ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0, &local_addr);
459 if (ret != 0) {
460 kdc_tcp_next_proxy(req);
461 return;
462 }
463
464 ret = tsocket_address_inet_from_strings(state, "ip",
465 state->proxy.ip,
466 state->port,
467 &proxy_addr);
468 if (ret != 0) {
469 kdc_tcp_next_proxy(req);
470 return;
471 }
472
473 subreq = tstream_inet_tcp_connect_send(state, state->ev,
474 local_addr, proxy_addr);
475 if (tevent_req_nomem(subreq, req)) {
476 return;
477 }
478 tevent_req_set_callback(subreq, kdc_tcp_proxy_connect_done, req);
479 tevent_req_set_endtime(subreq, state->ev,
480 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
kdc_tcp_proxy_connect_done(struct tevent_req * subreq)486 static void kdc_tcp_proxy_connect_done(struct tevent_req *subreq)
487 {
488 struct tevent_req *req =
489 tevent_req_callback_data(subreq,
490 struct tevent_req);
491 struct kdc_tcp_proxy_state *state =
492 tevent_req_data(req,
493 struct kdc_tcp_proxy_state);
494 int ret, sys_errno;
495
496 ret = tstream_inet_tcp_connect_recv(subreq, &sys_errno,
497 state, &state->proxy.stream, NULL);
498 TALLOC_FREE(subreq);
499 if (ret != 0) {
500 kdc_tcp_next_proxy(req);
501 return;
502 }
503
504 subreq = tstream_writev_send(state,
505 state->ev,
506 state->proxy.stream,
507 state->in_iov, 2);
508 if (tevent_req_nomem(subreq, req)) {
509 return;
510 }
511 tevent_req_set_callback(subreq, kdc_tcp_proxy_writev_done, req);
512
513 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 if (tevent_req_nomem(subreq, req)) {
520 return;
521 }
522 tevent_req_set_callback(subreq, kdc_tcp_proxy_read_pdu_done, req);
523 tevent_req_set_endtime(subreq, state->kdc->task->event_ctx,
524 timeval_current_ofs(state->kdc->proxy_timeout, 0));
525
526 DEBUG(4,("kdc_tcp_proxy: proxying request to %s[%s]\n",
527 state->proxy.name.name, state->proxy.ip));
528 }
529
kdc_tcp_proxy_writev_done(struct tevent_req * subreq)530 static void kdc_tcp_proxy_writev_done(struct tevent_req *subreq)
531 {
532 struct tevent_req *req =
533 tevent_req_callback_data(subreq,
534 struct tevent_req);
535 int ret, sys_errno;
536
537 ret = tstream_writev_recv(subreq, &sys_errno);
538 TALLOC_FREE(subreq);
539 if (ret == -1) {
540 kdc_tcp_next_proxy(req);
541 }
542 }
543
kdc_tcp_proxy_read_pdu_done(struct tevent_req * subreq)544 static void kdc_tcp_proxy_read_pdu_done(struct tevent_req *subreq)
545 {
546 struct tevent_req *req =
547 tevent_req_callback_data(subreq,
548 struct tevent_req);
549 struct kdc_tcp_proxy_state *state =
550 tevent_req_data(req,
551 struct kdc_tcp_proxy_state);
552 NTSTATUS status;
553 DATA_BLOB raw;
554
555 status = tstream_read_pdu_blob_recv(subreq, state, &raw);
556 TALLOC_FREE(subreq);
557 if (!NT_STATUS_IS_OK(status)) {
558 kdc_tcp_next_proxy(req);
559 return;
560 }
561
562 /*
563 * raw blob has the length in the first 4 bytes,
564 * which we do not need here.
565 */
566 state->out = data_blob_talloc(state, raw.data + 4, raw.length - 4);
567 if (state->out.length != raw.length - 4) {
568 tevent_req_oom(req);
569 return;
570 }
571
572 tevent_req_done(req);
573 }
574
kdc_tcp_proxy_recv(struct tevent_req * req,TALLOC_CTX * mem_ctx,DATA_BLOB * out)575 NTSTATUS kdc_tcp_proxy_recv(struct tevent_req *req,
576 TALLOC_CTX *mem_ctx,
577 DATA_BLOB *out)
578 {
579 struct kdc_tcp_proxy_state *state =
580 tevent_req_data(req,
581 struct kdc_tcp_proxy_state);
582 NTSTATUS status;
583
584 if (tevent_req_is_nterror(req, &status)) {
585 tevent_req_received(req);
586 return status;
587 }
588
589 out->data = talloc_move(mem_ctx, &state->out.data);
590 out->length = state->out.length;
591
592 tevent_req_received(req);
593 return NT_STATUS_OK;
594 }
595