r26402: Require a talloc context in libnetif.
[jelmer/samba4-debian.git] / source / smb_server / smb_server.c
index 469f9372192813793474369d269c4e82af86d5a1..bc17d100c5511c96383c11e3aedf1533b0c8952c 100644 (file)
@@ -6,7 +6,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 "smbd/service_task.h"
 #include "smbd/service_stream.h"
+#include "smbd/service.h"
 #include "smb_server/smb_server.h"
+#include "smb_server/service_smb_proto.h"
 #include "lib/messaging/irpc.h"
 #include "lib/stream/packet.h"
 #include "libcli/smb2/smb2.h"
 #include "smb_server/smb2/smb2_server.h"
 #include "system/network.h"
-#include "netif/netif.h"
+#include "lib/socket/netif.h"
+#include "param/share.h"
+#include "dsdb/samdb/samdb.h"
+#include "param/param.h"
 
 static NTSTATUS smbsrv_recv_generic_request(void *private, DATA_BLOB blob)
 {
@@ -37,7 +42,7 @@ static NTSTATUS smbsrv_recv_generic_request(void *private, DATA_BLOB blob)
 
        /* see if its a special NBT packet */
        if (CVAL(blob.data,0) != 0) {
-               status = smbsrv_init_smb_connection(smb_conn);
+               status = smbsrv_init_smb_connection(smb_conn, smb_conn->lp_ctx);
                NT_STATUS_NOT_OK_RETURN(status);
                packet_set_callback(smb_conn->packet, smbsrv_recv_smb_request);
                return smbsrv_recv_smb_request(smb_conn, blob);
@@ -53,12 +58,12 @@ static NTSTATUS smbsrv_recv_generic_request(void *private, DATA_BLOB blob)
 
        switch (protocol_version) {
        case SMB_MAGIC:
-               status = smbsrv_init_smb_connection(smb_conn);
+               status = smbsrv_init_smb_connection(smb_conn, smb_conn->lp_ctx);
                NT_STATUS_NOT_OK_RETURN(status);
                packet_set_callback(smb_conn->packet, smbsrv_recv_smb_request);
                return smbsrv_recv_smb_request(smb_conn, blob);
        case SMB2_MAGIC:
-               if (lp_maxprotocol() < PROTOCOL_SMB2) break;
+               if (lp_srv_maxprotocol(smb_conn->lp_ctx) < PROTOCOL_SMB2) break;
                status = smbsrv_init_smb2_connection(smb_conn);
                NT_STATUS_NOT_OK_RETURN(status);
                packet_set_callback(smb_conn->packet, smbsrv_recv_smb2_request);
@@ -89,9 +94,6 @@ static void smbsrv_recv(struct stream_connection *conn, uint16_t flags)
        DEBUG(10,("smbsrv_recv\n"));
 
        packet_recv(smb_conn->packet);
-
-       /* free up temporary memory */
-       lp_talloc_free();
 }
 
 /*
@@ -144,16 +146,25 @@ static void smbsrv_accept(struct stream_connection *conn)
        packet_set_fde(smb_conn->packet, conn->event.fde);
        packet_set_serialise(smb_conn->packet);
 
+       smb_conn->lp_ctx = global_loadparm;
        smb_conn->connection = conn;
        conn->private = smb_conn;
 
        irpc_add_name(conn->msg_ctx, "smb_server");
 
+       smb_conn->statistics.connect_time = timeval_current();
+
        smbsrv_management_init(smb_conn);
+
+       if (!NT_STATUS_IS_OK(share_get_context_by_name(smb_conn, lp_share_backend(smb_conn->lp_ctx), 
+                                                      &(smb_conn->share_context)))) {
+               smbsrv_terminate_connection(smb_conn, "share_init failed!");
+               return;
+       }
 }
 
 static const struct stream_server_ops smb_stream_ops = {
-       .name                   = "smb",
+       .name                   = "smbsrv",
        .accept_connection      = smbsrv_accept,
        .recv_handler           = smbsrv_recv,
        .send_handler           = smbsrv_send,
@@ -162,11 +173,12 @@ static const struct stream_server_ops smb_stream_ops = {
 /*
   setup a listening socket on all the SMB ports for a particular address
 */
-static NTSTATUS smb_add_socket(struct event_context *event_context,
+_PUBLIC_ NTSTATUS smbsrv_add_socket(struct event_context *event_context,
+                                   struct loadparm_context *lp_ctx,
                               const struct model_ops *model_ops,
                               const char *address)
 {
-       const char **ports = lp_smb_ports();
+       const char **ports = lp_smb_ports(lp_ctx);
        int i;
        NTSTATUS status;
 
@@ -174,41 +186,78 @@ static NTSTATUS smb_add_socket(struct event_context *event_context,
                uint16_t port = atoi(ports[i]);
                if (port == 0) continue;
                status = stream_setup_socket(event_context, model_ops, &smb_stream_ops, 
-                                            "ipv4", address, &port, NULL);
+                                            "ipv4", address, &port, 
+                                            lp_socket_options(lp_ctx), 
+                                            NULL);
                NT_STATUS_NOT_OK_RETURN(status);
        }
 
        return NT_STATUS_OK;
 }
 
+
+/*
+  pre-open some of our ldb databases, to prevent an explosion of memory usage
+  when we fork
+ */
+static void smbsrv_preopen_ldb(struct task_server *task)
+{
+       /* yes, this looks strange. It is a hack to preload the
+          schema. I'd like to share most of the ldb context with the
+          child too. That will come later */
+       talloc_free(samdb_connect(task, task->lp_ctx, NULL));
+}
+
 /*
-  called on startup of the smb server service It's job is to start
-  listening on all configured SMB server sockets
+  open the smb server sockets
 */
-static NTSTATUS smbsrv_init(struct event_context *event_context, const struct model_ops *model_ops)
+static void smbsrv_task_init(struct task_server *task)
 {      
        NTSTATUS status;
 
-       if (lp_interfaces() && lp_bind_interfaces_only()) {
-               int num_interfaces = iface_count();
+       task_server_set_title(task, "task[smbsrv]");
+
+       if (lp_interfaces(task->lp_ctx) && lp_bind_interfaces_only(task->lp_ctx)) {
+               int num_interfaces;
                int i;
+               struct interface *ifaces;
+
+               load_interfaces(task, lp_interfaces(task->lp_ctx), &ifaces);
+
+               num_interfaces = iface_count(ifaces);
 
                /* We have been given an interfaces line, and been 
                   told to only bind to those interfaces. Create a
                   socket per interface and bind to only these.
                */
                for(i = 0; i < num_interfaces; i++) {
-                       const char *address = iface_n_ip(i);
-                       status = smb_add_socket(event_context, model_ops, address);
-                       NT_STATUS_NOT_OK_RETURN(status);
+                       const char *address = iface_n_ip(ifaces, i);
+                       status = smbsrv_add_socket(task->event_ctx, task->lp_ctx, task->model_ops, address);
+                       if (!NT_STATUS_IS_OK(status)) goto failed;
                }
        } else {
                /* Just bind to lp_socket_address() (usually 0.0.0.0) */
-               status = smb_add_socket(event_context, model_ops, lp_socket_address());
-               NT_STATUS_NOT_OK_RETURN(status);
+               status = smbsrv_add_socket(task->event_ctx, task->lp_ctx, task->model_ops, 
+                                          lp_socket_address(task->lp_ctx));
+               if (!NT_STATUS_IS_OK(status)) goto failed;
        }
 
-       return NT_STATUS_OK;
+       smbsrv_preopen_ldb(task);
+
+       return;
+failed:
+       task_server_terminate(task, "Failed to startup smb server task");       
+}
+
+/*
+  called on startup of the smb server service It's job is to start
+  listening on all configured sockets
+*/
+static NTSTATUS smbsrv_init(struct event_context *event_context, 
+                           struct loadparm_context *lp_ctx,
+                           const struct model_ops *model_ops)
+{      
+       return task_server_startup(event_context, model_ops, smbsrv_task_init);
 }
 
 /* called at smbd startup - register ourselves as a server service */