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