#include "secrets.h"
#include "memcache.h"
#include "ctdbd_conn.h"
-#include "printing/printer_list.h"
+#include "printing/queue_process.h"
#include "rpc_server/rpc_service_setup.h"
-#include "printing/pcap.h"
-#include "printing.h"
+#include "rpc_server/rpc_config.h"
#include "serverid.h"
#include "passdb.h"
#include "auth.h"
#include "messages.h"
#include "smbprofile.h"
+#include "lib/id_cache.h"
+#include "lib/param/param.h"
+
+struct smbd_open_socket;
+struct smbd_child_pid;
+
+struct smbd_parent_context {
+ bool interactive;
+
+ struct tevent_context *ev_ctx;
+ struct messaging_context *msg_ctx;
+
+ /* the list of listening sockets */
+ struct smbd_open_socket *sockets;
+
+ /* the list of current child processes */
+ struct smbd_child_pid *children;
+ size_t num_children;
+
+ struct timed_event *cleanup_te;
+};
+
+struct smbd_open_socket {
+ struct smbd_open_socket *prev, *next;
+ struct smbd_parent_context *parent;
+ int fd;
+ struct tevent_fd *fde;
+};
+
+struct smbd_child_pid {
+ struct smbd_child_pid *prev, *next;
+ pid_t pid;
+};
extern void start_epmd(struct tevent_context *ev_ctx,
struct messaging_context *msg_ctx);
-extern void start_spoolssd(struct event_context *ev_ctx,
- struct messaging_context *msg_ctx);
+extern void start_lsasd(struct event_context *ev_ctx,
+ struct messaging_context *msg_ctx);
#ifdef WITH_DFS
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);
- 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, smbd_server_conn->sock, False);
- if (am_parent) {
- pcap_cache_reload(ev_ctx, msg,
- &reload_pcap_change_notify);
- }
+ reload_services(NULL, NULL, false);
+ printing_subsystem_update(ev_ctx, msg, false);
}
/*******************************************************************
DEBUG(10,("Got message saying pcap was updated. Reloading.\n"));
change_to_root_user();
- reload_printers(ev_ctx, msg);
+ delete_and_reload_printers(ev_ctx, msg);
}
/*******************************************************************
if(am_parent) kill(0,SIGTERM);
}
-/****************************************************************************
- Process a sam sync message - not sure whether to do this here or
- somewhere else.
-****************************************************************************/
-
-static void msg_sam_sync(struct messaging_context *msg,
- void *private_data,
- uint32_t msg_type,
- struct server_id server_id,
- DATA_BLOB *data)
-{
- DEBUG(10, ("** sam sync message received, ignoring\n"));
-}
-
static void msg_exit_server(struct messaging_context *msg,
void *private_data,
uint32_t msg_type,
}
#endif /* DEVELOPER */
+NTSTATUS messaging_send_to_children(struct messaging_context *msg_ctx,
+ uint32_t msg_type, DATA_BLOB* data)
+{
+ NTSTATUS status;
+ struct smbd_parent_context *parent = am_parent;
+ struct smbd_child_pid *child;
+
+ if (parent == NULL) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ for (child = parent->children; child != NULL; child = child->next) {
+ status = messaging_send(parent->msg_ctx,
+ pid_to_procid(child->pid),
+ msg_type, data);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+ return NT_STATUS_OK;
+}
+
/*
* Parent smbd process sets its own debug level first and then
* sends a message to all the smbd children to adjust their debug
struct server_id server_id,
DATA_BLOB *data)
{
- struct child_pid *child;
-
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);
+ 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 add_child_pid(pid_t pid)
+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)
{
- struct child_pid *child;
+ id_cache_delete_message(ctx, data, msg_type, srv_id, msg_data);
- child = SMB_MALLOC_P(struct child_pid);
+ messaging_send_to_children(ctx, msg_type, msg_data);
+}
+
+static void add_child_pid(struct smbd_parent_context *parent,
+ pid_t pid)
+{
+ struct smbd_child_pid *child;
+
+ child = talloc_zero(parent, struct smbd_child_pid);
if (child == NULL) {
DEBUG(0, ("Could not add child struct -- malloc failed\n"));
return;
}
child->pid = pid;
- DLIST_ADD(children, child);
- num_children += 1;
+ DLIST_ADD(parent->children, child);
+ parent->num_children += 1;
}
/*
struct timeval now,
void *private_data)
{
- struct timed_event **cleanup_te = (struct timed_event **)private_data;
+ struct smbd_parent_context *parent =
+ talloc_get_type_abort(private_data,
+ struct smbd_parent_context);
+
+ parent->cleanup_te = NULL;
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;
+ message_send_all(parent->msg_ctx, MSG_SMB_UNLOCK, NULL, 0, NULL);
+ messaging_send_buf(parent->msg_ctx,
+ messaging_server_id(parent->msg_ctx),
+ MSG_SMB_BRL_VALIDATE, NULL, 0);
}
-static void remove_child_pid(struct tevent_context *ev_ctx,
+static void remove_child_pid(struct smbd_parent_context *parent,
pid_t pid,
bool unclean_shutdown)
{
- struct child_pid *child;
- static struct timed_event *cleanup_te;
+ struct smbd_child_pid *child;
struct server_id child_id;
if (unclean_shutdown) {
*/
DEBUG(3,(__location__ " Unclean shutdown of pid %u\n",
(unsigned int)pid));
- if (!cleanup_te) {
+ if (parent->cleanup_te == NULL) {
/* call the cleanup timer, but not too often */
int cleanup_time = lp_parm_int(-1, "smbd", "cleanuptime", 20);
- cleanup_te = event_add_timed(ev_ctx, NULL,
+ parent->cleanup_te = tevent_add_timer(parent->ev_ctx,
+ parent,
timeval_current_ofs(cleanup_time, 0),
cleanup_timeout_fn,
- &cleanup_te);
+ parent);
DEBUG(1,("Scheduled cleanup of brl and lock database after unclean shutdown\n"));
}
}
- child_id = procid_self(); /* Just initialize pid and potentially vnn */
- child_id.pid = pid;
+ child_id = pid_to_procid(pid);
if (!serverid_deregister(child_id)) {
DEBUG(1, ("Could not remove pid %d from serverid.tdb\n",
(int)pid));
}
- for (child = children; child != NULL; child = child->next) {
+ for (child = parent->children; child != NULL; child = child->next) {
if (child->pid == pid) {
- struct child_pid *tmp = child;
- DLIST_REMOVE(children, child);
- SAFE_FREE(tmp);
- num_children -= 1;
+ struct smbd_child_pid *tmp = child;
+ DLIST_REMOVE(parent->children, child);
+ TALLOC_FREE(tmp);
+ parent->num_children -= 1;
return;
}
}
Have we reached the process limit ?
****************************************************************************/
-static bool allowable_number_of_smbd_processes(void)
+static bool allowable_number_of_smbd_processes(struct smbd_parent_context *parent)
{
int max_processes = lp_max_smbd_processes();
if (!max_processes)
return True;
- return num_children < max_processes;
+ return parent->num_children < max_processes;
}
static void smbd_sig_chld_handler(struct tevent_context *ev,
{
pid_t pid;
int status;
+ struct smbd_parent_context *parent =
+ talloc_get_type_abort(private_data,
+ struct smbd_parent_context);
while ((pid = sys_waitpid(-1, &status, WNOHANG)) > 0) {
bool unclean_shutdown = False;
if (WIFSIGNALED(status)) {
unclean_shutdown = True;
}
- remove_child_pid(ev, pid, unclean_shutdown);
+ remove_child_pid(parent, pid, unclean_shutdown);
}
}
-static void smbd_setup_sig_chld_handler(struct tevent_context *ev_ctx)
+static void smbd_setup_sig_chld_handler(struct smbd_parent_context *parent)
{
struct tevent_signal *se;
- se = tevent_add_signal(ev_ctx,
- ev_ctx, /* mem_ctx */
+ se = tevent_add_signal(parent->ev_ctx,
+ parent, /* mem_ctx */
SIGCHLD, 0,
smbd_sig_chld_handler,
- NULL);
+ parent);
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;
- struct messaging_context *msg_ctx;
-};
-
static void smbd_open_socket_close_fn(struct tevent_context *ev,
struct tevent_fd *fde,
int fd,
uint16_t flags,
void *private_data)
{
- struct smbd_server_connection *sconn = smbd_server_conn;
struct smbd_open_socket *s = talloc_get_type_abort(private_data,
struct smbd_open_socket);
- struct messaging_context *msg_ctx = s->msg_ctx;
+ struct messaging_context *msg_ctx = s->parent->msg_ctx;
+ struct smbd_server_connection *sconn = smbd_server_conn;
struct sockaddr_storage addr;
socklen_t in_addrlen = sizeof(addr);
int fd;
}
if (s->parent->interactive) {
- smbd_process(sconn);
+ smbd_process(ev, sconn);
exit_server_cleanly("end of interactive mode");
return;
}
- if (!allowable_number_of_smbd_processes()) {
+ if (!allowable_number_of_smbd_processes(s->parent)) {
close(fd);
sconn->sock = -1;
return;
NTSTATUS status = NT_STATUS_OK;
/* Child code ... */
- am_parent = 0;
+ am_parent = NULL;
+
+ /*
+ * 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;
set_my_unique_id(unique_id);
close_low_fds(False); /* Don't close stderr */
}
- /*
- * 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(msg_ctx,
ev,
- procid_self(),
true);
if (!NT_STATUS_IS_OK(status)) {
if (NT_STATUS_EQUAL(status,
smb_panic("reinit_after_fork() failed");
}
- smbd_setup_sig_term_handler();
- smbd_setup_sig_hup_handler(ev,
- msg_ctx);
+ smbd_setup_sig_term_handler(sconn);
+ smbd_setup_sig_hup_handler(sconn);
- if (!serverid_register(procid_self(),
+ if (!serverid_register(messaging_server_id(msg_ctx),
FLAG_MSG_GENERAL|FLAG_MSG_SMBD
|FLAG_MSG_DBWRAP
|FLAG_MSG_PRINT_GENERAL)) {
"serverid.tdb");
}
- smbd_process(smbd_server_conn);
+ smbd_process(ev, sconn);
exit:
exit_server_cleanly("end of child");
return;
sconn->sock = -1;
if (pid != 0) {
- add_child_pid(pid);
+ add_child_pid(s->parent, pid);
}
/* Force parent to check log size after
return false;
}
- s->msg_ctx = msg_ctx;
s->fde = tevent_add_fd(ev_ctx,
s,
s->fd, TEVENT_FD_READ,
return true;
}
-static bool smbd_parent_housekeeping(const struct timeval *now, void *private_data)
-{
- struct messaging_context *msg_ctx =
- talloc_get_type_abort(private_data, struct messaging_context);
- time_t printcap_cache_time = (time_t)lp_printcap_cache_time();
- time_t t = time_mono(NULL);
-
- DEBUG(5, ("parent housekeeping\n"));
-
- /* if periodic printcap rescan is enabled, see if it's time to reload */
- if ((printcap_cache_time != 0)
- && (t >= (last_printer_reload_time + printcap_cache_time))) {
- DEBUG( 3,( "Printcap cache time expired.\n"));
- pcap_cache_reload(messaging_event_context(msg_ctx),
- msg_ctx,
- &reload_pcap_change_notify);
- last_printer_reload_time = t;
- }
-
- return true;
-}
-
/****************************************************************************
Open the socket communication.
****************************************************************************/
#endif
/* Stop zombies */
- smbd_setup_sig_chld_handler(ev_ctx);
+ smbd_setup_sig_chld_handler(parent);
/* use a reasonable default set of ports - listing on 445 and 139 */
if (!smb_ports) {
operations until it has gone thru a full startup, which
includes checking to see that smbd is listening. */
- if (!serverid_register(procid_self(),
+ if (!serverid_register(messaging_server_id(msg_ctx),
FLAG_MSG_GENERAL|FLAG_MSG_SMBD
+ |FLAG_MSG_PRINT_GENERAL
|FLAG_MSG_DBWRAP)) {
DEBUG(0, ("open_sockets_smbd: Failed to register "
"myself in serverid.tdb\n"));
return false;
}
- if (!(event_add_idle(ev_ctx, NULL,
- timeval_set(SMBD_HOUSEKEEPING_INTERVAL, 0),
- "parent_housekeeping", smbd_parent_housekeeping,
- msg_ctx))) {
- DEBUG(0, ("Could not add parent_housekeeping event\n"));
- return false;
- }
-
/* Listen to messages */
- messaging_register(msg_ctx, NULL, MSG_SMB_SAM_SYNC, msg_sam_sync);
messaging_register(msg_ctx, NULL, MSG_SHUTDOWN, msg_exit_server);
- messaging_register(msg_ctx, NULL, MSG_SMB_FILE_RENAME,
- msg_file_was_renamed);
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);
+ messaging_register(msg_ctx, NULL, MSG_SMB_BRL_VALIDATE,
+ brl_revalidate);
- msg_idmap_register_msgs(msg_ctx);
+ 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()) {
return True;
}
+static void smbd_parent_sig_term_handler(struct tevent_context *ev,
+ struct tevent_signal *se,
+ int signum,
+ int count,
+ void *siginfo,
+ void *private_data)
+{
+ exit_server_cleanly("termination signal");
+}
+
+static void smbd_parent_sig_hup_handler(struct tevent_context *ev,
+ struct tevent_signal *se,
+ int signum,
+ int count,
+ void *siginfo,
+ void *private_data)
+{
+ struct smbd_parent_context *parent =
+ talloc_get_type_abort(private_data,
+ struct smbd_parent_context);
+
+ change_to_root_user();
+ DEBUG(1,("parent: Reloading services after SIGHUP\n"));
+ reload_services(NULL, NULL, false);
+
+ printing_subsystem_update(parent->ev_ctx, parent->msg_ctx, true);
+}
+
/****************************************************************************
main program.
****************************************************************************/
uint64_t unique_id;
struct tevent_context *ev_ctx;
struct messaging_context *msg_ctx;
+ struct tevent_signal *se;
/*
* Do this before any other talloc operation
* 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);
}
status = reinit_after_fork(msg_ctx,
ev_ctx,
- procid_self(), false);
+ false);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("reinit_after_fork() failed\n"));
exit(1);
smbd_server_conn->msg_ctx = msg_ctx;
- smbd_setup_sig_term_handler();
- smbd_setup_sig_hup_handler(ev_ctx,
- msg_ctx);
+ parent = talloc_zero(ev_ctx, struct smbd_parent_context);
+ if (!parent) {
+ exit_server("talloc(struct smbd_parent_context) failed");
+ }
+ parent->interactive = interactive;
+ parent->ev_ctx = ev_ctx;
+ parent->msg_ctx = msg_ctx;
+ am_parent = parent;
+
+ se = tevent_add_signal(parent->ev_ctx,
+ parent,
+ SIGTERM, 0,
+ smbd_parent_sig_term_handler,
+ parent);
+ if (!se) {
+ exit_server("failed to setup SIGTERM handler");
+ }
+ se = tevent_add_signal(parent->ev_ctx,
+ parent,
+ SIGHUP, 0,
+ smbd_parent_sig_hup_handler,
+ parent);
+ if (!se) {
+ exit_server("failed to setup SIGHUP handler");
+ }
/* Setup all the TDB's - including CLEAR_IF_FIRST tdb's. */
}
if (lp_server_role() == ROLE_DOMAIN_BDC || lp_server_role() == ROLE_DOMAIN_PDC) {
- if (!open_schannel_session_store(NULL, lp_private_dir())) {
+ struct loadparm_context *lp_ctx = loadparm_init_s3(NULL, loadparm_s3_context());
+ if (!open_schannel_session_store(NULL, lp_ctx)) {
DEBUG(0,("ERROR: Samba cannot open schannel store for secured NETLOGON operations.\n"));
exit(1);
}
+ TALLOC_FREE(lp_ctx);
}
if(!get_global_sam_sid()) {
exit(1);
}
- if (!printer_list_parent_init()) {
- exit(1);
- }
-
if (!W_ERROR_IS_OK(registry_init_full()))
exit(1);
- if (!print_backend_init(msg_ctx))
- exit(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
return -1;
}
- if (is_daemon && !interactive) {
- enum rpc_service_mode_e epm_mode = rpc_epmapper_mode();
+ /* This MUST be done before start_epmd() because otherwise
+ * start_epmd() forks and races against dcesrv_ep_setup() to
+ * call directory_create_or_exist() */
+ if (!directory_create_or_exist(lp_ncalrpc_dir(), geteuid(), 0755)) {
+ DEBUG(0, ("Failed to create pipe directory %s - %s\n",
+ lp_ncalrpc_dir(), strerror(errno)));
+ return -1;
+ }
- if (epm_mode == RPC_SERVICE_MODE_DAEMON) {
+ if (is_daemon && !interactive) {
+ if (rpc_epmapper_daemon() == RPC_DAEMON_FORK) {
start_epmd(ev_ctx, msg_ctx);
}
}
exit(1);
}
- /* Publish nt printers, this requires a working winreg pipe */
- pcap_cache_reload(ev_ctx, msg_ctx, &reload_printers);
-
- /* 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 */
+ /* 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 */
+ if (is_daemon && !interactive) {
- if (is_daemon && !interactive
- && lp_parm_bool(-1, "smbd", "backgroundqueue", true)) {
- start_background_queue(ev_ctx, msg_ctx);
- }
+ if (rpc_lsasd_daemon() == RPC_DAEMON_FORK) {
+ start_lsasd(ev_ctx, msg_ctx);
+ }
- if (is_daemon && !_lp_disable_spoolss()) {
- const char *rpcsrv_type;
+ if (!_lp_disable_spoolss() &&
+ (rpc_spoolss_daemon() != RPC_DAEMON_DISABLED)) {
+ bool bgq = lp_parm_bool(-1, "smbd", "backgroundqueue", true);
- /* start spoolss daemon */
- /* start as a separate daemon only if enabled */
- rpcsrv_type = lp_parm_const_string(GLOBAL_SECTION_SNUM,
- "rpc_server", "spoolss",
- "embedded");
- if (strcasecmp_m(rpcsrv_type, "daemon") == 0) {
- start_spoolssd(ev_ctx, msg_ctx);
+ if (!printing_subsystem_init(ev_ctx, msg_ctx, true, bgq)) {
+ exit(1);
+ }
+ }
+ } else if (!_lp_disable_spoolss() &&
+ (rpc_spoolss_daemon() != RPC_DAEMON_DISABLED)) {
+ if (!printing_subsystem_init(ev_ctx, msg_ctx, false, false)) {
+ exit(1);
}
}
#endif
/* Stop zombies */
- smbd_setup_sig_chld_handler(ev_ctx);
+ smbd_setup_sig_chld_handler(parent);
- smbd_process(smbd_server_conn);
+ smbd_process(ev_ctx, smbd_server_conn);
exit_server_cleanly(NULL);
return(0);
}
- parent = talloc_zero(ev_ctx, struct smbd_parent_context);
- if (!parent) {
- exit_server("talloc(struct smbd_parent_context) failed");
- }
- parent->interactive = interactive;
-
if (!open_sockets_smbd(parent, ev_ctx, msg_ctx, ports))
exit_server("open_sockets_smbd() failed");
+ /* do a printer update now that all messaging has been set up,
+ * before we allow clients to start connecting */
+ printing_subsystem_update(ev_ctx, msg_ctx, false);
+
TALLOC_FREE(frame);
/* make sure we always have a valid stackframe */
frame = talloc_stackframe();