r17930: Merge noinclude branch:
[ira/wip.git] / source / winbind / wb_server.c
index 3959153b05527657e777146ad18ac494dd9c46cc..4c6ff397c1cca16b1e0972b527842b636cfb467a 100644 (file)
 
 #include "includes.h"
 #include "lib/socket/socket.h"
-#include "system/dir.h"
-#include "system/filesys.h"
-#include "dlinklist.h"
+#include "lib/util/dlinklist.h"
 #include "lib/events/events.h"
 #include "smbd/service_task.h"
+#include "smbd/process_model.h"
 #include "smbd/service_stream.h"
 #include "nsswitch/winbind_nss_config.h"
-#include "nsswitch/winbindd_nss.h"
 #include "winbind/wb_server.h"
+#include "lib/stream/packet.h"
+#include "smbd/service.h"
+#include "passdb/secrets.h"
 
 void wbsrv_terminate_connection(struct wbsrv_connection *wbconn, const char *reason)
 {
@@ -38,167 +39,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);
+               stream_terminate_connection(conn, "wbsrv_accept: out of memory");
                return;
        }
+       wbconn->conn          = conn;
+       wbconn->listen_socket = listen_socket;
+       conn->private         = wbconn;
 
-       /* 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);
+       wbconn->packet = packet_init(wbconn);
+       if (wbconn->packet == NULL) {
+               wbsrv_terminate_connection(wbconn, "wbsrv_accept: out of memory");
                return;
        }
-
-       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) {
-               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);
+       struct wbsrv_connection *wbconn = talloc_get_type(conn->private, 
+                                                         struct wbsrv_connection);
+       packet_recv(wbconn->packet);
 
-       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);
-
-       /* the call isn't needed any more */
-       wbconn->pending_calls--;
-       talloc_free(call);
-       return NT_STATUS_OK;
 }
 
 /*
@@ -206,48 +93,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
 */
@@ -259,6 +116,8 @@ static void winbind_task_init(struct task_server *task)
        struct wbsrv_service *service;
        struct wbsrv_listen_socket *listen_socket;
 
+       task_server_set_title(task, "task[winbind]");
+
        /* within the winbind task we want to be a single process, so
           ask for the single process model ops and pass these to the
           stream_setup_socket() call. */
@@ -269,23 +128,34 @@ static void winbind_task_init(struct task_server *task)
                return;
        }
 
-       /* Make sure the directory for NCALRPC exists */
-       if (!directory_exist(WINBINDD_DIR)) {
-               mkdir(WINBINDD_DIR, 0755);
+       /* Make sure the directory for the Samba3 socket exists, and is of the correct permissions */
+       if (!directory_create_or_exist(lp_winbindd_socket_directory(), geteuid(), 0755)) {
+               task_server_terminate(task,
+                                     "Cannot create winbindd pipe directory");
+               return;
        }
 
        service = talloc_zero(task, struct wbsrv_service);
        if (!service) goto nomem;
        service->task   = task;
 
+       service->primary_sid = secrets_get_domain_sid(service,
+                                                     lp_workgroup());
+       if (service->primary_sid == NULL) {
+               task_server_terminate(
+                       task, nt_errstr(NT_STATUS_CANT_ACCESS_DOMAIN_INFO));
+               return;
+       }
+
        /* setup the unprivileged samba3 socket */
        listen_socket = talloc(service, struct wbsrv_listen_socket);
        if (!listen_socket) goto nomem;
-       listen_socket->socket_path      = WINBINDD_SAMBA3_SOCKET;
+       listen_socket->socket_path      = talloc_asprintf(listen_socket, "%s/%s", 
+                                                         lp_winbindd_socket_directory(), 
+                                                         WINBINDD_SAMBA3_SOCKET);
        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,
@@ -301,13 +171,15 @@ 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,
                                     listen_socket);
        if (!NT_STATUS_IS_OK(status)) goto listen_failed;
 
+       status = wbsrv_init_irpc(service);
+       if (!NT_STATUS_IS_OK(status)) goto irpc_failed;
+
        return;
 
 listen_failed:
@@ -315,6 +187,11 @@ listen_failed:
                 listen_socket->socket_path, nt_errstr(status)));
        task_server_terminate(task, nt_errstr(status));
        return;
+irpc_failed:
+       DEBUG(0,("wbsrv_init_irpc() failed - %s\n",
+                nt_errstr(status)));
+       task_server_terminate(task, nt_errstr(status));
+       return;
 nomem:
        task_server_terminate(task, nt_errstr(NT_STATUS_NO_MEMORY));
        return;