2 Unix SMB/CIFS implementation.
6 Copyright (c) 2005-2008 Andrew Bartlett <abartlet@samba.org>
7 Copyright (c) 2005 Andrew Tridgell <tridge@samba.org>
8 Copyright (c) 2005 Stefan Metzmacher <metze@samba.org>
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/>.
25 #include "param/param.h"
26 #include "smbd/process_model.h"
27 #include "lib/tsocket/tsocket.h"
28 #include "libcli/util/tstream.h"
29 #include "kdc/kdc-server.h"
30 #include "kdc/kdc-proxy.h"
31 #include "lib/stream/packet.h"
34 * State of an open tcp connection
36 struct kdc_tcp_connection
{
37 /* stream connection we belong to */
38 struct stream_connection
*conn
;
40 /* the kdc_server the connection belongs to */
41 struct kdc_socket
*kdc_socket
;
43 struct tstream_context
*tstream
;
45 struct tevent_queue
*send_queue
;
49 struct kdc_tcp_connection
*kdc_conn
;
53 struct iovec out_iov
[2];
57 struct kdc_udp_socket
*sock
;
58 struct tsocket_address
*src
;
63 static void kdc_udp_call_proxy_done(struct tevent_req
*subreq
);
64 static void kdc_udp_call_sendto_done(struct tevent_req
*subreq
);
66 static void kdc_tcp_call_writev_done(struct tevent_req
*subreq
);
67 static void kdc_tcp_call_proxy_done(struct tevent_req
*subreq
);
69 static void kdc_tcp_terminate_connection(struct kdc_tcp_connection
*kdc_conn
,
72 stream_terminate_connection(kdc_conn
->conn
, reason
);
75 static NTSTATUS
kdc_proxy_unavailable_error(struct kdc_server
*kdc
,
82 code
= smb_krb5_mk_error(kdc
->smb_krb5_context
->krb5_context
,
83 KRB5KDC_ERR_SVC_UNAVAILABLE
,
90 DBG_WARNING("Unable to form krb5 error reply\n");
91 return NT_STATUS_INTERNAL_ERROR
;
94 *out
= data_blob_talloc(mem_ctx
, enc_error
.data
, enc_error
.length
);
95 smb_krb5_free_data_contents(kdc
->smb_krb5_context
->krb5_context
,
98 return NT_STATUS_NO_MEMORY
;
104 static void kdc_udp_call_loop(struct tevent_req
*subreq
)
106 struct kdc_udp_socket
*sock
= tevent_req_callback_data(subreq
,
107 struct kdc_udp_socket
);
108 struct kdc_udp_call
*call
;
114 call
= talloc(sock
, struct kdc_udp_call
);
121 len
= tdgram_recvfrom_recv(subreq
, &sys_errno
,
122 call
, &buf
, &call
->src
);
130 call
->in
.length
= len
;
132 DEBUG(10,("Received krb5 UDP packet of length %lu from %s\n",
133 (long)call
->in
.length
,
134 tsocket_address_string(call
->src
, call
)));
137 ret
= sock
->kdc_socket
->process(sock
->kdc_socket
->kdc
,
142 sock
->kdc_socket
->local_address
,
144 if (ret
== KDC_ERROR
) {
149 if (ret
== KDC_PROXY_REQUEST
) {
152 if (!sock
->kdc_socket
->kdc
->am_rodc
) {
153 DEBUG(0,("kdc_udp_call_loop: proxying requested when not RODC"));
158 port
= tsocket_address_inet_port(sock
->kdc_socket
->local_address
);
160 subreq
= kdc_udp_proxy_send(call
,
161 sock
->kdc_socket
->kdc
->task
->event_ctx
,
162 sock
->kdc_socket
->kdc
,
165 if (subreq
== NULL
) {
169 tevent_req_set_callback(subreq
, kdc_udp_call_proxy_done
, call
);
173 subreq
= tdgram_sendto_queue_send(call
,
174 sock
->kdc_socket
->kdc
->task
->event_ctx
,
180 if (subreq
== NULL
) {
184 tevent_req_set_callback(subreq
, kdc_udp_call_sendto_done
, call
);
187 subreq
= tdgram_recvfrom_send(sock
,
188 sock
->kdc_socket
->kdc
->task
->event_ctx
,
190 if (subreq
== NULL
) {
191 task_server_terminate(sock
->kdc_socket
->kdc
->task
,
192 "no memory for tdgram_recvfrom_send",
196 tevent_req_set_callback(subreq
, kdc_udp_call_loop
, sock
);
199 static void kdc_udp_call_proxy_done(struct tevent_req
*subreq
)
201 struct kdc_udp_call
*call
=
202 tevent_req_callback_data(subreq
,
203 struct kdc_udp_call
);
206 status
= kdc_udp_proxy_recv(subreq
, call
, &call
->out
);
208 if (!NT_STATUS_IS_OK(status
)) {
209 /* generate an error packet */
210 status
= kdc_proxy_unavailable_error(call
->sock
->kdc_socket
->kdc
,
214 if (!NT_STATUS_IS_OK(status
)) {
219 subreq
= tdgram_sendto_queue_send(call
,
220 call
->sock
->kdc_socket
->kdc
->task
->event_ctx
,
222 call
->sock
->send_queue
,
226 if (subreq
== NULL
) {
231 tevent_req_set_callback(subreq
, kdc_udp_call_sendto_done
, call
);
234 static void kdc_udp_call_sendto_done(struct tevent_req
*subreq
)
236 struct kdc_udp_call
*call
= tevent_req_callback_data(subreq
,
237 struct kdc_udp_call
);
240 tdgram_sendto_queue_recv(subreq
, &sys_errno
);
242 /* We don't care about errors */
247 static void kdc_tcp_call_loop(struct tevent_req
*subreq
)
249 struct kdc_tcp_connection
*kdc_conn
= tevent_req_callback_data(subreq
,
250 struct kdc_tcp_connection
);
251 struct kdc_tcp_call
*call
;
255 call
= talloc(kdc_conn
, struct kdc_tcp_call
);
257 kdc_tcp_terminate_connection(kdc_conn
, "kdc_tcp_call_loop: "
258 "no memory for kdc_tcp_call");
261 call
->kdc_conn
= kdc_conn
;
263 status
= tstream_read_pdu_blob_recv(subreq
,
267 if (!NT_STATUS_IS_OK(status
)) {
270 reason
= talloc_asprintf(call
, "kdc_tcp_call_loop: "
271 "tstream_read_pdu_blob_recv() - %s",
274 reason
= nt_errstr(status
);
277 kdc_tcp_terminate_connection(kdc_conn
, reason
);
281 DEBUG(10,("Received krb5 TCP packet of length %lu from %s\n",
282 (long) call
->in
.length
,
283 tsocket_address_string(kdc_conn
->conn
->remote_address
, call
)));
285 /* skip length header */
287 call
->in
.length
-= 4;
290 ret
= kdc_conn
->kdc_socket
->process(kdc_conn
->kdc_socket
->kdc
,
294 kdc_conn
->conn
->remote_address
,
295 kdc_conn
->conn
->local_address
,
297 if (ret
== KDC_ERROR
) {
298 kdc_tcp_terminate_connection(kdc_conn
,
299 "kdc_tcp_call_loop: process function failed");
303 if (ret
== KDC_PROXY_REQUEST
) {
306 if (!kdc_conn
->kdc_socket
->kdc
->am_rodc
) {
307 kdc_tcp_terminate_connection(kdc_conn
,
308 "kdc_tcp_call_loop: proxying requested when not RODC");
311 port
= tsocket_address_inet_port(kdc_conn
->conn
->local_address
);
313 subreq
= kdc_tcp_proxy_send(call
,
314 kdc_conn
->conn
->event
.ctx
,
315 kdc_conn
->kdc_socket
->kdc
,
318 if (subreq
== NULL
) {
319 kdc_tcp_terminate_connection(kdc_conn
,
320 "kdc_tcp_call_loop: kdc_tcp_proxy_send failed");
323 tevent_req_set_callback(subreq
, kdc_tcp_call_proxy_done
, call
);
327 /* First add the length of the out buffer */
328 RSIVAL(call
->out_hdr
, 0, call
->out
.length
);
329 call
->out_iov
[0].iov_base
= (char *) call
->out_hdr
;
330 call
->out_iov
[0].iov_len
= 4;
332 call
->out_iov
[1].iov_base
= (char *) call
->out
.data
;
333 call
->out_iov
[1].iov_len
= call
->out
.length
;
335 subreq
= tstream_writev_queue_send(call
,
336 kdc_conn
->conn
->event
.ctx
,
338 kdc_conn
->send_queue
,
340 if (subreq
== NULL
) {
341 kdc_tcp_terminate_connection(kdc_conn
, "kdc_tcp_call_loop: "
342 "no memory for tstream_writev_queue_send");
345 tevent_req_set_callback(subreq
, kdc_tcp_call_writev_done
, call
);
348 * The krb5 tcp pdu's has the length as 4 byte (initial_read_size),
349 * packet_full_request_u32 provides the pdu length then.
351 subreq
= tstream_read_pdu_blob_send(kdc_conn
,
352 kdc_conn
->conn
->event
.ctx
,
354 4, /* initial_read_size */
355 packet_full_request_u32
,
357 if (subreq
== NULL
) {
358 kdc_tcp_terminate_connection(kdc_conn
, "kdc_tcp_call_loop: "
359 "no memory for tstream_read_pdu_blob_send");
362 tevent_req_set_callback(subreq
, kdc_tcp_call_loop
, kdc_conn
);
365 static void kdc_tcp_call_proxy_done(struct tevent_req
*subreq
)
367 struct kdc_tcp_call
*call
= tevent_req_callback_data(subreq
,
368 struct kdc_tcp_call
);
369 struct kdc_tcp_connection
*kdc_conn
= call
->kdc_conn
;
372 status
= kdc_tcp_proxy_recv(subreq
, call
, &call
->out
);
374 if (!NT_STATUS_IS_OK(status
)) {
375 /* generate an error packet */
376 status
= kdc_proxy_unavailable_error(kdc_conn
->kdc_socket
->kdc
,
380 if (!NT_STATUS_IS_OK(status
)) {
383 reason
= talloc_asprintf(call
, "kdc_tcp_call_proxy_done: "
384 "kdc_proxy_unavailable_error - %s",
387 reason
= "kdc_tcp_call_proxy_done: kdc_proxy_unavailable_error() failed";
390 kdc_tcp_terminate_connection(call
->kdc_conn
, reason
);
394 /* First add the length of the out buffer */
395 RSIVAL(call
->out_hdr
, 0, call
->out
.length
);
396 call
->out_iov
[0].iov_base
= (char *) call
->out_hdr
;
397 call
->out_iov
[0].iov_len
= 4;
399 call
->out_iov
[1].iov_base
= (char *) call
->out
.data
;
400 call
->out_iov
[1].iov_len
= call
->out
.length
;
402 subreq
= tstream_writev_queue_send(call
,
403 kdc_conn
->conn
->event
.ctx
,
405 kdc_conn
->send_queue
,
407 if (subreq
== NULL
) {
408 kdc_tcp_terminate_connection(kdc_conn
, "kdc_tcp_call_loop: "
409 "no memory for tstream_writev_queue_send");
412 tevent_req_set_callback(subreq
, kdc_tcp_call_writev_done
, call
);
415 * The krb5 tcp pdu's has the length as 4 byte (initial_read_size),
416 * packet_full_request_u32 provides the pdu length then.
418 subreq
= tstream_read_pdu_blob_send(kdc_conn
,
419 kdc_conn
->conn
->event
.ctx
,
421 4, /* initial_read_size */
422 packet_full_request_u32
,
424 if (subreq
== NULL
) {
425 kdc_tcp_terminate_connection(kdc_conn
, "kdc_tcp_call_loop: "
426 "no memory for tstream_read_pdu_blob_send");
429 tevent_req_set_callback(subreq
, kdc_tcp_call_loop
, kdc_conn
);
432 static void kdc_tcp_call_writev_done(struct tevent_req
*subreq
)
434 struct kdc_tcp_call
*call
= tevent_req_callback_data(subreq
,
435 struct kdc_tcp_call
);
439 rc
= tstream_writev_queue_recv(subreq
, &sys_errno
);
444 reason
= talloc_asprintf(call
, "kdc_tcp_call_writev_done: "
445 "tstream_writev_queue_recv() - %d:%s",
446 sys_errno
, strerror(sys_errno
));
448 reason
= "kdc_tcp_call_writev_done: tstream_writev_queue_recv() failed";
451 kdc_tcp_terminate_connection(call
->kdc_conn
, reason
);
455 /* We don't care about errors */
461 called when we get a new connection
463 static void kdc_tcp_accept(struct stream_connection
*conn
)
465 struct kdc_socket
*kdc_socket
;
466 struct kdc_tcp_connection
*kdc_conn
;
467 struct tevent_req
*subreq
;
470 kdc_conn
= talloc_zero(conn
, struct kdc_tcp_connection
);
471 if (kdc_conn
== NULL
) {
472 stream_terminate_connection(conn
,
473 "kdc_tcp_accept: out of memory");
477 kdc_conn
->send_queue
= tevent_queue_create(conn
, "kdc_tcp_accept");
478 if (kdc_conn
->send_queue
== NULL
) {
479 stream_terminate_connection(conn
,
480 "kdc_tcp_accept: out of memory");
484 kdc_socket
= talloc_get_type(conn
->private_data
, struct kdc_socket
);
486 TALLOC_FREE(conn
->event
.fde
);
488 rc
= tstream_bsd_existing_socket(kdc_conn
,
489 socket_get_fd(conn
->socket
),
492 stream_terminate_connection(conn
,
493 "kdc_tcp_accept: out of memory");
497 kdc_conn
->conn
= conn
;
498 kdc_conn
->kdc_socket
= kdc_socket
;
499 conn
->private_data
= kdc_conn
;
502 * The krb5 tcp pdu's has the length as 4 byte (initial_read_size),
503 * packet_full_request_u32 provides the pdu length then.
505 subreq
= tstream_read_pdu_blob_send(kdc_conn
,
506 kdc_conn
->conn
->event
.ctx
,
508 4, /* initial_read_size */
509 packet_full_request_u32
,
511 if (subreq
== NULL
) {
512 kdc_tcp_terminate_connection(kdc_conn
, "kdc_tcp_accept: "
513 "no memory for tstream_read_pdu_blob_send");
516 tevent_req_set_callback(subreq
, kdc_tcp_call_loop
, kdc_conn
);
519 static void kdc_tcp_recv(struct stream_connection
*conn
, uint16_t flags
)
521 struct kdc_tcp_connection
*kdcconn
= talloc_get_type(conn
->private_data
,
522 struct kdc_tcp_connection
);
523 /* this should never be triggered! */
524 kdc_tcp_terminate_connection(kdcconn
, "kdc_tcp_recv: called");
527 static void kdc_tcp_send(struct stream_connection
*conn
, uint16_t flags
)
529 struct kdc_tcp_connection
*kdcconn
= talloc_get_type(conn
->private_data
,
530 struct kdc_tcp_connection
);
531 /* this should never be triggered! */
532 kdc_tcp_terminate_connection(kdcconn
, "kdc_tcp_send: called");
535 static const struct stream_server_ops kdc_tcp_stream_ops
= {
537 .accept_connection
= kdc_tcp_accept
,
538 .recv_handler
= kdc_tcp_recv
,
539 .send_handler
= kdc_tcp_send
543 * Start listening on the given address
545 NTSTATUS
kdc_add_socket(struct kdc_server
*kdc
,
546 const struct model_ops
*model_ops
,
550 kdc_process_fn_t process
,
553 struct kdc_socket
*kdc_socket
;
554 struct kdc_udp_socket
*kdc_udp_socket
;
555 struct tevent_req
*udpsubreq
;
559 kdc_socket
= talloc(kdc
, struct kdc_socket
);
560 NT_STATUS_HAVE_NO_MEMORY(kdc_socket
);
562 kdc_socket
->kdc
= kdc
;
563 kdc_socket
->process
= process
;
565 ret
= tsocket_address_inet_from_strings(kdc_socket
, "ip",
567 &kdc_socket
->local_address
);
569 status
= map_nt_error_from_unix_common(errno
);
574 status
= stream_setup_socket(kdc
->task
,
575 kdc
->task
->event_ctx
,
579 "ip", address
, &port
,
580 lpcfg_socket_options(kdc
->task
->lp_ctx
),
582 kdc
->task
->process_context
);
583 if (!NT_STATUS_IS_OK(status
)) {
584 DEBUG(0,("Failed to bind to %s:%u TCP - %s\n",
585 address
, port
, nt_errstr(status
)));
586 talloc_free(kdc_socket
);
591 kdc_udp_socket
= talloc(kdc_socket
, struct kdc_udp_socket
);
592 NT_STATUS_HAVE_NO_MEMORY(kdc_udp_socket
);
594 kdc_udp_socket
->kdc_socket
= kdc_socket
;
596 ret
= tdgram_inet_udp_socket(kdc_socket
->local_address
,
599 &kdc_udp_socket
->dgram
);
601 status
= map_nt_error_from_unix_common(errno
);
602 DEBUG(0,("Failed to bind to %s:%u UDP - %s\n",
603 address
, port
, nt_errstr(status
)));
607 kdc_udp_socket
->send_queue
= tevent_queue_create(kdc_udp_socket
,
608 "kdc_udp_send_queue");
609 NT_STATUS_HAVE_NO_MEMORY(kdc_udp_socket
->send_queue
);
611 udpsubreq
= tdgram_recvfrom_send(kdc_udp_socket
,
612 kdc
->task
->event_ctx
,
613 kdc_udp_socket
->dgram
);
614 NT_STATUS_HAVE_NO_MEMORY(udpsubreq
);
615 tevent_req_set_callback(udpsubreq
, kdc_udp_call_loop
, kdc_udp_socket
);