param: Change from _lp to lp__ as the prefix for internal parameter wrappers
[kai/samba.git] / source3 / smbd / server.c
index f351b995018de95154dd79172d565662e5054acb..16c2d28a26678a11b8505da1422ae8c5f862dd69 100644 (file)
@@ -87,23 +87,20 @@ extern int dcelogin_atmost_once;
  What to do when smb.conf is updated.
  ********************************************************************/
 
-static void smb_conf_updated(struct messaging_context *msg,
-                            void *private_data,
-                            uint32_t msg_type,
-                            struct server_id server_id,
-                            DATA_BLOB *data)
+static void smbd_parent_conf_updated(struct messaging_context *msg,
+                                    void *private_data,
+                                    uint32_t msg_type,
+                                    struct server_id server_id,
+                                    DATA_BLOB *data)
 {
        struct tevent_context *ev_ctx =
                talloc_get_type_abort(private_data, struct tevent_context);
-       struct smbd_server_connection *sconn = msg_ctx_to_sconn(msg);
 
-       DEBUG(10,("smb_conf_updated: Got message saying smb.conf was "
+       DEBUG(10,("smbd_parent_conf_updated: Got message saying smb.conf was "
                  "updated. Reloading.\n"));
        change_to_root_user();
-       reload_services(msg, sconn->sock, False);
-       if (am_parent) {
-               printing_subsystem_update(ev_ctx, msg, false);
-       }
+       reload_services(NULL, NULL, false);
+       printing_subsystem_update(ev_ctx, msg, false);
 }
 
 /*******************************************************************
@@ -187,7 +184,7 @@ static void msg_inject_fault(struct messaging_context *msg,
                  procid_str_static(&src), sig));
 #endif
 
-       kill(sys_getpid(), sig);
+       kill(getpid(), sig);
 }
 #endif /* DEVELOPER */
 
@@ -230,6 +227,57 @@ static void smbd_msg_debug(struct messaging_context *msg_ctx,
        messaging_send_to_children(msg_ctx, MSG_DEBUG, data);
 }
 
+static void smbd_parent_id_cache_kill(struct messaging_context *msg_ctx,
+                                     void *private_data,
+                                     uint32_t msg_type,
+                                     struct server_id server_id,
+                                     DATA_BLOB* data)
+{
+       const char *msg = (data && data->data)
+               ? (const char *)data->data : "<NULL>";
+       struct id_cache_ref id;
+
+       if (!id_cache_ref_parse(msg, &id)) {
+               DEBUG(0, ("Invalid ?ID: %s\n", msg));
+               return;
+       }
+
+       id_cache_delete_from_cache(&id);
+
+       messaging_send_to_children(msg_ctx, msg_type, data);
+}
+
+static void smbd_parent_id_cache_flush(struct messaging_context *ctx,
+                                      void* data,
+                                      uint32_t msg_type,
+                                      struct server_id srv_id,
+                                      DATA_BLOB* msg_data)
+{
+       id_cache_flush_message(ctx, data, msg_type, srv_id, msg_data);
+
+       messaging_send_to_children(ctx, msg_type, msg_data);
+}
+
+static void smbd_parent_id_cache_delete(struct messaging_context *ctx,
+                                       void* data,
+                                       uint32_t msg_type,
+                                       struct server_id srv_id,
+                                       DATA_BLOB* msg_data)
+{
+       id_cache_delete_message(ctx, data, msg_type, srv_id, msg_data);
+
+       messaging_send_to_children(ctx, msg_type, msg_data);
+}
+
+static void smb_parent_force_tdis(struct messaging_context *ctx,
+                                 void* data,
+                                 uint32_t msg_type,
+                                 struct server_id srv_id,
+                                 DATA_BLOB* msg_data)
+{
+       messaging_send_to_children(ctx, msg_type, msg_data);
+}
+
 static void add_child_pid(struct smbd_parent_context *parent,
                          pid_t pid)
 {
@@ -418,6 +466,7 @@ static void smbd_accept_connection(struct tevent_context *ev,
        }
 
        if (s->parent->interactive) {
+               reinit_after_fork(msg_ctx, sconn->ev_ctx, true);
                smbd_process(ev, sconn);
                exit_server_cleanly("end of interactive mode");
                return;
@@ -433,9 +482,9 @@ static void smbd_accept_connection(struct tevent_context *ev,
         * Generate a unique id in the parent process so that we use
         * the global random state in the parent.
         */
-       generate_random_buffer((uint8_t *)&unique_id, sizeof(unique_id));
+       unique_id = serverid_get_random_unique_id();
 
-       pid = sys_fork();
+       pid = fork();
        if (pid == 0) {
                NTSTATUS status = NT_STATUS_OK;
 
@@ -455,12 +504,6 @@ static void smbd_accept_connection(struct tevent_context *ev,
                 * them, counting worker smbds. */
                CatchChild();
 
-               /* close our standard file
-                  descriptors */
-               if (!debug_get_output_is_stdout()) {
-                       close_low_fds(False); /* Don't close stderr */
-               }
-
                status = reinit_after_fork(msg_ctx,
                                           ev,
                                           true);
@@ -502,7 +545,7 @@ static void smbd_accept_connection(struct tevent_context *ev,
        }
 
        if (pid < 0) {
-               DEBUG(0,("smbd_accept_connection: sys_fork() failed: %s\n",
+               DEBUG(0,("smbd_accept_connection: fork() failed: %s\n",
                         strerror(errno)));
        }
 
@@ -759,15 +802,23 @@ static bool open_sockets_smbd(struct smbd_parent_context *parent,
 
        messaging_register(msg_ctx, NULL, MSG_SHUTDOWN, msg_exit_server);
        messaging_register(msg_ctx, ev_ctx, MSG_SMB_CONF_UPDATED,
-                          smb_conf_updated);
+                          smbd_parent_conf_updated);
        messaging_register(msg_ctx, NULL, MSG_SMB_STAT_CACHE_DELETE,
                           smb_stat_cache_delete);
        messaging_register(msg_ctx, NULL, MSG_DEBUG, smbd_msg_debug);
        messaging_register(msg_ctx, ev_ctx, MSG_PRINTER_PCAP,
                           smb_pcap_updated);
-       brl_register_msgs(msg_ctx);
-
-       msg_idmap_register_msg(msg_ctx);
+       messaging_register(msg_ctx, NULL, MSG_SMB_BRL_VALIDATE,
+                          brl_revalidate);
+       messaging_register(msg_ctx, NULL, MSG_SMB_FORCE_TDIS,
+                          smb_parent_force_tdis);
+
+       messaging_register(msg_ctx, NULL,
+                          ID_CACHE_FLUSH, smbd_parent_id_cache_flush);
+       messaging_register(msg_ctx, NULL,
+                          ID_CACHE_DELETE, smbd_parent_id_cache_delete);
+       messaging_register(msg_ctx, NULL,
+                          ID_CACHE_KILL, smbd_parent_id_cache_kill);
 
 #ifdef CLUSTER_SUPPORT
        if (lp_clustering()) {
@@ -800,6 +851,23 @@ static bool open_sockets_smbd(struct smbd_parent_context *parent,
        return true;
 }
 
+
+/*
+  handle stdin becoming readable when we are in --foreground mode
+ */
+static void smbd_stdin_handler(struct tevent_context *ev,
+                              struct tevent_fd *fde,
+                              uint16_t flags,
+                              void *private_data)
+{
+       char c;
+       if (read(0, &c, 1) != 1) {
+               /* we have reached EOF on stdin, which means the
+                  parent has exited. Shutdown the server */
+               exit_server_cleanly("EOF on stdin");
+       }
+}
+
 static void smbd_parent_loop(struct tevent_context *ev_ctx,
                             struct smbd_parent_context *parent)
 {
@@ -865,7 +933,7 @@ static void smbd_parent_sig_hup_handler(struct tevent_context *ev,
 
        change_to_root_user();
        DEBUG(1,("parent: Reloading services after SIGHUP\n"));
-       reload_services(parent->msg_ctx, -1, false);
+       reload_services(NULL, NULL, false);
 
        printing_subsystem_update(parent->ev_ctx, parent->msg_ctx, true);
 }
@@ -917,10 +985,10 @@ extern void build_options(bool screen);
        struct smbd_parent_context *parent = NULL;
        TALLOC_CTX *frame;
        NTSTATUS status;
-       uint64_t unique_id;
        struct tevent_context *ev_ctx;
        struct messaging_context *msg_ctx;
        struct tevent_signal *se;
+       char *np_dir = NULL;
 
        /*
         * Do this before any other talloc operation
@@ -1093,7 +1161,7 @@ extern void build_options(bool screen);
         * Reloading of the printers will not work here as we don't have a
         * server info and rpc services set up. It will be called later.
         */
-       if (!reload_services(NULL, -1, False)) {
+       if (!reload_services(NULL, NULL, false)) {
                exit(1);
        }
 
@@ -1135,8 +1203,7 @@ extern void build_options(bool screen);
                become_daemon(Fork, no_process_group, log_stdout);
        }
 
-        generate_random_buffer((uint8_t *)&unique_id, sizeof(unique_id));
-        set_my_unique_id(unique_id);
+        set_my_unique_id(serverid_get_random_unique_id());
 
 #if HAVE_SETPGID
        /*
@@ -1150,6 +1217,9 @@ extern void build_options(bool screen);
        if (!directory_exist(lp_lockdir()))
                mkdir(lp_lockdir(), 0755);
 
+       if (!directory_exist(lp_piddir()))
+               mkdir(lp_piddir(), 0755);
+
        if (is_daemon)
                pidfile_create("smbd");
 
@@ -1161,6 +1231,19 @@ extern void build_options(bool screen);
                exit(1);
        }
 
+       if (!interactive) {
+               /*
+                * Do not initialize the parent-child-pipe before becoming a
+                * daemon: this is used to detect a died parent in the child
+                * process.
+                */
+               status = init_before_fork();
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(0, ("init_before_fork failed: %s\n", nt_errstr(status)));
+                       exit(1);
+               }
+       }
+
        smbd_server_conn->msg_ctx = msg_ctx;
 
        parent = talloc_zero(ev_ctx, struct smbd_parent_context);
@@ -1282,16 +1365,24 @@ extern void build_options(bool screen);
                return -1;
        }
 
+       np_dir = talloc_asprintf(talloc_tos(), "%s/np", lp_ncalrpc_dir());
+       if (!np_dir) {
+               DEBUG(0, ("%s: Out of memory\n", __location__));
+               return -1;
+       }
+
+       if (!directory_create_or_exist(np_dir, geteuid(), 0700)) {
+               DEBUG(0, ("Failed to create pipe directory %s - %s\n",
+                         np_dir, strerror(errno)));
+               return -1;
+       }
+
        if (is_daemon && !interactive) {
                if (rpc_epmapper_daemon() == RPC_DAEMON_FORK) {
                        start_epmd(ev_ctx, msg_ctx);
                }
        }
 
-       if (!dcesrv_ep_setup(ev_ctx, msg_ctx)) {
-               exit(1);
-       }
-
        /* only start other daemons if we are running as a daemon
         * -- bad things will happen if smbd is launched via inetd
         *  and we fork a copy of ourselves here */
@@ -1301,7 +1392,7 @@ extern void build_options(bool screen);
                        start_lsasd(ev_ctx, msg_ctx);
                }
 
-               if (!_lp_disable_spoolss() &&
+               if (!lp__disable_spoolss() &&
                    (rpc_spoolss_daemon() != RPC_DAEMON_DISABLED)) {
                        bool bgq = lp_parm_bool(-1, "smbd", "backgroundqueue", true);
 
@@ -1309,13 +1400,17 @@ extern void build_options(bool screen);
                                exit(1);
                        }
                }
-       } else if (!_lp_disable_spoolss() &&
+       } else if (!lp__disable_spoolss() &&
                   (rpc_spoolss_daemon() != RPC_DAEMON_DISABLED)) {
                if (!printing_subsystem_init(ev_ctx, msg_ctx, false, false)) {
                        exit(1);
                }
        }
 
+       if (!dcesrv_ep_setup(ev_ctx, msg_ctx)) {
+               exit(1);
+       }
+
        if (!is_daemon) {
                /* inetd mode */
                TALLOC_FREE(frame);
@@ -1325,10 +1420,8 @@ extern void build_options(bool screen);
                   goes away */
                smbd_server_conn->sock = dup(0);
 
-               /* close our standard file descriptors */
-               if (!debug_get_output_is_stdout()) {
-                       close_low_fds(False); /* Don't close stderr */
-               }
+               /* close stdin, stdout (if not logging to it), but not stderr */
+               close_low_fds(true, !debug_get_output_is_stdout(), false);
 
 #ifdef HAVE_ATEXIT
                atexit(killkids);
@@ -1354,6 +1447,14 @@ extern void build_options(bool screen);
        /* make sure we always have a valid stackframe */
        frame = talloc_stackframe();
 
+       if (!Fork) {
+               /* if we are running in the foreground then look for
+                  EOF on stdin, and exit if it happens. This allows
+                  us to die if the parent process dies
+               */
+               tevent_add_fd(ev_ctx, parent, 0, TEVENT_FD_READ, smbd_stdin_handler, NULL);
+       }
+
        smbd_parent_loop(ev_ctx, parent);
 
        exit_server_cleanly(NULL);