Merge branch 'v3-2-test' of ssh://git.samba.org/data/git/samba into ctdb-merge
[nivanova/samba-autobuild/.git] / source3 / smbd / server.c
index e89a94599efee951874e113dc3987ad21d2063b7..7116027adfe841502abae99f4d1906d724e789af 100644 (file)
@@ -27,12 +27,6 @@ static_decl_rpc;
 
 static int am_parent = 1;
 
-/* the last message the was processed */
-int last_message = -1;
-
-/* a useful macro to debug the last message processed */
-#define LAST_MESSAGE() smb_fn_name(last_message)
-
 extern struct auth_context *negprot_global_auth_context;
 extern SIG_ATOMIC_T got_sig_term;
 extern SIG_ATOMIC_T reload_after_sighup;
@@ -86,6 +80,19 @@ struct messaging_context *smbd_messaging_context(void)
        return ctx;
 }
 
+struct memcache *smbd_memcache(void)
+{
+       static struct memcache *cache;
+
+       if (!cache
+           && !(cache = memcache_init(NULL,
+                                      lp_max_stat_cache_size()*1024))) {
+
+               smb_panic("Could not init smbd memcache");
+       }
+       return cache;
+}
+
 /*******************************************************************
  What to do when smb.conf is updated.
  ********************************************************************/
@@ -261,10 +268,20 @@ static void add_child_pid(pid_t pid)
        num_children += 1;
 }
 
