summaryrefslogtreecommitdiff
path: root/source4/kdc/kdc.c
diff options
context:
space:
mode:
Diffstat (limited to 'source4/kdc/kdc.c')
-rw-r--r--source4/kdc/kdc.c127
1 files changed, 123 insertions, 4 deletions
diff --git a/source4/kdc/kdc.c b/source4/kdc/kdc.c
index 05c1d9c40d..26365acc7c 100644
--- a/source4/kdc/kdc.c
+++ b/source4/kdc/kdc.c
@@ -62,6 +62,45 @@ static NTSTATUS kdc_proxy_unavailable_error(struct kdc_server *kdc,
return NT_STATUS_OK;
}
+typedef enum kdc_process_ret (*kdc_process_fn_t)(struct kdc_server *kdc,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *input,
+ DATA_BLOB *reply,
+ struct tsocket_address *peer_addr,
+ struct tsocket_address *my_addr,
+ int datagram);
+
+/* hold information about one kdc socket */
+struct kdc_socket {
+ struct kdc_server *kdc;
+ struct tsocket_address *local_address;
+ kdc_process_fn_t process;
+};
+
+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);
@@ -143,6 +182,7 @@ static enum kdc_process_ret kdc_process(struct kdc_server *kdc,
return KDC_PROCESS_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)
@@ -202,14 +242,94 @@ static void kdc_tcp_call_loop(struct tevent_req *subreq)
}
if (ret == KDC_PROCESS_PROXY) {
+ 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;
}
- kdc_tcp_proxy(kdc_conn->kdc_socket->kdc, kdc_conn, call,
- tsocket_address_inet_port(kdc_conn->conn->local_address));
- goto done;
+ 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 */
@@ -232,7 +352,6 @@ static void kdc_tcp_call_loop(struct tevent_req *subreq)
}
tevent_req_set_callback(subreq, kdc_tcp_call_writev_done, call);
-done:
/*
* The krb5 tcp pdu's has the length as 4 byte (initial_read_size),
* packet_full_request_u32 provides the pdu length then.