diff options
Diffstat (limited to 'source4/smbd/server.c')
-rw-r--r-- | source4/smbd/server.c | 372 |
1 files changed, 372 insertions, 0 deletions
diff --git a/source4/smbd/server.c b/source4/smbd/server.c new file mode 100644 index 0000000000..5bd5568913 --- /dev/null +++ b/source4/smbd/server.c @@ -0,0 +1,372 @@ +/* + Unix SMB/CIFS implementation. + + Main SMB server routines + + Copyright (C) Andrew Tridgell 1992-2005 + Copyright (C) Martin Pool 2002 + Copyright (C) Jelmer Vernooij 2002 + Copyright (C) James J Myers 2003 <myersjj@samba.org> + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "lib/events/events.h" +#include "version.h" +#include "lib/cmdline/popt_common.h" +#include "system/dir.h" +#include "system/filesys.h" +#include "ldb/include/ldb.h" +#include "registry/registry.h" +#include "ntvfs/ntvfs.h" +#include "ntptr/ntptr.h" +#include "auth/gensec/gensec.h" +#include "smbd/process_model.h" +#include "smbd/service.h" +#include "param/secrets.h" +#include "smbd/pidfile.h" +#include "cluster/ctdb/ctdb_cluster.h" +#include "param/param.h" + +/* + recursively delete a directory tree +*/ +static void recursive_delete(const char *path) +{ + DIR *dir; + struct dirent *de; + + dir = opendir(path); + if (!dir) { + return; + } + + for (de=readdir(dir);de;de=readdir(dir)) { + char *fname; + struct stat st; + + if (ISDOT(de->d_name) || ISDOTDOT(de->d_name)) { + continue; + } + + fname = talloc_asprintf(path, "%s/%s", path, de->d_name); + if (stat(fname, &st) != 0) { + continue; + } + if (S_ISDIR(st.st_mode)) { + recursive_delete(fname); + talloc_free(fname); + continue; + } + if (unlink(fname) != 0) { + DEBUG(0,("Unabled to delete '%s' - %s\n", + fname, strerror(errno))); + smb_panic("unable to cleanup tmp files"); + } + talloc_free(fname); + } + closedir(dir); +} + +/* + cleanup temporary files. This is the new alternative to + TDB_CLEAR_IF_FIRST. Unfortunately TDB_CLEAR_IF_FIRST is not + efficient on unix systems due to the lack of scaling of the byte + range locking system. So instead of putting the burden on tdb to + cleanup tmp files, this function deletes them. +*/ +static void cleanup_tmp_files(struct loadparm_context *lp_ctx) +{ + char *path; + TALLOC_CTX *mem_ctx = talloc_new(NULL); + + path = smbd_tmp_path(mem_ctx, lp_ctx, NULL); + + recursive_delete(path); + talloc_free(mem_ctx); +} + +static void sig_hup(int sig) +{ + debug_schedule_reopen_logs(); +} + +static void sig_term(int sig) +{ +#if HAVE_GETPGRP + static int done_sigterm; + if (done_sigterm == 0 && getpgrp() == getpid()) { + DEBUG(0,("SIGTERM: killing children\n")); + done_sigterm = 1; + kill(-getpgrp(), SIGTERM); + } +#endif + exit(0); +} + +/* + setup signal masks +*/ +static void setup_signals(void) +{ + /* we are never interested in SIGPIPE */ + BlockSignals(true,SIGPIPE); + +#if defined(SIGFPE) + /* we are never interested in SIGFPE */ + BlockSignals(true,SIGFPE); +#endif + + /* We are no longer interested in USR1 */ + BlockSignals(true, SIGUSR1); + +#if defined(SIGUSR2) + /* We are no longer interested in USR2 */ + BlockSignals(true,SIGUSR2); +#endif + + /* POSIX demands that signals are inherited. If the invoking process has + * these signals masked, we will have problems, as we won't recieve them. */ + BlockSignals(false, SIGHUP); + BlockSignals(false, SIGTERM); + + CatchSignal(SIGHUP, sig_hup); + CatchSignal(SIGTERM, sig_term); +} + +/* + handle io on stdin +*/ +static void server_stdin_handler(struct event_context *event_ctx, struct fd_event *fde, + uint16_t flags, void *private) +{ + const char *binary_name = (const char *)private; + uint8_t c; + if (read(0, &c, 1) == 0) { + DEBUG(0,("%s: EOF on stdin - terminating\n", binary_name)); +#if HAVE_GETPGRP + if (getpgrp() == getpid()) { + kill(-getpgrp(), SIGTERM); + } +#endif + exit(0); + } +} + +/* + die if the user selected maximum runtime is exceeded +*/ +_NORETURN_ static void max_runtime_handler(struct event_context *ev, + struct timed_event *te, + struct timeval t, void *private) +{ + const char *binary_name = (const char *)private; + DEBUG(0,("%s: maximum runtime exceeded - terminating\n", binary_name)); + exit(0); +} + +/* + main server. +*/ +static int binary_smbd_main(const char *binary_name, int argc, const char *argv[]) +{ + bool opt_daemon = false; + bool opt_interactive = false; + int opt; + poptContext pc; + extern NTSTATUS server_service_wrepl_init(void); + extern NTSTATUS server_service_kdc_init(void); + extern NTSTATUS server_service_ldap_init(void); + extern NTSTATUS server_service_web_init(void); + extern NTSTATUS server_service_ldap_init(void); + extern NTSTATUS server_service_winbind_init(void); + extern NTSTATUS server_service_nbtd_init(void); + extern NTSTATUS server_service_auth_init(void); + extern NTSTATUS server_service_cldapd_init(void); + extern NTSTATUS server_service_smb_init(void); + extern NTSTATUS server_service_drepl_init(void); + extern NTSTATUS server_service_rpc_init(void); + extern NTSTATUS server_service_ntp_signd_init(void); + init_module_fn static_init[] = { STATIC_smbd_MODULES }; + init_module_fn *shared_init; + struct event_context *event_ctx; + uint16_t stdin_event_flags; + NTSTATUS status; + const char *model = "standard"; + int max_runtime = 0; + enum { + OPT_DAEMON = 1000, + OPT_INTERACTIVE, + OPT_PROCESS_MODEL + }; + struct poptOption long_options[] = { + POPT_AUTOHELP + {"daemon", 'D', POPT_ARG_NONE, NULL, OPT_DAEMON, + "Become a daemon (default)", NULL }, + {"interactive", 'i', POPT_ARG_NONE, NULL, OPT_INTERACTIVE, + "Run interactive (not a daemon)", NULL}, + {"model", 'M', POPT_ARG_STRING, NULL, OPT_PROCESS_MODEL, + "Select process model", "MODEL"}, + {"maximum-runtime",0, POPT_ARG_INT, &max_runtime, 0, + "set maximum runtime of the server process, till autotermination", "seconds"}, + POPT_COMMON_SAMBA + POPT_COMMON_VERSION + { NULL } + }; + + pc = poptGetContext(binary_name, argc, argv, long_options, 0); + while((opt = poptGetNextOpt(pc)) != -1) { + switch(opt) { + case OPT_DAEMON: + opt_daemon = true; + break; + case OPT_INTERACTIVE: + opt_interactive = true; + break; + case OPT_PROCESS_MODEL: + model = poptGetOptArg(pc); + break; + default: + fprintf(stderr, "\nInvalid option %s: %s\n\n", + poptBadOption(pc, 0), poptStrerror(opt)); + poptPrintUsage(pc, stderr, 0); + exit(1); + } + } + + if (opt_daemon && opt_interactive) { + fprintf(stderr,"\nERROR: " + "Option -i|--interactive is not allowed together with -D|--daemon\n\n"); + poptPrintUsage(pc, stderr, 0); + exit(1); + } else if (!opt_interactive) { + /* default is --daemon */ + opt_daemon = true; + } + + poptFreeContext(pc); + + setup_logging(binary_name, opt_interactive?DEBUG_STDOUT:DEBUG_FILE); + setup_signals(); + + /* we want total control over the permissions on created files, + so set our umask to 0 */ + umask(0); + + DEBUG(0,("%s version %s started.\n", binary_name, SAMBA_VERSION_STRING)); + DEBUGADD(0,("Copyright Andrew Tridgell and the Samba Team 1992-2008\n")); + + if (sizeof(uint16_t) < 2 || sizeof(uint32_t) < 4 || sizeof(uint64_t) < 8) { + DEBUG(0,("ERROR: Samba is not configured correctly for the word size on your machine\n")); + DEBUGADD(0,("sizeof(uint16_t) = %u, sizeof(uint32_t) %u, sizeof(uint64_t) = %u\n", + (unsigned int)sizeof(uint16_t), (unsigned int)sizeof(uint32_t), (unsigned int)sizeof(uint64_t))); + exit(1); + } + + if (opt_daemon) { + DEBUG(3,("Becoming a daemon.\n")); + become_daemon(true); + } + + cleanup_tmp_files(cmdline_lp_ctx); + + if (!directory_exist(lp_lockdir(cmdline_lp_ctx))) { + mkdir(lp_lockdir(cmdline_lp_ctx), 0755); + } + + pidfile_create(lp_piddir(cmdline_lp_ctx), binary_name); + + /* Do *not* remove this, until you have removed + * passdb/secrets.c, and proved that Samba still builds... */ + /* Setup the SECRETS subsystem */ + if (secrets_init(talloc_autofree_context(), cmdline_lp_ctx) == NULL) { + exit(1); + } + + gensec_init(cmdline_lp_ctx); /* FIXME: */ + + ntptr_init(cmdline_lp_ctx); /* FIXME: maybe run this in the initialization function + of the spoolss RPC server instead? */ + + ntvfs_init(cmdline_lp_ctx); /* FIXME: maybe run this in the initialization functions + of the SMB[,2] server instead? */ + + process_model_init(cmdline_lp_ctx); + + shared_init = load_samba_modules(NULL, cmdline_lp_ctx, "service"); + + run_init_functions(static_init); + run_init_functions(shared_init); + + talloc_free(shared_init); + + /* the event context is the top level structure in smbd. Everything else + should hang off that */ + event_ctx = s4_event_context_init(talloc_autofree_context()); + + if (event_ctx == NULL) { + DEBUG(0,("Initializing event context failed\n")); + return 1; + } + + /* initialise clustering if needed */ + cluster_ctdb_init(cmdline_lp_ctx, event_ctx, model); + + if (opt_interactive) { + /* terminate when stdin goes away */ + stdin_event_flags = EVENT_FD_READ; + } else { + /* stay alive forever */ + stdin_event_flags = 0; + } + + /* catch EOF on stdin */ +#ifdef SIGTTIN + signal(SIGTTIN, SIG_IGN); +#endif + event_add_fd(event_ctx, event_ctx, 0, stdin_event_flags, + server_stdin_handler, + discard_const(binary_name)); + + if (max_runtime) { + event_add_timed(event_ctx, event_ctx, + timeval_current_ofs(max_runtime, 0), + max_runtime_handler, + discard_const(binary_name)); + } + + DEBUG(0,("%s: using '%s' process model\n", binary_name, model)); + status = server_service_startup(event_ctx, cmdline_lp_ctx, model, + lp_server_services(cmdline_lp_ctx)); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("Starting Services failed - %s\n", nt_errstr(status))); + return 1; + } + + /* wait for events - this is where smbd sits for most of its + life */ + event_loop_wait(event_ctx); + + /* as everything hangs off this event context, freeing it + should initiate a clean shutdown of all services */ + talloc_free(event_ctx); + + return 0; +} + + int main(int argc, const char *argv[]) +{ + return binary_smbd_main("smbd", argc, argv); +} |