diff options
author | Andreas Schneider <asn@samba.org> | 2016-06-10 11:29:20 +0200 |
---|---|---|
committer | Jeremy Allison <jra@samba.org> | 2016-06-19 03:31:32 +0200 |
commit | 3de3f643a870239a7a410a13065a86053992f7fa (patch) | |
tree | e04872abf6530fe23e1505f471b9ecede0414b62 /source4/kdc/kdc-heimdal.c | |
parent | 3da8932e4ce4c289daf7bb102c0e5f54413b568c (diff) | |
download | samba-3de3f643a870239a7a410a13065a86053992f7fa.tar.gz |
s4-kdc: Move KDC packet handling functions to kdc-server.c
Create an Kerberos implmentation independent KDC-SERVER subsystem so we
can use it to implement a kpasswd server with MIT Kerberos in future.
Signed-off-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
Autobuild-User(master): Jeremy Allison <jra@samba.org>
Autobuild-Date(master): Sun Jun 19 03:31:32 CEST 2016 on sn-devel-144
Diffstat (limited to 'source4/kdc/kdc-heimdal.c')
-rw-r--r-- | source4/kdc/kdc-heimdal.c | 587 |
1 files changed, 0 insertions, 587 deletions
diff --git a/source4/kdc/kdc-heimdal.c b/source4/kdc/kdc-heimdal.c index 493b30b8425..be4507386bc 100644 --- a/source4/kdc/kdc-heimdal.c +++ b/source4/kdc/kdc-heimdal.c @@ -24,11 +24,9 @@ #include "includes.h" #include "smbd/process_model.h" #include "lib/tsocket/tsocket.h" -#include "libcli/util/tstream.h" #include "lib/messaging/irpc.h" #include "librpc/gen_ndr/ndr_irpc.h" #include "librpc/gen_ndr/ndr_krb5pac.h" -#include "lib/stream/packet.h" #include "lib/socket/netif.h" #include "param/param.h" #include "kdc/kdc-server.h" @@ -45,78 +43,6 @@ NTSTATUS server_service_kdc_init(void); extern struct krb5plugin_windc_ftable windc_plugin_table; -static NTSTATUS kdc_proxy_unavailable_error(struct kdc_server *kdc, - TALLOC_CTX *mem_ctx, - DATA_BLOB *out) -{ - int kret; - krb5_data k5_error_blob; - - kret = smb_krb5_mk_error(kdc->smb_krb5_context->krb5_context, - KRB5KDC_ERR_SVC_UNAVAILABLE, - NULL, - NULL, - &k5_error_blob); - if (kret != 0) { - DEBUG(2,(__location__ ": Unable to form krb5 error reply\n")); - return NT_STATUS_INTERNAL_ERROR; - } - - *out = data_blob_talloc(mem_ctx, k5_error_blob.data, k5_error_blob.length); - kerberos_free_data_contents(kdc->smb_krb5_context->krb5_context, - &k5_error_blob); - if (!out->data) { - return NT_STATUS_NO_MEMORY; - } - - return NT_STATUS_OK; -} - -struct kdc_tcp_call { - struct kdc_tcp_connection *kdc_conn; - DATA_BLOB in; - DATA_BLOB out; - uint8_t out_hdr[4]; - struct iovec out_iov[2]; -}; - -/* - state of an open tcp connection -*/ -struct kdc_tcp_connection { - /* stream connection we belong to */ - struct stream_connection *conn; - - /* the kdc_server the connection belongs to */ - struct kdc_socket *kdc_socket; - - struct tstream_context *tstream; - - struct tevent_queue *send_queue; -}; - - -static void kdc_tcp_terminate_connection(struct kdc_tcp_connection *kdcconn, const char *reason) -{ - stream_terminate_connection(kdcconn->conn, reason); -} - -static void kdc_tcp_recv(struct stream_connection *conn, uint16_t flags) -{ - struct kdc_tcp_connection *kdcconn = talloc_get_type(conn->private_data, - struct kdc_tcp_connection); - /* this should never be triggered! */ - kdc_tcp_terminate_connection(kdcconn, "kdc_tcp_recv: called"); -} - -static void kdc_tcp_send(struct stream_connection *conn, uint16_t flags) -{ - struct kdc_tcp_connection *kdcconn = talloc_get_type(conn->private_data, - struct kdc_tcp_connection); - /* this should never be triggered! */ - kdc_tcp_terminate_connection(kdcconn, "kdc_tcp_send: called"); -} - /** Wrapper for krb5_kdc_process_krb5_request, converting to/from Samba calling conventions @@ -180,519 +106,6 @@ static kdc_code kdc_process(struct kdc_server *kdc, return KDC_OK; } -static void kdc_tcp_call_proxy_done(struct tevent_req *subreq); -static void kdc_tcp_call_writev_done(struct tevent_req *subreq); - -static void kdc_tcp_call_loop(struct tevent_req *subreq) -{ - struct kdc_tcp_connection *kdc_conn = tevent_req_callback_data(subreq, - struct kdc_tcp_connection); - struct kdc_tcp_call *call; - NTSTATUS status; - kdc_code ret; - - call = talloc(kdc_conn, struct kdc_tcp_call); - if (call == NULL) { - kdc_tcp_terminate_connection(kdc_conn, "kdc_tcp_call_loop: " - "no memory for kdc_tcp_call"); - return; - } - call->kdc_conn = kdc_conn; - - status = tstream_read_pdu_blob_recv(subreq, - call, - &call->in); - TALLOC_FREE(subreq); - if (!NT_STATUS_IS_OK(status)) { - const char *reason; - - reason = talloc_asprintf(call, "kdc_tcp_call_loop: " - "tstream_read_pdu_blob_recv() - %s", - nt_errstr(status)); - if (!reason) { - reason = nt_errstr(status); - } - - kdc_tcp_terminate_connection(kdc_conn, reason); - return; - } - - DEBUG(10,("Received krb5 TCP packet of length %lu from %s\n", - (long) call->in.length, - tsocket_address_string(kdc_conn->conn->remote_address, call))); - - /* skip length header */ - call->in.data +=4; - call->in.length -= 4; - - /* Call krb5 */ - ret = kdc_conn->kdc_socket->process(kdc_conn->kdc_socket->kdc, - call, - &call->in, - &call->out, - kdc_conn->conn->remote_address, - kdc_conn->conn->local_address, - 0 /* Stream */); - if (ret == KDC_ERROR) { - kdc_tcp_terminate_connection(kdc_conn, - "kdc_tcp_call_loop: process function failed"); - return; - } - - if (ret == KDC_PROXY_REQUEST) { - uint16_t port; - - if (!kdc_conn->kdc_socket->kdc->am_rodc) { - kdc_tcp_terminate_connection(kdc_conn, - "kdc_tcp_call_loop: proxying requested when not RODC"); - return; - } - port = tsocket_address_inet_port(kdc_conn->conn->local_address); - - subreq = kdc_tcp_proxy_send(call, - kdc_conn->conn->event.ctx, - kdc_conn->kdc_socket->kdc, - port, - call->in); - if (subreq == NULL) { - kdc_tcp_terminate_connection(kdc_conn, - "kdc_tcp_call_loop: kdc_tcp_proxy_send failed"); - return; - } - tevent_req_set_callback(subreq, kdc_tcp_call_proxy_done, call); - return; - } - - /* First add the length of the out buffer */ - RSIVAL(call->out_hdr, 0, call->out.length); - call->out_iov[0].iov_base = (char *) call->out_hdr; - call->out_iov[0].iov_len = 4; - - call->out_iov[1].iov_base = (char *) call->out.data; - call->out_iov[1].iov_len = call->out.length; - - subreq = tstream_writev_queue_send(call, - kdc_conn->conn->event.ctx, - kdc_conn->tstream, - kdc_conn->send_queue, - call->out_iov, 2); - if (subreq == NULL) { - kdc_tcp_terminate_connection(kdc_conn, "kdc_tcp_call_loop: " - "no memory for tstream_writev_queue_send"); - return; - } - tevent_req_set_callback(subreq, kdc_tcp_call_writev_done, call); - - /* - * The krb5 tcp pdu's has the length as 4 byte (initial_read_size), - * packet_full_request_u32 provides the pdu length then. - */ - subreq = tstream_read_pdu_blob_send(kdc_conn, - kdc_conn->conn->event.ctx, - kdc_conn->tstream, - 4, /* initial_read_size */ - packet_full_request_u32, - kdc_conn); - if (subreq == NULL) { - kdc_tcp_terminate_connection(kdc_conn, "kdc_tcp_call_loop: " - "no memory for tstream_read_pdu_blob_send"); - return; - } - tevent_req_set_callback(subreq, kdc_tcp_call_loop, kdc_conn); -} - -static void kdc_tcp_call_proxy_done(struct tevent_req *subreq) -{ - struct kdc_tcp_call *call = tevent_req_callback_data(subreq, - struct kdc_tcp_call); - struct kdc_tcp_connection *kdc_conn = call->kdc_conn; - NTSTATUS status; - - status = kdc_tcp_proxy_recv(subreq, call, &call->out); - TALLOC_FREE(subreq); - if (!NT_STATUS_IS_OK(status)) { - /* generate an error packet */ - status = kdc_proxy_unavailable_error(kdc_conn->kdc_socket->kdc, - call, &call->out); - } - - if (!NT_STATUS_IS_OK(status)) { - const char *reason; - - reason = talloc_asprintf(call, "kdc_tcp_call_proxy_done: " - "kdc_proxy_unavailable_error - %s", - nt_errstr(status)); - if (!reason) { - reason = "kdc_tcp_call_proxy_done: kdc_proxy_unavailable_error() failed"; - } - - kdc_tcp_terminate_connection(call->kdc_conn, reason); - return; - } - - /* First add the length of the out buffer */ - RSIVAL(call->out_hdr, 0, call->out.length); - call->out_iov[0].iov_base = (char *) call->out_hdr; - call->out_iov[0].iov_len = 4; - - call->out_iov[1].iov_base = (char *) call->out.data; - call->out_iov[1].iov_len = call->out.length; - - subreq = tstream_writev_queue_send(call, - kdc_conn->conn->event.ctx, - kdc_conn->tstream, - kdc_conn->send_queue, - call->out_iov, 2); - if (subreq == NULL) { - kdc_tcp_terminate_connection(kdc_conn, "kdc_tcp_call_loop: " - "no memory for tstream_writev_queue_send"); - return; - } - tevent_req_set_callback(subreq, kdc_tcp_call_writev_done, call); - - /* - * The krb5 tcp pdu's has the length as 4 byte (initial_read_size), - * packet_full_request_u32 provides the pdu length then. - */ - subreq = tstream_read_pdu_blob_send(kdc_conn, - kdc_conn->conn->event.ctx, - kdc_conn->tstream, - 4, /* initial_read_size */ - packet_full_request_u32, - kdc_conn); - if (subreq == NULL) { - kdc_tcp_terminate_connection(kdc_conn, "kdc_tcp_call_loop: " - "no memory for tstream_read_pdu_blob_send"); - return; - } - tevent_req_set_callback(subreq, kdc_tcp_call_loop, kdc_conn); -} - -static void kdc_tcp_call_writev_done(struct tevent_req *subreq) -{ - struct kdc_tcp_call *call = tevent_req_callback_data(subreq, - struct kdc_tcp_call); - int sys_errno; - int rc; - - rc = tstream_writev_queue_recv(subreq, &sys_errno); - TALLOC_FREE(subreq); - if (rc == -1) { - const char *reason; - - reason = talloc_asprintf(call, "kdc_tcp_call_writev_done: " - "tstream_writev_queue_recv() - %d:%s", - sys_errno, strerror(sys_errno)); - if (!reason) { - reason = "kdc_tcp_call_writev_done: tstream_writev_queue_recv() failed"; - } - - kdc_tcp_terminate_connection(call->kdc_conn, reason); - return; - } - - /* We don't care about errors */ - - talloc_free(call); -} - -/* - called when we get a new connection -*/ -static void kdc_tcp_accept(struct stream_connection *conn) -{ - struct kdc_socket *kdc_socket; - struct kdc_tcp_connection *kdc_conn; - struct tevent_req *subreq; - int rc; - - kdc_conn = talloc_zero(conn, struct kdc_tcp_connection); - if (kdc_conn == NULL) { - stream_terminate_connection(conn, - "kdc_tcp_accept: out of memory"); - return; - } - - kdc_conn->send_queue = tevent_queue_create(conn, "kdc_tcp_accept"); - if (kdc_conn->send_queue == NULL) { - stream_terminate_connection(conn, - "kdc_tcp_accept: out of memory"); - return; - } - - kdc_socket = talloc_get_type(conn->private_data, struct kdc_socket); - - TALLOC_FREE(conn->event.fde); - - rc = tstream_bsd_existing_socket(kdc_conn, - socket_get_fd(conn->socket), - &kdc_conn->tstream); - if (rc < 0) { - stream_terminate_connection(conn, - "kdc_tcp_accept: out of memory"); - return; - } - - kdc_conn->conn = conn; - kdc_conn->kdc_socket = kdc_socket; - conn->private_data = kdc_conn; - - /* - * The krb5 tcp pdu's has the length as 4 byte (initial_read_size), - * packet_full_request_u32 provides the pdu length then. - */ - subreq = tstream_read_pdu_blob_send(kdc_conn, - kdc_conn->conn->event.ctx, - kdc_conn->tstream, - 4, /* initial_read_size */ - packet_full_request_u32, - kdc_conn); - if (subreq == NULL) { - kdc_tcp_terminate_connection(kdc_conn, "kdc_tcp_accept: " - "no memory for tstream_read_pdu_blob_send"); - return; - } - tevent_req_set_callback(subreq, kdc_tcp_call_loop, kdc_conn); -} - -static const struct stream_server_ops kdc_tcp_stream_ops = { - .name = "kdc_tcp", - .accept_connection = kdc_tcp_accept, - .recv_handler = kdc_tcp_recv, - .send_handler = kdc_tcp_send -}; - -struct kdc_udp_call { - struct kdc_udp_socket *sock; - struct tsocket_address *src; - DATA_BLOB in; - DATA_BLOB out; -}; - -static void kdc_udp_call_proxy_done(struct tevent_req *subreq); -static void kdc_udp_call_sendto_done(struct tevent_req *subreq); - -static void kdc_udp_call_loop(struct tevent_req *subreq) -{ - struct kdc_udp_socket *sock = tevent_req_callback_data(subreq, - struct kdc_udp_socket); - struct kdc_udp_call *call; - uint8_t *buf; - ssize_t len; - int sys_errno; - kdc_code ret; - - call = talloc(sock, struct kdc_udp_call); - if (call == NULL) { - talloc_free(call); - goto done; - } - call->sock = sock; - - len = tdgram_recvfrom_recv(subreq, &sys_errno, - call, &buf, &call->src); - TALLOC_FREE(subreq); - if (len == -1) { - talloc_free(call); - goto done; - } - - call->in.data = buf; - call->in.length = len; - - DEBUG(10,("Received krb5 UDP packet of length %lu from %s\n", - (long)call->in.length, - tsocket_address_string(call->src, call))); - - /* Call krb5 */ - ret = sock->kdc_socket->process(sock->kdc_socket->kdc, - call, - &call->in, - &call->out, - call->src, - sock->kdc_socket->local_address, - 1 /* Datagram */); - if (ret == KDC_ERROR) { - talloc_free(call); - goto done; - } - - if (ret == KDC_PROXY_REQUEST) { - uint16_t port; - - if (!sock->kdc_socket->kdc->am_rodc) { - DEBUG(0,("kdc_udp_call_loop: proxying requested when not RODC")); - talloc_free(call); - goto done; - } - - port = tsocket_address_inet_port(sock->kdc_socket->local_address); - - subreq = kdc_udp_proxy_send(call, - sock->kdc_socket->kdc->task->event_ctx, - sock->kdc_socket->kdc, - port, - call->in); - if (subreq == NULL) { - talloc_free(call); - goto done; - } - tevent_req_set_callback(subreq, kdc_udp_call_proxy_done, call); - goto done; - } - - subreq = tdgram_sendto_queue_send(call, - sock->kdc_socket->kdc->task->event_ctx, - sock->dgram, - sock->send_queue, - call->out.data, - call->out.length, - call->src); - if (subreq == NULL) { - talloc_free(call); - goto done; - } - tevent_req_set_callback(subreq, kdc_udp_call_sendto_done, call); - -done: - subreq = tdgram_recvfrom_send(sock, - sock->kdc_socket->kdc->task->event_ctx, - sock->dgram); - if (subreq == NULL) { - task_server_terminate(sock->kdc_socket->kdc->task, - "no memory for tdgram_recvfrom_send", - true); - return; - } - tevent_req_set_callback(subreq, kdc_udp_call_loop, sock); -} - -static void kdc_udp_call_proxy_done(struct tevent_req *subreq) -{ - struct kdc_udp_call *call = - tevent_req_callback_data(subreq, - struct kdc_udp_call); - NTSTATUS status; - - status = kdc_udp_proxy_recv(subreq, call, &call->out); - TALLOC_FREE(subreq); - if (!NT_STATUS_IS_OK(status)) { - /* generate an error packet */ - status = kdc_proxy_unavailable_error(call->sock->kdc_socket->kdc, - call, &call->out); - } - - if (!NT_STATUS_IS_OK(status)) { - talloc_free(call); - return; - } - - subreq = tdgram_sendto_queue_send(call, - call->sock->kdc_socket->kdc->task->event_ctx, - call->sock->dgram, - call->sock->send_queue, - call->out.data, - call->out.length, - call->src); - if (subreq == NULL) { - talloc_free(call); - return; - } - - tevent_req_set_callback(subreq, kdc_udp_call_sendto_done, call); -} - -static void kdc_udp_call_sendto_done(struct tevent_req *subreq) -{ - struct kdc_udp_call *call = tevent_req_callback_data(subreq, - struct kdc_udp_call); - int sys_errno; - - tdgram_sendto_queue_recv(subreq, &sys_errno); - - /* We don't care about errors */ - - talloc_free(call); -} - -/* - start listening on the given address -*/ -static NTSTATUS kdc_add_socket(struct kdc_server *kdc, - const struct model_ops *model_ops, - const char *name, - const char *address, - uint16_t port, - kdc_process_fn_t process, - bool udp_only) -{ - struct kdc_socket *kdc_socket; - struct kdc_udp_socket *kdc_udp_socket; - struct tevent_req *udpsubreq; - NTSTATUS status; - int ret; - - kdc_socket = talloc(kdc, struct kdc_socket); - NT_STATUS_HAVE_NO_MEMORY(kdc_socket); - - kdc_socket->kdc = kdc; - kdc_socket->process = process; - - ret = tsocket_address_inet_from_strings(kdc_socket, "ip", - address, port, - &kdc_socket->local_address); - if (ret != 0) { - status = map_nt_error_from_unix_common(errno); - return status; - } - - if (!udp_only) { - status = stream_setup_socket(kdc->task, - kdc->task->event_ctx, - kdc->task->lp_ctx, - model_ops, - &kdc_tcp_stream_ops, - "ip", address, &port, - lpcfg_socket_options(kdc->task->lp_ctx), - kdc_socket); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("Failed to bind to %s:%u TCP - %s\n", - address, port, nt_errstr(status))); - talloc_free(kdc_socket); - return status; - } - } - - kdc_udp_socket = talloc(kdc_socket, struct kdc_udp_socket); - NT_STATUS_HAVE_NO_MEMORY(kdc_udp_socket); - - kdc_udp_socket->kdc_socket = kdc_socket; - - ret = tdgram_inet_udp_socket(kdc_socket->local_address, - NULL, - kdc_udp_socket, - &kdc_udp_socket->dgram); - if (ret != 0) { - status = map_nt_error_from_unix_common(errno); - DEBUG(0,("Failed to bind to %s:%u UDP - %s\n", - address, port, nt_errstr(status))); - return status; - } - - kdc_udp_socket->send_queue = tevent_queue_create(kdc_udp_socket, - "kdc_udp_send_queue"); - NT_STATUS_HAVE_NO_MEMORY(kdc_udp_socket->send_queue); - - udpsubreq = tdgram_recvfrom_send(kdc_udp_socket, - kdc->task->event_ctx, - kdc_udp_socket->dgram); - NT_STATUS_HAVE_NO_MEMORY(udpsubreq); - tevent_req_set_callback(udpsubreq, kdc_udp_call_loop, kdc_udp_socket); - - return NT_STATUS_OK; -} - - /* setup our listening sockets on the configured network interfaces */ |