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); }
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"); }
/* 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 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_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; enum kdc_process_ret 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_PROCESS_FAILED) { kdc_tcp_terminate_connection(kdc_conn, "kdc_tcp_call_loop: process function failed"); return; } 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; } 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); }
/* called when we get a new connection */ static void kdc_tcp_accept(struct stream_connection *conn) { struct kdc_socket *kdc_socket = talloc_get_type(conn->private_data, struct kdc_socket); struct kdc_tcp_connection *kdcconn; struct socket_address *src_addr; struct socket_address *my_addr; int ret; kdcconn = talloc_zero(conn, struct kdc_tcp_connection); if (!kdcconn) { stream_terminate_connection(conn, "kdc_tcp_accept: out of memory"); return; } kdcconn->conn = conn; kdcconn->kdc_socket = kdc_socket; conn->private_data = kdcconn; src_addr = socket_get_peer_addr(kdcconn->conn->socket, kdcconn); if (!src_addr) { kdc_tcp_terminate_connection(kdcconn, "kdc_tcp_accept: out of memory"); return; } my_addr = socket_get_my_addr(kdcconn->conn->socket, kdcconn); if (!my_addr) { kdc_tcp_terminate_connection(kdcconn, "kdc_tcp_accept: out of memory"); return; } ret = tsocket_address_bsd_from_sockaddr(kdcconn, src_addr->sockaddr, src_addr->sockaddrlen, &kdcconn->remote_address); if (ret < 0) { kdc_tcp_terminate_connection(kdcconn, "kdc_tcp_accept: out of memory"); return; } ret = tsocket_address_bsd_from_sockaddr(kdcconn, my_addr->sockaddr, my_addr->sockaddrlen, &kdcconn->local_address); if (ret < 0) { kdc_tcp_terminate_connection(kdcconn, "kdc_tcp_accept: out of memory"); return; } TALLOC_FREE(src_addr); TALLOC_FREE(my_addr); kdcconn->packet = packet_init(kdcconn); if (kdcconn->packet == NULL) { kdc_tcp_terminate_connection(kdcconn, "kdc_tcp_accept: out of memory"); return; } packet_set_private(kdcconn->packet, kdcconn); packet_set_socket(kdcconn->packet, conn->socket); packet_set_callback(kdcconn->packet, kdc_tcp_recv); packet_set_full_request(kdcconn->packet, packet_full_request_u32); packet_set_error_handler(kdcconn->packet, kdc_tcp_recv_error); packet_set_event_context(kdcconn->packet, conn->event.ctx); packet_set_fde(kdcconn->packet, conn->event.fde); packet_set_serialise(kdcconn->packet); }
/* called on a tcp recv error */ static void kdc_tcp_recv_error(void *private_data, NTSTATUS status) { struct kdc_tcp_connection *kdcconn = talloc_get_type(private_data, struct kdc_tcp_connection); kdc_tcp_terminate_connection(kdcconn, nt_errstr(status)); }