diff options
Diffstat (limited to 'source4/winbind/wb_server.c')
-rw-r--r-- | source4/winbind/wb_server.c | 215 |
1 files changed, 35 insertions, 180 deletions
diff --git a/source4/winbind/wb_server.c b/source4/winbind/wb_server.c index 6bd60d209e..a08b080334 100644 --- a/source4/winbind/wb_server.c +++ b/source4/winbind/wb_server.c @@ -28,6 +28,7 @@ #include "smbd/service_stream.h" #include "nsswitch/winbind_nss_config.h" #include "winbind/wb_server.h" +#include "lib/stream/packet.h" void wbsrv_terminate_connection(struct wbsrv_connection *wbconn, const char *reason) { @@ -35,167 +36,53 @@ void wbsrv_terminate_connection(struct wbsrv_connection *wbconn, const char *rea } /* - called when we get a new connection + called on a tcp recv error */ +static void wbsrv_recv_error(void *private, NTSTATUS status) +{ + struct wbsrv_connection *wbconn = talloc_get_type(private, struct wbsrv_connection); + wbsrv_terminate_connection(wbconn, nt_errstr(status)); +} + static void wbsrv_accept(struct stream_connection *conn) { - struct wbsrv_listen_socket *listen_socket = - talloc_get_type(conn->private, struct wbsrv_listen_socket); + struct wbsrv_listen_socket *listen_socket = talloc_get_type(conn->private, + struct wbsrv_listen_socket); struct wbsrv_connection *wbconn; wbconn = talloc_zero(conn, struct wbsrv_connection); if (!wbconn) { - stream_terminate_connection(conn, - "wbsrv_accept: out of memory"); - return; - } - wbconn->conn = conn; - wbconn->listen_socket = listen_socket; - conn->private = wbconn; -} - -/* - receive some data on a winbind connection -*/ -static void wbsrv_recv(struct stream_connection *conn, uint16_t flags) -{ - struct wbsrv_connection *wbconn = - talloc_get_type(conn->private, struct wbsrv_connection); - const struct wbsrv_protocol_ops *ops = wbconn->listen_socket->ops; - struct wbsrv_call *call; - NTSTATUS status = NT_STATUS_UNSUCCESSFUL; - size_t nread; - - /* avoid recursion, because of half async code */ - if (wbconn->processing) { - EVENT_FD_NOT_READABLE(conn->event.fde); - return; - } - - /* if the used protocol doesn't support pending requests disallow - * them */ - if (wbconn->pending_calls && !ops->allow_pending_calls) { - EVENT_FD_NOT_READABLE(conn->event.fde); + stream_terminate_connection(conn, "wbsrv_accept: out of memory"); return; } + wbconn->conn = conn; + wbconn->listen_socket = listen_socket; + conn->private = wbconn; - if (wbconn->partial.length == 0) { - wbconn->partial = data_blob_talloc(wbconn, NULL, 4); - if (!wbconn->partial.data) goto nomem; - - wbconn->partial_read = 0; - } - - /* read in the packet length */ - if (wbconn->partial_read < 4) { - uint32_t packet_length; - - status = socket_recv(conn->socket, - wbconn->partial.data+wbconn->partial_read, - 4 - wbconn->partial_read, - &nread, 0); - if (NT_STATUS_IS_ERR(status)) goto failed; - if (!NT_STATUS_IS_OK(status)) return; - - wbconn->partial_read += nread; - if (wbconn->partial_read != 4) return; - - packet_length = ops->packet_length(wbconn->partial); - - wbconn->partial.data = - talloc_realloc(wbconn, wbconn->partial.data, uint8_t, - packet_length); - if (!wbconn->partial.data) goto nomem; - - wbconn->partial.length = packet_length; - } - - /* read in the body */ - status = socket_recv(conn->socket, - wbconn->partial.data + wbconn->partial_read, - wbconn->partial.length - wbconn->partial_read, - &nread, 0); - if (NT_STATUS_IS_ERR(status)) goto failed; - if (!NT_STATUS_IS_OK(status)) return; - - wbconn->partial_read += nread; - if (wbconn->partial_read != wbconn->partial.length) return; - - /* we have a full request - parse it */ - status = ops->pull_request(wbconn->partial, wbconn, &call); - if (!NT_STATUS_IS_OK(status)) goto failed; - call->wbconn = wbconn; - call->event_ctx = conn->event.ctx; - - /* - * we have parsed the request, so we can reset the - * wbconn->partial_read, maybe we could also free wbconn->partial, but - * for now we keep it, and overwrite it the next time - */ - wbconn->partial_read = 0; - - /* actually process the request */ - wbconn->pending_calls++; - wbconn->processing = True; - status = ops->handle_call(call); - wbconn->processing = False; - if (!NT_STATUS_IS_OK(status)) goto failed; - - /* if the backend want to reply later just return here */ - if (call->flags & WBSRV_CALL_FLAGS_REPLY_ASYNC) { + wbconn->packet = packet_init(wbconn); + if (wbconn->packet == NULL) { + wbsrv_terminate_connection(wbconn, "wbsrv_accept: out of memory"); return; } - - /* - * and queue the reply, this implies talloc_free(call), - * and set the socket to readable again - */ - status = wbsrv_send_reply(call); - if (!NT_STATUS_IS_OK(status)) goto failed; - - return; -nomem: - status = NT_STATUS_NO_MEMORY; -failed: - wbsrv_terminate_connection(wbconn, nt_errstr(status)); + packet_set_private(wbconn->packet, wbconn); + packet_set_socket(wbconn->packet, conn->socket); + packet_set_callback(wbconn->packet, wbsrv_samba3_process); + packet_set_full_request(wbconn->packet, wbsrv_samba3_packet_full_request); + packet_set_error_handler(wbconn->packet, wbsrv_recv_error); + packet_set_event_context(wbconn->packet, conn->event.ctx); + packet_set_fde(wbconn->packet, conn->event.fde); + packet_set_serialise(wbconn->packet); } /* - * queue a wbsrv_call reply on a wbsrv_connection - * NOTE: that this implies talloc_free(call), - * use talloc_reference(call) if you need it after - * calling wbsrv_queue_reply - * NOTE: if this function desn't return NT_STATUS_OK, - * the caller needs to call - * wbsrv_terminate_connection(call->wbconn, "reason..."); - * return; - * to drop the connection - */ -NTSTATUS wbsrv_send_reply(struct wbsrv_call *call) + receive some data on a winbind connection +*/ +static void wbsrv_recv(struct stream_connection *conn, uint16_t flags) { - struct wbsrv_connection *wbconn = call->wbconn; - const struct wbsrv_protocol_ops *ops = wbconn->listen_socket->ops; - struct data_blob_list_item *rep; - NTSTATUS status; - - /* and now encode the reply */ - rep = talloc(wbconn, struct data_blob_list_item); - NT_STATUS_HAVE_NO_MEMORY(rep); - - status = ops->push_reply(call, rep, &rep->blob); - NT_STATUS_NOT_OK_RETURN(status); - - if (!wbconn->send_queue) { - EVENT_FD_WRITEABLE(wbconn->conn->event.fde); - } - DLIST_ADD_END(wbconn->send_queue, rep, struct data_blob_list_item *); - - EVENT_FD_READABLE(wbconn->conn->event.fde); + struct wbsrv_connection *wbconn = talloc_get_type(conn->private, + struct wbsrv_connection); + packet_recv(wbconn->packet); - /* the call isn't needed any more */ - wbconn->pending_calls--; - talloc_free(call); - return NT_STATUS_OK; } /* @@ -203,48 +90,18 @@ NTSTATUS wbsrv_send_reply(struct wbsrv_call *call) */ static void wbsrv_send(struct stream_connection *conn, uint16_t flags) { - struct wbsrv_connection *wbconn = talloc_get_type(conn->private, struct wbsrv_connection); - NTSTATUS status; - - while (wbconn->send_queue) { - struct data_blob_list_item *q = wbconn->send_queue; - size_t sendlen; - - status = socket_send(conn->socket, &q->blob, &sendlen, 0); - if (NT_STATUS_IS_ERR(status)) goto failed; - if (!NT_STATUS_IS_OK(status)) return; - - q->blob.length -= sendlen; - q->blob.data += sendlen; - - if (q->blob.length == 0) { - DLIST_REMOVE(wbconn->send_queue, q); - talloc_free(q); - } - } - - EVENT_FD_NOT_WRITEABLE(conn->event.fde); - return; -failed: - wbsrv_terminate_connection(wbconn, nt_errstr(status)); + struct wbsrv_connection *wbconn = talloc_get_type(conn->private, + struct wbsrv_connection); + packet_queue_run(wbconn->packet); } static const struct stream_server_ops wbsrv_ops = { - .name = "winbind", + .name = "winbind samba3 protocol", .accept_connection = wbsrv_accept, .recv_handler = wbsrv_recv, .send_handler = wbsrv_send }; -static const struct wbsrv_protocol_ops wbsrv_samba3_protocol_ops = { - .name = "winbind samba3 protocol", - .allow_pending_calls = False, - .packet_length = wbsrv_samba3_packet_length, - .pull_request = wbsrv_samba3_pull_request, - .handle_call = wbsrv_samba3_handle_call, - .push_reply = wbsrv_samba3_push_reply -}; - /* startup the winbind task */ @@ -290,7 +147,6 @@ static void winbind_task_init(struct task_server *task) if (!listen_socket->socket_path) goto nomem; listen_socket->service = service; listen_socket->privileged = False; - listen_socket->ops = &wbsrv_samba3_protocol_ops; status = stream_setup_socket(task->event_ctx, model_ops, &wbsrv_ops, "unix", listen_socket->socket_path, &port, @@ -306,7 +162,6 @@ static void winbind_task_init(struct task_server *task) if (!listen_socket->socket_path) goto nomem; listen_socket->service = service; listen_socket->privileged = True; - listen_socket->ops = &wbsrv_samba3_protocol_ops; status = stream_setup_socket(task->event_ctx, model_ops, &wbsrv_ops, "unix", listen_socket->socket_path, &port, |