s3-printing: clean up get_correct_cversion error paths
[Samba.git] / source4 / kdc / proxy.c
blob3929a127efd575f1ea90f90775485a72fa2a97ac
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 "system/network.h"
28 #include "param/param.h"
29 #include "lib/stream/packet.h"
30 #include "kdc/kdc-glue.h"
31 #include "ldb.h"
32 #include "librpc/gen_ndr/drsblobs.h"
33 #include "dsdb/schema/schema.h"
34 #include "dsdb/common/proto.h"
35 #include "libcli/composite/composite.h"
36 #include "libcli/resolve/resolve.h"
40 get a list of our replication partners from repsFrom, returning it in *proxy_list
42 static WERROR kdc_proxy_get_writeable_dcs(struct kdc_server *kdc, TALLOC_CTX *mem_ctx, char ***proxy_list)
44 WERROR werr;
45 uint32_t count, i;
46 struct repsFromToBlob *reps;
48 werr = dsdb_loadreps(kdc->samdb, mem_ctx, ldb_get_default_basedn(kdc->samdb), "repsFrom", &reps, &count);
49 W_ERROR_NOT_OK_RETURN(werr);
51 if (count == 0) {
52 /* we don't have any DCs to replicate with. Very
53 strange for a RODC */
54 DEBUG(1,(__location__ ": No replication sources for RODC in KDC proxy\n"));
55 talloc_free(reps);
56 return WERR_DS_DRA_NO_REPLICA;
59 (*proxy_list) = talloc_array(mem_ctx, char *, count+1);
60 W_ERROR_HAVE_NO_MEMORY_AND_FREE(*proxy_list, reps);
62 talloc_steal(*proxy_list, reps);
64 for (i=0; i<count; i++) {
65 const char *dns_name = NULL;
66 if (reps->version == 1) {
67 dns_name = reps->ctr.ctr1.other_info->dns_name;
68 } else if (reps->version == 2) {
69 dns_name = reps->ctr.ctr2.other_info->dns_name1;
71 (*proxy_list)[i] = talloc_strdup(*proxy_list, dns_name);
72 W_ERROR_HAVE_NO_MEMORY_AND_FREE((*proxy_list)[i], *proxy_list);
74 (*proxy_list)[i] = NULL;
76 talloc_free(reps);
78 return WERR_OK;
82 struct kdc_udp_proxy_state {
83 struct kdc_udp_call *call;
84 struct kdc_udp_socket *sock;
85 struct kdc_server *kdc;
86 char **proxy_list;
87 uint32_t next_proxy;
88 const char *proxy_ip;
89 uint16_t port;
93 static void kdc_udp_next_proxy(struct kdc_udp_proxy_state *state);
96 called when the send of the call to the proxy is complete
97 this is used to get an errors from the sendto()
99 static void kdc_udp_proxy_sendto_done(struct tevent_req *req)
101 struct kdc_udp_proxy_state *state = tevent_req_callback_data(req,
102 struct kdc_udp_proxy_state);
103 ssize_t ret;
104 int sys_errno;
106 ret = tdgram_sendto_queue_recv(req, &sys_errno);
107 talloc_free(req);
109 if (ret == -1) {
110 DEBUG(4,("kdc_udp_proxy: sendto for %s gave %d : %s\n",
111 state->proxy_ip, sys_errno, strerror(sys_errno)));
112 kdc_udp_next_proxy(state);
117 called when the send of the reply to the client is complete
118 this is used to get an errors from the sendto()
120 static void kdc_udp_proxy_reply_done(struct tevent_req *req)
122 struct kdc_udp_proxy_state *state = tevent_req_callback_data(req,
123 struct kdc_udp_proxy_state);
124 ssize_t ret;
125 int sys_errno;
127 ret = tdgram_sendto_queue_recv(req, &sys_errno);
128 if (ret == -1) {
129 DEBUG(3,("kdc_udp_proxy: reply sendto gave %d : %s\n",
130 sys_errno, strerror(sys_errno)));
133 /* all done - we can destroy the proxy state */
134 talloc_free(req);
135 talloc_free(state);
140 called when the proxy replies
142 static void kdc_udp_proxy_reply(struct tevent_req *req)
144 struct kdc_udp_proxy_state *state = tevent_req_callback_data(req,
145 struct kdc_udp_proxy_state);
146 int sys_errno;
147 uint8_t *buf;
148 struct tsocket_address *src;
149 ssize_t len;
151 len = tdgram_recvfrom_recv(req, &sys_errno,
152 state, &buf, &src);
153 talloc_free(req);
154 if (len == -1) {
155 DEBUG(4,("kdc_udp_proxy: reply from %s gave %d : %s\n",
156 state->proxy_ip, sys_errno, strerror(sys_errno)));
157 kdc_udp_next_proxy(state);
158 return;
161 state->call->out.length = len;
162 state->call->out.data = buf;
164 /* TODO: check the reply came from the right IP? */
166 req = tdgram_sendto_queue_send(state,
167 state->kdc->task->event_ctx,
168 state->sock->dgram,
169 state->sock->send_queue,
170 state->call->out.data,
171 state->call->out.length,
172 state->call->src);
173 if (req == NULL) {
174 kdc_udp_next_proxy(state);
175 return;
178 tevent_req_set_callback(req, kdc_udp_proxy_reply_done, state);
183 called when we've resolved the name of a proxy
185 static void kdc_udp_proxy_resolve_done(struct composite_context *c)
187 struct kdc_udp_proxy_state *state;
188 NTSTATUS status;
189 struct tevent_req *req;
190 struct tsocket_address *local_addr, *proxy_addr;
191 int ret;
192 struct tdgram_context *dgram;
193 struct tevent_queue *send_queue;
195 state = talloc_get_type(c->async.private_data, struct kdc_udp_proxy_state);
197 status = resolve_name_recv(c, state, &state->proxy_ip);
198 if (!NT_STATUS_IS_OK(status)) {
199 DEBUG(0,("Unable to resolve proxy\n"));
200 kdc_udp_next_proxy(state);
201 return;
204 /* get an address for us to use locally */
205 ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0, &local_addr);
206 if (ret != 0) {
207 kdc_udp_next_proxy(state);
208 return;
211 ret = tsocket_address_inet_from_strings(state, "ip",
212 state->proxy_ip, state->port, &proxy_addr);
213 if (ret != 0) {
214 kdc_udp_next_proxy(state);
215 return;
218 /* create a socket for us to work on */
219 ret = tdgram_inet_udp_socket(local_addr, proxy_addr, state, &dgram);
220 if (ret != 0) {
221 kdc_udp_next_proxy(state);
222 return;
225 send_queue = tevent_queue_create(state, "kdc_udp_proxy");
226 if (send_queue == NULL) {
227 kdc_udp_next_proxy(state);
228 return;
231 req = tdgram_sendto_queue_send(state,
232 state->kdc->task->event_ctx,
233 dgram,
234 send_queue,
235 state->call->in.data,
236 state->call->in.length,
237 proxy_addr);
238 if (req == NULL) {
239 kdc_udp_next_proxy(state);
240 return;
243 tevent_req_set_callback(req, kdc_udp_proxy_sendto_done, state);
245 /* setup to receive the reply from the proxy */
246 req = tdgram_recvfrom_send(state, state->kdc->task->event_ctx, dgram);
247 if (req == NULL) {
248 kdc_udp_next_proxy(state);
249 return;
252 tevent_req_set_callback(req, kdc_udp_proxy_reply, state);
254 tevent_req_set_endtime(req, state->kdc->task->event_ctx,
255 timeval_current_ofs(state->kdc->proxy_timeout, 0));
257 DEBUG(4,("kdc_udp_proxy: proxying request to %s\n", state->proxy_ip));
262 called when our proxies are not available
264 static void kdc_udp_proxy_unavailable(struct kdc_udp_proxy_state *state)
266 int kret;
267 krb5_data k5_error_blob;
268 struct tevent_req *req;
270 kret = krb5_mk_error(state->kdc->smb_krb5_context->krb5_context,
271 KRB5KDC_ERR_SVC_UNAVAILABLE, NULL, NULL,
272 NULL, NULL, NULL, NULL, &k5_error_blob);
273 if (kret != 0) {
274 DEBUG(2,(__location__ ": Unable to form krb5 error reply\n"));
275 talloc_free(state);
276 return;
279 state->call->out = data_blob_talloc(state, k5_error_blob.data, k5_error_blob.length);
280 krb5_data_free(&k5_error_blob);
281 if (!state->call->out.data) {
282 talloc_free(state);
283 return;
286 req = tdgram_sendto_queue_send(state,
287 state->kdc->task->event_ctx,
288 state->sock->dgram,
289 state->sock->send_queue,
290 state->call->out.data,
291 state->call->out.length,
292 state->call->src);
293 if (!req) {
294 talloc_free(state);
295 return;
298 tevent_req_set_callback(req, kdc_udp_proxy_reply_done, state);
302 try the next proxy in the list
304 static void kdc_udp_next_proxy(struct kdc_udp_proxy_state *state)
306 const char *proxy_dnsname = state->proxy_list[state->next_proxy];
307 struct nbt_name name;
308 struct composite_context *c;
310 if (proxy_dnsname == NULL) {
311 kdc_udp_proxy_unavailable(state);
312 return;
315 state->next_proxy++;
317 make_nbt_name(&name, proxy_dnsname, 0);
319 c = resolve_name_ex_send(lpcfg_resolve_context(state->kdc->task->lp_ctx),
320 state,
321 RESOLVE_NAME_FLAG_FORCE_DNS,
323 &name,
324 state->kdc->task->event_ctx);
325 if (c == NULL) {
326 kdc_udp_next_proxy(state);
327 return;
329 c->async.fn = kdc_udp_proxy_resolve_done;
330 c->async.private_data = state;
335 proxy a UDP kdc request to a writeable DC
337 void kdc_udp_proxy(struct kdc_server *kdc, struct kdc_udp_socket *sock,
338 struct kdc_udp_call *call, uint16_t port)
340 struct kdc_udp_proxy_state *state;
341 WERROR werr;
343 state = talloc_zero(kdc, struct kdc_udp_proxy_state);
344 if (state == NULL) {
345 talloc_free(call);
346 return;
349 state->call = talloc_steal(state, call);
350 state->sock = sock;
351 state->kdc = kdc;
352 state->port = port;
354 werr = kdc_proxy_get_writeable_dcs(kdc, state, &state->proxy_list);
355 if (!W_ERROR_IS_OK(werr)) {
356 kdc_udp_proxy_unavailable(state);
357 return;
360 kdc_udp_next_proxy(state);
364 struct kdc_tcp_proxy_state {
365 struct kdc_tcp_call *call;
366 struct kdc_tcp_connection *kdc_conn;
367 struct kdc_server *kdc;
368 uint16_t port;
369 uint32_t next_proxy;
370 char **proxy_list;
371 const char *proxy_ip;
374 static void kdc_tcp_next_proxy(struct kdc_tcp_proxy_state *state);
377 called when the send of the proxied reply to the client is done
379 static void kdc_tcp_proxy_reply_done(struct tevent_req *req)
381 struct kdc_tcp_proxy_state *state = tevent_req_callback_data(req,
382 struct kdc_tcp_proxy_state);
383 int ret, sys_errno;
385 ret = tstream_writev_queue_recv(req, &sys_errno);
386 if (ret == -1) {
387 DEBUG(4,("kdc_tcp_proxy: writev of reply gave %d : %s\n",
388 sys_errno, strerror(sys_errno)));
390 talloc_free(req);
391 talloc_free(state);
395 called when the recv of the proxied reply is done
397 static void kdc_tcp_proxy_recv_done(struct tevent_req *req)
399 struct kdc_tcp_proxy_state *state = tevent_req_callback_data(req,
400 struct kdc_tcp_proxy_state);
401 NTSTATUS status;
403 status = tstream_read_pdu_blob_recv(req,
404 state,
405 &state->call->out);
406 talloc_free(req);
408 if (!NT_STATUS_IS_OK(status)) {
409 kdc_tcp_next_proxy(state);
410 return;
414 /* send the reply to the original caller */
416 state->call->out_iov[0].iov_base = (char *)state->call->out.data;
417 state->call->out_iov[0].iov_len = state->call->out.length;
419 req = tstream_writev_queue_send(state,
420 state->kdc_conn->conn->event.ctx,
421 state->kdc_conn->tstream,
422 state->kdc_conn->send_queue,
423 state->call->out_iov, 1);
424 if (req == NULL) {
425 kdc_tcp_next_proxy(state);
426 return;
429 tevent_req_set_callback(req, kdc_tcp_proxy_reply_done, state);
433 called when the send of the proxied packet is done
435 static void kdc_tcp_proxy_send_done(struct tevent_req *req)
437 struct kdc_tcp_proxy_state *state = tevent_req_callback_data(req,
438 struct kdc_tcp_proxy_state);
439 int ret, sys_errno;
441 ret = tstream_writev_queue_recv(req, &sys_errno);
442 talloc_free(req);
443 if (ret == -1) {
444 kdc_tcp_next_proxy(state);
449 called when we've connected to the proxy
451 static void kdc_tcp_proxy_connect_done(struct tevent_req *req)
453 struct kdc_tcp_proxy_state *state = tevent_req_callback_data(req,
454 struct kdc_tcp_proxy_state);
455 int ret, sys_errno;
456 struct tstream_context *stream;
457 struct tevent_queue *send_queue;
460 ret = tstream_inet_tcp_connect_recv(req, &sys_errno, state, &stream, NULL);
461 talloc_free(req);
463 if (ret != 0) {
464 kdc_tcp_next_proxy(state);
465 return;
468 RSIVAL(state->call->out_hdr, 0, state->call->in.length);
469 state->call->out_iov[0].iov_base = (char *)state->call->out_hdr;
470 state->call->out_iov[0].iov_len = 4;
471 state->call->out_iov[1].iov_base = (char *) state->call->in.data;
472 state->call->out_iov[1].iov_len = state->call->in.length;
474 send_queue = tevent_queue_create(state, "kdc_tcp_proxy");
475 if (send_queue == NULL) {
476 kdc_tcp_next_proxy(state);
477 return;
480 req = tstream_writev_queue_send(state,
481 state->kdc_conn->conn->event.ctx,
482 stream,
483 send_queue,
484 state->call->out_iov, 2);
485 if (req == NULL) {
486 kdc_tcp_next_proxy(state);
487 return;
490 tevent_req_set_callback(req, kdc_tcp_proxy_send_done, state);
492 req = tstream_read_pdu_blob_send(state,
493 state->kdc_conn->conn->event.ctx,
494 stream,
495 4, /* initial_read_size */
496 packet_full_request_u32,
497 state);
498 if (req == NULL) {
499 kdc_tcp_next_proxy(state);
500 return;
503 tevent_req_set_callback(req, kdc_tcp_proxy_recv_done, state);
504 tevent_req_set_endtime(req, state->kdc->task->event_ctx,
505 timeval_current_ofs(state->kdc->proxy_timeout, 0));
511 called when name resolution for a proxy is done
513 static void kdc_tcp_proxy_resolve_done(struct composite_context *c)
515 struct kdc_tcp_proxy_state *state;
516 NTSTATUS status;
517 struct tevent_req *req;
518 struct tsocket_address *local_addr, *proxy_addr;
519 int ret;
521 state = talloc_get_type(c->async.private_data, struct kdc_tcp_proxy_state);
523 status = resolve_name_recv(c, state, &state->proxy_ip);
524 if (!NT_STATUS_IS_OK(status)) {
525 kdc_tcp_next_proxy(state);
526 return;
529 /* get an address for us to use locally */
530 ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0, &local_addr);
531 if (ret != 0) {
532 kdc_tcp_next_proxy(state);
533 return;
536 ret = tsocket_address_inet_from_strings(state, "ip",
537 state->proxy_ip, state->port, &proxy_addr);
538 if (ret != 0) {
539 kdc_tcp_next_proxy(state);
540 return;
543 /* connect to the proxy */
544 req = tstream_inet_tcp_connect_send(state, state->kdc->task->event_ctx, local_addr, proxy_addr);
545 if (req == NULL) {
546 kdc_tcp_next_proxy(state);
547 return;
550 tevent_req_set_callback(req, kdc_tcp_proxy_connect_done, state);
552 tevent_req_set_endtime(req, state->kdc->task->event_ctx,
553 timeval_current_ofs(state->kdc->proxy_timeout, 0));
555 DEBUG(4,("kdc_tcp_proxy: proxying request to %s\n", state->proxy_ip));
560 called when our proxies are not available
562 static void kdc_tcp_proxy_unavailable(struct kdc_tcp_proxy_state *state)
564 int kret;
565 krb5_data k5_error_blob;
566 struct tevent_req *req;
568 kret = krb5_mk_error(state->kdc->smb_krb5_context->krb5_context,
569 KRB5KDC_ERR_SVC_UNAVAILABLE, NULL, NULL,
570 NULL, NULL, NULL, NULL, &k5_error_blob);
571 if (kret != 0) {
572 DEBUG(2,(__location__ ": Unable to form krb5 error reply\n"));
573 talloc_free(state);
574 return;
578 state->call->out = data_blob_talloc(state, k5_error_blob.data, k5_error_blob.length);
579 krb5_data_free(&k5_error_blob);
580 if (!state->call->out.data) {
581 talloc_free(state);
582 return;
585 state->call->out_iov[0].iov_base = (char *)state->call->out.data;
586 state->call->out_iov[0].iov_len = state->call->out.length;
588 req = tstream_writev_queue_send(state,
589 state->kdc_conn->conn->event.ctx,
590 state->kdc_conn->tstream,
591 state->kdc_conn->send_queue,
592 state->call->out_iov, 1);
593 if (!req) {
594 talloc_free(state);
595 return;
598 tevent_req_set_callback(req, kdc_tcp_proxy_reply_done, state);
602 try the next proxy in the list
604 static void kdc_tcp_next_proxy(struct kdc_tcp_proxy_state *state)
606 const char *proxy_dnsname = state->proxy_list[state->next_proxy];
607 struct nbt_name name;
608 struct composite_context *c;
610 if (proxy_dnsname == NULL) {
611 kdc_tcp_proxy_unavailable(state);
612 return;
615 state->next_proxy++;
617 make_nbt_name(&name, proxy_dnsname, 0);
619 c = resolve_name_ex_send(lpcfg_resolve_context(state->kdc->task->lp_ctx),
620 state,
621 RESOLVE_NAME_FLAG_FORCE_DNS,
623 &name,
624 state->kdc->task->event_ctx);
625 if (c == NULL) {
626 kdc_tcp_next_proxy(state);
627 return;
629 c->async.fn = kdc_tcp_proxy_resolve_done;
630 c->async.private_data = state;
635 proxy a TCP kdc request to a writeable DC
637 void kdc_tcp_proxy(struct kdc_server *kdc, struct kdc_tcp_connection *kdc_conn,
638 struct kdc_tcp_call *call, uint16_t port)
640 struct kdc_tcp_proxy_state *state;
641 WERROR werr;
643 state = talloc_zero(kdc_conn, struct kdc_tcp_proxy_state);
645 state->call = talloc_steal(state, call);
646 state->kdc_conn = kdc_conn;
647 state->kdc = kdc;
648 state->port = port;
650 werr = kdc_proxy_get_writeable_dcs(kdc, state, &state->proxy_list);
651 if (!W_ERROR_IS_OK(werr)) {
652 kdc_tcp_proxy_unavailable(state);
653 return;
656 kdc_tcp_next_proxy(state);