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)
{
if (!smbd_event_ctx) {
{
DEBUG(10,("smb_conf_updated: Got message saying smb.conf was "
"updated. Reloading.\n"));
+ change_to_root_user();
reload_services(False);
}
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.
*****************************************************************************/
DEBUG(10, ("** sam sync message received, ignoring\n"));
}
-
-/****************************************************************************
- Open the socket communication - inetd.
-****************************************************************************/
-
-static bool open_sockets_inetd(void)
-{
- /* Started from inetd. fd 0 is the socket. */
- /* We will abort gracefully when the client or remote system
- goes away */
- smbd_set_server_fd(dup(0));
-
- /* 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;
-}
-
static void msg_exit_server(struct messaging_context *msg,
void *private_data,
uint32_t msg_type,
}
#endif /* DEVELOPER */
-struct child_pid {
- struct child_pid *prev, *next;
- pid_t pid;
-};
+/*
+ * Parent smbd process sets its own debug level first and then
+ * sends a message to all the smbd children to adjust their debug
+ * level to that of the parent.
+ */
-static void add_child_pid(pid_t pid)
+static void smbd_msg_debug(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
{
struct child_pid *child;
- if (lp_max_smbd_processes() == 0) {
- /* Don't bother with the child list if we don't care anyway */
- return;
+ debug_message(msg_ctx, private_data, MSG_DEBUG, server_id, data);
+
+ for (child = children; child != NULL; child = child->next) {
+ messaging_send_buf(msg_ctx, pid_to_procid(child->pid),
+ MSG_DEBUG,
+ data->data,
+ strlen((char *) data->data) + 1);
}
+}
+
+static void add_child_pid(pid_t pid)
+{
+ struct child_pid *child;
child = SMB_MALLOC_P(struct child_pid);
if (child == NULL) {
num_children += 1;
}
+/*
+ at most every smbd:cleanuptime seconds (default 20), we scan the BRL
+ and locking database for entries to cleanup. As a side effect this
+ also cleans up dead entries in the connections database (due to the
+ traversal in message_send_all()
+
+ Using a timer for this prevents a flood of traversals when a large
+ number of clients disconnect at the same time (perhaps due to a
+ network outage).
+*/
+
+static void cleanup_timeout_fn(struct event_context *event_ctx,
+ struct timed_event *te,
+ struct timeval now,
+ void *private_data)
+{
+ struct timed_event **cleanup_te = (struct timed_event **)private_data;
+
+ DEBUG(1,("Cleaning up brl and lock database after unclean shutdown\n"));
+ message_send_all(smbd_messaging_context(), MSG_SMB_UNLOCK, NULL, 0, NULL);
+ messaging_send_buf(smbd_messaging_context(), procid_self(),
+ MSG_SMB_BRL_VALIDATE, NULL, 0);
+ /* mark the cleanup as having been done */
+ (*cleanup_te) = NULL;
+}
+
static void remove_child_pid(pid_t pid, bool unclean_shutdown)
{
struct child_pid *child;
+ static struct timed_event *cleanup_te;
if (unclean_shutdown) {
- /* a child terminated uncleanly so tickle all processes to see
- if they can grab any of the pending locks
- */
- DEBUG(3,(__location__ " Unclean shutdown of pid %u\n", pid));
- 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;
+ /* a child terminated uncleanly so tickle all
+ processes to see if they can grab any of the
+ pending locks
+ */
+ DEBUG(3,(__location__ " Unclean shutdown of pid %u\n",
+ (unsigned int)pid));
+ if (!cleanup_te) {
+ /* call the cleanup timer, but not too often */
+ int cleanup_time = lp_parm_int(-1, "smbd", "cleanuptime", 20);
+ cleanup_te = event_add_timed(smbd_event_context(), NULL,
+ timeval_current_ofs(cleanup_time, 0),
+ cleanup_timeout_fn,
+ &cleanup_te);
+ DEBUG(1,("Scheduled cleanup of brl and lock database after unclean shutdown\n"));
+ }
}
for (child = children; child != NULL; child = child->next) {
}
}
- DEBUG(0, ("Could not find child %d -- ignoring\n", (int)pid));
+ /* not all forked child processes are added to the children list */
+ DEBUG(1, ("Could not find child %d -- ignoring\n", (int)pid));
}
/****************************************************************************
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");
+ }
+}
+
+struct smbd_open_socket;
+
+struct smbd_parent_context {
+ bool interactive;
+
+ /* the list of listening sockets */
+ struct smbd_open_socket *sockets;
+};
+
+struct smbd_open_socket {
+ struct smbd_open_socket *prev, *next;
+ struct smbd_parent_context *parent;
+ int fd;
+ struct tevent_fd *fde;
+};
+
+static void smbd_open_socket_close_fn(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ int fd,
+ void *private_data)
+{
+ /* this might be the socket_wrapper swrap_close() */
+ close(fd);
+}
+
+static void smbd_accept_connection(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data)
+{
+ struct smbd_open_socket *s = talloc_get_type_abort(private_data,
+ struct smbd_open_socket);
+ struct sockaddr_storage addr;
+ socklen_t in_addrlen = sizeof(addr);
+ pid_t pid = 0;
+
+ smbd_set_server_fd(accept(s->fd,(struct sockaddr *)&addr,&in_addrlen));
+
+ if (smbd_server_fd() == -1 && errno == EINTR)
+ return;
+
+ if (smbd_server_fd() == -1) {
+ DEBUG(0,("open_sockets_smbd: accept: %s\n",
+ strerror(errno)));
+ return;
+ }
+
+ if (s->parent->interactive) {
+ smbd_process();
+ exit_server_cleanly("end of interactive mode");
+ return;
+ }
+
+ if (!allowable_number_of_smbd_processes()) {
+ close(smbd_server_fd());
+ smbd_set_server_fd(-1);
+ return;
+ }
+
+ pid = sys_fork();
+ if (pid == 0) {
+ NTSTATUS status = NT_STATUS_OK;
+ /* Child code ... */
+ am_parent = 0;
+
+ /* Stop zombies, the parent explicitly handles
+ * them, counting worker smbds. */
+ CatchChild();
+
+ /* close our standard file
+ descriptors */
+ close_low_fds(False);
+
+ /*
+ * Can't use TALLOC_FREE here. Nulling out the argument to it
+ * would overwrite memory we've just freed.
+ */
+ talloc_free(s->parent);
+ s = NULL;
+
+ status = reinit_after_fork(smbd_messaging_context(),
+ smbd_event_context(), true);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status,
+ NT_STATUS_TOO_MANY_OPENED_FILES)) {
+ DEBUG(0,("child process cannot initialize "
+ "because too many files are open\n"));
+ goto exit;
+ }
+ DEBUG(0,("reinit_after_fork() failed\n"));
+ smb_panic("reinit_after_fork() failed");
+ }
+
+ smbd_setup_sig_term_handler();
+ smbd_setup_sig_hup_handler();
+
+ smbd_process();
+ exit:
+ exit_server_cleanly("end of child");
+ return;
+ } else if (pid < 0) {
+ DEBUG(0,("smbd_accept_connection: sys_fork() failed: %s\n",
+ strerror(errno)));
+ }
+
+ /* The parent doesn't need this socket */
+ close(smbd_server_fd());
+
+ /* Sun May 6 18:56:14 2001 ackley@cs.unm.edu:
+ Clear the closed fd info out of server_fd --
+ and more importantly, out of client_fd in
+ util_sock.c, to avoid a possible
+ getpeername failure if we reopen the logs
+ and use %I in the filename.
+ */
+
+ smbd_set_server_fd(-1);
+
+ if (pid != 0) {
+ add_child_pid(pid);
+ }
+
+ /* Force parent to check log size after
+ * spawning child. Fix from
+ * klausr@ITAP.Physik.Uni-Stuttgart.De. The
+ * parent smbd will log to logserver.smb. It
+ * writes only two messages for each child
+ * started/finished. But each child writes,
+ * say, 50 messages also in logserver.smb,
+ * begining with the debug_count of the
+ * parent, before the child opens its own log
+ * file logserver.client. In a worst case
+ * scenario the size of logserver.smb would be
+ * checked after about 50*50=2500 messages
+ * (ca. 100kb).
+ * */
+ force_check_log_size();
+}
+
+static bool smbd_open_one_socket(struct smbd_parent_context *parent,
+ const struct sockaddr_storage *ifss,
+ uint16_t port)
+{
+ struct smbd_open_socket *s;
+
+ s = talloc(parent, struct smbd_open_socket);
+ if (!s) {
+ return false;
+ }
+
+ s->parent = parent;
+ s->fd = open_socket_in(SOCK_STREAM,
+ port,
+ parent->sockets == NULL ? 0 : 2,
+ ifss,
+ true);
+ if (s->fd == -1) {
+ DEBUG(0,("smbd_open_once_socket: open_socket_in: "
+ "%s\n", strerror(errno)));
+ TALLOC_FREE(s);
+ /*
+ * We ignore an error here, as we've done before
+ */
+ return true;
+ }
+
+ /* ready to listen */
+ set_socket_options(s->fd, "SO_KEEPALIVE");
+ set_socket_options(s->fd, lp_socket_options());
+
+ /* Set server socket to
+ * non-blocking for the accept. */
+ set_blocking(s->fd, False);
+
+ if (listen(s->fd, SMBD_LISTEN_BACKLOG) == -1) {
+ DEBUG(0,("open_sockets_smbd: listen: "
+ "%s\n", strerror(errno)));
+ close(s->fd);
+ TALLOC_FREE(s);
+ return false;
+ }
+
+ s->fde = tevent_add_fd(smbd_event_context(),
+ s,
+ s->fd, TEVENT_FD_READ,
+ smbd_accept_connection,
+ s);
+ if (!s->fde) {
+ DEBUG(0,("open_sockets_smbd: "
+ "tevent_add_fd: %s\n",
+ strerror(errno)));
+ close(s->fd);
+ TALLOC_FREE(s);
+ return false;
+ }
+ tevent_fd_set_close_fn(s->fde, smbd_open_socket_close_fn);
+
+ DLIST_ADD_END(parent->sockets, s, struct smbd_open_socket *);
+
+ return true;
+}
+
+static bool parent_housekeeping_fn(const struct timeval *now, void *private_data)
+{
+ DEBUG(5, ("houskeeping\n"));
+ /* check if we need to reload services */
+ check_reload(time(NULL));
+ return true;
+}
+
/****************************************************************************
Open the socket communication.
****************************************************************************/
-static bool open_sockets_smbd(bool is_daemon, bool interactive, const char *smb_ports)
+static bool open_sockets_smbd(struct smbd_parent_context *parent,
+ 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;
char *ports;
- struct dns_reg_state * dns_reg = NULL;
unsigned dns_port = 0;
- if (!is_daemon) {
- return open_sockets_inetd();
- }
-
#ifdef HAVE_ATEXIT
atexit(killkids);
#endif
/* Stop zombies */
- CatchSignal(SIGCLD, sig_cld);
-
- FD_ZERO(&listen_set);
+ smbd_setup_sig_chld_handler();
/* 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);
+ ports = talloc_strdup(talloc_tos(), SMB_PORTS);
} else {
- ports = smb_xstrdup(ports);
+ ports = talloc_strdup(talloc_tos(), ports);
}
} else {
- ports = smb_xstrdup(smb_ports);
+ ports = talloc_strdup(talloc_tos(), smb_ports);
}
if (lp_interfaces() && lp_bind_interfaces_only()) {
/* 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);
char *tok;
continue;
}
- frame = talloc_stackframe();
for (ptr=ports;
- next_token_talloc(frame,&ptr, &tok, " \t,");) {
+ next_token_talloc(talloc_tos(),&ptr, &tok, " \t,");) {
unsigned port = atoi(tok);
if (port == 0 || port > 0xffff) {
continue;
dns_port = port;
}
- s = fd_listenset[num_sockets] =
- open_socket_in(SOCK_STREAM,
- port,
- num_sockets == 0 ? 0 : 2,
- ifss,
- true);
- if(s == -1) {
- continue;
- }
-
- /* ready to listen */
- set_socket_options(s,"SO_KEEPALIVE");
- set_socket_options(s,lp_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);
- TALLOC_FREE(frame);
- 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"));
- TALLOC_FREE(frame);
- return False;
+ if (!smbd_open_one_socket(parent, ifss, port)) {
+ return false;
}
}
- TALLOC_FREE(frame);
}
} else {
/* Just bind to 0.0.0.0 - accept connections
from anywhere. */
- TALLOC_CTX *frame = talloc_stackframe();
char *tok;
const char *ptr;
const char *sock_addr = lp_socket_address();
}
for (sock_ptr=sock_addr;
- next_token_talloc(frame, &sock_ptr, &sock_tok, " \t,"); ) {
- for (ptr=ports; next_token_talloc(frame, &ptr, &tok, " \t,"); ) {
+ next_token_talloc(talloc_tos(), &sock_ptr, &sock_tok, " \t,"); ) {
+ for (ptr=ports; next_token_talloc(talloc_tos(), &ptr, &tok, " \t,"); ) {
struct sockaddr_storage ss;
unsigned port = atoi(tok);
continue;
}
- s = open_socket_in(SOCK_STREAM,
- port,
- num_sockets == 0 ? 0 : 2,
- &ss,
- true);
- if (s == -1) {
- continue;
- }
-
- /* ready to listen */
- set_socket_options(s,"SO_KEEPALIVE");
- set_socket_options(s,lp_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);
- TALLOC_FREE(frame);
- 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"));
- TALLOC_FREE(frame);
- return False;
+ if (!smbd_open_one_socket(parent, &ss, port)) {
+ return false;
}
}
}
- TALLOC_FREE(frame);
}
- SAFE_FREE(ports);
-
- if (num_sockets == 0) {
+ if (parent->sockets == NULL) {
DEBUG(0,("open_sockets_smbd: No "
"sockets available to bind to.\n"));
return false;
claim_connection(NULL,"",
FLAG_MSG_GENERAL|FLAG_MSG_SMBD|FLAG_MSG_DBWRAP);
+ if (!(event_add_idle(smbd_event_context(), NULL,
+ timeval_set(SMBD_HOUSEKEEPING_INTERVAL, 0),
+ "parent_housekeeping", parent_housekeeping_fn,
+ parent))) {
+ DEBUG(0, ("Could not add housekeeping event\n"));
+ exit(1);
+ }
+
/* Listen to messages */
messaging_register(smbd_messaging_context(), NULL,
MSG_SMB_CONF_UPDATED, smb_conf_updated);
messaging_register(smbd_messaging_context(), NULL,
MSG_SMB_STAT_CACHE_DELETE, smb_stat_cache_delete);
+ messaging_register(smbd_messaging_context(), NULL,
+ MSG_DEBUG, smbd_msg_debug);
brl_register_msgs(smbd_messaging_context());
#ifdef CLUSTER_SUPPORT
MSG_SMB_INJECT_FAULT, msg_inject_fault);
#endif
- /* now accept incoming connections - forking a new process
- for each incoming connection */
- DEBUG(2,("waiting for a connection\n"));
- while (1) {
- struct timeval now, idle_timeout;
- 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();
-
- memcpy((char *)&r_fds, (char *)&listen_set,
- sizeof(listen_set));
- 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);
-
- num = sys_select(maxfd+1,&r_fds,&w_fds,NULL,
- timeval_is_zero(&idle_timeout) ?
- NULL : &idle_timeout);
+ if (dns_port != 0) {
+#ifdef WITH_DNSSD_SUPPORT
+ smbd_setup_mdns_registration(smbd_event_context(),
+ parent, dns_port);
+#endif
+#ifdef WITH_AVAHI_SUPPORT
+ void *avahi_conn;
- if (run_events(smbd_event_context(), num, &r_fds, &w_fds)) {
- continue;
+ avahi_conn = avahi_start_register(
+ smbd_event_context(), smbd_event_context(), dns_port);
+ if (avahi_conn == NULL) {
+ DEBUG(10, ("avahi_start_register failed\n"));
}
+#endif
+ }
- 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;
- }
-
- continue;
- }
-
+ return true;
+}
- /* 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");
- }
+static void smbd_parent_loop(struct smbd_parent_context *parent)
+{
+ /* now accept incoming connections - forking a new process
+ for each incoming connection */
+ DEBUG(2,("waiting for connections\n"));
+ while (1) {
+ int ret;
+ TALLOC_CTX *frame = talloc_stackframe();
- /* process pending nDNS responses */
- if (dns_register_smbd_reply(dns_reg, &r_fds, &idle_timeout)) {
- --num;
+ ret = tevent_loop_once(smbd_event_context());
+ if (ret != 0) {
+ exit_server_cleanly("tevent_loop_once() error");
}
- /* check if we need to reload services */
- check_reload(time(NULL));
-
- /* Find the sockets that are read-ready -
- accept on these. */
- for( ; num > 0; num--) {
- struct sockaddr addr;
- socklen_t in_addrlen = sizeof(addr);
- pid_t child = 0;
-
- s = -1;
- for(i = 0; i < num_sockets; i++) {
- 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],&r_fds);
- break;
- }
- }
-
- smbd_set_server_fd(accept(s,&addr,&in_addrlen));
-
- if (smbd_server_fd() == -1 && errno == EINTR)
- continue;
-
- if (smbd_server_fd() == -1) {
- DEBUG(2,("open_sockets_smbd: accept: %s\n",
- strerror(errno)));
- continue;
- }
-
- /* Ensure child is set to blocking mode */
- set_blocking(smbd_server_fd(),True);
-
- if (smbd_server_fd() != -1 && 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
- * them, counting worker smbds. */
- CatchChild();
-
- /* close the listening socket(s) */
- 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);
- 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(),
- true)) {
- DEBUG(0,("reinit_after_fork() failed\n"));
- smb_panic("reinit_after_fork() failed");
- }
-
- return True;
- }
- /* The parent doesn't need this socket */
- close(smbd_server_fd());
-
- /* Sun May 6 18:56:14 2001 ackley@cs.unm.edu:
- Clear the closed fd info out of server_fd --
- and more importantly, out of client_fd in
- util_sock.c, to avoid a possible
- getpeername failure if we reopen the logs
- and use %I in the filename.
- */
-
- smbd_set_server_fd(-1);
-
- if (child != 0) {
- add_child_pid(child);
- }
-
- /* Force parent to check log size after
- * spawning child. Fix from
- * klausr@ITAP.Physik.Uni-Stuttgart.De. The
- * parent smbd will log to logserver.smb. It
- * writes only two messages for each child
- * started/finished. But each child writes,
- * say, 50 messages also in logserver.smb,
- * begining with the debug_count of the
- * parent, before the child opens its own log
- * file logserver.client. In a worst case
- * scenario the size of logserver.smb would be
- * checked after about 50*50=2500 messages
- * (ca. 100kb).
- * */
- force_check_log_size();
-
- } /* end for num */
+ TALLOC_FREE(frame);
} /* end while 1 */
/* NOTREACHED return True; */
}
-/****************************************************************************
- Reload printers
-**************************************************************************/
+/***************************************************************************
+ purge stale printers and reload from pre-populated pcap cache
+***************************************************************************/
void reload_printers(void)
{
int snum;
int pnum = lp_servicenumber(PRINTERS_NAME);
const char *pname;
- pcap_cache_reload();
-
- /* remove stale printers */
+ DEBUG(10, ("reloading printer services from pcap cache\n"));
for (snum = 0; snum < n_services; snum++) {
/* avoid removing PRINTERS_NAME or non-autoloaded printers */
if (snum == pnum || !(lp_snum_ok(snum) && lp_print_ok(snum) &&
DEBUG(3, ("removing stale printer %s\n", pname));
if (is_printer_published(NULL, snum, NULL))
- nt_printer_publish(NULL, snum, SPOOL_DS_UNPUBLISH);
+ nt_printer_publish(NULL, snum, DSPRINT_UNPUBLISH);
del_a_printer(pname);
lp_killservice(snum);
}
set_dyn_CONFIGFILE(fname);
test = False;
}
+ TALLOC_FREE(fname);
}
reopen_logs();
ret = lp_load(get_dyn_CONFIGFILE(), False, False, True, True);
- reload_printers();
+ pcap_cache_reload(&reload_printers);
/* perhaps the config filename is now set */
if (!test)
static void exit_server_common(enum server_exit_reason how,
const char *const reason)
{
- bool had_open_conn;
+ bool had_open_conn = false;
+ struct smbd_server_connection *sconn = smbd_server_conn;
if (!exit_firsttime)
exit(0);
change_to_root_user();
- if (negprot_global_auth_context) {
- (negprot_global_auth_context->free)(&negprot_global_auth_context);
+ if (sconn && sconn->smb1.negprot.auth_context) {
+ struct auth_context *a = sconn->smb1.negprot.auth_context;
+ a->free(&sconn->smb1.negprot.auth_context);
}
- had_open_conn = conn_close_all();
-
- invalidate_all_vuids();
+ if (sconn) {
+ had_open_conn = conn_close_all(sconn);
+ invalidate_all_vuids(sconn);
+ }
/* 3 second timeout. */
print_notify_send_messages(smbd_messaging_context(), 3);
/* delete our entry in the connections database. */
yield_connection(NULL,"");
- respond_to_all_remaining_local_messages();
-
#ifdef WITH_DFS
if (dcelogin_atmost_once) {
dfs_unlogin();
locking_end();
printing_end();
+ /*
+ * we need to force the order of freeing the following,
+ * because smbd_msg_ctx is not a talloc child of smbd_server_conn.
+ */
+ sconn = NULL;
+ TALLOC_FREE(smbd_server_conn);
+ TALLOC_FREE(smbd_msg_ctx);
+ TALLOC_FREE(smbd_event_ctx);
+
if (how != SERVER_EXIT_NORMAL) {
int oldlevel = DEBUGLEVEL;
} else {
DEBUG(3,("Server exit (%s)\n",
(reason ? reason : "normal exit")));
+ if (am_parent) {
+ pidfile_unlink();
+ }
+ gencache_stabilize();
}
/* if we had any open SMB connections when we exited then we
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.
****************************************************************************/
if (!init_names())
return False;
- conn_init();
-
file_init();
- init_dptrs();
-
if (!secrets_init())
return False;
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.
****************************************************************************/
POPT_COMMON_DYNCONFIG
POPT_TABLEEND
};
+ struct smbd_parent_context *parent = NULL;
TALLOC_CTX *frame = talloc_stackframe(); /* Setup tos. */
smbd_init_globals();
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);
BlockSignals(False, SIGUSR1);
BlockSignals(False, SIGTERM);
+ /* Ensure we leave no zombies until we
+ * correctly set up child handling below. */
+
+ CatchChild();
+
/* we want total control over the permissions on created files,
so set our umask to 0 */
umask(0);
if (is_daemon)
pidfile_create("smbd");
- if (!reinit_after_fork(smbd_messaging_context(),
- smbd_event_context(), false)) {
+ if (!NT_STATUS_IS_OK(reinit_after_fork(smbd_messaging_context(),
+ smbd_event_context(), false))) {
DEBUG(0,("reinit_after_fork() failed\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) {
return -1;
}
+ /* Open the share_info.tdb here, so we don't have to open
+ after the fork on every single connection. This is a small
+ performance improvment and reduces the total number of system
+ fds used. */
+ if (!share_info_db_init()) {
+ DEBUG(0,("ERROR: failed to load share info db.\n"));
+ exit(1);
+ }
+
/* 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
start_background_queue();
}
- 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 (!is_daemon) {
+ /* inetd mode */
+ TALLOC_FREE(frame);
- if (*lp_rootdir()) {
- if (chroot(lp_rootdir()) == 0)
- DEBUG(2,("Changed root to %s\n", lp_rootdir()));
- }
+ /* Started from inetd. fd 0 is the socket. */
+ /* We will abort gracefully when the client or remote system
+ goes away */
+ smbd_set_server_fd(dup(0));
- /* Setup oplocks */
- if (!init_oplocks(smbd_messaging_context()))
- exit(1);
+ /* close our standard file descriptors */
+ close_low_fds(False); /* Don't close stderr */
- /* Setup aio signal handler. */
- initialize_async_io_handler();
+#ifdef HAVE_ATEXIT
+ atexit(killkids);
+#endif
- /* 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);
- }
+ /* Stop zombies */
+ smbd_setup_sig_chld_handler();
- 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);
- }
+ smbd_process();
- 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);
+ exit_server_cleanly(NULL);
+ return(0);
}
-#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(),
- &srv, &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)));
- }
+ parent = talloc_zero(smbd_event_context(), struct smbd_parent_context);
+ if (!parent) {
+ exit_server("talloc(struct smbd_parent_context) failed");
}
+ parent->interactive = interactive;
-#endif
+ if (!open_sockets_smbd(parent, ports))
+ exit_server("open_sockets_smbd() failed");
TALLOC_FREE(frame);
+ /* make sure we always have a valid stackframe */
+ frame = talloc_stackframe();
- smbd_process();
-
- namecache_shutdown();
+ smbd_parent_loop(parent);
exit_server_cleanly(NULL);
+ TALLOC_FREE(frame);
return(0);
}