diff options
Diffstat (limited to 'source4/librpc')
-rw-r--r-- | source4/librpc/idl/dcerpc.idl | 6 | ||||
-rw-r--r-- | source4/librpc/idl/misc.idl | 8 | ||||
-rw-r--r-- | source4/librpc/ndr/ndr_basic.c | 77 | ||||
-rw-r--r-- | source4/librpc/rpc/dcerpc.c | 89 | ||||
-rw-r--r-- | source4/librpc/rpc/dcerpc.h | 3 | ||||
-rw-r--r-- | source4/librpc/rpc/dcerpc_smb.c | 4 | ||||
-rw-r--r-- | source4/librpc/rpc/dcerpc_tcp.c | 2 | ||||
-rw-r--r-- | source4/librpc/rpc/dcerpc_util.c | 14 |
8 files changed, 132 insertions, 71 deletions
diff --git a/source4/librpc/idl/dcerpc.idl b/source4/librpc/idl/dcerpc.idl index cf195b6aea..ad82679576 100644 --- a/source4/librpc/idl/dcerpc.idl +++ b/source4/librpc/idl/dcerpc.idl @@ -13,8 +13,7 @@ interface dcerpc { typedef [public] struct { GUID uuid; - uint16 major_version; - uint16 minor_version; + uint32 if_version; } dcerpc_syntax_id; typedef struct { @@ -28,7 +27,7 @@ interface dcerpc uint16 max_xmit_frag; uint16 max_recv_frag; uint32 assoc_group_id; - uint8 num_contexts; + uint8 num_contexts; dcerpc_ctx_list ctx_list[num_contexts]; [flag(NDR_ALIGN8)] DATA_BLOB _pad; [flag(NDR_REMAINING)] DATA_BLOB auth_info; @@ -167,6 +166,7 @@ interface dcerpc const uint8 DCERPC_PFC_FLAG_NOCALL = 0x20; /* these offsets are needed by the signing code */ + const uint8 DCERPC_DREP_OFFSET = 4; const uint8 DCERPC_FRAG_LEN_OFFSET = 8; const uint8 DCERPC_AUTH_LEN_OFFSET = 10; diff --git a/source4/librpc/idl/misc.idl b/source4/librpc/idl/misc.idl index eb2288bc35..a1f8549eaa 100644 --- a/source4/librpc/idl/misc.idl +++ b/source4/librpc/idl/misc.idl @@ -8,6 +8,14 @@ interface misc { + typedef [public,noprint] struct { + uint32 time_low; + uint16 time_mid; + uint16 time_hi_and_version; + uint8 clock_seq[2]; + uint8 node[6]; + } GUID; + /* a domain SID. Note that unlike Samba3 this contains a pointer, so you can't copy them using assignment */ typedef [public,noprint] struct { diff --git a/source4/librpc/ndr/ndr_basic.c b/source4/librpc/ndr/ndr_basic.c index 3b5aea60ca..ed75b8c27c 100644 --- a/source4/librpc/ndr/ndr_basic.c +++ b/source4/librpc/ndr/ndr_basic.c @@ -22,6 +22,12 @@ #include "includes.h" +#define NDR_BE(ndr) ((ndr)->flags & LIBNDR_FLAG_BIGENDIAN) +#define NDR_SVAL(ndr, ofs) (NDR_BE(ndr)?RSVAL(ndr->data,ofs):SVAL(ndr->data,ofs)) +#define NDR_IVAL(ndr, ofs) (NDR_BE(ndr)?RIVAL(ndr->data,ofs):IVAL(ndr->data,ofs)) +#define NDR_SSVAL(ndr, ofs, v) do { if (NDR_BE(ndr)) { RSSVAL(ndr->data,ofs,v); } else SSVAL(ndr->data,ofs,v); } while (0) +#define NDR_SIVAL(ndr, ofs, v) do { if (NDR_BE(ndr)) { RSIVAL(ndr->data,ofs,v); } else SIVAL(ndr->data,ofs,v); } while (0) + /* parse a uint8 */ @@ -41,7 +47,7 @@ NTSTATUS ndr_pull_uint16(struct ndr_pull *ndr, uint16 *v) { NDR_PULL_ALIGN(ndr, 2); NDR_PULL_NEED_BYTES(ndr, 2); - *v = SVAL(ndr->data, ndr->offset); + *v = NDR_SVAL(ndr, ndr->offset); ndr->offset += 2; return NT_STATUS_OK; } @@ -54,7 +60,7 @@ NTSTATUS ndr_pull_uint32(struct ndr_pull *ndr, uint32 *v) { NDR_PULL_ALIGN(ndr, 4); NDR_PULL_NEED_BYTES(ndr, 4); - *v = IVAL(ndr->data, ndr->offset); + *v = NDR_IVAL(ndr, ndr->offset); ndr->offset += 4; return NT_STATUS_OK; } @@ -66,8 +72,8 @@ NTSTATUS ndr_pull_HYPER_T(struct ndr_pull *ndr, HYPER_T *v) { NDR_PULL_ALIGN(ndr, 8); NDR_PULL_NEED_BYTES(ndr, 8); - v->low = IVAL(ndr->data, ndr->offset); - v->high = IVAL(ndr->data, ndr->offset+4); + v->low = NDR_IVAL(ndr, ndr->offset); + v->high = NDR_IVAL(ndr, ndr->offset+4); ndr->offset += 8; return NT_STATUS_OK; } @@ -174,18 +180,6 @@ NTSTATUS ndr_pull_array_uint32(struct ndr_pull *ndr, int ndr_flags, uint32 *data } /* - parse a GUID -*/ -NTSTATUS ndr_pull_GUID(struct ndr_pull *ndr, int ndr_flags, GUID *guid) -{ - if (ndr_flags & NDR_SCALARS) { - return ndr_pull_bytes(ndr, guid->info, GUID_SIZE); - } - return NT_STATUS_OK; -} - - -/* push a uint8 */ NTSTATUS ndr_push_uint8(struct ndr_push *ndr, uint8 v) @@ -203,7 +197,7 @@ NTSTATUS ndr_push_uint16(struct ndr_push *ndr, uint16 v) { NDR_PUSH_ALIGN(ndr, 2); NDR_PUSH_NEED_BYTES(ndr, 2); - SSVAL(ndr->data, ndr->offset, v); + NDR_SSVAL(ndr, ndr->offset, v); ndr->offset += 2; return NT_STATUS_OK; } @@ -215,7 +209,7 @@ NTSTATUS ndr_push_uint32(struct ndr_push *ndr, uint32 v) { NDR_PUSH_ALIGN(ndr, 4); NDR_PUSH_NEED_BYTES(ndr, 4); - SIVAL(ndr->data, ndr->offset, v); + NDR_SIVAL(ndr, ndr->offset, v); ndr->offset += 4; return NT_STATUS_OK; } @@ -227,8 +221,8 @@ NTSTATUS ndr_push_HYPER_T(struct ndr_push *ndr, HYPER_T v) { NDR_PUSH_ALIGN(ndr, 8); NDR_PUSH_NEED_BYTES(ndr, 8); - SIVAL(ndr->data, ndr->offset, v.low); - SIVAL(ndr->data, ndr->offset+4, v.high); + NDR_SIVAL(ndr, ndr->offset, v.low); + NDR_SIVAL(ndr, ndr->offset+4, v.high); ndr->offset += 8; return NT_STATUS_OK; } @@ -582,17 +576,6 @@ NTSTATUS ndr_push_string(struct ndr_push *ndr, int ndr_flags, const char *s) } /* - push a GUID -*/ -NTSTATUS ndr_push_GUID(struct ndr_push *ndr, int ndr_flags, GUID *guid) -{ - if (ndr_flags & NDR_SCALARS) { - return ndr_push_bytes(ndr, guid->info, GUID_SIZE); - } - return NT_STATUS_OK; -} - -/* push a NTTIME */ NTSTATUS ndr_push_NTTIME(struct ndr_push *ndr, NTTIME t) @@ -770,26 +753,25 @@ NTSTATUS GUID_from_string(const char *s, struct GUID *guid) { uint32 time_low; uint32 time_mid, time_hi_and_version; - uint32 clock_seq_hi_and_reserved; - uint32 clock_seq_low; + uint32 clock_seq[2]; 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, + &clock_seq[0], &clock_seq[1], &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); + guid->time_low = time_low; + guid->time_mid = time_mid; + guid->time_hi_and_version = time_hi_and_version; + guid->clock_seq[0] = clock_seq[0]; + guid->clock_seq[1] = clock_seq[1]; for (i=0;i<6;i++) { - SCVAL(guid->info, 10 + i, node[i]); - } + guid->node[i] = node[i]; + } return NT_STATUS_OK; } @@ -801,12 +783,13 @@ const char *GUID_string(TALLOC_CTX *mem_ctx, const struct GUID *guid) { return talloc_asprintf(mem_ctx, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", - IVAL(guid->info, 0), SVAL(guid->info, 4), - SVAL(guid->info, 6), - guid->info[8], guid->info[9], - guid->info[10], guid->info[11], - guid->info[12], guid->info[13], - guid->info[14], guid->info[15]); + guid->time_low, guid->time_mid, + guid->time_hi_and_version, + guid->clock_seq[0], + guid->clock_seq[1], + guid->node[0], guid->node[1], + guid->node[2], guid->node[3], + guid->node[4], guid->node[5]); } void ndr_print_GUID(struct ndr_print *ndr, const char *name, const struct GUID *guid) diff --git a/source4/librpc/rpc/dcerpc.c b/source4/librpc/rpc/dcerpc.c index 3dcaca83ec..c82d8d67ab 100644 --- a/source4/librpc/rpc/dcerpc.c +++ b/source4/librpc/rpc/dcerpc.c @@ -64,6 +64,35 @@ void dcerpc_pipe_close(struct dcerpc_pipe *p) } } +/* we need to be able to get/set the fragment length without doing a full + decode */ +void dcerpc_set_frag_length(DATA_BLOB *blob, uint16 v) +{ + if (CVAL(blob->data,DCERPC_DREP_OFFSET) & 0x10) { + SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v); + } else { + RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v); + } +} + +uint16 dcerpc_get_frag_length(DATA_BLOB *blob) +{ + if (CVAL(blob->data,DCERPC_DREP_OFFSET) & 0x10) { + return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET); + } else { + return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET); + } +} + +void dcerpc_set_auth_length(DATA_BLOB *blob, uint16 v) +{ + if (CVAL(blob->data,DCERPC_DREP_OFFSET) & 0x10) { + SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v); + } else { + RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v); + } +} + /* parse a data blob into a dcerpc_packet structure. This handles both @@ -79,6 +108,10 @@ static NTSTATUS dcerpc_pull(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, return NT_STATUS_NO_MEMORY; } + if (! (CVAL(blob, DCERPC_DREP_OFFSET) & 0x10)) { + ndr->flags |= DCERPC_PULL_BIGENDIAN; + } + return ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt); } @@ -104,6 +137,10 @@ static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_pipe *p, return NT_STATUS_NO_MEMORY; } + if (! (CVAL(blob, DCERPC_DREP_OFFSET) & 0x10)) { + ndr->flags |= DCERPC_PULL_BIGENDIAN; + } + /* pull the basic packet */ status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt); if (!NT_STATUS_IS_OK(status)) { @@ -132,6 +169,10 @@ static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_pipe *p, return NT_STATUS_NO_MEMORY; } + if (! (CVAL(blob, DCERPC_DREP_OFFSET) & 0x10)) { + ndr->flags |= DCERPC_PULL_BIGENDIAN; + } + status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth); if (!NT_STATUS_IS_OK(status)) { return status; @@ -184,7 +225,7 @@ static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p, /* non-signed packets are simpler */ if (!p->auth_info || !p->ntlmssp_state) { - return dcerpc_push_auth(blob, mem_ctx, pkt, p->auth_info); + return dcerpc_push_auth(blob, mem_ctx, pkt, p->auth_info, p->flags); } ndr = ndr_push_init_ctx(mem_ctx); @@ -192,6 +233,10 @@ static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p, return NT_STATUS_NO_MEMORY; } + if (p->flags & DCERPC_PUSH_BIGENDIAN) { + ndr->flags |= LIBNDR_FLAG_BIGENDIAN; + } + status = ndr_push_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt); if (!NT_STATUS_IS_OK(status)) { return status; @@ -242,8 +287,8 @@ static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p, /* fill in the fragment length and auth_length, we can't fill in these earlier as we don't know the signature length (it could be variable length) */ - SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, blob->length); - SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, p->auth_info->credentials.length); + dcerpc_set_frag_length(blob, blob->length); + dcerpc_set_auth_length(blob, p->auth_info->credentials.length); data_blob_free(&p->auth_info->credentials); @@ -254,11 +299,15 @@ static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p, /* fill in the fixed values in a dcerpc header */ -static void init_dcerpc_hdr(struct dcerpc_packet *pkt) +static void init_dcerpc_hdr(struct dcerpc_pipe *p, struct dcerpc_packet *pkt) { pkt->rpc_vers = 5; pkt->rpc_vers_minor = 0; - pkt->drep[0] = 0x10; /* Little endian */ + if (p->flags & DCERPC_PUSH_BIGENDIAN) { + pkt->drep[0] = 0; + } else { + pkt->drep[0] = 0x10; + } pkt->drep[1] = 0; pkt->drep[2] = 0; pkt->drep[3] = 0; @@ -281,7 +330,7 @@ NTSTATUS dcerpc_bind(struct dcerpc_pipe *p, DATA_BLOB blob; struct dcerpc_syntax_id tsyntax; - init_dcerpc_hdr(&pkt); + init_dcerpc_hdr(p, &pkt); pkt.ptype = DCERPC_PKT_BIND; pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST; @@ -304,7 +353,7 @@ NTSTATUS dcerpc_bind(struct dcerpc_pipe *p, pkt.u.bind.auth_info = data_blob(NULL, 0); /* construct the NDR form of the packet */ - status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->auth_info); + status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->auth_info, p->flags); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -353,7 +402,7 @@ NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p, NTSTATUS status; DATA_BLOB blob; - init_dcerpc_hdr(&pkt); + init_dcerpc_hdr(p, &pkt); pkt.ptype = DCERPC_PKT_AUTH3; pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST; @@ -363,7 +412,7 @@ NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p, pkt.u.auth.auth_info = data_blob(NULL, 0); /* construct the NDR form of the packet */ - status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->auth_info); + status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->auth_info, p->flags); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -392,15 +441,13 @@ NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p, DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n")); return status; } - syntax.major_version = version; - syntax.minor_version = 0; + syntax.if_version = version; status = GUID_from_string(NDR_GUID, &transfer_syntax.uuid); if (!NT_STATUS_IS_OK(status)) { return status; } - transfer_syntax.major_version = NDR_GUID_VERSION; - transfer_syntax.minor_version = 0; + transfer_syntax.if_version = NDR_GUID_VERSION; return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax); } @@ -420,7 +467,7 @@ NTSTATUS dcerpc_request(struct dcerpc_pipe *p, DATA_BLOB blob, payload; uint32 remaining, chunk_size; - init_dcerpc_hdr(&pkt); + init_dcerpc_hdr(p, &pkt); remaining = stub_data_in->length; @@ -552,6 +599,12 @@ NTSTATUS dcerpc_request(struct dcerpc_pipe *p, *stub_data_out = payload; } + if (!(pkt.drep[0] & 0x10)) { + p->flags |= DCERPC_PULL_BIGENDIAN; + } else { + p->flags &= ~DCERPC_PULL_BIGENDIAN; + } + return status; } @@ -723,6 +776,10 @@ NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p, return NT_STATUS_NO_MEMORY; } + if (p->flags & DCERPC_PUSH_BIGENDIAN) { + push->flags |= LIBNDR_FLAG_BIGENDIAN; + } + /* push the structure into a blob */ status = ndr_push(push, NDR_IN, struct_ptr); if (!NT_STATUS_IS_OK(status)) { @@ -755,6 +812,10 @@ NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p, goto failed; } + if (p->flags & DCERPC_PULL_BIGENDIAN) { + pull->flags |= LIBNDR_FLAG_BIGENDIAN; + } + DEBUG(10,("rpc reply data:\n")); dump_data(10, pull->data, pull->data_size); diff --git a/source4/librpc/rpc/dcerpc.h b/source4/librpc/rpc/dcerpc.h index fa2ced2537..5d25882041 100644 --- a/source4/librpc/rpc/dcerpc.h +++ b/source4/librpc/rpc/dcerpc.h @@ -65,6 +65,9 @@ struct dcerpc_pipe { #define DCERPC_SIGN 16 #define DCERPC_SEAL 32 +#define DCERPC_PUSH_BIGENDIAN 64 +#define DCERPC_PULL_BIGENDIAN 128 + /* this is used to find pointers to calls */ diff --git a/source4/librpc/rpc/dcerpc_smb.c b/source4/librpc/rpc/dcerpc_smb.c index 9acae00249..fc71a47cf4 100644 --- a/source4/librpc/rpc/dcerpc_smb.c +++ b/source4/librpc/rpc/dcerpc_smb.c @@ -91,7 +91,7 @@ static NTSTATUS dcerpc_raw_recv(struct dcerpc_pipe *p, /* we might have recieved a partial fragment, in which case we need to pull the rest of it */ - frag_length = SVAL(payload.data, 8); + frag_length = dcerpc_get_frag_length(&payload); if (frag_length <= payload.length) { goto done; } @@ -197,7 +197,7 @@ NTSTATUS smb_secondary_request(struct dcerpc_pipe *p, return status; } - frag_length = SVAL(blob->data, 8); + frag_length = dcerpc_get_frag_length(blob); if (frag_length <= blob->length) { return status; } diff --git a/source4/librpc/rpc/dcerpc_tcp.c b/source4/librpc/rpc/dcerpc_tcp.c index 468cd9465b..b577260033 100644 --- a/source4/librpc/rpc/dcerpc_tcp.c +++ b/source4/librpc/rpc/dcerpc_tcp.c @@ -60,7 +60,7 @@ static NTSTATUS tcp_raw_recv(struct dcerpc_pipe *p, /* we might have recieved a partial fragment, in which case we need to pull the rest of it */ - frag_length = SVAL(blob1.data, 8); + frag_length = dcerpc_get_frag_length(&blob1); if (frag_length == blob1.length) { *blob = blob1; return NT_STATUS_OK; diff --git a/source4/librpc/rpc/dcerpc_util.c b/source4/librpc/rpc/dcerpc_util.c index 02e224a26f..fbc97f316d 100644 --- a/source4/librpc/rpc/dcerpc_util.c +++ b/source4/librpc/rpc/dcerpc_util.c @@ -59,7 +59,7 @@ NTSTATUS dcerpc_epm_map_tcp_port(const char *server, NTSTATUS status; struct epm_Map r; struct policy_handle handle; - GUID guid; + struct GUID guid; struct epm_twr_t twr, *twr_r; if (strcasecmp(uuid, DCERPC_EPMAPPER_UUID) == 0 || @@ -223,7 +223,8 @@ const struct dcerpc_interface_table *idl_iface_by_uuid(const char *uuid) */ NTSTATUS dcerpc_push_auth(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, struct dcerpc_packet *pkt, - struct dcerpc_auth *auth_info) + struct dcerpc_auth *auth_info, + unsigned flags) { NTSTATUS status; struct ndr_push *ndr; @@ -233,6 +234,10 @@ NTSTATUS dcerpc_push_auth(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, return NT_STATUS_NO_MEMORY; } + if (flags & DCERPC_PUSH_BIGENDIAN) { + ndr->flags |= LIBNDR_FLAG_BIGENDIAN; + } + if (auth_info) { pkt->auth_length = auth_info->credentials.length; } else { @@ -251,7 +256,7 @@ NTSTATUS dcerpc_push_auth(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, *blob = ndr_push_blob(ndr); /* fill in the frag length */ - SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, blob->length); + dcerpc_set_frag_length(blob, blob->length); return NT_STATUS_OK; } @@ -278,7 +283,8 @@ NTSTATUS dcerpc_parse_binding(TALLOC_CTX *mem_ctx, const char *s, struct dcerpc_ } options[] = { {"sign", DCERPC_SIGN}, {"seal", DCERPC_SEAL}, - {"validate", DCERPC_DEBUG_VALIDATE_BOTH} + {"validate", DCERPC_DEBUG_VALIDATE_BOTH}, + {"bigendian", DCERPC_PUSH_BIGENDIAN} }; p = strchr(s, ':'); |