Rework service init functions to pass down service name. This is
[ira/wip.git] / source / winbind / wb_server.c
index 121aeb5a3a86f412dd4f74abb5299236eb6626eb..9acde4a557cb31bfa2a30f5584c7a99c4e9d20fd 100644 (file)
@@ -7,7 +7,7 @@
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #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"
-
-#define WINBINDD_DIR "/tmp/.winbindd/"
-#define WINBINDD_ECHO_SOCKET  WINBINDD_DIR"echo"
-#define WINBINDD_ADDR_PREFIX "127.0.255."
-#define WINBINDD_ECHO_ADDR WINBINDD_ADDR_PREFIX"1"
-#define WINBINDD_ECHO_PORT 55555
-
-/*
-  state of an open winbind connection
-*/
-struct wbserver_connection {
-       DATA_BLOB blob;
-       struct send_queue {
-               struct send_queue *next, *prev;
-               DATA_BLOB blob;
-       } *queue;
-};
-
-
-/*
-  called when we get a new connection
-*/
-static void winbind_accept(struct stream_connection *conn)
+#include "nsswitch/winbind_nss_config.h"
+#include "winbind/wb_server.h"
+#include "lib/stream/packet.h"
+#include "smbd/service.h"
+#include "param/secrets.h"
+#include "param/param.h"
+
+void wbsrv_terminate_connection(struct wbsrv_connection *wbconn, const char *reason)
 {
-       struct wbserver_connection *wbconn;
-
-       wbconn = talloc_zero(conn, struct wbserver_connection);
-       wbconn->blob = data_blob_talloc(wbconn, NULL, 1024);
-       
-       conn->private = wbconn;
+       stream_terminate_connection(wbconn->conn, reason);
 }
 
 /*
-  receive some data on a winbind connection
+  called on a tcp recv error
 */
-static void winbind_recv(struct stream_connection *conn, uint16_t flags)
+static void wbsrv_recv_error(void *private, NTSTATUS status)
 {
-       struct wbserver_connection *wbconn = talloc_get_type(conn->private, struct wbserver_connection);
-       NTSTATUS status;
-       size_t nread;
-       struct send_queue *q;
+       struct wbsrv_connection *wbconn = talloc_get_type(private, struct wbsrv_connection);
+       wbsrv_terminate_connection(wbconn, nt_errstr(status));
+}
 
-       status = socket_recv(conn->socket, wbconn->blob.data, wbconn->blob.length, &nread, 0);
-       if (NT_STATUS_IS_ERR(status)) {
-               DEBUG(10,("socket_recv: %s\n",nt_errstr(status)));
-               stream_terminate_connection(conn, "socket_recv: failed\n");
-               return;
-       }
+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_connection *wbconn;
 
-       /* just reflect the data back down the socket */
-       q = talloc(wbconn, struct send_queue);
-       if (q == NULL) {
-               stream_terminate_connection(conn, "winbind_recv: out of memory\n");
+       wbconn = talloc_zero(conn, struct wbsrv_connection);
+       if (!wbconn) {
+               stream_terminate_connection(conn, "wbsrv_accept: out of memory");
                return;
        }
-
-       q->blob = data_blob_talloc(q, wbconn->blob.data, nread);
-       if (q->blob.data == NULL) {
-               stream_terminate_connection(conn, "winbind_recv: out of memory\n");
+       wbconn->conn          = conn;
+       wbconn->listen_socket = listen_socket;
+       wbconn->lp_ctx        = listen_socket->service->task->lp_ctx;
+       conn->private         = wbconn;
+
+       wbconn->packet = packet_init(wbconn);
+       if (wbconn->packet == NULL) {
+               wbsrv_terminate_connection(wbconn, "wbsrv_accept: out of memory");
                return;
        }
+       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);
+}
 
-       DLIST_ADD_END(wbconn->queue, q, struct send_queue *);
+/*
+  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);
+       packet_recv(wbconn->packet);
 
-       EVENT_FD_WRITEABLE(conn->event.fde);
 }
 
 /*
   called when we can write to a connection
 */
-static void winbind_send(struct stream_connection *conn, uint16_t flags)
+static void wbsrv_send(struct stream_connection *conn, uint16_t flags)
 {
-       struct wbserver_connection *wbconn = talloc_get_type(conn->private, struct wbserver_connection);
-
-       while (wbconn->queue) {
-               struct send_queue *q = wbconn->queue;
-               NTSTATUS status;
-               size_t sendlen;
-
-               status = socket_send(conn->socket, &q->blob, &sendlen, 0);
-               if (NT_STATUS_IS_ERR(status)) {
-                       DEBUG(10,("socket_send() %s\n",nt_errstr(status)));
-                       stream_terminate_connection(conn, "socket_send: failed\n");
-                       return;
-               }
-               if (!NT_STATUS_IS_OK(status)) {
-                       return;
-               }
-
-               q->blob.length -= sendlen;
-               q->blob.data   += sendlen;
-
-               if (q->blob.length == 0) {
-                       DLIST_REMOVE(wbconn->queue, q);
-                       talloc_free(q);
-               }
-       }
-
-       EVENT_FD_NOT_WRITEABLE(conn->event.fde);
+       struct wbsrv_connection *wbconn = talloc_get_type(conn->private, 
+                                                         struct wbsrv_connection);
+       packet_queue_run(wbconn->packet);
 }
 
