wmi-1.3.16 from opsview.com
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
# server subsystem
|
||||
|
||||
################################################
|
||||
# Start MODULE service_auth
|
||||
[MODULE::service_auth]
|
||||
INIT_FUNCTION = server_service_auth_init
|
||||
SUBSYSTEM = service
|
||||
PUBLIC_DEPENDENCIES = \
|
||||
auth
|
||||
# End MODULE server_auth
|
||||
################################################
|
||||
|
||||
#######################
|
||||
# Start SUBSERVICE
|
||||
[LIBRARY::service]
|
||||
PRIVATE_PROTO_HEADER = service_proto.h
|
||||
OBJ_FILES = \
|
||||
service.o \
|
||||
service_stream.o \
|
||||
service_task.o
|
||||
PUBLIC_DEPENDENCIES = \
|
||||
MESSAGING
|
||||
# End SUBSYSTEM SERVER
|
||||
#######################
|
||||
|
||||
[SUBSYSTEM::PIDFILE]
|
||||
OBJ_FILES = pidfile.o
|
||||
PRIVATE_PROTO_HEADER = pidfile.h
|
||||
|
||||
#################################
|
||||
# Start BINARY smbd
|
||||
[BINARY::smbd]
|
||||
INSTALLDIR = SBINDIR
|
||||
MANPAGE = smbd.8
|
||||
OBJ_FILES = \
|
||||
server.o
|
||||
PRIVATE_DEPENDENCIES = \
|
||||
process_model \
|
||||
service \
|
||||
LIBSAMBA-CONFIG \
|
||||
LIBSAMBA-UTIL \
|
||||
POPT_SAMBA \
|
||||
PIDFILE \
|
||||
LIBPOPT \
|
||||
gensec \
|
||||
registry \
|
||||
ntptr \
|
||||
ntvfs \
|
||||
share
|
||||
# End BINARY smbd
|
||||
#################################
|
||||
@@ -0,0 +1,121 @@
|
||||
/* this code is broken - there is a race condition with the unlink (tridge) */
|
||||
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
pidfile handling
|
||||
Copyright (C) Andrew Tridgell 1998
|
||||
|
||||
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"
|
||||
#include "system/filesys.h"
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Pid file handling
|
||||
*/
|
||||
|
||||
/**
|
||||
* return the pid in a pidfile. return 0 if the process (or pidfile)
|
||||
* does not exist
|
||||
*/
|
||||
pid_t pidfile_pid(const char *name)
|
||||
{
|
||||
int fd;
|
||||
char pidstr[20];
|
||||
pid_t ret;
|
||||
char *pidFile;
|
||||
|
||||
asprintf(&pidFile, "%s/%s.pid", lp_piddir(), name);
|
||||
|
||||
fd = open(pidFile, O_NONBLOCK | O_RDONLY, 0644);
|
||||
|
||||
if (fd == -1) {
|
||||
SAFE_FREE(pidFile);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ZERO_STRUCT(pidstr);
|
||||
|
||||
if (read(fd, pidstr, sizeof(pidstr)-1) <= 0) {
|
||||
goto noproc;
|
||||
}
|
||||
|
||||
ret = (pid_t)atoi(pidstr);
|
||||
|
||||
if (!process_exists(ret)) {
|
||||
goto noproc;
|
||||
}
|
||||
|
||||
if (fcntl_lock(fd,F_SETLK,0,1,F_RDLCK)) {
|
||||
/* we could get the lock - it can't be a Samba process */
|
||||
goto noproc;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
SAFE_FREE(pidFile);
|
||||
return ret;
|
||||
|
||||
noproc:
|
||||
close(fd);
|
||||
unlink(pidFile);
|
||||
SAFE_FREE(pidFile);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* create a pid file in the pid directory. open it and leave it locked
|
||||
*/
|
||||
void pidfile_create(const char *name)
|
||||
{
|
||||
int fd;
|
||||
char buf[20];
|
||||
char *pidFile;
|
||||
pid_t pid;
|
||||
|
||||
asprintf(&pidFile, "%s/%s.pid", lp_piddir(), name);
|
||||
|
||||
pid = pidfile_pid(name);
|
||||
if (pid != 0) {
|
||||
DEBUG(0,("ERROR: %s is already running. File %s exists and process id %d is running.\n",
|
||||
name, pidFile, (int)pid));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fd = open(pidFile, O_NONBLOCK | O_CREAT | O_WRONLY | O_EXCL, 0644);
|
||||
if (fd == -1) {
|
||||
DEBUG(0,("ERROR: can't open %s: Error was %s\n", pidFile,
|
||||
strerror(errno)));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (fcntl_lock(fd,F_SETLK,0,1,F_WRLCK)==False) {
|
||||
DEBUG(0,("ERROR: %s : fcntl lock of file %s failed. Error was %s\n",
|
||||
name, pidFile, strerror(errno)));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
slprintf(buf, sizeof(buf) - 1, "%u\n", (unsigned int) getpid());
|
||||
if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf)) {
|
||||
DEBUG(0,("ERROR: can't write to file %s: %s\n",
|
||||
pidFile, strerror(errno)));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Leave pid file open & locked for the duration... */
|
||||
SAFE_FREE(pidFile);
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
process model manager - main loop
|
||||
Copyright (C) Andrew Tridgell 1992-2003
|
||||
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"
|
||||
#include "smbd/process_model.h"
|
||||
#include "build.h"
|
||||
|
||||
/*
|
||||
setup the events for the chosen process model
|
||||
*/
|
||||
_PUBLIC_ const struct model_ops *process_model_startup(struct event_context *ev, const char *model)
|
||||
{
|
||||
const struct model_ops *ops;
|
||||
|
||||
ops = process_model_byname(model);
|
||||
if (!ops) {
|
||||
DEBUG(0,("Unknown process model '%s'\n", model));
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
ops->model_init(ev);
|
||||
|
||||
return ops;
|
||||
}
|
||||
|
||||
/* the list of currently registered process models */
|
||||
static struct process_model {
|
||||
struct model_ops *ops;
|
||||
} *models = NULL;
|
||||
static int num_models;
|
||||
|
||||
/*
|
||||
register a process model.
|
||||
|
||||
The 'name' can be later used by other backends to find the operations
|
||||
structure for this backend.
|
||||
*/
|
||||
_PUBLIC_ NTSTATUS register_process_model(const void *_ops)
|
||||
{
|
||||
const struct model_ops *ops = _ops;
|
||||
|
||||
if (process_model_byname(ops->name) != NULL) {
|
||||
/* its already registered! */
|
||||
DEBUG(0,("PROCESS_MODEL '%s' already registered\n",
|
||||
ops->name));
|
||||
return NT_STATUS_OBJECT_NAME_COLLISION;
|
||||
}
|
||||
|
||||
models = realloc_p(models, struct process_model, num_models+1);
|
||||
if (!models) {
|
||||
smb_panic("out of memory in register_process_model");
|
||||
}
|
||||
|
||||
models[num_models].ops = smb_xmemdup(ops, sizeof(*ops));
|
||||
models[num_models].ops->name = smb_xstrdup(ops->name);
|
||||
|
||||
num_models++;
|
||||
|
||||
DEBUG(3,("PROCESS_MODEL '%s' registered\n",
|
||||
ops->name));
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
NTSTATUS process_model_init(void)
|
||||
{
|
||||
init_module_fn static_init[] = STATIC_process_model_MODULES;
|
||||
init_module_fn *shared_init = load_samba_modules(NULL, "process_model");
|
||||
|
||||
run_init_functions(static_init);
|
||||
run_init_functions(shared_init);
|
||||
|
||||
talloc_free(shared_init);
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
return the operations structure for a named backend of the specified type
|
||||
*/
|
||||
const struct model_ops *process_model_byname(const char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0;i<num_models;i++) {
|
||||
if (strcmp(models[i].ops->name, name) == 0) {
|
||||
return models[i].ops;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
return the PROCESS_MODEL module version, and the size of some critical types
|
||||
This can be used by process model modules to either detect compilation errors, or provide
|
||||
multiple implementations for different smbd compilation options in one module
|
||||
*/
|
||||
const struct process_model_critical_sizes *process_model_version(void)
|
||||
{
|
||||
static const struct process_model_critical_sizes critical_sizes = {
|
||||
PROCESS_MODEL_VERSION,
|
||||
sizeof(struct model_ops)
|
||||
};
|
||||
|
||||
return &critical_sizes;
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
process model manager - structures
|
||||
|
||||
Copyright (C) Andrew Tridgell 1992-2005
|
||||
Copyright (C) James J Myers 2003 <myersjj@samba.org>
|
||||
Copyright (C) Stefan (metze) Metzmacher 2004-2005
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef __PROCESS_MODEL_H__
|
||||
#define __PROCESS_MODEL_H__
|
||||
|
||||
#include "lib/socket/socket.h"
|
||||
|
||||
/* modules can use the following to determine if the interface has changed
|
||||
* please increment the version number after each interface change
|
||||
* with a comment and maybe update struct process_model_critical_sizes.
|
||||
*/
|
||||
/* version 1 - initial version - metze */
|
||||
#define PROCESS_MODEL_VERSION 1
|
||||
|
||||
/* the process model operations structure - contains function pointers to
|
||||
the model-specific implementations of each operation */
|
||||
struct model_ops {
|
||||
/* the name of the process_model */
|
||||
const char *name;
|
||||
|
||||
/* called at startup when the model is selected */
|
||||
void (*model_init)(struct event_context *);
|
||||
|
||||
/* function to accept new connection */
|
||||
void (*accept_connection)(struct event_context *, struct socket_context *,
|
||||
void (*)(struct event_context *, struct socket_context *,
|
||||
uint32_t , void *),
|
||||
void *);
|
||||
|
||||
/* function to create a task */
|
||||
void (*new_task)(struct event_context *,
|
||||
void (*)(struct event_context *, uint32_t, void *),
|
||||
void *);
|
||||
|
||||
/* function to terminate a connection or task */
|
||||
void (*terminate)(struct event_context *, const char *reason);
|
||||
|
||||
/* function to set a title for the connection or task */
|
||||
void (*set_title)(struct event_context *, const char *title);
|
||||
};
|
||||
|
||||
/* this structure is used by modules to determine the size of some critical types */
|
||||
struct process_model_critical_sizes {
|
||||
int interface_version;
|
||||
int sizeof_model_ops;
|
||||
};
|
||||
|
||||
#include "smbd/process_model_proto.h"
|
||||
|
||||
#endif /* __PROCESS_MODEL_H__ */
|
||||
@@ -0,0 +1,60 @@
|
||||
dnl # Server process model subsystem
|
||||
|
||||
SMB_ENABLE(process_model_thread,NO)
|
||||
|
||||
#################################################
|
||||
# check for pthread support
|
||||
AC_MSG_CHECKING(whether to use pthreads)
|
||||
AC_ARG_WITH(pthreads,
|
||||
[ --with-pthreads Include pthreads (default=no) ],
|
||||
[ case "$withval" in
|
||||
yes)
|
||||
AC_MSG_RESULT(yes)
|
||||
if test x"$ac_cv_func_pread" != x"yes" -o x"$ac_cv_func_pwrite" != x"yes";then
|
||||
AC_MSG_ERROR([You cannot enable threads when you don't have pread/pwrite!])
|
||||
fi
|
||||
SMB_ENABLE(process_model_thread,YES)
|
||||
SMB_ENABLE(PTHREAD,YES)
|
||||
;;
|
||||
*)
|
||||
AC_MSG_RESULT(no)
|
||||
;;
|
||||
esac ],
|
||||
AC_MSG_RESULT(no)
|
||||
)
|
||||
|
||||
SMB_EXT_LIB(PTHREAD,[-lpthread])
|
||||
|
||||
AC_MSG_CHECKING(whether to search for setproctitle support)
|
||||
AC_ARG_WITH(setproctitle,
|
||||
[ --with-setproctitle Search for setproctitle support (default=no)],
|
||||
[ case "$withval" in
|
||||
yes)
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_CHECK_HEADERS(setproctitle.h)
|
||||
AC_CHECK_FUNC(setproctitle, [], [
|
||||
AC_CHECK_LIB_EXT(setproctitle, SETPROCTITLE_LIBS, setproctitle)
|
||||
])
|
||||
AC_MSG_CHECKING(whether to use setproctitle)
|
||||
if test x"$ac_cv_func_setproctitle" = x"yes" -o \
|
||||
\( x"$ac_cv_header_setproctitle_h" = x"yes" -a \
|
||||
x"$ac_cv_lib_ext_setproctitle_setproctitle" = x"yes" \) ; then
|
||||
AC_MSG_RESULT(yes)
|
||||
SMB_ENABLE(SETPROCTITLE, YES)
|
||||
AC_DEFINE(HAVE_SETPROCTITLE,1,[Whether setproctitle() is available])
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
AC_MSG_RESULT(no)
|
||||
;;
|
||||
esac ],
|
||||
AC_MSG_RESULT(no)
|
||||
)
|
||||
|
||||
SMB_EXT_LIB(SETPROCTITLE,
|
||||
[${SETPROCTITLE_LIBS}],
|
||||
[${SETPROCTITLE_CFLAGS}],
|
||||
[${SETPROCTITLE_CPPFLAGS}],
|
||||
[${SETPROCTITLE_LDFLAGS}])
|
||||
@@ -0,0 +1,46 @@
|
||||
# Server process model subsystem
|
||||
|
||||
################################################
|
||||
# Start MODULE process_model_single
|
||||
[MODULE::process_model_single]
|
||||
INIT_FUNCTION = process_model_single_init
|
||||
SUBSYSTEM = process_model
|
||||
OBJ_FILES = \
|
||||
process_single.o
|
||||
# End MODULE process_model_single
|
||||
################################################
|
||||
|
||||
################################################
|
||||
# Start MODULE process_model_standard
|
||||
[MODULE::process_model_standard]
|
||||
INIT_FUNCTION = process_model_standard_init
|
||||
SUBSYSTEM = process_model
|
||||
OBJ_FILES = \
|
||||
process_standard.o
|
||||
PRIVATE_DEPENDENCIES = SETPROCTITLE
|
||||
# End MODULE process_model_standard
|
||||
################################################
|
||||
|
||||
################################################
|
||||
# Start MODULE process_model_thread
|
||||
[MODULE::process_model_thread]
|
||||
INIT_FUNCTION = process_model_thread_init
|
||||
SUBSYSTEM = process_model
|
||||
OBJ_FILES = \
|
||||
process_thread.o
|
||||
PRIVATE_DEPENDENCIES = PTHREAD
|
||||
# End MODULE process_model_thread
|
||||
################################################
|
||||
|
||||
################################################
|
||||
# Start SUBSYSTEM process_model
|
||||
[LIBRARY::process_model]
|
||||
VERSION = 0.0.1
|
||||
SO_VERSION = 0
|
||||
PRIVATE_PROTO_HEADER = process_model_proto.h
|
||||
OBJ_FILES = \
|
||||
process_model.o
|
||||
PRIVATE_DEPENDENCIES = LIBSAMBA-UTIL LIBSAMBA-CONFIG
|
||||
#
|
||||
# End SUBSYSTEM process_model
|
||||
################################################
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
process model: process (1 process handles all client connections)
|
||||
|
||||
Copyright (C) Andrew Tridgell 2003
|
||||
Copyright (C) James J Myers 2003 <myersjj@samba.org>
|
||||
Copyright (C) Stefan (metze) Metzmacher 2004
|
||||
|
||||
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"
|
||||
#include "smbd/process_model.h"
|
||||
#include "system/filesys.h"
|
||||
|
||||
/*
|
||||
called when the process model is selected
|
||||
*/
|
||||
static void single_model_init(struct event_context *ev)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
called when a listening socket becomes readable.
|
||||
*/
|
||||
static void single_accept_connection(struct event_context *ev,
|
||||
struct socket_context *sock,
|
||||
void (*new_conn)(struct event_context *, struct socket_context *,
|
||||
uint32_t , void *),
|
||||
void *private)
|
||||
{
|
||||
NTSTATUS status;
|
||||
struct socket_context *sock2;
|
||||
|
||||
/* accept an incoming connection. */
|
||||
status = socket_accept(sock, &sock2);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(0,("single_accept_connection: accept: %s\n", nt_errstr(status)));
|
||||
/* this looks strange, but is correct. We need to
|
||||
throttle things until the system clears enough
|
||||
resources to handle this new socket. If we don't
|
||||
then we will spin filling the log and causing more
|
||||
problems. We don't panic as this is probably a
|
||||
temporary resource constraint */
|
||||
sleep(1);
|
||||
return;
|
||||
}
|
||||
|
||||
talloc_steal(private, sock);
|
||||
|
||||
new_conn(ev, sock2, socket_get_fd(sock2), private);
|
||||
}
|
||||
|
||||
/*
|
||||
called to startup a new task
|
||||
*/
|
||||
static void single_new_task(struct event_context *ev,
|
||||
void (*new_task)(struct event_context *, uint32_t, void *),
|
||||
void *private)
|
||||
{
|
||||
static uint32_t taskid = 0x10000000;
|
||||
new_task(ev, taskid++, private);
|
||||
}
|
||||
|
||||
|
||||
/* called when a task goes down */
|
||||
static void single_terminate(struct event_context *ev, const char *reason)
|
||||
{
|
||||
DEBUG(2,("single_terminate: reason[%s]\n",reason));
|
||||
}
|
||||
|
||||
/* called to set a title of a task or connection */
|
||||
static void single_set_title(struct event_context *ev, const char *title)
|
||||
{
|
||||
}
|
||||
|
||||
static const struct model_ops single_ops = {
|
||||
.name = "single",
|
||||
.model_init = single_model_init,
|
||||
.new_task = single_new_task,
|
||||
.accept_connection = single_accept_connection,
|
||||
.terminate = single_terminate,
|
||||
.set_title = single_set_title,
|
||||
};
|
||||
|
||||
/*
|
||||
initialise the single process model, registering ourselves with the
|
||||
process model subsystem
|
||||
*/
|
||||
NTSTATUS process_model_single_init(void)
|
||||
{
|
||||
return register_process_model(&single_ops);
|
||||
}
|
||||
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
process model: standard (1 process per client connection)
|
||||
|
||||
Copyright (C) Andrew Tridgell 1992-2005
|
||||
Copyright (C) James J Myers 2003 <myersjj@samba.org>
|
||||
Copyright (C) Stefan (metze) Metzmacher 2004
|
||||
|
||||
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"
|
||||
#include "lib/events/events.h"
|
||||
#include "lib/tdb/include/tdb.h"
|
||||
#include "lib/socket/socket.h"
|
||||
#include "smbd/process_model.h"
|
||||
#include "param/secrets.h"
|
||||
|
||||
#include "system/filesys.h"
|
||||
|
||||
#ifdef HAVE_SETPROCTITLE
|
||||
#ifdef HAVE_SETPROCTITLE_H
|
||||
#include <setproctitle.h>
|
||||
#endif
|
||||
#else
|
||||
#define setproctitle none_setproctitle
|
||||
static int none_setproctitle(const char *fmt, ...) PRINTF_ATTRIBUTE(1, 2);
|
||||
static int none_setproctitle(const char *fmt, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
called when the process model is selected
|
||||
*/
|
||||
static void standard_model_init(struct event_context *ev)
|
||||
{
|
||||
signal(SIGCHLD, SIG_IGN);
|
||||
}
|
||||
|
||||
/*
|
||||
called when a listening socket becomes readable.
|
||||
*/
|
||||
static void standard_accept_connection(struct event_context *ev,
|
||||
struct socket_context *sock,
|
||||
void (*new_conn)(struct event_context *, struct socket_context *,
|
||||
uint32_t , void *),
|
||||
void *private)
|
||||
{
|
||||
NTSTATUS status;
|
||||
struct socket_context *sock2;
|
||||
pid_t pid;
|
||||
struct event_context *ev2;
|
||||
struct socket_address *c, *s;
|
||||
|
||||
/* accept an incoming connection. */
|
||||
status = socket_accept(sock, &sock2);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(0,("standard_accept_connection: accept: %s\n",
|
||||
nt_errstr(status)));
|
||||
/* this looks strange, but is correct. We need to throttle things until
|
||||
the system clears enough resources to handle this new socket */
|
||||
sleep(1);
|
||||
return;
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
|
||||
if (pid != 0) {
|
||||
/* parent or error code ... */
|
||||
talloc_free(sock2);
|
||||
/* go back to the event loop */
|
||||
return;
|
||||
}
|
||||
|
||||
pid = getpid();
|
||||
|
||||
/* This is now the child code. We need a completely new event_context to work with */
|
||||
ev2 = event_context_init(NULL);
|
||||
|
||||
/* the service has given us a private pointer that
|
||||
encapsulates the context it needs for this new connection -
|
||||
everything else will be freed */
|
||||
talloc_steal(ev2, private);
|
||||
talloc_steal(private, sock2);
|
||||
|
||||
/* this will free all the listening sockets and all state that
|
||||
is not associated with this new connection */
|
||||
talloc_free(sock);
|
||||
talloc_free(ev);
|
||||
|
||||
/* we don't care if the dup fails, as its only a select()
|
||||
speed optimisation */
|
||||
socket_dup(sock2);
|
||||
|
||||
/* tdb needs special fork handling */
|
||||
if (tdb_reopen_all(1) == -1) {
|
||||
DEBUG(0,("standard_accept_connection: tdb_reopen_all failed.\n"));
|
||||
}
|
||||
|
||||
/* Ensure that the forked children do not expose identical random streams */
|
||||
set_need_random_reseed();
|
||||
|
||||
/* setup the process title */
|
||||
c = socket_get_peer_addr(sock2, ev2);
|
||||
s = socket_get_my_addr(sock2, ev2);
|
||||
if (s && c) {
|
||||
setproctitle("conn c[%s:%u] s[%s:%u] server_id[%d]",
|
||||
c->addr, c->port, s->addr, s->port, pid);
|
||||
}
|
||||
talloc_free(c);
|
||||
talloc_free(s);
|
||||
|
||||
/* setup this new connection */
|
||||
new_conn(ev2, sock2, pid, private);
|
||||
|
||||
/* we can't return to the top level here, as that event context is gone,
|
||||
so we now process events in the new event context until there are no
|
||||
more to process */
|
||||
event_loop_wait(ev2);
|
||||
|
||||
talloc_free(ev2);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/*
|
||||
called to create a new server task
|
||||
*/
|
||||
static void standard_new_task(struct event_context *ev,
|
||||
void (*new_task)(struct event_context *, uint32_t , void *),
|
||||
void *private)
|
||||
{
|
||||
pid_t pid;
|
||||
struct event_context *ev2;
|
||||
|
||||
pid = fork();
|
||||
|
||||
if (pid != 0) {
|
||||
/* parent or error code ... go back to the event loop */
|
||||
return;
|
||||
}
|
||||
|
||||
pid = getpid();
|
||||
|
||||
/* This is now the child code. We need a completely new event_context to work with */
|
||||
ev2 = event_context_init(NULL);
|
||||
|
||||
/* the service has given us a private pointer that
|
||||
encapsulates the context it needs for this new connection -
|
||||
everything else will be freed */
|
||||
talloc_steal(ev2, private);
|
||||
|
||||
/* this will free all the listening sockets and all state that
|
||||
is not associated with this new connection */
|
||||
talloc_free(ev);
|
||||
|
||||
/* tdb needs special fork handling */
|
||||
if (tdb_reopen_all(1) == -1) {
|
||||
DEBUG(0,("standard_accept_connection: tdb_reopen_all failed.\n"));
|
||||
}
|
||||
|
||||
/* Ensure that the forked children do not expose identical random streams */
|
||||
set_need_random_reseed();
|
||||
|
||||
setproctitle("task server_id[%d]", pid);
|
||||
|
||||
/* setup this new connection */
|
||||
new_task(ev2, pid, private);
|
||||
|
||||
/* we can't return to the top level here, as that event context is gone,
|
||||
so we now process events in the new event context until there are no
|
||||
more to process */
|
||||
event_loop_wait(ev2);
|
||||
|
||||
talloc_free(ev2);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
/* called when a task goes down */
|
||||
static void standard_terminate(struct event_context *ev, const char *reason)
|
||||
{
|
||||
DEBUG(2,("standard_terminate: reason[%s]\n",reason));
|
||||
|
||||
/* this init_iconv() has the effect of freeing the iconv context memory,
|
||||
which makes leak checking easier */
|
||||
init_iconv();
|
||||
|
||||
/* the secrets db should really hang off the connection structure */
|
||||
secrets_shutdown();
|
||||
|
||||
talloc_free(ev);
|
||||
|
||||
/* terminate this process */
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* called to set a title of a task or connection */
|
||||
static void standard_set_title(struct event_context *ev, const char *title)
|
||||
{
|
||||
if (title) {
|
||||
setproctitle("%s", title);
|
||||
} else {
|
||||
setproctitle(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct model_ops standard_ops = {
|
||||
.name = "standard",
|
||||
.model_init = standard_model_init,
|
||||
.accept_connection = standard_accept_connection,
|
||||
.new_task = standard_new_task,
|
||||
.terminate = standard_terminate,
|
||||
.set_title = standard_set_title,
|
||||
};
|
||||
|
||||
/*
|
||||
initialise the standard process model, registering ourselves with the process model subsystem
|
||||
*/
|
||||
NTSTATUS process_model_standard_init(void)
|
||||
{
|
||||
return register_process_model(&standard_ops);
|
||||
}
|
||||
@@ -0,0 +1,560 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
thread model: standard (1 thread per client connection)
|
||||
|
||||
Copyright (C) Andrew Tridgell 2003-2005
|
||||
Copyright (C) James J Myers 2003 <myersjj@samba.org>
|
||||
Copyright (C) Stefan (metze) Metzmacher 2004
|
||||
|
||||
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"
|
||||
#include "version.h"
|
||||
#include <pthread.h>
|
||||
#ifdef HAVE_BACKTRACE
|
||||
#include <execinfo.h>
|
||||
#endif
|
||||
#include "system/wait.h"
|
||||
#include "system/filesys.h"
|
||||
#include "lib/events/events.h"
|
||||
#include "lib/util/dlinklist.h"
|
||||
#include "lib/util/mutex.h"
|
||||
#include "smbd/process_model.h"
|
||||
|
||||
static pthread_key_t title_key;
|
||||
|
||||
struct new_conn_state {
|
||||
struct event_context *ev;
|
||||
struct socket_context *sock;
|
||||
void (*new_conn)(struct event_context *, struct socket_context *, uint32_t , void *);
|
||||
void *private;
|
||||
};
|
||||
|
||||
static void *thread_connection_fn(void *thread_parm)
|
||||
{
|
||||
struct new_conn_state *new_conn = talloc_get_type(thread_parm, struct new_conn_state);
|
||||
|
||||
new_conn->new_conn(new_conn->ev, new_conn->sock, pthread_self(), new_conn->private);
|
||||
|
||||
/* run this connection from here */
|
||||
event_loop_wait(new_conn->ev);
|
||||
|
||||
talloc_free(new_conn);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
called when a listening socket becomes readable
|
||||
*/
|
||||
static void thread_accept_connection(struct event_context *ev,
|
||||
struct socket_context *sock,
|
||||
void (*new_conn)(struct event_context *, struct socket_context *,
|
||||
uint32_t , void *),
|
||||
void *private)
|
||||
{
|
||||
NTSTATUS status;
|
||||
int rc;
|
||||
pthread_t thread_id;
|
||||
pthread_attr_t thread_attr;
|
||||
struct new_conn_state *state;
|
||||
struct event_context *ev2;
|
||||
|
||||
ev2 = event_context_init(ev);
|
||||
if (ev2 == NULL) return;
|
||||
|
||||
state = talloc(ev2, struct new_conn_state);
|
||||
if (state == NULL) {
|
||||
talloc_free(ev2);
|
||||
return;
|
||||
}
|
||||
|
||||
state->new_conn = new_conn;
|
||||
state->private = private;
|
||||
state->ev = ev2;
|
||||
|
||||
/* accept an incoming connection. */
|
||||
status = socket_accept(sock, &state->sock);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
talloc_free(ev2);
|
||||
/* We need to throttle things until the system clears
|
||||
enough resources to handle this new socket. If we
|
||||
don't then we will spin filling the log and causing
|
||||
more problems. We don't panic as this is probably a
|
||||
temporary resource constraint */
|
||||
sleep(1);
|
||||
return;
|
||||
}
|
||||
|
||||
talloc_steal(state, state->sock);
|
||||
|
||||
pthread_attr_init(&thread_attr);
|
||||
pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
|
||||
rc = pthread_create(&thread_id, &thread_attr, thread_connection_fn, state);
|
||||
pthread_attr_destroy(&thread_attr);
|
||||
if (rc == 0) {
|
||||
DEBUG(4,("accept_connection_thread: created thread_id=%lu for fd=%d\n",
|
||||
(unsigned long int)thread_id, socket_get_fd(sock)));
|
||||
} else {
|
||||
DEBUG(0,("accept_connection_thread: thread create failed for fd=%d, rc=%d\n", socket_get_fd(sock), rc));
|
||||
talloc_free(ev2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct new_task_state {
|
||||
struct event_context *ev;
|
||||
void (*new_task)(struct event_context *, uint32_t , void *);
|
||||
void *private;
|
||||
};
|
||||
|
||||
static void *thread_task_fn(void *thread_parm)
|
||||
{
|
||||
struct new_task_state *new_task = talloc_get_type(thread_parm, struct new_task_state);
|
||||
|
||||
new_task->new_task(new_task->ev, pthread_self(), new_task->private);
|
||||
|
||||
/* run this connection from here */
|
||||
event_loop_wait(new_task->ev);
|
||||
|
||||
talloc_free(new_task);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
called when a new task is needed
|
||||
*/
|
||||
static void thread_new_task(struct event_context *ev,
|
||||
void (*new_task)(struct event_context *, uint32_t , void *),
|
||||
void *private)
|
||||
{
|
||||
int rc;
|
||||
pthread_t thread_id;
|
||||
pthread_attr_t thread_attr;
|
||||
struct new_task_state *state;
|
||||
struct event_context *ev2;
|
||||
|
||||
ev2 = event_context_init(ev);
|
||||
if (ev2 == NULL) return;
|
||||
|
||||
state = talloc(ev2, struct new_task_state);
|
||||
if (state == NULL) {
|
||||
talloc_free(ev2);
|
||||
return;
|
||||
}
|
||||
|
||||
state->new_task = new_task;
|
||||
state->private = private;
|
||||
state->ev = ev2;
|
||||
|
||||
pthread_attr_init(&thread_attr);
|
||||
pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
|
||||
rc = pthread_create(&thread_id, &thread_attr, thread_task_fn, state);
|
||||
pthread_attr_destroy(&thread_attr);
|
||||
if (rc == 0) {
|
||||
DEBUG(4,("thread_new_task: created thread_id=%lu\n",
|
||||
(unsigned long int)thread_id));
|
||||
} else {
|
||||
DEBUG(0,("thread_new_task: thread create failed rc=%d\n", rc));
|
||||
talloc_free(ev2);
|
||||
}
|
||||
}
|
||||
|
||||
/* called when a task goes down */
|
||||
static void thread_terminate(struct event_context *event_ctx, const char *reason)
|
||||
{
|
||||
DEBUG(10,("thread_terminate: reason[%s]\n",reason));
|
||||
|
||||
talloc_free(event_ctx);
|
||||
|
||||
/* terminate this thread */
|
||||
pthread_exit(NULL); /* thread cleanup routine will do actual cleanup */
|
||||
}
|
||||
|
||||
/* called to set a title of a task or connection */
|
||||
static void thread_set_title(struct event_context *ev, const char *title)
|
||||
{
|
||||
char *old_title;
|
||||
char *new_title;
|
||||
|
||||
old_title = pthread_getspecific(title_key);
|
||||
talloc_free(old_title);
|
||||
|
||||
new_title = talloc_strdup(ev, title);
|
||||
pthread_setspecific(title_key, new_title);
|
||||
}
|
||||
|
||||
/*
|
||||
mutex init function for thread model
|
||||
*/
|
||||
static int thread_mutex_init(smb_mutex_t *mutex, const char *name)
|
||||
{
|
||||
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
|
||||
mutex->mutex = memdup(&m, sizeof(m));
|
||||
if (! mutex->mutex) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
return pthread_mutex_init((pthread_mutex_t *)mutex->mutex, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
mutex destroy function for thread model
|
||||
*/
|
||||
static int thread_mutex_destroy(smb_mutex_t *mutex, const char *name)
|
||||
{
|
||||
return pthread_mutex_destroy((pthread_mutex_t *)mutex->mutex);
|
||||
}
|
||||
|
||||
static void mutex_start_timer(struct timeval *tp1)
|
||||
{
|
||||
gettimeofday(tp1,NULL);
|
||||
}
|
||||
|
||||
static double mutex_end_timer(struct timeval tp1)
|
||||
{
|
||||
struct timeval tp2;
|
||||
gettimeofday(&tp2,NULL);
|
||||
return((tp2.tv_sec - tp1.tv_sec) +
|
||||
(tp2.tv_usec - tp1.tv_usec)*1.0e-6);
|
||||
}
|
||||
|
||||
/*
|
||||
mutex lock function for thread model
|
||||
*/
|
||||
static int thread_mutex_lock(smb_mutex_t *mutexP, const char *name)
|
||||
{
|
||||
pthread_mutex_t *mutex = (pthread_mutex_t *)mutexP->mutex;
|
||||
int rc;
|
||||
double t;
|
||||
struct timeval tp1;
|
||||
/* Test below is ONLY for debugging */
|
||||
if ((rc = pthread_mutex_trylock(mutex))) {
|
||||
if (rc == EBUSY) {
|
||||
mutex_start_timer(&tp1);
|
||||
printf("mutex lock: thread %d, lock %s not available\n",
|
||||
(uint32_t)pthread_self(), name);
|
||||
print_suspicious_usage("mutex_lock", name);
|
||||
pthread_mutex_lock(mutex);
|
||||
t = mutex_end_timer(tp1);
|
||||
printf("mutex lock: thread %d, lock %s now available, waited %g seconds\n",
|
||||
(uint32_t)pthread_self(), name, t);
|
||||
return 0;
|
||||
}
|
||||
printf("mutex lock: thread %d, lock %s failed rc=%d\n",
|
||||
(uint32_t)pthread_self(), name, rc);
|
||||
SMB_ASSERT(errno == 0); /* force error */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
mutex unlock for thread model
|
||||
*/
|
||||
static int thread_mutex_unlock(smb_mutex_t *mutex, const char *name)
|
||||
{
|
||||
return pthread_mutex_unlock((pthread_mutex_t *)mutex->mutex);
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
Read/write lock routines.
|
||||
*****************************************************************/
|
||||
/*
|
||||
rwlock init function for thread model
|
||||
*/
|
||||
static int thread_rwlock_init(smb_rwlock_t *rwlock, const char *name)
|
||||
{
|
||||
pthread_rwlock_t m = PTHREAD_RWLOCK_INITIALIZER;
|
||||
rwlock->rwlock = memdup(&m, sizeof(m));
|
||||
if (! rwlock->rwlock) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
return pthread_rwlock_init((pthread_rwlock_t *)rwlock->rwlock, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
rwlock destroy function for thread model
|
||||
*/
|
||||
static int thread_rwlock_destroy(smb_rwlock_t *rwlock, const char *name)
|
||||
{
|
||||
return pthread_rwlock_destroy((pthread_rwlock_t *)rwlock->rwlock);
|
||||
}
|
||||
|
||||
/*
|
||||
rwlock lock for read function for thread model
|
||||
*/
|
||||
static int thread_rwlock_lock_read(smb_rwlock_t *rwlockP, const char *name)
|
||||
{
|
||||
pthread_rwlock_t *rwlock = (pthread_rwlock_t *)rwlockP->rwlock;
|
||||
int rc;
|
||||
double t;
|
||||
struct timeval tp1;
|
||||
/* Test below is ONLY for debugging */
|
||||
if ((rc = pthread_rwlock_tryrdlock(rwlock))) {
|
||||
if (rc == EBUSY) {
|
||||
mutex_start_timer(&tp1);
|
||||
printf("rwlock lock_read: thread %d, lock %s not available\n",
|
||||
(uint32_t)pthread_self(), name);
|
||||
print_suspicious_usage("rwlock_lock_read", name);
|
||||
pthread_rwlock_rdlock(rwlock);
|
||||
t = mutex_end_timer(tp1);
|
||||
printf("rwlock lock_read: thread %d, lock %s now available, waited %g seconds\n",
|
||||
(uint32_t)pthread_self(), name, t);
|
||||
return 0;
|
||||
}
|
||||
printf("rwlock lock_read: thread %d, lock %s failed rc=%d\n",
|
||||
(uint32_t)pthread_self(), name, rc);
|
||||
SMB_ASSERT(errno == 0); /* force error */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
rwlock lock for write function for thread model
|
||||
*/
|
||||
static int thread_rwlock_lock_write(smb_rwlock_t *rwlockP, const char *name)
|
||||
{
|
||||
pthread_rwlock_t *rwlock = (pthread_rwlock_t *)rwlockP->rwlock;
|
||||
int rc;
|
||||
double t;
|
||||
struct timeval tp1;
|
||||
/* Test below is ONLY for debugging */
|
||||
if ((rc = pthread_rwlock_trywrlock(rwlock))) {
|
||||
if (rc == EBUSY) {
|
||||
mutex_start_timer(&tp1);
|
||||
printf("rwlock lock_write: thread %d, lock %s not available\n",
|
||||
(uint32_t)pthread_self(), name);
|
||||
print_suspicious_usage("rwlock_lock_write", name);
|
||||
pthread_rwlock_wrlock(rwlock);
|
||||
t = mutex_end_timer(tp1);
|
||||
printf("rwlock lock_write: thread %d, lock %s now available, waited %g seconds\n",
|
||||
(uint32_t)pthread_self(), name, t);
|
||||
return 0;
|
||||
}
|
||||
printf("rwlock lock_write: thread %d, lock %s failed rc=%d\n",
|
||||
(uint32_t)pthread_self(), name, rc);
|
||||
SMB_ASSERT(errno == 0); /* force error */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
rwlock unlock for thread model
|
||||
*/
|
||||
static int thread_rwlock_unlock(smb_rwlock_t *rwlock, const char *name)
|
||||
{
|
||||
return pthread_rwlock_unlock((pthread_rwlock_t *)rwlock->rwlock);
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
Log suspicious usage (primarily for possible thread-unsafe behavior).
|
||||
*****************************************************************/
|
||||
static void thread_log_suspicious_usage(const char* from, const char* info)
|
||||
{
|
||||
DEBUG(1,("log_suspicious_usage: from %s info='%s'\n", from, info));
|
||||
#ifdef HAVE_BACKTRACE
|
||||
{
|
||||
void *addresses[10];
|
||||
int num_addresses = backtrace(addresses, 8);
|
||||
char **bt_symbols = backtrace_symbols(addresses, num_addresses);
|
||||
int i;
|
||||
|
||||
if (bt_symbols) {
|
||||
for (i=0; i<num_addresses; i++) {
|
||||
DEBUG(1,("log_suspicious_usage: %s%s\n", DEBUGTAB(1), bt_symbols[i]));
|
||||
}
|
||||
free(bt_symbols);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
Log suspicious usage to stdout (primarily for possible thread-unsafe behavior.
|
||||
Used in mutex code where DEBUG calls would cause recursion.
|
||||
*****************************************************************/
|
||||
static void thread_print_suspicious_usage(const char* from, const char* info)
|
||||
{
|
||||
printf("log_suspicious_usage: from %s info='%s'\n", from, info);
|
||||
#ifdef HAVE_BACKTRACE
|
||||
{
|
||||
void *addresses[10];
|
||||
int num_addresses = backtrace(addresses, 8);
|
||||
char **bt_symbols = backtrace_symbols(addresses, num_addresses);
|
||||
int i;
|
||||
|
||||
if (bt_symbols) {
|
||||
for (i=0; i<num_addresses; i++) {
|
||||
printf("log_suspicious_usage: %s%s\n", DEBUGTAB(1), bt_symbols[i]);
|
||||
}
|
||||
free(bt_symbols);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint32_t thread_get_task_id(void)
|
||||
{
|
||||
return (uint32_t)pthread_self();
|
||||
}
|
||||
|
||||
static void thread_log_task_id(int fd)
|
||||
{
|
||||
char *s= NULL;
|
||||
|
||||
asprintf(&s, "thread[%u][%s]:\n",
|
||||
(uint32_t)pthread_self(),
|
||||
(const char *)pthread_getspecific(title_key));
|
||||
if (!s) return;
|
||||
write(fd, s, strlen(s));
|
||||
free(s);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
catch serious errors
|
||||
****************************************************************************/
|
||||
static void thread_sig_fault(int sig)
|
||||
{
|
||||
DEBUG(0,("===============================================================\n"));
|
||||
DEBUG(0,("TERMINAL ERROR: Recursive signal %d in thread [%u][%s] (%s)\n",
|
||||
sig,(uint32_t)pthread_self(),
|
||||
(const char *)pthread_getspecific(title_key),
|
||||
SAMBA_VERSION_STRING));
|
||||
DEBUG(0,("===============================================================\n"));
|
||||
exit(1); /* kill the whole server for now */
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
setup our recursive fault handlers
|
||||
********************************************************************/
|
||||
static void thread_fault_setup(void)
|
||||
{
|
||||
#ifdef SIGSEGV
|
||||
CatchSignal(SIGSEGV,SIGNAL_CAST thread_sig_fault);
|
||||
#endif
|
||||
#ifdef SIGBUS
|
||||
CatchSignal(SIGBUS,SIGNAL_CAST thread_sig_fault);
|
||||
#endif
|
||||
#ifdef SIGABRT
|
||||
CatchSignal(SIGABRT,SIGNAL_CAST thread_sig_fault);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
report a fault in a thread
|
||||
********************************************************************/
|
||||
static void thread_fault_handler(int sig)
|
||||
{
|
||||
static int counter;
|
||||
|
||||
/* try to catch recursive faults */
|
||||
thread_fault_setup();
|
||||
|
||||
counter++; /* count number of faults that have occurred */
|
||||
|
||||
DEBUG(0,("===============================================================\n"));
|
||||
DEBUG(0,("INTERNAL ERROR: Signal %d in thread [%u] [%s] (%s)\n",
|
||||
sig,(uint32_t)pthread_self(),
|
||||
(const char *)pthread_getspecific(title_key),
|
||||
SAMBA_VERSION_STRING));
|
||||
DEBUG(0,("Please read the file BUGS.txt in the distribution\n"));
|
||||
DEBUG(0,("===============================================================\n"));
|
||||
#ifdef HAVE_BACKTRACE
|
||||
{
|
||||
void *addresses[10];
|
||||
int num_addresses = backtrace(addresses, 8);
|
||||
char **bt_symbols = backtrace_symbols(addresses, num_addresses);
|
||||
int i;
|
||||
|
||||
if (bt_symbols) {
|
||||
for (i=0; i<num_addresses; i++) {
|
||||
DEBUG(1,("fault_report: %s%s\n", DEBUGTAB(1), bt_symbols[i]));
|
||||
}
|
||||
free(bt_symbols);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
pthread_exit(NULL); /* terminate failing thread only */
|
||||
}
|
||||
|
||||
/*
|
||||
called when the process model is selected
|
||||
*/
|
||||
static void thread_model_init(struct event_context *event_context)
|
||||
{
|
||||
struct mutex_ops m_ops;
|
||||
struct debug_ops d_ops;
|
||||
|
||||
ZERO_STRUCT(m_ops);
|
||||
ZERO_STRUCT(d_ops);
|
||||
|
||||
pthread_key_create(&title_key, NULL);
|
||||
pthread_setspecific(title_key, talloc_strdup(event_context, ""));
|
||||
|
||||
/* register mutex/rwlock handlers */
|
||||
m_ops.mutex_init = thread_mutex_init;
|
||||
m_ops.mutex_lock = thread_mutex_lock;
|
||||
m_ops.mutex_unlock = thread_mutex_unlock;
|
||||
m_ops.mutex_destroy = thread_mutex_destroy;
|
||||
|
||||
m_ops.rwlock_init = thread_rwlock_init;
|
||||
m_ops.rwlock_lock_write = thread_rwlock_lock_write;
|
||||
m_ops.rwlock_lock_read = thread_rwlock_lock_read;
|
||||
m_ops.rwlock_unlock = thread_rwlock_unlock;
|
||||
m_ops.rwlock_destroy = thread_rwlock_destroy;
|
||||
|
||||
register_mutex_handlers("thread", &m_ops);
|
||||
|
||||
register_fault_handler("thread", thread_fault_handler);
|
||||
|
||||
d_ops.log_suspicious_usage = thread_log_suspicious_usage;
|
||||
d_ops.print_suspicious_usage = thread_print_suspicious_usage;
|
||||
d_ops.get_task_id = thread_get_task_id;
|
||||
d_ops.log_task_id = thread_log_task_id;
|
||||
|
||||
register_debug_handlers("thread", &d_ops);
|
||||
}
|
||||
|
||||
|
||||
static const struct model_ops thread_ops = {
|
||||
.name = "thread",
|
||||
.model_init = thread_model_init,
|
||||
.accept_connection = thread_accept_connection,
|
||||
.new_task = thread_new_task,
|
||||
.terminate = thread_terminate,
|
||||
.set_title = thread_set_title,
|
||||
};
|
||||
|
||||
/*
|
||||
initialise the thread process model, registering ourselves with the model subsystem
|
||||
*/
|
||||
NTSTATUS process_model_thread_init(void)
|
||||
{
|
||||
NTSTATUS ret;
|
||||
|
||||
/* register ourselves with the PROCESS_MODEL subsystem. */
|
||||
ret = register_process_model(&thread_ops);
|
||||
if (!NT_STATUS_IS_OK(ret)) {
|
||||
DEBUG(0,("Failed to register process_model 'thread'!\n"));
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,326 @@
|
||||
/*
|
||||
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 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"
|
||||
#include "lib/events/events.h"
|
||||
#include "version.h"
|
||||
#include "lib/cmdline/popt_common.h"
|
||||
#include "system/dir.h"
|
||||
#include "system/filesys.h"
|
||||
#include "build.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"
|
||||
|
||||
/*
|
||||
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(void)
|
||||
{
|
||||
char *path;
|
||||
TALLOC_CTX *mem_ctx = talloc_new(NULL);
|
||||
|
||||
path = smbd_tmp_path(mem_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 = 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
|
||||
*/
|
||||
static void max_runtime_handler(struct event_context *ev, struct timed_event *te,
|
||||
struct timeval t, void *private)
|
||||
{
|
||||
const char *binary_name = 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 interactive = False;
|
||||
int opt;
|
||||
poptContext pc;
|
||||
init_module_fn static_init[] = STATIC_service_MODULES;
|
||||
init_module_fn *shared_init;
|
||||
struct event_context *event_ctx;
|
||||
NTSTATUS status;
|
||||
const char *model = "standard";
|
||||
int max_runtime = 0;
|
||||
enum {
|
||||
OPT_INTERACTIVE = 1000,
|
||||
OPT_PROCESS_MODEL
|
||||
};
|
||||
struct poptOption long_options[] = {
|
||||
POPT_AUTOHELP
|
||||
{"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_INTERACTIVE:
|
||||
interactive = True;
|
||||
break;
|
||||
case OPT_PROCESS_MODEL:
|
||||
model = poptGetOptArg(pc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
poptFreeContext(pc);
|
||||
|
||||
setup_logging(binary_name, 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-2006\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"));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!interactive) {
|
||||
DEBUG(3,("Becoming a daemon.\n"));
|
||||
become_daemon(True);
|
||||
}
|
||||
|
||||
cleanup_tmp_files();
|
||||
|
||||
if (!directory_exist(lp_lockdir())) {
|
||||
mkdir(lp_lockdir(), 0755);
|
||||
}
|
||||
|
||||
pidfile_create(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()) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ldb_global_init(); /* FIXME: */
|
||||
|
||||
share_init();
|
||||
|
||||
gensec_init(); /* FIXME: */
|
||||
|
||||
registry_init(); /* FIXME: maybe run this in the initialization function
|
||||
of the winreg RPC server instead? */
|
||||
|
||||
ntptr_init(); /* FIXME: maybe run this in the initialization function
|
||||
of the spoolss RPC server instead? */
|
||||
|
||||
ntvfs_init(); /* FIXME: maybe run this in the initialization functions
|
||||
of the SMB[,2] server instead? */
|
||||
|
||||
process_model_init();
|
||||
|
||||
shared_init = load_samba_modules(NULL, "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 = event_context_init(NULL);
|
||||
|
||||
if (interactive) {
|
||||
/* catch EOF on stdin */
|
||||
#ifdef SIGTTIN
|
||||
signal(SIGTTIN, SIG_IGN);
|
||||
#endif
|
||||
event_add_fd(event_ctx, event_ctx, 0, EVENT_FD_READ,
|
||||
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, model, lp_server_services());
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
SERVER SERVICE code
|
||||
|
||||
Copyright (C) Andrew Tridgell 2003-2005
|
||||
Copyright (C) Stefan (metze) Metzmacher 2004
|
||||
|
||||
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"
|
||||
#include "lib/util/dlinklist.h"
|
||||
#include "smbd/process_model.h"
|
||||
|
||||
/*
|
||||
a linked list of registered servers
|
||||
*/
|
||||
static struct registered_server {
|
||||
struct registered_server *next, *prev;
|
||||
const char *service_name;
|
||||
NTSTATUS (*service_init)(struct event_context *, const struct model_ops *);
|
||||
} *registered_servers;
|
||||
|
||||
/*
|
||||
register a server service.
|
||||
*/
|
||||
NTSTATUS register_server_service(const char *name,
|
||||
NTSTATUS (*service_init)(struct event_context *, const struct model_ops *))
|
||||
{
|
||||
struct registered_server *srv;
|
||||
srv = talloc(talloc_autofree_context(), struct registered_server);
|
||||
NT_STATUS_HAVE_NO_MEMORY(srv);
|
||||
srv->service_name = name;
|
||||
srv->service_init = service_init;
|
||||
DLIST_ADD_END(registered_servers, srv, struct registered_server *);
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
initialise a server service
|
||||
*/
|
||||
static NTSTATUS server_service_init(const char *name,
|
||||
struct event_context *event_ctx,
|
||||
const struct model_ops *model_ops)
|
||||
{
|
||||
struct registered_server *srv;
|
||||
for (srv=registered_servers; srv; srv=srv->next) {
|
||||
if (strcasecmp(name, srv->service_name) == 0) {
|
||||
return srv->service_init(event_ctx, model_ops);
|
||||
}
|
||||
}
|
||||
return NT_STATUS_INVALID_SYSTEM_SERVICE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
startup all of our server services
|
||||
*/
|
||||
NTSTATUS server_service_startup(struct event_context *event_ctx,
|
||||
const char *model, const char **server_services)
|
||||
{
|
||||
int i;
|
||||
const struct model_ops *model_ops;
|
||||
|
||||
if (!server_services) {
|
||||
DEBUG(0,("server_service_startup: no endpoint servers configured\n"));
|
||||
return NT_STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
model_ops = process_model_startup(event_ctx, model);
|
||||
if (!model_ops) {
|
||||
DEBUG(0,("process_model_startup('%s') failed\n", model));
|
||||
return NT_STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
for (i=0;server_services[i];i++) {
|
||||
NTSTATUS status;
|
||||
|
||||
status = server_service_init(server_services[i], event_ctx, model_ops);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(0,("Failed to start service '%s' - %s\n",
|
||||
server_services[i], nt_errstr(status)));
|
||||
}
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
}
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
SERVER SERVICE code
|
||||
|
||||
Copyright (C) Andrew Tridgell 2003-2005
|
||||
Copyright (C) Stefan (metze) Metzmacher 2004
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef __SERVICE_H__
|
||||
#define __SERVICE_H__
|
||||
|
||||
#include "smbd/service_stream.h"
|
||||
#include "smbd/service_task.h"
|
||||
#include "smbd/service_proto.h"
|
||||
|
||||
#endif /* __SERVICE_H__ */
|
||||
@@ -0,0 +1,309 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
helper functions for stream based servers
|
||||
|
||||
Copyright (C) Andrew Tridgell 2003-2005
|
||||
Copyright (C) Stefan (metze) Metzmacher 2004
|
||||
|
||||
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"
|
||||
#include "process_model.h"
|
||||
#include "lib/events/events.h"
|
||||
#include "lib/socket/socket.h"
|
||||
#include "smbd/service.h"
|
||||
#include "smbd/service_stream.h"
|
||||
#include "lib/messaging/irpc.h"
|
||||
|
||||
/* the range of ports to try for dcerpc over tcp endpoints */
|
||||
#define SERVER_TCP_LOW_PORT 1024
|
||||
#define SERVER_TCP_HIGH_PORT 1300
|
||||
|
||||
/* size of listen() backlog in smbd */
|
||||
#define SERVER_LISTEN_BACKLOG 10
|
||||
|
||||
|
||||
/*
|
||||
private structure for a single listening stream socket
|
||||
*/
|
||||
struct stream_socket {
|
||||
const struct stream_server_ops *ops;
|
||||
struct event_context *event_ctx;
|
||||
const struct model_ops *model_ops;
|
||||
struct socket_context *sock;
|
||||
void *private;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
close the socket and shutdown a stream_connection
|
||||
*/
|
||||
void stream_terminate_connection(struct stream_connection *srv_conn, const char *reason)
|
||||
{
|
||||
struct event_context *event_ctx = srv_conn->event.ctx;
|
||||
const struct model_ops *model_ops = srv_conn->model_ops;
|
||||
|
||||
if (!reason) reason = "unknown reason";
|
||||
|
||||
srv_conn->terminate = reason;
|
||||
|
||||
if (srv_conn->processing) {
|
||||
/*
|
||||
* if we're currently inside the stream_io_handler(),
|
||||
* defer the termination to the end of stream_io_hendler()
|
||||
*
|
||||
* and we don't want to read or write to the connection...
|
||||
*/
|
||||
event_set_fd_flags(srv_conn->event.fde, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
talloc_free(srv_conn->event.fde);
|
||||
srv_conn->event.fde = NULL;
|
||||
talloc_free(srv_conn);
|
||||
model_ops->terminate(event_ctx, reason);
|
||||
}
|
||||
|
||||
/*
|
||||
the select loop has indicated that a stream is ready for IO
|
||||
*/
|
||||
static void stream_io_handler(struct stream_connection *conn, uint16_t flags)
|
||||
{
|
||||
conn->processing = True;
|
||||
if (flags & EVENT_FD_WRITE) {
|
||||
conn->ops->send_handler(conn, flags);
|
||||
} else if (flags & EVENT_FD_READ) {
|
||||
conn->ops->recv_handler(conn, flags);
|
||||
}
|
||||
conn->processing = False;
|
||||
|
||||
if (conn->terminate) {
|
||||
stream_terminate_connection(conn, conn->terminate);
|
||||
}
|
||||
}
|
||||
|
||||
static void stream_io_handler_fde(struct event_context *ev, struct fd_event *fde,
|
||||
uint16_t flags, void *private)
|
||||
{
|
||||
struct stream_connection *conn = talloc_get_type(private,
|
||||
struct stream_connection);
|
||||
stream_io_handler(conn, flags);
|
||||
}
|
||||
|
||||
void stream_io_handler_callback(void *private, uint16_t flags)
|
||||
{
|
||||
struct stream_connection *conn = talloc_get_type(private,
|
||||
struct stream_connection);
|
||||
stream_io_handler(conn, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
this creates a stream_connection from an already existing connection,
|
||||
used for protocols, where a client connection needs to switched into
|
||||
a server connection
|
||||
*/
|
||||
NTSTATUS stream_new_connection_merge(struct event_context *ev,
|
||||
const struct model_ops *model_ops,
|
||||
struct socket_context *sock,
|
||||
const struct stream_server_ops *stream_ops,
|
||||
struct messaging_context *msg_ctx,
|
||||
void *private_data,
|
||||
struct stream_connection **_srv_conn)
|
||||
{
|
||||
struct stream_connection *srv_conn;
|
||||
|
||||
srv_conn = talloc_zero(ev, struct stream_connection);
|
||||
NT_STATUS_HAVE_NO_MEMORY(srv_conn);
|
||||
|
||||
talloc_steal(srv_conn, sock);
|
||||
|
||||
srv_conn->private = private_data;
|
||||
srv_conn->model_ops = model_ops;
|
||||
srv_conn->socket = sock;
|
||||
srv_conn->server_id = 0;
|
||||
srv_conn->ops = stream_ops;
|
||||
srv_conn->msg_ctx = msg_ctx;
|
||||
srv_conn->event.ctx = ev;
|
||||
srv_conn->event.fde = event_add_fd(ev, srv_conn, socket_get_fd(sock),
|
||||
EVENT_FD_READ,
|
||||
stream_io_handler_fde, srv_conn);
|
||||
*_srv_conn = srv_conn;
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
called when a new socket connection has been established. This is called in the process
|
||||
context of the new process (if appropriate)
|
||||
*/
|
||||
static void stream_new_connection(struct event_context *ev,
|
||||
struct socket_context *sock,
|
||||
uint32_t server_id, void *private)
|
||||
{
|
||||
struct stream_socket *stream_socket = talloc_get_type(private, struct stream_socket);
|
||||
struct stream_connection *srv_conn;
|
||||
struct socket_address *c, *s;
|
||||
|
||||
srv_conn = talloc_zero(ev, struct stream_connection);
|
||||
if (!srv_conn) {
|
||||
DEBUG(0,("talloc(mem_ctx, struct stream_connection) failed\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
talloc_steal(srv_conn, sock);
|
||||
|
||||
srv_conn->private = stream_socket->private;
|
||||
srv_conn->model_ops = stream_socket->model_ops;
|
||||
srv_conn->socket = sock;
|
||||
srv_conn->server_id = server_id;
|
||||
srv_conn->ops = stream_socket->ops;
|
||||
srv_conn->event.ctx = ev;
|
||||
srv_conn->event.fde = event_add_fd(ev, srv_conn, socket_get_fd(sock),
|
||||
EVENT_FD_READ,
|
||||
stream_io_handler_fde, srv_conn);
|
||||
|
||||
if (!socket_check_access(sock, "smbd", lp_hostsallow(-1), lp_hostsdeny(-1))) {
|
||||
stream_terminate_connection(srv_conn, "denied by access rules");
|
||||
return;
|
||||
}
|
||||
|
||||
/* setup to receive internal messages on this connection */
|
||||
srv_conn->msg_ctx = messaging_init(srv_conn, srv_conn->server_id, ev);
|
||||
if (!srv_conn->msg_ctx) {
|
||||
stream_terminate_connection(srv_conn, "messaging_init() failed");
|
||||
return;
|
||||
}
|
||||
|
||||
c = socket_get_peer_addr(sock, ev);
|
||||
s = socket_get_my_addr(sock, ev);
|
||||
if (s && c) {
|
||||
const char *title;
|
||||
title = talloc_asprintf(s, "conn[%s] c[%s:%u] s[%s:%u] server_id[%d]",
|
||||
stream_socket->ops->name,
|
||||
c->addr, c->port, s->addr, s->port,
|
||||
server_id);
|
||||
if (title) {
|
||||
stream_connection_set_title(srv_conn, title);
|
||||
}
|
||||
}
|
||||
talloc_free(c);
|
||||
talloc_free(s);
|
||||
|
||||
/* call the server specific accept code */
|
||||
stream_socket->ops->accept_connection(srv_conn);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
called when someone opens a connection to one of our listening ports
|
||||
*/
|
||||
static void stream_accept_handler(struct event_context *ev, struct fd_event *fde,
|
||||
uint16_t flags, void *private)
|
||||
{
|
||||
struct stream_socket *stream_socket = talloc_get_type(private, struct stream_socket);
|
||||
|
||||
/* ask the process model to create us a process for this new
|
||||
connection. When done, it calls stream_new_connection()
|
||||
with the newly created socket */
|
||||
stream_socket->model_ops->accept_connection(ev, stream_socket->sock,
|
||||
stream_new_connection, stream_socket);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
setup a listen stream socket
|
||||
if you pass *port == 0, then a port > 1024 is used
|
||||
*/
|
||||
NTSTATUS stream_setup_socket(struct event_context *event_context,
|
||||
const struct model_ops *model_ops,
|
||||
const struct stream_server_ops *stream_ops,
|
||||
const char *family,
|
||||
const char *sock_addr,
|
||||
uint16_t *port,
|
||||
void *private)
|
||||
{
|
||||
NTSTATUS status;
|
||||
struct stream_socket *stream_socket;
|
||||
struct socket_address *socket_address;
|
||||
int i;
|
||||
|
||||
stream_socket = talloc_zero(event_context, struct stream_socket);
|
||||
NT_STATUS_HAVE_NO_MEMORY(stream_socket);
|
||||
|
||||
status = socket_create(family, SOCKET_TYPE_STREAM, &stream_socket->sock, 0);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
|
||||
talloc_steal(stream_socket, stream_socket->sock);
|
||||
|
||||
/* ready to listen */
|
||||
status = socket_set_option(stream_socket->sock, "SO_KEEPALIVE", NULL);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
|
||||
status = socket_set_option(stream_socket->sock, lp_socket_options(), NULL);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
|
||||
/* TODO: set socket ACL's here when they're implemented */
|
||||
|
||||
if (*port == 0) {
|
||||
for (i=SERVER_TCP_LOW_PORT;i<= SERVER_TCP_HIGH_PORT;i++) {
|
||||
socket_address = socket_address_from_strings(stream_socket,
|
||||
stream_socket->sock->backend_name,
|
||||
sock_addr, i);
|
||||
NT_STATUS_HAVE_NO_MEMORY(socket_address);
|
||||
status = socket_listen(stream_socket->sock, socket_address,
|
||||
SERVER_LISTEN_BACKLOG, 0);
|
||||
talloc_free(socket_address);
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
*port = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
socket_address = socket_address_from_strings(stream_socket,
|
||||
stream_socket->sock->backend_name,
|
||||
sock_addr, *port);
|
||||
NT_STATUS_HAVE_NO_MEMORY(socket_address);
|
||||
status = socket_listen(stream_socket->sock, socket_address, SERVER_LISTEN_BACKLOG, 0);
|
||||
talloc_free(socket_address);
|
||||
}
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(0,("Failed to listen on %s:%u - %s\n",
|
||||
sock_addr, *port, nt_errstr(status)));
|
||||
talloc_free(stream_socket);
|
||||
return status;
|
||||
}
|
||||
|
||||
event_add_fd(event_context, stream_socket->sock,
|
||||
socket_get_fd(stream_socket->sock),
|
||||
EVENT_FD_READ, stream_accept_handler, stream_socket);
|
||||
|
||||
stream_socket->private = talloc_reference(stream_socket, private);
|
||||
stream_socket->ops = stream_ops;
|
||||
stream_socket->event_ctx = event_context;
|
||||
stream_socket->model_ops = model_ops;
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
setup a connection title
|
||||
*/
|
||||
void stream_connection_set_title(struct stream_connection *conn, const char *title)
|
||||
{
|
||||
conn->model_ops->set_title(conn->event.ctx, title);
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
structures specific to stream servers
|
||||
|
||||
Copyright (C) Stefan (metze) Metzmacher 2004
|
||||
Copyright (C) Andrew Tridgell 2005
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef __SERVICE_STREAM_H__
|
||||
#define __SERVICE_STREAM_H__
|
||||
|
||||
/* modules can use the following to determine if the interface has changed
|
||||
* please increment the version number after each interface change
|
||||
* with a comment and maybe update struct stream_connection_critical_sizes.
|
||||
*/
|
||||
/* version 0 - initial version - metze */
|
||||
#define SERVER_SERVICE_VERSION 0
|
||||
|
||||
/*
|
||||
top level context for an established stream connection
|
||||
*/
|
||||
struct stream_connection {
|
||||
const struct stream_server_ops *ops;
|
||||
const struct model_ops *model_ops;
|
||||
uint32_t server_id;
|
||||
void *private;
|
||||
|
||||
struct {
|
||||
struct event_context *ctx;
|
||||
struct fd_event *fde;
|
||||
} event;
|
||||
|
||||
struct socket_context *socket;
|
||||
struct messaging_context *msg_ctx;
|
||||
|
||||
BOOL processing;
|
||||
const char *terminate;
|
||||
};
|
||||
|
||||
|
||||
/* operations passed to the service_stream code */
|
||||
struct stream_server_ops {
|
||||
/* the name of the server_service */
|
||||
const char *name;
|
||||
void (*accept_connection)(struct stream_connection *);
|
||||
void (*recv_handler)(struct stream_connection *, uint16_t);
|
||||
void (*send_handler)(struct stream_connection *, uint16_t);
|
||||
};
|
||||
|
||||
#endif /* __SERVICE_STREAM_H__ */
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
helper functions for task based servers (nbtd, winbind etc)
|
||||
|
||||
Copyright (C) Andrew Tridgell 2005
|
||||
|
||||
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"
|
||||
#include "process_model.h"
|
||||
#include "lib/events/events.h"
|
||||
#include "smbd/service.h"
|
||||
#include "smbd/service_task.h"
|
||||
#include "lib/messaging/irpc.h"
|
||||
|
||||
/*
|
||||
terminate a task service
|
||||
*/
|
||||
void task_server_terminate(struct task_server *task, const char *reason)
|
||||
{
|
||||
struct event_context *event_ctx = task->event_ctx;
|
||||
const struct model_ops *model_ops = task->model_ops;
|
||||
DEBUG(0,("task_server_terminate: [%s]\n", reason));
|
||||
talloc_free(task);
|
||||
model_ops->terminate(event_ctx, reason);
|
||||
}
|
||||
|
||||
/* used for the callback from the process model code */
|
||||
struct task_state {
|
||||
void (*task_init)(struct task_server *);
|
||||
const struct model_ops *model_ops;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
called by the process model code when the new task starts up. This then calls
|
||||
the server specific startup code
|
||||
*/
|
||||
static void task_server_callback(struct event_context *event_ctx, uint32_t server_id, void *private)
|
||||
{
|
||||
struct task_state *state = talloc_get_type(private, struct task_state);
|
||||
struct task_server *task;
|
||||
|
||||
task = talloc(event_ctx, struct task_server);
|
||||
if (task == NULL) return;
|
||||
|
||||
task->event_ctx = event_ctx;
|
||||
task->model_ops = state->model_ops;
|
||||
task->server_id = server_id;
|
||||
|
||||
task->msg_ctx = messaging_init(task, task->server_id, task->event_ctx);
|
||||
if (!task->msg_ctx) {
|
||||
task_server_terminate(task, "messaging_init() failed");
|
||||
return;
|
||||
}
|
||||
|
||||
state->task_init(task);
|
||||
}
|
||||
|
||||
/*
|
||||
startup a task based server
|
||||
*/
|
||||
NTSTATUS task_server_startup(struct event_context *event_ctx,
|
||||
const struct model_ops *model_ops,
|
||||
void (*task_init)(struct task_server *))
|
||||
{
|
||||
struct task_state *state;
|
||||
|
||||
state = talloc(event_ctx, struct task_state);
|
||||
NT_STATUS_HAVE_NO_MEMORY(state);
|
||||
|
||||
state->task_init = task_init;
|
||||
state->model_ops = model_ops;
|
||||
|
||||
model_ops->new_task(event_ctx, task_server_callback, state);
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
setup a task title
|
||||
*/
|
||||
void task_server_set_title(struct task_server *task, const char *title)
|
||||
{
|
||||
task->model_ops->set_title(task->event_ctx, title);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
structures for task based servers
|
||||
|
||||
Copyright (C) Andrew Tridgell 2005
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef __SERVICE_TASK_H__
|
||||
#define __SERVICE_TASK_H__
|
||||
|
||||
struct task_server {
|
||||
struct event_context *event_ctx;
|
||||
const struct model_ops *model_ops;
|
||||
struct messaging_context *msg_ctx;
|
||||
uint32_t server_id;
|
||||
void *private;
|
||||
};
|
||||
|
||||
#endif /* __SERVICE_TASK_H__ */
|
||||
@@ -0,0 +1,177 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!DOCTYPE refentry PUBLIC "-//Samba-Team//DTD DocBook V4.2-Based Variant V1.0//EN" "http://www.samba.org/samba/DTD/samba-doc">
|
||||
<refentry id="smbd.8">
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>smbd</refentrytitle>
|
||||
<manvolnum>8</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
|
||||
<refnamediv>
|
||||
<refname>smbd</refname>
|
||||
<refpurpose>server to provide filesharing- and directory services to clients</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>smbd</command>
|
||||
<arg choice="opt">-i</arg>
|
||||
<arg choice="opt">-M model</arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>DESCRIPTION</title>
|
||||
<para>This program is part of the <citerefentry><refentrytitle>samba</refentrytitle>
|
||||
<manvolnum>7</manvolnum></citerefentry> suite.</para>
|
||||
|
||||
<para><command>smbd</command> is the server daemon that
|
||||
provides filesharing and directory services to Windows clients.
|
||||
The server provides filespace and directory services to
|
||||
clients using the SMB (or CIFS) protocol and other
|
||||
related protocols such as DCE/RPC, LDAP and Kerberos.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Clients supported include MSCLIENT 3.0 for DOS, Windows for
|
||||
Workgroups, Windows 95/98/ME, Windows NT, Windows 2000/XP/2003,
|
||||
OS/2, DAVE for Macintosh, and cifsfs for Linux.</para>
|
||||
|
||||
<para>An extensive description of the services that the
|
||||
server can provide is given in the man page for the
|
||||
configuration file controlling the attributes of those
|
||||
services (see <citerefentry><refentrytitle>smb.conf</refentrytitle>
|
||||
<manvolnum>5</manvolnum></citerefentry>. This man page will not describe the
|
||||
services, but will concentrate on the administrative aspects
|
||||
of running the server.</para>
|
||||
|
||||
<para>Please note that there are significant security
|
||||
implications to running this server, and the <citerefentry><refentrytitle>smb.conf</refentrytitle>
|
||||
<manvolnum>5</manvolnum></citerefentry> manual page should be regarded as mandatory reading before
|
||||
proceeding with installation.</para>
|
||||
|
||||
<para>As of Samba 4, smbd also incorporates all the functionality of
|
||||
nmbd.</para>
|
||||
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>OPTIONS</title>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>-i</term>
|
||||
<listitem><para>If this parameter is specified it causes the
|
||||
server to run "interactively", not as a daemon, even if the
|
||||
server is executed on the command line of a shell. Setting this
|
||||
parameter negates the implicit deamon mode when run from the
|
||||
command line. <command>smbd</command> also logs to standard
|
||||
output, as if the <command>-S</command> parameter had been
|
||||
given.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>-M model</term>
|
||||
<listitem><para>This parameter can be used to specify the
|
||||
"process model" smbd should use. This determines
|
||||
how concurrent clients are handled. Available process
|
||||
models include <emphasis>single</emphasis> (everything in
|
||||
a single process), <emphasis>standard</emphasis> (similar
|
||||
behaviour to that of Samba 3), <emphasis>thread</emphasis>
|
||||
(single process, different threads.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>FILES</title>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><filename>/etc/rc</filename></term>
|
||||
<listitem><para>or whatever initialization script your
|
||||
system uses).</para>
|
||||
|
||||
<para>If running the server as a daemon at startup,
|
||||
this file will need to contain an appropriate startup
|
||||
sequence for the server. </para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><filename>/etc/services</filename></term>
|
||||
<listitem><para>If running the server via the
|
||||
meta-daemon <command>inetd</command>, this file
|
||||
must contain a mapping of service name (e.g., netbios-ssn)
|
||||
to service port (e.g., 139) and protocol type (e.g., tcp).
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><filename>/usr/local/samba/lib/smb.conf</filename></term>
|
||||
<listitem><para>This is the default location of the <citerefentry><refentrytitle>smb.conf</refentrytitle>
|
||||
<manvolnum>5</manvolnum></citerefentry> server configuration file. Other common places that systems
|
||||
install this file are <filename>/usr/samba/lib/smb.conf</filename>
|
||||
and <filename>/etc/samba/smb.conf</filename>.</para>
|
||||
|
||||
<para>This file describes all the services the server
|
||||
is to make available to clients. See <citerefentry><refentrytitle>smb.conf</refentrytitle>
|
||||
<manvolnum>5</manvolnum></citerefentry> for more information.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>VERSION</title>
|
||||
|
||||
<para>This man page is correct for version 4 of
|
||||
the Samba suite.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>DIAGNOSTICS</title>
|
||||
|
||||
<para>Most diagnostics issued by the server are logged
|
||||
in a specified log file. The log file name is specified
|
||||
at compile time, but may be overridden on the command line.</para>
|
||||
|
||||
<para>The number and nature of diagnostics available depends
|
||||
on the debug level used by the server. If you have problems, set
|
||||
the debug level to 3 and peruse the log files.</para>
|
||||
|
||||
<para>Most messages are reasonably self-explanatory. Unfortunately,
|
||||
at the time this man page was created, there are too many diagnostics
|
||||
available in the source code to warrant describing each and every
|
||||
diagnostic. At this stage your best bet is still to grep the
|
||||
source code and inspect the conditions that gave rise to the
|
||||
diagnostics you are seeing.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>SEE ALSO</title>
|
||||
<para><citerefentry><refentrytitle>hosts_access</refentrytitle>
|
||||
<manvolnum>5</manvolnum></citerefentry>
|
||||
<citerefentry><refentrytitle>smb.conf</refentrytitle>
|
||||
<manvolnum>5</manvolnum></citerefentry>, <citerefentry><refentrytitle>smbclient</refentrytitle>
|
||||
<manvolnum>1</manvolnum></citerefentry>, <citerefentry><refentrytitle>testparm</refentrytitle>
|
||||
<manvolnum>1</manvolnum></citerefentry>, and the
|
||||
Internet RFC's <filename>rfc1001.txt</filename>, <filename>rfc1002.txt</filename>.
|
||||
In addition the CIFS (formerly SMB) specification is available
|
||||
as a link from the Web page <ulink noescape="1" url="http://samba.org/cifs/">
|
||||
http://samba.org/cifs/</ulink>.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>AUTHOR</title>
|
||||
|
||||
<para>The original Samba software and related utilities
|
||||
were created by Andrew Tridgell. Samba is now developed
|
||||
by the Samba Team as an Open Source project similar
|
||||
to the way the Linux kernel is developed.</para>
|
||||
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
||||
Reference in New Issue
Block a user