mirror of
https://github.com/samba-team/samba.git
synced 2025-01-13 13:18:06 +03:00
a9b28120b8
metze
(This used to be commit 4597643e76
)
207 lines
4.7 KiB
C
207 lines
4.7 KiB
C
/*
|
|
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;
|
|
}
|
|
|
|
/* this could be a ncacn_http endpoint - this doesn't work
|
|
yet, but it goes close */
|
|
if (strncmp(blob1.data, "ncacn_http/1.0", 14) == 0) {
|
|
memmove(blob1.data, blob1.data+14, 2);
|
|
ret = read_data(tcp->fd, blob1.data+2, 14);
|
|
if (ret != 14) {
|
|
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 = dcerpc_get_frag_length(&blob1);
|
|
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
|
|
*/
|
|
static 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)
|
|
{
|
|
struct tcp_private *tcp;
|
|
int fd;
|
|
struct in_addr addr;
|
|
|
|
if (port == 0) {
|
|
port = EPMAPPER_PORT;
|
|
}
|
|
|
|
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.transport = NCACN_IP_TCP;
|
|
(*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;
|
|
|
|
return NT_STATUS_OK;
|
|
}
|