1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-17 02:05:21 +03:00
Jelmer Vernooij fc3c05e63f r2696: DCOM updates:
- Start working on OXIDResolver interface
 - Add torture test for SimplePing()
(This used to be commit b54d14a01a71082251ff926ab57974c6eb3c0a41)
2007-10-10 12:59:24 -05:00

216 lines
5.6 KiB
C

/*
Unix SMB/CIFS implementation.
server side dcerpc over tcp code
Copyright (C) Andrew Tridgell 2003
Copyright (C) Stefan (metze) Metzmacher 2004
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
struct dcesrv_socket_context {
const struct dcesrv_endpoint *endpoint;
struct dcesrv_context *dcesrv_ctx;
};
/*
write_fn callback for dcesrv_output()
*/
static ssize_t dcerpc_write_fn(void *private, DATA_BLOB *out)
{
NTSTATUS status;
struct socket_context *sock = private;
size_t sendlen;
status = socket_send(sock, sock, out, &sendlen, 0);
if (!NT_STATUS_IS_OK(status)) {
return -1;
}
return sendlen;
}
void dcesrv_terminate_connection(struct dcesrv_connection *dce_conn, const char *reason)
{
server_terminate_connection(dce_conn->srv_conn, reason);
}
/*
add a socket address to the list of events, one event per dcerpc endpoint
*/
static void add_socket_rpc(struct server_service *service,
const struct model_ops *model_ops,
struct dcesrv_context *dce_ctx,
struct in_addr *ifip)
{
struct dcesrv_endpoint *e;
char *ip_str = talloc_strdup(service, inet_ntoa(*ifip));
for (e=dce_ctx->endpoint_list;e;e=e->next) {
if (e->ep_description.type == ENDPOINT_TCP) {
struct server_socket *sock;
struct dcesrv_socket_context *dcesrv_sock;
sock = service_setup_socket(service,model_ops, ip_str, &e->ep_description.info.tcp_port);
if (!sock) {
DEBUG(0,("service_setup_socket(port=%u) failed\n",e->ep_description.info.tcp_port));
continue;
}
dcesrv_sock = talloc_p(sock, struct dcesrv_socket_context);
if (!dcesrv_sock) {
DEBUG(0,("talloc_p(sock->mem_ctx, struct dcesrv_socket_context) failed\n"));
continue;
}
/* remember the endpoint of this socket */
dcesrv_sock->endpoint = e;
dcesrv_sock->dcesrv_ctx = dce_ctx;
sock->private_data = dcesrv_sock;
}
}
talloc_free(ip_str);
}
/****************************************************************************
Open the listening sockets for RPC over TCP
****************************************************************************/
void dcesrv_tcp_init(struct server_service *service, const struct model_ops *model_ops, struct dcesrv_context *dce_ctx)
{
DEBUG(1,("dcesrv_tcp_init\n"));
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(service, model_ops, dce_ctx, ifip);
}
} else {
struct in_addr *ifip;
ifip = interpret_addr2(dce_ctx, lp_socket_address());
add_socket_rpc(service, model_ops, dce_ctx, ifip);
talloc_free(ifip);
}
return;
}
void dcesrv_tcp_accept(struct server_connection *conn)
{
NTSTATUS status;
struct dcesrv_socket_context *dcesrv_sock = conn->server_socket->private_data;
struct dcesrv_connection *dcesrv_conn = NULL;
DEBUG(5,("dcesrv_tcp_accept\n"));
status = dcesrv_endpoint_connect(dcesrv_sock->dcesrv_ctx, dcesrv_sock->endpoint, &dcesrv_conn);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("dcesrv_tcp_accept: dcesrv_endpoint_connect failed: %s\n",
nt_errstr(status)));
return;
}
dcesrv_conn->srv_conn = conn;
conn->private_data = dcesrv_conn;
return;
}
void dcesrv_tcp_recv(struct server_connection *conn, time_t t, uint16_t flags)
{
NTSTATUS status;
struct dcesrv_connection *dce_conn = conn->private_data;
DATA_BLOB tmp_blob;
DEBUG(10,("dcesrv_tcp_recv\n"));
status = socket_recv(conn->socket, conn->socket, &tmp_blob, 0x4000, 0);
if (!NT_STATUS_IS_OK(status)) {
if (NT_STATUS_IS_ERR(status)) {
dcesrv_terminate_connection(dce_conn, "eof on socket");
return;
}
return;
}
status = dcesrv_input(dce_conn, &tmp_blob);
talloc_free(tmp_blob.data);
if (!NT_STATUS_IS_OK(status)) {
dcesrv_terminate_connection(dce_conn, "eof on socket");
return;
}
if (dce_conn->call_list && dce_conn->call_list->replies) {
conn->event.fde->flags |= EVENT_FD_WRITE;
}
return;
}
void dcesrv_tcp_send(struct server_connection *conn, time_t t, uint16_t flags)
{
struct dcesrv_connection *dce_conn = conn->private_data;
NTSTATUS status;
DEBUG(10,("dcesrv_tcp_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");
return;
}
if (!dce_conn->call_list || !dce_conn->call_list->replies) {
conn->event.fde->flags &= ~EVENT_FD_WRITE;
}
return;
}
void dcesrv_tcp_idle(struct server_connection *conn, time_t t)
{
DEBUG(10,("dcesrv_tcp_idle\n"));
conn->event.idle->next_event = t + 5;
return;
}
void dcesrv_tcp_close(struct server_connection *conn, const char *reason)
{
struct dcesrv_connection *dce_conn = conn->private_data;
DEBUG(5,("dcesrv_tcp_close: %s\n",reason));
talloc_free(dce_conn);
return;
}
void dcesrv_tcp_exit(struct server_service *service, const char *reason)
{
DEBUG(1,("dcesrv_tcp_exit: %s\n",reason));
return;
}