libads: Make ads_cldap_netlogon() static
[samba4-gss.git] / source4 / kdc / kdc-proxy.c
blob4e990a9ce88a72152a365270df589a06fea28922
1 /*
2 Unix SMB/CIFS implementation.
4 KDC Server request proxying
6 Copyright (C) Andrew Tridgell 2010
7 Copyright (C) Andrew Bartlett 2010
8 Copyright (C) Stefan Metzmacher 2011
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.
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.
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/>.
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/samba_kdc.h"
32 #include "kdc/kdc-proxy.h"
33 #include "dsdb/samdb/samdb.h"
34 #include "libcli/composite/composite.h"
35 #include "libcli/resolve/resolve.h"
37 #undef DBGC_CLASS
38 #define DBGC_CLASS DBGC_KERBEROS
41 get a list of our replication partners from repsFrom, returning it in *proxy_list
43 static WERROR kdc_proxy_get_writeable_dcs(struct kdc_server *kdc, TALLOC_CTX *mem_ctx, char ***proxy_list)
45 WERROR werr;
46 uint32_t count, i;
47 struct repsFromToBlob *reps;
49 werr = dsdb_loadreps(kdc->kdc_db_ctx->samdb,
50 mem_ctx,
51 ldb_get_default_basedn(kdc->kdc_db_ctx->samdb),
52 "repsFrom",
53 &reps,
54 &count);
55 W_ERROR_NOT_OK_RETURN(werr);
57 if (count == 0) {
58 /* we don't have any DCs to replicate with. Very
59 strange for a RODC */
60 DBG_WARNING("No replication sources for RODC in KDC proxy\n");
61 talloc_free(reps);
62 return WERR_DS_DRA_NO_REPLICA;
65 (*proxy_list) = talloc_array(mem_ctx, char *, count+1);
66 W_ERROR_HAVE_NO_MEMORY_AND_FREE(*proxy_list, reps);
68 talloc_steal(*proxy_list, reps);
70 for (i=0; i<count; i++) {
71 const char *dns_name = NULL;
72 if (reps->version == 1) {
73 dns_name = reps->ctr.ctr1.other_info->dns_name;
74 } else if (reps->version == 2) {
75 dns_name = reps->ctr.ctr2.other_info->dns_name1;
77 (*proxy_list)[i] = talloc_strdup(*proxy_list, dns_name);
78 W_ERROR_HAVE_NO_MEMORY_AND_FREE((*proxy_list)[i], *proxy_list);
80 (*proxy_list)[i] = NULL;
82 talloc_free(reps);
84 return WERR_OK;
88 struct kdc_udp_proxy_state {
89 struct tevent_context *ev;
90 struct kdc_server *kdc;
91 uint16_t port;
92 DATA_BLOB in;
93 DATA_BLOB out;
94 char **proxy_list;
95 uint32_t next_proxy;
96 struct {
97 struct nbt_name name;
98 const char *ip;
99 struct tdgram_context *dgram;
100 } proxy;
104 static void kdc_udp_next_proxy(struct tevent_req *req);
106 struct tevent_req *kdc_udp_proxy_send(TALLOC_CTX *mem_ctx,
107 struct tevent_context *ev,
108 struct kdc_server *kdc,
109 uint16_t port,
110 DATA_BLOB in)
112 struct tevent_req *req;
113 struct kdc_udp_proxy_state *state;
114 WERROR werr;
116 req = tevent_req_create(mem_ctx, &state,
117 struct kdc_udp_proxy_state);
118 if (req == NULL) {
119 return NULL;
121 state->ev = ev;
122 state->kdc = kdc;
123 state->port = port;
124 state->in = in;
126 werr = kdc_proxy_get_writeable_dcs(kdc, state, &state->proxy_list);
127 if (!W_ERROR_IS_OK(werr)) {
128 NTSTATUS status = werror_to_ntstatus(werr);
129 tevent_req_nterror(req, status);
130 return tevent_req_post(req, ev);
133 kdc_udp_next_proxy(req);
134 if (!tevent_req_is_in_progress(req)) {
135 return tevent_req_post(req, ev);
138 return req;
141 static void kdc_udp_proxy_resolve_done(struct composite_context *csubreq);
144 try the next proxy in the list
146 static void kdc_udp_next_proxy(struct tevent_req *req)
148 struct kdc_udp_proxy_state *state =
149 tevent_req_data(req,
150 struct kdc_udp_proxy_state);
151 const char *proxy_dnsname = state->proxy_list[state->next_proxy];
152 struct composite_context *csubreq;
154 if (proxy_dnsname == NULL) {
155 tevent_req_nterror(req, NT_STATUS_NO_LOGON_SERVERS);
156 return;
159 state->next_proxy++;
161 /* make sure we close the socket of the last try */
162 TALLOC_FREE(state->proxy.dgram);
163 ZERO_STRUCT(state->proxy);
165 make_nbt_name(&state->proxy.name, proxy_dnsname, 0);
167 csubreq = resolve_name_ex_send(lpcfg_resolve_context(state->kdc->task->lp_ctx),
168 state,
169 RESOLVE_NAME_FLAG_FORCE_DNS,
171 &state->proxy.name,
172 state->ev);
173 if (tevent_req_nomem(csubreq, req)) {
174 return;
176 csubreq->async.fn = kdc_udp_proxy_resolve_done;
177 csubreq->async.private_data = req;
180 static void kdc_udp_proxy_sendto_done(struct tevent_req *subreq);
181 static void kdc_udp_proxy_recvfrom_done(struct tevent_req *subreq);
183 static void kdc_udp_proxy_resolve_done(struct composite_context *csubreq)
185 struct tevent_req *req =
186 talloc_get_type_abort(csubreq->async.private_data,
187 struct tevent_req);
188 struct kdc_udp_proxy_state *state =
189 tevent_req_data(req,
190 struct kdc_udp_proxy_state);
191 NTSTATUS status;
192 struct tevent_req *subreq;
193 struct tsocket_address *local_addr, *proxy_addr;
194 int ret;
195 bool ok;
197 status = resolve_name_recv(csubreq, state, &state->proxy.ip);
198 if (!NT_STATUS_IS_OK(status)) {
199 DBG_ERR("Unable to resolve proxy[%s] - %s\n",
200 state->proxy.name.name, nt_errstr(status));
201 kdc_udp_next_proxy(req);
202 return;
205 /* get an address for us to use locally */
206 ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0, &local_addr);
207 if (ret != 0) {
208 kdc_udp_next_proxy(req);
209 return;
212 ret = tsocket_address_inet_from_strings(state, "ip",
213 state->proxy.ip,
214 state->port,
215 &proxy_addr);
216 if (ret != 0) {
217 kdc_udp_next_proxy(req);
218 return;
221 /* create a socket for us to work on */
222 ret = tdgram_inet_udp_socket(local_addr, proxy_addr,
223 state, &state->proxy.dgram);
224 if (ret != 0) {
225 kdc_udp_next_proxy(req);
226 return;
229 subreq = tdgram_sendto_send(state,
230 state->ev,
231 state->proxy.dgram,
232 state->in.data,
233 state->in.length,
234 NULL);
235 if (tevent_req_nomem(subreq, req)) {
236 return;
238 tevent_req_set_callback(subreq, kdc_udp_proxy_sendto_done, req);
240 /* setup to receive the reply from the proxy */
241 subreq = tdgram_recvfrom_send(state, state->ev, state->proxy.dgram);
242 if (tevent_req_nomem(subreq, req)) {
243 return;
245 tevent_req_set_callback(subreq, kdc_udp_proxy_recvfrom_done, req);
247 ok = tevent_req_set_endtime(
248 subreq,
249 state->ev,
250 timeval_current_ofs(state->kdc->proxy_timeout, 0));
251 if (!ok) {
252 DBG_DEBUG("tevent_req_set_endtime failed\n");
253 return;
256 DEBUG(4,("kdc_udp_proxy: proxying request to %s[%s]\n",
257 state->proxy.name.name, state->proxy.ip));
261 called when the send of the call to the proxy is complete
262 this is used to get an errors from the sendto()
264 static void kdc_udp_proxy_sendto_done(struct tevent_req *subreq)
266 struct tevent_req *req =
267 tevent_req_callback_data(subreq,
268 struct tevent_req);
269 struct kdc_udp_proxy_state *state =
270 tevent_req_data(req,
271 struct kdc_udp_proxy_state);
272 ssize_t ret;
273 int sys_errno;
275 ret = tdgram_sendto_recv(subreq, &sys_errno);
276 TALLOC_FREE(subreq);
277 if (ret == -1) {
278 DEBUG(4,("kdc_udp_proxy: sendto for %s[%s] gave %d : %s\n",
279 state->proxy.name.name, state->proxy.ip,
280 sys_errno, strerror(sys_errno)));
281 kdc_udp_next_proxy(req);
286 called when the proxy replies
288 static void kdc_udp_proxy_recvfrom_done(struct tevent_req *subreq)
290 struct tevent_req *req =
291 tevent_req_callback_data(subreq,
292 struct tevent_req);
293 struct kdc_udp_proxy_state *state =
294 tevent_req_data(req,
295 struct kdc_udp_proxy_state);
296 int sys_errno;
297 uint8_t *buf;
298 ssize_t len;
300 len = tdgram_recvfrom_recv(subreq, &sys_errno,
301 state, &buf, NULL);
302 TALLOC_FREE(subreq);
303 if (len == -1) {
304 DEBUG(4,("kdc_udp_proxy: reply from %s[%s] gave %d : %s\n",
305 state->proxy.name.name, state->proxy.ip,
306 sys_errno, strerror(sys_errno)));
307 kdc_udp_next_proxy(req);
308 return;
312 * Check the reply came from the right IP?
313 * As we use connected udp sockets, that should not be needed...
316 state->out.length = len;
317 state->out.data = buf;
319 tevent_req_done(req);
322 NTSTATUS kdc_udp_proxy_recv(struct tevent_req *req,
323 TALLOC_CTX *mem_ctx,
324 DATA_BLOB *out)
326 struct kdc_udp_proxy_state *state =
327 tevent_req_data(req,
328 struct kdc_udp_proxy_state);
329 NTSTATUS status;
331 if (tevent_req_is_nterror(req, &status)) {
332 tevent_req_received(req);
333 return status;
336 out->data = talloc_move(mem_ctx, &state->out.data);
337 out->length = state->out.length;
339 tevent_req_received(req);
340 return NT_STATUS_OK;
343 struct kdc_tcp_proxy_state {
344 struct tevent_context *ev;
345 struct kdc_server *kdc;
346 uint16_t port;
347 DATA_BLOB in;
348 uint8_t in_hdr[4];
349 struct iovec in_iov[2];
350 DATA_BLOB out;
351 char **proxy_list;
352 uint32_t next_proxy;
353 struct {
354 struct nbt_name name;
355 const char *ip;
356 struct tstream_context *stream;
357 } proxy;
360 static void kdc_tcp_next_proxy(struct tevent_req *req);
362 struct tevent_req *kdc_tcp_proxy_send(TALLOC_CTX *mem_ctx,
363 struct tevent_context *ev,
364 struct kdc_server *kdc,
365 uint16_t port,
366 DATA_BLOB in)
368 struct tevent_req *req;
369 struct kdc_tcp_proxy_state *state;
370 WERROR werr;
372 req = tevent_req_create(mem_ctx, &state,
373 struct kdc_tcp_proxy_state);
374 if (req == NULL) {
375 return NULL;
377 state->ev = ev;
378 state->kdc = kdc;
379 state->port = port;
380 state->in = in;
382 werr = kdc_proxy_get_writeable_dcs(kdc, state, &state->proxy_list);
383 if (!W_ERROR_IS_OK(werr)) {
384 NTSTATUS status = werror_to_ntstatus(werr);
385 tevent_req_nterror(req, status);
386 return tevent_req_post(req, ev);
389 RSIVAL(state->in_hdr, 0, state->in.length);
390 state->in_iov[0].iov_base = (char *)state->in_hdr;
391 state->in_iov[0].iov_len = 4;
392 state->in_iov[1].iov_base = (char *)state->in.data;
393 state->in_iov[1].iov_len = state->in.length;
395 kdc_tcp_next_proxy(req);
396 if (!tevent_req_is_in_progress(req)) {
397 return tevent_req_post(req, ev);
400 return req;
403 static void kdc_tcp_proxy_resolve_done(struct composite_context *csubreq);
406 try the next proxy in the list
408 static void kdc_tcp_next_proxy(struct tevent_req *req)
410 struct kdc_tcp_proxy_state *state =
411 tevent_req_data(req,
412 struct kdc_tcp_proxy_state);
413 const char *proxy_dnsname = state->proxy_list[state->next_proxy];
414 struct composite_context *csubreq;
416 if (proxy_dnsname == NULL) {
417 tevent_req_nterror(req, NT_STATUS_NO_LOGON_SERVERS);
418 return;
421 state->next_proxy++;
423 /* make sure we close the socket of the last try */
424 TALLOC_FREE(state->proxy.stream);
425 ZERO_STRUCT(state->proxy);
427 make_nbt_name(&state->proxy.name, proxy_dnsname, 0);
429 csubreq = resolve_name_ex_send(lpcfg_resolve_context(state->kdc->task->lp_ctx),
430 state,
431 RESOLVE_NAME_FLAG_FORCE_DNS,
433 &state->proxy.name,
434 state->ev);
435 if (tevent_req_nomem(csubreq, req)) {
436 return;
438 csubreq->async.fn = kdc_tcp_proxy_resolve_done;
439 csubreq->async.private_data = req;
442 static void kdc_tcp_proxy_connect_done(struct tevent_req *subreq);
444 static void kdc_tcp_proxy_resolve_done(struct composite_context *csubreq)
446 struct tevent_req *req =
447 talloc_get_type_abort(csubreq->async.private_data,
448 struct tevent_req);
449 struct kdc_tcp_proxy_state *state =
450 tevent_req_data(req,
451 struct kdc_tcp_proxy_state);
452 NTSTATUS status;
453 struct tevent_req *subreq;
454 struct tsocket_address *local_addr, *proxy_addr;
455 int ret;
457 status = resolve_name_recv(csubreq, state, &state->proxy.ip);
458 if (!NT_STATUS_IS_OK(status)) {
459 DBG_ERR("Unable to resolve proxy[%s] - %s\n",
460 state->proxy.name.name, nt_errstr(status));
461 kdc_tcp_next_proxy(req);
462 return;
465 /* get an address for us to use locally */
466 ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0, &local_addr);
467 if (ret != 0) {
468 kdc_tcp_next_proxy(req);
469 return;
472 ret = tsocket_address_inet_from_strings(state, "ip",
473 state->proxy.ip,
474 state->port,
475 &proxy_addr);
476 if (ret != 0) {
477 kdc_tcp_next_proxy(req);
478 return;
481 subreq = tstream_inet_tcp_connect_send(state, state->ev,
482 local_addr, proxy_addr);
483 if (tevent_req_nomem(subreq, req)) {
484 return;
486 tevent_req_set_callback(subreq, kdc_tcp_proxy_connect_done, req);
487 tevent_req_set_endtime(subreq, state->ev,
488 timeval_current_ofs(state->kdc->proxy_timeout, 0));
491 static void kdc_tcp_proxy_writev_done(struct tevent_req *subreq);
492 static void kdc_tcp_proxy_read_pdu_done(struct tevent_req *subreq);
494 static void kdc_tcp_proxy_connect_done(struct tevent_req *subreq)
496 struct tevent_req *req =
497 tevent_req_callback_data(subreq,
498 struct tevent_req);
499 struct kdc_tcp_proxy_state *state =
500 tevent_req_data(req,
501 struct kdc_tcp_proxy_state);
502 int ret, sys_errno;
504 ret = tstream_inet_tcp_connect_recv(subreq, &sys_errno,
505 state, &state->proxy.stream, NULL);
506 TALLOC_FREE(subreq);
507 if (ret != 0) {
508 kdc_tcp_next_proxy(req);
509 return;
512 subreq = tstream_writev_send(state,
513 state->ev,
514 state->proxy.stream,
515 state->in_iov, 2);
516 if (tevent_req_nomem(subreq, req)) {
517 return;
519 tevent_req_set_callback(subreq, kdc_tcp_proxy_writev_done, req);
521 subreq = tstream_read_pdu_blob_send(state,
522 state->ev,
523 state->proxy.stream,
524 4, /* initial_read_size */
525 tstream_full_request_u32,
526 req);
527 if (tevent_req_nomem(subreq, req)) {
528 return;
530 tevent_req_set_callback(subreq, kdc_tcp_proxy_read_pdu_done, req);
531 tevent_req_set_endtime(subreq, state->kdc->task->event_ctx,
532 timeval_current_ofs(state->kdc->proxy_timeout, 0));
534 DEBUG(4,("kdc_tcp_proxy: proxying request to %s[%s]\n",
535 state->proxy.name.name, state->proxy.ip));
538 static void kdc_tcp_proxy_writev_done(struct tevent_req *subreq)
540 struct tevent_req *req =
541 tevent_req_callback_data(subreq,
542 struct tevent_req);
543 int ret, sys_errno;
545 ret = tstream_writev_recv(subreq, &sys_errno);
546 TALLOC_FREE(subreq);
547 if (ret == -1) {
548 kdc_tcp_next_proxy(req);
552 static void kdc_tcp_proxy_read_pdu_done(struct tevent_req *subreq)
554 struct tevent_req *req =
555 tevent_req_callback_data(subreq,
556 struct tevent_req);
557 struct kdc_tcp_proxy_state *state =
558 tevent_req_data(req,
559 struct kdc_tcp_proxy_state);
560 NTSTATUS status;
561 DATA_BLOB raw;
563 status = tstream_read_pdu_blob_recv(subreq, state, &raw);
564 TALLOC_FREE(subreq);
565 if (!NT_STATUS_IS_OK(status)) {
566 kdc_tcp_next_proxy(req);
567 return;
571 * raw blob has the length in the first 4 bytes,
572 * which we do not need here.
574 state->out = data_blob_talloc(state, raw.data + 4, raw.length - 4);
575 if (state->out.length != raw.length - 4) {
576 tevent_req_oom(req);
577 return;
580 tevent_req_done(req);
583 NTSTATUS kdc_tcp_proxy_recv(struct tevent_req *req,
584 TALLOC_CTX *mem_ctx,
585 DATA_BLOB *out)
587 struct kdc_tcp_proxy_state *state =
588 tevent_req_data(req,
589 struct kdc_tcp_proxy_state);
590 NTSTATUS status;
592 if (tevent_req_is_nterror(req, &status)) {
593 tevent_req_received(req);
594 return status;
597 out->data = talloc_move(mem_ctx, &state->out.data);
598 out->length = state->out.length;
600 tevent_req_received(req);
601 return NT_STATUS_OK;