-static const struct stream_server_ops winbind_stream_ops = {
-       .name                   = "winbind_echo",
-       .accept_connection      = winbind_accept,
-       .recv_handler           = winbind_recv,
-       .send_handler           = winbind_send,
+static const struct stream_server_ops wbsrv_ops = {
+       .name                   = "winbind samba3 protocol",
+       .accept_connection      = wbsrv_accept,
+       .recv_handler           = wbsrv_recv,
+       .send_handler           = wbsrv_send
 };
 
 /*
@@ -144,48 +114,102 @@ static void winbind_task_init(struct task_server *task)
        uint16_t port = 1;
        const struct model_ops *model_ops;
        NTSTATUS status;
+       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. */
        model_ops = process_model_byname("single");
        if (!model_ops) {
-               task_terminate(task, "Can't find 'single' process model_ops");
+               task_server_terminate(task,
+                                     "Can't find 'single' process model_ops");
                return;
        }
 
-       /* Make sure the directory for NCALRPC exists */
-       if (!directory_exist(WINBINDD_DIR)) {
-               mkdir(WINBINDD_DIR, 0755);
-       }
-
-       status = stream_setup_socket(task->event_ctx, model_ops, &winbind_stream_ops, 
-                                    "unix", WINBINDD_ECHO_SOCKET, &port, NULL);
-       if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(0,("service_setup_stream_socket(path=%s) failed - %s\n",
-                        WINBINDD_ECHO_SOCKET, nt_errstr(status)));
-               task_terminate(task, "winbind Failed to find to ECHO unix socket");
+       /* Make sure the directory for the Samba3 socket exists, and is of the correct permissions */
+       if (!directory_create_or_exist(lp_winbindd_socket_directory(task->lp_ctx), geteuid(), 0755)) {
+               task_server_terminate(task,
+                                     "Cannot create winbindd pipe directory");
                return;
        }
 
-       port = WINBINDD_ECHO_PORT;
+       service = talloc_zero(task, struct wbsrv_service);
+       if (!service) goto nomem;
+       service->task   = task;
 
-       status = stream_setup_socket(task->event_ctx, model_ops, &winbind_stream_ops,
-                                    "ipv4", WINBINDD_ECHO_ADDR, &port, NULL);
-       if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(0,("service_setup_stream_socket(address=%s,port=%u) failed - %s\n",
-                        WINBINDD_ECHO_ADDR, port, nt_errstr(status)));
-               task_terminate(task, "winbind Failed to find to ECHO tcp socket");
+       service->primary_sid = secrets_get_domain_sid(service,
+                                                     task->lp_ctx,
+                                                     lp_workgroup(task->lp_ctx));
+       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      = talloc_asprintf(listen_socket, "%s/%s", 
+                                                         lp_winbindd_socket_directory(task->lp_ctx), 
+                                                         WINBINDD_SAMBA3_SOCKET);
+       if (!listen_socket->socket_path) goto nomem;
+       listen_socket->service          = service;
+       listen_socket->privileged       = false;
+       status = stream_setup_socket(task->event_ctx, task->lp_ctx, model_ops,
+                                    &wbsrv_ops, "unix",
+                                    listen_socket->socket_path, &port,
+                                    lp_socket_options(task->lp_ctx), 
+                                    listen_socket);
+       if (!NT_STATUS_IS_OK(status)) goto listen_failed;
+
+       /* setup the privileged samba3 socket */
+       listen_socket = talloc(service, struct wbsrv_listen_socket);
+       if (!listen_socket) goto nomem;
+       listen_socket->socket_path      =
+               smbd_tmp_path(listen_socket, task->lp_ctx, 
+                             WINBINDD_SAMBA3_PRIVILEGED_SOCKET);
+       if (!listen_socket->socket_path) goto nomem;
+       listen_socket->service          = service;
+       listen_socket->privileged       = true;
+       status = stream_setup_socket(task->event_ctx, task->lp_ctx, model_ops,
+                                    &wbsrv_ops, "unix",
+                                    listen_socket->socket_path, &port,
+                                    lp_socket_options(task->lp_ctx), 
+                                    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:
+       DEBUG(0,("stream_setup_socket(path=%s) failed - %s\n",
+                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;
 }
 
 /*
   initialise the winbind server
  */
-static NTSTATUS winbind_init(struct event_context *event_ctx, const struct model_ops *model_ops)
+static NTSTATUS winbind_init(struct event_context *event_ctx,
+                            struct loadparm_context *lp_ctx,
+                            const struct model_ops *model_ops)
 {
-       return task_server_startup(event_ctx, model_ops, winbind_task_init);
+       return task_server_startup(event_ctx, lp_ctx, "winbind",
+                                  model_ops, winbind_task_init);
 }
 
 /*