From c5b43710543a83e25c387566691031a357f5a1da Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Thu, 22 Jan 2009 18:34:06 +0100 Subject: Add the named pipe rpc client transport --- source3/Makefile.in | 2 +- source3/include/proto.h | 7 +- source3/rpc_client/rpc_transport_np.c | 329 ++++++++++++++++++++++++++++++++++ 3 files changed, 336 insertions(+), 2 deletions(-) create mode 100644 source3/rpc_client/rpc_transport_np.c (limited to 'source3') diff --git a/source3/Makefile.in b/source3/Makefile.in index b4d9841a4a..7fbe22fded 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -576,7 +576,7 @@ RPC_PARSE_OBJ = $(RPC_PARSE_OBJ2) \ rpc_parse/parse_spoolss.o \ rpc_parse/parse_eventlog.o rpc_parse/parse_buffer.o -RPC_CLIENT_OBJ = rpc_client/cli_pipe.o +RPC_CLIENT_OBJ = rpc_client/cli_pipe.o rpc_client/rpc_transport_np.o LOCKING_OBJ = locking/locking.o locking/brlock.o locking/posix.o diff --git a/source3/include/proto.h b/source3/include/proto.h index d55546f94c..1e71533156 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -5216,7 +5216,6 @@ NTSTATUS rpc_pipe_bind(struct rpc_pipe_client *cli, unsigned int rpccli_set_timeout(struct rpc_pipe_client *cli, unsigned int timeout); bool rpccli_get_pwd_hash(struct rpc_pipe_client *cli, uint8_t nt_hash[16]); -struct cli_state *rpc_pipe_np_smb_conn(struct rpc_pipe_client *p); NTSTATUS rpccli_anon_bind_data(TALLOC_CTX *mem_ctx, struct cli_pipe_auth_data **presult); NTSTATUS rpccli_ntlmssp_bind_data(TALLOC_CTX *mem_ctx, @@ -5296,6 +5295,12 @@ NTSTATUS cli_get_session_key(TALLOC_CTX *mem_ctx, struct rpc_pipe_client *cli, DATA_BLOB *session_key); +/* The following definitions come from rpc_client/rpc_transport_np.c */ + +NTSTATUS rpc_transport_np_init(TALLOC_CTX *mem_ctx, struct cli_state *cli, + const struct ndr_syntax_id *abstract_syntax, + struct rpc_cli_transport **presult); +struct cli_state *rpc_pipe_np_smb_conn(struct rpc_pipe_client *p); /* The following definitions come from rpc_client/cli_reg.c */ diff --git a/source3/rpc_client/rpc_transport_np.c b/source3/rpc_client/rpc_transport_np.c new file mode 100644 index 0000000000..e8a333e509 --- /dev/null +++ b/source3/rpc_client/rpc_transport_np.c @@ -0,0 +1,329 @@ +/* + * Unix SMB/CIFS implementation. + * RPC client transport over named pipes + * Copyright (C) Volker Lendecke 2009 + * + * 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 3 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, see . + */ + +#include "includes.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_RPC_CLI + +struct rpc_transport_np_state { + struct cli_state *cli; + const char *pipe_name; + uint16_t fnum; +}; + +static int rpc_transport_np_state_destructor(struct rpc_transport_np_state *s) +{ + bool ret; + ret = cli_close(s->cli, s->fnum); + if (!ret) { + DEBUG(1, ("rpc_transport_np_state_destructor: cli_close " + "failed on pipe %s. Error was %s\n", s->pipe_name, + cli_errstr(s->cli))); + } + DEBUG(10, ("rpc_pipe_destructor: closed %s\n", s->pipe_name)); + /* + * We can't do much on failure + */ + return 0; +} + +struct rpc_np_write_state { + size_t size; + size_t written; +}; + +static void rpc_np_write_done(struct async_req *subreq); + +static struct async_req *rpc_np_write_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + const uint8_t *data, size_t size, + void *priv) +{ + struct rpc_transport_np_state *np_transport = talloc_get_type_abort( + priv, struct rpc_transport_np_state); + struct async_req *result, *subreq; + struct rpc_np_write_state *state; + + if (!async_req_setup(mem_ctx, &result, &state, + struct rpc_np_write_state)) { + return NULL; + } + state->size = size; + + subreq = cli_write_andx_send(mem_ctx, ev, np_transport->cli, + np_transport->fnum, + 8, /* 8 means message mode. */ + data, 0, size); + if (subreq == NULL) { + goto fail; + } + subreq->async.fn = rpc_np_write_done; + subreq->async.priv = result; + return result; + fail: + TALLOC_FREE(result); + return NULL; +} + +static void rpc_np_write_done(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + struct rpc_np_write_state *state = talloc_get_type_abort( + req->private_data, struct rpc_np_write_state); + NTSTATUS status; + + status = cli_write_andx_recv(subreq, &state->written); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + async_req_error(req, status); + return; + } + async_req_done(req); +} + +static NTSTATUS rpc_np_write_recv(struct async_req *req, ssize_t *pwritten) +{ + struct rpc_np_write_state *state = talloc_get_type_abort( + req->private_data, struct rpc_np_write_state); + NTSTATUS status; + + if (async_req_is_error(req, &status)) { + return status; + } + *pwritten = state->written; + return NT_STATUS_OK; +} + +struct rpc_np_read_state { + uint8_t *data; + size_t size; + ssize_t received; +}; + +static void rpc_np_read_done(struct async_req *subreq); + +static struct async_req *rpc_np_read_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + uint8_t *data, size_t size, + void *priv) +{ + struct rpc_transport_np_state *np_transport = talloc_get_type_abort( + priv, struct rpc_transport_np_state); + struct async_req *result, *subreq; + struct rpc_np_read_state *state; + + if (!async_req_setup(mem_ctx, &result, &state, + struct rpc_np_read_state)) { + return NULL; + } + state->data = data; + state->size = size; + + subreq = cli_read_andx_send(mem_ctx, ev, np_transport->cli, + np_transport->fnum, 0, size); + if (subreq == NULL) { + goto fail; + } + subreq->async.fn = rpc_np_read_done; + subreq->async.priv = result; + return result; + fail: + TALLOC_FREE(result); + return NULL; +} + +static void rpc_np_read_done(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + struct rpc_np_read_state *state = talloc_get_type_abort( + req->private_data, struct rpc_np_read_state); + NTSTATUS status; + uint8_t *rcvbuf; + + status = cli_read_andx_recv(subreq, &state->received, &rcvbuf); + /* + * We can't TALLOC_FREE(subreq) as usual here, as rcvbuf still is a + * child of that. + */ + if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) { + status = NT_STATUS_OK; + } + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(subreq); + async_req_error(req, status); + return; + } + + if (state->received > state->size) { + TALLOC_FREE(subreq); + async_req_error(req, NT_STATUS_INVALID_NETWORK_RESPONSE); + return; + } + + memcpy(state->data, rcvbuf, state->received); + async_req_done(req); +} + +static NTSTATUS rpc_np_read_recv(struct async_req *req, ssize_t *preceived) +{ + struct rpc_np_read_state *state = talloc_get_type_abort( + req->private_data, struct rpc_np_read_state); + NTSTATUS status; + + if (async_req_is_error(req, &status)) { + return status; + } + *preceived = state->received; + return NT_STATUS_OK; +} + +struct rpc_np_trans_state { + uint16_t setup[2]; + uint8_t *rdata; + uint32_t rdata_len; +}; + +static void rpc_np_trans_done(struct async_req *subreq); + +static struct async_req *rpc_np_trans_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + uint8_t *data, size_t data_len, + uint32_t max_rdata_len, + void *priv) +{ + struct rpc_transport_np_state *np_transport = talloc_get_type_abort( + priv, struct rpc_transport_np_state); + struct async_req *result, *subreq; + struct rpc_np_trans_state *state; + + if (!async_req_setup(mem_ctx, &result, &state, + struct rpc_np_trans_state)) { + return NULL; + } + + SSVAL(state->setup+0, 0, TRANSACT_DCERPCCMD); + SSVAL(state->setup+1, 0, np_transport->fnum); + + subreq = cli_trans_send( + state, ev, np_transport->cli, SMBtrans, + "\\PIPE\\", 0, 0, 0, state->setup, 2, 0, + NULL, 0, 0, data, data_len, max_rdata_len); + if (subreq == NULL) { + goto fail; + } + subreq->async.fn = rpc_np_trans_done; + subreq->async.priv = result; + return result; + + fail: + TALLOC_FREE(result); + return NULL; +} + +static void rpc_np_trans_done(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + struct rpc_np_trans_state *state = talloc_get_type_abort( + req->private_data, struct rpc_np_trans_state); + NTSTATUS status; + + status = cli_trans_recv(subreq, state, NULL, NULL, NULL, NULL, + &state->rdata, &state->rdata_len); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + async_req_error(req, status); + return; + } + async_req_done(req); +} + +static NTSTATUS rpc_np_trans_recv(struct async_req *req, TALLOC_CTX *mem_ctx, + uint8_t **prdata, uint32_t *prdata_len) +{ + struct rpc_np_trans_state *state = talloc_get_type_abort( + req->private_data, struct rpc_np_trans_state); + NTSTATUS status; + + if (async_req_is_error(req, &status)) { + return status; + } + *prdata = talloc_move(mem_ctx, &state->rdata); + *prdata_len = state->rdata_len; + return NT_STATUS_OK; +} + +NTSTATUS rpc_transport_np_init(TALLOC_CTX *mem_ctx, struct cli_state *cli, + const struct ndr_syntax_id *abstract_syntax, + struct rpc_cli_transport **presult) +{ + struct rpc_cli_transport *result; + struct rpc_transport_np_state *state; + int fnum; + + result = talloc(mem_ctx, struct rpc_cli_transport); + if (result == NULL) { + return NT_STATUS_NO_MEMORY; + } + state = talloc(result, struct rpc_transport_np_state); + if (state == NULL) { + TALLOC_FREE(result); + return NT_STATUS_NO_MEMORY; + } + result->priv = state; + + state->cli = cli; + state->pipe_name = cli_get_pipe_name_from_iface( + state, abstract_syntax); + + fnum = cli_nt_create(cli, state->pipe_name, DESIRED_ACCESS_PIPE); + if (fnum == -1) { + DEBUG(3,("rpc_pipe_open_np: cli_nt_create failed on pipe %s " + "to machine %s. Error was %s\n", state->pipe_name, + cli->desthost, cli_errstr(cli))); + TALLOC_FREE(result); + return cli_get_nt_error(cli); + } + state->fnum = fnum; + talloc_set_destructor(state, rpc_transport_np_state_destructor); + + result->write_send = rpc_np_write_send; + result->write_recv = rpc_np_write_recv; + result->read_send = rpc_np_read_send; + result->read_recv = rpc_np_read_recv; + result->trans_send = rpc_np_trans_send; + result->trans_recv = rpc_np_trans_recv; + + *presult = result; + return NT_STATUS_OK; +} + +struct cli_state *rpc_pipe_np_smb_conn(struct rpc_pipe_client *p) +{ + struct rpc_transport_np_state *state = talloc_get_type( + p->transport->priv, struct rpc_transport_np_state); + + if (state == NULL) { + return NULL; + } + return state->cli; +} -- cgit