summaryrefslogtreecommitdiff
path: root/source4/librpc/rpc
diff options
context:
space:
mode:
Diffstat (limited to 'source4/librpc/rpc')
-rw-r--r--source4/librpc/rpc/dcerpc.c804
-rw-r--r--source4/librpc/rpc/dcerpc.h129
-rw-r--r--source4/librpc/rpc/dcerpc_smb.c320
-rw-r--r--source4/librpc/rpc/rpc_echo.c137
-rw-r--r--source4/librpc/rpc/rpc_lsa.c149
5 files changed, 1539 insertions, 0 deletions
diff --git a/source4/librpc/rpc/dcerpc.c b/source4/librpc/rpc/dcerpc.c
new file mode 100644
index 0000000000..9e6c05e7ae
--- /dev/null
+++ b/source4/librpc/rpc/dcerpc.c
@@ -0,0 +1,804 @@
+/*
+ Unix SMB/CIFS implementation.
+ raw dcerpc operations
+
+ Copyright (C) Tim Potter 2003
+ 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"
+
+/* 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 *p;
+
+ TALLOC_CTX *mem_ctx = talloc_init("dcerpc_tree");
+ if (mem_ctx == NULL)
+ return NULL;
+
+ p = talloc(mem_ctx, sizeof(*p));
+ if (!p) {
+ talloc_destroy(mem_ctx);
+ return NULL;
+ }
+
+ p->reference_count = 0;
+ p->mem_ctx = mem_ctx;
+ p->tree = tree;
+ p->tree->reference_count++;
+ p->call_id = 1;
+ p->fnum = 0;
+
+ return p;
+}
+
+/* close down a dcerpc over SMB pipe */
+void dcerpc_pipe_close(struct dcerpc_pipe *p)
+{
+ if (!p) return;
+ p->reference_count--;
+ if (p->reference_count <= 0) {
+ cli_tree_close(p->tree);
+ talloc_destroy(p->mem_ctx);
+ }
+}
+
+#define BLOB_CHECK_BOUNDS(blob, offset, len) do { \
+ if ((offset) > blob->length || (blob->length - (offset) < (len))) { \
+ return NT_STATUS_INVALID_PARAMETER; \
+ } \
+} while (0)
+
+#define DCERPC_ALIGN(offset, n) do { \
+ (offset) = ((offset) + ((n)-1)) & ~((n)-1); \
+} while (0)
+
+/*
+ pull a wire format uuid into a string. This will consume 16 bytes
+*/
+static char *dcerpc_pull_uuid(char *data, TALLOC_CTX *mem_ctx)
+{
+ uint32 time_low;
+ uint16 time_mid, time_hi_and_version;
+ uint8 clock_seq_hi_and_reserved;
+ uint8 clock_seq_low;
+ uint8 node[6];
+ int i;
+
+ time_low = IVAL(data, 0);
+ time_mid = SVAL(data, 4);
+ time_hi_and_version = SVAL(data, 6);
+ clock_seq_hi_and_reserved = CVAL(data, 8);
+ clock_seq_low = CVAL(data, 9);
+ for (i=0;i<6;i++) {
+ node[i] = CVAL(data, 10 + i);
+ }
+
+ return talloc_asprintf(mem_ctx,
+ "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ time_low, time_mid, time_hi_and_version,
+ clock_seq_hi_and_reserved, clock_seq_low,
+ node[0], node[1], node[2], node[3], node[4], node[5]);
+}
+
+/*
+ push a uuid_str into wire format. It will consume 16 bytes
+*/
+static NTSTATUS push_uuid_str(char *data, const char *uuid_str)
+{
+ uint32 time_low;
+ uint32 time_mid, time_hi_and_version;
+ uint32 clock_seq_hi_and_reserved;
+ uint32 clock_seq_low;
+ uint32 node[6];
+ int i;
+
+ if (11 != sscanf(uuid_str, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ &time_low, &time_mid, &time_hi_and_version,
+ &clock_seq_hi_and_reserved, &clock_seq_low,
+ &node[0], &node[1], &node[2], &node[3], &node[4], &node[5])) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ SIVAL(data, 0, time_low);
+ SSVAL(data, 4, time_mid);
+ SSVAL(data, 6, time_hi_and_version);
+ SCVAL(data, 8, clock_seq_hi_and_reserved);
+ SCVAL(data, 9, clock_seq_low);
+ for (i=0;i<6;i++) {
+ SCVAL(data, 10 + i, node[i]);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ pull a dcerpc syntax id from a blob
+*/
+static NTSTATUS dcerpc_pull_syntax_id(DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
+ uint32 *offset,
+ struct dcerpc_syntax_id *syntax)
+{
+ syntax->uuid_str = dcerpc_pull_uuid(blob->data + (*offset), mem_ctx);
+ if (!syntax->uuid_str) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ (*offset) += 16;
+ syntax->if_version = IVAL(blob->data, *offset);
+ (*offset) += 4;
+ return NT_STATUS_OK;
+}
+
+/*
+ push a syntax id onto the wire. It will consume 20 bytes
+*/
+static NTSTATUS push_syntax_id(char *data, const struct dcerpc_syntax_id *syntax)
+{
+ NTSTATUS status;
+
+ status = push_uuid_str(data, syntax->uuid_str);
+ SIVAL(data, 16, syntax->if_version);
+
+ return status;
+}
+
+/*
+ pull an auth verifier from a packet
+*/
+static NTSTATUS dcerpc_pull_auth_verifier(DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
+ uint32 *offset,
+ struct dcerpc_hdr *hdr,
+ DATA_BLOB *auth)
+{
+ if (hdr->auth_length == 0) {
+ return NT_STATUS_OK;
+ }
+
+ BLOB_CHECK_BOUNDS(blob, *offset, hdr->auth_length);
+ *auth = data_blob_talloc(mem_ctx, blob->data + (*offset), hdr->auth_length);
+ if (!auth->data) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ (*offset) += hdr->auth_length;
+ return NT_STATUS_OK;
+}
+
+/*
+ parse a struct dcerpc_response
+*/
+static NTSTATUS dcerpc_pull_response(DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
+ uint32 *offset,
+ struct dcerpc_hdr *hdr,
+ struct dcerpc_response *pkt)
+{
+ uint32 stub_len;
+
+ BLOB_CHECK_BOUNDS(blob, *offset, 8);
+
+ pkt->alloc_hint = IVAL(blob->data, (*offset) + 0);
+ pkt->context_id = SVAL(blob->data, (*offset) + 4);
+ pkt->cancel_count = CVAL(blob->data, (*offset) + 6);
+
+ (*offset) += 8;
+
+ stub_len = blob->length - ((*offset) + hdr->auth_length);
+ BLOB_CHECK_BOUNDS(blob, *offset, stub_len);
+ pkt->stub_data = data_blob_talloc(mem_ctx, blob->data + (*offset), stub_len);
+ if (stub_len != 0 && !pkt->stub_data.data) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ (*offset) += stub_len;
+
+ return dcerpc_pull_auth_verifier(blob, mem_ctx, offset, hdr, &pkt->auth_verifier);
+}
+
+
+/*
+ parse a struct bind_ack
+*/
+static NTSTATUS dcerpc_pull_bind_ack(DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
+ uint32 *offset,
+ struct dcerpc_hdr *hdr,
+ struct dcerpc_bind_ack *pkt)
+{
+ uint16 len;
+ int i;
+
+ BLOB_CHECK_BOUNDS(blob, *offset, 10);
+ pkt->max_xmit_frag = SVAL(blob->data, (*offset) + 0);
+ pkt->max_recv_frag = SVAL(blob->data, (*offset) + 2);
+ pkt->assoc_group_id = IVAL(blob->data, (*offset) + 4);
+ len = SVAL(blob->data, (*offset) + 8);
+ (*offset) += 10;
+
+ if (len) {
+ BLOB_CHECK_BOUNDS(blob, *offset, len);
+ pkt->secondary_address = talloc_strndup(mem_ctx, blob->data + (*offset), len);
+ if (!pkt->secondary_address) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ (*offset) += len;
+ }
+
+ DCERPC_ALIGN(*offset, 4);
+ BLOB_CHECK_BOUNDS(blob, *offset, 4);
+ pkt->num_results = CVAL(blob->data, *offset);
+ (*offset) += 4;
+
+ if (pkt->num_results > 0) {
+ pkt->ctx_list = talloc(mem_ctx, sizeof(pkt->ctx_list[0]) * pkt->num_results);
+ if (!pkt->ctx_list) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ for (i=0;i<pkt->num_results;i++) {
+ NTSTATUS status;
+
+ BLOB_CHECK_BOUNDS(blob, *offset, 24);
+ pkt->ctx_list[i].result = IVAL(blob->data, *offset);
+ (*offset) += 4;
+ status = dcerpc_pull_syntax_id(blob, mem_ctx, offset, &pkt->ctx_list[i].syntax);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ return dcerpc_pull_auth_verifier(blob, mem_ctx, offset, hdr, &pkt->auth_verifier);
+}
+
+
+/*
+ parse a dcerpc header
+*/
+static NTSTATUS dcerpc_pull_hdr(DATA_BLOB *blob, uint32 *offset, struct dcerpc_hdr *hdr)
+{
+ BLOB_CHECK_BOUNDS(blob, *offset, 16);
+
+ hdr->rpc_vers = CVAL(blob->data, (*offset) + 0);
+ hdr->rpc_vers_minor = CVAL(blob->data, (*offset) + 1);
+ hdr->ptype = CVAL(blob->data, (*offset) + 2);
+ hdr->pfc_flags = CVAL(blob->data, (*offset) + 3);
+ memcpy(hdr->drep, blob->data + (*offset) + 4, 4);
+ hdr->frag_length = SVAL(blob->data, (*offset) + 8);
+ hdr->auth_length = SVAL(blob->data, (*offset) + 10);
+ hdr->call_id = IVAL(blob->data, (*offset) + 12);
+
+ (*offset) += 16;
+
+ return NT_STATUS_OK;
+}
+
+/*
+ parse a dcerpc header. It consumes 16 bytes
+*/
+static void dcerpc_push_hdr(char *data, struct dcerpc_hdr *hdr)
+{
+ SCVAL(data, 0, hdr->rpc_vers);
+ SCVAL(data, 1, hdr->rpc_vers_minor);
+ SCVAL(data, 2, hdr->ptype);
+ SCVAL(data, 3, hdr->pfc_flags);
+ memcpy(data + 4, hdr->drep, 4);
+ SSVAL(data, 8, hdr->frag_length);
+ SSVAL(data, 12, hdr->call_id);
+}
+
+
+
+/*
+ parse a data blob into a dcerpc_packet structure. This handles both
+ input and output packets
+*/
+NTSTATUS dcerpc_pull(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, struct dcerpc_packet *pkt)
+{
+ NTSTATUS status;
+ uint32 offset = 0;
+
+ status = dcerpc_pull_hdr(blob, &offset, &pkt->hdr);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ switch (pkt->hdr.ptype) {
+ case DCERPC_PKT_BIND_ACK:
+ status = dcerpc_pull_bind_ack(blob, mem_ctx, &offset, &pkt->hdr, &pkt->out.bind_ack);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ break;
+
+ case DCERPC_PKT_RESPONSE:
+ status = dcerpc_pull_response(blob, mem_ctx, &offset, &pkt->hdr, &pkt->out.response);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ break;
+
+ default:
+ return NT_STATUS_INVALID_LEVEL;
+ }
+
+ return status;
+}
+
+
+/*
+ push a dcerpc_bind into a blob
+*/
+static NTSTATUS dcerpc_push_bind(DATA_BLOB *blob, uint32 *offset,
+ struct dcerpc_hdr *hdr,
+ struct dcerpc_bind *pkt)
+{
+ int i, j;
+
+ SSVAL(blob->data, (*offset) + 0, pkt->max_xmit_frag);
+ SSVAL(blob->data, (*offset) + 2, pkt->max_recv_frag);
+ SIVAL(blob->data, (*offset) + 4, pkt->assoc_group_id);
+ SCVAL(blob->data, (*offset) + 8, pkt->num_contexts);
+ (*offset) += 12;
+
+ for (i=0;i<pkt->num_contexts;i++) {
+ NTSTATUS status;
+
+ SSVAL(blob->data, (*offset) + 0, pkt->ctx_list[i].context_id);
+ SCVAL(blob->data, (*offset) + 2, pkt->ctx_list[i].num_transfer_syntaxes);
+ status = push_syntax_id(blob->data + (*offset) + 4, &pkt->ctx_list[i].abstract_syntax);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ (*offset) += 24;
+ for (j=0;j<pkt->ctx_list[i].num_transfer_syntaxes;j++) {
+ status = push_syntax_id(blob->data + (*offset),
+ &pkt->ctx_list[i].transfer_syntaxes[j]);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ (*offset) += 20;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ push a dcerpc_request into a blob
+*/
+static NTSTATUS dcerpc_push_request(DATA_BLOB *blob, uint32 *offset,
+ struct dcerpc_hdr *hdr,
+ struct dcerpc_request *pkt)
+{
+ SIVAL(blob->data, (*offset) + 0, pkt->alloc_hint);
+ SSVAL(blob->data, (*offset) + 4, pkt->context_id);
+ SSVAL(blob->data, (*offset) + 6, pkt->opnum);
+
+ (*offset) += 8;
+
+ memcpy(blob->data + (*offset), pkt->stub_data.data, pkt->stub_data.length);
+ (*offset) += pkt->stub_data.length;
+
+ memcpy(blob->data + (*offset), pkt->auth_verifier.data, pkt->auth_verifier.length);
+ (*offset) += pkt->auth_verifier.length;
+
+ return NT_STATUS_OK;
+}
+
+
+/*
+ work out the wire size of a dcerpc packet
+*/
+static uint32 dcerpc_wire_size(struct dcerpc_packet *pkt)
+{
+ int i;
+ uint32 size = 0;
+
+ size += 16; /* header */
+
+ switch (pkt->hdr.ptype) {
+ case DCERPC_PKT_REQUEST:
+ size += 8;
+ size += pkt->in.request.stub_data.length;
+ size += pkt->in.request.auth_verifier.length;
+ break;
+
+ case DCERPC_PKT_RESPONSE:
+ size += 8;
+ size += pkt->out.response.stub_data.length;
+ size += pkt->hdr.auth_length;
+ break;
+
+ case DCERPC_PKT_BIND:
+ size += 12;
+ for (i=0;i<pkt->in.bind.num_contexts;i++) {
+ size += 24;
+ size += pkt->in.bind.ctx_list[i].num_transfer_syntaxes * 20;
+ }
+ size += pkt->hdr.auth_length;
+ break;
+
+ case DCERPC_PKT_BIND_ACK:
+ size += 10;
+ if (pkt->out.bind_ack.secondary_address) {
+ size += strlen(pkt->out.bind_ack.secondary_address) + 1;
+ }
+ size += 4;
+ size += pkt->out.bind_ack.num_results * 24;
+ size += pkt->hdr.auth_length;
+ break;
+ }
+
+ return size;
+}
+
+/*
+ push a dcerpc_packet into a blob. This handles both input and
+ output packets
+*/
+NTSTATUS dcerpc_push(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, struct dcerpc_packet *pkt)
+{
+ uint32 offset = 0;
+ uint32 wire_size;
+ NTSTATUS status;
+
+ /* work out how big the packet will be on the wire */
+ wire_size = dcerpc_wire_size(pkt);
+
+ (*blob) = data_blob_talloc(mem_ctx, NULL, wire_size);
+ if (!blob->data) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ pkt->hdr.frag_length = wire_size;
+
+ dcerpc_push_hdr(blob->data + offset, &pkt->hdr);
+ offset += 16;
+
+ switch (pkt->hdr.ptype) {
+ case DCERPC_PKT_BIND:
+ status = dcerpc_push_bind(blob, &offset, &pkt->hdr, &pkt->in.bind);
+ break;
+
+ case DCERPC_PKT_REQUEST:
+ status = dcerpc_push_request(blob, &offset, &pkt->hdr, &pkt->in.request);
+ break;
+
+ default:
+ status = NT_STATUS_INVALID_LEVEL;
+ }
+
+ return status;
+}
+
+
+
+
+/*
+ fill in the fixed values in a dcerpc header
+*/
+static void init_dcerpc_hdr(struct dcerpc_hdr *hdr)
+{
+ hdr->rpc_vers = 5;
+ hdr->rpc_vers_minor = 0;
+ hdr->drep[0] = 0x10; /* Little endian */
+ hdr->drep[1] = 0;
+ hdr->drep[2] = 0;
+ hdr->drep[3] = 0;
+}
+
+
+/*
+ perform a bind using the given syntax
+*/
+NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
+ const struct dcerpc_syntax_id *syntax,
+ const struct dcerpc_syntax_id *transfer_syntax)
+{
+ TALLOC_CTX *mem_ctx;
+ struct dcerpc_packet pkt;
+ NTSTATUS status;
+ DATA_BLOB blob;
+ DATA_BLOB blob_out;
+
+ mem_ctx = talloc_init("dcerpc_bind");
+ if (!mem_ctx) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ init_dcerpc_hdr(&pkt.hdr);
+
+ pkt.hdr.ptype = DCERPC_PKT_BIND;
+ pkt.hdr.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
+ pkt.hdr.call_id = p->call_id++;
+ pkt.hdr.auth_length = 0;
+
+ pkt.in.bind.max_xmit_frag = 0x2000;
+ pkt.in.bind.max_recv_frag = 0x2000;
+ pkt.in.bind.assoc_group_id = 0;
+ pkt.in.bind.num_contexts = 1;
+ pkt.in.bind.ctx_list = talloc(mem_ctx, sizeof(pkt.in.bind.ctx_list[0]));
+ if (!pkt.in.bind.ctx_list) {
+ talloc_destroy(mem_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+ pkt.in.bind.ctx_list[0].context_id = 0;
+ pkt.in.bind.ctx_list[0].num_transfer_syntaxes = 1;
+ pkt.in.bind.ctx_list[0].abstract_syntax = *syntax;
+ pkt.in.bind.ctx_list[0].transfer_syntaxes = transfer_syntax;
+
+ pkt.in.bind.auth_verifier = data_blob(NULL, 0);
+
+ status = dcerpc_push(&blob, mem_ctx, &pkt);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_destroy(mem_ctx);
+ return status;
+ }
+
+ status = dcerpc_raw_packet(p, mem_ctx, &blob, &blob_out);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_destroy(mem_ctx);
+ return status;
+ }
+
+ status = dcerpc_pull(&blob_out, mem_ctx, &pkt);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_destroy(mem_ctx);
+ return status;
+ }
+
+ if (pkt.hdr.ptype != DCERPC_PKT_BIND_ACK) {
+ status = NT_STATUS_UNSUCCESSFUL;
+ }
+
+ p->srv_max_xmit_frag = pkt.out.bind_ack.max_xmit_frag;
+ p->srv_max_recv_frag = pkt.out.bind_ack.max_recv_frag;
+
+ talloc_destroy(mem_ctx);
+
+ return status;
+}
+
+static const struct {
+ const char *name;
+ struct dcerpc_syntax_id syntax;
+ const struct dcerpc_syntax_id transfer_syntax;
+} known_pipes[] = {
+ { "lsarpc" , { "12345778-1234-abcd-ef00-0123456789ab", 0 }, DCERPC_TRANSFER_SYNTAX_V2 },
+ { "samr" , { "12345778-1234-abcd-ef00-0123456789ac", 1 }, DCERPC_TRANSFER_SYNTAX_V2 },
+ { "netlogon", { "12345778-1234-abcd-ef00-01234567cffb", 1 }, DCERPC_TRANSFER_SYNTAX_V2 },
+ { "srvsvc" , { "4b324fc8-1670-01d3-1278-5a47bf6ee188", 3 }, DCERPC_TRANSFER_SYNTAX_V2 },
+ { "wkssvc" , { "6bffd098-a112-3610-9833-46c3f87e345a", 1 }, DCERPC_TRANSFER_SYNTAX_V2 },
+ { "winreg" , { "338cd001-2244-31f1-aaaa-900038001003", 1 }, DCERPC_TRANSFER_SYNTAX_V2 },
+ { "spoolss" , { "12345678-1234-abcd-ef00-0123456789ab", 1 }, DCERPC_TRANSFER_SYNTAX_V2 },
+ { "netdfs" , { "4fc742e0-4a10-11cf-8273-00aa004ae673", 3 }, DCERPC_TRANSFER_SYNTAX_V2 },
+ { "rpcecho" , { "60a15ec5-4de8-11d7-a637-005056a20182", 1 }, DCERPC_TRANSFER_SYNTAX_V2 },
+ { NULL , }
+};
+
+
+/* Perform a bind using the given well-known pipe name */
+NTSTATUS dcerpc_bind_byname(struct dcerpc_pipe *p, const char *pipe_name)
+{
+ int i;
+
+ for (i=0; known_pipes[i].name; i++) {
+ if (strcasecmp(known_pipes[i].name, pipe_name) == 0)
+ break;
+ }
+
+ if (known_pipes[i].name == NULL) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ return dcerpc_bind(p, &known_pipes[i].syntax, &known_pipes[i].transfer_syntax);
+}
+
+/*
+ perform a full request/response pair on a dcerpc pipe
+*/
+NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
+ uint16 opnum,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *stub_data_in,
+ DATA_BLOB *stub_data_out)
+{
+
+ struct dcerpc_packet pkt;
+ NTSTATUS status;
+ DATA_BLOB blob_in, blob_out, payload;
+ uint32 remaining, chunk_size;
+
+ init_dcerpc_hdr(&pkt.hdr);
+
+ remaining = stub_data_in->length;
+
+ /* we can write a full max_recv_frag size, minus the dcerpc
+ request header size */
+ chunk_size = p->srv_max_recv_frag - 24;
+
+ pkt.hdr.ptype = DCERPC_PKT_REQUEST;
+ pkt.hdr.call_id = p->call_id++;
+ pkt.hdr.auth_length = 0;
+ pkt.in.request.alloc_hint = remaining;
+ pkt.in.request.context_id = 0;
+ pkt.in.request.opnum = opnum;
+ pkt.in.request.auth_verifier = data_blob(NULL, 0);
+
+ /* we send a series of pdus without waiting for a reply until
+ the last pdu */
+ while (remaining > chunk_size) {
+ if (remaining == stub_data_in->length) {
+ pkt.hdr.pfc_flags = DCERPC_PFC_FLAG_FIRST;
+ } else {
+ pkt.hdr.pfc_flags = 0;
+ }
+
+ pkt.in.request.stub_data.data = stub_data_in->data +
+ (stub_data_in->length - remaining);
+ pkt.in.request.stub_data.length = chunk_size;
+
+ status = dcerpc_push(&blob_in, mem_ctx, &pkt);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = dcerpc_raw_packet_initial(p, mem_ctx, &blob_in);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ remaining -= chunk_size;
+ }
+
+ /* now we send a pdu with LAST_FRAG sent and get the first
+ part of the reply */
+ if (remaining == stub_data_in->length) {
+ pkt.hdr.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
+ } else {
+ pkt.hdr.pfc_flags = DCERPC_PFC_FLAG_LAST;
+ }
+ pkt.in.request.stub_data.data = stub_data_in->data +
+ (stub_data_in->length - remaining);
+ pkt.in.request.stub_data.length = remaining;
+
+ status = dcerpc_push(&blob_in, mem_ctx, &pkt);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /* send the pdu and get the initial response pdu */
+ status = dcerpc_raw_packet(p, mem_ctx, &blob_in, &blob_out);
+
+ status = dcerpc_pull(&blob_out, mem_ctx, &pkt);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (pkt.hdr.ptype != DCERPC_PKT_RESPONSE) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (!(pkt.hdr.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
+ /* something is badly wrong! */
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ payload = pkt.out.response.stub_data;
+
+ /* continue receiving fragments */
+ while (!(pkt.hdr.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
+ uint32 length;
+
+ status = dcerpc_raw_packet_secondary(p, mem_ctx, &blob_out);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = dcerpc_pull(&blob_out, mem_ctx, &pkt);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (pkt.hdr.pfc_flags & DCERPC_PFC_FLAG_FIRST) {
+ /* start of another packet!? */
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (pkt.hdr.ptype != DCERPC_PKT_RESPONSE) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ length = pkt.out.response.stub_data.length;
+
+ payload.data = talloc_realloc(mem_ctx,
+ payload.data,
+ payload.length + length);
+ if (!payload.data) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ memcpy(payload.data + payload.length,
+ pkt.out.response.stub_data.data,
+ length);
+
+ payload.length += length;
+ }
+
+ if (stub_data_out) {
+ *stub_data_out = payload;
+ }
+
+ return status;
+}
+
+
+/*
+ a useful helper function for synchronous rpc requests
+
+ this can be used when you have ndr push/pull functions in the
+ standard format
+*/
+NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
+ uint32 opnum,
+ TALLOC_CTX *mem_ctx,
+ NTSTATUS (*ndr_push)(struct ndr_push *, void *),
+ NTSTATUS (*ndr_pull)(struct ndr_pull *, void *),
+ void *struct_ptr)
+{
+ struct ndr_push *push;
+ struct ndr_pull *pull;
+ NTSTATUS status;
+ DATA_BLOB request, response;
+
+ /* setup for a ndr_push_* call */
+ push = ndr_push_init();
+ if (!push) {
+ talloc_destroy(mem_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* push the structure into a blob */
+ status = ndr_push(push, struct_ptr);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto failed;
+ }
+
+ /* retrieve the blob */
+ request = ndr_push_blob(push);
+
+ /* make the actual dcerpc request */
+ status = dcerpc_request(p, opnum, mem_ctx, &request, &response);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto failed;
+ }
+
+ /* prepare for ndr_pull_* */
+ pull = ndr_pull_init_blob(&response, mem_ctx);
+ if (!pull) {
+ goto failed;
+ }
+
+ /* pull the structure from the blob */
+ status = ndr_pull(pull, struct_ptr);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto failed;
+ }
+
+failed:
+ ndr_push_free(push);
+ return status;
+}
diff --git a/source4/librpc/rpc/dcerpc.h b/source4/librpc/rpc/dcerpc.h
new file mode 100644
index 0000000000..09ddc3625c
--- /dev/null
+++ b/source4/librpc/rpc/dcerpc.h
@@ -0,0 +1,129 @@
+/*
+ Unix SMB/CIFS implementation.
+ DCERPC interface structures
+
+ Copyright (C) Tim Potter 2003
+ 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.
+*/
+
+/*
+ see http://www.opengroup.org/onlinepubs/9629399/chap12.htm for details
+ of these structures
+
+ note that the structure definitions here don't include some of the
+ fields that are wire-artifacts. Those are put on the wire by the
+ marshalling/unmarshalling routines in decrpc.c
+*/
+
+struct dcerpc_pipe {
+ TALLOC_CTX *mem_ctx;
+ uint16 fnum;
+ int reference_count;
+ uint32 call_id;
+ uint32 srv_max_xmit_frag;
+ uint32 srv_max_recv_frag;
+ struct cli_tree *tree;
+};
+
+/* dcerpc packet types */
+#define DCERPC_PKT_REQUEST 0
+#define DCERPC_PKT_RESPONSE 2
+#define DCERPC_PKT_BIND 11
+#define DCERPC_PKT_BIND_ACK 12
+#define DCERPC_PKT_BIND_NAK 13
+
+/* hdr.pfc_flags */
+#define DCERPC_PFC_FLAG_FIRST 0x01
+#define DCERPC_PFC_FLAG_LAST 0x02
+#define DCERPC_PFC_FLAG_NOCALL 0x20
+
+/*
+ all dcerpc packets use this structure.
+*/
+struct dcerpc_packet {
+ /* all requests and responses contain a dcerpc header */
+ struct dcerpc_hdr {
+ uint8 rpc_vers; /* RPC version */
+ uint8 rpc_vers_minor; /* Minor version */
+ uint8 ptype; /* Packet type */
+ uint8 pfc_flags; /* Fragmentation flags */
+ uint8 drep[4]; /* NDR data representation */
+ uint16 frag_length; /* Total length of fragment */
+ uint16 auth_length; /* authenticator length */
+ uint32 call_id; /* Call identifier */
+ } hdr;
+
+ union {
+ struct dcerpc_bind {
+ uint16 max_xmit_frag;
+ uint16 max_recv_frag;
+ uint32 assoc_group_id;
+ uint8 num_contexts;
+ struct {
+ uint16 context_id;
+ uint8 num_transfer_syntaxes;
+ struct dcerpc_syntax_id {
+ const char *uuid_str;
+ uint32 if_version;
+ } abstract_syntax;
+ const struct dcerpc_syntax_id *transfer_syntaxes;
+ } *ctx_list;
+ DATA_BLOB auth_verifier;
+ } bind;
+
+ struct dcerpc_request {
+ uint32 alloc_hint;
+ uint16 context_id;
+ uint16 opnum;
+ DATA_BLOB stub_data;
+ DATA_BLOB auth_verifier;
+ } request;
+ } in;
+
+ union {
+ struct dcerpc_bind_ack {
+ uint16 max_xmit_frag;
+ uint16 max_recv_frag;
+ uint32 assoc_group_id;
+ const char *secondary_address;
+ uint8 num_results;
+ struct {
+ uint32 result;
+ struct dcerpc_syntax_id syntax;
+ } *ctx_list;
+ DATA_BLOB auth_verifier;
+ } bind_ack;
+
+ struct dcerpc_bind_nak {
+ uint16 reject_reason;
+ uint32 num_versions;
+ uint32 *versions;
+ } bind_nak;
+
+ struct dcerpc_response {
+ uint32 alloc_hint;
+ uint16 context_id;
+ uint8 cancel_count;
+ DATA_BLOB stub_data;
+ DATA_BLOB auth_verifier;
+ } response;
+ } out;
+};
+
+/* this seems to be the only transfer syntax used */
+#define DCERPC_TRANSFER_SYNTAX_V2 {"8a885d04-1ceb-11c9-9fe8-08002b104860", 2}
+
diff --git a/source4/librpc/rpc/dcerpc_smb.c b/source4/librpc/rpc/dcerpc_smb.c
new file mode 100644
index 0000000000..0541200015
--- /dev/null
+++ b/source4/librpc/rpc/dcerpc_smb.c
@@ -0,0 +1,320 @@
+/*
+ Unix SMB/CIFS implementation.
+ raw dcerpc operations
+
+ Copyright (C) Tim Potter 2003
+ 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"
+
+
+/*
+ open a rpc connection to a named pipe
+*/
+NTSTATUS dcerpc_pipe_open_smb(struct dcerpc_pipe *p, const char *pipe_name)
+{
+ NTSTATUS status;
+ char *name = NULL;
+ union smb_open io;
+ TALLOC_CTX *mem_ctx;
+
+ asprintf(&name, "\\%s", pipe_name);
+ if (!name) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ io.ntcreatex.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.root_fid = 0;
+ io.ntcreatex.in.access_mask =
+ STD_RIGHT_READ_CONTROL_ACCESS |
+ SA_RIGHT_FILE_WRITE_ATTRIBUTES |
+ SA_RIGHT_FILE_WRITE_EA |
+ GENERIC_RIGHTS_FILE_READ |
+ GENERIC_RIGHTS_FILE_WRITE;
+ io.ntcreatex.in.file_attr = 0;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.share_access =
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_IMPERSONATION;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = name;
+
+ mem_ctx = talloc_init("torture_rpc_connection");
+ if (!mem_ctx) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ status = smb_raw_open(p->tree, mem_ctx, &io);
+ free(name);
+ talloc_destroy(mem_ctx);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ p->fnum = io.ntcreatex.out.fnum;
+
+ /* bind to the pipe, using the pipe_name as the key */
+ status = dcerpc_bind_byname(p, pipe_name);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ union smb_close c;
+ c.close.level = RAW_CLOSE_CLOSE;
+ c.close.in.fnum = p->fnum;
+ c.close.in.write_time = 0;
+ smb_raw_close(p->tree, &c);
+ }
+
+ return status;
+}
+
+
+struct cli_request *dcerpc_raw_send(struct dcerpc_pipe *p, DATA_BLOB *blob)
+{
+ struct smb_trans2 trans;
+ uint16 setup[2];
+ struct cli_request *req;
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_init("dcerpc_raw_send");
+ if (!mem_ctx) return NULL;
+
+ trans.in.data = *blob;
+ trans.in.params = data_blob(NULL, 0);
+
+ setup[0] = TRANSACT_DCERPCCMD;
+ setup[1] = p->fnum;
+
+ trans.in.max_param = 0;
+ trans.in.max_data = 0x8000;
+ trans.in.max_setup = 0;
+ trans.in.setup_count = 2;
+ trans.in.flags = 0;
+ trans.in.timeout = 0;
+ trans.in.setup = setup;
+ trans.in.trans_name = "\\PIPE\\";
+
+ req = smb_raw_trans_send(p->tree, &trans);
+
+ talloc_destroy(mem_ctx);
+
+ return req;
+}
+
+
+NTSTATUS dcerpc_raw_recv(struct dcerpc_pipe *p,
+ struct cli_request *req,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *blob)
+{
+ struct smb_trans2 trans;
+ NTSTATUS status;
+ uint16 frag_length;
+ DATA_BLOB payload;
+
+ status = smb_raw_trans_recv(req, mem_ctx, &trans);
+ /* STATUS_BUFFER_OVERFLOW means that there is more data
+ available via SMBreadX */
+ if (!NT_STATUS_IS_OK(status) &&
+ !NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
+ return status;
+ }
+
+ payload = trans.out.data;
+
+ if (trans.out.data.length < 16 ||
+ !NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
+ goto done;
+ }
+
+ /* we might have recieved a partial fragment, in which case we
+ need to pull the rest of it */
+ frag_length = SVAL(payload.data, 8);
+ if (frag_length <= payload.length) {
+ goto done;
+ }
+
+ /* make sure the payload can hold the whole fragment */
+ payload.data = talloc_realloc(mem_ctx, payload.data, frag_length);
+ if (!payload.data) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* the rest of the data is available via SMBreadX */
+ while (frag_length > payload.length) {
+ uint32 n;
+ union smb_read io;
+
+ n = frag_length - payload.length;
+ if (n > 0xFF00) {
+ n = 0xFF00;
+ }
+
+ io.generic.level = RAW_READ_READX;
+ io.readx.in.fnum = p->fnum;
+ io.readx.in.mincnt = n;
+ io.readx.in.maxcnt = n;
+ io.readx.in.offset = 0;
+ io.readx.in.remaining = 0;
+ io.readx.out.data = payload.data + payload.length;
+ status = smb_raw_read(p->tree, &io);
+ if (!NT_STATUS_IS_OK(status) &&
+ !NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
+ break;
+ }
+
+ n = io.readx.out.nread;
+ if (n == 0) {
+ status = NT_STATUS_UNSUCCESSFUL;
+ break;
+ }
+
+ payload.length += n;
+
+ /* if the SMBreadX returns NT_STATUS_OK then there
+ isn't any more data to be read */
+ if (NT_STATUS_IS_OK(status)) {
+ break;
+ }
+ }
+
+done:
+ if (blob) {
+ *blob = payload;
+ }
+
+ return status;
+}
+
+NTSTATUS dcerpc_raw_packet(struct dcerpc_pipe *p,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *request_blob,
+ DATA_BLOB *reply_blob)
+{
+ struct cli_request *req;
+ req = dcerpc_raw_send(p, request_blob);
+ return dcerpc_raw_recv(p, req, mem_ctx, reply_blob);
+}
+
+
+/*
+ retrieve a secondary pdu from a pipe
+*/
+NTSTATUS dcerpc_raw_packet_secondary(struct dcerpc_pipe *p,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *blob)
+{
+ union smb_read io;
+ uint32 n = 0x2000;
+ uint32 frag_length;
+ NTSTATUS status;
+
+ *blob = data_blob_talloc(mem_ctx, NULL, n);
+ if (!blob->data) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ io.generic.level = RAW_READ_READX;
+ io.readx.in.fnum = p->fnum;
+ io.readx.in.mincnt = n;
+ io.readx.in.maxcnt = n;
+ io.readx.in.offset = 0;
+ io.readx.in.remaining = 0;
+ io.readx.out.data = blob->data;
+
+ status = smb_raw_read(p->tree, &io);
+ if (!NT_STATUS_IS_OK(status) &&
+ !NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
+ return status;
+ }
+
+ blob->length = io.readx.out.nread;
+
+ if (blob->length < 16) {
+ return status;
+ }
+
+ frag_length = SVAL(blob->data, 8);
+ if (frag_length <= blob->length) {
+ return status;
+ }
+
+ blob->data = talloc_realloc(mem_ctx, blob->data, frag_length);
+ if (!blob->data) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ while (frag_length > blob->length &&
+ NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
+
+ n = frag_length - blob->length;
+ if (n > 0xFF00) {
+ n = 0xFF00;
+ }
+
+ io.readx.in.mincnt = n;
+ io.readx.in.maxcnt = n;
+ io.readx.out.data = blob->data + blob->length;
+ status = smb_raw_read(p->tree, &io);
+
+ if (!NT_STATUS_IS_OK(status) &&
+ !NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
+ return status;
+ }
+
+ n = io.readx.out.nread;
+ blob->length += n;
+ }
+
+ return status;
+}
+
+
+/*
+ send an initial pdu in a multi-pdu sequence
+*/
+NTSTATUS dcerpc_raw_packet_initial(struct dcerpc_pipe *p,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *blob)
+{
+ union smb_write io;
+ NTSTATUS status;
+
+ io.generic.level = RAW_WRITE_WRITEX;
+ io.writex.in.fnum = p->fnum;
+ io.writex.in.offset = 0;
+ io.writex.in.wmode = PIPE_START_MESSAGE;
+ io.writex.in.remaining = blob->length;
+ io.writex.in.count = blob->length;
+ io.writex.in.data = blob->data;
+
+ status = smb_raw_write(p->tree, &io);
+ if (NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /* make sure it accepted it all */
+ if (io.writex.out.nwritten != blob->length) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return status;
+}
diff --git a/source4/librpc/rpc/rpc_echo.c b/source4/librpc/rpc/rpc_echo.c
new file mode 100644
index 0000000000..d73f9bda9c
--- /dev/null
+++ b/source4/librpc/rpc/rpc_echo.c
@@ -0,0 +1,137 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ rpc echo pipe calls
+
+ 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"
+
+/*
+ addone interface
+*/
+NTSTATUS dcerpc_rpcecho_addone(struct dcerpc_pipe *p,
+ int in_data, int *out_data)
+{
+ struct rpcecho_addone r;
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_init("dcerpc_rpcecho_addone");
+ if (!mem_ctx) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* fill the .in side of the call */
+ r.in.data = in_data;
+
+ /* make the call */
+ status = dcerpc_ndr_request(p, RPCECHO_CALL_ADDONE, mem_ctx,
+ (ndr_push_fn_t) ndr_push_rpcecho_addone,
+ (ndr_pull_fn_t) ndr_pull_rpcecho_addone,
+ &r);
+
+ /* and extract the .out parameters */
+ *out_data = r.out.data;
+
+ talloc_destroy(mem_ctx);
+ return status;
+}
+
+
+/*
+ echodata interface
+*/
+NTSTATUS dcerpc_rpcecho_echodata(struct dcerpc_pipe *p,
+ TALLOC_CTX *mem_ctx,
+ int len,
+ const char *in_data,
+ int *out_len,
+ char **out_data)
+{
+ struct rpcecho_echodata r;
+ NTSTATUS status;
+
+ /* fill the .in side of the call */
+ r.in.len = len;
+ r.in.data = in_data;
+
+ /* make the call */
+ status = dcerpc_ndr_request(p, RPCECHO_CALL_ECHODATA, mem_ctx,
+ (ndr_push_fn_t) ndr_push_rpcecho_echodata,
+ (ndr_pull_fn_t) ndr_pull_rpcecho_echodata,
+ &r);
+
+ /* and extract the .out parameters */
+ *out_len = r.out.len;
+ *out_data = r.out.data;
+
+ return status;
+}
+
+/*
+ sourcedata interface
+*/
+NTSTATUS dcerpc_rpcecho_sourcedata(struct dcerpc_pipe *p,
+ TALLOC_CTX *mem_ctx,
+ int len,
+ int *out_len,
+ char **out_data)
+{
+ struct rpcecho_sourcedata r;
+ NTSTATUS status;
+
+ /* fill the .in side of the call */
+ r.in.len = len;
+
+ /* make the call */
+ status = dcerpc_ndr_request(p, RPCECHO_CALL_SOURCEDATA, mem_ctx,
+ (ndr_push_fn_t) ndr_push_rpcecho_sourcedata,
+ (ndr_pull_fn_t) ndr_pull_rpcecho_sourcedata,
+ &r);
+
+ /* and extract the .out parameters */
+ *out_len = r.out.len;
+ *out_data = r.out.data;
+
+ return status;
+}
+
+/*
+ sinkdata interface
+*/
+NTSTATUS dcerpc_rpcecho_sinkdata(struct dcerpc_pipe *p,
+ TALLOC_CTX *mem_ctx,
+ int len,
+ char *data)
+{
+ struct rpcecho_sinkdata r;
+ NTSTATUS status;
+
+ /* fill the .in side of the call */
+ r.in.len = len;
+ r.in.data = data;
+
+ /* make the call */
+ status = dcerpc_ndr_request(p, RPCECHO_CALL_SINKDATA, mem_ctx,
+ (ndr_push_fn_t) ndr_push_rpcecho_sinkdata,
+ (ndr_pull_fn_t) ndr_pull_rpcecho_sinkdata,
+ &r);
+
+ return status;
+}
diff --git a/source4/librpc/rpc/rpc_lsa.c b/source4/librpc/rpc/rpc_lsa.c
new file mode 100644
index 0000000000..2aa3f78730
--- /dev/null
+++ b/source4/librpc/rpc/rpc_lsa.c
@@ -0,0 +1,149 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ rpc lsa pipe calls
+
+ 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"
+
+
+NTSTATUS ndr_push_lsa_OpenPolicy(struct ndr_push *ndr, struct lsa_OpenPolicy *r);
+NTSTATUS ndr_push_lsa_OpenPolicy2(struct ndr_push *ndr, struct lsa_OpenPolicy2 *r);
+NTSTATUS ndr_push_lsa_EnumSids(struct ndr_push *ndr, struct lsa_EnumSids *r);
+
+/*
+ OpenPolicy interface
+*/
+NTSTATUS dcerpc_lsa_OpenPolicy(struct dcerpc_pipe *p,
+ const char *server,
+ struct lsa_ObjectAttribute *attr,
+ uint32 access_mask,
+ struct policy_handle *handle)
+{
+ struct lsa_OpenPolicy r;
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx;
+ uint16 s;
+
+ mem_ctx = talloc_init("dcerpc_lsa_openpolicy");
+ if (!mem_ctx) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* fill the .in side of the call */
+ s = server[0];
+ r.in.system_name = &s;
+ r.in.attr = attr;
+ r.in.desired_access = access_mask;
+
+ /* make the call */
+ status = dcerpc_ndr_request(p, LSA_OPENPOLICY, mem_ctx,
+ (ndr_push_fn_t) ndr_push_lsa_OpenPolicy,
+ (ndr_pull_fn_t) ndr_pull_lsa_OpenPolicy,
+ &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ /* and extract the .out parameters */
+ *handle = *r.out.handle;
+ status = r.out.result;
+
+done:
+ talloc_destroy(mem_ctx);
+ return status;
+}
+
+
+/*
+ OpenPolicy2 interface
+*/
+NTSTATUS dcerpc_lsa_OpenPolicy2(struct dcerpc_pipe *p,
+ const char *server,
+ struct lsa_ObjectAttribute *attr,
+ uint32 access_mask,
+ struct policy_handle *handle)
+{
+ struct lsa_OpenPolicy2 r;
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_init("dcerpc_lsa_openpolicy2");
+ if (!mem_ctx) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* fill the .in side of the call */
+ r.in.system_name = server;
+ r.in.attr = attr;
+ r.in.desired_access = access_mask;
+
+ /* make the call */
+ status = dcerpc_ndr_request(p, LSA_OPENPOLICY2, mem_ctx,
+ (ndr_push_fn_t) ndr_push_lsa_OpenPolicy2,
+ (ndr_pull_fn_t) ndr_pull_lsa_OpenPolicy2,
+ &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ /* and extract the .out parameters */
+ *handle = *r.out.handle;
+ status = r.out.result;
+
+done:
+ talloc_destroy(mem_ctx);
+ return status;
+}
+
+/*
+ EnumSids interface
+*/
+NTSTATUS dcerpc_lsa_EnumSids(struct dcerpc_pipe *p,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle,
+ uint32 resume_handle,
+ uint32 *num_entries,
+ struct dom_sid ***sids)
+{
+ struct lsa_EnumSids r;
+ NTSTATUS status;
+
+ /* fill the .in side of the call */
+ r.in.handle = handle;
+ r.in.start_at = 0;
+ r.in.num_entries = *num_entries;
+
+ /* make the call */
+ status = dcerpc_ndr_request(p, LSA_ENUM_ACCOUNTS, mem_ctx,
+ (ndr_push_fn_t) ndr_push_lsa_EnumSids,
+ (ndr_pull_fn_t) ndr_pull_lsa_EnumSids,
+ &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ /* and extract the .out parameters */
+ *num_entries = r.out.num_entries;
+ *sids = r.out.sids;
+ status = r.out.result;
+
+done:
+ return status;
+}