diff options
author | Andrew Tridgell <tridge@samba.org> | 2003-11-06 12:34:04 +0000 |
---|---|---|
committer | Andrew Tridgell <tridge@samba.org> | 2003-11-06 12:34:04 +0000 |
commit | 4fa0f615f286631820316f8c87dd61eda494e203 (patch) | |
tree | c06fd75490e2de5cf5692154148b24209fef2fcd /source4/librpc/rpc | |
parent | fa3db33a5441ed31f9d8c19dc6984d160b86e4da (diff) | |
download | samba-4fa0f615f286631820316f8c87dd61eda494e203.tar.gz samba-4fa0f615f286631820316f8c87dd61eda494e203.tar.bz2 samba-4fa0f615f286631820316f8c87dd61eda494e203.zip |
another major bit of restructuring of rpc in Samba4. Mostly moving
files around, but also added the first bits of auto-generated code for
the lsa pipe.
I haven't updated the Makefile to call pidl yet, so for now the code
was cut-and-pasted into librpc/ndr/ndr_lsa.c manually
(This used to be commit 6b222d3b6541ee74cf8bf3f0913cd444903ca991)
Diffstat (limited to 'source4/librpc/rpc')
-rw-r--r-- | source4/librpc/rpc/dcerpc.c | 804 | ||||
-rw-r--r-- | source4/librpc/rpc/dcerpc.h | 129 | ||||
-rw-r--r-- | source4/librpc/rpc/dcerpc_smb.c | 320 | ||||
-rw-r--r-- | source4/librpc/rpc/rpc_echo.c | 137 | ||||
-rw-r--r-- | source4/librpc/rpc/rpc_lsa.c | 149 |
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; +} |