s4-ldb_modules/acl: Get correct NTDSDSA objectGUID to check SPN for
[Samba.git] / source4 / kdc / proxy.c
blob6179bf18ab18c961543c8d3ddc839348c50e592d
1 /*
2 Unix SMB/CIFS implementation.
4 KDC Server request proxying
6 Copyright (C) Andrew Tridgell 2010
7 Copyright (C) Andrew Bartlett 2010
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
24 #include "smbd/process_model.h"
25 #include "lib/tsocket/tsocket.h"
26 #include "libcli/util/tstream.h"
27 #include "lib/stream/packet.h"
28 #include "kdc/kdc-glue.h"
29 #include "dsdb/samdb/samdb.h"
30 #include "libcli/composite/composite.h"
31 #include "libcli/resolve/resolve.h"
35 get a list of our replication partners from repsFrom, returning it in *proxy_list
37 static WERROR kdc_proxy_get_writeable_dcs(struct kdc_server *kdc, TALLOC_CTX *mem_ctx, char ***proxy_list)
39 WERROR werr;
40 uint32_t count, i;
41 struct repsFromToBlob *reps;
43 werr = dsdb_loadreps(kdc->samdb, mem_ctx, ldb_get_default_basedn(kdc->samdb), "repsFrom", &reps, &count);
44 W_ERROR_NOT_OK_RETURN(werr);
46 if (count == 0) {
47 /* we don't have any DCs to replicate with. Very
48 strange for a RODC */
49 DEBUG(1,(__location__ ": No replication sources for RODC in KDC proxy\n"));
50 talloc_free(reps);
51 return WERR_DS_DRA_NO_REPLICA;
54 (*proxy_list) = talloc_array(mem_ctx, char *, count+1);
55 W_ERROR_HAVE_NO_MEMORY_AND_FREE(*proxy_list, reps);
57 talloc_steal(*proxy_list, reps);
59 for (i=0; i<count; i++) {
60 const char *dns_name = NULL;
61 if (reps->version == 1) {
62 dns_name = reps->ctr.ctr1.other_info->dns_name;
63 } else if (reps->version == 2) {
64 dns_name = reps->ctr.ctr2.other_info->dns_name1;
66 (*proxy_list)[i] = talloc_strdup(*proxy_list, dns_name);
67 W_ERROR_HAVE_NO_MEMORY_AND_FREE((*proxy_list)[i], *proxy_list);
69 (*proxy_list)[i] = NULL;
71 talloc_free(reps);
73 return WERR_OK;
77 struct kdc_udp_proxy_state {
78 struct kdc_udp_call *call;
79 struct kdc_udp_socket *sock;
80 struct kdc_server *kdc;
81 char **proxy_list;
82 uint32_t next_proxy;
83 const char *proxy_ip;
84 uint16_t port;
88 static void kdc_udp_next_proxy(struct kdc_udp_proxy_state *state);
91 called when the send of the call to the proxy is complete
92 this is used to get an errors from the sendto()
94 static void kdc_udp_proxy_sendto_done(struct tevent_req *req)
96 struct kdc_udp_proxy_state *state = tevent_req_callback_data(req,
97 struct kdc_udp_proxy_state);
98 ssize_t ret;
99 int sys_errno;
101 ret = tdgram_sendto_queue_recv(req, &sys_errno);
102 talloc_free(req);
104 if (ret == -1) {
105 DEBUG(4,("kdc_udp_proxy: sendto for %s gave %d : %s\n",
106 state->proxy_ip, sys_errno, strerror(sys_errno)));
107 kdc_udp_next_proxy(state);
112 called when the send of the reply to the client is complete
113 this is used to get an errors from the sendto()
115 static void kdc_udp_proxy_reply_done(struct tevent_req *req)
117 struct kdc_udp_proxy_state *state = tevent_req_callback_data(req,
118 struct kdc_udp_proxy_state);
119 ssize_t ret;
120 int sys_errno;
122 ret = tdgram_sendto_queue_recv(req, &sys_errno);
123 if (ret == -1) {
124 DEBUG(3,("kdc_udp_proxy: reply sendto gave %d : %s\n",
125 sys_errno, strerror(sys_errno)));
128 /* all done - we can destroy the proxy state */
129 talloc_free(req);
130 talloc_free(state);
135 called when the proxy replies
137 static void kdc_udp_proxy_reply(struct tevent_req *req)
139 struct kdc_udp_proxy_state *state = tevent_req_callback_data(req,
140 struct kdc_udp_proxy_state);
141 int sys_errno;
142 uint8_t *buf;
143 struct tsocket_address *src;
144 ssize_t len;
146 len = tdgram_recvfrom_recv(req, &sys_errno,
147 state, &buf, &src);
148 talloc_free(req);
149 if (len == -1) {
150 DEBUG(4,("kdc_udp_proxy: reply from %s gave %d : %s\n",
151 state->proxy_ip, sys_errno, strerror(sys_errno)));
152 kdc_udp_next_proxy(state);
153 return;
156 state->call->out.length = len;
157 state->call->out.data = buf;
159 /* TODO: check the reply came from the right IP? */
161 req = tdgram_sendto_queue_send(state,
162 state->kdc->task->event_ctx,
163 state->sock->dgram,
164 state->sock->send_queue,
165 state->call->out.data,
166 state->call->out.length,
167 state->call->src);
168 if (req == NULL) {
169 kdc_udp_next_proxy(state);
170 return;
173 tevent_req_set_callback(req, kdc_udp_proxy_reply_done, state);
178 called when we've resolved the name of a proxy
180 static void kdc_udp_proxy_resolve_done(struct composite_context *c)
182 struct kdc_udp_proxy_state *state;
183 NTSTATUS status;
184 struct tevent_req *req;
185 struct tsocket_address *local_addr, *proxy_addr;
186 int ret;
187 struct tdgram_context *dgram;
188 struct tevent_queue *send_queue;
190 state = talloc_get_type(c->async.private_data, struct kdc_udp_proxy_state);
192 status = resolve_name_recv(c, state, &state->proxy_ip);
193 if (!NT_STATUS_IS_OK(status)) {
194 DEBUG(0,("Unable to resolve proxy\n"));
195 kdc_udp_next_proxy(state);
196 return;
199 /* get an address for us to use locally */
200 ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0, &local_addr);
201 if (ret != 0) {
202 kdc_udp_next_proxy(state);
203 return;
206 ret = tsocket_address_inet_from_strings(state, "ip",
207 state->proxy_ip, state->port, &proxy_addr);
208 if (ret != 0) {
209 kdc_udp_next_proxy(state);
210 return;
213 /* create a socket for us to work on */
214 ret = tdgram_inet_udp_socket(local_addr, proxy_addr, state, &dgram);
215 if (ret != 0) {
216 kdc_udp_next_proxy(state);
217 return;
220 send_queue = tevent_queue_create(state, "kdc_udp_proxy");
221 if (send_queue == NULL) {
222 kdc_udp_next_proxy(state);
223 return;
226 req = tdgram_sendto_queue_send(state,
227 state->kdc->task->event_ctx,
228 dgram,
229 send_queue,
230 state->call->in.data,
231 state->call->in.length,
232 proxy_addr);
233 if (req == NULL) {
234 kdc_udp_next_proxy(state);
235 return;
238 tevent_req_set_callback(req, kdc_udp_proxy_sendto_done, state);
240 /* setup to receive the reply from the proxy */
241 req = tdgram_recvfrom_send(state, state->kdc->task->event_ctx, dgram);
242 if (req == NULL) {
243 kdc_udp_next_proxy(state);
244 return;
247 tevent_req_set_callback(req, kdc_udp_proxy_reply, state);
249 tevent_req_set_endtime(req, state->kdc->task->event_ctx,
250 timeval_current_ofs(state->kdc->proxy_timeout, 0));
252 DEBUG(4,("kdc_udp_proxy: proxying request to %s\n", state->proxy_ip));
257 called when our proxies are not available
259 static void kdc_udp_proxy_unavailable(struct kdc_udp_proxy_state *state)
261 int kret;
262 krb5_data k5_error_blob;
263 struct tevent_req *req;
265 kret = krb5_mk_error(state->kdc->smb_krb5_context->krb5_context,
266 KRB5KDC_ERR_SVC_UNAVAILABLE, NULL, NULL,
267 NULL, NULL, NULL, NULL, &k5_error_blob);
268 if (kret != 0) {
269 DEBUG(2,(__location__ ": Unable to form krb5 error reply\n"));
270 talloc_free(state);
271 return;
274 state->call->out = data_blob_talloc(state, k5_error_blob.data, k5_error_blob.length);
275 krb5_data_free(&k5_error_blob);
276 if (!state->call->out.data) {
277 talloc_free(state);
278 return;
281 req = tdgram_sendto_queue_send(state,
282 state->kdc->task->event_ctx,
283 state->sock->dgram,
284 state->sock->send_queue,
285 state->call->out.data,
286 state->call->out.length,
287 state->call->src);
288 if (!req) {
289 talloc_free(state);
290 return;
293 tevent_req_set_callback(req, kdc_udp_proxy_reply_done, state);
297 try the next proxy in the list
299 static void kdc_udp_next_proxy(struct kdc_udp_proxy_state *state)
301 const char *proxy_dnsname = state->proxy_list[state->next_proxy];
302 struct nbt_name name;
303 struct composite_context *c;
305 if (proxy_dnsname == NULL) {
306 kdc_udp_proxy_unavailable(state);
307 return;
310 state->next_proxy++;
312 make_nbt_name(&name, proxy_dnsname, 0);
314 c = resolve_name_ex_send(lpcfg_resolve_context(state->kdc->task->lp_ctx),
315 state,
316 RESOLVE_NAME_FLAG_FORCE_DNS,
318 &name,
319 state->kdc->task->event_ctx);
320 if (c == NULL) {
321 kdc_udp_next_proxy(state);
322 return;
324 c->async.fn = kdc_udp_proxy_resolve_done;
325 c->async.private_data = state;
330 proxy a UDP kdc request to a writeable DC
332 void kdc_udp_proxy(struct kdc_server *kdc, struct kdc_udp_socket *sock,
333 struct kdc_udp_call *call, uint16_t port)
335 struct kdc_udp_proxy_state *state;
336 WERROR werr;
338 state = talloc_zero(kdc, struct kdc_udp_proxy_state);
339 if (state == NULL) {
340 talloc_free(call);
341 return;
344 state->call = talloc_steal(state, call);
345 state->sock = sock;
346 state->kdc = kdc;
347 state->port = port;
349 werr = kdc_proxy_get_writeable_dcs(kdc, state, &state->proxy_list);
350 if (!W_ERROR_IS_OK(werr)) {
351 kdc_udp_proxy_unavailable(state);
352 return;
355 kdc_udp_next_proxy(state);
359 struct kdc_tcp_proxy_state {
360 struct kdc_tcp_call *call;
361 struct kdc_tcp_connection *kdc_conn;
362 struct kdc_server *kdc;
363 uint16_t port;
364 uint32_t next_proxy;
365 char **proxy_list;
366 const char *proxy_ip;
369 static void kdc_tcp_next_proxy(struct kdc_tcp_proxy_state *state);
372 called when the send of the proxied reply to the client is done
374 static void kdc_tcp_proxy_reply_done(struct tevent_req *req)
376 struct kdc_tcp_proxy_state *state = tevent_req_callback_data(req,
377 struct kdc_tcp_proxy_state);
378 int ret, sys_errno;
380 ret = tstream_writev_queue_recv(req, &sys_errno);
381 if (ret == -1) {
382 DEBUG(4,("kdc_tcp_proxy: writev of reply gave %d : %s\n",
383 sys_errno, strerror(sys_errno)));
385 talloc_free(req);
386 talloc_free(state);
390 called when the recv of the proxied reply is done
392 static void kdc_tcp_proxy_recv_done(struct tevent_req *req)
394 struct kdc_tcp_proxy_state *state = tevent_req_callback_data(req,
395 struct kdc_tcp_proxy_state);
396 NTSTATUS status;
398 status = tstream_read_pdu_blob_recv(req,
399 state,
400 &state->call->out);
401 talloc_free(req);
403 if (!NT_STATUS_IS_OK(status)) {
404 kdc_tcp_next_proxy(state);
405 return;
409 /* send the reply to the original caller */
411 state->call->out_iov[0].iov_base = (char *)state->call->out.data;
412 state->call->out_iov[0].iov_len = state->call->out.length;
414 req = tstream_writev_queue_send(state,
415 state->kdc_conn->conn->event.ctx,
416 state->kdc_conn->tstream,
417 state->kdc_conn->send_queue,
418 state->call->out_iov, 1);
419 if (req == NULL) {
420 kdc_tcp_next_proxy(state);
421 return;
424 tevent_req_set_callback(req, kdc_tcp_proxy_reply_done, state);
428 called when the send of the proxied packet is done
430 static void kdc_tcp_proxy_send_done(struct tevent_req *req)
432 struct kdc_tcp_proxy_state *state = tevent_req_callback_data(req,
433 struct kdc_tcp_proxy_state);
434 int ret, sys_errno;
436 ret = tstream_writev_queue_recv(req, &sys_errno);
437 talloc_free(req);
438 if (ret == -1) {
439 kdc_tcp_next_proxy(state);
444 called when we've connected to the proxy
446 static void kdc_tcp_proxy_connect_done(struct tevent_req *req)
448 struct kdc_tcp_proxy_state *state = tevent_req_callback_data(req,
449 struct kdc_tcp_proxy_state);
450 int ret, sys_errno;
451 struct tstream_context *stream;
452 struct tevent_queue *send_queue;
455 ret = tstream_inet_tcp_connect_recv(req, &sys_errno, state, &stream, NULL);
456 talloc_free(req);
458 if (ret != 0) {
459 kdc_tcp_next_proxy(state);
460 return;
463 RSIVAL(state->call->out_hdr, 0, state->call->in.length);
464 state->call->out_iov[0].iov_base = (char *)state->call->out_hdr;
465 state->call->out_iov[0].iov_len = 4;
466 state->call->out_iov[1].iov_base = (char *) state->call->in.data;
467 state->call->out_iov[1].iov_len = state->call->in.length;
469 send_queue = tevent_queue_create(state, "kdc_tcp_proxy");
470 if (send_queue == NULL) {
471 kdc_tcp_next_proxy(state);
472 return;
475 req = tstream_writev_queue_send(state,
476 state->kdc_conn->conn->event.ctx,
477 stream,
478 send_queue,
479 state->call->out_iov, 2);
480 if (req == NULL) {
481 kdc_tcp_next_proxy(state);
482 return;
485 tevent_req_set_callback(req, kdc_tcp_proxy_send_done, state);
487 req = tstream_read_pdu_blob_send(state,
488 state->kdc_conn->conn->event.ctx,
489 stream,
490 4, /* initial_read_size */
491 packet_full_request_u32,
492 state);
493 if (req == NULL) {
494 kdc_tcp_next_proxy(state);
495 return;
498 tevent_req_set_callback(req, kdc_tcp_proxy_recv_done, state);
499 tevent_req_set_endtime(req, state->kdc->task->event_ctx,
500 timeval_current_ofs(state->kdc->proxy_timeout, 0));
506 called when name resolution for a proxy is done
508 static void kdc_tcp_proxy_resolve_done(struct composite_context *c)
510 struct kdc_tcp_proxy_state *state;
511 NTSTATUS status;
512 struct tevent_req *req;
513 struct tsocket_address *local_addr, *proxy_addr;
514 int ret;
516 state = talloc_get_type(c->async.private_data, struct kdc_tcp_proxy_state);
518 status = resolve_name_recv(c, state, &state->proxy_ip);
519 if (!NT_STATUS_IS_OK(status)) {
520 kdc_tcp_next_proxy(state);
521 return;
524 /* get an address for us to use locally */
525 ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0, &local_addr);
526 if (ret != 0) {
527 kdc_tcp_next_proxy(state);
528 return;
531 ret = tsocket_address_inet_from_strings(state, "ip",
532 state->proxy_ip, state->port, &proxy_addr);
533 if (ret != 0) {
534 kdc_tcp_next_proxy(state);
535 return;
538 /* connect to the proxy */
539 req = tstream_inet_tcp_connect_send(state, state->kdc->task->event_ctx, local_addr, proxy_addr);
540 if (req == NULL) {
541 kdc_tcp_next_proxy(state);
542 return;
545 tevent_req_set_callback(req, kdc_tcp_proxy_connect_done, state);
547 tevent_req_set_endtime(req, state->kdc->task->event_ctx,
548 timeval_current_ofs(state->kdc->proxy_timeout, 0));
550 DEBUG(4,("kdc_tcp_proxy: proxying request to %s\n", state->proxy_ip));
555 called when our proxies are not available
557 static void kdc_tcp_proxy_unavailable(struct kdc_tcp_proxy_state *state)
559 int kret;
560 krb5_data k5_error_blob;
561 struct tevent_req *req;
563 kret = krb5_mk_error(state->kdc->smb_krb5_context->krb5_context,
564 KRB5KDC_ERR_SVC_UNAVAILABLE, NULL, NULL,
565 NULL, NULL, NULL, NULL, &k5_error_blob);
566 if (kret != 0) {
567 DEBUG(2,(__location__ ": Unable to form krb5 error reply\n"));
568 talloc_free(state);
569 return;
573 state->call->out = data_blob_talloc(state, k5_error_blob.data, k5_error_blob.length);
574 krb5_data_free(&k5_error_blob);
575 if (!state->call->out.data) {
576 talloc_free(state);
577 return;
580 state->call->out_iov[0].iov_base = (char *)state->call->out.data;
581 state->call->out_iov[0].iov_len = state->call->out.length;
583 req = tstream_writev_queue_send(state,
584 state->kdc_conn->conn->event.ctx,
585 state->kdc_conn->tstream,
586 state->kdc_conn->send_queue,
587 state->call->out_iov, 1);
588 if (!req) {
589 talloc_free(state);
590 return;
593 tevent_req_set_callback(req, kdc_tcp_proxy_reply_done, state);
597 try the next proxy in the list
599 static void kdc_tcp_next_proxy(struct kdc_tcp_proxy_state *state)
601 const char *proxy_dnsname = state->proxy_list[state->next_proxy];
602 struct nbt_name name;
603 struct composite_context *c;
605 if (proxy_dnsname == NULL) {
606 kdc_tcp_proxy_unavailable(state);
607 return;
610 state->next_proxy++;
612 make_nbt_name(&name, proxy_dnsname, 0);
614 c = resolve_name_ex_send(lpcfg_resolve_context(state->kdc->task->lp_ctx),
615 state,
616 RESOLVE_NAME_FLAG_FORCE_DNS,
618 &name,
619 state->kdc->task->event_ctx);
620 if (c == NULL) {
621 kdc_tcp_next_proxy(state);
622 return;
624 c->async.fn = kdc_tcp_proxy_resolve_done;
625 c->async.private_data = state;
630 proxy a TCP kdc request to a writeable DC
632 void kdc_tcp_proxy(struct kdc_server *kdc, struct kdc_tcp_connection *kdc_conn,
633 struct kdc_tcp_call *call, uint16_t port)
635 struct kdc_tcp_proxy_state *state;
636 WERROR werr;
638 state = talloc_zero(kdc_conn, struct kdc_tcp_proxy_state);
640 state->call = talloc_steal(state, call);
641 state->kdc_conn = kdc_conn;
642 state->kdc = kdc;
643 state->port = port;
645 werr = kdc_proxy_get_writeable_dcs(kdc, state, &state->proxy_list);
646 if (!W_ERROR_IS_OK(werr)) {
647 kdc_tcp_proxy_unavailable(state);
648 return;
651 kdc_tcp_next_proxy(state);