*/
#include "includes.h"
+#include "smbd/globals.h"
static_decl_rpc;
-static int am_parent = 1;
-
-extern struct auth_context *negprot_global_auth_context;
-extern SIG_ATOMIC_T got_sig_term;
-extern SIG_ATOMIC_T reload_after_sighup;
-static SIG_ATOMIC_T got_sig_cld;
-
#ifdef WITH_DFS
extern int dcelogin_atmost_once;
#endif /* WITH_DFS */
-/* really we should have a top level context structure that has the
- client file descriptor as an element. That would require a major rewrite :(
-
- the following 2 functions are an alternative - they make the file
- descriptor private to smbd
- */
-static int server_fd = -1;
-
int smbd_server_fd(void)
{
return server_fd;
return server_fd;
}
-#ifdef CLUSTER_SUPPORT
-static int client_get_tcp_info(struct sockaddr_storage *server,
- struct sockaddr_storage *client)
-{
- socklen_t length;
- if (server_fd == -1) {
- return -1;
- }
- length = sizeof(*server);
- if (getsockname(server_fd, (struct sockaddr *)server, &length) != 0) {
- return -1;
- }
- length = sizeof(*client);
- if (getpeername(server_fd, (struct sockaddr *)client, &length) != 0) {
- return -1;
- }
- return 0;
-}
-#endif
-
struct event_context *smbd_event_context(void)
{
- static struct event_context *ctx;
-
- if (!ctx && !(ctx = event_context_init(talloc_autofree_context()))) {
+ if (!smbd_event_ctx) {
+ smbd_event_ctx = event_context_init(talloc_autofree_context());
+ }
+ if (!smbd_event_ctx) {
smb_panic("Could not init smbd event context");
}
- return ctx;
+ return smbd_event_ctx;
}
struct messaging_context *smbd_messaging_context(void)
{
- static struct messaging_context *ctx;
-
- if (ctx == NULL) {
- ctx = messaging_init(talloc_autofree_context(), server_id_self(),
- smbd_event_context());
+ if (smbd_msg_ctx == NULL) {
+ smbd_msg_ctx = messaging_init(talloc_autofree_context(),
+ server_id_self(),
+ smbd_event_context());
}
- if (ctx == NULL) {
+ if (smbd_msg_ctx == NULL) {
DEBUG(0, ("Could not init smbd messaging context.\n"));
}
- return ctx;
+ return smbd_msg_ctx;
}
struct memcache *smbd_memcache(void)
{
- static struct memcache *cache;
-
- if (!cache
- && !(cache = memcache_init(talloc_autofree_context(),
- lp_max_stat_cache_size()*1024))) {
-
+ if (!smbd_memcache_ctx) {
+ smbd_memcache_ctx = memcache_init(talloc_autofree_context(),
+ lp_max_stat_cache_size()*1024);
+ }
+ if (!smbd_memcache_ctx) {
smb_panic("Could not init smbd memcache");
}
- return cache;
+
+ return smbd_memcache_ctx;
}
/*******************************************************************
stat_cache_delete(name);
}
-/****************************************************************************
- Terminate signal.
-****************************************************************************/
-
-static void sig_term(void)
-{
- got_sig_term = 1;
- sys_select_signal(SIGTERM);
-}
-
-/****************************************************************************
- Catch a sighup.
-****************************************************************************/
-
-static void sig_hup(int sig)
-{
- reload_after_sighup = 1;
- sys_select_signal(SIGHUP);
-}
-
-/****************************************************************************
- Catch a sigcld
-****************************************************************************/
-static void sig_cld(int sig)
-{
- got_sig_cld = 1;
- sys_select_signal(SIGCLD);
-}
-
/****************************************************************************
Send a SIGTERM to our process group.
*****************************************************************************/
/* close our standard file descriptors */
close_low_fds(False); /* Don't close stderr */
-
- set_socket_options(smbd_server_fd(),"SO_KEEPALIVE");
- set_socket_options(smbd_server_fd(), lp_socket_options());
return True;
}
pid_t pid;
};
-static struct child_pid *children;
-static int num_children;
-
static void add_child_pid(pid_t pid)
{
struct child_pid *child;
return num_children < max_processes;
}
+static void smbd_sig_chld_handler(struct tevent_context *ev,
+ struct tevent_signal *se,
+ int signum,
+ int count,
+ void *siginfo,
+ void *private_data)
+{
+ pid_t pid;
+ int status;
+
+ 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);
+ }
+}
+
+static void smbd_setup_sig_chld_handler(void)
+{
+ struct tevent_signal *se;
+
+ se = tevent_add_signal(smbd_event_context(),
+ smbd_event_context(),
+ SIGCHLD, 0,
+ smbd_sig_chld_handler,
+ NULL);
+ if (!se) {
+ exit_server("failed to setup SIGCHLD handler");
+ }
+}
+
/****************************************************************************
Open the socket communication.
****************************************************************************/
#endif
/* Stop zombies */
- CatchSignal(SIGCLD, sig_cld);
+ smbd_setup_sig_chld_handler();
FD_ZERO(&listen_set);
fd_set r_fds, w_fds;
int num;
- /* Ensure we respond to PING and DEBUG messages from the main smbd. */
- message_dispatch(smbd_messaging_context());
-
- if (got_sig_cld) {
- pid_t pid;
- int status;
-
- got_sig_cld = False;
-
- 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);
- }
+ if (run_events(smbd_event_context(), 0, NULL, NULL)) {
+ continue;
}
idle_timeout = timeval_zero();
timeval_is_zero(&idle_timeout) ?
NULL : &idle_timeout);
- if (num == -1 && errno == EINTR) {
- if (got_sig_term) {
- exit_server_cleanly(NULL);
- }
-
- /* check for sighup processing */
- if (reload_after_sighup) {
- change_to_root_user();
- DEBUG(1,("Reloading services after SIGHUP\n"));
- reload_services(False);
- reload_after_sighup = 0;
- }
-
+ if (run_events(smbd_event_context(), num, &r_fds, &w_fds)) {
continue;
}
-
/* If the idle timeout fired and we don't have any connected
* users, exit gracefully. We should be running under a process
--num;
}
- if (run_events(smbd_event_context(), num, &r_fds, &w_fds)) {
- continue;
- }
-
/* check if we need to reload services */
check_reload(time(NULL));
continue;
}
- /* Ensure child is set to blocking mode */
- set_blocking(smbd_server_fd(),True);
-
- if (smbd_server_fd() != -1 && interactive)
+ if (interactive)
return True;
if (allowable_number_of_smbd_processes() &&
- smbd_server_fd() != -1 &&
((child = sys_fork())==0)) {
- char remaddr[INET6_ADDRSTRLEN];
-
/* Child code ... */
/* Stop zombies, the parent explicitly handles
close_low_fds(False);
am_parent = 0;
- set_socket_options(smbd_server_fd(),"SO_KEEPALIVE");
- set_socket_options(smbd_server_fd(),
- lp_socket_options());
-
- /* this is needed so that we get decent entries
- in smbstatus for port 445 connects */
- set_remote_machine_name(get_peer_addr(smbd_server_fd(),
- remaddr,
- sizeof(remaddr)),
- false);
-
if (!reinit_after_fork(
smbd_messaging_context(),
smbd_event_context(),
smb_panic("reinit_after_fork() failed");
}
+ smbd_setup_sig_term_handler();
+ smbd_setup_sig_hup_handler();
+
return True;
}
/* The parent doesn't need this socket */
static void exit_server_common(enum server_exit_reason how,
const char *const reason)
{
- static int firsttime=1;
bool had_open_conn;
- if (!firsttime)
+ if (!exit_firsttime)
exit(0);
- firsttime = 0;
+ exit_firsttime = false;
change_to_root_user();
exit_server("critical server fault");
}
-
-/****************************************************************************
-received when we should release a specific IP
-****************************************************************************/
-static void release_ip(const char *ip, void *priv)
-{
- 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));
- /* note we must exit with non-zero status so the unclean handler gets
- called in the parent, so that the brl database is tickled */
- _exit(1);
- }
-}
-
-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)
-{
- release_ip((char *)data->data, NULL);
-}
-
/****************************************************************************
Initialise connect, service and file structs.
****************************************************************************/
file_init();
- /* for RPC pipes */
- init_rpc_pipe_hnd();
-
init_dptrs();
if (!secrets_init())
return True;
}
-/*
- * Send keepalive packets to our client
- */
-static bool keepalive_fn(const struct timeval *now, void *private_data)
-{
- if (!send_keepalive(smbd_server_fd())) {
- DEBUG( 2, ( "Keepalive failed - exiting.\n" ) );
- return False;
- }
- return True;
-}
-
-/*
- * Do the recurring check if we're idle
- */
-static bool deadtime_fn(const struct timeval *now, void *private_data)
-{
- if ((conn_num_open() == 0)
- || (conn_idle_all(now->tv_sec))) {
- DEBUG( 2, ( "Closing idle connection\n" ) );
- messaging_send(smbd_messaging_context(), procid_self(),
- MSG_SHUTDOWN, &data_blob_null);
- return False;
- }
-
- return True;
-}
-
-/*
- * Do the recurring log file and smb.conf reload checks.
- */
-
-static bool housekeeping_fn(const struct timeval *now, void *private_data)
-{
- change_to_root_user();
-
- /* update printer queue caches if necessary */
- update_monitored_printq_cache();
-
- /* check if we need to reload services */
- check_reload(time(NULL));
-
- /* Change machine password if neccessary. */
- attempt_machine_password_change();
-
- /*
- * Force a log file check.
- */
- force_check_log_size();
- check_log_size();
- return true;
-}
-
/****************************************************************************
main program.
****************************************************************************/
int main(int argc,const char *argv[])
{
/* shall I run as a daemon */
- 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;
+ bool is_daemon = false;
+ bool interactive = false;
+ bool Fork = true;
+ bool no_process_group = false;
+ bool log_stdout = false;
+ char *ports = NULL;
+ char *profile_level = NULL;
int opt;
poptContext pc;
bool print_build_options = False;
};
TALLOC_CTX *frame = talloc_stackframe(); /* Setup tos. */
+ smbd_init_globals();
+
TimeInit();
#ifdef HAVE_SET_AUTH_PARAMETERS
fault_setup((void (*)(void *))exit_server_fault);
dump_core_setup("smbd");
- CatchSignal(SIGTERM , SIGNAL_CAST sig_term);
- CatchSignal(SIGHUP,SIGNAL_CAST sig_hup);
-
/* we are never interested in SIGPIPE */
BlockSignals(True,SIGPIPE);
reopen_logs();
- DEBUG(0,("smbd version %s started.\n", SAMBA_VERSION_STRING));
+ DEBUG(0,("smbd version %s started.\n", samba_version_string()));
DEBUGADD(0,("%s\n", COPYRIGHT_STARTUP_MESSAGE));
DEBUG(2,("uid=%d gid=%d euid=%d egid=%d\n",
exit(1);
}
+ smbd_setup_sig_term_handler();
+ smbd_setup_sig_hup_handler();
+
/* Setup all the TDB's - including CLEAR_IF_FIRST tdb's. */
if (smbd_memcache() == NULL) {
if (!open_sockets_smbd(is_daemon, interactive, ports))
exit(1);
- /*
- * everything after this point is run after the fork()
- */
-
- static_init_rpc;
-
- init_modules();
-
- /* Possibly reload the services file. Only worth doing in
- * daemon mode. In inetd mode, we know we only just loaded this.
- */
- if (is_daemon) {
- reload_services(True);
- }
-
- if (!init_account_policy()) {
- DEBUG(0,("Could not open account policy tdb.\n"));
- exit(1);
- }
-
- if (*lp_rootdir()) {
- if (chroot(lp_rootdir()) == 0)
- DEBUG(2,("Changed root to %s\n", lp_rootdir()));
- }
-
- /* Setup oplocks */
- if (!init_oplocks(smbd_messaging_context()))
- exit(1);
-
- /* Setup aio signal handler. */
- initialize_async_io_handler();
-
- /* 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);
- messaging_register(smbd_messaging_context(), NULL,
- MSG_SMB_CLOSE_FILE, msg_close_file);
-
- if ((lp_keepalive() != 0)
- && !(event_add_idle(smbd_event_context(), NULL,
- timeval_set(lp_keepalive(), 0),
- "keepalive", keepalive_fn,
- NULL))) {
- DEBUG(0, ("Could not add keepalive event\n"));
- exit(1);
- }
-
- if (!(event_add_idle(smbd_event_context(), NULL,
- timeval_set(IDLE_CLOSED_TIMEOUT, 0),
- "deadtime", deadtime_fn, NULL))) {
- DEBUG(0, ("Could not add deadtime event\n"));
- exit(1);
- }
-
- if (!(event_add_idle(smbd_event_context(), NULL,
- timeval_set(SMBD_SELECT_TIMEOUT, 0),
- "housekeeping", housekeeping_fn, NULL))) {
- DEBUG(0, ("Could not add housekeeping event\n"));
- exit(1);
- }
-
-#ifdef CLUSTER_SUPPORT
-
- if (lp_clustering()) {
- /*
- * We need to tell ctdb about our client's TCP
- * connection, so that for failover ctdbd can send
- * tickle acks, triggering a reconnection by the
- * client.
- */
-
- struct sockaddr_storage srv, clnt;
-
- if (client_get_tcp_info(&srv, &clnt) == 0) {
-
- NTSTATUS status;
-
- status = ctdbd_register_ips(
- messaging_ctdbd_connection(),
- (struct sockaddr *)&srv,
- (struct sockaddr *)&clnt,
- release_ip, NULL);
-
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0, ("ctdbd_register_ips failed: %s\n",
- nt_errstr(status)));
- }
- } else
- {
- DEBUG(0,("Unable to get tcp info for "
- "CTDB_CONTROL_TCP_CLIENT: %s\n",
- strerror(errno)));
- }
- }
-
-#endif
-
TALLOC_FREE(frame);
smbd_process();
- namecache_shutdown();
-
exit_server_cleanly(NULL);
return(0);
}