diff options
Diffstat (limited to 'source4/librpc/rpc/dcerpc_tcp.c')
-rw-r--r-- | source4/librpc/rpc/dcerpc_tcp.c | 201 |
1 files changed, 201 insertions, 0 deletions
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; +} |