diff options
author | Andrew Tridgell <tridge@samba.org> | 2003-11-23 06:28:12 +0000 |
---|---|---|
committer | Andrew Tridgell <tridge@samba.org> | 2003-11-23 06:28:12 +0000 |
commit | 800d3e0134b72135fa359fa5a239f1c68adf4ca1 (patch) | |
tree | 1f0e6cafab8f1d62dee9a3796443ab18b6394fe1 /source4 | |
parent | 02dc7536dd625e0cdee23a96e66cb41b407cdba8 (diff) | |
download | samba-800d3e0134b72135fa359fa5a239f1c68adf4ca1.tar.gz samba-800d3e0134b72135fa359fa5a239f1c68adf4ca1.tar.bz2 samba-800d3e0134b72135fa359fa5a239f1c68adf4ca1.zip |
ooh, this is fun!
I have recoded the core dcerpc packet structures (all the PDUs etc) in
terms of IDL, which means we now use pidl to generate all the code for
handling the most basic dcerpc packets. This is not normally possible
as it isn't completely valid NDR, but pidl has a number of extensions
that make it quite easy.
This also means we get the server side dcerpc
marshalling/unmarshalling code for free.
(This used to be commit 92bcad02587c3c1b31b523ee9fa46658a6cef9ff)
Diffstat (limited to 'source4')
-rw-r--r-- | source4/Makefile.in | 1 | ||||
-rw-r--r-- | source4/build/pidl/idl.gram | 2 | ||||
-rw-r--r-- | source4/build/pidl/parser.pm | 6 | ||||
-rw-r--r-- | source4/librpc/idl/dcerpc.idl | 112 | ||||
-rw-r--r-- | source4/librpc/idl/idl_types.h | 13 | ||||
-rw-r--r-- | source4/librpc/ndr/libndr.h | 16 | ||||
-rw-r--r-- | source4/librpc/ndr/ndr.c | 10 | ||||
-rw-r--r-- | source4/librpc/ndr/ndr_basic.c | 54 | ||||
-rw-r--r-- | source4/librpc/rpc/dcerpc.c | 561 | ||||
-rw-r--r-- | source4/librpc/rpc/dcerpc.h | 87 |
10 files changed, 317 insertions, 545 deletions
diff --git a/source4/Makefile.in b/source4/Makefile.in index e4d9dc6ce2..eec2447f5a 100644 --- a/source4/Makefile.in +++ b/source4/Makefile.in @@ -196,6 +196,7 @@ LIBCLIUTIL_OBJ = libcli/util/asn1.o \ LIBRAW_NDR_OBJ = librpc/ndr/ndr.o librpc/ndr/ndr_basic.o librpc/ndr/ndr_sec.o \ librpc/ndr/ndr_spoolss_buf.o \ + librpc/gen_ndr/ndr_dcerpc.o \ librpc/gen_ndr/ndr_echo.o librpc/gen_ndr/ndr_misc.o \ librpc/gen_ndr/ndr_lsa.o librpc/gen_ndr/ndr_dfs.o \ librpc/gen_ndr/ndr_samr.o librpc/gen_ndr/ndr_spoolss.o \ diff --git a/source4/build/pidl/idl.gram b/source4/build/pidl/idl.gram index 1e19ae6cf1..b79c771f98 100644 --- a/source4/build/pidl/idl.gram +++ b/source4/build/pidl/idl.gram @@ -166,7 +166,7 @@ type : text: /[\w\s\..?-]*/ -text2: /[\|\w\s\*\>\/\..?-]*/ +text2: /[\|\w\s,\*\>\/\..?-]*/ anytext: text2 '(' <commit> anytext ')' anytext {{ "$item[1]($item[4])$item[6]" }} diff --git a/source4/build/pidl/parser.pm b/source4/build/pidl/parser.pm index df05d7fdba..41976cfdc9 100644 --- a/source4/build/pidl/parser.pm +++ b/source4/build/pidl/parser.pm @@ -74,7 +74,7 @@ sub find_size_var($$) return $size; } - if ($size =~ /ndr->/) { + if ($size =~ /ndr->|\(/) { return $size; } @@ -371,6 +371,10 @@ sub ParseElementPrintScalar($$) my($var_prefix) = shift; my $cprefix = util::c_push_prefix($e); + if (util::has_property($e, "noprint")) { + return; + } + if (defined $e->{VALUE}) { pidl "\tndr_print_$e->{TYPE}(ndr, \"$e->{NAME}\", $e->{VALUE});\n"; } elsif (util::has_direct_buffers($e)) { diff --git a/source4/librpc/idl/dcerpc.idl b/source4/librpc/idl/dcerpc.idl new file mode 100644 index 0000000000..14518d6c3d --- /dev/null +++ b/source4/librpc/idl/dcerpc.idl @@ -0,0 +1,112 @@ +#include "idl_types.h" + +/* + the base dcerpc packet definitions - not traditionally coded as IDL, + but given that pidl can handle it nicely it simplifies things a lot + to do it this way +*/ +[] +interface dcerpc +{ + typedef struct { + GUID uuid; + uint32 if_version; + } dcerpc_syntax_id; + + typedef struct { + uint16 context_id; + uint8 num_transfer_syntaxes; + dcerpc_syntax_id abstract_syntax; + dcerpc_syntax_id transfer_syntaxes[num_transfer_syntaxes]; + } dcerpc_ctx_list; + + typedef struct { + uint16 max_xmit_frag; + uint16 max_recv_frag; + uint32 assoc_group_id; + uint8 num_contexts; + dcerpc_ctx_list ctx_list[num_contexts]; + [flag(NDR_ALIGN8)] DATA_BLOB _pad; + [flag(NDR_REMAINING)] DATA_BLOB auth_verifier; + } dcerpc_bind; + + typedef struct { + uint32 alloc_hint; + uint16 context_id; + uint16 opnum; + [flag(NDR_ALIGN8)] DATA_BLOB _pad; + [flag(NDR_REMAINING)] DATA_BLOB stub_and_verifier; + } dcerpc_request; + + typedef struct { + uint16 result; + uint16 reason; + dcerpc_syntax_id syntax; + } dcerpc_ack_ctx; + + typedef struct { + uint16 max_xmit_frag; + uint16 max_recv_frag; + uint32 assoc_group_id; + ascstr3 secondary_address; + [flag(NDR_ALIGN4)] DATA_BLOB _pad1; + uint8 num_results; + dcerpc_ack_ctx ctx_list[num_results]; + [flag(NDR_ALIGN8)] DATA_BLOB _pad2; + [flag(NDR_REMAINING)] DATA_BLOB auth_verifier; + } dcerpc_bind_ack; + + typedef struct { + uint16 reject_reason; + uint32 num_versions; + uint32 versions[num_versions]; + } dcerpc_bind_nak; + + typedef struct { + uint32 alloc_hint; + uint16 context_id; + uint8 cancel_count; + [flag(NDR_ALIGN8)] DATA_BLOB _pad; + [flag(NDR_REMAINING)] DATA_BLOB stub_and_verifier; + } dcerpc_response; + + typedef struct { + uint32 status; + } dcerpc_fault; + + typedef enum { + DCERPC_PKT_REQUEST=0, + DCERPC_PKT_RESPONSE=2, + DCERPC_PKT_FAULT=3, + DCERPC_PKT_BIND=11, + DCERPC_PKT_BIND_ACK=12, + DCERPC_PKT_BIND_NAK=13 + } dcerpc_pkt_type; + + typedef [nodiscriminant] union { + [case(DCERPC_PKT_REQUEST)] dcerpc_request request; + [case(DCERPC_PKT_RESPONSE)] dcerpc_response response; + [case(DCERPC_PKT_BIND)] dcerpc_bind bind; + [case(DCERPC_PKT_BIND_ACK)] dcerpc_bind_ack bind_ack; + [case(DCERPC_PKT_FAULT)] dcerpc_fault fault; + } dcerpc_payload; + + + /* pfc_flags values */ + const uint8 DCERPC_PFC_FLAG_FIRST = 0x01; + const uint8 DCERPC_PFC_FLAG_LAST = 0x02; + const uint8 DCERPC_PFC_FLAG_NOCALL = 0x20; + + typedef [public] struct { + 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 */ + + [switch_is(ptype)] dcerpc_payload u; + } dcerpc_packet; +} diff --git a/source4/librpc/idl/idl_types.h b/source4/librpc/idl/idl_types.h index ba4e8ab14d..d2bbe1ab45 100644 --- a/source4/librpc/idl/idl_types.h +++ b/source4/librpc/idl/idl_types.h @@ -1,6 +1,7 @@ #define STR_ASCII LIBNDR_FLAG_STR_ASCII #define STR_LEN4 LIBNDR_FLAG_STR_LEN4 #define STR_SIZE4 LIBNDR_FLAG_STR_SIZE4 +#define STR_SIZE2 LIBNDR_FLAG_STR_SIZE2 #define STR_NOTERM LIBNDR_FLAG_STR_NOTERM #define STR_NULLTERM LIBNDR_FLAG_STR_NULLTERM @@ -37,5 +38,15 @@ */ #define ascstr2 [flag(STR_ASCII|STR_LEN4)] string +/* + an ascii string prefixed with [size], 16 bits + null terminated +*/ +#define ascstr3 [flag(STR_ASCII|STR_SIZE2)] string + -#define NDR_NOALIGN LIBNDR_FLAG_NOALIGN +#define NDR_NOALIGN LIBNDR_FLAG_NOALIGN +#define NDR_REMAINING LIBNDR_FLAG_REMAINING +#define NDR_ALIGN2 LIBNDR_FLAG_ALIGN2 +#define NDR_ALIGN4 LIBNDR_FLAG_ALIGN4 +#define NDR_ALIGN8 LIBNDR_FLAG_ALIGN8 diff --git a/source4/librpc/ndr/libndr.h b/source4/librpc/ndr/libndr.h index 3c77646239..5c51113874 100644 --- a/source4/librpc/ndr/libndr.h +++ b/source4/librpc/ndr/libndr.h @@ -99,9 +99,16 @@ struct ndr_print { #define LIBNDR_FLAG_STR_SIZE4 (1<<4) #define LIBNDR_FLAG_STR_NOTERM (1<<5) #define LIBNDR_FLAG_STR_NULLTERM (1<<6) -#define LIBNDR_STRING_FLAGS (0x7C) +#define LIBNDR_FLAG_STR_SIZE2 (1<<7) +#define LIBNDR_STRING_FLAGS (0xFC) #define LIBNDR_FLAG_REF_ALLOC (1<<10) +#define LIBNDR_FLAG_REMAINING (1<<11) +#define LIBNDR_FLAG_ALIGN2 (1<<12) +#define LIBNDR_FLAG_ALIGN4 (1<<13) +#define LIBNDR_FLAG_ALIGN8 (1<<14) + +#define LIBNDR_ALIGN_FLAGS (LIBNDR_FLAG_ALIGN2|LIBNDR_FLAG_ALIGN4|LIBNDR_FLAG_ALIGN8) /* useful macro for debugging */ #define NDR_PRINT_DEBUG(type, p) ndr_print_debug((ndr_print_fn_t)ndr_print_ ##type, #p, p) @@ -146,6 +153,8 @@ enum ndr_err_code { } \ } while(0) +#define NDR_ALIGN(ndr, n) ndr_align_size(ndr->offset, n) + #define NDR_PULL_ALIGN(ndr, n) do { \ if (!(ndr->flags & LIBNDR_FLAG_NOALIGN)) { \ ndr->offset = (ndr->offset + (n-1)) & ~(n-1); \ @@ -176,7 +185,7 @@ enum ndr_err_code { #define NDR_ALLOC_SIZE(ndr, s, size) do { \ (s) = talloc(ndr->mem_ctx, size); \ - if (!(s)) return ndr_pull_error(ndr, NDR_ERR_ALLOC, \ + if ((size) && !(s)) return ndr_pull_error(ndr, NDR_ERR_ALLOC, \ "Alloc %u failed\n", \ size); \ } while (0) @@ -201,7 +210,7 @@ enum ndr_err_code { #define NDR_PUSH_ALLOC_SIZE(ndr, s, size) do { \ (s) = talloc(ndr->mem_ctx, size); \ - if (!(s)) return ndr_push_error(ndr, NDR_ERR_ALLOC, \ + if ((size) && !(s)) return ndr_push_error(ndr, NDR_ERR_ALLOC, \ "push alloc %u failed\n",\ size); \ } while (0) @@ -225,6 +234,7 @@ typedef void (*ndr_print_union_fn_t)(struct ndr_print *, const char *, uint32, v /* now pull in the individual parsers */ #include "librpc/ndr/ndr_basic.h" #include "librpc/ndr/ndr_sec.h" +#include "librpc/gen_ndr/ndr_dcerpc.h" #include "librpc/gen_ndr/ndr_misc.h" #include "librpc/gen_ndr/ndr_echo.h" #include "librpc/gen_ndr/ndr_lsa.h" diff --git a/source4/librpc/ndr/ndr.c b/source4/librpc/ndr/ndr.c index 44472147fd..bce4759d8a 100644 --- a/source4/librpc/ndr/ndr.c +++ b/source4/librpc/ndr/ndr.c @@ -31,6 +31,16 @@ #define NDR_BASE_MARSHALL_SIZE 1024 + +/* + work out the number of bytes needed to align on a n byte boundary +*/ +size_t ndr_align_size(uint32 offset, size_t n) +{ + if ((offset & (n-1)) == 0) return 0; + return n - (offset & (n-1)); +} + /* initialise a ndr parse structure from a data blob */ diff --git a/source4/librpc/ndr/ndr_basic.c b/source4/librpc/ndr/ndr_basic.c index 4d0be44a89..081d9ff87a 100644 --- a/source4/librpc/ndr/ndr_basic.c +++ b/source4/librpc/ndr/ndr_basic.c @@ -343,6 +343,7 @@ NTSTATUS ndr_pull_string(struct ndr_pull *ndr, int ndr_flags, const char **s) { char *as=NULL; uint32 len1, ofs, len2; + uint16 len3; int ret; if (!(ndr_flags & NDR_SCALARS)) { @@ -437,6 +438,14 @@ NTSTATUS ndr_pull_string(struct ndr_pull *ndr, int ndr_flags, const char **s) (*s) = as; break; + case LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_SIZE2: + NDR_CHECK(ndr_pull_uint16(ndr, &len3)); + NDR_ALLOC_N(ndr, as, (len3+1)); + NDR_CHECK(ndr_pull_bytes(ndr, as, len3)); + as[len3] = 0; + (*s) = as; + break; + default: return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n", ndr->flags & LIBNDR_STRING_FLAGS); @@ -546,6 +555,19 @@ NTSTATUS ndr_push_string(struct ndr_push *ndr, int ndr_flags, const char *s) ndr->offset += c_len + 1; break; + case LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_SIZE2: + NDR_CHECK(ndr_push_uint16(ndr, c_len+1)); + NDR_PUSH_NEED_BYTES(ndr, c_len + 1); + ret = convert_string(CH_UNIX, CH_DOS, + s, s_len + 1, + ndr->data+ndr->offset, c_len + 1); + if (ret == -1) { + return ndr_push_error(ndr, NDR_ERR_CHARCNV, + "Bad character conversion"); + } + ndr->offset += c_len + 1; + break; + default: return ndr_push_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n", ndr->flags & LIBNDR_STRING_FLAGS); @@ -729,7 +751,19 @@ void ndr_print_DATA_BLOB(struct ndr_print *ndr, const char *name, DATA_BLOB r) */ NTSTATUS ndr_push_DATA_BLOB(struct ndr_push *ndr, DATA_BLOB blob) { - NDR_CHECK(ndr_push_uint32(ndr, blob.length)); + if (ndr->flags & LIBNDR_ALIGN_FLAGS) { + if (ndr->flags & LIBNDR_FLAG_ALIGN2) { + blob.length = NDR_ALIGN(ndr, 2); + } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) { + blob.length = NDR_ALIGN(ndr, 4); + } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) { + blob.length = NDR_ALIGN(ndr, 8); + } + NDR_PUSH_ALLOC_SIZE(ndr, blob.data, blob.length); + data_blob_clear(&blob); + } else if (!(ndr->flags & LIBNDR_FLAG_REMAINING)) { + NDR_CHECK(ndr_push_uint32(ndr, blob.length)); + } NDR_CHECK(ndr_push_bytes(ndr, blob.data, blob.length)); return NT_STATUS_OK; } @@ -740,7 +774,23 @@ NTSTATUS ndr_push_DATA_BLOB(struct ndr_push *ndr, DATA_BLOB blob) NTSTATUS ndr_pull_DATA_BLOB(struct ndr_pull *ndr, DATA_BLOB *blob) { uint32 length; - NDR_CHECK(ndr_pull_uint32(ndr, &length)); + + if (ndr->flags & LIBNDR_ALIGN_FLAGS) { + if (ndr->flags & LIBNDR_FLAG_ALIGN2) { + length = NDR_ALIGN(ndr, 2); + } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) { + length = NDR_ALIGN(ndr, 4); + } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) { + length = NDR_ALIGN(ndr, 8); + } + if (ndr->data_size - ndr->offset < length) { + length = ndr->data_size - ndr->offset; + } + } else if (ndr->flags & LIBNDR_FLAG_REMAINING) { + length = ndr->data_size - ndr->offset; + } else { + NDR_CHECK(ndr_pull_uint32(ndr, &length)); + } NDR_PULL_NEED_BYTES(ndr, length); *blob = data_blob_talloc(ndr->mem_ctx, ndr->data+ndr->offset, length); ndr->offset += length; diff --git a/source4/librpc/rpc/dcerpc.c b/source4/librpc/rpc/dcerpc.c index 2cb52ece0b..6a8b867136 100644 --- a/source4/librpc/rpc/dcerpc.c +++ b/source4/librpc/rpc/dcerpc.c @@ -59,446 +59,94 @@ void dcerpc_pipe_close(struct dcerpc_pipe *p) } } -#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 + build a GUID from a string */ -static NTSTATUS push_syntax_id(char *data, const struct dcerpc_syntax_id *syntax) +static NTSTATUS guid_from_string(const char *s, struct GUID *guid) { - 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 = SVAL(blob->data, *offset); - pkt->ctx_list[i].reason = SVAL(blob->data, 2 + *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; + 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(s, "%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(guid->info, 0, time_low); + SSVAL(guid->info, 4, time_mid); + SSVAL(guid->info, 6, time_hi_and_version); + SCVAL(guid->info, 8, clock_seq_hi_and_reserved); + SCVAL(guid->info, 9, clock_seq_low); + for (i=0;i<6;i++) { + SCVAL(guid->info, 10 + i, node[i]); + } + + 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; + struct ndr_pull *ndr; - 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_NET_WRITE_FAULT; - } - - 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; - } + ndr = ndr_pull_init_blob(blob, mem_ctx); + if (!ndr) { + return NT_STATUS_NO_MEMORY; } - 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; + return ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt); } -/* - 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; + struct ndr_push *ndr; 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) { + ndr = ndr_push_init_ctx(mem_ctx); + if (!ndr) { return NT_STATUS_NO_MEMORY; } - pkt->hdr.frag_length = wire_size; - - dcerpc_push_hdr(blob->data + offset, &pkt->hdr); - offset += 16; + status = ndr_push_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt); + if (!NT_STATUS_IS_OK(status)) { + return status; + } - switch (pkt->hdr.ptype) { - case DCERPC_PKT_BIND: - status = dcerpc_push_bind(blob, &offset, &pkt->hdr, &pkt->in.bind); - break; + *blob = ndr_push_blob(ndr); - case DCERPC_PKT_REQUEST: - status = dcerpc_push_request(blob, &offset, &pkt->hdr, &pkt->in.request); - break; - - default: - status = NT_STATUS_NET_WRITE_FAULT; - } + /* fill in the frag length */ + SSVAL(blob->data, 8, blob->length); return status; } - - /* fill in the fixed values in a dcerpc header */ -static void init_dcerpc_hdr(struct dcerpc_hdr *hdr) +static void init_dcerpc_hdr(struct dcerpc_packet *pkt) { - 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; + pkt->rpc_vers = 5; + pkt->rpc_vers_minor = 0; + pkt->drep[0] = 0x10; /* Little endian */ + pkt->drep[1] = 0; + pkt->drep[2] = 0; + pkt->drep[3] = 0; } @@ -510,38 +158,39 @@ NTSTATUS dcerpc_bind(struct dcerpc_pipe *p, const struct dcerpc_syntax_id *transfer_syntax) { TALLOC_CTX *mem_ctx; - struct dcerpc_packet pkt; + struct dcerpc_packet pkt; NTSTATUS status; DATA_BLOB blob; DATA_BLOB blob_out; + struct dcerpc_syntax_id tsyntax; mem_ctx = talloc_init("dcerpc_bind"); if (!mem_ctx) { return NT_STATUS_NO_MEMORY; } - init_dcerpc_hdr(&pkt.hdr); + init_dcerpc_hdr(&pkt); - 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.ptype = DCERPC_PKT_BIND; + pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST; + pkt.call_id = p->call_id++; + pkt.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) { + pkt.u.bind.max_xmit_frag = 0x2000; + pkt.u.bind.max_recv_frag = 0x2000; + pkt.u.bind.assoc_group_id = 0; + pkt.u.bind.num_contexts = 1; + pkt.u.bind.ctx_list = talloc(mem_ctx, sizeof(pkt.u.bind.ctx_list[0])); + if (!pkt.u.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); + pkt.u.bind.ctx_list[0].context_id = 0; + pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1; + pkt.u.bind.ctx_list[0].abstract_syntax = *syntax; + tsyntax = *transfer_syntax; + pkt.u.bind.ctx_list[0].transfer_syntaxes = &tsyntax; + pkt.u.bind.auth_verifier = data_blob(NULL, 0); status = dcerpc_push(&blob, mem_ctx, &pkt); if (!NT_STATUS_IS_OK(status)) { @@ -561,14 +210,14 @@ NTSTATUS dcerpc_bind(struct dcerpc_pipe *p, return status; } - if (pkt.hdr.ptype != DCERPC_PKT_BIND_ACK || - pkt.out.bind_ack.num_results == 0 || - pkt.out.bind_ack.ctx_list[0].result != 0) { + if (pkt.ptype != DCERPC_PKT_BIND_ACK || + pkt.u.bind_ack.num_results == 0 || + pkt.u.bind_ack.ctx_list[0].result != 0) { 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; + p->srv_max_xmit_frag = pkt.u.bind_ack.max_xmit_frag; + p->srv_max_recv_frag = pkt.u.bind_ack.max_recv_frag; talloc_destroy(mem_ctx); @@ -581,11 +230,20 @@ NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p, { struct dcerpc_syntax_id syntax; struct dcerpc_syntax_id transfer_syntax; + NTSTATUS status; - syntax.uuid_str = uuid; + status = guid_from_string(uuid, &syntax.uuid); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n")); + return status; + } syntax.if_version = version; - transfer_syntax.uuid_str = "8a885d04-1ceb-11c9-9fe8-08002b104860"; + status = guid_from_string("8a885d04-1ceb-11c9-9fe8-08002b104860", + &transfer_syntax.uuid); + if (!NT_STATUS_IS_OK(status)) { + return status; + } transfer_syntax.if_version = 2; return dcerpc_bind(p, &syntax, &transfer_syntax); @@ -606,7 +264,7 @@ NTSTATUS dcerpc_request(struct dcerpc_pipe *p, DATA_BLOB blob_in, blob_out, payload; uint32 remaining, chunk_size; - init_dcerpc_hdr(&pkt.hdr); + init_dcerpc_hdr(&pkt); remaining = stub_data_in->length; @@ -614,26 +272,25 @@ NTSTATUS dcerpc_request(struct dcerpc_pipe *p, 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); + pkt.ptype = DCERPC_PKT_REQUEST; + pkt.call_id = p->call_id++; + pkt.auth_length = 0; + pkt.u.request.alloc_hint = remaining; + pkt.u.request.context_id = 0; + pkt.u.request.opnum = opnum; /* 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; + pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST; } else { - pkt.hdr.pfc_flags = 0; + pkt.pfc_flags = 0; } - pkt.in.request.stub_data.data = stub_data_in->data + + pkt.u.request.stub_and_verifier.data = stub_data_in->data + (stub_data_in->length - remaining); - pkt.in.request.stub_data.length = chunk_size; + pkt.u.request.stub_and_verifier.length = chunk_size; status = dcerpc_push(&blob_in, mem_ctx, &pkt); if (!NT_STATUS_IS_OK(status)) { @@ -651,14 +308,14 @@ NTSTATUS dcerpc_request(struct dcerpc_pipe *p, /* 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; + pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST; } else { - pkt.hdr.pfc_flags = DCERPC_PFC_FLAG_LAST; + pkt.pfc_flags = DCERPC_PFC_FLAG_LAST; } - pkt.in.request.stub_data.data = stub_data_in->data + + pkt.u.request.stub_and_verifier.data = stub_data_in->data + (stub_data_in->length - remaining); - pkt.in.request.stub_data.length = remaining; - + pkt.u.request.stub_and_verifier.length = remaining; + status = dcerpc_push(&blob_in, mem_ctx, &pkt); if (!NT_STATUS_IS_OK(status)) { return status; @@ -672,19 +329,23 @@ NTSTATUS dcerpc_request(struct dcerpc_pipe *p, return status; } - if (pkt.hdr.ptype != DCERPC_PKT_RESPONSE) { + if (pkt.ptype == DCERPC_PKT_FAULT) { + return NT_STATUS_NET_WRITE_FAULT; + } + + if (pkt.ptype != DCERPC_PKT_RESPONSE) { return NT_STATUS_UNSUCCESSFUL; } - if (!(pkt.hdr.pfc_flags & DCERPC_PFC_FLAG_FIRST)) { + if (!(pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) { /* something is badly wrong! */ return NT_STATUS_UNSUCCESSFUL; } - payload = pkt.out.response.stub_data; + payload = pkt.u.response.stub_and_verifier; /* continue receiving fragments */ - while (!(pkt.hdr.pfc_flags & DCERPC_PFC_FLAG_LAST)) { + while (!(pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) { uint32 length; status = dcerpc_raw_packet_secondary(p, mem_ctx, &blob_out); @@ -697,16 +358,16 @@ NTSTATUS dcerpc_request(struct dcerpc_pipe *p, return status; } - if (pkt.hdr.pfc_flags & DCERPC_PFC_FLAG_FIRST) { + if (pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST) { /* start of another packet!? */ return NT_STATUS_UNSUCCESSFUL; } - if (pkt.hdr.ptype != DCERPC_PKT_RESPONSE) { + if (pkt.ptype != DCERPC_PKT_RESPONSE) { return NT_STATUS_UNSUCCESSFUL; } - length = pkt.out.response.stub_data.length; + length = pkt.u.response.stub_and_verifier.length; payload.data = talloc_realloc(mem_ctx, payload.data, @@ -716,7 +377,7 @@ NTSTATUS dcerpc_request(struct dcerpc_pipe *p, } memcpy(payload.data + payload.length, - pkt.out.response.stub_data.data, + pkt.u.response.stub_and_verifier.data, length); payload.length += length; diff --git a/source4/librpc/rpc/dcerpc.h b/source4/librpc/rpc/dcerpc.h index 65566878e3..ec6189302a 100644 --- a/source4/librpc/rpc/dcerpc.h +++ b/source4/librpc/rpc/dcerpc.h @@ -40,18 +40,6 @@ struct dcerpc_pipe { unsigned flags; }; -/* 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 - /* dcerpc pipe flags */ #define DCERPC_DEBUG_PRINT_IN 1 #define DCERPC_DEBUG_PRINT_OUT 2 @@ -60,78 +48,3 @@ struct dcerpc_pipe { #define DCERPC_DEBUG_VALIDATE_IN 4 #define DCERPC_DEBUG_VALIDATE_OUT 8 #define DCERPC_DEBUG_VALIDATE_BOTH (DCERPC_DEBUG_VALIDATE_IN | DCERPC_DEBUG_VALIDATE_OUT) - -/* - 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 { - uint16 result; - uint16 reason; - 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; -}; - |