-static void remove_child_pid(pid_t pid)
+static void remove_child_pid(pid_t pid, bool unclean_shutdown)
 {
        struct child_pid *child;
 
+       if (unclean_shutdown) {
+               /* a child terminated uncleanly so tickle all processes to see 
+                  if they can grab any of the pending locks
+               */
+               messaging_send_buf(smbd_messaging_context(), procid_self(), 
+                                  MSG_SMB_BRL_VALIDATE, NULL, 0);
+               message_send_all(smbd_messaging_context(), 
+                                MSG_SMB_UNLOCK, NULL, 0, NULL);
+       }
+
        if (lp_max_smbd_processes() == 0) {
                /* Don't bother with the child list if we don't care anyway */
                return;
@@ -311,6 +328,8 @@ static bool open_sockets_smbd(bool is_daemon, bool interactive, const char *smb_
        int maxfd = 0;
        int i;
        char *ports;
+       struct dns_reg_state * dns_reg = NULL;
+       unsigned dns_port = 0;
 
        if (!is_daemon) {
                return open_sockets_inetd();
@@ -352,9 +371,10 @@ static bool open_sockets_smbd(bool is_daemon, bool interactive, const char *smb_
                /* Now open a listen socket for each of the
                   interfaces. */
                for(i = 0; i < num_interfaces; i++) {
+                       TALLOC_CTX *frame = NULL;
                        const struct sockaddr_storage *ifss =
                                        iface_n_sockaddr_storage(i);
-                       fstring tok;
+                       char *tok;
                        const char *ptr;
 
                        if (ifss == NULL) {
@@ -364,15 +384,27 @@ static bool open_sockets_smbd(bool is_daemon, bool interactive, const char *smb_
                                continue;
                        }
 
-                       for (ptr=ports; next_token(&ptr, tok, " \t,",
-                                               sizeof(tok)); ) {
+                       frame = talloc_stackframe();
+                       for (ptr=ports;
+                                       next_token_talloc(frame,&ptr, &tok, " \t,");) {
                                unsigned port = atoi(tok);
                                if (port == 0 || port > 0xffff) {
                                        continue;
                                }
+
+                               /* Keep the first port for mDNS service
+                                * registration.
+                                */
+                               if (dns_port == 0) {
+                                       dns_port = port;
+                               }
+
                                s = fd_listenset[num_sockets] =
-                                       open_socket_in(SOCK_STREAM, port, 0,
-                                                       ifss, True);
+                                       open_socket_in(SOCK_STREAM,
+                                                       port,
+                                                       num_sockets == 0 ? 0 : 2,
+                                                       ifss,
+                                                       true);
                                if(s == -1) {
                                        continue;
                                }
@@ -389,6 +421,7 @@ static bool open_sockets_smbd(bool is_daemon, bool interactive, const char *smb_
                                        DEBUG(0,("open_sockets_smbd: listen: "
                                                "%s\n", strerror(errno)));
                                        close(s);
+                                       TALLOC_FREE(frame);
                                        return False;
                                }
                                FD_SET(s,&listen_set);
@@ -398,18 +431,21 @@ static bool open_sockets_smbd(bool is_daemon, bool interactive, const char *smb_
                                if (num_sockets >= FD_SETSIZE) {
                                        DEBUG(0,("open_sockets_smbd: Too "
                                                "many sockets to bind to\n"));
+                                       TALLOC_FREE(frame);
                                        return False;
                                }
                        }
+                       TALLOC_FREE(frame);
                }
        } else {
                /* Just bind to 0.0.0.0 - accept connections
                   from anywhere. */
 
-               fstring tok;
+               TALLOC_CTX *frame = talloc_stackframe();
+               char *tok;
                const char *ptr;
                const char *sock_addr = lp_socket_address();
-               fstring sock_tok;
+               char *sock_tok;
                const char *sock_ptr;
 
                if (strequal(sock_addr, "0.0.0.0") ||
@@ -421,24 +457,34 @@ static bool open_sockets_smbd(bool is_daemon, bool interactive, const char *smb_
 #endif
                }
 
-               for (sock_ptr=sock_addr; next_token(&sock_ptr, sock_tok, " \t,",
-                                       sizeof(sock_tok)); ) {
-                       for (ptr=ports; next_token(&ptr, tok, " \t,",
-                                               sizeof(tok)); ) {
+               for (sock_ptr=sock_addr;
+                               next_token_talloc(frame, &sock_ptr, &sock_tok, " \t,"); ) {
+                       for (ptr=ports; next_token_talloc(frame, &ptr, &tok, " \t,"); ) {
                                struct sockaddr_storage ss;
 
                                unsigned port = atoi(tok);
                                if (port == 0 || port > 0xffff) {
                                        continue;
                                }
+
+                               /* Keep the first port for mDNS service
+                                * registration.
+                                */
+                               if (dns_port == 0) {
+                                       dns_port = port;
+                               }
+
                                /* open an incoming socket */
                                if (!interpret_string_addr(&ss, sock_tok,
                                                AI_NUMERICHOST|AI_PASSIVE)) {
                                        continue;
                                }
 
-                               s = open_socket_in(SOCK_STREAM, port, 0,
-                                                  &ss, true);
+                               s = open_socket_in(SOCK_STREAM,
+                                               port,
+                                               num_sockets == 0 ? 0 : 2,
+                                               &ss,
+                                               true);
                                if (s == -1) {
                                        continue;
                                }
@@ -456,6 +502,7 @@ static bool open_sockets_smbd(bool is_daemon, bool interactive, const char *smb_
                                                "listen: %s\n",
                                                 strerror(errno)));
                                        close(s);
+                                       TALLOC_FREE(frame);
                                        return False;
                                }
 
@@ -468,10 +515,12 @@ static bool open_sockets_smbd(bool is_daemon, bool interactive, const char *smb_
                                if (num_sockets >= FD_SETSIZE) {
                                        DEBUG(0,("open_sockets_smbd: Too "
                                                "many sockets to bind to\n"));
+                                       TALLOC_FREE(frame);
                                        return False;
                                }
                        }
                }
+               TALLOC_FREE(frame);
        }
 
        SAFE_FREE(ports);
@@ -521,10 +570,27 @@ static bool open_sockets_smbd(bool is_daemon, bool interactive, const char *smb_
 
                if (got_sig_cld) {
                        pid_t pid;
+                       int status;
+
                        got_sig_cld = False;
 
-                       while ((pid = sys_waitpid(-1, NULL, WNOHANG)) > 0) {
-                               remove_child_pid(pid);
+                       while ((pid = sys_waitpid(-1, &status, WNOHANG)) > 0) {
+                               bool unclean_shutdown = False;
+                               
+                               /* If the child terminated normally, assume
+                                  it was an unclean shutdown unless the
+                                  status is 0 
+                               */
+                               if (WIFEXITED(status)) {
+                                       unclean_shutdown = WEXITSTATUS(status);
+                               }
+                               /* If the child terminated due to a signal
+                                  we always assume it was unclean.
+                               */
+                               if (WIFSIGNALED(status)) {
+                                       unclean_shutdown = True;
+                               }
+                               remove_child_pid(pid, unclean_shutdown);
                        }
                }
 
@@ -535,6 +601,12 @@ static bool open_sockets_smbd(bool is_daemon, bool interactive, const char *smb_
                FD_ZERO(&w_fds);
                GetTimeOfDay(&now);
 
+               /* Kick off our mDNS registration. */
+               if (dns_port != 0) {
+                       dns_register_smbd(&dns_reg, dns_port, &maxfd,
+                                       &r_fds, &idle_timeout);
+               }
+
                event_add_to_select_args(smbd_event_context(), &now,
                                         &r_fds, &w_fds, &idle_timeout,
                                         &maxfd);
@@ -558,6 +630,20 @@ static bool open_sockets_smbd(bool is_daemon, bool interactive, const char *smb_
 
                        continue;
                }
+               
+
+               /* If the idle timeout fired and we don't have any connected
+                * users, exit gracefully. We should be running under a process
+                * controller that will restart us if necessry.
+                */
+               if (num == 0 && count_all_current_connections() == 0) {
+                       exit_server_cleanly("idle timeout");
+               }
+
+               /* process pending nDNS responses */
+               if (dns_register_smbd_reply(dns_reg, &r_fds, &idle_timeout)) {
+                       --num;
+               }
 
                if (run_events(smbd_event_context(), num, &r_fds, &w_fds)) {
                        continue;
@@ -616,6 +702,9 @@ static bool open_sockets_smbd(bool is_daemon, bool interactive, const char *smb_
                                for(i = 0; i < num_sockets; i++)
                                        close(fd_listenset[i]);
 
+                               /* close our mDNS daemon handle */
+                               dns_register_close(&dns_reg);
+
                                /* close our standard file
                                   descriptors */
                                close_low_fds(False);
@@ -726,13 +815,12 @@ void reload_printers(void)
 bool reload_services(bool test)
 {
        bool ret;
-       
+
        if (lp_loaded()) {
-               pstring fname;
-               pstrcpy(fname,lp_configfile());
+               char *fname = lp_configfile();
                if (file_exist(fname, NULL) &&
-                   !strcsequal(fname, dyn_CONFIGFILE)) {
-                       pstrcpy(dyn_CONFIGFILE, fname);
+                   !strcsequal(fname, get_dyn_CONFIGFILE())) {
+                       set_dyn_CONFIGFILE(fname);
                        test = False;
                }
        }
@@ -744,7 +832,7 @@ bool reload_services(bool test)
 
        lp_killunused(conn_snum_used);
 
-       ret = lp_load(dyn_CONFIGFILE, False, False, True, True);
+       ret = lp_load(get_dyn_CONFIGFILE(), False, False, True, True);
 
        reload_printers();
 
@@ -756,7 +844,7 @@ bool reload_services(bool test)
 
        load_interfaces();
 
-       if (smbd_server_fd() != -1) {      
+       if (smbd_server_fd() != -1) {
                set_socket_options(smbd_server_fd(),"SO_KEEPALIVE");
                set_socket_options(smbd_server_fd(), lp_socket_options());
        }
@@ -854,6 +942,29 @@ void exit_server_fault(void)
        exit_server("critical server fault");
 }
 
+
+/****************************************************************************
+received when we should release a specific IP
+****************************************************************************/
+static void msg_release_ip(struct messaging_context *msg_ctx, void *private_data, 
+                          uint32_t msg_type, struct server_id server_id, DATA_BLOB *data)
+{
+       const char *ip = (const char *)data->data;
+       char addr[INET6_ADDRSTRLEN];
+
+       if (strcmp(client_socket_addr(get_client_fd(),addr,sizeof(addr)), ip) == 0) {
+               /* we can't afford to do a clean exit - that involves
+                  database writes, which would potentially mean we
+                  are still running after the failover has finished -
+                  we have to get rid of this process ID straight
+                  away */
+               DEBUG(0,("Got release IP message for our IP %s - exiting immediately\n",
+                       ip));
+               _exit(0);
+       }
+}
+
+
 /****************************************************************************
  Initialise connect, service and file structs.
 ****************************************************************************/
@@ -955,8 +1066,7 @@ extern void build_options(bool screen);
        POPT_COMMON_DYNCONFIG
        POPT_TABLEEND
        };
-
-       load_case_tables();
+       TALLOC_CTX *frame = talloc_stackframe(); /* Setup tos. */
 
        TimeInit();
 
@@ -994,11 +1104,20 @@ extern void build_options(bool screen);
        }
        poptFreeContext(pc);
 
+       if (interactive) {
+               Fork = False;
+               log_stdout = True;
+       }
+
+       setup_logging(argv[0],log_stdout);
+
        if (print_build_options) {
                build_options(True); /* Display output to screen as well as debug */
                exit(0);
        }
 
+       load_case_tables();
+
 #ifdef HAVE_SETLUID
        /* needed for SecureWare on SCO */
        setluid(0);
@@ -1008,11 +1127,6 @@ extern void build_options(bool screen);
 
        set_remote_machine_name("smbd", False);
 
-       if (interactive) {
-               Fork = False;
-               log_stdout = True;
-       }
-
        if (interactive && (DEBUGLEVEL >= 9)) {
                talloc_enable_leak_report();
        }
@@ -1022,8 +1136,6 @@ extern void build_options(bool screen);
                exit(1);
        }
 
-       setup_logging(argv[0],log_stdout);
-
        /* we want to re-seed early to prevent time delays causing
            client problems at a later date. (tridge) */
        generate_random_buffer(NULL, 0);
@@ -1144,6 +1256,12 @@ extern void build_options(bool screen);
        if (smbd_messaging_context() == NULL)
                exit(1);
 
+       if (smbd_memcache() == NULL) {
+               exit(1);
+       }
+
+       memcache_set_global(smbd_memcache());
+
        /* Initialise the password backed before the global_sam_sid
           to ensure that we fetch from ldap before we make a domain sid up */
 
@@ -1166,7 +1284,7 @@ extern void build_options(bool screen);
        if (!connections_init(True))
                exit(1);
 
-       if (!locking_init(0))
+       if (!locking_init())
                exit(1);
 
        namecache_enable();
@@ -1195,12 +1313,6 @@ extern void build_options(bool screen);
        if ( is_daemon && !interactive )
                start_background_queue(); 
 
-       /* Always attempt to initialize DMAPI. We will only use it later if
-        * lp_dmapi_support is set on the share, but we need a single global
-        * session to work with.
-        */
-       dmapi_init_session();
-
        if (!open_sockets_smbd(is_daemon, interactive, ports))
                exit(1);
 
@@ -1232,7 +1344,7 @@ extern void build_options(bool screen);
        /* Setup oplocks */
        if (!init_oplocks(smbd_messaging_context()))
                exit(1);
-       
+
        /* Setup aio signal handler. */
        initialize_async_io_handler();
 
@@ -1246,6 +1358,8 @@ extern void build_options(bool screen);
        /* register our message handlers */
        messaging_register(smbd_messaging_context(), NULL,
                           MSG_SMB_FORCE_TDIS, msg_force_tdis);
+       messaging_register(smbd_messaging_context(), NULL,
+                          MSG_SMB_RELEASE_IP, msg_release_ip);
 
        if ((lp_keepalive() != 0)
            && !(event_add_idle(smbd_event_context(), NULL,
@@ -1263,6 +1377,8 @@ extern void build_options(bool screen);
                exit(1);
        }
 
+       TALLOC_FREE(frame);
+
        smbd_process();
 
        namecache_shutdown();