mirror of
https://github.com/samba-team/samba.git
synced 2024-12-22 13:34:15 +03:00
r5102: This is a major simplification of the logic for controlling top level
servers in smbd. The old code still contained a fairly bit of legacy
from the time when smbd was only handling SMB connection. The new code
gets rid of all of the smb_server specific code in smbd/, and creates
a much simpler infrastructures for new server code.
Major changes include:
- simplified the process model code a lot.
- got rid of the top level server and service structures
completely. The top level context is now the event_context. This
got rid of service.h and server.h completely (they were the most
confusing parts of the old code)
- added service_stream.[ch] for the helper functions that are
specific to stream type services (services that handle streams, and
use a logically separate process per connection)
- got rid of the builtin idle_handler code in the service logic, as
none of the servers were using it, and it can easily be handled by
a server in future by adding its own timed_event to the event
context.
- fixed some major memory leaks in the rpc server code.
- added registration of servers, rather than hard coding our list of
possible servers. This allows for servers as modules in the future.
- temporarily disabled the winbind code until I add the helper
functions for that type of server
- added error checking on service startup. If a configured server
fails to startup then smbd doesn't startup.
- cleaned up the command line handling in smbd, removing unused options
(This used to be commit cf6a46c3cb
)
This commit is contained in:
parent
5540449f1c
commit
55d4d36993
@ -54,8 +54,7 @@ sub smb_build_main($)
|
||||
"client/config.mk",
|
||||
"libcli/libsmb.mk",
|
||||
"libcli/config.mk",
|
||||
"libcli/security/config.mk",
|
||||
"winbind/config.mk",
|
||||
"libcli/security/config.mk"
|
||||
);
|
||||
|
||||
$| = 1;
|
||||
|
@ -139,8 +139,6 @@ extern int errno;
|
||||
#include "lib/dcom/common/dcom.h"
|
||||
#include "librpc/gen_ndr/ndr_dcom.h"
|
||||
#include "smb_interfaces.h"
|
||||
#include "smbd/server.h"
|
||||
#include "smbd/service.h"
|
||||
#include "ntvfs/ntvfs.h"
|
||||
#include "cli_context.h"
|
||||
#include "nsswitch/winbind_client.h"
|
||||
|
@ -151,3 +151,8 @@ struct nbt_name_socket;
|
||||
struct nbt_name_query;
|
||||
struct nbt_name_status;
|
||||
|
||||
|
||||
struct messaging_context;
|
||||
struct stream_connection;
|
||||
struct model_ops;
|
||||
struct stream_server_ops;
|
||||
|
@ -25,107 +25,14 @@
|
||||
#include "dlinklist.h"
|
||||
#include "asn_1.h"
|
||||
#include "ldap_server/ldap_server.h"
|
||||
#include "smbd/service_stream.h"
|
||||
|
||||
/*
|
||||
close the socket and shutdown a server_context
|
||||
*/
|
||||
static void ldapsrv_terminate_connection(struct ldapsrv_connection *ldap_conn, const char *reason)
|
||||
{
|
||||
server_terminate_connection(ldap_conn->connection, reason);
|
||||
}
|
||||
|
||||
static const struct server_stream_ops *ldapsrv_get_stream_ops(void);
|
||||
|
||||
/*
|
||||
add a socket address to the list of events, one event per port
|
||||
*/
|
||||
static void add_socket(struct server_service *service,
|
||||
struct ipv4_addr *ifip)
|
||||
{
|
||||
struct server_stream_socket *stream_socket;
|
||||
uint16_t port = 389;
|
||||
char *ip_str = talloc_strdup(service, sys_inet_ntoa(*ifip));
|
||||
|
||||
stream_socket = service_setup_stream_socket(service, ldapsrv_get_stream_ops(), "ipv4", ip_str, &port);
|
||||
|
||||
port = 3268;
|
||||
stream_socket = service_setup_stream_socket(service, ldapsrv_get_stream_ops(), "ipv4", ip_str, &port);
|
||||
|
||||
talloc_free(ip_str);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Open the socket communication.
|
||||
****************************************************************************/
|
||||
static void ldapsrv_init(struct server_service *service)
|
||||
{
|
||||
struct ldapsrv_service *ldap_service;
|
||||
struct ldapsrv_partition *rootDSE_part;
|
||||
struct ldapsrv_partition *part;
|
||||
|
||||
DEBUG(10,("ldapsrv_init\n"));
|
||||
|
||||
ldap_service = talloc(service, struct ldapsrv_service);
|
||||
if (!ldap_service) {
|
||||
DEBUG(0,("talloc(service, struct ldapsrv_service) failed\n"));
|
||||
return;
|
||||
}
|
||||
ZERO_STRUCTP(ldap_service);
|
||||
|
||||
rootDSE_part = talloc(ldap_service, struct ldapsrv_partition);
|
||||
if (!rootDSE_part) {
|
||||
DEBUG(0,("talloc(ldap_service, struct ldapsrv_partition) failed\n"));
|
||||
return;
|
||||
}
|
||||
rootDSE_part->base_dn = ""; /* RootDSE */
|
||||
rootDSE_part->ops = ldapsrv_get_rootdse_partition_ops();
|
||||
|
||||
ldap_service->rootDSE = rootDSE_part;
|
||||
DLIST_ADD_END(ldap_service->partitions, rootDSE_part, struct ldapsrv_partition *);
|
||||
|
||||
part = talloc(ldap_service, struct ldapsrv_partition);
|
||||
if (!ldap_service) {
|
||||
DEBUG(0,("talloc(ldap_service, struct ldapsrv_partition) failed\n"));
|
||||
return;
|
||||
}
|
||||
part->base_dn = "*"; /* default partition */
|
||||
if (lp_parm_bool(-1, "ldapsrv", "hacked", False)) {
|
||||
part->ops = ldapsrv_get_hldb_partition_ops();
|
||||
} else {
|
||||
part->ops = ldapsrv_get_sldb_partition_ops();
|
||||
}
|
||||
|
||||
ldap_service->default_partition = part;
|
||||
DLIST_ADD_END(ldap_service->partitions, part, struct ldapsrv_partition *);
|
||||
|
||||
service->service.private_data = ldap_service;
|
||||
|
||||
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 ipv4_addr *ifip = iface_n_ip(i);
|
||||
|
||||
if (ifip == NULL) {
|
||||
DEBUG(0,("ldapsrv_init: interface %d has NULL "
|
||||
"IP address !\n", i));
|
||||
continue;
|
||||
}
|
||||
|
||||
add_socket(service, ifip);
|
||||
}
|
||||
} else {
|
||||
struct ipv4_addr ifip;
|
||||
|
||||
/* Just bind to lp_socket_address() (usually 0.0.0.0) */
|
||||
ifip = interpret_addr2(lp_socket_address());
|
||||
add_socket(service, &ifip);
|
||||
}
|
||||
stream_terminate_connection(ldap_conn->connection, reason);
|
||||
}
|
||||
|
||||
/* This rw-buf api is made to avoid memcpy. For now do that like mad... The
|
||||
@ -421,10 +328,10 @@ NTSTATUS ldapsrv_flush_responses(struct ldapsrv_connection *conn)
|
||||
/*
|
||||
called when a LDAP socket becomes readable
|
||||
*/
|
||||
static void ldapsrv_recv(struct server_connection *conn, struct timeval t,
|
||||
static void ldapsrv_recv(struct stream_connection *conn, struct timeval t,
|
||||
uint16_t flags)
|
||||
{
|
||||
struct ldapsrv_connection *ldap_conn = conn->connection.private_data;
|
||||
struct ldapsrv_connection *ldap_conn = talloc_get_type(conn->private, struct ldapsrv_connection);
|
||||
uint8_t *buf;
|
||||
size_t buf_length, msg_length;
|
||||
DATA_BLOB blob;
|
||||
@ -517,10 +424,10 @@ static void ldapsrv_recv(struct server_connection *conn, struct timeval t,
|
||||
/*
|
||||
called when a LDAP socket becomes writable
|
||||
*/
|
||||
static void ldapsrv_send(struct server_connection *conn, struct timeval t,
|
||||
static void ldapsrv_send(struct stream_connection *conn, struct timeval t,
|
||||
uint16_t flags)
|
||||
{
|
||||
struct ldapsrv_connection *ldap_conn = conn->connection.private_data;
|
||||
struct ldapsrv_connection *ldap_conn = talloc_get_type(conn->private, struct ldapsrv_connection);
|
||||
|
||||
DEBUG(10,("ldapsrv_send\n"));
|
||||
|
||||
@ -540,52 +447,108 @@ static void ldapsrv_send(struct server_connection *conn, struct timeval t,
|
||||
initialise a server_context from a open socket and register a event handler
|
||||
for reading from that socket
|
||||
*/
|
||||
static void ldapsrv_accept(struct server_connection *conn)
|
||||
static void ldapsrv_accept(struct stream_connection *conn)
|
||||
{
|
||||
struct ldapsrv_connection *ldap_conn;
|
||||
|
||||
DEBUG(10, ("ldapsrv_accept\n"));
|
||||
|
||||
ldap_conn = talloc(conn, struct ldapsrv_connection);
|
||||
ldap_conn = talloc_zero(conn, struct ldapsrv_connection);
|
||||
|
||||
if (ldap_conn == NULL)
|
||||
return;
|
||||
|
||||
ZERO_STRUCTP(ldap_conn);
|
||||
ldap_conn->connection = conn;
|
||||
ldap_conn->service = talloc_reference(ldap_conn, conn->stream_socket->service->service.private_data);
|
||||
|
||||
conn->connection.private_data = ldap_conn;
|
||||
|
||||
return;
|
||||
ldap_conn->service = talloc_get_type(conn->private, struct ldapsrv_service);
|
||||
conn->private = ldap_conn;
|
||||
}
|
||||
|
||||
static const struct server_stream_ops ldap_stream_ops = {
|
||||
static const struct stream_server_ops ldap_stream_ops = {
|
||||
.name = "ldap",
|
||||
.socket_init = NULL,
|
||||
.accept_connection = ldapsrv_accept,
|
||||
.recv_handler = ldapsrv_recv,
|
||||
.send_handler = ldapsrv_send,
|
||||
.idle_handler = NULL,
|
||||
.close_connection = NULL
|
||||
};
|
||||
|
||||
static const struct server_stream_ops *ldapsrv_get_stream_ops(void)
|
||||
/*
|
||||
add a socket address to the list of events, one event per port
|
||||
*/
|
||||
static NTSTATUS add_socket(struct event_context *event_context, const struct model_ops *model_ops,
|
||||
const char *address, struct ldapsrv_service *ldap_service)
|
||||
{
|
||||
return &ldap_stream_ops;
|
||||
uint16_t port = 389;
|
||||
NTSTATUS status;
|
||||
|
||||
status = stream_setup_socket(event_context, model_ops, &ldap_stream_ops,
|
||||
"ipv4", address, &port, ldap_service);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
|
||||
port = 3268;
|
||||
|
||||
return stream_setup_socket(event_context, model_ops, &ldap_stream_ops,
|
||||
"ipv4", address, &port, ldap_service);
|
||||
}
|
||||
|
||||
static const struct server_service_ops ldap_server_ops = {
|
||||
.name = "ldap",
|
||||
.service_init = ldapsrv_init
|
||||
};
|
||||
/*
|
||||
open the ldap server sockets
|
||||
*/
|
||||
static NTSTATUS ldapsrv_init(struct event_context *event_context, const struct model_ops *model_ops)
|
||||
{
|
||||
struct ldapsrv_service *ldap_service;
|
||||
struct ldapsrv_partition *rootDSE_part;
|
||||
struct ldapsrv_partition *part;
|
||||
NTSTATUS status;
|
||||
|
||||
const struct server_service_ops *ldapsrv_get_ops(void)
|
||||
{
|
||||
return &ldap_server_ops;
|
||||
DEBUG(10,("ldapsrv_init\n"));
|
||||
|
||||
ldap_service = talloc_zero(event_context, struct ldapsrv_service);
|
||||
NT_STATUS_HAVE_NO_MEMORY(ldap_service);
|
||||
|
||||
rootDSE_part = talloc(ldap_service, struct ldapsrv_partition);
|
||||
NT_STATUS_HAVE_NO_MEMORY(rootDSE_part);
|
||||
|
||||
rootDSE_part->base_dn = ""; /* RootDSE */
|
||||
rootDSE_part->ops = ldapsrv_get_rootdse_partition_ops();
|
||||
|
||||
ldap_service->rootDSE = rootDSE_part;
|
||||
DLIST_ADD_END(ldap_service->partitions, rootDSE_part, struct ldapsrv_partition *);
|
||||
|
||||
part = talloc(ldap_service, struct ldapsrv_partition);
|
||||
NT_STATUS_HAVE_NO_MEMORY(part);
|
||||
|
||||
part->base_dn = "*"; /* default partition */
|
||||
if (lp_parm_bool(-1, "ldapsrv", "hacked", False)) {
|
||||
part->ops = ldapsrv_get_hldb_partition_ops();
|
||||
} else {
|
||||
part->ops = ldapsrv_get_sldb_partition_ops();
|
||||
}
|
||||
|
||||
ldap_service->default_partition = part;
|
||||
DLIST_ADD_END(ldap_service->partitions, part, struct ldapsrv_partition *);
|
||||
|
||||
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++) {
|
||||
const char *address = sys_inet_ntoa(*iface_n_ip(i));
|
||||
status = add_socket(event_context, model_ops, address, ldap_service);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
}
|
||||
} else {
|
||||
status = add_socket(event_context, model_ops, lp_socket_address(), ldap_service);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
}
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS server_service_ldap_init(void)
|
||||
{
|
||||
return NT_STATUS_OK;
|
||||
return register_server_service("ldap", ldapsrv_init);
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ struct ldapsrv_call {
|
||||
struct ldapsrv_service;
|
||||
|
||||
struct ldapsrv_connection {
|
||||
struct server_connection *connection;
|
||||
struct stream_connection *connection;
|
||||
|
||||
struct gensec_security *gensec;
|
||||
struct auth_session_info *session_info;
|
||||
|
@ -33,7 +33,7 @@
|
||||
#define MESSAGING_BACKOFF 250000
|
||||
|
||||
struct messaging_context {
|
||||
servid_t server_id;
|
||||
uint32_t server_id;
|
||||
struct socket_context *sock;
|
||||
char *path;
|
||||
struct dispatch_fn *dispatch;
|
||||
@ -51,7 +51,7 @@ struct dispatch_fn {
|
||||
uint32_t msg_type;
|
||||
void *private;
|
||||
void (*fn)(struct messaging_context *msg, void *private,
|
||||
uint32_t msg_type, servid_t server_id, DATA_BLOB *data);
|
||||
uint32_t msg_type, uint32_t server_id, DATA_BLOB *data);
|
||||
};
|
||||
|
||||
/* an individual message */
|
||||
@ -64,8 +64,8 @@ struct messaging_rec {
|
||||
struct {
|
||||
uint32_t version;
|
||||
uint32_t msg_type;
|
||||
servid_t from;
|
||||
servid_t to;
|
||||
uint32_t from;
|
||||
uint32_t to;
|
||||
uint32_t length;
|
||||
} header;
|
||||
|
||||
@ -78,7 +78,7 @@ struct messaging_rec {
|
||||
A useful function for testing the message system.
|
||||
*/
|
||||
static void ping_message(struct messaging_context *msg, void *private,
|
||||
uint32_t msg_type, servid_t src, DATA_BLOB *data)
|
||||
uint32_t msg_type, uint32_t src, DATA_BLOB *data)
|
||||
{
|
||||
DEBUG(1,("INFO: Received PING message from server %u [%.*s]\n",
|
||||
(uint_t)src, data->length, data->data?(const char *)data->data:""));
|
||||
@ -88,7 +88,7 @@ static void ping_message(struct messaging_context *msg, void *private,
|
||||
/*
|
||||
return the path to a messaging socket
|
||||
*/
|
||||
static char *messaging_path(TALLOC_CTX *mem_ctx, servid_t server_id)
|
||||
static char *messaging_path(TALLOC_CTX *mem_ctx, uint32_t server_id)
|
||||
{
|
||||
char *name = talloc_asprintf(mem_ctx, "messaging/msg.%u", (unsigned)server_id);
|
||||
char *ret;
|
||||
@ -228,7 +228,7 @@ static void messaging_listen_handler(struct event_context *ev, struct fd_event *
|
||||
*/
|
||||
void messaging_register(struct messaging_context *msg, void *private,
|
||||
uint32_t msg_type,
|
||||
void (*fn)(struct messaging_context *, void *, uint32_t, servid_t, DATA_BLOB *))
|
||||
void (*fn)(struct messaging_context *, void *, uint32_t, uint32_t, DATA_BLOB *))
|
||||
{
|
||||
struct dispatch_fn *d;
|
||||
|
||||
@ -365,7 +365,7 @@ static void messaging_backoff_handler(struct event_context *ev, struct timed_eve
|
||||
/*
|
||||
Send a message to a particular server
|
||||
*/
|
||||
NTSTATUS messaging_send(struct messaging_context *msg, servid_t server, uint32_t msg_type, DATA_BLOB *data)
|
||||
NTSTATUS messaging_send(struct messaging_context *msg, uint32_t server, uint32_t msg_type, DATA_BLOB *data)
|
||||
{
|
||||
struct messaging_rec *rec;
|
||||
NTSTATUS status;
|
||||
@ -429,7 +429,7 @@ NTSTATUS messaging_send(struct messaging_context *msg, servid_t server, uint32_t
|
||||
/*
|
||||
Send a message to a particular server, with the message containing a single pointer
|
||||
*/
|
||||
NTSTATUS messaging_send_ptr(struct messaging_context *msg, servid_t server,
|
||||
NTSTATUS messaging_send_ptr(struct messaging_context *msg, uint32_t server,
|
||||
uint32_t msg_type, void *ptr)
|
||||
{
|
||||
DATA_BLOB blob;
|
||||
@ -454,7 +454,7 @@ static int messaging_destructor(void *ptr)
|
||||
/*
|
||||
create the listening socket and setup the dispatcher
|
||||
*/
|
||||
struct messaging_context *messaging_init(TALLOC_CTX *mem_ctx, servid_t server_id, struct event_context *ev)
|
||||
struct messaging_context *messaging_init(TALLOC_CTX *mem_ctx, uint32_t server_id, struct event_context *ev)
|
||||
{
|
||||
struct messaging_context *msg;
|
||||
NTSTATUS status;
|
||||
@ -496,7 +496,7 @@ struct messaging_context *messaging_init(TALLOC_CTX *mem_ctx, servid_t server_id
|
||||
fde.flags = EVENT_FD_READ;
|
||||
fde.handler = messaging_listen_handler;
|
||||
|
||||
msg->event.ev = talloc_reference(msg,ev);
|
||||
msg->event.ev = talloc_reference(msg, ev);
|
||||
msg->event.fde = event_add_fd(ev, &fde, msg);
|
||||
|
||||
talloc_set_destructor(msg, messaging_destructor);
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "libcli/composite/composite.h"
|
||||
#include "smb_server/smb_server.h"
|
||||
#include "smbd/service_stream.h"
|
||||
|
||||
/* this is stored in ntvfs_private */
|
||||
struct cvfs_private {
|
||||
@ -48,22 +49,6 @@ struct async_info {
|
||||
|
||||
#define SETUP_PID private->tree->session->pid = SVAL(req->in.hdr, HDR_PID)
|
||||
|
||||
/*
|
||||
an idle function to cope with messages from the smbd client while
|
||||
waiting for a reply from the server
|
||||
this function won't be needed once all of the cifs backend
|
||||
and the core of smbd is converted to use async calls
|
||||
*/
|
||||
static void idle_func(struct smbcli_transport *transport, void *p_private)
|
||||
{
|
||||
struct cvfs_private *private = p_private;
|
||||
int fd = socket_get_fd(private->tcon->smb_conn->connection->socket);
|
||||
|
||||
if (socket_pending(fd)) {
|
||||
smbd_process_async(private->tcon->smb_conn);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
a handler for oplock break events from the server - these need to be passed
|
||||
along to the client
|
||||
@ -158,7 +143,6 @@ static NTSTATUS cvfs_connect(struct ntvfs_module_context *ntvfs,
|
||||
|
||||
/* we need to receive oplock break requests from the server */
|
||||
smbcli_oplock_handler(private->transport, oplock_handler, private);
|
||||
smbcli_transport_idle_handler(private->transport, idle_func, 50000, private);
|
||||
|
||||
private->transport->socket->event.fde->handler = cifs_socket_handler;
|
||||
private->transport->socket->event.fde->private = private;
|
||||
|
@ -41,7 +41,7 @@
|
||||
lock is the same as another lock
|
||||
*/
|
||||
struct lock_context {
|
||||
servid_t server;
|
||||
uint32_t server;
|
||||
uint16_t smbpid;
|
||||
uint16_t tid;
|
||||
};
|
||||
@ -60,7 +60,7 @@ struct lock_struct {
|
||||
|
||||
struct brl_context {
|
||||
struct tdb_wrap *w;
|
||||
servid_t server;
|
||||
uint32_t server;
|
||||
uint16_t tid;
|
||||
struct messaging_context *messaging_ctx;
|
||||
struct lock_struct last_lock;
|
||||
@ -72,7 +72,7 @@ struct brl_context {
|
||||
talloc_free(). We need the messaging_ctx to allow for
|
||||
pending lock notifications.
|
||||
*/
|
||||
struct brl_context *brl_init(TALLOC_CTX *mem_ctx, servid_t server, uint16_t tid,
|
||||
struct brl_context *brl_init(TALLOC_CTX *mem_ctx, uint32_t server, uint16_t tid,
|
||||
struct messaging_context *messaging_ctx)
|
||||
{
|
||||
char *path;
|
||||
|
@ -44,7 +44,7 @@
|
||||
|
||||
struct odb_context {
|
||||
struct tdb_wrap *w;
|
||||
servid_t server;
|
||||
uint32_t server;
|
||||
struct messaging_context *messaging_ctx;
|
||||
};
|
||||
|
||||
@ -53,7 +53,7 @@ struct odb_context {
|
||||
following form
|
||||
*/
|
||||
struct odb_entry {
|
||||
servid_t server;
|
||||
uint32_t server;
|
||||
void *file_handle;
|
||||
uint32_t stream_id;
|
||||
uint32_t share_access;
|
||||
@ -78,7 +78,7 @@ struct odb_lock {
|
||||
talloc_free(). We need the messaging_ctx to allow for pending open
|
||||
notifications.
|
||||
*/
|
||||
struct odb_context *odb_init(TALLOC_CTX *mem_ctx, servid_t server,
|
||||
struct odb_context *odb_init(TALLOC_CTX *mem_ctx, uint32_t server,
|
||||
struct messaging_context *messaging_ctx)
|
||||
{
|
||||
char *path;
|
||||
|
@ -180,7 +180,7 @@ static NTSTATUS ipc_open_generic(struct ntvfs_module_context *ntvfs,
|
||||
struct dcerpc_binding ep_description;
|
||||
struct ipc_private *private = ntvfs->private_data;
|
||||
int fnum;
|
||||
struct server_connection *srv_conn;
|
||||
struct stream_connection *srv_conn = req->smb_conn->connection;
|
||||
|
||||
if (!req->session || !req->session->session_info) {
|
||||
return NT_STATUS_ACCESS_DENIED;
|
||||
@ -211,11 +211,6 @@ static NTSTATUS ipc_open_generic(struct ntvfs_module_context *ntvfs,
|
||||
ep_description.transport = NCACN_NP;
|
||||
ep_description.endpoint = p->pipe_name;
|
||||
|
||||
/* TOTO: pass in full server_connection in here */
|
||||
srv_conn = talloc_zero(p, struct server_connection);
|
||||
NT_STATUS_HAVE_NO_MEMORY(srv_conn);
|
||||
srv_conn->event.ctx = talloc_reference(srv_conn, req->smb_conn->connection->event.ctx);
|
||||
|
||||
/* The session info is refcount-increased in the
|
||||
* dcesrv_endpoint_search_connect() function
|
||||
*/
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "events.h"
|
||||
#include "dlinklist.h"
|
||||
#include "vfs_posix.h"
|
||||
#include "smbd/service_stream.h"
|
||||
|
||||
/* the context for a single wait instance */
|
||||
struct pvfs_wait {
|
||||
@ -56,7 +57,7 @@ NTSTATUS pvfs_async_setup(struct ntvfs_module_context *ntvfs,
|
||||
receive a completion message for a wait
|
||||
*/
|
||||
static void pvfs_wait_dispatch(struct messaging_context *msg, void *private, uint32_t msg_type,
|
||||
servid_t src, DATA_BLOB *data)
|
||||
uint32_t src, DATA_BLOB *data)
|
||||
{
|
||||
struct pvfs_wait *pwait = private;
|
||||
struct smbsrv_request *req;
|
||||
@ -133,7 +134,7 @@ static int pvfs_wait_destructor(void *ptr)
|
||||
|
||||
pwait->private = private;
|
||||
pwait->handler = fn;
|
||||
pwait->msg_ctx = pvfs->tcon->smb_conn->connection->messaging.ctx;
|
||||
pwait->msg_ctx = pvfs->tcon->smb_conn->connection->msg_ctx;
|
||||
pwait->ev = req->tcon->smb_conn->connection->event.ctx;
|
||||
pwait->msg_type = msg_type;
|
||||
pwait->req = talloc_reference(pwait, req);
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "includes.h"
|
||||
#include "vfs_posix.h"
|
||||
#include "librpc/gen_ndr/ndr_security.h"
|
||||
#include "smbd/service_stream.h"
|
||||
|
||||
|
||||
/*
|
||||
@ -130,16 +131,16 @@ static NTSTATUS pvfs_connect(struct ntvfs_module_context *ntvfs,
|
||||
ntvfs->private_data = pvfs;
|
||||
|
||||
pvfs->brl_context = brl_init(pvfs,
|
||||
pvfs->tcon->smb_conn->connection->connection.id,
|
||||
pvfs->tcon->smb_conn->connection->server_id,
|
||||
pvfs->tcon->service,
|
||||
pvfs->tcon->smb_conn->connection->messaging.ctx);
|
||||
pvfs->tcon->smb_conn->connection->msg_ctx);
|
||||
if (pvfs->brl_context == NULL) {
|
||||
return NT_STATUS_INTERNAL_DB_CORRUPTION;
|
||||
}
|
||||
|
||||
pvfs->odb_context = odb_init(pvfs,
|
||||
pvfs->tcon->smb_conn->connection->connection.id,
|
||||
pvfs->tcon->smb_conn->connection->messaging.ctx);
|
||||
pvfs->tcon->smb_conn->connection->server_id,
|
||||
pvfs->tcon->smb_conn->connection->msg_ctx);
|
||||
if (pvfs->odb_context == NULL) {
|
||||
return NT_STATUS_INTERNAL_DB_CORRUPTION;
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ BOOL secrets_init(void)
|
||||
pstrcpy(fname, lp_private_dir());
|
||||
pstrcat(fname,"/secrets.tdb");
|
||||
|
||||
tdb = tdb_wrap_open(NULL, fname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
|
||||
tdb = tdb_wrap_open(talloc_autofree_context(), fname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
|
||||
|
||||
if (!tdb) {
|
||||
DEBUG(0,("Failed to open %s\n", fname));
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "dlinklist.h"
|
||||
#include "rpc_server/dcerpc_server.h"
|
||||
#include "events.h"
|
||||
#include "smbd/service_stream.h"
|
||||
|
||||
/*
|
||||
see if two endpoints match
|
||||
@ -299,7 +300,7 @@ static int dcesrv_endpoint_destructor(void *ptr)
|
||||
NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
const struct dcesrv_endpoint *ep,
|
||||
struct server_connection *srv_conn,
|
||||
struct stream_connection *srv_conn,
|
||||
struct dcesrv_connection **_p)
|
||||
{
|
||||
struct dcesrv_connection *p;
|
||||
@ -333,7 +334,7 @@ NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
const struct dcerpc_binding *ep_description,
|
||||
struct auth_session_info *session_info,
|
||||
struct server_connection *srv_conn,
|
||||
struct stream_connection *srv_conn,
|
||||
struct dcesrv_connection **dce_conn_p)
|
||||
{
|
||||
NTSTATUS status;
|
||||
@ -1204,7 +1205,7 @@ static NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, const char **endpoint_s
|
||||
}
|
||||
|
||||
/*
|
||||
initialise the dcerpc server context
|
||||
initialise the dcerpc server context for ncacn_np based services
|
||||
*/
|
||||
NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct dcesrv_context **_dce_ctx)
|
||||
{
|
||||
@ -1218,45 +1219,6 @@ NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct dcesrv_context **_d
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
static void dcesrv_init(struct server_service *service)
|
||||
{
|
||||
NTSTATUS status;
|
||||
struct dcesrv_context *dce_ctx;
|
||||
|
||||
DEBUG(1,("dcesrv_init\n"));
|
||||
|
||||
status = dcesrv_init_context(service,
|
||||
lp_dcerpc_endpoint_servers(),
|
||||
DCESRV_CALL_STATE_FLAG_MAY_ASYNC,
|
||||
&dce_ctx);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
service->service.private_data = dce_ctx;
|
||||
|
||||
dcesrv_sock_init(service);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void dcesrv_accept(struct server_connection *srv_conn)
|
||||
{
|
||||
dcesrv_sock_accept(srv_conn);
|
||||
}
|
||||
|
||||
static void dcesrv_recv(struct server_connection *srv_conn,
|
||||
struct timeval t, uint16_t flags)
|
||||
{
|
||||
dcesrv_sock_recv(srv_conn, t, flags);
|
||||
}
|
||||
|
||||
static void dcesrv_send(struct server_connection *srv_conn,
|
||||
struct timeval t, uint16_t flags)
|
||||
{
|
||||
dcesrv_sock_send(srv_conn, t, flags);
|
||||
}
|
||||
|
||||
/* the list of currently registered DCERPC endpoint servers.
|
||||
*/
|
||||
static struct ep_server {
|
||||
@ -1338,32 +1300,25 @@ const struct dcesrv_critical_sizes *dcerpc_module_version(void)
|
||||
return &critical_sizes;
|
||||
}
|
||||
|
||||
static const struct server_stream_ops dcesrv_stream_ops = {
|
||||
.name = "rpc",
|
||||
.socket_init = NULL,
|
||||
.accept_connection = dcesrv_accept,
|
||||
.recv_handler = dcesrv_recv,
|
||||
.send_handler = dcesrv_send,
|
||||
.idle_handler = NULL,
|
||||
.close_connection = NULL
|
||||
};
|
||||
|
||||
const struct server_stream_ops *dcesrv_get_stream_ops(void)
|
||||
/*
|
||||
initialise the dcerpc server context for socket based services
|
||||
*/
|
||||
static NTSTATUS dcesrv_init(struct event_context *event_context, const struct model_ops *model_ops)
|
||||
{
|
||||
return &dcesrv_stream_ops;
|
||||
NTSTATUS status;
|
||||
struct dcesrv_context *dce_ctx;
|
||||
|
||||
status = dcesrv_init_context(event_context,
|
||||
lp_dcerpc_endpoint_servers(),
|
||||
DCESRV_CALL_STATE_FLAG_MAY_ASYNC,
|
||||
&dce_ctx);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
|
||||
return dcesrv_sock_init(dce_ctx, event_context, model_ops);
|
||||
}
|
||||
|
||||
static const struct server_service_ops dcesrv_ops = {
|
||||
.name = "rpc",
|
||||
.service_init = dcesrv_init,
|
||||
};
|
||||
|
||||
const struct server_service_ops *dcesrv_get_ops(void)
|
||||
{
|
||||
return &dcesrv_ops;
|
||||
}
|
||||
|
||||
NTSTATUS server_service_rpc_init(void)
|
||||
{
|
||||
return NT_STATUS_OK;
|
||||
return register_server_service("rpc", dcesrv_init);
|
||||
}
|
||||
|
@ -174,7 +174,7 @@ struct dcesrv_connection {
|
||||
/* the current authentication state */
|
||||
struct dcesrv_auth auth_state;
|
||||
|
||||
struct server_connection *srv_conn;
|
||||
struct stream_connection *srv_conn;
|
||||
|
||||
/* the transport level session key */
|
||||
DATA_BLOB transport_session_key;
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "includes.h"
|
||||
#include "events.h"
|
||||
#include "rpc_server/dcerpc_server.h"
|
||||
#include "smbd/service_stream.h"
|
||||
|
||||
struct dcesrv_socket_context {
|
||||
const struct dcesrv_endpoint *endpoint;
|
||||
@ -50,185 +51,19 @@ static ssize_t dcerpc_write_fn(void *private, DATA_BLOB *out)
|
||||
|
||||
static void dcesrv_terminate_connection(struct dcesrv_connection *dce_conn, const char *reason)
|
||||
{
|
||||
server_terminate_connection(dce_conn->srv_conn, reason);
|
||||
stream_terminate_connection(dce_conn->srv_conn, reason);
|
||||
}
|
||||
|
||||
static void add_socket_rpc_unix(struct server_service *service, struct dcesrv_endpoint *e)
|
||||
{
|
||||
struct dcesrv_context *dce_ctx = service->service.private_data;
|
||||
struct server_stream_socket *stream_socket;
|
||||
struct dcesrv_socket_context *dcesrv_sock;
|
||||
uint16_t port = 1;
|
||||
|
||||
stream_socket = service_setup_stream_socket(service, dcesrv_get_stream_ops(), "unix", e->ep_description.endpoint, &port);
|
||||
if (!stream_socket) {
|
||||
DEBUG(0,("service_setup_stream_socket(path=%s) failed\n",e->ep_description.endpoint));
|
||||
return;
|
||||
}
|
||||
|
||||
dcesrv_sock = talloc(stream_socket, struct dcesrv_socket_context);
|
||||
if (!dcesrv_sock) {
|
||||
DEBUG(0,("talloc(stream_socket, struct dcesrv_socket_context) failed\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
/* remember the endpoint of this socket */
|
||||
dcesrv_sock->endpoint = e;
|
||||
dcesrv_sock->dcesrv_ctx = dce_ctx;
|
||||
|
||||
stream_socket->stream.private_data = dcesrv_sock;
|
||||
}
|
||||
|
||||
static void add_socket_rpc_ncalrpc(struct server_service *service, struct dcesrv_endpoint *e)
|
||||
{
|
||||
struct dcesrv_context *dce_ctx = service->service.private_data;
|
||||
struct server_stream_socket *stream_socket;
|
||||
struct dcesrv_socket_context *dcesrv_sock;
|
||||
uint16_t port = 1;
|
||||
char *full_path;
|
||||
|
||||
if (!e->ep_description.endpoint) {
|
||||
/* No identifier specified: use DEFAULT.
|
||||
* DO NOT hardcode this value anywhere else. Rather, specify
|
||||
* no endpoint and let the epmapper worry about it. */
|
||||
e->ep_description.endpoint = talloc_strdup(dce_ctx, "DEFAULT");
|
||||
}
|
||||
|
||||
full_path = talloc_asprintf(dce_ctx, "%s/%s", lp_ncalrpc_dir(), e->ep_description.endpoint);
|
||||
|
||||
stream_socket = service_setup_stream_socket(service, dcesrv_get_stream_ops(), "unix", full_path, &port);
|
||||
if (!stream_socket) {
|
||||
DEBUG(0,("service_setup_stream_socket(identifier=%s,path=%s) failed\n",e->ep_description.endpoint, full_path));
|
||||
return;
|
||||
}
|
||||
|
||||
dcesrv_sock = talloc(stream_socket, struct dcesrv_socket_context);
|
||||
if (!dcesrv_sock) {
|
||||
DEBUG(0,("talloc(stream_socket, struct dcesrv_socket_context) failed\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
/* remember the endpoint of this socket */
|
||||
dcesrv_sock->endpoint = e;
|
||||
dcesrv_sock->dcesrv_ctx = dce_ctx;
|
||||
|
||||
stream_socket->stream.private_data = dcesrv_sock;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
add a socket address to the list of events, one event per dcerpc endpoint
|
||||
*/
|
||||
static void add_socket_rpc_tcp_iface(struct server_service *service,
|
||||
struct dcesrv_endpoint *e,
|
||||
struct ipv4_addr *ifip)
|
||||
{
|
||||
struct dcesrv_context *dce_ctx = service->service.private_data;
|
||||
struct server_stream_socket *stream_socket;
|
||||
struct dcesrv_socket_context *dcesrv_sock;
|
||||
uint16_t port = 0;
|
||||
char *ip_str = talloc_strdup(service, sys_inet_ntoa(*ifip));
|
||||
|
||||
if (e->ep_description.endpoint)
|
||||
port = atoi(e->ep_description.endpoint);
|
||||
|
||||
stream_socket = service_setup_stream_socket(service, dcesrv_get_stream_ops(), "ipv4", ip_str, &port);
|
||||
if (!stream_socket) {
|
||||
DEBUG(0,("service_setup_stream_socket(address=%s,port=%u) failed\n", ip_str, port));
|
||||
return;
|
||||
}
|
||||
|
||||
if (e->ep_description.endpoint == NULL) {
|
||||
e->ep_description.endpoint = talloc_asprintf(dce_ctx, "%d", port);
|
||||
}
|
||||
|
||||
dcesrv_sock = talloc(stream_socket, struct dcesrv_socket_context);
|
||||
if (!dcesrv_sock) {
|
||||
DEBUG(0,("talloc(stream_socket, struct dcesrv_socket_context) failed\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
/* remember the endpoint of this socket */
|
||||
dcesrv_sock->endpoint = e;
|
||||
dcesrv_sock->dcesrv_ctx = dce_ctx;
|
||||
|
||||
stream_socket->stream.private_data = dcesrv_sock;
|
||||
|
||||
talloc_free(ip_str);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void add_socket_rpc_tcp(struct server_service *service, struct dcesrv_endpoint *e)
|
||||
{
|
||||
/* Add TCP/IP sockets */
|
||||
if (lp_interfaces() && lp_bind_interfaces_only()) {
|
||||
int num_interfaces = iface_count();
|
||||
int i;
|
||||
for(i = 0; i < num_interfaces; i++) {
|
||||
struct ipv4_addr *ifip = iface_n_ip(i);
|
||||
if (ifip == NULL) {
|
||||
continue;
|
||||
}
|
||||
add_socket_rpc_tcp_iface(service, e, ifip);
|
||||
}
|
||||
} else {
|
||||
struct ipv4_addr ifip;
|
||||
ifip = interpret_addr2(lp_socket_address());
|
||||
add_socket_rpc_tcp_iface(service, e, &ifip);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Open the listening sockets for RPC over NCACN_IP_TCP/NCALRPC/NCACN_UNIX_STREAM
|
||||
****************************************************************************/
|
||||
void dcesrv_sock_init(struct server_service *service)
|
||||
{
|
||||
struct dcesrv_context *dce_ctx = service->service.private_data;
|
||||
struct dcesrv_endpoint *e;
|
||||
|
||||
DEBUG(1,("dcesrv_sock_init\n"));
|
||||
|
||||
/* Make sure the directory for NCALRPC exists */
|
||||
if (!directory_exist(lp_ncalrpc_dir(), NULL)) {
|
||||
mkdir(lp_ncalrpc_dir(), 0755);
|
||||
}
|
||||
|
||||
for (e=dce_ctx->endpoint_list;e;e=e->next) {
|
||||
switch (e->ep_description.transport) {
|
||||
case NCACN_UNIX_STREAM:
|
||||
add_socket_rpc_unix(service, e);
|
||||
break;
|
||||
|
||||
case NCALRPC:
|
||||
add_socket_rpc_ncalrpc(service, e);
|
||||
break;
|
||||
|
||||
case NCACN_IP_TCP:
|
||||
add_socket_rpc_tcp(service, e);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void dcesrv_sock_accept(struct server_connection *srv_conn)
|
||||
void dcesrv_sock_accept(struct stream_connection *srv_conn)
|
||||
{
|
||||
NTSTATUS status;
|
||||
struct dcesrv_socket_context *dcesrv_sock = srv_conn->stream_socket->stream.private_data;
|
||||
struct dcesrv_socket_context *dcesrv_sock =
|
||||
talloc_get_type(srv_conn->private, struct dcesrv_socket_context);
|
||||
struct dcesrv_connection *dcesrv_conn = NULL;
|
||||
|
||||
DEBUG(5,("dcesrv_sock_accept\n"));
|
||||
|
||||
status = dcesrv_endpoint_connect(dcesrv_sock->dcesrv_ctx,
|
||||
dcesrv_sock,
|
||||
srv_conn,
|
||||
dcesrv_sock->endpoint,
|
||||
srv_conn,
|
||||
&dcesrv_conn);
|
||||
@ -238,15 +73,15 @@ void dcesrv_sock_accept(struct server_connection *srv_conn)
|
||||
return;
|
||||
}
|
||||
|
||||
srv_conn->connection.private_data = dcesrv_conn;
|
||||
srv_conn->private = dcesrv_conn;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void dcesrv_sock_recv(struct server_connection *conn, struct timeval t, uint16_t flags)
|
||||
void dcesrv_sock_recv(struct stream_connection *conn, struct timeval t, uint16_t flags)
|
||||
{
|
||||
NTSTATUS status;
|
||||
struct dcesrv_connection *dce_conn = conn->connection.private_data;
|
||||
struct dcesrv_connection *dce_conn = talloc_get_type(conn->private, struct dcesrv_connection);
|
||||
DATA_BLOB tmp_blob;
|
||||
size_t nread;
|
||||
|
||||
@ -279,17 +114,13 @@ void dcesrv_sock_recv(struct server_connection *conn, struct timeval t, uint16_t
|
||||
if (dce_conn->call_list && dce_conn->call_list->replies) {
|
||||
conn->event.fde->flags |= EVENT_FD_WRITE;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void dcesrv_sock_send(struct server_connection *conn, struct timeval t, uint16_t flags)
|
||||
void dcesrv_sock_send(struct stream_connection *conn, struct timeval t, uint16_t flags)
|
||||
{
|
||||
struct dcesrv_connection *dce_conn = conn->connection.private_data;
|
||||
struct dcesrv_connection *dce_conn = talloc_get_type(conn->private, struct dcesrv_connection);
|
||||
NTSTATUS status;
|
||||
|
||||
DEBUG(10,("dcesrv_sock_send\n"));
|
||||
|
||||
status = dcesrv_output(dce_conn, conn->socket, dcerpc_write_fn);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
dcesrv_terminate_connection(dce_conn, "eof on socket");
|
||||
@ -299,6 +130,170 @@ void dcesrv_sock_send(struct server_connection *conn, struct timeval t, uint16_t
|
||||
if (!dce_conn->call_list || !dce_conn->call_list->replies) {
|
||||
conn->event.fde->flags &= ~EVENT_FD_WRITE;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static const struct stream_server_ops dcesrv_stream_ops = {
|
||||
.name = "rpc",
|
||||
.accept_connection = dcesrv_sock_accept,
|
||||
.recv_handler = dcesrv_sock_recv,
|
||||
.send_handler = dcesrv_sock_send,
|
||||
};
|
||||
|
||||
|
||||
|
||||
static NTSTATUS add_socket_rpc_unix(struct dcesrv_context *dce_ctx, struct dcesrv_endpoint *e,
|
||||
struct event_context *event_ctx, const struct model_ops *model_ops)
|
||||
{
|
||||
struct dcesrv_socket_context *dcesrv_sock;
|
||||
uint16_t port = 1;
|
||||
NTSTATUS status;
|
||||
|
||||
dcesrv_sock = talloc(dce_ctx, struct dcesrv_socket_context);
|
||||
NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
|
||||
|
||||
/* remember the endpoint of this socket */
|
||||
dcesrv_sock->endpoint = e;
|
||||
dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx);
|
||||
|
||||
status = stream_setup_socket(event_ctx, model_ops, &dcesrv_stream_ops,
|
||||
"unix", e->ep_description.endpoint, &port,
|
||||
dcesrv_sock);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(0,("service_setup_stream_socket(path=%s) failed - %s\n",
|
||||
e->ep_description.endpoint, nt_errstr(status)));
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static NTSTATUS add_socket_rpc_ncalrpc(struct dcesrv_context *dce_ctx, struct dcesrv_endpoint *e,
|
||||
struct event_context *event_ctx, const struct model_ops *model_ops)
|
||||
{
|
||||
struct dcesrv_socket_context *dcesrv_sock;
|
||||
uint16_t port = 1;
|
||||
char *full_path;
|
||||
NTSTATUS status;
|
||||
|
||||
if (!e->ep_description.endpoint) {
|
||||
/* No identifier specified: use DEFAULT.
|
||||
* DO NOT hardcode this value anywhere else. Rather, specify
|
||||
* no endpoint and let the epmapper worry about it. */
|
||||
e->ep_description.endpoint = talloc_strdup(dce_ctx, "DEFAULT");
|
||||
}
|
||||
|
||||
full_path = talloc_asprintf(dce_ctx, "%s/%s", lp_ncalrpc_dir(), e->ep_description.endpoint);
|
||||
|
||||
dcesrv_sock = talloc(dce_ctx, struct dcesrv_socket_context);
|
||||
NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
|
||||
|
||||
/* remember the endpoint of this socket */
|
||||
dcesrv_sock->endpoint = e;
|
||||
dcesrv_sock->dcesrv_ctx = dce_ctx;
|
||||
|
||||
status = stream_setup_socket(event_ctx, model_ops, &dcesrv_stream_ops,
|
||||
"unix", full_path, &port, dcesrv_sock);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(0,("service_setup_stream_socket(identifier=%s,path=%s) failed - %s\n",
|
||||
e->ep_description.endpoint, full_path, nt_errstr(status)));
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
add a socket address to the list of events, one event per dcerpc endpoint
|
||||
*/
|
||||
static NTSTATUS add_socket_rpc_tcp_iface(struct dcesrv_context *dce_ctx, struct dcesrv_endpoint *e,
|
||||
struct event_context *event_ctx, const struct model_ops *model_ops,
|
||||
const char *address)
|
||||
{
|
||||
struct dcesrv_socket_context *dcesrv_sock;
|
||||
uint16_t port = 0;
|
||||
NTSTATUS status;
|
||||
|
||||
if (e->ep_description.endpoint) {
|
||||
port = atoi(e->ep_description.endpoint);
|
||||
}
|
||||
|
||||
dcesrv_sock = talloc(dce_ctx, struct dcesrv_socket_context);
|
||||
NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
|
||||
|
||||
/* remember the endpoint of this socket */
|
||||
dcesrv_sock->endpoint = e;
|
||||
dcesrv_sock->dcesrv_ctx = dce_ctx;
|
||||
|
||||
status = stream_setup_socket(event_ctx, model_ops, &dcesrv_stream_ops,
|
||||
"ipv4", address, &port, dcesrv_sock);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(0,("service_setup_stream_socket(address=%s,port=%u) failed - %s\n",
|
||||
address, port, nt_errstr(status)));
|
||||
}
|
||||
|
||||
if (e->ep_description.endpoint == NULL) {
|
||||
e->ep_description.endpoint = talloc_asprintf(dce_ctx, "%d", port);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static NTSTATUS add_socket_rpc_tcp(struct dcesrv_context *dce_ctx, struct dcesrv_endpoint *e,
|
||||
struct event_context *event_ctx, const struct model_ops *model_ops)
|
||||
{
|
||||
NTSTATUS status;
|
||||
|
||||
/* Add TCP/IP sockets */
|
||||
if (lp_interfaces() && lp_bind_interfaces_only()) {
|
||||
int num_interfaces = iface_count();
|
||||
int i;
|
||||
for(i = 0; i < num_interfaces; i++) {
|
||||
const char *address = sys_inet_ntoa(*iface_n_ip(i));
|
||||
status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx, model_ops, address);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
}
|
||||
} else {
|
||||
status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx, model_ops, lp_socket_address());
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
}
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Open the listening sockets for RPC over NCACN_IP_TCP/NCALRPC/NCACN_UNIX_STREAM
|
||||
****************************************************************************/
|
||||
NTSTATUS dcesrv_sock_init(struct dcesrv_context *dce_ctx,
|
||||
struct event_context *event_ctx, const struct model_ops *model_ops)
|
||||
{
|
||||
struct dcesrv_endpoint *e;
|
||||
NTSTATUS status;
|
||||
|
||||
/* Make sure the directory for NCALRPC exists */
|
||||
if (!directory_exist(lp_ncalrpc_dir(), NULL)) {
|
||||
mkdir(lp_ncalrpc_dir(), 0755);
|
||||
}
|
||||
|
||||
for (e=dce_ctx->endpoint_list;e;e=e->next) {
|
||||
switch (e->ep_description.transport) {
|
||||
case NCACN_UNIX_STREAM:
|
||||
status = add_socket_rpc_unix(dce_ctx, e, event_ctx, model_ops);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
break;
|
||||
|
||||
case NCALRPC:
|
||||
status = add_socket_rpc_ncalrpc(dce_ctx, e, event_ctx, model_ops);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
break;
|
||||
|
||||
case NCACN_IP_TCP:
|
||||
status = add_socket_rpc_tcp(dce_ctx, e, event_ctx, model_ops);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
|
@ -217,10 +217,11 @@ static error_status_t epm_Map(struct dcesrv_call_state *dce_call, TALLOC_CTX *me
|
||||
transport = dcerpc_transport_by_tower(&r->in.map_tower->tower);
|
||||
|
||||
if (transport == -1) {
|
||||
DEBUG(1, ("Client requested unknown transport with levels: "));
|
||||
DEBUG(2, ("Client requested unknown transport with levels: "));
|
||||
for (i = 2; i < r->in.map_tower->tower.num_floors; i++) {
|
||||
DEBUG(1, ("%d, ", r->in.map_tower->tower.floors[i].lhs.protocol));
|
||||
DEBUG(2, ("%d, ", r->in.map_tower->tower.floors[i].lhs.protocol));
|
||||
}
|
||||
DEBUG(2, ("\n"));
|
||||
goto failed;
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "system/filesys.h"
|
||||
#include "dlinklist.h"
|
||||
#include "smb_server/smb_server.h"
|
||||
#include "smbd/service_stream.h"
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "includes.h"
|
||||
#include "auth/auth.h"
|
||||
#include "smb_server/smb_server.h"
|
||||
#include "smbd/service_stream.h"
|
||||
|
||||
|
||||
/* initialise the auth_context for this server and return the cryptkey */
|
||||
@ -144,7 +145,7 @@ static void reply_lanman1(struct smbsrv_request *req, uint16_t choice)
|
||||
SSVAL(req->out.vwv, VWV(3), lp_maxmux());
|
||||
SSVAL(req->out.vwv, VWV(4), 1);
|
||||
SSVAL(req->out.vwv, VWV(5), raw);
|
||||
SIVAL(req->out.vwv, VWV(6), req->smb_conn->connection->connection.id);
|
||||
SIVAL(req->out.vwv, VWV(6), req->smb_conn->connection->server_id);
|
||||
srv_push_dos_date(req->smb_conn, req->out.vwv, VWV(8), t);
|
||||
SSVAL(req->out.vwv, VWV(10), req->smb_conn->negotiate.zone_offset/60);
|
||||
SIVAL(req->out.vwv, VWV(11), 0); /* reserved */
|
||||
@ -198,7 +199,7 @@ static void reply_lanman2(struct smbsrv_request *req, uint16_t choice)
|
||||
SSVAL(req->out.vwv, VWV(3), lp_maxmux());
|
||||
SSVAL(req->out.vwv, VWV(4), 1);
|
||||
SSVAL(req->out.vwv, VWV(5), raw);
|
||||
SIVAL(req->out.vwv, VWV(6), req->smb_conn->connection->connection.id);
|
||||
SIVAL(req->out.vwv, VWV(6), req->smb_conn->connection->server_id);
|
||||
srv_push_dos_date(req->smb_conn, req->out.vwv, VWV(8), t);
|
||||
SSVAL(req->out.vwv, VWV(10), req->smb_conn->negotiate.zone_offset/60);
|
||||
SIVAL(req->out.vwv, VWV(11), 0);
|
||||
@ -310,7 +311,7 @@ static void reply_nt1(struct smbsrv_request *req, uint16_t choice)
|
||||
SSVAL(req->out.vwv+1, VWV(2), 1); /* num vcs */
|
||||
SIVAL(req->out.vwv+1, VWV(3), req->smb_conn->negotiate.max_recv);
|
||||
SIVAL(req->out.vwv+1, VWV(5), 0x10000); /* raw size. full 64k */
|
||||
SIVAL(req->out.vwv+1, VWV(7), req->smb_conn->connection->connection.id); /* session key */
|
||||
SIVAL(req->out.vwv+1, VWV(7), req->smb_conn->connection->server_id); /* session key */
|
||||
SIVAL(req->out.vwv+1, VWV(9), capabilities);
|
||||
push_nttime(req->out.vwv+1, VWV(11), nttime);
|
||||
SSVALS(req->out.vwv+1,VWV(15), req->smb_conn->negotiate.zone_offset/60);
|
||||
@ -443,7 +444,6 @@ void reply_negprot(struct smbsrv_request *req)
|
||||
|
||||
if(choice != -1) {
|
||||
sub_set_remote_proto(supported_protocols[protocol].short_name);
|
||||
reload_services(req->smb_conn, True);
|
||||
supported_protocols[protocol].proto_reply_fn(req, choice);
|
||||
DEBUG(3,("Selected protocol %s\n",supported_protocols[protocol].proto_name));
|
||||
} else {
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "events.h"
|
||||
#include "dlinklist.h"
|
||||
#include "smb_server/smb_server.h"
|
||||
#include "smbd/service_stream.h"
|
||||
|
||||
|
||||
/* we over allocate the data buffer to prevent too many realloc calls */
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
#include "includes.h"
|
||||
#include "smb_server/smb_server.h"
|
||||
#include "smbd/service_stream.h"
|
||||
|
||||
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "version.h"
|
||||
#include "auth/auth.h"
|
||||
#include "smb_server/smb_server.h"
|
||||
#include "smbd/service_stream.h"
|
||||
|
||||
|
||||
/*
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "events.h"
|
||||
#include "system/time.h"
|
||||
#include "dlinklist.h"
|
||||
#include "smbd/service_stream.h"
|
||||
#include "smb_server/smb_server.h"
|
||||
|
||||
|
||||
@ -506,7 +507,7 @@ static void switch_message(int type, struct smbsrv_request *req)
|
||||
session_tag = req->session->vuid;
|
||||
}
|
||||
|
||||
DEBUG(3,("switch message %s (task_id %d)\n",smb_fn_name(type), req->smb_conn->connection->connection.id));
|
||||
DEBUG(3,("switch message %s (task_id %d)\n",smb_fn_name(type), req->smb_conn->connection->server_id));
|
||||
|
||||
/* does this protocol need a valid tree connection? */
|
||||
if ((flags & AS_USER) && !req->tcon) {
|
||||
@ -646,69 +647,15 @@ error:
|
||||
*/
|
||||
void smbsrv_terminate_connection(struct smbsrv_connection *smb_conn, const char *reason)
|
||||
{
|
||||
server_terminate_connection(smb_conn->connection, reason);
|
||||
}
|
||||
|
||||
static const struct server_stream_ops *smbsrv_stream_ops(void);
|
||||
|
||||
/*
|
||||
add a socket address to the list of events, one event per port
|
||||
*/
|
||||
static void smb_add_socket(struct server_service *service,
|
||||
struct ipv4_addr *ifip)
|
||||
{
|
||||
const char **ports = lp_smb_ports();
|
||||
int i;
|
||||
char *ip_str = talloc_strdup(service, sys_inet_ntoa(*ifip));
|
||||
|
||||
for (i=0;ports[i];i++) {
|
||||
uint16_t port = atoi(ports[i]);
|
||||
if (port == 0) continue;
|
||||
service_setup_stream_socket(service, smbsrv_stream_ops(), "ipv4", ip_str, &port);
|
||||
}
|
||||
|
||||
talloc_free(ip_str);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Open the socket communication.
|
||||
****************************************************************************/
|
||||
static void smbsrv_init(struct server_service *service)
|
||||
{
|
||||
DEBUG(1,("smbsrv_init\n"));
|
||||
|
||||
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 ipv4_addr *ifip = iface_n_ip(i);
|
||||
|
||||
if (ifip == NULL) {
|
||||
DEBUG(0,("open_sockets_smbd: interface %d has NULL IP address !\n", i));
|
||||
continue;
|
||||
}
|
||||
|
||||
smb_add_socket(service, ifip);
|
||||
}
|
||||
} else {
|
||||
struct ipv4_addr ifip;
|
||||
/* Just bind to lp_socket_address() (usually 0.0.0.0) */
|
||||
ifip = interpret_addr2(lp_socket_address());
|
||||
smb_add_socket(service, &ifip);
|
||||
}
|
||||
stream_terminate_connection(smb_conn->connection, reason);
|
||||
}
|
||||
|
||||
/*
|
||||
called when a SMB socket becomes readable
|
||||
*/
|
||||
static void smbsrv_recv(struct server_connection *conn, struct timeval t, uint16_t flags)
|
||||
static void smbsrv_recv(struct stream_connection *conn, struct timeval t, uint16_t flags)
|
||||
{
|
||||
struct smbsrv_connection *smb_conn = conn->connection.private_data;
|
||||
struct smbsrv_connection *smb_conn = talloc_get_type(conn->private, struct smbsrv_connection);
|
||||
NTSTATUS status;
|
||||
|
||||
DEBUG(10,("smbsrv_recv\n"));
|
||||
@ -727,9 +674,9 @@ static void smbsrv_recv(struct server_connection *conn, struct timeval t, uint16
|
||||
/*
|
||||
called when a SMB socket becomes writable
|
||||
*/
|
||||
static void smbsrv_send(struct server_connection *conn, struct timeval t, uint16_t flags)
|
||||
static void smbsrv_send(struct stream_connection *conn, struct timeval t, uint16_t flags)
|
||||
{
|
||||
struct smbsrv_connection *smb_conn = conn->connection.private_data;
|
||||
struct smbsrv_connection *smb_conn = talloc_get_type(conn->private, struct smbsrv_connection);
|
||||
|
||||
while (smb_conn->pending_send) {
|
||||
struct smbsrv_request *req = smb_conn->pending_send;
|
||||
@ -767,39 +714,11 @@ static void smbsrv_send(struct server_connection *conn, struct timeval t, uint16
|
||||
}
|
||||
}
|
||||
|
||||
static void smbsrv_close(struct server_connection *conn, const char *reason)
|
||||
{
|
||||
struct smbsrv_connection *smb_conn = conn->connection.private_data;
|
||||
|
||||
DEBUG(5,("smbsrv_close: %s\n",reason));
|
||||
|
||||
talloc_free(smb_conn);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
process a message from an SMB socket while still processing a
|
||||
previous message this is used by backends who need to ensure that
|
||||
new messages from clients are still processed while they are
|
||||
performing long operations
|
||||
*/
|
||||
void smbd_process_async(struct smbsrv_connection *smb_conn)
|
||||
{
|
||||
NTSTATUS status;
|
||||
|
||||
status = receive_smb_request(smb_conn, timeval_current());
|
||||
if (NT_STATUS_IS_ERR(status)) {
|
||||
smbsrv_terminate_connection(smb_conn, nt_errstr(status));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
initialise a server_context from a open socket and register a event handler
|
||||
for reading from that socket
|
||||
*/
|
||||
static void smbsrv_accept(struct server_connection *conn)
|
||||
static void smbsrv_accept(struct stream_connection *conn)
|
||||
{
|
||||
struct smbsrv_connection *smb_conn;
|
||||
|
||||
@ -825,37 +744,71 @@ static void smbsrv_accept(struct server_connection *conn)
|
||||
|
||||
smb_conn->connection = conn;
|
||||
|
||||
conn->connection.private_data = smb_conn;
|
||||
|
||||
return;
|
||||
conn->private = smb_conn;
|
||||
}
|
||||
|
||||
static const struct server_stream_ops smb_stream_ops = {
|
||||
|
||||
static const struct stream_server_ops smb_stream_ops = {
|
||||
.name = "smb",
|
||||
.socket_init = NULL,
|
||||
.accept_connection = smbsrv_accept,
|
||||
.recv_handler = smbsrv_recv,
|
||||
.send_handler = smbsrv_send,
|
||||
.idle_handler = NULL,
|
||||
.close_connection = smbsrv_close
|
||||
};
|
||||
|
||||
static const struct server_stream_ops *smbsrv_stream_ops(void)
|
||||
/*
|
||||
setup a listening socket on all the SMB ports for a particular address
|
||||
*/
|
||||
static NTSTATUS smb_add_socket(struct event_context *event_context,
|
||||
const struct model_ops *model_ops,
|
||||
const char *address)
|
||||
{
|
||||
return &smb_stream_ops;
|
||||
const char **ports = lp_smb_ports();
|
||||
int i;
|
||||
NTSTATUS status;
|
||||
|
||||
for (i=0;ports[i];i++) {
|
||||
uint16_t port = atoi(ports[i]);
|
||||
if (port == 0) continue;
|
||||
status = stream_setup_socket(event_context, model_ops, &smb_stream_ops,
|
||||
"ipv4", address, &port, NULL);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
}
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
static const struct server_service_ops smb_server_ops = {
|
||||
.name = "smb",
|
||||
.service_init = smbsrv_init,
|
||||
};
|
||||
/*
|
||||
called on startup of the smb server service It's job is to start
|
||||
listening on all configured SMB server sockets
|
||||
*/
|
||||
static NTSTATUS smbsrv_init(struct event_context *event_context, const struct model_ops *model_ops)
|
||||
{
|
||||
NTSTATUS status;
|
||||
|
||||
const struct server_service_ops *smbsrv_get_ops(void)
|
||||
{
|
||||
return &smb_server_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++) {
|
||||
const char *address = sys_inet_ntoa(*iface_n_ip(i));
|
||||
status = smb_add_socket(event_context, model_ops, address);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
}
|
||||
} else {
|
||||
/* Just bind to lp_socket_address() (usually 0.0.0.0) */
|
||||
status = smb_add_socket(event_context, model_ops, lp_socket_address());
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
}
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/* called at smbd startup - register ourselves as a server service */
|
||||
NTSTATUS server_service_smb_init(void)
|
||||
{
|
||||
return NT_STATUS_OK;
|
||||
return register_server_service("smb", smbsrv_init);
|
||||
}
|
||||
|
@ -232,7 +232,7 @@ struct smbsrv_connection {
|
||||
|
||||
struct smb_signing_context signing;
|
||||
|
||||
struct server_connection *connection;
|
||||
struct stream_connection *connection;
|
||||
|
||||
/* this holds a partially received request */
|
||||
struct smbsrv_request *partial_req;
|
||||
|
@ -44,7 +44,8 @@ REQUIRED_SUBSYSTEMS = \
|
||||
# Start SUBSYSTEM SERVICE
|
||||
[SUBSYSTEM::SERVER_SERVICE]
|
||||
INIT_OBJ_FILES = \
|
||||
smbd/service.o
|
||||
smbd/service.o \
|
||||
smbd/service_stream.o
|
||||
REQUIRED_SUBSYSTEMS = \
|
||||
MESSAGING
|
||||
# End SUBSYSTEM SERVER
|
||||
@ -54,8 +55,7 @@ REQUIRED_SUBSYSTEMS = \
|
||||
# Start BINARY smbd
|
||||
[BINARY::smbd]
|
||||
OBJ_FILES = \
|
||||
smbd/server.o \
|
||||
smbd/rewrite.o
|
||||
smbd/server.o
|
||||
REQUIRED_SUBSYSTEMS = \
|
||||
PROCESS_MODEL \
|
||||
SERVER_SERVICE \
|
||||
|
@ -22,12 +22,11 @@
|
||||
#include "includes.h"
|
||||
#include "events.h"
|
||||
#include "smb_server/smb_server.h"
|
||||
#include "smbd/process_model.h"
|
||||
|
||||
/*
|
||||
setup the events for the chosen process model
|
||||
*/
|
||||
const struct model_ops *process_model_startup(struct server_context *srv_ctx, const char *model)
|
||||
const struct model_ops *process_model_startup(struct event_context *ev, const char *model)
|
||||
{
|
||||
const struct model_ops *ops;
|
||||
|
||||
@ -37,7 +36,7 @@ const struct model_ops *process_model_startup(struct server_context *srv_ctx, co
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
ops->model_init(srv_ctx);
|
||||
ops->model_init(ev);
|
||||
|
||||
return ops;
|
||||
}
|
||||
@ -107,7 +106,6 @@ 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),
|
||||
sizeof(struct smbsrv_connection),
|
||||
sizeof(struct event_context),
|
||||
sizeof(struct fd_event)
|
||||
};
|
||||
|
@ -1,7 +1,9 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
process model manager - main loop
|
||||
Copyright (C) Andrew Tridgell 1992-2003
|
||||
|
||||
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
|
||||
|
||||
@ -20,9 +22,6 @@
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef SAMBA_PROCESS_MODEL_H
|
||||
#define SAMBA_PROCESS_MODEL_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.
|
||||
@ -37,32 +36,22 @@ struct model_ops {
|
||||
const char *name;
|
||||
|
||||
/* called at startup when the model is selected */
|
||||
void (*model_init)(struct server_context *srv_ctx);
|
||||
/* called at th eend of the main server process */
|
||||
void (*model_exit)(struct server_context *srv_ctx, const char *reason);
|
||||
|
||||
void (*model_init)(struct event_context *);
|
||||
|
||||
/* function to accept new connection */
|
||||
void (*accept_connection)(struct event_context *, struct fd_event *,
|
||||
struct timeval t, uint16_t);
|
||||
void (*accept_connection)(struct event_context *, struct socket_context *,
|
||||
void (*)(struct event_context *, struct socket_context *,
|
||||
uint32_t , void *),
|
||||
void *);
|
||||
|
||||
/* function to terminate a connection */
|
||||
void (*terminate_connection)(struct server_connection *srv_conn,
|
||||
const char *reason);
|
||||
|
||||
|
||||
/* function to create a new task event_context */
|
||||
void (*create_task)(struct server_task *task);
|
||||
/* function to exit this task */
|
||||
void (*terminate_task)(struct server_task *task, const char *reason);
|
||||
void (*terminate_connection)(struct event_context *, const char *reason);
|
||||
};
|
||||
|
||||
/* 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;
|
||||
int sizeof_server_context;
|
||||
int sizeof_event_context;
|
||||
int sizeof_fd_event;
|
||||
};
|
||||
|
||||
#endif /* SAMBA_PROCESS_MODEL_H */
|
||||
|
@ -1,6 +1,8 @@
|
||||
/*
|
||||
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
|
||||
@ -24,121 +26,57 @@
|
||||
#include "events.h"
|
||||
#include "dlinklist.h"
|
||||
#include "smb_server/smb_server.h"
|
||||
#include "process_model.h"
|
||||
|
||||
|
||||
/*
|
||||
called when the process model is selected
|
||||
*/
|
||||
static void single_model_init(struct server_context *server)
|
||||
static void single_model_init(struct event_context *ev)
|
||||
{
|
||||
}
|
||||
|
||||
static void single_model_exit(struct server_context *server, const char *reason)
|
||||
{
|
||||
DEBUG(1,("single_exit_server: reason[%s]\n",reason));
|
||||
talloc_free(server);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/*
|
||||
called when a listening socket becomes readable
|
||||
called when a listening socket becomes readable.
|
||||
*/
|
||||
static void single_accept_connection(struct event_context *ev, struct fd_event *srv_fde,
|
||||
struct timeval t, uint16_t flags)
|
||||
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 *sock;
|
||||
struct server_stream_socket *stream_socket = srv_fde->private;
|
||||
struct server_connection *conn;
|
||||
struct socket_context *sock2;
|
||||
|
||||
/* accept an incoming connection. */
|
||||
status = socket_accept(stream_socket->socket, &sock);
|
||||
status = socket_accept(sock, &sock2);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(0,("accept_connection_single: accept: %s\n",
|
||||
nt_errstr(status)));
|
||||
DEBUG(0,("accept_connection_single: accept: %s\n", nt_errstr(status)));
|
||||
return;
|
||||
}
|
||||
|
||||
conn = server_setup_connection(ev, stream_socket, sock, t, socket_get_fd(sock));
|
||||
if (!conn) {
|
||||
DEBUG(10,("server_setup_connection failed\n"));
|
||||
return;
|
||||
}
|
||||
talloc_steal(private, sock);
|
||||
|
||||
talloc_steal(conn, sock);
|
||||
|
||||
/* return to event handling */
|
||||
return;
|
||||
new_conn(ev, sock2, socket_get_fd(sock), private);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* called when a SMB connection goes down */
|
||||
static void single_terminate_connection(struct server_connection *conn, const char *reason)
|
||||
/* called when a connection goes down */
|
||||
static void single_terminate_connection(struct event_context *ev, const char *reason)
|
||||
{
|
||||
DEBUG(2,("single_terminate_connection: reason[%s]\n",reason));
|
||||
|
||||
if (conn) {
|
||||
talloc_free(conn);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
called to create a new event context for a new task
|
||||
*/
|
||||
static void single_create_task(struct server_task *task)
|
||||
{
|
||||
task->task.id = (uint32_t)task;
|
||||
task->event.ctx = task->service->server->event.ctx;
|
||||
|
||||
/* setup to receive internal messages on this connection */
|
||||
task->messaging.ctx = messaging_init(task, task->task.id, task->event.ctx);
|
||||
if (!task->messaging.ctx) {
|
||||
server_terminate_task(task, "messaging_init() failed");
|
||||
return;
|
||||
}
|
||||
|
||||
task->task.ops->task_init(task);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
called to exit from a server_task
|
||||
*/
|
||||
static void single_terminate_task(struct server_task *task, const char *reason)
|
||||
{
|
||||
DEBUG(1,("single_exit_server: reason[%s]\n",reason));
|
||||
talloc_free(task);
|
||||
return;
|
||||
}
|
||||
|
||||
static const struct model_ops single_ops = {
|
||||
.name = "single",
|
||||
|
||||
.model_init = single_model_init,
|
||||
.model_exit = single_model_exit,
|
||||
|
||||
.accept_connection = single_accept_connection,
|
||||
.terminate_connection = single_terminate_connection,
|
||||
|
||||
.create_task = single_create_task,
|
||||
.terminate_task = single_terminate_task
|
||||
};
|
||||
|
||||
/*
|
||||
initialise the single process model, registering ourselves with the process model subsystem
|
||||
initialise the single process model, registering ourselves with the
|
||||
process model subsystem
|
||||
*/
|
||||
NTSTATUS process_model_single_init(void)
|
||||
{
|
||||
NTSTATUS ret;
|
||||
|
||||
/* register ourselves with the PROCESS_MODEL subsystem. */
|
||||
ret = register_process_model(&single_ops);
|
||||
if (!NT_STATUS_IS_OK(ret)) {
|
||||
DEBUG(0,("Failed to register process_model 'single'!\n"));
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return register_process_model(&single_ops);
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
process model: standard (1 process per client connection)
|
||||
Copyright (C) Andrew Tridgell 1992-2003
|
||||
|
||||
Copyright (C) Andrew Tridgell 1992-2005
|
||||
Copyright (C) James J Myers 2003 <myersjj@samba.org>
|
||||
Copyright (C) Stefan (metze) Metzmacher 2004
|
||||
|
||||
@ -24,37 +26,31 @@
|
||||
#include "events.h"
|
||||
#include "dlinklist.h"
|
||||
#include "smb_server/smb_server.h"
|
||||
#include "process_model.h"
|
||||
|
||||
/*
|
||||
called when the process model is selected
|
||||
*/
|
||||
static void standard_model_init(struct server_context *server)
|
||||
static void standard_model_init(struct event_context *ev)
|
||||
{
|
||||
signal(SIGCHLD, SIG_IGN);
|
||||
}
|
||||
|
||||
static void standard_model_exit(struct server_context *server, const char *reason)
|
||||
{
|
||||
DEBUG(1,("standard_model_exit: reason[%s]\n",reason));
|
||||
talloc_free(server);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/*
|
||||
called when a listening socket becomes readable
|
||||
called when a listening socket becomes readable.
|
||||
*/
|
||||
static void standard_accept_connection(struct event_context *ev, struct fd_event *srv_fde,
|
||||
struct timeval t, uint16_t flags)
|
||||
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 *sock;
|
||||
struct server_stream_socket *stream_socket = srv_fde->private;
|
||||
struct server_connection *conn;
|
||||
struct socket_context *sock2;
|
||||
pid_t pid;
|
||||
struct event_context *ev2;
|
||||
|
||||
/* accept an incoming connection. */
|
||||
status = socket_accept(stream_socket->socket, &sock);
|
||||
status = socket_accept(sock, &sock2);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(0,("standard_accept_connection: accept: %s\n",
|
||||
nt_errstr(status)));
|
||||
@ -65,20 +61,28 @@ static void standard_accept_connection(struct event_context *ev, struct fd_event
|
||||
|
||||
if (pid != 0) {
|
||||
/* parent or error code ... */
|
||||
|
||||
socket_destroy(sock);
|
||||
talloc_free(sock2);
|
||||
/* go back to the event loop */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Child code ... */
|
||||
/* This is now the child code. We need a completely new event_context to work with */
|
||||
ev2 = event_context_init(NULL);
|
||||
|
||||
/* close all the listening sockets */
|
||||
event_remove_fd_all_handler(ev, server_accept_handler);
|
||||
/* 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(sock);
|
||||
socket_dup(sock2);
|
||||
|
||||
/* tdb needs special fork handling */
|
||||
if (tdb_reopen_all() == -1) {
|
||||
@ -86,31 +90,26 @@ static void standard_accept_connection(struct event_context *ev, struct fd_event
|
||||
}
|
||||
|
||||
/* Ensure that the forked children do not expose identical random streams */
|
||||
|
||||
set_need_random_reseed();
|
||||
|
||||
conn = server_setup_connection(ev, stream_socket, sock, t, getpid());
|
||||
if (!conn) {
|
||||
DEBUG(0,("server_setup_connection(ev, server_socket, sock, t) failed\n"));
|
||||
exit(1);
|
||||
return;
|
||||
}
|
||||
/* setup this new connection */
|
||||
new_conn(ev2, sock2, getpid(), private);
|
||||
|
||||
talloc_steal(conn, sock);
|
||||
/* 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);
|
||||
|
||||
/* return to the event loop */
|
||||
talloc_free(ev2);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
/* called when a SMB connection goes down */
|
||||
static void standard_terminate_connection(struct server_connection *conn, const char *reason)
|
||||
/* called when a connection goes down */
|
||||
static void standard_terminate_connection(struct event_context *ev, const char *reason)
|
||||
{
|
||||
DEBUG(2,("standard_terminate_connection: reason[%s]\n",reason));
|
||||
|
||||
if (conn) {
|
||||
talloc_free(conn->stream_socket->service->server);
|
||||
}
|
||||
|
||||
/* this init_iconv() has the effect of freeing the iconv context memory,
|
||||
which makes leak checking easier */
|
||||
init_iconv();
|
||||
@ -118,87 +117,18 @@ static void standard_terminate_connection(struct server_connection *conn, const
|
||||
/* the secrets db should really hang off the connection structure */
|
||||
secrets_shutdown();
|
||||
|
||||
/* terminate this process */
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/*
|
||||
called to create a new event context for a new task
|
||||
*/
|
||||
static void standard_create_task(struct server_task *task)
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
pid = fork();
|
||||
|
||||
if (pid != 0) {
|
||||
/* parent or error code ... */
|
||||
talloc_free(task);
|
||||
/* go back to the event loop */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Child code ... */
|
||||
|
||||
/* close all the listening sockets */
|
||||
event_remove_fd_all_handler(task->service->server->event.ctx, server_accept_handler);
|
||||
|
||||
/* tdb needs special fork handling */
|
||||
if (tdb_reopen_all() == -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();
|
||||
|
||||
task->task.id = (uint32)getpid();
|
||||
task->event.ctx = task->service->server->event.ctx;
|
||||
|
||||
/* setup to receive internal messages on this connection */
|
||||
task->messaging.ctx = messaging_init(task, task->task.id, task->event.ctx);
|
||||
if (!task->messaging.ctx) {
|
||||
server_terminate_task(task, "messaging_init() failed");
|
||||
return;
|
||||
}
|
||||
|
||||
task->task.ops->task_init(task);
|
||||
|
||||
server_terminate_task(task, "exit");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
called to destroy a new event context for a new task
|
||||
*/
|
||||
static void standard_terminate_task(struct server_task *task, const char *reason)
|
||||
{
|
||||
DEBUG(2,("standard_terminate_task: reason[%s]\n",reason));
|
||||
|
||||
talloc_free(task);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
|
||||
static const struct model_ops standard_ops = {
|
||||
.name = "standard",
|
||||
|
||||
.model_init = standard_model_init,
|
||||
.model_exit = standard_model_exit,
|
||||
|
||||
.accept_connection = standard_accept_connection,
|
||||
.terminate_connection = standard_terminate_connection,
|
||||
|
||||
.create_task = standard_create_task,
|
||||
.terminate_task = standard_terminate_task
|
||||
};
|
||||
|
||||
/*
|
||||
@ -206,14 +136,5 @@ static const struct model_ops standard_ops = {
|
||||
*/
|
||||
NTSTATUS process_model_standard_init(void)
|
||||
{
|
||||
NTSTATUS ret;
|
||||
|
||||
/* register ourselves with the PROCESS_MODEL subsystem. */
|
||||
ret = register_process_model(&standard_ops);
|
||||
if (!NT_STATUS_IS_OK(ret)) {
|
||||
DEBUG(0,("Failed to register process_model 'standard'!\n"));
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return register_process_model(&standard_ops);
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
thread model: standard (1 thread per client connection)
|
||||
Copyright (C) Andrew Tridgell 2003
|
||||
|
||||
Copyright (C) Andrew Tridgell 2003-2005
|
||||
Copyright (C) James J Myers 2003 <myersjj@samba.org>
|
||||
Copyright (C) Stefan (metze) Metzmacher 2004
|
||||
|
||||
@ -30,89 +32,85 @@
|
||||
#include "events.h"
|
||||
#include "dlinklist.h"
|
||||
#include "smb_server/smb_server.h"
|
||||
#include "process_model.h"
|
||||
|
||||
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 server_connection *conn = thread_parm;
|
||||
struct new_conn_state *new_conn = talloc_get_type(thread_parm, struct new_conn_state);
|
||||
|
||||
conn->connection.id = pthread_self();
|
||||
new_conn->new_conn(new_conn->ev, new_conn->sock, pthread_self(), new_conn->private);
|
||||
|
||||
/* wait for action */
|
||||
event_loop_wait(conn->event.ctx);
|
||||
/* run this connection from here */
|
||||
event_loop_wait(new_conn->ev);
|
||||
|
||||
talloc_free(new_conn);
|
||||
|
||||
#if 0
|
||||
pthread_cleanup_pop(1); /* will invoke terminate_mt_connection() */
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
called when a listening socket becomes readable
|
||||
*/
|
||||
static void thread_accept_connection(struct event_context *ev, struct fd_event *srv_fde,
|
||||
struct timeval t, uint16_t flags)
|
||||
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;
|
||||
struct socket_context *sock;
|
||||
int rc;
|
||||
pthread_t thread_id;
|
||||
pthread_attr_t thread_attr;
|
||||
struct server_stream_socket *stream_socket = srv_fde->private;
|
||||
struct server_connection *conn;
|
||||
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(stream_socket->socket, &sock);
|
||||
status = socket_accept(sock, &state->sock);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
talloc_free(ev2);
|
||||
return;
|
||||
}
|
||||
|
||||
/* create new detached thread for this connection. The new
|
||||
thread gets a new event_context with a single fd_event for
|
||||
receiving from the new socket. We set that thread running
|
||||
with the main event loop, then return. When we return the
|
||||
main event_context is continued.
|
||||
*/
|
||||
|
||||
ev = event_context_init(stream_socket);
|
||||
if (!ev) {
|
||||
socket_destroy(sock);
|
||||
return;
|
||||
}
|
||||
|
||||
conn = server_setup_connection(ev, stream_socket, sock, t, -1);
|
||||
if (!conn) {
|
||||
event_context_destroy(ev);
|
||||
socket_destroy(sock);
|
||||
return;
|
||||
}
|
||||
|
||||
talloc_steal(conn, ev);
|
||||
talloc_steal(conn, sock);
|
||||
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, conn);
|
||||
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));
|
||||
event_context_destroy(ev);
|
||||
socket_destroy(sock);
|
||||
return;
|
||||
talloc_free(ev2);
|
||||
}
|
||||
}
|
||||
|
||||
/* called when a SMB connection goes down */
|
||||
static void thread_terminate_connection(struct server_connection *conn, const char *reason)
|
||||
static void thread_terminate_connection(struct event_context *event_ctx, const char *reason)
|
||||
{
|
||||
DEBUG(10,("thread_terminate_connection: reason[%s]\n",reason));
|
||||
|
||||
if (conn) {
|
||||
talloc_free(conn);
|
||||
}
|
||||
talloc_free(event_ctx);
|
||||
|
||||
/* terminate this thread */
|
||||
pthread_exit(NULL); /* thread cleanup routine will do actual cleanup */
|
||||
@ -342,6 +340,7 @@ static void thread_log_task_id(int fd)
|
||||
write(fd, s, strlen(s));
|
||||
free(s);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
catch serious errors
|
||||
****************************************************************************/
|
||||
@ -406,7 +405,7 @@ static void thread_fault_handler(int sig)
|
||||
/*
|
||||
called when the process model is selected
|
||||
*/
|
||||
static void thread_model_init(struct server_context *server)
|
||||
static void thread_model_init(struct event_context *event_context)
|
||||
{
|
||||
struct mutex_ops m_ops;
|
||||
struct debug_ops d_ops;
|
||||
@ -438,89 +437,12 @@ static void thread_model_init(struct server_context *server)
|
||||
register_debug_handlers("thread", &d_ops);
|
||||
}
|
||||
|
||||
static void thread_model_exit(struct server_context *server, const char *reason)
|
||||
{
|
||||
DEBUG(1,("thread_model_exit: reason[%s]\n",reason));
|
||||
talloc_free(server);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static void *thread_task_fn(void *thread_parm)
|
||||
{
|
||||
struct server_task *task = thread_parm;
|
||||
|
||||
task->task.id = pthread_self();
|
||||
|
||||
task->event.ctx = event_context_init(task);
|
||||
if (!task->event.ctx) {
|
||||
server_terminate_task(task, "event_context_init() failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
task->messaging.ctx = messaging_init(task, task->task.id, task->event.ctx);
|
||||
if (!task->messaging.ctx) {
|
||||
server_terminate_task(task, "messaging_init() failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
task->task.ops->task_init(task);
|
||||
|
||||
/* wait for action */
|
||||
event_loop_wait(task->event.ctx);
|
||||
|
||||
server_terminate_task(task, "exit");
|
||||
#if 0
|
||||
pthread_cleanup_pop(1); /* will invoke terminate_mt_connection() */
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
/*
|
||||
called to create a new event context for a new task
|
||||
*/
|
||||
static void thread_create_task(struct server_task *task)
|
||||
{
|
||||
int rc;
|
||||
pthread_t thread_id;
|
||||
pthread_attr_t thread_attr;
|
||||
|
||||
pthread_attr_init(&thread_attr);
|
||||
pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
|
||||
rc = pthread_create(&thread_id, &thread_attr, thread_task_fn, task);
|
||||
pthread_attr_destroy(&thread_attr);
|
||||
if (rc == 0) {
|
||||
DEBUG(4,("thread_create_task: created thread_id=%lu for task='%s'\n",
|
||||
(unsigned long int)thread_id, task->task.ops->name));
|
||||
} else {
|
||||
DEBUG(0,("thread_create_task: thread create failed for task='%s', rc=%d\n", task->task.ops->name, rc));
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
called to destroy a new event context for a new task
|
||||
*/
|
||||
static void thread_terminate_task(struct server_task *task, const char *reason)
|
||||
{
|
||||
DEBUG(2,("thread_terminate_task: reason[%s]\n",reason));
|
||||
|
||||
talloc_free(task);
|
||||
|
||||
/* terminate this thread */
|
||||
pthread_exit(NULL); /* thread cleanup routine will do actual cleanup */
|
||||
}
|
||||
|
||||
static const struct model_ops thread_ops = {
|
||||
.name = "thread",
|
||||
|
||||
.model_init = thread_model_init,
|
||||
.model_exit = thread_model_exit,
|
||||
|
||||
.accept_connection = thread_accept_connection,
|
||||
.terminate_connection = thread_terminate_connection,
|
||||
|
||||
.create_task = thread_create_task,
|
||||
.terminate_task = thread_terminate_task
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -1,70 +0,0 @@
|
||||
#include "includes.h"
|
||||
#include "dynconfig.h"
|
||||
|
||||
|
||||
/*
|
||||
* initialize an smb process. Guaranteed to be called only once per
|
||||
* smbd instance (so it can assume it is starting from scratch, and
|
||||
* delete temporary files etc)
|
||||
*/
|
||||
void smbd_process_init(void)
|
||||
{
|
||||
/* possibly reload the services file. */
|
||||
reload_services(NULL, True);
|
||||
|
||||
if (*lp_rootdir()) {
|
||||
if (sys_chroot(lp_rootdir()) == 0)
|
||||
DEBUG(2,("Changed root to %s\n", lp_rootdir()));
|
||||
}
|
||||
|
||||
service_cleanup_tmp_files();
|
||||
}
|
||||
|
||||
void init_subsystems(void)
|
||||
{
|
||||
/* 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);
|
||||
}
|
||||
|
||||
smbd_init_subsystems;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Reload the services file.
|
||||
**************************************************************************/
|
||||
BOOL reload_services(struct smbsrv_connection *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);
|
||||
|
||||
ret = lp_load(dyn_CONFIGFILE, False, False, True);
|
||||
|
||||
/* perhaps the config filename is now set */
|
||||
if (!test)
|
||||
reload_services(smb, True);
|
||||
|
||||
reopen_logs();
|
||||
|
||||
load_interfaces();
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
Main SMB server routines
|
||||
Copyright (C) Andrew Tridgell 1992-1998
|
||||
|
||||
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>
|
||||
@ -23,56 +25,56 @@
|
||||
|
||||
#include "includes.h"
|
||||
#include "version.h"
|
||||
#include "dynconfig.h"
|
||||
#include "lib/cmdline/popt_common.h"
|
||||
#include "system/dir.h"
|
||||
|
||||
/****************************************************************************
|
||||
main server.
|
||||
****************************************************************************/
|
||||
static int binary_smbd_main(int argc,const char *argv[])
|
||||
|
||||
/*
|
||||
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)
|
||||
{
|
||||
BOOL is_daemon = False;
|
||||
BOOL interactive = False;
|
||||
BOOL Fork = True;
|
||||
BOOL log_stdout = False;
|
||||
int opt;
|
||||
poptContext pc;
|
||||
struct server_context *server;
|
||||
const char *model = "standard";
|
||||
struct poptOption long_options[] = {
|
||||
POPT_AUTOHELP
|
||||
POPT_COMMON_SAMBA
|
||||
{"daemon", 'D', POPT_ARG_VAL, &is_daemon, True, "Become a daemon (default)" , NULL },
|
||||
{"interactive", 'i', POPT_ARG_VAL, &interactive, True, "Run interactive (not a daemon)", NULL},
|
||||
{"foreground", 'F', POPT_ARG_VAL, &Fork, True, "Run daemon in foreground (for daemontools & etc)" , NULL },
|
||||
{"log-stdout", 'S', POPT_ARG_VAL, &log_stdout, True, "Log to stdout", NULL },
|
||||
{"port", 'p', POPT_ARG_STRING, NULL, 0, "Listen on the specified ports", "PORTS"},
|
||||
{"model", 'M', POPT_ARG_STRING, &model, True, "Select process model", "MODEL"},
|
||||
POPT_COMMON_VERSION
|
||||
POPT_TABLEEND
|
||||
};
|
||||
|
||||
pc = poptGetContext("smbd", argc, argv, long_options, 0);
|
||||
|
||||
while((opt = poptGetNextOpt(pc)) != -1) {
|
||||
switch (opt) {
|
||||
case 'p':
|
||||
lp_set_cmdline("smb ports", poptGetOptArg(pc));
|
||||
break;
|
||||
char *path;
|
||||
DIR *dir;
|
||||
struct dirent *de;
|
||||
TALLOC_CTX *mem_ctx = talloc_new(NULL);
|
||||
|
||||
path = smbd_tmp_path(mem_ctx, NULL);
|
||||
|
||||
dir = opendir(path);
|
||||
if (!dir) {
|
||||
talloc_free(mem_ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
for (de=readdir(dir);de;de=readdir(dir)) {
|
||||
char *fname = talloc_asprintf(mem_ctx, "%s/%s", path, de->d_name);
|
||||
int ret = unlink(fname);
|
||||
if (ret == -1 &&
|
||||
errno != ENOENT &&
|
||||
errno != EISDIR &&
|
||||
errno != EISDIR) {
|
||||
DEBUG(0,("Unabled to delete '%s' - %s\n",
|
||||
fname, strerror(errno)));
|
||||
smb_panic("unable to cleanup tmp files");
|
||||
}
|
||||
talloc_free(fname);
|
||||
}
|
||||
poptFreeContext(pc);
|
||||
closedir(dir);
|
||||
|
||||
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?DEBUG_STDOUT:DEBUG_FILE);
|
||||
talloc_free(mem_ctx);
|
||||
}
|
||||
|
||||
/*
|
||||
setup signal masks
|
||||
*/
|
||||
static void setup_signals(void)
|
||||
{
|
||||
fault_setup(NULL);
|
||||
|
||||
/* we are never interested in SIGPIPE */
|
||||
@ -93,6 +95,39 @@ static int binary_smbd_main(int argc,const char *argv[])
|
||||
BlockSignals(False, SIGHUP);
|
||||
BlockSignals(False, SIGUSR1);
|
||||
BlockSignals(False, SIGTERM);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
main server.
|
||||
*/
|
||||
static int binary_smbd_main(int argc, const char *argv[])
|
||||
{
|
||||
BOOL interactive = False;
|
||||
int opt;
|
||||
poptContext pc;
|
||||
struct event_context *event_ctx;
|
||||
NTSTATUS status;
|
||||
const char *model = "standard";
|
||||
struct poptOption long_options[] = {
|
||||
POPT_AUTOHELP
|
||||
POPT_COMMON_SAMBA
|
||||
{"interactive", 'i', POPT_ARG_VAL, &interactive, True,
|
||||
"Run interactive (not a daemon)", NULL},
|
||||
{"model", 'M', POPT_ARG_STRING, &model, True,
|
||||
"Select process model", "MODEL"},
|
||||
POPT_COMMON_VERSION
|
||||
POPT_TABLEEND
|
||||
};
|
||||
|
||||
pc = poptGetContext("smbd", argc, argv, long_options, 0);
|
||||
|
||||
while((opt = poptGetNextOpt(pc)) != -1) /* noop */ ;
|
||||
|
||||
poptFreeContext(pc);
|
||||
|
||||
setup_logging(argv[0], interactive?DEBUG_STDOUT:DEBUG_FILE);
|
||||
setup_signals();
|
||||
|
||||
/* we want total control over the permissions on created files,
|
||||
so set our umask to 0 */
|
||||
@ -108,49 +143,51 @@ static int binary_smbd_main(int argc,const char *argv[])
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!reload_services(NULL, False))
|
||||
return(-1);
|
||||
lp_load(dyn_CONFIGFILE, False, False, True);
|
||||
|
||||
if (!is_daemon && !is_a_socket(0)) {
|
||||
if (!interactive)
|
||||
DEBUG(0,("standard input is not a socket, assuming -D option\n"));
|
||||
reopen_logs();
|
||||
load_interfaces();
|
||||
|
||||
/*
|
||||
* Setting is_daemon here prevents us from eventually calling
|
||||
* the open_sockets_inetd()
|
||||
*/
|
||||
|
||||
is_daemon = True;
|
||||
}
|
||||
|
||||
if (is_daemon && !interactive) {
|
||||
if (!interactive) {
|
||||
DEBUG(3,("Becoming a daemon.\n"));
|
||||
become_daemon(Fork);
|
||||
become_daemon(True);
|
||||
}
|
||||
|
||||
cleanup_tmp_files();
|
||||
|
||||
if (!directory_exist(lp_lockdir(), NULL)) {
|
||||
mkdir(lp_lockdir(), 0755);
|
||||
}
|
||||
|
||||
if (is_daemon) {
|
||||
pidfile_create("smbd");
|
||||
pidfile_create("smbd");
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
init_subsystems();
|
||||
smbd_init_subsystems;
|
||||
|
||||
smbd_process_init();
|
||||
/* the event context is the top level structure in smbd. Everything else
|
||||
should hang off that */
|
||||
event_ctx = event_context_init(NULL);
|
||||
|
||||
DEBUG(0,("Using %s process model\n", model));
|
||||
server = server_service_startup(model, lp_server_services());
|
||||
if (!server) {
|
||||
DEBUG(0,("Starting Services failed.\n"));
|
||||
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 */
|
||||
event_loop_wait(server->event.ctx);
|
||||
/* wait for events - this is where smbd sits for most of its
|
||||
life */
|
||||
event_loop_wait(event_ctx);
|
||||
|
||||
server_service_shutdown(server, "exit");
|
||||
/* as everything hangs off this event context, freeing it
|
||||
should initiate a clean shutdown of all services */
|
||||
talloc_free(event_ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,49 +0,0 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
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 _SERVER_H
|
||||
#define _SERVER_H
|
||||
|
||||
struct server_service;
|
||||
struct event_context;
|
||||
|
||||
struct server_context {
|
||||
struct {
|
||||
struct event_context *ctx;
|
||||
} event;
|
||||
|
||||
struct {
|
||||
const struct model_ops *ops;
|
||||
} model;
|
||||
|
||||
struct server_service *service_list;
|
||||
};
|
||||
|
||||
/* size of listen() backlog in smbd */
|
||||
#define SERVER_LISTEN_BACKLOG 10
|
||||
|
||||
/* the range of ports to try for dcerpc over tcp endpoints */
|
||||
#define SERVER_TCP_LOW_PORT 1024
|
||||
#define SERVER_TCP_HIGH_PORT 1300
|
||||
|
||||
/* the default idle time of a service */
|
||||
#define SERVER_DEFAULT_IDLE_TIME 300
|
||||
|
||||
#endif /* _SERVER_H */
|
@ -3,7 +3,7 @@
|
||||
|
||||
SERVER SERVICE code
|
||||
|
||||
Copyright (C) Andrew Tridgell 2003
|
||||
Copyright (C) Andrew Tridgell 2003-2005
|
||||
Copyright (C) Stefan (metze) Metzmacher 2004
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
@ -22,377 +22,77 @@
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "events.h"
|
||||
#include "system/dir.h"
|
||||
#include "dlinklist.h"
|
||||
#include "process_model.h"
|
||||
|
||||
struct server_context *server_service_startup(const char *model, const char **server_services)
|
||||
/*
|
||||
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;
|
||||
struct server_context *server;
|
||||
const struct model_ops *model_ops;
|
||||
|
||||
if (!server_services) {
|
||||
DEBUG(0,("server_service_startup: no endpoint servers configured\n"));
|
||||
return NULL;
|
||||
return NT_STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
server = talloc_zero(NULL, struct server_context);
|
||||
if (!server) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
server->model.ops = process_model_startup(server, model);
|
||||
if (!server->model.ops) {
|
||||
model_ops = process_model_startup(event_ctx, model);
|
||||
if (!model_ops) {
|
||||
DEBUG(0,("process_model_startup('%s') failed\n", model));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
server->event.ctx = event_context_init(server);
|
||||
if (!server->event.ctx) {
|
||||
DEBUG(0,("event_context_init() failed\n"));
|
||||
return NULL;
|
||||
return NT_STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
for (i=0;server_services[i];i++) {
|
||||
const struct server_service_ops *service_ops;
|
||||
struct server_service *service;
|
||||
NTSTATUS status;
|
||||
|
||||
service_ops = server_service_byname(server_services[i]);
|
||||
if (!service_ops) {
|
||||
DEBUG(0,("process_model_startup: failed to find server service = '%s'\n", server_services[i]));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
service = talloc_zero(server, struct server_service);
|
||||
if (!service) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
service->service.ops = service_ops;
|
||||
service->server = server;
|
||||
|
||||
/* TODO: service_init() should return a result */
|
||||
service->service.ops->service_init(service);
|
||||
|
||||
DLIST_ADD(server->service_list, service);
|
||||
status = server_service_init(server_services[i], event_ctx, model_ops);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
}
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
void server_service_shutdown(struct server_context *server, const char *reason)
|
||||
{
|
||||
server->model.ops->model_exit(server, reason);
|
||||
}
|
||||
|
||||
/*
|
||||
setup a listen stream socket
|
||||
if you pass *port == 0, then a port > 1024 is used
|
||||
*/
|
||||
struct server_stream_socket *service_setup_stream_socket(struct server_service *service,
|
||||
const struct server_stream_ops *stream_ops,
|
||||
const char *family,
|
||||
const char *sock_addr,
|
||||
uint16_t *port)
|
||||
{
|
||||
NTSTATUS status;
|
||||
struct server_stream_socket *stream_socket;
|
||||
struct socket_context *sock;
|
||||
struct fd_event fde;
|
||||
int i;
|
||||
|
||||
status = socket_create(family, SOCKET_TYPE_STREAM, &sock, 0);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(0,("Failed to open socket on %s:%u - %s\n",
|
||||
sock_addr, *port, nt_errstr(status)));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ready to listen */
|
||||
status = socket_set_option(sock, "SO_KEEPALIVE SO_REUSEADDR=1", NULL);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(0,("socket_set_option(socket_ctx, SO_KEEPALIVE, NULL): %s\n",
|
||||
nt_errstr(status)));
|
||||
socket_destroy(sock);
|
||||
return NULL;
|
||||
}
|
||||
status = socket_set_option(sock, lp_socket_options(), NULL);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(0,("socket_set_option(socket_ctx, lp_socket_options(), NULL): %s\n",
|
||||
nt_errstr(status)));
|
||||
socket_destroy(sock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* 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++) {
|
||||
status = socket_listen(sock, sock_addr, i, SERVER_LISTEN_BACKLOG, 0);
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
*port = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
status = socket_listen(sock, sock_addr, *port, SERVER_LISTEN_BACKLOG, 0);
|
||||
}
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(0,("Failed to listen on %s:%u - %s\n",
|
||||
sock_addr, *port, nt_errstr(status)));
|
||||
socket_destroy(sock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
stream_socket = talloc_zero(service, struct server_stream_socket);
|
||||
if (!stream_socket) {
|
||||
DEBUG(0,("talloc(mem_ctx, struct server_stream_socket) failed\n"));
|
||||
socket_destroy(sock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* we are only interested in read events on the listen socket */
|
||||
fde.fd = socket_get_fd(sock);
|
||||
fde.flags = EVENT_FD_READ;
|
||||
fde.private = stream_socket;
|
||||
fde.handler = server_accept_handler;
|
||||
|
||||
stream_socket->stream.ops = stream_ops;
|
||||
stream_socket->service = service;
|
||||
stream_socket->socket = sock;
|
||||
stream_socket->event.ctx = service->server->event.ctx;
|
||||
stream_socket->event.fde = event_add_fd(stream_socket->event.ctx,
|
||||
&fde, stream_socket);
|
||||
if (!stream_socket->event.fde) {
|
||||
socket_destroy(sock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
talloc_steal(stream_socket, sock);
|
||||
|
||||
if (stream_socket->stream.ops->socket_init) {
|
||||
stream_socket->stream.ops->socket_init(stream_socket);
|
||||
}
|
||||
|
||||
return stream_socket;
|
||||
}
|
||||
|
||||
/*
|
||||
destructor that handles necessary event context changes
|
||||
*/
|
||||
static int server_connection_destructor(void *ptr)
|
||||
{
|
||||
struct server_connection *conn = ptr;
|
||||
|
||||
if (conn->stream_socket &&
|
||||
conn->stream_socket->stream.ops->close_connection) {
|
||||
/* don't remove this! the stream service needs to free it's data
|
||||
* before we destroy the server_connection
|
||||
*/
|
||||
conn->stream_socket->stream.ops->close_connection(conn, "shutdown");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct server_connection *server_setup_connection(struct event_context *ev,
|
||||
struct server_stream_socket *stream_socket,
|
||||
struct socket_context *sock,
|
||||
struct timeval t,
|
||||
servid_t server_id)
|
||||
{
|
||||
struct fd_event fde;
|
||||
struct timed_event idle;
|
||||
struct server_connection *srv_conn;
|
||||
|
||||
srv_conn = talloc(stream_socket, struct server_connection);
|
||||
if (!srv_conn) {
|
||||
DEBUG(0,("talloc(mem_ctx, struct server_connection) failed\n"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ZERO_STRUCTP(srv_conn);
|
||||
|
||||
fde.private = srv_conn;
|
||||
fde.fd = socket_get_fd(sock);
|
||||
fde.flags = EVENT_FD_READ;
|
||||
fde.handler = server_io_handler;
|
||||
|
||||
idle.private = srv_conn;
|
||||
idle.next_event = timeval_add(&t, SERVER_DEFAULT_IDLE_TIME, 0);
|
||||
idle.handler = server_idle_handler;
|
||||
|
||||
srv_conn->event.ctx = ev;
|
||||
srv_conn->event.fde = &fde;
|
||||
srv_conn->event.idle = &idle;
|
||||
srv_conn->event.idle_time = timeval_set(SERVER_DEFAULT_IDLE_TIME, 0);
|
||||
|
||||
srv_conn->stream_socket = stream_socket;
|
||||
srv_conn->socket = sock;
|
||||
srv_conn->connection.id = server_id;
|
||||
|
||||
/* create a server context and add it to out event
|
||||
handling */
|
||||
stream_socket->stream.ops->accept_connection(srv_conn);
|
||||
|
||||
/* accpect_connection() of the service may changed idle.next_event */
|
||||
srv_conn->event.fde = event_add_fd(ev, &fde, srv_conn);
|
||||
srv_conn->event.idle = event_add_timed(ev, &idle, srv_conn);
|
||||
|
||||
talloc_set_destructor(srv_conn, server_connection_destructor);
|
||||
|
||||
if (!socket_check_access(sock, "smbd", lp_hostsallow(-1), lp_hostsdeny(-1))) {
|
||||
server_terminate_connection(srv_conn, "denied by access rules");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* setup to receive internal messages on this connection */
|
||||
srv_conn->messaging.ctx = messaging_init(srv_conn, srv_conn->connection.id, ev);
|
||||
if (!srv_conn->messaging.ctx) {
|
||||
server_terminate_connection(srv_conn, "messaging_init() failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return srv_conn;
|
||||
}
|
||||
|
||||
/*
|
||||
close the socket and shutdown a server_context
|
||||
*/
|
||||
void server_terminate_connection(struct server_connection *srv_conn, const char *reason)
|
||||
{
|
||||
DEBUG(2,("server_terminate_connection\n"));
|
||||
srv_conn->stream_socket->service->server->model.ops->terminate_connection(srv_conn, reason);
|
||||
}
|
||||
|
||||
void server_accept_handler(struct event_context *ev, struct fd_event *fde,
|
||||
struct timeval t, uint16_t flags)
|
||||
{
|
||||
struct server_stream_socket *stream_socket = talloc_get_type(fde->private,
|
||||
struct server_stream_socket);
|
||||
|
||||
stream_socket->service->server->model.ops->accept_connection(ev, fde, t, flags);
|
||||
}
|
||||
|
||||
void server_io_handler(struct event_context *ev, struct fd_event *fde,
|
||||
struct timeval t, uint16_t flags)
|
||||
{
|
||||
struct server_connection *conn = talloc_get_type(fde->private,
|
||||
struct server_connection);
|
||||
|
||||
conn->event.idle->next_event = timeval_sum(&t, &conn->event.idle_time);
|
||||
|
||||
if (flags & EVENT_FD_WRITE) {
|
||||
conn->stream_socket->stream.ops->send_handler(conn, t, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
if (flags & EVENT_FD_READ) {
|
||||
conn->stream_socket->stream.ops->recv_handler(conn, t, flags);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void server_idle_handler(struct event_context *ev, struct timed_event *idle,
|
||||
struct timeval t)
|
||||
{
|
||||
struct server_connection *conn = talloc_get_type(idle->private,
|
||||
struct server_connection);
|
||||
|
||||
/* Not all services provide an idle handler */
|
||||
if (conn->stream_socket->stream.ops->idle_handler) {
|
||||
conn->event.idle->next_event = timeval_sum(&t, &conn->event.idle_time);
|
||||
conn->stream_socket->stream.ops->idle_handler(conn, t);
|
||||
}
|
||||
}
|
||||
|
||||
void server_terminate_task(struct server_task *task, const char *reason)
|
||||
{
|
||||
task->service->server->model.ops->terminate_task(task, reason);
|
||||
return;
|
||||
}
|
||||
|
||||
void server_run_task(struct server_service *service, const struct server_task_ops *ops)
|
||||
{
|
||||
struct server_task *task;
|
||||
|
||||
task = talloc_zero(service, struct server_task);
|
||||
if (!task) {
|
||||
return;
|
||||
}
|
||||
task->service = service;
|
||||
task->task.ops = ops;
|
||||
|
||||
service->server->model.ops->create_task(task);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
return the operations structure for a named backend of the specified type
|
||||
*/
|
||||
const struct server_service_ops *server_service_byname(const char *name)
|
||||
{
|
||||
if (strcmp("smb",name)==0) {
|
||||
return smbsrv_get_ops();
|
||||
}
|
||||
if (strcmp("rpc",name)==0) {
|
||||
return dcesrv_get_ops();
|
||||
}
|
||||
if (strcmp("ldap",name)==0) {
|
||||
return ldapsrv_get_ops();
|
||||
}
|
||||
if (strcmp("winbind",name)==0) {
|
||||
return winbind_get_ops();
|
||||
}
|
||||
if (strcmp("winbind_task",name)==0) {
|
||||
return winbind_task_get_ops();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
NTSTATUS register_server_service_ops(const void *_ops)
|
||||
{
|
||||
return NT_STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
void service_cleanup_tmp_files(void)
|
||||
{
|
||||
char *path;
|
||||
DIR *dir;
|
||||
struct dirent *de;
|
||||
TALLOC_CTX *mem_ctx = talloc_init("service_cleanup_tmp_files");
|
||||
|
||||
path = smbd_tmp_path(mem_ctx, NULL);
|
||||
|
||||
dir = opendir(path);
|
||||
if (!dir) {
|
||||
talloc_free(mem_ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
for (de=readdir(dir);de;de=readdir(dir)) {
|
||||
char *fname = talloc_asprintf(mem_ctx, "%s/%s", path, de->d_name);
|
||||
int ret = unlink(fname);
|
||||
if (ret == -1 &&
|
||||
errno != ENOENT &&
|
||||
errno != EISDIR &&
|
||||
errno != EISDIR) {
|
||||
DEBUG(0,("Unabled to delete '%s' - %s\n",
|
||||
fname, strerror(errno)));
|
||||
smb_panic("unable to cleanup tmp files");
|
||||
}
|
||||
talloc_free(fname);
|
||||
}
|
||||
closedir(dir);
|
||||
|
||||
talloc_free(mem_ctx);
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
@ -1,165 +0,0 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
SERVER SERVICE code
|
||||
|
||||
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 _SERVER_SERVICE_H
|
||||
#define _SERVER_SERVICE_H
|
||||
|
||||
struct event_context;
|
||||
struct model_ops;
|
||||
struct server_context;
|
||||
|
||||
struct server_connection;
|
||||
struct server_service;
|
||||
|
||||
/* 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 SERVER_SERVICE_VERSION 1
|
||||
|
||||
struct server_service_ops {
|
||||
/* the name of the server_service */
|
||||
const char *name;
|
||||
|
||||
/* called at startup when the server_service is selected */
|
||||
void (*service_init)(struct server_service *service);
|
||||
};
|
||||
|
||||
struct server_stream_socket;
|
||||
|
||||
struct server_stream_ops {
|
||||
/* the name of the server_service */
|
||||
const char *name;
|
||||
|
||||
/* called at startup when the server_service is selected */
|
||||
void (*socket_init)(struct server_stream_socket *socket);
|
||||
|
||||
/* function to accept new connection */
|
||||
void (*accept_connection)(struct server_connection *);
|
||||
|
||||
void (*recv_handler)(struct server_connection *, struct timeval, uint16_t);
|
||||
|
||||
void (*send_handler)(struct server_connection *, struct timeval, uint16_t);
|
||||
|
||||
/* function to be called when the server is idle */
|
||||
void (*idle_handler)(struct server_connection *, struct timeval);
|
||||
|
||||
/* function to close a connection */
|
||||
void (*close_connection)(struct server_connection *, const char *reason);
|
||||
};
|
||||
|
||||
struct socket_context;
|
||||
|
||||
struct server_stream_socket {
|
||||
struct server_stream_socket *next,*prev;
|
||||
struct {
|
||||
const struct server_stream_ops *ops;
|
||||
void *private_data;
|
||||
} stream;
|
||||
|
||||
struct {
|
||||
struct event_context *ctx;
|
||||
struct fd_event *fde;
|
||||
} event;
|
||||
|
||||
struct socket_context *socket;
|
||||
|
||||
struct server_service *service;
|
||||
};
|
||||
|
||||
struct server_service {
|
||||
struct server_service *next,*prev;
|
||||
struct {
|
||||
const struct server_service_ops *ops;
|
||||
void *private_data;
|
||||
} service;
|
||||
|
||||
struct server_context *server;
|
||||
};
|
||||
|
||||
/* the concept of whether two operations are on the same server
|
||||
connection or different connections is an important one in SMB, especially
|
||||
for locking and share modes. We will use a servid_t to distinguish different
|
||||
connections
|
||||
|
||||
this means that (for example) a unique open file is distinguished by the triple
|
||||
of
|
||||
servid_t server;
|
||||
uint16 tid;
|
||||
uint16 fnum;
|
||||
*/
|
||||
typedef uint32_t servid_t;
|
||||
|
||||
struct server_connection {
|
||||
struct server_connection *next,*prev;
|
||||
struct {
|
||||
void *private_data;
|
||||
servid_t id;
|
||||
} connection;
|
||||
|
||||
struct {
|
||||
struct event_context *ctx;
|
||||
struct fd_event *fde;
|
||||
struct timed_event *idle;
|
||||
struct timeval idle_time;
|
||||
} event;
|
||||
|
||||
struct socket_context *socket;
|
||||
|
||||
struct server_stream_socket *stream_socket;
|
||||
|
||||
struct {
|
||||
struct messaging_context *ctx;
|
||||
} messaging;
|
||||
};
|
||||
|
||||
struct server_task;
|
||||
|
||||
struct server_task_ops {
|
||||
/* the name of the server_task */
|
||||
const char *name;
|
||||
|
||||
/* called at startup when the server_task is selected */
|
||||
void (*task_init)(struct server_task *task);
|
||||
};
|
||||
|
||||
struct server_task {
|
||||
struct server_task *next,*prev;
|
||||
struct {
|
||||
const struct server_task_ops *ops;
|
||||
void *private_data;
|
||||
servid_t id;
|
||||
} task;
|
||||
|
||||
struct {
|
||||
struct event_context *ctx;
|
||||
} event;
|
||||
|
||||
struct {
|
||||
struct messaging_context *ctx;
|
||||
} messaging;
|
||||
|
||||
struct server_service *service;
|
||||
};
|
||||
|
||||
#endif /* _SERVER_SERVICE_H */
|
@ -25,7 +25,7 @@
|
||||
enum {MY_PING=1000, MY_PONG, MY_EXIT};
|
||||
|
||||
static void ping_message(struct messaging_context *msg, void *private,
|
||||
uint32_t msg_type, servid_t src, DATA_BLOB *data)
|
||||
uint32_t msg_type, uint32_t src, DATA_BLOB *data)
|
||||
{
|
||||
NTSTATUS status;
|
||||
status = messaging_send(msg, src, MY_PONG, data);
|
||||
@ -35,14 +35,14 @@ static void ping_message(struct messaging_context *msg, void *private,
|
||||
}
|
||||
|
||||
static void pong_message(struct messaging_context *msg, void *private,
|
||||
uint32_t msg_type, servid_t src, DATA_BLOB *data)
|
||||
uint32_t msg_type, uint32_t src, DATA_BLOB *data)
|
||||
{
|
||||
int *count = private;
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
static void exit_message(struct messaging_context *msg, void *private,
|
||||
uint32_t msg_type, servid_t src, DATA_BLOB *data)
|
||||
uint32_t msg_type, uint32_t src, DATA_BLOB *data)
|
||||
{
|
||||
talloc_free(private);
|
||||
exit(0);
|
||||
|
Loading…
Reference in New Issue
Block a user