1
0
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:
Andrew Tridgell 2005-01-30 00:54:57 +00:00 committed by Gerald (Jerry) Carter
parent 5540449f1c
commit 55d4d36993
36 changed files with 673 additions and 1598 deletions

View File

@ -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;

View File

@ -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"

View File

@ -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;

View File

@ -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);
}

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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
*/

View File

@ -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);

View File

@ -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;
}

View File

@ -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));

View File

@ -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);
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -23,6 +23,7 @@
#include "system/filesys.h"
#include "dlinklist.h"
#include "smb_server/smb_server.h"
#include "smbd/service_stream.h"
/****************************************************************************

View File

@ -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 {

View File

@ -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 */

View File

@ -20,6 +20,7 @@
#include "includes.h"
#include "smb_server/smb_server.h"
#include "smbd/service_stream.h"

View File

@ -25,6 +25,7 @@
#include "version.h"
#include "auth/auth.h"
#include "smb_server/smb_server.h"
#include "smbd/service_stream.h"
/*

View File

@ -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);
}

View File

@ -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;

View File

@ -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 \

View File

@ -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)
};

View File

@ -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 */

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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
};
/*

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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 */

View File

@ -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;
}

View File

@ -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 */

View File

@ -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);