summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/Makefile.in1
-rw-r--r--source4/include/context.h3
-rw-r--r--source4/librpc/idl/epmapper.idl1
-rw-r--r--source4/ntvfs/ipc/vfs_ipc.c2
-rw-r--r--source4/rpc_server/dcerpc_server.c70
-rw-r--r--source4/rpc_server/dcerpc_server.h4
-rw-r--r--source4/rpc_server/dcerpc_tcp.c256
-rw-r--r--source4/rpc_server/echo/rpc_echo.c4
-rw-r--r--source4/rpc_server/epmapper/rpc_epmapper.c53
-rw-r--r--source4/smbd/process.c11
-rw-r--r--source4/smbd/process_single.c24
-rw-r--r--source4/smbd/process_standard.c41
-rw-r--r--source4/smbd/process_thread.c44
-rw-r--r--source4/smbd/rewrite.c3
-rw-r--r--source4/smbd/server.c70
15 files changed, 496 insertions, 91 deletions
diff --git a/source4/Makefile.in b/source4/Makefile.in
index f675aa4b29..dca9c8b7bd 100644
--- a/source4/Makefile.in
+++ b/source4/Makefile.in
@@ -285,6 +285,7 @@ SMBD_NTVFS_OBJ = ntvfs/ntvfs_base.o ntvfs/ntvfs_util.o \
ntvfs/ntvfs_generic.o @NTVFS_STATIC@
SMBD_RPC_OBJ = rpc_server/dcerpc_server.o \
+ rpc_server/dcerpc_tcp.o \
rpc_server/handles.o \
rpc_server/echo/rpc_echo.o \
rpc_server/epmapper/rpc_epmapper.o
diff --git a/source4/include/context.h b/source4/include/context.h
index f9a9bdc554..9ec5d2d8dd 100644
--- a/source4/include/context.h
+++ b/source4/include/context.h
@@ -335,6 +335,9 @@ struct model_ops {
/* function to accept new connection */
void (*accept_connection)(struct event_context *, struct fd_event *, time_t, uint16);
+
+ /* function to accept new rpc over tcp connection */
+ void (*accept_rpc_connection)(struct event_context *, struct fd_event *, time_t, uint16);
/* function to terminate a connection */
void (*terminate_connection)(struct server_context *smb, const char *reason);
diff --git a/source4/librpc/idl/epmapper.idl b/source4/librpc/idl/epmapper.idl
index 79fb7f3dd1..fff05b9bc3 100644
--- a/source4/librpc/idl/epmapper.idl
+++ b/source4/librpc/idl/epmapper.idl
@@ -7,6 +7,7 @@
[
uuid(e1af8308-5d1f-11c9-91a4-08002b14a0fa),
version(3.0),
+ endpoints(epmapper, TCP-135),
pointer_default(unique)
]
interface epmapper
diff --git a/source4/ntvfs/ipc/vfs_ipc.c b/source4/ntvfs/ipc/vfs_ipc.c
index 04825ec632..a3b3ab19b7 100644
--- a/source4/ntvfs/ipc/vfs_ipc.c
+++ b/source4/ntvfs/ipc/vfs_ipc.c
@@ -240,7 +240,7 @@ static NTSTATUS ipc_open(struct request_context *req, union smb_open *oi)
endpoint.type = ENDPOINT_SMB;
endpoint.info.smb_pipe = p->pipe_name;
- status = dcesrv_endpoint_connect(req->smb, &endpoint, &p->pipe_state);
+ status = dcesrv_endpoint_connect(&req->smb->dcesrv, &endpoint, &p->pipe_state);
if (!NT_STATUS_IS_OK(status)) {
talloc_destroy(mem_ctx);
return status;
diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c
index 67b36cdc48..81c9d4cb8f 100644
--- a/source4/rpc_server/dcerpc_server.c
+++ b/source4/rpc_server/dcerpc_server.c
@@ -25,11 +25,11 @@
/*
find the set of endpoint operations for an endpoint server
*/
-static const struct dcesrv_endpoint_ops *find_endpoint(struct server_context *smb,
+static const struct dcesrv_endpoint_ops *find_endpoint(struct dcesrv_context *dce,
const struct dcesrv_endpoint *endpoint)
{
struct dce_endpoint *ep;
- for (ep=smb->dcesrv.endpoint_list; ep; ep=ep->next) {
+ for (ep=dce->endpoint_list; ep; ep=ep->next) {
if (ep->endpoint_ops->query_endpoint(endpoint)) {
return ep->endpoint_ops;
}
@@ -54,7 +54,7 @@ static struct dcesrv_call_state *dcesrv_find_call(struct dcesrv_state *dce, uint
/*
register an endpoint server
*/
-BOOL dcesrv_endpoint_register(struct server_context *smb,
+BOOL dcesrv_endpoint_register(struct dcesrv_context *dce,
const struct dcesrv_endpoint_ops *ops)
{
struct dce_endpoint *ep;
@@ -63,26 +63,20 @@ BOOL dcesrv_endpoint_register(struct server_context *smb,
return False;
}
ep->endpoint_ops = ops;
- DLIST_ADD(smb->dcesrv.endpoint_list, ep);
+ DLIST_ADD(dce->endpoint_list, ep);
return True;
}
/*
connect to a dcerpc endpoint
*/
-NTSTATUS dcesrv_endpoint_connect(struct server_context *smb,
- const struct dcesrv_endpoint *endpoint,
- struct dcesrv_state **p)
+NTSTATUS dcesrv_endpoint_connect_ops(struct dcesrv_context *dce,
+ const struct dcesrv_endpoint *endpoint,
+ const struct dcesrv_endpoint_ops *ops,
+ struct dcesrv_state **p)
{
TALLOC_CTX *mem_ctx;
NTSTATUS status;
- const struct dcesrv_endpoint_ops *ops;
-
- /* make sure this endpoint exists */
- ops = find_endpoint(smb, endpoint);
- if (!ops) {
- return NT_STATUS_OBJECT_NAME_NOT_FOUND;
- }
mem_ctx = talloc_init("dcesrv_endpoint_connect");
if (!mem_ctx) {
@@ -95,7 +89,7 @@ NTSTATUS dcesrv_endpoint_connect(struct server_context *smb,
return NT_STATUS_NO_MEMORY;
}
- (*p)->smb = smb;
+ (*p)->dce = dce;
(*p)->mem_ctx = mem_ctx;
(*p)->endpoint = *endpoint;
(*p)->ops = ops;
@@ -117,6 +111,24 @@ NTSTATUS dcesrv_endpoint_connect(struct server_context *smb,
return NT_STATUS_OK;
}
+/*
+ connect to a dcerpc endpoint
+*/
+NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce,
+ const struct dcesrv_endpoint *endpoint,
+ struct dcesrv_state **p)
+{
+ const struct dcesrv_endpoint_ops *ops;
+
+ /* make sure this endpoint exists */
+ ops = find_endpoint(dce, endpoint);
+ if (!ops) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ return dcesrv_endpoint_connect_ops(dce, endpoint, ops, p);
+}
+
/*
disconnect a link to an endpoint
@@ -646,27 +658,35 @@ int dcesrv_lookup_endpoints(const struct dcerpc_interface_table *table,
TALLOC_CTX *mem_ctx,
struct dcesrv_ep_iface **e)
{
- *e = talloc_p(mem_ctx, struct dcesrv_ep_iface);
+ int i;
+ *e = talloc_array_p(mem_ctx, struct dcesrv_ep_iface, table->endpoints->count);
if (! *e) {
return -1;
}
- (*e)->name = table->name;
- (*e)->uuid = table->uuid;
- (*e)->if_version = table->if_version;
- (*e)->endpoint.type = ENDPOINT_SMB;
- (*e)->endpoint.info.smb_pipe = table->endpoints->names[0];
+ for (i=0;i<table->endpoints->count;i++) {
+ (*e)[i].name = table->name;
+ (*e)[i].uuid = table->uuid;
+ (*e)[i].if_version = table->if_version;
+ if (strncmp(table->endpoints->names[i], "TCP-", 4) == 0) {
+ (*e)[i].endpoint.type = ENDPOINT_TCP;
+ (*e)[i].endpoint.info.tcp_port = atoi(table->endpoints->names[i]+4);
+ } else {
+ (*e)[i].endpoint.type = ENDPOINT_SMB;
+ (*e)[i].endpoint.info.smb_pipe = table->endpoints->names[i];
+ }
+ }
- return 1;
+ return i;
}
/*
initialise the dcerpc server subsystem
*/
-BOOL dcesrv_init(struct server_context *smb)
+BOOL dcesrv_init(struct dcesrv_context *dce)
{
- rpc_echo_init(smb);
- rpc_epmapper_init(smb);
+ rpc_echo_init(dce);
+ rpc_epmapper_init(dce);
return True;
}
diff --git a/source4/rpc_server/dcerpc_server.h b/source4/rpc_server/dcerpc_server.h
index 83e0ee249a..38340bcf16 100644
--- a/source4/rpc_server/dcerpc_server.h
+++ b/source4/rpc_server/dcerpc_server.h
@@ -71,7 +71,7 @@ struct dcesrv_handle {
/* the state associated with a dcerpc server connection */
struct dcesrv_state {
/* the top level context for this server */
- struct server_context *smb;
+ struct dcesrv_context *dce;
TALLOC_CTX *mem_ctx;
@@ -120,7 +120,7 @@ struct dcesrv_endpoint_ops {
void (*disconnect)(struct dcesrv_state *);
/* this function is used to ask an endpoint server for a list
- of endpoints it wants to handle */
+ of endpoints/interfaces it wants to handle */
int (*lookup_endpoints)(TALLOC_CTX *mem_ctx, struct dcesrv_ep_iface **);
};
diff --git a/source4/rpc_server/dcerpc_tcp.c b/source4/rpc_server/dcerpc_tcp.c
new file mode 100644
index 0000000000..110789dba6
--- /dev/null
+++ b/source4/rpc_server/dcerpc_tcp.c
@@ -0,0 +1,256 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ server side dcerpc over tcp code
+
+ Copyright (C) Andrew Tridgell 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+struct rpc_listen {
+ struct dce_endpoint *e;
+ struct model_ops *model_ops;
+};
+
+
+/*
+ called when a RPC socket becomes writable
+*/
+static void dcerpc_write_handler(struct event_context *ev, struct fd_event *fde,
+ time_t t, uint16 flags)
+{
+ struct dcesrv_state *dce = fde->private;
+ DATA_BLOB blob;
+ NTSTATUS status;
+
+ blob = data_blob(NULL, 0x4000);
+ if (!blob.data) {
+ smb_panic("out of memory in rpc write handler");
+ }
+
+ status = dcesrv_output(dce, &blob);
+ if (!NT_STATUS_IS_OK(status)) {
+ fde->flags &= ~EVENT_FD_WRITE;
+ } else {
+ write_data(fde->fd, blob.data, blob.length);
+ }
+
+ data_blob_free(&blob);
+}
+
+/*
+ called when a RPC socket becomes readable
+*/
+static void dcerpc_read_handler(struct event_context *ev, struct fd_event *fde,
+ time_t t, uint16 flags)
+{
+ struct dcesrv_state *dce = fde->private;
+ DATA_BLOB blob;
+ ssize_t ret;
+
+ blob = data_blob(NULL, 0x4000);
+ if (!blob.data) {
+ smb_panic("out of memory in rpc read handler");
+ }
+
+ ret = read(fde->fd, blob.data, blob.length);
+ if (ret == 0) {
+ smb_panic("need a shutdown routine");
+ }
+ if (ret == -1 && errno != EINTR) {
+ smb_panic("need a shutdown routine");
+ }
+ if (ret == -1) {
+ return;
+ }
+
+ dcesrv_input(dce, &blob);
+
+ data_blob_free(&blob);
+
+ fde->flags |= EVENT_FD_WRITE;
+}
+
+
+
+
+/*
+ called when a RPC socket becomes readable
+*/
+static void dcerpc_io_handler(struct event_context *ev, struct fd_event *fde,
+ time_t t, uint16 flags)
+{
+ if (flags & EVENT_FD_WRITE) {
+ dcerpc_write_handler(ev, fde, t, flags);
+ }
+
+ if (flags & EVENT_FD_READ) {
+ dcerpc_read_handler(ev, fde, t, flags);
+ }
+}
+
+/*
+ initialise a server_context from a open socket and register a event handler
+ for reading from that socket
+*/
+void init_rpc_session(struct event_context *ev, void *private, int fd)
+{
+ struct dcesrv_context context;
+ struct dcesrv_state *dce;
+ struct fd_event fde;
+ struct rpc_listen *r = private;
+ struct dcesrv_endpoint endpoint;
+
+ set_socket_options(fd,"SO_KEEPALIVE");
+ set_socket_options(fd, lp_socket_options());
+
+ context.endpoint_list = NULL;
+ dcesrv_init(&context);
+
+ endpoint.type = ENDPOINT_TCP;
+ endpoint.info.tcp_port = 0;
+
+ dcesrv_endpoint_connect_ops(&context, &endpoint, r->e->endpoint_ops, &dce);
+
+ dce->dce = talloc_p(dce->mem_ctx, struct dcesrv_context);
+ *dce->dce = context;
+
+ set_blocking(fd, False);
+
+ /* setup a event handler for this socket. We are initially
+ only interested in reading from the socket */
+ fde.fd = fd;
+ fde.handler = dcerpc_io_handler;
+ fde.private = dce;
+ fde.flags = EVENT_FD_READ;
+
+ event_add_fd(ev, &fde);
+}
+
+
+/*
+ setup a single rpc listener
+ */
+static void setup_listen_rpc(struct event_context *events,
+ struct model_ops *model_ops,
+ struct in_addr *ifip, unsigned port,
+ struct dce_endpoint *e)
+{
+ struct fd_event fde;
+ struct rpc_listen *r;
+
+ fde.fd = open_socket_in(SOCK_STREAM, port, 0, ifip->s_addr, True);
+ if (fde.fd == -1) {
+ DEBUG(0,("Failed to open socket on %s:%u - %s\n",
+ inet_ntoa(*ifip), port, strerror(errno)));
+ return;
+ }
+
+ /* ready to listen */
+ set_socket_options(fde.fd, "SO_KEEPALIVE");
+ set_socket_options(fde.fd, lp_socket_options());
+
+ if (listen(fde.fd, SMBD_LISTEN_BACKLOG) == -1) {
+ DEBUG(0,("Failed to listen on %s:%d - %s\n",
+ inet_ntoa(*ifip), port, strerror(errno)));
+ close(fde.fd);
+ return;
+ }
+
+ r = malloc(sizeof(*r));
+ if (!r) {
+ return;
+ }
+
+ r->e = e;
+ r->model_ops = model_ops;
+
+ /* we are only interested in read events on the listen socket */
+ fde.flags = EVENT_FD_READ;
+ fde.private = r;
+ fde.handler = model_ops->accept_rpc_connection;
+
+ event_add_fd(events, &fde);
+}
+
+/*
+ add a socket address to the list of events, one event per dcerpc endpoint
+*/
+static void add_socket_rpc(struct event_context *events,
+ struct model_ops *model_ops,
+ struct in_addr *ifip)
+{
+ struct dcesrv_context dce;
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_init("add_socket_rpc");
+ if (!mem_ctx) {
+ smb_panic("out of memory in add_socket_rpc");
+ }
+
+ dce.endpoint_list = NULL;
+
+ dcesrv_init(&dce);
+
+ while (dce.endpoint_list) {
+ struct dce_endpoint *e = dce.endpoint_list;
+ struct dcesrv_ep_iface *ifaces;
+ int count, i;
+
+ count = e->endpoint_ops->lookup_endpoints(mem_ctx, &ifaces);
+ for (i=0;i<count;i++) {
+ if (ifaces[i].endpoint.type == ENDPOINT_TCP) {
+ setup_listen_rpc(events, model_ops, ifip,
+ ifaces[i].endpoint.info.tcp_port,
+ e);
+ break;
+ }
+ }
+
+ DLIST_REMOVE(dce.endpoint_list, e);
+ }
+
+ talloc_destroy(mem_ctx);
+}
+
+/****************************************************************************
+ Open the listening sockets for RPC over TCP
+****************************************************************************/
+void open_sockets_rpc(struct event_context *events,
+ struct model_ops *model_ops)
+{
+ if (lp_interfaces() && lp_bind_interfaces_only()) {
+ int num_interfaces = iface_count();
+ int i;
+ for(i = 0; i < num_interfaces; i++) {
+ struct in_addr *ifip = iface_n_ip(i);
+ if (ifip == NULL) {
+ continue;
+ }
+ add_socket_rpc(events, model_ops, ifip);
+ }
+ } else {
+ TALLOC_CTX *mem_ctx = talloc_init("open_sockets_smbd");
+ struct in_addr *ifip = interpret_addr2(mem_ctx, lp_socket_address());
+ if (!mem_ctx) {
+ smb_panic("No memory");
+ }
+ add_socket_rpc(events, model_ops, ifip);
+ talloc_destroy(mem_ctx);
+ }
+}
diff --git a/source4/rpc_server/echo/rpc_echo.c b/source4/rpc_server/echo/rpc_echo.c
index f741e63d62..0f3c504c37 100644
--- a/source4/rpc_server/echo/rpc_echo.c
+++ b/source4/rpc_server/echo/rpc_echo.c
@@ -179,9 +179,9 @@ static const struct dcesrv_endpoint_ops rpc_echo_ops = {
/*
register with the dcerpc server
*/
-void rpc_echo_init(struct server_context *smb)
+void rpc_echo_init(struct dcesrv_context *dce)
{
- if (!dcesrv_endpoint_register(smb, &rpc_echo_ops)) {
+ if (!dcesrv_endpoint_register(dce, &rpc_echo_ops)) {
DEBUG(1,("Failed to register rpcecho endpoint\n"));
}
}
diff --git a/source4/rpc_server/epmapper/rpc_epmapper.c b/source4/rpc_server/epmapper/rpc_epmapper.c
index 2898a70159..32a239f44d 100644
--- a/source4/rpc_server/epmapper/rpc_epmapper.c
+++ b/source4/rpc_server/epmapper/rpc_epmapper.c
@@ -66,20 +66,37 @@ static BOOL fill_protocol_tower(TALLOC_CTX *mem_ctx, struct epm_towers *twr,
twr->floors[2].lhs.protocol = EPM_PROTOCOL_RPC_C;
twr->floors[2].lhs.info.lhs_data = data_blob(NULL, 0);
twr->floors[2].rhs.rhs_data = data_blob_talloc_zero(mem_ctx, 2);
-
- /* on a SMB pipe ... */
- twr->floors[3].lhs.protocol = EPM_PROTOCOL_SMB;
- twr->floors[3].lhs.info.lhs_data = data_blob(NULL, 0);
- twr->floors[3].rhs.rhs_data.data = talloc_asprintf(mem_ctx, "\\PIPE\\%s",
- e->endpoint.info.smb_pipe);
- twr->floors[3].rhs.rhs_data.length = strlen(twr->floors[3].rhs.rhs_data.data)+1;
-
- /* on an NetBIOS link ... */
- twr->floors[4].lhs.protocol = EPM_PROTOCOL_NETBIOS;
- twr->floors[4].lhs.info.lhs_data = data_blob(NULL, 0);
- twr->floors[4].rhs.rhs_data.data = talloc_asprintf(mem_ctx, "\\\\%s",
- lp_netbios_name());
- twr->floors[4].rhs.rhs_data.length = strlen(twr->floors[4].rhs.rhs_data.data)+1;
+
+ switch (e->endpoint.type) {
+ case ENDPOINT_SMB:
+ /* on a SMB pipe ... */
+ twr->floors[3].lhs.protocol = EPM_PROTOCOL_SMB;
+ twr->floors[3].lhs.info.lhs_data = data_blob(NULL, 0);
+ twr->floors[3].rhs.rhs_data.data = talloc_asprintf(mem_ctx, "\\PIPE\\%s",
+ e->endpoint.info.smb_pipe);
+ twr->floors[3].rhs.rhs_data.length = strlen(twr->floors[3].rhs.rhs_data.data)+1;
+
+ /* on an NetBIOS link ... */
+ twr->floors[4].lhs.protocol = EPM_PROTOCOL_NETBIOS;
+ twr->floors[4].lhs.info.lhs_data = data_blob(NULL, 0);
+ twr->floors[4].rhs.rhs_data.data = talloc_asprintf(mem_ctx, "\\\\%s",
+ lp_netbios_name());
+ twr->floors[4].rhs.rhs_data.length = strlen(twr->floors[4].rhs.rhs_data.data)+1;
+ break;
+
+ case ENDPOINT_TCP:
+ /* on a TCP connection ... */
+ twr->floors[3].lhs.protocol = EPM_PROTOCOL_TCP;
+ twr->floors[3].lhs.info.lhs_data = data_blob(NULL, 0);
+ twr->floors[3].rhs.rhs_data = data_blob_talloc(mem_ctx, NULL, 2);
+ RSSVAL(twr->floors[3].rhs.rhs_data.data, 0, e->endpoint.info.tcp_port);
+
+ /* on an IP link ... */
+ twr->floors[4].lhs.protocol = EPM_PROTOCOL_IP;
+ twr->floors[4].lhs.info.lhs_data = data_blob(NULL, 0);
+ twr->floors[4].rhs.rhs_data = data_blob_talloc_zero(mem_ctx, 4);
+ break;
+ }
return True;
}
@@ -160,7 +177,7 @@ static NTSTATUS epm_Lookup(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx,
}
h->data = eps;
- eps->count = build_ep_list(h->mem_ctx, dce->smb->dcesrv.endpoint_list, &eps->e);
+ eps->count = build_ep_list(h->mem_ctx, dce->dce->endpoint_list, &eps->e);
}
/* return the next N elements */
@@ -218,7 +235,7 @@ static NTSTATUS epm_Map(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx,
struct dcesrv_ep_iface *eps;
struct epm_floor *floors;
- count = build_ep_list(mem_ctx, dce->smb->dcesrv.endpoint_list, &eps);
+ count = build_ep_list(mem_ctx, dce->dce->endpoint_list, &eps);
ZERO_STRUCTP(r->out.entry_handle);
r->out.num_towers = 1;
@@ -368,9 +385,9 @@ static const struct dcesrv_endpoint_ops rpc_epmapper_ops = {
/*
register with the dcerpc server
*/
-void rpc_epmapper_init(struct server_context *smb)
+void rpc_epmapper_init(struct dcesrv_context *dce)
{
- if (!dcesrv_endpoint_register(smb, &rpc_epmapper_ops)) {
+ if (!dcesrv_endpoint_register(dce, &rpc_epmapper_ops)) {
DEBUG(1,("Failed to register epmapper endpoint\n"));
}
}
diff --git a/source4/smbd/process.c b/source4/smbd/process.c
index db145d0a26..b5138ac971 100644
--- a/source4/smbd/process.c
+++ b/source4/smbd/process.c
@@ -670,8 +670,8 @@ void server_terminate(struct server_context *smb)
/*
called when a SMB socket becomes readable
*/
-static void smbd_read_handler(struct event_context *ev, struct fd_event *fde,
- time_t t, uint16 flags)
+void smbd_read_handler(struct event_context *ev, struct fd_event *fde,
+ time_t t, uint16 flags)
{
struct request_context *req;
struct server_context *smb = fde->private;
@@ -713,7 +713,8 @@ void smbd_process_async(struct server_context *smb)
initialise a server_context from a open socket and register a event handler
for reading from that socket
*/
-void init_smbsession(struct event_context *ev, struct model_ops *model_ops, int fd)
+void init_smbsession(struct event_context *ev, struct model_ops *model_ops, int fd,
+ void (*read_handler)(struct event_context *, struct fd_event *, time_t, uint16))
{
struct server_context *smb;
TALLOC_CTX *mem_ctx;
@@ -757,14 +758,14 @@ void init_smbsession(struct event_context *ev, struct model_ops *model_ops, int
/* setup a event handler for this socket. We are initially
only interested in reading from the socket */
fde.fd = fd;
- fde.handler = smbd_read_handler;
+ fde.handler = read_handler;
fde.private = smb;
fde.flags = EVENT_FD_READ;
event_add_fd(ev, &fde);
/* setup the DCERPC server subsystem */
- dcesrv_init(smb);
+ dcesrv_init(&smb->dcesrv);
}
diff --git a/source4/smbd/process_single.c b/source4/smbd/process_single.c
index e6bb9b6c9c..a19577b3cf 100644
--- a/source4/smbd/process_single.c
+++ b/source4/smbd/process_single.c
@@ -49,11 +49,32 @@ static void accept_connection(struct event_context *ev, struct fd_event *fde, ti
/* create a smb server context and add it to out event
handling */
- init_smbsession(ev, model_ops, accepted_fd);
+ init_smbsession(ev, model_ops, accepted_fd, smbd_read_handler);
/* return to event handling */
}
+
+/*
+ called when a rpc listening socket becomes readable
+*/
+static void accept_rpc_connection(struct event_context *ev, struct fd_event *fde, time_t t, uint16 flags)
+{
+ int accepted_fd;
+ struct sockaddr addr;
+ socklen_t in_addrlen = sizeof(addr);
+
+ /* accept an incoming connection. */
+ accepted_fd = accept(fde->fd,&addr,&in_addrlen);
+ if (accepted_fd == -1) {
+ DEBUG(0,("accept_connection_single: accept: %s\n",
+ strerror(errno)));
+ return;
+ }
+
+ init_rpc_session(ev, fde->private, accepted_fd);
+}
+
/* called when a SMB connection goes down */
static void terminate_connection(struct server_context *server, const char *reason)
{
@@ -77,6 +98,7 @@ void process_model_single_init(void)
/* fill in all the operations */
ops.model_startup = model_startup;
ops.accept_connection = accept_connection;
+ ops.accept_rpc_connection = accept_rpc_connection;
ops.terminate_connection = terminate_connection;
ops.exit_server = NULL;
ops.get_id = get_id;
diff --git a/source4/smbd/process_standard.c b/source4/smbd/process_standard.c
index f12784bc79..507c179a26 100644
--- a/source4/smbd/process_standard.c
+++ b/source4/smbd/process_standard.c
@@ -59,7 +59,8 @@ static void accept_connection(struct event_context *ev, struct fd_event *fde, ti
/* Child code ... */
/* close all the listening sockets */
- event_remove_fd_all_handler(ev, accept_connection);
+ event_remove_fd_all_handler(ev, model_ops->accept_connection);
+ event_remove_fd_all_handler(ev, model_ops->accept_rpc_connection);
/* tdb needs special fork handling */
if (tdb_reopen_all() == -1) {
@@ -72,11 +73,46 @@ static void accept_connection(struct event_context *ev, struct fd_event *fde, ti
/* initialize new process */
smbd_process_init();
- init_smbsession(ev, model_ops, accepted_fd);
+ init_smbsession(ev, model_ops, accepted_fd, smbd_read_handler);
/* return to the event loop */
}
+/*
+ called when a rpc listening socket becomes readable
+*/
+static void accept_rpc_connection(struct event_context *ev, struct fd_event *fde, time_t t, uint16 flags)
+{
+ int accepted_fd;
+ struct sockaddr addr;
+ socklen_t in_addrlen = sizeof(addr);
+ pid_t pid;
+
+ accepted_fd = accept(fde->fd,&addr,&in_addrlen);
+ if (accepted_fd == -1) {
+ DEBUG(0,("accept_connection_standard: accept: %s\n",
+ strerror(errno)));
+ return;
+ }
+
+ pid = fork();
+
+ if (pid != 0) {
+ /* parent or error code ... */
+ close(accepted_fd);
+ /* go back to the event loop */
+ return;
+ }
+
+ /* Child code ... */
+
+ /* close all the listening sockets */
+ event_remove_fd_all_handler(ev, accept_connection);
+ event_remove_fd_all_handler(ev, accept_rpc_connection);
+
+ init_rpc_session(ev, fde->private, accepted_fd);
+}
+
/* called when a SMB connection goes down */
static void terminate_connection(struct server_context *server, const char *reason)
{
@@ -102,6 +138,7 @@ void process_model_standard_init(void)
/* fill in all the operations */
ops.model_startup = model_startup;
ops.accept_connection = accept_connection;
+ ops.accept_rpc_connection = accept_rpc_connection;
ops.terminate_connection = terminate_connection;
ops.get_id = get_id;
diff --git a/source4/smbd/process_thread.c b/source4/smbd/process_thread.c
index 9c312e0d1f..634e826395 100644
--- a/source4/smbd/process_thread.c
+++ b/source4/smbd/process_thread.c
@@ -45,7 +45,8 @@ static int get_id(struct request_context *req)
/*
called when a listening socket becomes readable
*/
-static void accept_connection(struct event_context *ev, struct fd_event *fde, time_t t, uint16 flags)
+static void accept_connection(struct event_context *ev, struct fd_event *fde,
+ time_t t, uint16 flags)
{
int accepted_fd, rc;
struct sockaddr addr;
@@ -71,7 +72,45 @@ static void accept_connection(struct event_context *ev, struct fd_event *fde, ti
*/
ev = event_context_init();
MUTEX_LOCK_BY_ID(MUTEX_SMBD);
- init_smbsession(ev, model_ops, accepted_fd);
+ init_smbsession(ev, model_ops, accepted_fd, smbd_read_handler);
+ MUTEX_UNLOCK_BY_ID(MUTEX_SMBD);
+
+ pthread_attr_init(&thread_attr);
+ pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
+ rc = pthread_create(&thread_id, &thread_attr, &connection_thread, ev);
+ 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, accepted_fd));
+ } else {
+ DEBUG(0,("accept_connection_thread: thread create failed for fd=%d, rc=%d\n", accepted_fd, rc));
+ }
+}
+
+
+/*
+ called when a rpc listening socket becomes readable
+*/
+static void accept_rpc_connection(struct event_context *ev, struct fd_event *fde, time_t t, uint16 flags)
+{
+ int accepted_fd, rc;
+ struct sockaddr addr;
+ socklen_t in_addrlen = sizeof(addr);
+ pthread_t thread_id;
+ pthread_attr_t thread_attr;
+
+ /* accept an incoming connection */
+ accepted_fd = accept(fde->fd,&addr,&in_addrlen);
+
+ if (accepted_fd == -1) {
+ DEBUG(0,("accept_connection_thread: accept: %s\n",
+ strerror(errno)));
+ return;
+ }
+
+ ev = event_context_init();
+ MUTEX_LOCK_BY_ID(MUTEX_SMBD);
+ init_rpcsession(ev, fde->private, accepted_fd);
MUTEX_UNLOCK_BY_ID(MUTEX_SMBD);
pthread_attr_init(&thread_attr);
@@ -416,6 +455,7 @@ void process_model_thread_init(void)
/* fill in all the operations */
ops.model_startup = model_startup;
ops.accept_connection = accept_connection;
+ ops.accept_rpc_connection = accept_rpc_connection;
ops.terminate_connection = terminate_connection;
ops.exit_server = NULL;
ops.get_id = get_id;
diff --git a/source4/smbd/rewrite.c b/source4/smbd/rewrite.c
index 18ff62e9dc..5e30db1192 100644
--- a/source4/smbd/rewrite.c
+++ b/source4/smbd/rewrite.c
@@ -25,9 +25,6 @@ void load_printers(void)
void file_init(void)
{}
-void init_rpc_pipe_hnd(void)
-{}
-
BOOL init_oplocks(void)
{ return True; }
diff --git a/source4/smbd/server.c b/source4/smbd/server.c
index 65ead2f4ce..35e50602fa 100644
--- a/source4/smbd/server.c
+++ b/source4/smbd/server.c
@@ -34,48 +34,56 @@ void exit_server(struct server_context *smb, const char *reason)
/*
+ setup a single listener of any type
+ */
+static void setup_listen(struct event_context *events,
+ struct model_ops *model_ops,
+ void (*accept_handler)(struct event_context *,struct fd_event *,time_t,uint16),
+ struct in_addr *ifip, unsigned port)
+{
+ struct fd_event fde;
+ fde.fd = open_socket_in(SOCK_STREAM, port, 0, ifip->s_addr, True);
+ if (fde.fd == -1) {
+ DEBUG(0,("Failed to open socket on %s:%u - %s\n",
+ inet_ntoa(*ifip), port, strerror(errno)));
+ return;
+ }
+
+ /* ready to listen */
+ set_socket_options(fde.fd, "SO_KEEPALIVE");
+ set_socket_options(fde.fd, lp_socket_options());
+
+ if (listen(fde.fd, SMBD_LISTEN_BACKLOG) == -1) {
+ DEBUG(0,("Failed to listen on %s:%d - %s\n",
+ inet_ntoa(*ifip), port, strerror(errno)));
+ close(fde.fd);
+ return;
+ }
+
+ /* we are only interested in read events on the listen socket */
+ fde.flags = EVENT_FD_READ;
+ fde.private = model_ops;
+ fde.handler = accept_handler;
+
+ event_add_fd(events, &fde);
+}
+
+/*
add a socket address to the list of events, one event per port
*/
static void add_socket(struct event_context *events,
struct model_ops *model_ops,
struct in_addr *ifip)
{
- char *ports = lp_smb_ports();
char *ptr, *tok;
const char *delim = ", ";
- for (tok=strtok_r(ports, delim, &ptr);
+ for (tok=strtok_r(lp_smb_ports(), delim, &ptr);
tok;
tok=strtok_r(NULL, delim, &ptr)) {
unsigned port = atoi(tok);
- struct fd_event fde;
-
if (port == 0) continue;
-
- fde.fd = open_socket_in(SOCK_STREAM, port, 0, ifip->s_addr, True);
- if (fde.fd == -1) {
- DEBUG(0,("Failed to open socket on %s:%u - %s\n",
- inet_ntoa(*ifip), port, strerror(errno)));
- continue;
- }
-
- /* ready to listen */
- set_socket_options(fde.fd, "SO_KEEPALIVE");
- set_socket_options(fde.fd, lp_socket_options());
-
- if (listen(fde.fd, SMBD_LISTEN_BACKLOG) == -1) {
- DEBUG(0,("Failed to listen on %s:%d - %s\n",
- inet_ntoa(*ifip), port, strerror(errno)));
- close(fde.fd);
- continue;
- }
-
- /* we are only interested in read events on the listen socket */
- fde.flags = EVENT_FD_READ;
- fde.private = model_ops;
- fde.handler = model_ops->accept_connection;
-
- event_add_fd(events, &fde);
+ setup_listen(events, model_ops, model_ops->accept_connection, ifip, port);
}
}
@@ -170,7 +178,6 @@ static BOOL init_structs(void)
{
init_names();
file_init();
- init_rpc_pipe_hnd();
secrets_init();
/* we want to re-seed early to prevent time delays causing
@@ -202,6 +209,9 @@ static void setup_process_model(struct event_context *events,
/* now setup the listening sockets, adding
event handlers to the events structure */
open_sockets_smbd(events, ops);
+
+ /* setup any sockets we need to listen on for RPC over TCP */
+ open_sockets_rpc(events, ops);
}
/****************************************************************************