summaryrefslogtreecommitdiff
path: root/source4/smbd/server.c
diff options
context:
space:
mode:
Diffstat (limited to 'source4/smbd/server.c')
-rw-r--r--source4/smbd/server.c340
1 files changed, 340 insertions, 0 deletions
diff --git a/source4/smbd/server.c b/source4/smbd/server.c
new file mode 100644
index 00000000000..e33a13e75db
--- /dev/null
+++ b/source4/smbd/server.c
@@ -0,0 +1,340 @@
+/*
+ Unix SMB/CIFS implementation.
+ Main SMB server routines
+ Copyright (C) Andrew Tridgell 1992-1998
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+
+/*
+ called on a fatal error that should cause this server to terminate
+*/
+void exit_server(struct server_context *smb, const char *reason)
+{
+ smb->model_ops->terminate_connection(smb, reason);
+}
+
+
+/*
+ add a socket address to the list of events, one event per port
+*/
+static void add_socket(struct event_context *events,
+ struct model_ops *model_ops,
+ struct in_addr *ifip)
+{
+ char *ports = lp_smb_ports();
+ char *ptr, *tok;
+ const char *delim = ", ";
+
+ for (tok=strtok_r(ports, delim, &ptr);
+ tok;
+ tok=strtok_r(NULL, delim, &ptr)) {
+ unsigned port = atoi(tok);
+ struct fd_event fde;
+
+ if (port == 0) continue;
+
+ fde.fd = open_socket_in(SOCK_STREAM, port, 0, ifip->s_addr, True);
+ if (fde.fd == -1) {
+ DEBUG(0,("Failed to open socket on %s:%u - %s\n",
+ inet_ntoa(*ifip), port, strerror(errno)));
+ continue;
+ }
+
+ /* ready to listen */
+ set_socket_options(fde.fd, "SO_KEEPALIVE");
+ set_socket_options(fde.fd, lp_socket_options());
+
+ if (listen(fde.fd, 10) == -1) {
+ DEBUG(0,("Failed to listen on %s:%d - %s\n",
+ inet_ntoa(*ifip), port, strerror(errno)));
+ close(fde.fd);
+ continue;
+ }
+
+ /* we are only interested in read events on the listen socket */
+ fde.flags = EVENT_FD_READ;
+ fde.private = model_ops;
+ fde.handler = model_ops->accept_connection;
+
+ event_add_fd(events, &fde);
+ }
+}
+
+/****************************************************************************
+ Open the socket communication.
+****************************************************************************/
+static void open_sockets_smbd(struct event_context *events,
+ struct model_ops *model_ops)
+{
+ if (lp_interfaces() && lp_bind_interfaces_only()) {
+ int num_interfaces = iface_count();
+ int i;
+
+ /* 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.
+ */
+ for(i = 0; i < num_interfaces; i++) {
+ struct in_addr *ifip = iface_n_ip(i);
+
+ if (ifip == NULL) {
+ DEBUG(0,("open_sockets_smbd: interface %d has NULL IP address !\n", i));
+ continue;
+ }
+
+ add_socket(events, model_ops, ifip);
+ }
+ } else {
+ TALLOC_CTX *mem_ctx = talloc_init("open_sockets_smbd");
+
+ struct in_addr *ifip = interpret_addr2(mem_ctx, lp_socket_address());
+ /* Just bind to lp_socket_address() (usually 0.0.0.0) */
+ if (!mem_ctx) {
+ smb_panic("No memory");
+ }
+ add_socket(events, model_ops, ifip);
+ talloc_destroy(mem_ctx);
+ }
+}
+
+/****************************************************************************
+ Reload the services file.
+**************************************************************************/
+BOOL reload_services(struct server_context *smb, BOOL test)
+{
+ BOOL ret;
+
+ if (lp_loaded()) {
+ pstring fname;
+ pstrcpy(fname,lp_configfile());
+ if (file_exist(fname, NULL) &&
+ !strcsequal(fname, dyn_CONFIGFILE)) {
+ pstrcpy(dyn_CONFIGFILE, fname);
+ test = False;
+ }
+ }
+
+ reopen_logs();
+
+ if (test && !lp_file_list_changed())
+ return(True);
+
+ if (smb) {
+ lp_killunused(smb, conn_snum_used);
+ }
+
+ ret = lp_load(dyn_CONFIGFILE, False, False, True);
+
+ load_printers();
+
+ /* perhaps the config filename is now set */
+ if (!test)
+ reload_services(smb, True);
+
+ reopen_logs();
+
+ load_interfaces();
+
+ mangle_reset_cache();
+ reset_stat_cache();
+
+ /* this forces service parameters to be flushed */
+ set_current_service(NULL,True);
+
+ return(ret);
+}
+
+/****************************************************************************
+ Initialise connect, service and file structs.
+****************************************************************************/
+static BOOL init_structs(void)
+{
+ init_names();
+ file_init();
+ init_rpc_pipe_hnd();
+ secrets_init();
+
+ /* we want to re-seed early to prevent time delays causing
+ client problems at a later date. (tridge) */
+ generate_random_buffer(NULL, 0, False);
+
+ return True;
+}
+
+
+/*
+ setup the events for the chosen process model
+*/
+static void setup_process_model(struct event_context *events,
+ const char *model)
+{
+ struct model_ops *ops;
+
+ process_model_init();
+
+ ops = process_model_byname(model);
+ if (!ops) {
+ DEBUG(0,("Unknown process model '%s'\n", model));
+ exit(-1);
+ }
+
+ ops->model_startup();
+
+ /* now setup the listening sockets, adding
+ event handlers to the events structure */
+ open_sockets_smbd(events, ops);
+}
+
+/****************************************************************************
+ main program.
+****************************************************************************/
+ int main(int argc,const char *argv[])
+{
+ BOOL is_daemon = False;
+ BOOL interactive = False;
+ BOOL Fork = True;
+ BOOL log_stdout = False;
+ int opt;
+ poptContext pc;
+ struct event_context *events;
+ const char *model = "standard";
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ {"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)" },
+ {"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, NULL, 0, "Listen on the specified ports"},
+ {"model", 'M', POPT_ARG_STRING, &model, 0, "select process model"},
+ POPT_COMMON_SAMBA
+ { NULL }
+ };
+
+ pc = poptGetContext("smbd", argc, argv, long_options, 0);
+
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ switch (opt) {
+ case 'b':
+ /* Display output to screen as well as debug */
+ build_options(True);
+ exit(0);
+ break;
+ case 'p':
+ lp_set_cmdline("smb ports", poptGetOptArg(pc));
+ break;
+ }
+ }
+ poptFreeContext(pc);
+
+ events = event_context_init();
+
+ load_case_tables();
+
+ if (interactive) {
+ Fork = False;
+ log_stdout = True;
+ }
+
+ 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);
+ }
+ setup_logging(argv[0], log_stdout);
+
+ fault_setup((void (*)(void *))exit_server);
+
+ /* we are never interested in SIGPIPE */
+ BlockSignals(True,SIGPIPE);
+
+#if defined(SIGFPE)
+ /* we are never interested in SIGFPE */
+ BlockSignals(True,SIGFPE);
+#endif
+
+#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, SIGUSR1);
+ BlockSignals(False, SIGTERM);
+
+ /* we want total control over the permissions on created files,
+ so set our umask to 0 */
+ umask(0);
+
+ reopen_logs();
+
+ DEBUG(0,("smbd version %s started.\n", SAMBA_VERSION));
+ DEBUGADD(0,("Copyright Andrew Tridgell and the Samba Team 1992-2003\n"));
+
+ /* Output the build options to the debug log */
+ build_options(False);
+
+ if (sizeof(uint16) < 2 || sizeof(uint32) < 4) {
+ DEBUG(0,("ERROR: Samba is not configured correctly for the word size on your machine\n"));
+ exit(1);
+ }
+ DEBUG(0,("Using %s process model\n", model));
+
+ if (!reload_services(NULL, False))
+ return(-1);
+
+ init_structs();
+
+ 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 (is_daemon && !interactive) {
+ DEBUG(3,("Becoming a daemon.\n"));
+ become_daemon(Fork);
+ }
+
+ if (!directory_exist(lp_lockdir(), NULL)) {
+ mkdir(lp_lockdir(), 0755);
+ }
+
+ if (is_daemon) {
+ pidfile_create("smbd");
+ }
+
+ register_msg_pool_usage();
+ register_dmalloc_msgs();
+
+ setup_process_model(events, model);
+
+ /* wait for events */
+ return event_loop_wait(events);
+}