From 7befc0648e4366980b7efdf31cc946ea11de5101 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 24 Nov 2003 12:40:47 +0000 Subject: initial implementation of dcerpc over tcp. RPC-EPMAPPER works, now to add epm_Map calls and support the rest of the pipes (This used to be commit 39add481582609ddb9d0b3bae45fde3226ece481) --- source4/Makefile.in | 3 +- source4/librpc/rpc/dcerpc.c | 2 +- source4/librpc/rpc/dcerpc_smb.c | 7 +- source4/librpc/rpc/dcerpc_tcp.c | 201 ++++++++++++++++++++++++++++++++++++++++ source4/torture/rpc/epmapper.c | 8 +- source4/torture/torture.c | 24 +++++ 6 files changed, 236 insertions(+), 9 deletions(-) create mode 100644 source4/librpc/rpc/dcerpc_tcp.c (limited to 'source4') diff --git a/source4/Makefile.in b/source4/Makefile.in index 47122679c6..19264c1237 100644 --- a/source4/Makefile.in +++ b/source4/Makefile.in @@ -199,7 +199,8 @@ LIBRAW_NDR_OBJ = librpc/ndr/ndr.o librpc/ndr/ndr_basic.o librpc/ndr/ndr_sec.o \ librpc/gen_ndr/ndr_epmapper.o librpc/gen_ndr/ndr_winreg.o \ librpc/gen_ndr/ndr_mgmt.o -LIBRAW_RPC_OBJ = librpc/rpc/dcerpc.o librpc/rpc/dcerpc_smb.o \ +LIBRAW_RPC_OBJ = librpc/rpc/dcerpc.o \ + librpc/rpc/dcerpc_smb.o librpc/rpc/dcerpc_tcp.o \ librpc/gen_rpc/rpc_echo.o librpc/gen_rpc/rpc_lsa.o \ librpc/gen_rpc/rpc_dfs.o librpc/gen_rpc/rpc_spoolss.o \ librpc/gen_rpc/rpc_samr.o librpc/gen_rpc/rpc_wkssvc.o \ diff --git a/source4/librpc/rpc/dcerpc.c b/source4/librpc/rpc/dcerpc.c index 495e36ec1f..012677a122 100644 --- a/source4/librpc/rpc/dcerpc.c +++ b/source4/librpc/rpc/dcerpc.c @@ -24,7 +24,7 @@ /* initialise a dcerpc pipe. This currently assumes a SMB named pipe transport */ -struct dcerpc_pipe *dcerpc_pipe_init(struct cli_tree *tree) +struct dcerpc_pipe *dcerpc_pipe_init(void) { struct dcerpc_pipe *p; diff --git a/source4/librpc/rpc/dcerpc_smb.c b/source4/librpc/rpc/dcerpc_smb.c index ba9c0c62a2..6af997275c 100644 --- a/source4/librpc/rpc/dcerpc_smb.c +++ b/source4/librpc/rpc/dcerpc_smb.c @@ -1,6 +1,7 @@ /* Unix SMB/CIFS implementation. - raw dcerpc operations + + dcerpc over SMB transport Copyright (C) Tim Potter 2003 Copyright (C) Andrew Tridgell 2003 @@ -348,7 +349,7 @@ NTSTATUS dcerpc_pipe_open_smb(struct dcerpc_pipe **p, return status; } - if (!(*p = dcerpc_pipe_init(tree))) { + if (!(*p = dcerpc_pipe_init())) { return NT_STATUS_NO_MEMORY; } @@ -381,5 +382,5 @@ NTSTATUS dcerpc_pipe_open_smb(struct dcerpc_pipe **p, dcerpc_pipe_close(*p); } - return status; + return NT_STATUS_OK; } diff --git a/source4/librpc/rpc/dcerpc_tcp.c b/source4/librpc/rpc/dcerpc_tcp.c new file mode 100644 index 0000000000..785ef46423 --- /dev/null +++ b/source4/librpc/rpc/dcerpc_tcp.c @@ -0,0 +1,201 @@ +/* + Unix SMB/CIFS implementation. + + dcerpc over TCP transport + + 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" + +/* transport private information used by TCP pipe transport */ +struct tcp_private { + int fd; + char *server_name; + uint32 port; +}; + +static NTSTATUS tcp_raw_recv(struct dcerpc_pipe *p, + TALLOC_CTX *mem_ctx, + DATA_BLOB *blob) +{ + struct tcp_private *tcp = p->transport.private; + ssize_t ret; + uint32 frag_length; + DATA_BLOB blob1; + + blob1 = data_blob_talloc(mem_ctx, NULL, 16); + if (!blob1.data) { + return NT_STATUS_NO_MEMORY; + } + + ret = read_data(tcp->fd, blob1.data, blob1.length); + if (ret != blob1.length) { + return NT_STATUS_NET_WRITE_FAULT; + } + + /* we might have recieved a partial fragment, in which case we + need to pull the rest of it */ + frag_length = SVAL(blob1.data, 8); + if (frag_length == blob1.length) { + *blob = blob1; + return NT_STATUS_OK; + } + + *blob = data_blob_talloc(mem_ctx, NULL, frag_length); + if (!blob->data) { + return NT_STATUS_NO_MEMORY; + } + memcpy(blob->data, blob1.data, blob1.length); + + ret = read_data(tcp->fd, blob->data + blob1.length, frag_length - blob1.length); + if (ret != frag_length - blob1.length) { + return NT_STATUS_NET_WRITE_FAULT; + } + + return NT_STATUS_OK; +} + +static NTSTATUS tcp_full_request(struct dcerpc_pipe *p, + TALLOC_CTX *mem_ctx, + DATA_BLOB *request_blob, + DATA_BLOB *reply_blob) +{ + struct tcp_private *tcp = p->transport.private; + ssize_t ret; + + ret = write_data(tcp->fd, request_blob->data, request_blob->length); + if (ret != request_blob->length) { + return NT_STATUS_NET_WRITE_FAULT; + } + + return tcp_raw_recv(p, mem_ctx, reply_blob); +} + + +/* + retrieve a secondary pdu from a pipe +*/ +NTSTATUS tcp_secondary_request(struct dcerpc_pipe *p, + TALLOC_CTX *mem_ctx, + DATA_BLOB *blob) +{ + return tcp_raw_recv(p, mem_ctx, blob); +} + + +/* + send an initial pdu in a multi-pdu sequence +*/ +static NTSTATUS tcp_initial_request(struct dcerpc_pipe *p, + TALLOC_CTX *mem_ctx, + DATA_BLOB *blob) +{ + struct tcp_private *tcp = p->transport.private; + ssize_t ret; + + ret = write_data(tcp->fd, blob->data, blob->length); + if (ret != blob->length) { + return NT_STATUS_NET_WRITE_FAULT; + } + + return NT_STATUS_OK; +} + + +/* + shutdown TCP pipe connection +*/ +static NTSTATUS tcp_shutdown_pipe(struct dcerpc_pipe *p) +{ + struct tcp_private *tcp = p->transport.private; + + if (tcp) { + close(tcp->fd); + } + + return NT_STATUS_OK; +} + +/* + return TCP server name +*/ +static const char *tcp_peer_name(struct dcerpc_pipe *p) +{ + struct tcp_private *tcp = p->transport.private; + return tcp->server_name; +} + + +/* + open a rpc connection to a named pipe +*/ +NTSTATUS dcerpc_pipe_open_tcp(struct dcerpc_pipe **p, + const char *server, + uint32 port, + const char *pipe_uuid, + uint32 pipe_version) +{ + struct tcp_private *tcp; + NTSTATUS status; + int fd; + struct in_addr addr; + + addr.s_addr = interpret_addr(server); + if (addr.s_addr == 0) { + return NT_STATUS_BAD_NETWORK_NAME; + } + + fd = open_socket_out(SOCK_STREAM, &addr, port, 30000); + if (fd == -1) { + return NT_STATUS_PORT_CONNECTION_REFUSED; + } + + if (!(*p = dcerpc_pipe_init())) { + return NT_STATUS_NO_MEMORY; + } + + /* + fill in the transport methods + */ + (*p)->transport.private = NULL; + (*p)->transport.full_request = tcp_full_request; + (*p)->transport.secondary_request = tcp_secondary_request; + (*p)->transport.initial_request = tcp_initial_request; + (*p)->transport.shutdown_pipe = tcp_shutdown_pipe; + (*p)->transport.peer_name = tcp_peer_name; + + tcp = talloc((*p)->mem_ctx, sizeof(*tcp)); + if (!tcp) { + dcerpc_pipe_close(*p); + return NT_STATUS_NO_MEMORY; + } + + tcp->fd = fd; + tcp->server_name = talloc_strdup((*p)->mem_ctx, server); + + (*p)->transport.private = tcp; + + /* bind to the pipe, using the uuid as the key */ + status = dcerpc_bind_byuuid(*p, pipe_uuid, pipe_version); + + if (!NT_STATUS_IS_OK(status)) { + dcerpc_pipe_close(*p); + } + + return NT_STATUS_OK; +} diff --git a/source4/torture/rpc/epmapper.c b/source4/torture/rpc/epmapper.c index de3b0b67d2..a056f2254e 100644 --- a/source4/torture/rpc/epmapper.c +++ b/source4/torture/rpc/epmapper.c @@ -179,10 +179,10 @@ BOOL torture_rpc_epmapper(int dummy) mem_ctx = talloc_init("torture_rpc_epmapper"); - status = torture_rpc_connection(&p, - DCERPC_EPMAPPER_NAME, - DCERPC_EPMAPPER_UUID, - DCERPC_EPMAPPER_VERSION); + status = torture_rpc_tcp(&p, + DCERPC_EPMAPPER_NAME, + DCERPC_EPMAPPER_UUID, + DCERPC_EPMAPPER_VERSION); if (!NT_STATUS_IS_OK(status)) { return False; } diff --git a/source4/torture/torture.c b/source4/torture/torture.c index c07b516baa..73373d944c 100644 --- a/source4/torture/torture.c +++ b/source4/torture/torture.c @@ -157,6 +157,30 @@ NTSTATUS torture_rpc_connection(struct dcerpc_pipe **p, return status; } +/* open a rpc connection to a named pipe */ +NTSTATUS torture_rpc_tcp(struct dcerpc_pipe **p, + const char *pipe_name, + const char *pipe_uuid, + uint32 pipe_version) +{ + NTSTATUS status; + + status = dcerpc_pipe_open_tcp(p, + lp_parm_string(-1, "torture", "host"), + lp_parm_int(-1, "torture", "share"), + pipe_uuid, pipe_version); + if (!NT_STATUS_IS_OK(status)) { + printf("Open of pipe '%s' failed with error (%s)\n", + pipe_name, nt_errstr(status)); + return status; + } + + /* always do NDR validation in smbtorture */ + (*p)->flags |= DCERPC_DEBUG_VALIDATE_BOTH; + + return status; +} + /* close a rpc connection to a named pipe */ NTSTATUS torture_rpc_close(struct dcerpc_pipe *p) { -- cgit