s4:kdc: provide a PAC_UPN_DNS_INFO element for logons
[sfrench/samba-autobuild/.git] / source4 / kdc / 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    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  */
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
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  */
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
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
188         status = resolve_name_recv(csubreq, state, &state->proxy.ip);
189         if (!NT_STATUS_IS_OK(status)) {
190                 DEBUG(0,("Unable to resolve proxy[%s] - %s\n",
191                         state->proxy.name.name, nt_errstr(status)));
192                 kdc_udp_next_proxy(req);
193                 return;
194         }
195
196         /* get an address for us to use locally */
197         ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0, &local_addr);
198         if (ret != 0) {
199                 kdc_udp_next_proxy(req);
200                 return;
201         }
202
203         ret = tsocket_address_inet_from_strings(state, "ip",
204                                                 state->proxy.ip,
205                                                 state->port,
206                                                 &proxy_addr);
207         if (ret != 0) {
208                 kdc_udp_next_proxy(req);
209                 return;
210         }
211
212         /* create a socket for us to work on */
213         ret = tdgram_inet_udp_socket(local_addr, proxy_addr,
214                                      state, &state->proxy.dgram);
215         if (ret != 0) {
216                 kdc_udp_next_proxy(req);
217                 return;
218         }
219
220         subreq = tdgram_sendto_send(state,
221                                     state->ev,
222                                     state->proxy.dgram,
223                                     state->in.data,
224                                     state->in.length,
225                                     NULL);
226         if (tevent_req_nomem(subreq, req)) {
227                 return;
228         }
229         tevent_req_set_callback(subreq, kdc_udp_proxy_sendto_done, req);
230
231         /* setup to receive the reply from the proxy */
232         subreq = tdgram_recvfrom_send(state, state->ev, state->proxy.dgram);
233         if (tevent_req_nomem(subreq, req)) {
234                 return;
235         }
236         tevent_req_set_callback(subreq, kdc_udp_proxy_recvfrom_done, req);
237         tevent_req_set_endtime(subreq, state->ev,
238                                timeval_current_ofs(state->kdc->proxy_timeout, 0));
239
240         DEBUG(4,("kdc_udp_proxy: proxying request to %s[%s]\n",
241                  state->proxy.name.name, state->proxy.ip));
242 }
243
244 /*
245   called when the send of the call to the proxy is complete
246   this is used to get an errors from the sendto()
247  */
248 static void kdc_udp_proxy_sendto_done(struct tevent_req *subreq)
249 {
250         struct tevent_req *req =
251                 tevent_req_callback_data(subreq,
252                 struct tevent_req);
253         struct kdc_udp_proxy_state *state =
254                 tevent_req_data(req,
255                 struct kdc_udp_proxy_state);
256         ssize_t ret;
257         int sys_errno;
258
259         ret = tdgram_sendto_recv(subreq, &sys_errno);
260         TALLOC_FREE(subreq);
261         if (ret == -1) {
262                 DEBUG(4,("kdc_udp_proxy: sendto for %s[%s] gave %d : %s\n",
263                          state->proxy.name.name, state->proxy.ip,
264                          sys_errno, strerror(sys_errno)));
265                 kdc_udp_next_proxy(req);
266         }
267 }
268
269 /*
270   called when the proxy replies
271  */
272 static void kdc_udp_proxy_recvfrom_done(struct tevent_req *subreq)
273 {
274         struct tevent_req *req =
275                 tevent_req_callback_data(subreq,
276                 struct tevent_req);
277         struct kdc_udp_proxy_state *state =
278                 tevent_req_data(req,
279                 struct kdc_udp_proxy_state);
280         int sys_errno;
281         uint8_t *buf;
282         ssize_t len;
283
284         len = tdgram_recvfrom_recv(subreq, &sys_errno,
285                                    state, &buf, NULL);
286         TALLOC_FREE(subreq);
287         if (len == -1) {
288                 DEBUG(4,("kdc_udp_proxy: reply from %s[%s] gave %d : %s\n",
289                          state->proxy.name.name, state->proxy.ip,
290                          sys_errno, strerror(sys_errno)));
291                 kdc_udp_next_proxy(req);
292                 return;
293         }
294
295         /*
296          * Check the reply came from the right IP?
297          * As we use connected udp sockets, that should not be needed...
298          */
299
300         state->out.length = len;
301         state->out.data = buf;
302
303         tevent_req_done(req);
304 }
305
306 NTSTATUS kdc_udp_proxy_recv(struct tevent_req *req,
307                             TALLOC_CTX *mem_ctx,
308                             DATA_BLOB *out)
309 {
310         struct kdc_udp_proxy_state *state =
311                 tevent_req_data(req,
312                 struct kdc_udp_proxy_state);
313         NTSTATUS status;
314
315         if (tevent_req_is_nterror(req, &status)) {
316                 tevent_req_received(req);
317                 return status;
318         }
319
320         out->data = talloc_move(mem_ctx, &state->out.data);
321         out->length = state->out.length;
322
323         tevent_req_received(req);
324         return NT_STATUS_OK;
325 }
326
327 struct kdc_tcp_proxy_state {
328         struct tevent_context *ev;
329         struct kdc_server *kdc;
330         uint16_t port;
331         DATA_BLOB in;
332         uint8_t in_hdr[4];
333         struct iovec in_iov[2];
334         DATA_BLOB out;
335         char **proxy_list;
336         uint32_t next_proxy;
337         struct {
338                 struct nbt_name name;
339                 const char *ip;
340                 struct tstream_context *stream;
341         } proxy;
342 };
343
344 static void kdc_tcp_next_proxy(struct tevent_req *req);
345
346 struct tevent_req *kdc_tcp_proxy_send(TALLOC_CTX *mem_ctx,
347                                       struct tevent_context *ev,
348                                       struct kdc_server *kdc,
349                                       uint16_t port,
350                                       DATA_BLOB in)
351 {
352         struct tevent_req *req;
353         struct kdc_tcp_proxy_state *state;
354         WERROR werr;
355
356         req = tevent_req_create(mem_ctx, &state,
357                                 struct kdc_tcp_proxy_state);
358         if (req == NULL) {
359                 return NULL;
360         }
361         state->ev = ev;
362         state->kdc  = kdc;
363         state->port = port;
364         state->in = in;
365
366         werr = kdc_proxy_get_writeable_dcs(kdc, state, &state->proxy_list);
367         if (!W_ERROR_IS_OK(werr)) {
368                 NTSTATUS status = werror_to_ntstatus(werr);
369                 tevent_req_nterror(req, status);
370                 return tevent_req_post(req, ev);
371         }
372
373         RSIVAL(state->in_hdr, 0, state->in.length);
374         state->in_iov[0].iov_base = (char *)state->in_hdr;
375         state->in_iov[0].iov_len = 4;
376         state->in_iov[1].iov_base = (char *)state->in.data;
377         state->in_iov[1].iov_len = state->in.length;
378
379         kdc_tcp_next_proxy(req);
380         if (!tevent_req_is_in_progress(req)) {
381                 return tevent_req_post(req, ev);
382         }
383
384         return req;
385 }
386
387 static void kdc_tcp_proxy_resolve_done(struct composite_context *csubreq);
388
389 /*
390   try the next proxy in the list
391  */
392 static void kdc_tcp_next_proxy(struct tevent_req *req)
393 {
394         struct kdc_tcp_proxy_state *state =
395                 tevent_req_data(req,
396                 struct kdc_tcp_proxy_state);
397         const char *proxy_dnsname = state->proxy_list[state->next_proxy];
398         struct composite_context *csubreq;
399
400         if (proxy_dnsname == NULL) {
401                 tevent_req_nterror(req, NT_STATUS_NO_LOGON_SERVERS);
402                 return;
403         }
404
405         state->next_proxy++;
406
407         /* make sure we close the socket of the last try */
408         TALLOC_FREE(state->proxy.stream);
409         ZERO_STRUCT(state->proxy);
410
411         make_nbt_name(&state->proxy.name, proxy_dnsname, 0);
412
413         csubreq = resolve_name_ex_send(lpcfg_resolve_context(state->kdc->task->lp_ctx),
414                                        state,
415                                        RESOLVE_NAME_FLAG_FORCE_DNS,
416                                        0,
417                                        &state->proxy.name,
418                                        state->ev);
419         if (tevent_req_nomem(csubreq, req)) {
420                 return;
421         }
422         csubreq->async.fn = kdc_tcp_proxy_resolve_done;
423         csubreq->async.private_data = req;
424 }
425
426 static void kdc_tcp_proxy_connect_done(struct tevent_req *subreq);
427
428 static void kdc_tcp_proxy_resolve_done(struct composite_context *csubreq)
429 {
430         struct tevent_req *req =
431                 talloc_get_type_abort(csubreq->async.private_data,
432                 struct tevent_req);
433         struct kdc_tcp_proxy_state *state =
434                 tevent_req_data(req,
435                 struct kdc_tcp_proxy_state);
436         NTSTATUS status;
437         struct tevent_req *subreq;
438         struct tsocket_address *local_addr, *proxy_addr;
439         int ret;
440
441         status = resolve_name_recv(csubreq, state, &state->proxy.ip);
442         if (!NT_STATUS_IS_OK(status)) {
443                 DEBUG(0,("Unable to resolve proxy[%s] - %s\n",
444                         state->proxy.name.name, nt_errstr(status)));
445                 kdc_tcp_next_proxy(req);
446                 return;
447         }
448
449         /* get an address for us to use locally */
450         ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0, &local_addr);
451         if (ret != 0) {
452                 kdc_tcp_next_proxy(req);
453                 return;
454         }
455
456         ret = tsocket_address_inet_from_strings(state, "ip",
457                                                 state->proxy.ip,
458                                                 state->port,
459                                                 &proxy_addr);
460         if (ret != 0) {
461                 kdc_tcp_next_proxy(req);
462                 return;
463         }
464
465         subreq = tstream_inet_tcp_connect_send(state, state->ev,
466                                                local_addr, proxy_addr);
467         if (tevent_req_nomem(subreq, req)) {
468                 return;
469         }
470         tevent_req_set_callback(subreq, kdc_tcp_proxy_connect_done, req);
471         tevent_req_set_endtime(subreq, state->ev,
472                                timeval_current_ofs(state->kdc->proxy_timeout, 0));
473 }
474
475 static void kdc_tcp_proxy_writev_done(struct tevent_req *subreq);
476 static void kdc_tcp_proxy_read_pdu_done(struct tevent_req *subreq);
477
478 static void kdc_tcp_proxy_connect_done(struct tevent_req *subreq)
479 {
480         struct tevent_req *req =
481                 tevent_req_callback_data(subreq,
482                 struct tevent_req);
483         struct kdc_tcp_proxy_state *state =
484                 tevent_req_data(req,
485                 struct kdc_tcp_proxy_state);
486         int ret, sys_errno;
487
488         ret = tstream_inet_tcp_connect_recv(subreq, &sys_errno,
489                                             state, &state->proxy.stream, NULL);
490         TALLOC_FREE(subreq);
491         if (ret != 0) {
492                 kdc_tcp_next_proxy(req);
493                 return;
494         }
495
496         subreq = tstream_writev_send(state,
497                                      state->ev,
498                                      state->proxy.stream,
499                                      state->in_iov, 2);
500         if (tevent_req_nomem(subreq, req)) {
501                 return;
502         }
503         tevent_req_set_callback(subreq, kdc_tcp_proxy_writev_done, req);
504
505         subreq = tstream_read_pdu_blob_send(state,
506                                             state->ev,
507                                             state->proxy.stream,
508                                             4, /* initial_read_size */
509                                             packet_full_request_u32,
510                                             req);
511         if (tevent_req_nomem(subreq, req)) {
512                 return;
513         }
514         tevent_req_set_callback(subreq, kdc_tcp_proxy_read_pdu_done, req);
515         tevent_req_set_endtime(subreq, state->kdc->task->event_ctx,
516                                timeval_current_ofs(state->kdc->proxy_timeout, 0));
517
518         DEBUG(4,("kdc_tcp_proxy: proxying request to %s[%s]\n",
519                  state->proxy.name.name, state->proxy.ip));
520 }
521
522 static void kdc_tcp_proxy_writev_done(struct tevent_req *subreq)
523 {
524         struct tevent_req *req =
525                 tevent_req_callback_data(subreq,
526                 struct tevent_req);
527         int ret, sys_errno;
528
529         ret = tstream_writev_recv(subreq, &sys_errno);
530         TALLOC_FREE(subreq);
531         if (ret == -1) {
532                 kdc_tcp_next_proxy(req);
533         }
534 }
535
536 static void kdc_tcp_proxy_read_pdu_done(struct tevent_req *subreq)
537 {
538         struct tevent_req *req =
539                 tevent_req_callback_data(subreq,
540                 struct tevent_req);
541         struct kdc_tcp_proxy_state *state =
542                 tevent_req_data(req,
543                 struct kdc_tcp_proxy_state);
544         NTSTATUS status;
545         DATA_BLOB raw;
546
547         status = tstream_read_pdu_blob_recv(subreq, state, &raw);
548         TALLOC_FREE(subreq);
549         if (!NT_STATUS_IS_OK(status)) {
550                 kdc_tcp_next_proxy(req);
551                 return;
552         }
553
554         /*
555          * raw blob has the length in the first 4 bytes,
556          * which we do not need here.
557          */
558         state->out = data_blob_talloc(state, raw.data + 4, raw.length - 4);
559         if (state->out.length != raw.length - 4) {
560                 tevent_req_oom(req);
561                 return;
562         }
563
564         tevent_req_done(req);
565 }
566
567 NTSTATUS kdc_tcp_proxy_recv(struct tevent_req *req,
568                             TALLOC_CTX *mem_ctx,
569                             DATA_BLOB *out)
570 {
571         struct kdc_tcp_proxy_state *state =
572                 tevent_req_data(req,
573                 struct kdc_tcp_proxy_state);
574         NTSTATUS status;
575
576         if (tevent_req_is_nterror(req, &status)) {
577                 tevent_req_received(req);
578                 return status;
579         }
580
581         out->data = talloc_move(mem_ctx, &state->out.data);
582         out->length = state->out.length;
583
584         tevent_req_received(req);
585         return NT_STATUS_OK;
586 }