diff options
Diffstat (limited to 'source4/smbd/server.c')
-rw-r--r-- | source4/smbd/server.c | 340 |
1 files changed, 340 insertions, 0 deletions
diff --git a/source4/smbd/server.c b/source4/smbd/server.c new file mode 100644 index 0000000000..e33a13e75d --- /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); +} |