Copyright (C) Andrew Tridgell 1992-1998
Copyright (C) Martin Pool 2002
Copyright (C) Jelmer Vernooij 2002-2003
- Copyright (C) James Peach 2007
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"
static struct event_context *ctx;
if (!ctx && !(ctx = event_context_init(NULL))) {
- smb_panic("Could not init smbd event context\n");
+ smb_panic("Could not init smbd event context");
}
return ctx;
}
if (!ctx && !(ctx = messaging_init(NULL, server_id_self(),
smbd_event_context()))) {
- smb_panic("Could not init smbd messaging context\n");
+ smb_panic("Could not init smbd messaging context");
}
return ctx;
}
DEBUG(10, ("** sam sync message received, ignoring\n"));
}
-/****************************************************************************
- Process a sam sync replicate message - not sure whether to do this here or
- somewhere else.
-****************************************************************************/
-
-static void msg_sam_repl(struct messaging_context *msg,
- void *private_data,
- uint32_t msg_type,
- struct server_id server_id,
- DATA_BLOB *data)
-{
- uint32 low_serial;
-
- if (data->length != sizeof(low_serial))
- return;
-
- low_serial = *((uint32 *)data->data);
-
- DEBUG(3, ("received sam replication message, serial = 0x%04x\n",
- low_serial));
-}
/****************************************************************************
Open the socket communication - inetd.
Open the socket communication.
****************************************************************************/
-static BOOL open_sockets_smbd(enum smb_server_mode server_mode, const char *smb_ports)
+static BOOL open_sockets_smbd(BOOL is_daemon, BOOL interactive, const char *smb_ports)
{
+ int num_interfaces = iface_count();
int num_sockets = 0;
int fd_listenset[FD_SETSIZE];
fd_set listen_set;
int s;
int maxfd = 0;
int i;
- struct timeval idle_timeout = timeval_zero();
+ char *ports;
- if (server_mode == SERVER_MODE_INETD) {
+ if (!is_daemon) {
return open_sockets_inetd();
}
+
#ifdef HAVE_ATEXIT
{
static int atexit_set;
/* Stop zombies */
CatchSignal(SIGCLD, sig_cld);
-
+
FD_ZERO(&listen_set);
- /* At this point, it doesn't matter what daemon mode we are in, we
- * need some sockets to listen on.
- */
- num_sockets = smbd_sockinit(smb_ports, fd_listenset, &idle_timeout);
- if (num_sockets == 0) {
- return False;
+ /* use a reasonable default set of ports - listing on 445 and 139 */
+ if (!smb_ports) {
+ ports = lp_smb_ports();
+ if (!ports || !*ports) {
+ ports = smb_xstrdup(SMB_PORTS);
+ } else {
+ ports = smb_xstrdup(ports);
+ }
+ } else {
+ ports = smb_xstrdup(smb_ports);
}
- for (i = 0; i < num_sockets; ++i) {
- FD_SET(fd_listenset[i], &listen_set);
- maxfd = MAX(maxfd, fd_listenset[i]);
- }
+ if (lp_interfaces() && lp_bind_interfaces_only()) {
+ /* 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.
+ */
+
+ /* Now open a listen socket for each of the
+ interfaces. */
+ for(i = 0; i < num_interfaces; i++) {
+ struct in_addr *ifip = iface_n_ip(i);
+ fstring tok;
+ const char *ptr;
+
+ if(ifip == NULL) {
+ DEBUG(0,("open_sockets_smbd: interface %d has NULL IP address !\n", i));
+ continue;
+ }
+
+ for (ptr=ports; next_token(&ptr, tok, " \t,", sizeof(tok)); ) {
+ unsigned port = atoi(tok);
+ if (port == 0 || port > 0xffff) {
+ continue;
+ }
+ s = fd_listenset[num_sockets] = open_socket_in(SOCK_STREAM, port, 0, ifip->s_addr, True);
+ if(s == -1)
+ return False;
+
+ /* ready to listen */
+ set_socket_options(s,"SO_KEEPALIVE");
+ set_socket_options(s,user_socket_options);
+
+ /* Set server socket to non-blocking for the accept. */
+ set_blocking(s,False);
+
+ if (listen(s, SMBD_LISTEN_BACKLOG) == -1) {
+ DEBUG(0,("listen: %s\n",strerror(errno)));
+ close(s);
+ return False;
+ }
+ FD_SET(s,&listen_set);
+ maxfd = MAX( maxfd, s);
+
+ num_sockets++;
+ if (num_sockets >= FD_SETSIZE) {
+ DEBUG(0,("open_sockets_smbd: Too many sockets to bind to\n"));
+ return False;
+ }
+ }
+ }
+ } else {
+ /* Just bind to 0.0.0.0 - accept connections
+ from anywhere. */
+
+ fstring tok;
+ const char *ptr;
+
+ num_interfaces = 1;
+
+ for (ptr=ports; next_token(&ptr, tok, " \t,", sizeof(tok)); ) {
+ unsigned port = atoi(tok);
+ if (port == 0 || port > 0xffff) continue;
+ /* open an incoming socket */
+ s = open_socket_in(SOCK_STREAM, port, 0,
+ interpret_addr(lp_socket_address()),True);
+ if (s == -1)
+ return(False);
+
+ /* ready to listen */
+ set_socket_options(s,"SO_KEEPALIVE");
+ set_socket_options(s,user_socket_options);
+
+ /* Set server socket to non-blocking for the accept. */
+ set_blocking(s,False);
+
+ if (listen(s, SMBD_LISTEN_BACKLOG) == -1) {
+ DEBUG(0,("open_sockets_smbd: listen: %s\n",
+ strerror(errno)));
+ close(s);
+ return False;
+ }
+
+ fd_listenset[num_sockets] = s;
+ FD_SET(s,&listen_set);
+ maxfd = MAX( maxfd, s);
+
+ num_sockets++;
+
+ if (num_sockets >= FD_SETSIZE) {
+ DEBUG(0,("open_sockets_smbd: Too many sockets to bind to\n"));
+ return False;
+ }
+ }
+ }
+
+ SAFE_FREE(ports);
+
+
+ /* Setup the main smbd so that we can get messages. Note that
+ do this after starting listening. This is needed as when in
+ clustered mode, ctdb won't allow us to start doing database
+ operations until it has gone thru a full startup, which
+ includes checking to see that smbd is listening. */
+ claim_connection(NULL,"",FLAG_MSG_GENERAL|FLAG_MSG_SMBD);
/* Listen to messages */
messaging_register(smbd_messaging_context(), NULL,
MSG_SMB_SAM_SYNC, msg_sam_sync);
- messaging_register(smbd_messaging_context(), NULL,
- MSG_SMB_SAM_REPL, msg_sam_repl);
messaging_register(smbd_messaging_context(), NULL,
MSG_SHUTDOWN, msg_exit_server);
messaging_register(smbd_messaging_context(), NULL,
for each incoming connection */
DEBUG(2,("waiting for a connection\n"));
while (1) {
- fd_set lfds;
+ struct timeval now, idle_timeout;
+ fd_set r_fds, w_fds;
int num;
- /* Free up temporary memory from the main smbd. */
- lp_TALLOC_FREE();
-
/* Ensure we respond to PING and DEBUG messages from the main smbd. */
message_dispatch(smbd_messaging_context());
}
}
- memcpy((char *)&lfds, (char *)&listen_set,
+ idle_timeout = timeval_zero();
+
+ memcpy((char *)&r_fds, (char *)&listen_set,
sizeof(listen_set));
+ FD_ZERO(&w_fds);
+ GetTimeOfDay(&now);
+
+ event_add_to_select_args(smbd_event_context(), &now,
+ &r_fds, &w_fds, &idle_timeout,
+ &maxfd);
- num = sys_select(maxfd+1,&lfds,NULL,NULL,
+ num = sys_select(maxfd+1,&r_fds,&w_fds,NULL,
timeval_is_zero(&idle_timeout) ?
NULL : &idle_timeout);
-
+
if (num == -1 && errno == EINTR) {
if (got_sig_term) {
exit_server_cleanly(NULL);
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");
+
+ if (run_events(smbd_event_context(), num, &r_fds, &w_fds)) {
+ continue;
}
/* check if we need to reload services */
s = -1;
for(i = 0; i < num_sockets; i++) {
- if(FD_ISSET(fd_listenset[i],&lfds)) {
+ if(FD_ISSET(fd_listenset[i],&r_fds)) {
s = fd_listenset[i];
/* Clear this so we don't look
at it again. */
- FD_CLR(fd_listenset[i],&lfds);
+ FD_CLR(fd_listenset[i],&r_fds);
break;
}
}
/* Ensure child is set to blocking mode */
set_blocking(smbd_server_fd(),True);
- /* In interactive mode, return with a connected socket.
- * Foreground and daemon modes should fork worker
- * processes.
- */
- if (server_mode == SERVER_MODE_INTERACTIVE) {
+ if (smbd_server_fd() != -1 && interactive)
return True;
- }
if (allowable_number_of_smbd_processes() &&
smbd_server_fd() != -1 &&
* CLEAR_IF_FIRST flags */
if (tdb_reopen_all(1) == -1) {
DEBUG(0,("tdb_reopen_all failed.\n"));
- smb_panic("tdb_reopen_all failed.");
+ smb_panic("tdb_reopen_all failed");
}
return True;
locking_end();
printing_end();
- server_encryption_shutdown();
-
if (how != SERVER_EXIT_NORMAL) {
int oldlevel = DEBUGLEVEL;
- char *last_inbuf = get_InBuffer();
DEBUGLEVEL = 10;
DEBUGSEP(0);
log_stack_trace();
- if (last_inbuf) {
- DEBUG(0,("Last message was %s\n", LAST_MESSAGE()));
- show_msg(last_inbuf);
- }
DEBUGLEVEL = oldlevel;
dump_core();
int main(int argc,const char *argv[])
{
/* shall I run as a daemon */
- BOOL no_process_group = False;
- BOOL log_stdout = False;
- const char *ports = NULL;
- const char *profile_level = NULL;
+ static BOOL is_daemon = False;
+ static BOOL interactive = False;
+ static BOOL Fork = True;
+ static BOOL no_process_group = False;
+ static BOOL log_stdout = False;
+ static char *ports = NULL;
+ static char *profile_level = NULL;
int opt;
poptContext pc;
-
- enum smb_server_mode server_mode = SERVER_MODE_DAEMON;
+ BOOL print_build_options = False;
struct poptOption long_options[] = {
POPT_AUTOHELP
- {"daemon", 'D', POPT_ARG_VAL, &server_mode, SERVER_MODE_DAEMON,
- "Become a daemon (default)" },
- {"interactive", 'i', POPT_ARG_VAL, &server_mode, SERVER_MODE_INTERACTIVE,
- "Run interactive (not a daemon)"},
- {"foreground", 'F', POPT_ARG_VAL, &server_mode, SERVER_MODE_FOREGROUND,
- "Run daemon in foreground (for daemontools, etc.)" },
- {"no-process-group", '\0', POPT_ARG_VAL, &no_process_group, True,
- "Don't create a new process group" },
+ {"daemon", 'D', POPT_ARG_VAL, &is_daemon, True, "Become a daemon (default)" },
+ {"interactive", 'i', POPT_ARG_VAL, &interactive, True, "Run interactive (not a daemon)"},
+ {"foreground", 'F', POPT_ARG_VAL, &Fork, False, "Run daemon in foreground (for daemontools, etc.)" },
+ {"no-process-group", '\0', POPT_ARG_VAL, &no_process_group, True, "Don't create a new process group" },
{"log-stdout", 'S', POPT_ARG_VAL, &log_stdout, True, "Log to stdout" },
{"build-options", 'b', POPT_ARG_NONE, NULL, 'b', "Print build options" },
{"port", 'p', POPT_ARG_STRING, &ports, 0, "Listen on the specified ports"},
#endif
pc = poptGetContext("smbd", argc, argv, long_options, 0);
-
while((opt = poptGetNextOpt(pc)) != -1) {
switch (opt) {
case 'b':
- build_options(True); /* Display output to screen as well as debug */
- exit(0);
+ print_build_options = True;
break;
+ default:
+ d_fprintf(stderr, "\nInvalid option %s: %s\n\n",
+ poptBadOption(pc, 0), poptStrerror(opt));
+ poptPrintUsage(pc, stderr, 0);
+ exit(1);
}
}
-
poptFreeContext(pc);
+ if (print_build_options) {
+ build_options(True); /* Display output to screen as well as debug */
+ exit(0);
+ }
+
#ifdef HAVE_SETLUID
/* needed for SecureWare on SCO */
setluid(0);
set_remote_machine_name("smbd", False);
- if (server_mode == SERVER_MODE_INTERACTIVE) {
+ if (interactive) {
+ Fork = False;
log_stdout = True;
- if (DEBUGLEVEL >= 9) {
- talloc_enable_leak_report();
- }
}
- if (log_stdout && server_mode == SERVER_MODE_DAEMON) {
+ if (interactive && (DEBUGLEVEL >= 9)) {
+ talloc_enable_leak_report();
+ }
+
+ if (log_stdout && Fork) {
DEBUG(0,("ERROR: Can't log to stdout (-S) unless daemon is in foreground (-F) or interactive (-i)\n"));
exit(1);
}
DEBUG(3,( "loaded services\n"));
- if (is_a_socket(0)) {
- if (server_mode == SERVER_MODE_DAEMON) {
- DEBUG(0,("standard input is a socket, "
- "assuming -F option\n"));
- }
- server_mode = SERVER_MODE_INETD;
+ if (!is_daemon && !is_a_socket(0)) {
+ if (!interactive)
+ DEBUG(0,("standard input is not a socket, assuming -D option\n"));
+
+ /*
+ * Setting is_daemon here prevents us from eventually calling
+ * the open_sockets_inetd()
+ */
+
+ is_daemon = True;
}
- if (server_mode == SERVER_MODE_DAEMON) {
+ if (is_daemon && !interactive) {
DEBUG( 3, ( "Becoming a daemon.\n" ) );
- become_daemon(True, no_process_group);
- } else if (server_mode == SERVER_MODE_FOREGROUND) {
- become_daemon(False, no_process_group);
+ become_daemon(Fork, no_process_group);
}
#if HAVE_SETPGID
* If we're interactive we want to set our own process group for
* signal management.
*/
- if (server_mode == SERVER_MODE_INTERACTIVE && !no_process_group) {
+ if (interactive && !no_process_group)
setpgid( (pid_t)0, (pid_t)0);
- }
#endif
if (!directory_exist(lp_lockdir(), NULL))
mkdir(lp_lockdir(), 0755);
- if (server_mode != SERVER_MODE_INETD &&
- server_mode != SERVER_MODE_INTERACTIVE) {
+ if (is_daemon)
pidfile_create("smbd");
- }
/* Setup all the TDB's - including CLEAR_IF_FIRST tdb's. */
return -1;
}
- /* Setup the main smbd so that we can get messages. */
- /* don't worry about general printing messages here */
-
- claim_connection(NULL,"",FLAG_MSG_GENERAL|FLAG_MSG_SMBD);
-
/* only start the background queue daemon 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 */
- if (server_mode != SERVER_MODE_INETD &&
- server_mode != SERVER_MODE_INTERACTIVE) {
+
+ 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
*/
dmapi_init_session();
- if (!open_sockets_smbd(server_mode, ports)) {
+ if (!open_sockets_smbd(is_daemon, interactive, ports))
exit(1);
- }
/*
* everything after this point is run after the fork()
/* Possibly reload the services file. Only worth doing in
* daemon mode. In inetd mode, we know we only just loaded this.
*/
- if (server_mode != SERVER_MODE_INETD &&
- server_mode != SERVER_MODE_INTERACTIVE) {
+ if (is_daemon) {
reload_services(True);
}
/* Setup aio signal handler. */
initialize_async_io_handler();
+ /*
+ * For clustering, we need to re-init our ctdbd connection after the
+ * fork
+ */
+ if (!NT_STATUS_IS_OK(messaging_reinit(smbd_messaging_context())))
+ exit(1);
+
/* register our message handlers */
messaging_register(smbd_messaging_context(), NULL,
MSG_SMB_FORCE_TDIS, msg_force_tdis);