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 "samba/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 #define DBGC_CLASS DBGC_KERBEROS
37 * State of an open tcp connection
39 struct kdc_tcp_connection
{
40 /* stream connection we belong to */
41 struct stream_connection
*conn
;
43 /* the kdc_server the connection belongs to */
44 struct kdc_socket
*kdc_socket
;
46 struct tstream_context
*tstream
;
48 struct tevent_queue
*send_queue
;
52 struct kdc_tcp_connection
*kdc_conn
;
56 struct iovec out_iov
[2];
60 struct kdc_udp_socket
*sock
;
61 struct tsocket_address
*src
;
66 static void kdc_udp_call_proxy_done(struct tevent_req
*subreq
);
67 static void kdc_udp_call_sendto_done(struct tevent_req
*subreq
);
69 static void kdc_tcp_call_writev_done(struct tevent_req
*subreq
);
70 static void kdc_tcp_call_proxy_done(struct tevent_req
*subreq
);
72 static void kdc_tcp_terminate_connection(struct kdc_tcp_connection
*kdc_conn
,
75 stream_terminate_connection(kdc_conn
->conn
, reason
);
78 static NTSTATUS
kdc_proxy_unavailable_error(struct kdc_server
*kdc
,
85 code
= smb_krb5_mk_error(kdc
->smb_krb5_context
->krb5_context
,
86 KRB5KDC_ERR_SVC_UNAVAILABLE
,
93 DBG_WARNING("Unable to form krb5 error reply\n");
94 return NT_STATUS_INTERNAL_ERROR
;
97 *out
= data_blob_talloc(mem_ctx
, enc_error
.data
, enc_error
.length
);
98 smb_krb5_free_data_contents(kdc
->smb_krb5_context
->krb5_context
,
101 return NT_STATUS_NO_MEMORY
;
107 static void kdc_udp_call_loop(struct tevent_req
*subreq
)
109 struct kdc_udp_socket
*sock
= tevent_req_callback_data(subreq
,
110 struct kdc_udp_socket
);
111 struct kdc_udp_call
*call
;
117 call
= talloc(sock
, struct kdc_udp_call
);
124 len
= tdgram_recvfrom_recv(subreq
, &sys_errno
,
125 call
, &buf
, &call
->src
);
133 call
->in
.length
= len
;
135 DBG_DEBUG("Received krb5 UDP packet of length %zu from %s\n",
137 tsocket_address_string(call
->src
, call
));
140 ret
= sock
->kdc_socket
->process(sock
->kdc_socket
->kdc
,
145 sock
->kdc_socket
->local_address
,
147 if (ret
== KDC_ERROR
) {
152 if (ret
== KDC_PROXY_REQUEST
) {
155 if (!sock
->kdc_socket
->kdc
->am_rodc
) {
156 DBG_ERR("proxying requested when not RODC\n");
161 port
= tsocket_address_inet_port(sock
->kdc_socket
->local_address
);
163 subreq
= kdc_udp_proxy_send(call
,
164 sock
->kdc_socket
->kdc
->task
->event_ctx
,
165 sock
->kdc_socket
->kdc
,
168 if (subreq
== NULL
) {
172 tevent_req_set_callback(subreq
, kdc_udp_call_proxy_done
, call
);
176 subreq
= tdgram_sendto_queue_send(call
,
177 sock
->kdc_socket
->kdc
->task
->event_ctx
,
183 if (subreq
== NULL
) {
187 tevent_req_set_callback(subreq
, kdc_udp_call_sendto_done
, call
);
190 subreq
= tdgram_recvfrom_send(sock
,
191 sock
->kdc_socket
->kdc
->task
->event_ctx
,
193 if (subreq
== NULL
) {
194 task_server_terminate(sock
->kdc_socket
->kdc
->task
,
195 "no memory for tdgram_recvfrom_send",
199 tevent_req_set_callback(subreq
, kdc_udp_call_loop
, sock
);
202 static void kdc_udp_call_proxy_done(struct tevent_req
*subreq
)
204 struct kdc_udp_call
*call
=
205 tevent_req_callback_data(subreq
,
206 struct kdc_udp_call
);
209 status
= kdc_udp_proxy_recv(subreq
, call
, &call
->out
);
211 if (!NT_STATUS_IS_OK(status
)) {
212 /* generate an error packet */
213 status
= kdc_proxy_unavailable_error(call
->sock
->kdc_socket
->kdc
,
217 if (!NT_STATUS_IS_OK(status
)) {
222 subreq
= tdgram_sendto_queue_send(call
,
223 call
->sock
->kdc_socket
->kdc
->task
->event_ctx
,
225 call
->sock
->send_queue
,
229 if (subreq
== NULL
) {
234 tevent_req_set_callback(subreq
, kdc_udp_call_sendto_done
, call
);
237 static void kdc_udp_call_sendto_done(struct tevent_req
*subreq
)
239 struct kdc_udp_call
*call
= tevent_req_callback_data(subreq
,
240 struct kdc_udp_call
);
243 tdgram_sendto_queue_recv(subreq
, &sys_errno
);
245 /* We don't care about errors */
250 static void kdc_tcp_call_loop(struct tevent_req
*subreq
)
252 struct kdc_tcp_connection
*kdc_conn
= tevent_req_callback_data(subreq
,
253 struct kdc_tcp_connection
);
254 struct kdc_tcp_call
*call
;
258 call
= talloc(kdc_conn
, struct kdc_tcp_call
);
260 kdc_tcp_terminate_connection(kdc_conn
, "kdc_tcp_call_loop: "
261 "no memory for kdc_tcp_call");
264 call
->kdc_conn
= kdc_conn
;
266 status
= tstream_read_pdu_blob_recv(subreq
,
270 if (!NT_STATUS_IS_OK(status
)) {
273 reason
= talloc_asprintf(call
, "kdc_tcp_call_loop: "
274 "tstream_read_pdu_blob_recv() - %s",
277 reason
= nt_errstr(status
);
280 kdc_tcp_terminate_connection(kdc_conn
, reason
);
284 DBG_DEBUG("Received krb5 TCP packet of length %zu from %s\n",
286 tsocket_address_string(kdc_conn
->conn
->remote_address
, call
));
288 /* skip length header */
290 call
->in
.length
-= 4;
293 ret
= kdc_conn
->kdc_socket
->process(kdc_conn
->kdc_socket
->kdc
,
297 kdc_conn
->conn
->remote_address
,
298 kdc_conn
->conn
->local_address
,
300 if (ret
== KDC_ERROR
) {
301 kdc_tcp_terminate_connection(kdc_conn
,
302 "kdc_tcp_call_loop: process function failed");
306 if (ret
== KDC_PROXY_REQUEST
) {
309 if (!kdc_conn
->kdc_socket
->kdc
->am_rodc
) {
310 kdc_tcp_terminate_connection(kdc_conn
,
311 "kdc_tcp_call_loop: proxying requested when not RODC");
314 port
= tsocket_address_inet_port(kdc_conn
->conn
->local_address
);
316 subreq
= kdc_tcp_proxy_send(call
,
317 kdc_conn
->conn
->event
.ctx
,
318 kdc_conn
->kdc_socket
->kdc
,
321 if (subreq
== NULL
) {
322 kdc_tcp_terminate_connection(kdc_conn
,
323 "kdc_tcp_call_loop: kdc_tcp_proxy_send failed");
326 tevent_req_set_callback(subreq
, kdc_tcp_call_proxy_done
, call
);
330 /* First add the length of the out buffer */
331 RSIVAL(call
->out_hdr
, 0, call
->out
.length
);
332 call
->out_iov
[0].iov_base
= (char *) call
->out_hdr
;
333 call
->out_iov
[0].iov_len
= 4;
335 call
->out_iov
[1].iov_base
= (char *) call
->out
.data
;
336 call
->out_iov
[1].iov_len
= call
->out
.length
;
338 subreq
= tstream_writev_queue_send(call
,
339 kdc_conn
->conn
->event
.ctx
,
341 kdc_conn
->send_queue
,
343 if (subreq
== NULL
) {
344 kdc_tcp_terminate_connection(kdc_conn
, "kdc_tcp_call_loop: "
345 "no memory for tstream_writev_queue_send");
348 tevent_req_set_callback(subreq
, kdc_tcp_call_writev_done
, call
);
351 * The krb5 tcp pdu's has the length as 4 byte (initial_read_size),
352 * tstream_full_request_u32 provides the pdu length then.
354 subreq
= tstream_read_pdu_blob_send(kdc_conn
,
355 kdc_conn
->conn
->event
.ctx
,
357 4, /* initial_read_size */
358 tstream_full_request_u32
,
360 if (subreq
== NULL
) {
361 kdc_tcp_terminate_connection(kdc_conn
, "kdc_tcp_call_loop: "
362 "no memory for tstream_read_pdu_blob_send");
365 tevent_req_set_callback(subreq
, kdc_tcp_call_loop
, kdc_conn
);
368 static void kdc_tcp_call_proxy_done(struct tevent_req
*subreq
)
370 struct kdc_tcp_call
*call
= tevent_req_callback_data(subreq
,
371 struct kdc_tcp_call
);
372 struct kdc_tcp_connection
*kdc_conn
= call
->kdc_conn
;
375 status
= kdc_tcp_proxy_recv(subreq
, call
, &call
->out
);
377 if (!NT_STATUS_IS_OK(status
)) {
378 /* generate an error packet */
379 status
= kdc_proxy_unavailable_error(kdc_conn
->kdc_socket
->kdc
,
383 if (!NT_STATUS_IS_OK(status
)) {
386 reason
= talloc_asprintf(call
, "kdc_tcp_call_proxy_done: "
387 "kdc_proxy_unavailable_error - %s",
390 reason
= "kdc_tcp_call_proxy_done: kdc_proxy_unavailable_error() failed";
393 kdc_tcp_terminate_connection(call
->kdc_conn
, reason
);
397 /* First add the length of the out buffer */
398 RSIVAL(call
->out_hdr
, 0, call
->out
.length
);
399 call
->out_iov
[0].iov_base
= (char *) call
->out_hdr
;
400 call
->out_iov
[0].iov_len
= 4;
402 call
->out_iov
[1].iov_base
= (char *) call
->out
.data
;
403 call
->out_iov
[1].iov_len
= call
->out
.length
;
405 subreq
= tstream_writev_queue_send(call
,
406 kdc_conn
->conn
->event
.ctx
,
408 kdc_conn
->send_queue
,
410 if (subreq
== NULL
) {
411 kdc_tcp_terminate_connection(kdc_conn
, "kdc_tcp_call_proxy_done: "
412 "no memory for tstream_writev_queue_send");
415 tevent_req_set_callback(subreq
, kdc_tcp_call_writev_done
, call
);
418 * The krb5 tcp pdu's has the length as 4 byte (initial_read_size),
419 * tstream_full_request_u32 provides the pdu length then.
421 subreq
= tstream_read_pdu_blob_send(kdc_conn
,
422 kdc_conn
->conn
->event
.ctx
,
424 4, /* initial_read_size */
425 tstream_full_request_u32
,
427 if (subreq
== NULL
) {
428 kdc_tcp_terminate_connection(kdc_conn
, "kdc_tcp_call_proxy_done: "
429 "no memory for tstream_read_pdu_blob_send");
432 tevent_req_set_callback(subreq
, kdc_tcp_call_loop
, kdc_conn
);
435 static void kdc_tcp_call_writev_done(struct tevent_req
*subreq
)
437 struct kdc_tcp_call
*call
= tevent_req_callback_data(subreq
,
438 struct kdc_tcp_call
);
442 rc
= tstream_writev_queue_recv(subreq
, &sys_errno
);
447 reason
= talloc_asprintf(call
, "kdc_tcp_call_writev_done: "
448 "tstream_writev_queue_recv() - %d:%s",
449 sys_errno
, strerror(sys_errno
));
451 reason
= "kdc_tcp_call_writev_done: tstream_writev_queue_recv() failed";
454 kdc_tcp_terminate_connection(call
->kdc_conn
, reason
);
458 /* We don't care about errors */
464 called when we get a new connection
466 static void kdc_tcp_accept(struct stream_connection
*conn
)
468 struct kdc_socket
*kdc_socket
;
469 struct kdc_tcp_connection
*kdc_conn
;
470 struct tevent_req
*subreq
;
473 kdc_conn
= talloc_zero(conn
, struct kdc_tcp_connection
);
474 if (kdc_conn
== NULL
) {
475 stream_terminate_connection(conn
,
476 "kdc_tcp_accept: out of memory");
480 kdc_conn
->send_queue
= tevent_queue_create(conn
, "kdc_tcp_accept");
481 if (kdc_conn
->send_queue
== NULL
) {
482 stream_terminate_connection(conn
,
483 "kdc_tcp_accept: out of memory");
487 kdc_socket
= talloc_get_type(conn
->private_data
, struct kdc_socket
);
489 TALLOC_FREE(conn
->event
.fde
);
491 rc
= tstream_bsd_existing_socket(kdc_conn
,
492 socket_get_fd(conn
->socket
),
495 stream_terminate_connection(conn
,
496 "kdc_tcp_accept: out of memory");
499 /* as server we want to fail early */
500 tstream_bsd_fail_readv_first_error(kdc_conn
->tstream
, true);
502 kdc_conn
->conn
= conn
;
503 kdc_conn
->kdc_socket
= kdc_socket
;
504 conn
->private_data
= kdc_conn
;
507 * The krb5 tcp pdu's has the length as 4 byte (initial_read_size),
508 * tstream_full_request_u32 provides the pdu length then.
510 subreq
= tstream_read_pdu_blob_send(kdc_conn
,
511 kdc_conn
->conn
->event
.ctx
,
513 4, /* initial_read_size */
514 tstream_full_request_u32
,
516 if (subreq
== NULL
) {
517 kdc_tcp_terminate_connection(kdc_conn
, "kdc_tcp_accept: "
518 "no memory for tstream_read_pdu_blob_send");
521 tevent_req_set_callback(subreq
, kdc_tcp_call_loop
, kdc_conn
);
524 static void kdc_tcp_recv(struct stream_connection
*conn
, uint16_t flags
)
526 struct kdc_tcp_connection
*kdcconn
= talloc_get_type(conn
->private_data
,
527 struct kdc_tcp_connection
);
528 /* this should never be triggered! */
529 kdc_tcp_terminate_connection(kdcconn
, "kdc_tcp_recv: called");
532 static void kdc_tcp_send(struct stream_connection
*conn
, uint16_t flags
)
534 struct kdc_tcp_connection
*kdcconn
= talloc_get_type(conn
->private_data
,
535 struct kdc_tcp_connection
);
536 /* this should never be triggered! */
537 kdc_tcp_terminate_connection(kdcconn
, "kdc_tcp_send: called");
540 static const struct stream_server_ops kdc_tcp_stream_ops
= {
542 .accept_connection
= kdc_tcp_accept
,
543 .recv_handler
= kdc_tcp_recv
,
544 .send_handler
= kdc_tcp_send
548 * Start listening on the given address
550 NTSTATUS
kdc_add_socket(struct kdc_server
*kdc
,
551 const struct model_ops
*model_ops
,
555 kdc_process_fn_t process
,
558 struct kdc_socket
*kdc_socket
;
559 struct kdc_udp_socket
*kdc_udp_socket
;
560 struct tevent_req
*udpsubreq
;
564 kdc_socket
= talloc(kdc
, struct kdc_socket
);
565 NT_STATUS_HAVE_NO_MEMORY(kdc_socket
);
567 kdc_socket
->kdc
= kdc
;
568 kdc_socket
->process
= process
;
570 ret
= tsocket_address_inet_from_strings(kdc_socket
, "ip",
572 &kdc_socket
->local_address
);
574 status
= map_nt_error_from_unix_common(errno
);
579 status
= stream_setup_socket(kdc
->task
,
580 kdc
->task
->event_ctx
,
584 "ip", address
, &port
,
585 lpcfg_socket_options(kdc
->task
->lp_ctx
),
587 kdc
->task
->process_context
);
588 if (!NT_STATUS_IS_OK(status
)) {
589 DBG_ERR("Failed to bind to %s:%u TCP - %s\n",
590 address
, port
, nt_errstr(status
));
591 talloc_free(kdc_socket
);
596 kdc_udp_socket
= talloc(kdc_socket
, struct kdc_udp_socket
);
597 NT_STATUS_HAVE_NO_MEMORY(kdc_udp_socket
);
599 kdc_udp_socket
->kdc_socket
= kdc_socket
;
601 ret
= tdgram_inet_udp_socket(kdc_socket
->local_address
,
604 &kdc_udp_socket
->dgram
);
606 status
= map_nt_error_from_unix_common(errno
);
607 DBG_ERR("Failed to bind to %s:%u UDP - %s\n",
608 address
, port
, nt_errstr(status
));
612 kdc_udp_socket
->send_queue
= tevent_queue_create(kdc_udp_socket
,
613 "kdc_udp_send_queue");
614 NT_STATUS_HAVE_NO_MEMORY(kdc_udp_socket
->send_queue
);
616 udpsubreq
= tdgram_recvfrom_send(kdc_udp_socket
,
617 kdc
->task
->event_ctx
,
618 kdc_udp_socket
->dgram
);
619 NT_STATUS_HAVE_NO_MEMORY(udpsubreq
);
620 tevent_req_set_callback(udpsubreq
, kdc_udp_call_loop
, kdc_udp_socket
);