s4:kdc/proxy.c - optimise includes in order to fix a build warning on Tru64
[kai/samba.git] / source4 / kdc / proxy.c
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
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.
13
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.
18
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/>.
21 */
22
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"
32
33
34 /*
35   get a list of our replication partners from repsFrom, returning it in *proxy_list
36  */
37 static WERROR kdc_proxy_get_writeable_dcs(struct kdc_server *kdc, TALLOC_CTX *mem_ctx, char ***proxy_list)
38 {
39         WERROR werr;
40         uint32_t count, i;
41         struct repsFromToBlob *reps;
42
43         werr = dsdb_loadreps(kdc->samdb, mem_ctx, ldb_get_default_basedn(kdc->samdb), "repsFrom", &reps, &count);
44         W_ERROR_NOT_OK_RETURN(werr);
45
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;
52         }
53
54         (*proxy_list) = talloc_array(mem_ctx, char *, count+1);
55         W_ERROR_HAVE_NO_MEMORY_AND_FREE(*proxy_list, reps);
56
57         talloc_steal(*proxy_list, reps);
58
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;
65                 }
66                 (*proxy_list)[i] = talloc_strdup(*proxy_list, dns_name);
67                 W_ERROR_HAVE_NO_MEMORY_AND_FREE((*proxy_list)[i], *proxy_list);
68         }
69         (*proxy_list)[i] = NULL;
70
71         talloc_free(reps);
72
73         return WERR_OK;
74 }
75
76
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;
85 };
86
87
88 static void kdc_udp_next_proxy(struct kdc_udp_proxy_state *state);
89
90 /*
91   called when the send of the call to the proxy is complete
92   this is used to get an errors from the sendto()
93  */
94 static void kdc_udp_proxy_sendto_done(struct tevent_req *req)
95 {
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;
100
101         ret = tdgram_sendto_queue_recv(req, &sys_errno);
102         talloc_free(req);
103
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);
108         }
109 }
110
111 /*
112   called when the send of the reply to the client is complete
113   this is used to get an errors from the sendto()
114  */
115 static void kdc_udp_proxy_reply_done(struct tevent_req *req)
116 {
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;
121
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)));
126         }
127
128         /* all done - we can destroy the proxy state */
129         talloc_free(req);
130         talloc_free(state);
131 }
132
133
134 /*
135   called when the proxy replies
136  */
137 static void kdc_udp_proxy_reply(struct tevent_req *req)
138 {
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;
145
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;
154         }
155
156         state->call->out.length = len;
157         state->call->out.data = buf;
158
159         /* TODO: check the reply came from the right IP? */
160
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;
171         }
172
173         tevent_req_set_callback(req, kdc_udp_proxy_reply_done, state);
174 }
175
176
177 /*
178   called when we've resolved the name of a proxy
179  */
180 static void kdc_udp_proxy_resolve_done(struct composite_context *c)
181 {
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;
189
190         state = talloc_get_type(c->async.private_data, struct kdc_udp_proxy_state);
191
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;
197         }
198
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;
204         }
205
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;
211         }
212
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;
218         }
219
220         send_queue = tevent_queue_create(state, "kdc_udp_proxy");
221         if (send_queue == NULL) {
222                 kdc_udp_next_proxy(state);
223                 return;
224         }
225
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;
236         }
237
238         tevent_req_set_callback(req, kdc_udp_proxy_sendto_done, state);
239
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;
245         }
246
247         tevent_req_set_callback(req, kdc_udp_proxy_reply, state);
248
249         tevent_req_set_endtime(req, state->kdc->task->event_ctx,
250                                timeval_current_ofs(state->kdc->proxy_timeout, 0));
251
252         DEBUG(4,("kdc_udp_proxy: proxying request to %s\n", state->proxy_ip));
253 }
254
255
256 /*
257   called when our proxies are not available
258  */
259 static void kdc_udp_proxy_unavailable(struct kdc_udp_proxy_state *state)
260 {
261         int kret;
262         krb5_data k5_error_blob;
263         struct tevent_req *req;
264
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;
272         }
273
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;
279         }
280
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;
291         }
292
293         tevent_req_set_callback(req, kdc_udp_proxy_reply_done, state);
294 }
295
296 /*
297   try the next proxy in the list
298  */
299 static void kdc_udp_next_proxy(struct kdc_udp_proxy_state *state)
300 {
301         const char *proxy_dnsname = state->proxy_list[state->next_proxy];
302         struct nbt_name name;
303         struct composite_context *c;
304
305         if (proxy_dnsname == NULL) {
306                 kdc_udp_proxy_unavailable(state);
307                 return;
308         }
309
310         state->next_proxy++;
311
312         make_nbt_name(&name, proxy_dnsname, 0);
313
314         c = resolve_name_ex_send(lpcfg_resolve_context(state->kdc->task->lp_ctx),
315                                  state,
316                                  RESOLVE_NAME_FLAG_FORCE_DNS,
317                                  0,
318                                  &name,
319                                  state->kdc->task->event_ctx);
320         if (c == NULL) {
321                 kdc_udp_next_proxy(state);
322                 return;
323         }
324         c->async.fn = kdc_udp_proxy_resolve_done;
325         c->async.private_data = state;
326 }
327
328
329 /*
330   proxy a UDP kdc request to a writeable DC
331  */
332 void kdc_udp_proxy(struct kdc_server *kdc, struct kdc_udp_socket *sock,
333                    struct kdc_udp_call *call, uint16_t port)
334 {
335         struct kdc_udp_proxy_state *state;
336         WERROR werr;
337
338         state = talloc_zero(kdc, struct kdc_udp_proxy_state);
339         if (state == NULL) {
340                 talloc_free(call);
341                 return;
342         }
343
344         state->call = talloc_steal(state, call);
345         state->sock = sock;
346         state->kdc  = kdc;
347         state->port = port;
348
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;
353         }
354
355         kdc_udp_next_proxy(state);
356 }
357
358
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;
367 };
368
369 static void kdc_tcp_next_proxy(struct kdc_tcp_proxy_state *state);
370
371 /*
372   called when the send of the proxied reply to the client is done
373  */
374 static void kdc_tcp_proxy_reply_done(struct tevent_req *req)
375 {
376         struct kdc_tcp_proxy_state *state = tevent_req_callback_data(req,
377                                                                      struct kdc_tcp_proxy_state);
378         int ret, sys_errno;
379
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)));
384         }
385         talloc_free(req);
386         talloc_free(state);
387 }
388
389 /*
390   called when the recv of the proxied reply is done
391  */
392 static void kdc_tcp_proxy_recv_done(struct tevent_req *req)
393 {
394         struct kdc_tcp_proxy_state *state = tevent_req_callback_data(req,
395                                                                      struct kdc_tcp_proxy_state);
396         NTSTATUS status;
397
398         status = tstream_read_pdu_blob_recv(req,
399                                             state,
400                                             &state->call->out);
401         talloc_free(req);
402
403         if (!NT_STATUS_IS_OK(status)) {
404                 kdc_tcp_next_proxy(state);
405                 return;
406         }
407
408
409         /* send the reply to the original caller */
410
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;
413
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;
422         }
423
424         tevent_req_set_callback(req, kdc_tcp_proxy_reply_done, state);
425 }
426
427 /*
428   called when the send of the proxied packet is done
429  */
430 static void kdc_tcp_proxy_send_done(struct tevent_req *req)
431 {
432         struct kdc_tcp_proxy_state *state = tevent_req_callback_data(req,
433                                                                      struct kdc_tcp_proxy_state);
434         int ret, sys_errno;
435
436         ret = tstream_writev_queue_recv(req, &sys_errno);
437         talloc_free(req);
438         if (ret == -1) {
439                 kdc_tcp_next_proxy(state);
440         }
441 }
442
443 /*
444   called when we've connected to the proxy
445  */
446 static void kdc_tcp_proxy_connect_done(struct tevent_req *req)
447 {
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;
453
454
455         ret = tstream_inet_tcp_connect_recv(req, &sys_errno, state, &stream, NULL);
456         talloc_free(req);
457
458         if (ret != 0) {
459                 kdc_tcp_next_proxy(state);
460                 return;
461         }
462
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;
468
469         send_queue = tevent_queue_create(state, "kdc_tcp_proxy");
470         if (send_queue == NULL) {
471                 kdc_tcp_next_proxy(state);
472                 return;
473         }
474
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;
483         }
484
485         tevent_req_set_callback(req, kdc_tcp_proxy_send_done, state);
486
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;
496         }
497
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));
501
502 }
503
504
505 /*
506   called when name resolution for a proxy is done
507  */
508 static void kdc_tcp_proxy_resolve_done(struct composite_context *c)
509 {
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;
515
516         state = talloc_get_type(c->async.private_data, struct kdc_tcp_proxy_state);
517
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;
522         }
523
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;
529         }
530
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;
536         }
537
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;
543         }
544
545         tevent_req_set_callback(req, kdc_tcp_proxy_connect_done, state);
546
547         tevent_req_set_endtime(req, state->kdc->task->event_ctx,
548                                timeval_current_ofs(state->kdc->proxy_timeout, 0));
549
550         DEBUG(4,("kdc_tcp_proxy: proxying request to %s\n", state->proxy_ip));
551 }
552
553
554 /*
555   called when our proxies are not available
556  */
557 static void kdc_tcp_proxy_unavailable(struct kdc_tcp_proxy_state *state)
558 {
559         int kret;
560         krb5_data k5_error_blob;
561         struct tevent_req *req;
562
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;
570         }
571
572
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;
578         }
579
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;
582
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;
591         }
592
593         tevent_req_set_callback(req, kdc_tcp_proxy_reply_done, state);
594 }
595
596 /*
597   try the next proxy in the list
598  */
599 static void kdc_tcp_next_proxy(struct kdc_tcp_proxy_state *state)
600 {
601         const char *proxy_dnsname = state->proxy_list[state->next_proxy];
602         struct nbt_name name;
603         struct composite_context *c;
604
605         if (proxy_dnsname == NULL) {
606                 kdc_tcp_proxy_unavailable(state);
607                 return;
608         }
609
610         state->next_proxy++;
611
612         make_nbt_name(&name, proxy_dnsname, 0);
613
614         c = resolve_name_ex_send(lpcfg_resolve_context(state->kdc->task->lp_ctx),
615                                  state,
616                                  RESOLVE_NAME_FLAG_FORCE_DNS,
617                                  0,
618                                  &name,
619                                  state->kdc->task->event_ctx);
620         if (c == NULL) {
621                 kdc_tcp_next_proxy(state);
622                 return;
623         }
624         c->async.fn = kdc_tcp_proxy_resolve_done;
625         c->async.private_data = state;
626 }
627
628
629 /*
630   proxy a TCP kdc request to a writeable DC
631  */
632 void kdc_tcp_proxy(struct kdc_server *kdc, struct kdc_tcp_connection *kdc_conn,
633                    struct kdc_tcp_call *call, uint16_t port)
634 {
635         struct kdc_tcp_proxy_state *state;
636         WERROR werr;
637
638         state = talloc_zero(kdc_conn, struct kdc_tcp_proxy_state);
639
640         state->call = talloc_steal(state, call);
641         state->kdc_conn = kdc_conn;
642         state->kdc  = kdc;
643         state->port = port;
644
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;
649         }
650
651         kdc_tcp_next_proxy(state);
652 }