diff options
author | Simo Sorce <idra@samba.org> | 2010-07-15 20:50:06 -0400 |
---|---|---|
committer | Simo Sorce <idra@samba.org> | 2010-07-15 20:50:06 -0400 |
commit | 2f249538ac8f2a54d9c8f8dbf0107db2f33bfe16 (patch) | |
tree | 00eb61080648488e0d4d5e370f4d30827f4e9228 /source3 | |
parent | 0ab8e8be62bcbb1f6441f745736fcee7cbd559eb (diff) | |
parent | 5f8678f34be57ccbbf9d9c93ee34b1d8f09c75c4 (diff) | |
download | samba-2f249538ac8f2a54d9c8f8dbf0107db2f33bfe16.tar.gz samba-2f249538ac8f2a54d9c8f8dbf0107db2f33bfe16.tar.bz2 samba-2f249538ac8f2a54d9c8f8dbf0107db2f33bfe16.zip |
Merge branch 'master' of ssh://git.samba.org/data/git/samba
Diffstat (limited to 'source3')
25 files changed, 1387 insertions, 2211 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in index b980b7f25c..9676b37927 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -354,10 +354,9 @@ LIBNDR_GEN_OBJ = librpc/gen_ndr/ndr_wkssvc.o \ # this includes only the low level parse code, not stuff # that requires knowledge of security contexts -RPC_PARSE_OBJ1 = rpc_parse/parse_prs.o rpc_parse/parse_misc.o +REG_PARSE_PRS_OBJ = registry/reg_parse_prs.o -RPC_PARSE_OBJ2 = rpc_parse/parse_rpc.o \ - rpc_client/init_netlogon.o \ +RPC_PARSE_OBJ2 = rpc_client/init_netlogon.o \ rpc_client/init_lsa.o LIBREPLACE_OBJ = @LIBREPLACE_OBJS@ @@ -488,7 +487,7 @@ LIBSMB_ERR_OBJ0 = $(NTERR_OBJ) $(DOSERR_OBJ) $(ERRORMAP_OBJ) $(DCE_RPC_ERR_OBJ) LIBSMB_ERR_OBJ1 = ../libcli/auth/smbdes.o ../libcli/auth/smbencrypt.o ../libcli/auth/msrpc_parse.o ../libcli/auth/session.o LIBSMB_ERR_OBJ = $(LIBSMB_ERR_OBJ0) $(LIBSMB_ERR_OBJ1) \ - $(RPC_PARSE_OBJ1) \ + $(REG_PARSE_PRS_OBJ) \ $(SECRETS_OBJ) LIBSMB_OBJ0 = \ @@ -565,6 +564,7 @@ LIBMSRPC_GEN_OBJ = librpc/gen_ndr/cli_lsa.o \ librpc/gen_ndr/cli_drsuapi.o \ librpc/gen_ndr/cli_spoolss.o \ ../librpc/rpc/dcerpc_util.o \ + librpc/rpc/dcerpc_helpers.o \ $(LIBNDR_GEN_OBJ) \ $(RPCCLIENT_NDR_OBJ) diff --git a/source3/client/client.c b/source3/client/client.c index 416a4bb6cf..326c23e657 100644 --- a/source3/client/client.c +++ b/source3/client/client.c @@ -1717,6 +1717,7 @@ static int do_put(const char *rname, const char *lname, bool reput) &state); if (!NT_STATUS_IS_OK(status)) { d_fprintf(stderr, "cli_push returned %s\n", nt_errstr(status)); + rc = 1; } if (!NT_STATUS_IS_OK(cli_close(targetcli, fnum))) { diff --git a/source3/include/ntdomain.h b/source3/include/ntdomain.h index d0006923ff..629e51cea3 100644 --- a/source3/include/ntdomain.h +++ b/source3/include/ntdomain.h @@ -28,46 +28,11 @@ * in the NTDOM branch - it didn't belong there. */ -#define prs_init_empty( _ps_, _ctx_, _io_ ) (void) prs_init((_ps_), 0, (_ctx_), (_io_)) - -typedef struct _prs_struct { - bool io; /* parsing in or out of data stream */ - /* - * If the (incoming) data is big-endian. On output we are - * always little-endian. - */ - bool bigendian_data; - uint8 align; /* data alignment */ - bool is_dynamic; /* Do we own this memory or not ? */ - uint32 data_offset; /* Current working offset into data. */ - uint32 buffer_size; /* Current allocated size of the buffer. */ - uint32 grow_size; /* size requested via prs_grow() calls */ - /* The buffer itself. If "is_dynamic" is true this - * MUST BE TALLOC'ed off mem_ctx. */ - char *data_p; - TALLOC_CTX *mem_ctx; /* When unmarshalling, use this.... */ -} prs_struct; - -/* - * Defines for io member of prs_struct. - */ - -#define MARSHALL 0 -#define UNMARSHALL 1 - -#define MARSHALLING(ps) (!(ps)->io) -#define UNMARSHALLING(ps) ((ps)->io) - -#define RPC_BIG_ENDIAN 1 -#define RPC_LITTLE_ENDIAN 0 - -#define RPC_PARSE_ALIGN 4 - typedef struct _output_data { /* * Raw RPC output data. This does not include RPC headers or footers. */ - prs_struct rdata; + DATA_BLOB rdata; /* The amount of data sent from the current rdata struct. */ uint32 data_sent_length; @@ -76,7 +41,7 @@ typedef struct _output_data { * The current fragment being returned. This inclues * headers, data and authentication footer. */ - prs_struct frag; + DATA_BLOB frag; /* The amount of data sent from the current PDU. */ uint32 current_pdu_sent; @@ -105,7 +70,8 @@ typedef struct _input_data { * the rpc headers and auth footers removed. * The maximum length of this (1Mb) is strictly enforced. */ - prs_struct data; + DATA_BLOB data; + } input_data; struct handle_list; diff --git a/source3/include/proto.h b/source3/include/proto.h index cfa68da723..ad16e7e52f 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -4838,44 +4838,20 @@ void set_profile_level(int level, struct server_id src); bool profile_setup(struct messaging_context *msg_ctx, bool rdonly); /* The following definitions come from rpc_client/cli_pipe.c */ +bool smb_register_ndr_interface(const struct ndr_interface_table *interface); +const struct ndr_interface_table *get_iface_from_syntax( + const struct ndr_syntax_id *syntax); +const char *get_pipe_name_from_syntax(TALLOC_CTX *mem_ctx, + const struct ndr_syntax_id *syntax); +enum dcerpc_AuthType map_pipe_auth_type_to_rpc_auth_type(enum pipe_auth_type auth_type); struct tevent_req *rpc_api_pipe_req_send(TALLOC_CTX *mem_ctx, struct event_context *ev, struct rpc_pipe_client *cli, uint8_t op_num, - prs_struct *req_data); + DATA_BLOB *req_data); NTSTATUS rpc_api_pipe_req_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, - prs_struct *reply_pdu); -NTSTATUS dcerpc_push_ncacn_packet(TALLOC_CTX *mem_ctx, - enum dcerpc_pkt_type ptype, - uint8_t pfc_flags, - uint16_t auth_length, - uint32_t call_id, - union dcerpc_payload *u, - DATA_BLOB *blob); -NTSTATUS dcerpc_push_ncacn_packet_header(TALLOC_CTX *mem_ctx, - enum dcerpc_pkt_type ptype, - uint8_t pfc_flags, - uint16_t frag_length, - uint16_t auth_length, - uint32_t call_id, - DATA_BLOB *blob); -NTSTATUS dcerpc_pull_ncacn_packet(TALLOC_CTX *mem_ctx, - const DATA_BLOB *blob, - struct ncacn_packet *r); -NTSTATUS dcerpc_pull_ncacn_packet_header(TALLOC_CTX *mem_ctx, - const DATA_BLOB *blob, - struct ncacn_packet_header *r); -NTSTATUS dcerpc_push_dcerpc_auth(TALLOC_CTX *mem_ctx, - enum dcerpc_AuthType auth_type, - enum dcerpc_AuthLevel auth_level, - uint8_t auth_pad_length, - uint32_t auth_context_id, - const DATA_BLOB *credentials, - DATA_BLOB *blob); -NTSTATUS dcerpc_pull_dcerpc_auth(TALLOC_CTX *mem_ctx, - const DATA_BLOB *blob, - struct dcerpc_auth *r); + DATA_BLOB *reply_pdu); struct tevent_req *rpc_pipe_bind_send(TALLOC_CTX *mem_ctx, struct event_context *ev, struct rpc_pipe_client *cli, @@ -5042,77 +5018,6 @@ NTSTATUS cli_do_rpc_ndr(struct rpc_pipe_client *cli, const struct ndr_interface_table *table, uint32 opnum, void *r); -/* The following definitions come from rpc_parse/parse_misc.c */ - -bool smb_io_time(const char *desc, NTTIME *nttime, prs_struct *ps, int depth); -bool smb_io_uuid(const char *desc, struct GUID *uuid, - prs_struct *ps, int depth); - -/* The following definitions come from rpc_parse/parse_prs.c */ - -void prs_dump(const char *name, int v, prs_struct *ps); -void prs_dump_before(const char *name, int v, prs_struct *ps); -void prs_dump_region(const char *name, int v, prs_struct *ps, - int from_off, int to_off); -void prs_debug(prs_struct *ps, int depth, const char *desc, const char *fn_name); -bool prs_init(prs_struct *ps, uint32 size, TALLOC_CTX *ctx, bool io); -void prs_mem_free(prs_struct *ps); -void prs_mem_clear(prs_struct *ps); -char *prs_alloc_mem_(prs_struct *ps, size_t size, unsigned int count); -char *prs_alloc_mem(prs_struct *ps, size_t size, unsigned int count); -TALLOC_CTX *prs_get_mem_context(prs_struct *ps); -void prs_give_memory(prs_struct *ps, char *buf, uint32 size, bool is_dynamic); -bool prs_set_buffer_size(prs_struct *ps, uint32 newsize); -bool prs_grow(prs_struct *ps, uint32 extra_space); -bool prs_force_grow(prs_struct *ps, uint32 extra_space); -char *prs_data_p(prs_struct *ps); -uint32 prs_data_size(prs_struct *ps); -uint32 prs_offset(prs_struct *ps); -bool prs_set_offset(prs_struct *ps, uint32 offset); -bool prs_append_prs_data(prs_struct *dst, prs_struct *src); -bool prs_append_some_data(prs_struct *dst, void *src_base, uint32_t start, - uint32_t len); -bool prs_append_some_prs_data(prs_struct *dst, prs_struct *src, int32 start, uint32 len); -bool prs_copy_data_in(prs_struct *dst, const char *src, uint32 len); -bool prs_copy_data_out(char *dst, prs_struct *src, uint32 len); -bool prs_copy_all_data_out(char *dst, prs_struct *src); -void prs_set_endian_data(prs_struct *ps, bool endian); -bool prs_align(prs_struct *ps); -bool prs_align_uint16(prs_struct *ps); -bool prs_align_uint64(prs_struct *ps); -bool prs_align_custom(prs_struct *ps, uint8 boundary); -bool prs_align_needed(prs_struct *ps, uint32 needed); -char *prs_mem_get(prs_struct *ps, uint32 extra_size); -void prs_switch_type(prs_struct *ps, bool io); -bool prs_uint8(const char *name, prs_struct *ps, int depth, uint8 *data8); -bool prs_uint16(const char *name, prs_struct *ps, int depth, uint16 *data16); -bool prs_uint32(const char *name, prs_struct *ps, int depth, uint32 *data32); -bool prs_int32(const char *name, prs_struct *ps, int depth, int32 *data32); -bool prs_uint64(const char *name, prs_struct *ps, int depth, uint64 *data64); -bool prs_dcerpc_status(const char *name, prs_struct *ps, int depth, NTSTATUS *status); -bool prs_uint8s(bool charmode, const char *name, prs_struct *ps, int depth, uint8 *data8s, int len); -bool prs_uint16s(bool charmode, const char *name, prs_struct *ps, int depth, uint16 *data16s, int len); -bool prs_uint32s(bool charmode, const char *name, prs_struct *ps, int depth, uint32 *data32s, int len); -bool prs_init_data_blob(prs_struct *prs, DATA_BLOB *blob, TALLOC_CTX *mem_ctx); -bool prs_data_blob(prs_struct *prs, DATA_BLOB *blob, TALLOC_CTX *mem_ctx); - -/* The following definitions come from rpc_parse/parse_rpc.c */ - -bool smb_register_ndr_interface(const struct ndr_interface_table *interface); -const struct ndr_interface_table *get_iface_from_syntax( - const struct ndr_syntax_id *syntax); -const char *get_pipe_name_from_syntax(TALLOC_CTX *mem_ctx, - const struct ndr_syntax_id *syntax); -NTSTATUS dcerpc_pull_dcerpc_bind(TALLOC_CTX *mem_ctx, - const DATA_BLOB *blob, - struct dcerpc_bind *r); -bool smb_io_rpc_hdr_resp(const char *desc, RPC_HDR_RESP *rpc, prs_struct *ps, int depth); -void init_rpc_hdr_auth(RPC_HDR_AUTH *rai, - uint8 auth_type, uint8 auth_level, - uint8 auth_pad_len, - uint32 auth_context_id); -bool smb_io_rpc_hdr_auth(const char *desc, RPC_HDR_AUTH *rai, prs_struct *ps, int depth); - /* The following definitions come from rpc_server/srv_eventlog_nt.c */ /* The following definitions come from rpc_server/rpc_handles.c */ diff --git a/source3/include/regfio.h b/source3/include/regfio.h index 840fbcd89a..f2d952b169 100644 --- a/source3/include/regfio.h +++ b/source3/include/regfio.h @@ -23,6 +23,7 @@ * Thanks Nigel! ***********************************************************/ +#include "registry/reg_parse_prs.h" #ifndef _REGFIO_H #define _REGFIO_H diff --git a/source3/include/rpc_dce.h b/source3/include/rpc_dce.h index 202382781e..7be8a8a6f7 100644 --- a/source3/include/rpc_dce.h +++ b/source3/include/rpc_dce.h @@ -22,7 +22,7 @@ #ifndef _DCE_RPC_H /* _DCE_RPC_H */ #define _DCE_RPC_H -#define RPC_AUTH_SCHANNEL_SIGN_OR_SEAL_CHK_LEN 0x20 +#define SCHANNEL_SIG_SIZE 0x20 /* Maximum size of the signing data in a fragment. */ #define RPC_MAX_SIGN_SIZE 0x38 /* 56 */ @@ -31,31 +31,9 @@ /* #define MAX_PDU_FRAG_LEN 0x1630 this is what wnt sets */ #define RPC_MAX_PDU_FRAG_LEN 0x10b8 /* this is what w2k sets */ -#define RPC_IFACE_LEN (UUID_SIZE + 4) - #define RPC_HEADER_LEN 16 -#define RPC_HDR_REQ_LEN 8 - -/* RPC_HDR_RESP - ms response rpc header */ -typedef struct rpc_hdr_resp_info { - uint32 alloc_hint; /* allocation hint - data size (bytes) minus header and tail. */ - uint16 context_id; /* 0 - presentation context identifier */ - uint8 cancel_count; /* 0 - cancel count */ - uint8 reserved; /* 0 - reserved. */ -} RPC_HDR_RESP; - -#define RPC_HDR_RESP_LEN 8 - -/* RPC_HDR_AUTH */ -typedef struct rpc_hdr_auth_info { - uint8 auth_type; /* See XXX_AUTH_TYPE above. */ - uint8 auth_level; /* See RPC_PIPE_AUTH_XXX_LEVEL above. */ - uint8 auth_pad_len; - uint8 auth_reserved; - uint32 auth_context_id; -} RPC_HDR_AUTH; - -#define RPC_HDR_AUTH_LEN 8 +#define RPC_BIG_ENDIAN 1 +#define RPC_LITTLE_ENDIAN 0 #endif /* _DCE_RPC_H */ diff --git a/source3/include/smb_macros.h b/source3/include/smb_macros.h index e5af20bac3..757c8a2c1e 100644 --- a/source3/include/smb_macros.h +++ b/source3/include/smb_macros.h @@ -273,8 +273,6 @@ NULL returns on zero request. JRA. #if defined(PARANOID_MALLOC_CHECKER) -#define PRS_ALLOC_MEM(ps, type, count) (type *)prs_alloc_mem_((ps),sizeof(type),(count)) - /* Get medieval on our ass about malloc.... */ /* Restrictions on malloc/realloc/calloc. */ @@ -311,8 +309,6 @@ NULL returns on zero request. JRA. #else -#define PRS_ALLOC_MEM(ps, type, count) (type *)prs_alloc_mem((ps),sizeof(type),(count)) - /* Regular malloc code. */ #define SMB_MALLOC(s) malloc(s) diff --git a/source3/librpc/gen_ndr/README b/source3/librpc/gen_ndr/README deleted file mode 100644 index 0c1fd160a5..0000000000 --- a/source3/librpc/gen_ndr/README +++ /dev/null @@ -1 +0,0 @@ -This contains the generated files from PIDL for the IDL files in ../idl/*.idl diff --git a/source3/librpc/rpc/dcerpc.h b/source3/librpc/rpc/dcerpc.h index 0c120dfef5..d18920ca0d 100644 --- a/source3/librpc/rpc/dcerpc.h +++ b/source3/librpc/rpc/dcerpc.h @@ -111,4 +111,31 @@ _PUBLIC_ NTSTATUS dcerpc_binding_build_tower(TALLOC_CTX *mem_ctx, const struct dcerpc_binding *binding, struct epm_tower *tower); +struct NL_AUTH_MESSAGE; + +/* The following definitions come from librpc/rpc/dcerpc_helpers.c */ +NTSTATUS dcerpc_push_ncacn_packet(TALLOC_CTX *mem_ctx, + enum dcerpc_pkt_type ptype, + uint8_t pfc_flags, + uint16_t auth_length, + uint32_t call_id, + union dcerpc_payload *u, + DATA_BLOB *blob); +NTSTATUS dcerpc_pull_ncacn_packet(TALLOC_CTX *mem_ctx, + const DATA_BLOB *blob, + struct ncacn_packet *r); +NTSTATUS dcerpc_push_schannel_bind(TALLOC_CTX *mem_ctx, + struct NL_AUTH_MESSAGE *r, + DATA_BLOB *blob); +NTSTATUS dcerpc_push_dcerpc_auth(TALLOC_CTX *mem_ctx, + enum dcerpc_AuthType auth_type, + enum dcerpc_AuthLevel auth_level, + uint8_t auth_pad_length, + uint32_t auth_context_id, + const DATA_BLOB *credentials, + DATA_BLOB *blob); +NTSTATUS dcerpc_pull_dcerpc_auth(TALLOC_CTX *mem_ctx, + const DATA_BLOB *blob, + struct dcerpc_auth *r); + #endif /* __DCERPC_H__ */ diff --git a/source3/librpc/rpc/dcerpc_helpers.c b/source3/librpc/rpc/dcerpc_helpers.c new file mode 100644 index 0000000000..ce48a691ac --- /dev/null +++ b/source3/librpc/rpc/dcerpc_helpers.c @@ -0,0 +1,212 @@ +/* + * DCERPC Helper routines + * Günther Deschner <gd@samba.org> 2010. + * Simo Sorce <idra@samba.org> 2010. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + + +#include "includes.h" +#include "librpc/rpc/dcerpc.h" +#include "librpc/gen_ndr/ndr_dcerpc.h" +#include "librpc/gen_ndr/ndr_schannel.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_RPC_PARSE + +/** +* @brief NDR Encodes a ncacn_packet +* +* @param mem_ctx The memory context the blob will be allocated on +* @param ptype The DCERPC packet type +* @param pfc_flags The DCERPC PFC Falgs +* @param auth_length The length of the trailing auth blob +* @param call_id The call ID +* @param u The payload of the packet +* @param blob [out] The encoded blob if successful +* +* @return an NTSTATUS error code +*/ +NTSTATUS dcerpc_push_ncacn_packet(TALLOC_CTX *mem_ctx, + enum dcerpc_pkt_type ptype, + uint8_t pfc_flags, + uint16_t auth_length, + uint32_t call_id, + union dcerpc_payload *u, + DATA_BLOB *blob) +{ + struct ncacn_packet r; + enum ndr_err_code ndr_err; + + r.rpc_vers = 5; + r.rpc_vers_minor = 0; + r.ptype = ptype; + r.pfc_flags = pfc_flags; + r.drep[0] = DCERPC_DREP_LE; + r.drep[1] = 0; + r.drep[2] = 0; + r.drep[3] = 0; + r.auth_length = auth_length; + r.call_id = call_id; + r.u = *u; + + ndr_err = ndr_push_struct_blob(blob, mem_ctx, &r, + (ndr_push_flags_fn_t)ndr_push_ncacn_packet); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return ndr_map_error2ntstatus(ndr_err); + } + + dcerpc_set_frag_length(blob, blob->length); + + + if (DEBUGLEVEL >= 10) { + /* set frag len for print function */ + r.frag_length = blob->length; + NDR_PRINT_DEBUG(ncacn_packet, &r); + } + + return NT_STATUS_OK; +} + +/** +* @brief Decodes a ncacn_packet +* +* @param mem_ctx The memory context on which to allocate the packet +* elements +* @param blob The blob of data to decode +* @param r An empty ncacn_packet, must not be NULL +* +* @return a NTSTATUS error code +*/ +NTSTATUS dcerpc_pull_ncacn_packet(TALLOC_CTX *mem_ctx, + const DATA_BLOB *blob, + struct ncacn_packet *r) +{ + enum ndr_err_code ndr_err; + + ndr_err = ndr_pull_struct_blob(blob, mem_ctx, r, + (ndr_pull_flags_fn_t)ndr_pull_ncacn_packet); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return ndr_map_error2ntstatus(ndr_err); + } + + if (DEBUGLEVEL >= 10) { + NDR_PRINT_DEBUG(ncacn_packet, r); + } + + return NT_STATUS_OK; +} + +/** +* @brief NDR Encodes a NL_AUTH_MESSAGE +* +* @param mem_ctx The memory context the blob will be allocated on +* @param r The NL_AUTH_MESSAGE to encode +* @param blob [out] The encoded blob if successful +* +* @return a NTSTATUS error code +*/ +NTSTATUS dcerpc_push_schannel_bind(TALLOC_CTX *mem_ctx, + struct NL_AUTH_MESSAGE *r, + DATA_BLOB *blob) +{ + enum ndr_err_code ndr_err; + + ndr_err = ndr_push_struct_blob(blob, mem_ctx, r, + (ndr_push_flags_fn_t)ndr_push_NL_AUTH_MESSAGE); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return ndr_map_error2ntstatus(ndr_err); + } + + if (DEBUGLEVEL >= 10) { + NDR_PRINT_DEBUG(NL_AUTH_MESSAGE, r); + } + + return NT_STATUS_OK; +} + +/** +* @brief NDR Encodes a dcerpc_auth structure +* +* @param mem_ctx The memory context the blob will be allocated on +* @param auth_type The DCERPC Authentication Type +* @param auth_level The DCERPC Authentication Level +* @param auth_pad_length The padding added to the packet this blob will be +* appended to. +* @param auth_context_id The context id +* @param credentials The authentication credentials blob (signature) +* @param blob [out] The encoded blob if successful +* +* @return a NTSTATUS error code +*/ +NTSTATUS dcerpc_push_dcerpc_auth(TALLOC_CTX *mem_ctx, + enum dcerpc_AuthType auth_type, + enum dcerpc_AuthLevel auth_level, + uint8_t auth_pad_length, + uint32_t auth_context_id, + const DATA_BLOB *credentials, + DATA_BLOB *blob) +{ + struct dcerpc_auth r; + enum ndr_err_code ndr_err; + + r.auth_type = auth_type; + r.auth_level = auth_level; + r.auth_pad_length = auth_pad_length; + r.auth_reserved = 0; + r.auth_context_id = auth_context_id; + r.credentials = *credentials; + + ndr_err = ndr_push_struct_blob(blob, mem_ctx, &r, + (ndr_push_flags_fn_t)ndr_push_dcerpc_auth); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return ndr_map_error2ntstatus(ndr_err); + } + + if (DEBUGLEVEL >= 10) { + NDR_PRINT_DEBUG(dcerpc_auth, &r); + } + + return NT_STATUS_OK; +} + +/** +* @brief Decodes a dcerpc_auth blob +* +* @param mem_ctx The memory context on which to allocate the packet +* elements +* @param blob The blob of data to decode +* @param r An empty dcerpc_auth structure, must not be NULL +* +* @return a NTSTATUS error code +*/ +NTSTATUS dcerpc_pull_dcerpc_auth(TALLOC_CTX *mem_ctx, + const DATA_BLOB *blob, + struct dcerpc_auth *r) +{ + enum ndr_err_code ndr_err; + + ndr_err = ndr_pull_struct_blob(blob, mem_ctx, r, + (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return ndr_map_error2ntstatus(ndr_err); + } + + if (DEBUGLEVEL >= 10) { + NDR_PRINT_DEBUG(dcerpc_auth, r); + } + + return NT_STATUS_OK; +} diff --git a/source3/rpc_parse/parse_prs.c b/source3/registry/reg_parse_prs.c index ec5bc9cf6a..c1b941bbae 100644 --- a/source3/rpc_parse/parse_prs.c +++ b/source3/registry/reg_parse_prs.c @@ -1,82 +1,31 @@ -/* +/* Unix SMB/CIFS implementation. Samba memory buffer functions Copyright (C) Andrew Tridgell 1992-1997 Copyright (C) Luke Kenneth Casson Leighton 1996-1997 Copyright (C) Jeremy Allison 1999 Copyright (C) Andrew Bartlett 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 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "includes.h" -#include "../librpc/gen_ndr/ndr_schannel.h" +#include "reg_parse_prs.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_RPC_PARSE -/** - * Dump a prs to a file: from the current location through to the end. - **/ -void prs_dump(const char *name, int v, prs_struct *ps) -{ - prs_dump_region(name, v, ps, ps->data_offset, ps->buffer_size); -} - -/** - * Dump from the start of the prs to the current location. - **/ -void prs_dump_before(const char *name, int v, prs_struct *ps) -{ - prs_dump_region(name, v, ps, 0, ps->data_offset); -} - -/** - * Dump everything from the start of the prs up to the current location. - **/ -void prs_dump_region(const char *name, int v, prs_struct *ps, - int from_off, int to_off) -{ - int fd, i; - char *fname = NULL; - ssize_t sz; - if (DEBUGLEVEL < 50) return; - for (i=1;i<100;i++) { - if (v != -1) { - if (asprintf(&fname,"/tmp/%s_%d.%d.prs", name, v, i) < 0) { - return; - } - } else { - if (asprintf(&fname,"/tmp/%s.%d.prs", name, i) < 0) { - return; - } - } - fd = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0644); - if (fd != -1 || errno != EEXIST) break; - } - if (fd != -1) { - sz = write(fd, ps->data_p + from_off, to_off - from_off); - i = close(fd); - if ( (sz != to_off-from_off) || (i != 0) ) { - DEBUG(0,("Error writing/closing %s: %ld!=%ld %d\n", fname, (unsigned long)sz, (unsigned long)to_off-from_off, i )); - } else { - DEBUG(0,("created %s\n", fname)); - } - } - SAFE_FREE(fname); -} - /******************************************************************* Debug output for parsing info @@ -259,7 +208,7 @@ bool prs_grow(prs_struct *ps, uint32 extra_space) (unsigned int)extra_space)); return False; } - + /* * Decide how much extra space we really need. */ @@ -507,7 +456,7 @@ bool prs_align(prs_struct *ps) /****************************************************************** Align on a 2 byte boundary *****************************************************************/ - + bool prs_align_uint16(prs_struct *ps) { bool ret; @@ -516,14 +465,14 @@ bool prs_align_uint16(prs_struct *ps) ps->align = 2; ret = prs_align(ps); ps->align = old_align; - + return ret; } /****************************************************************** Align on a 8 byte boundary *****************************************************************/ - + bool prs_align_uint64(prs_struct *ps) { bool ret; @@ -532,14 +481,14 @@ bool prs_align_uint64(prs_struct *ps) ps->align = 8; ret = prs_align(ps); ps->align = old_align; - + return ret; } /****************************************************************** Align on a specific byte boundary *****************************************************************/ - + bool prs_align_custom(prs_struct *ps, uint8 boundary) { bool ret; @@ -548,7 +497,7 @@ bool prs_align_custom(prs_struct *ps, uint8 boundary) ps->align = boundary; ret = prs_align(ps); ps->align = old_align; - + return ret; } @@ -907,12 +856,12 @@ bool prs_data_blob(prs_struct *prs, DATA_BLOB *blob, TALLOC_CTX *mem_ctx) { blob->length = prs_data_size(prs); blob->data = (uint8 *)TALLOC_ZERO_SIZE(mem_ctx, blob->length); - + /* set the pointer at the end of the buffer */ prs_set_offset( prs, prs_data_size(prs) ); if (!prs_copy_all_data_out((char *)blob->data, prs)) return False; - + return True; } diff --git a/source3/registry/reg_parse_prs.h b/source3/registry/reg_parse_prs.h new file mode 100644 index 0000000000..0dd475a026 --- /dev/null +++ b/source3/registry/reg_parse_prs.h @@ -0,0 +1,101 @@ +/* + Unix SMB/CIFS implementation. + SMB parameters and setup + Copyright (C) Andrew Tridgell 1992-1997 + Copyright (C) Luke Kenneth Casson Leighton 1996-1997 + Copyright (C) Paul Ashton 1997 + Copyright (C) Jeremy Allison 2000-2004 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _REG_PARSE_PRS_H_ +#define _REG_PARSE_PRS_H_ + + +#define prs_init_empty( _ps_, _ctx_, _io_ ) (void) prs_init((_ps_), 0, (_ctx_), (_io_)) + +typedef struct _prs_struct { + bool io; /* parsing in or out of data stream */ + /* + * If the (incoming) data is big-endian. On output we are + * always little-endian. + */ + bool bigendian_data; + uint8 align; /* data alignment */ + bool is_dynamic; /* Do we own this memory or not ? */ + uint32 data_offset; /* Current working offset into data. */ + uint32 buffer_size; /* Current allocated size of the buffer. */ + uint32 grow_size; /* size requested via prs_grow() calls */ + /* The buffer itself. If "is_dynamic" is true this + * MUST BE TALLOC'ed off mem_ctx. */ + char *data_p; + TALLOC_CTX *mem_ctx; /* When unmarshalling, use this.... */ +} prs_struct; + +/* + * Defines for io member of prs_struct. + */ + +#define MARSHALL 0 +#define UNMARSHALL 1 + +#define MARSHALLING(ps) (!(ps)->io) +#define UNMARSHALLING(ps) ((ps)->io) + +#define RPC_PARSE_ALIGN 4 + +void prs_debug(prs_struct *ps, int depth, const char *desc, const char *fn_name); +bool prs_init(prs_struct *ps, uint32 size, TALLOC_CTX *ctx, bool io); +void prs_mem_free(prs_struct *ps); +void prs_mem_clear(prs_struct *ps); +char *prs_alloc_mem_(prs_struct *ps, size_t size, unsigned int count); +char *prs_alloc_mem(prs_struct *ps, size_t size, unsigned int count); +TALLOC_CTX *prs_get_mem_context(prs_struct *ps); +void prs_give_memory(prs_struct *ps, char *buf, uint32 size, bool is_dynamic); +bool prs_set_buffer_size(prs_struct *ps, uint32 newsize); +bool prs_grow(prs_struct *ps, uint32 extra_space); +bool prs_force_grow(prs_struct *ps, uint32 extra_space); +char *prs_data_p(prs_struct *ps); +uint32 prs_data_size(prs_struct *ps); +uint32 prs_offset(prs_struct *ps); +bool prs_set_offset(prs_struct *ps, uint32 offset); +bool prs_append_prs_data(prs_struct *dst, prs_struct *src); +bool prs_append_some_data(prs_struct *dst, void *src_base, uint32_t start, + uint32_t len); +bool prs_append_some_prs_data(prs_struct *dst, prs_struct *src, int32 start, uint32 len); +bool prs_copy_data_in(prs_struct *dst, const char *src, uint32 len); +bool prs_copy_data_out(char *dst, prs_struct *src, uint32 len); +bool prs_copy_all_data_out(char *dst, prs_struct *src); +void prs_set_endian_data(prs_struct *ps, bool endian); +bool prs_align(prs_struct *ps); +bool prs_align_uint16(prs_struct *ps); +bool prs_align_uint64(prs_struct *ps); +bool prs_align_custom(prs_struct *ps, uint8 boundary); +bool prs_align_needed(prs_struct *ps, uint32 needed); +char *prs_mem_get(prs_struct *ps, uint32 extra_size); +void prs_switch_type(prs_struct *ps, bool io); +bool prs_uint8(const char *name, prs_struct *ps, int depth, uint8 *data8); +bool prs_uint16(const char *name, prs_struct *ps, int depth, uint16 *data16); +bool prs_uint32(const char *name, prs_struct *ps, int depth, uint32 *data32); +bool prs_int32(const char *name, prs_struct *ps, int depth, int32 *data32); +bool prs_uint64(const char *name, prs_struct *ps, int depth, uint64 *data64); +bool prs_dcerpc_status(const char *name, prs_struct *ps, int depth, NTSTATUS *status); +bool prs_uint8s(bool charmode, const char *name, prs_struct *ps, int depth, uint8 *data8s, int len); +bool prs_uint16s(bool charmode, const char *name, prs_struct *ps, int depth, uint16 *data16s, int len); +bool prs_uint32s(bool charmode, const char *name, prs_struct *ps, int depth, uint32 *data32s, int len); +bool prs_init_data_blob(prs_struct *prs, DATA_BLOB *blob, TALLOC_CTX *mem_ctx); +bool prs_data_blob(prs_struct *prs, DATA_BLOB *blob, TALLOC_CTX *mem_ctx); + +#endif diff --git a/source3/registry/reg_perfcount.h b/source3/registry/reg_perfcount.h index c6b76a5360..671153f21c 100644 --- a/source3/registry/reg_perfcount.h +++ b/source3/registry/reg_perfcount.h @@ -22,6 +22,8 @@ #ifndef _REG_PERFCOUNT_H #define _REG_PERFCOUNT_H +#include "reg_parse_prs.h" + void perfcount_init_keys( void ); uint32 reg_perfcount_get_base_index(void); uint32 reg_perfcount_get_last_counter(uint32 base_index); diff --git a/source3/registry/regfio.c b/source3/registry/regfio.c index d64eab84f9..7ab262d822 100644 --- a/source3/registry/regfio.c +++ b/source3/registry/regfio.c @@ -18,6 +18,7 @@ */ #include "includes.h" +#include "reg_parse_prs.h" #include "regfio.h" #include "reg_objects.h" #include "../librpc/gen_ndr/ndr_security.h" @@ -31,6 +32,44 @@ * ******************************************************************/ +#if defined(PARANOID_MALLOC_CHECKER) +#define PRS_ALLOC_MEM(ps, type, count) (type *)prs_alloc_mem_((ps),sizeof(type),(count)) +#else +#define PRS_ALLOC_MEM(ps, type, count) (type *)prs_alloc_mem((ps),sizeof(type),(count)) +#endif + +/******************************************************************* + Reads or writes an NTTIME structure. +********************************************************************/ + +static bool smb_io_time(const char *desc, NTTIME *nttime, prs_struct *ps, int depth) +{ + uint32 low, high; + if (nttime == NULL) + return False; + + prs_debug(ps, depth, desc, "smb_io_time"); + depth++; + + if(!prs_align(ps)) + return False; + + if (MARSHALLING(ps)) { + low = *nttime & 0xFFFFFFFF; + high = *nttime >> 32; + } + + if(!prs_uint32("low ", ps, depth, &low)) /* low part */ + return False; + if(!prs_uint32("high", ps, depth, &high)) /* high part */ + return False; + + if (UNMARSHALLING(ps)) { + *nttime = (((uint64_t)high << 32) + low); + } + + return True; +} /******************************************************************* *******************************************************************/ diff --git a/source3/rpc_client/cli_pipe.c b/source3/rpc_client/cli_pipe.c index 91eb767667..c90e06095c 100644 --- a/source3/rpc_client/cli_pipe.c +++ b/source3/rpc_client/cli_pipe.c @@ -42,6 +42,7 @@ #include "../libcli/auth/ntlmssp.h" #include "rpc_client/cli_netlogon.h" #include "librpc/gen_ndr/ndr_dcerpc.h" +#include "librpc/rpc/dcerpc.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_RPC_CLI @@ -217,7 +218,7 @@ const char *get_pipe_name_from_syntax(TALLOC_CTX *mem_ctx, Map internal value to wire value. ********************************************************************/ -static int map_pipe_auth_type_to_rpc_auth_type(enum pipe_auth_type auth_type) +enum dcerpc_AuthType map_pipe_auth_type_to_rpc_auth_type(enum pipe_auth_type auth_type) { switch (auth_type) { @@ -269,199 +270,6 @@ static uint32 get_rpc_call_id(void) return ++call_id; } -/* - * Realloc pdu to have a least "size" bytes - */ - -static bool rpc_grow_buffer(prs_struct *pdu, size_t size) -{ - size_t extra_size; - - if (prs_data_size(pdu) >= size) { - return true; - } - - extra_size = size - prs_data_size(pdu); - - if (!prs_force_grow(pdu, extra_size)) { - DEBUG(0, ("rpc_grow_buffer: Failed to grow parse struct by " - "%d bytes.\n", (int)extra_size)); - return false; - } - - DEBUG(5, ("rpc_grow_buffer: grew buffer by %d bytes to %u\n", - (int)extra_size, prs_data_size(pdu))); - return true; -} - -/******************************************************************* -*******************************************************************/ - -NTSTATUS dcerpc_push_ncacn_packet(TALLOC_CTX *mem_ctx, - enum dcerpc_pkt_type ptype, - uint8_t pfc_flags, - uint16_t auth_length, - uint32_t call_id, - union dcerpc_payload *u, - DATA_BLOB *blob) -{ - struct ncacn_packet r; - enum ndr_err_code ndr_err; - - r.rpc_vers = 5; - r.rpc_vers_minor = 0; - r.ptype = ptype; - r.pfc_flags = pfc_flags; - r.drep[0] = DCERPC_DREP_LE; - r.drep[1] = 0; - r.drep[2] = 0; - r.drep[3] = 0; - r.auth_length = auth_length; - r.call_id = call_id; - r.u = *u; - - ndr_err = ndr_push_struct_blob(blob, mem_ctx, &r, - (ndr_push_flags_fn_t)ndr_push_ncacn_packet); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - return ndr_map_error2ntstatus(ndr_err); - } - - dcerpc_set_frag_length(blob, blob->length); - - - if (DEBUGLEVEL >= 10) { - /* set frag len for print function */ - r.frag_length = blob->length; - NDR_PRINT_DEBUG(ncacn_packet, &r); - } - - return NT_STATUS_OK; -} - -NTSTATUS dcerpc_push_ncacn_packet_header(TALLOC_CTX *mem_ctx, - enum dcerpc_pkt_type ptype, - uint8_t pfc_flags, - uint16_t frag_length, - uint16_t auth_length, - uint32_t call_id, - DATA_BLOB *blob) -{ - struct ncacn_packet_header r; - enum ndr_err_code ndr_err; - - r.rpc_vers = 5; - r.rpc_vers_minor = 0; - r.ptype = ptype; - r.pfc_flags = pfc_flags; - r.drep[0] = DCERPC_DREP_LE; - r.drep[1] = 0; - r.drep[2] = 0; - r.drep[3] = 0; - r.frag_length = frag_length; - r.auth_length = auth_length; - r.call_id = call_id; - - ndr_err = ndr_push_struct_blob(blob, mem_ctx, &r, - (ndr_push_flags_fn_t)ndr_push_ncacn_packet_header); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - return ndr_map_error2ntstatus(ndr_err); - } - - if (DEBUGLEVEL >= 10) { - NDR_PRINT_DEBUG(ncacn_packet_header, &r); - } - - return NT_STATUS_OK; -} - -/******************************************************************* -*******************************************************************/ - -NTSTATUS dcerpc_pull_ncacn_packet(TALLOC_CTX *mem_ctx, - const DATA_BLOB *blob, - struct ncacn_packet *r) -{ - enum ndr_err_code ndr_err; - - ndr_err = ndr_pull_struct_blob(blob, mem_ctx, r, - (ndr_pull_flags_fn_t)ndr_pull_ncacn_packet); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - return ndr_map_error2ntstatus(ndr_err); - } - - if (DEBUGLEVEL >= 10) { - NDR_PRINT_DEBUG(ncacn_packet, r); - } - - return NT_STATUS_OK; -} - -/******************************************************************* -*******************************************************************/ - -NTSTATUS dcerpc_pull_ncacn_packet_header(TALLOC_CTX *mem_ctx, - const DATA_BLOB *blob, - struct ncacn_packet_header *r) -{ - enum ndr_err_code ndr_err; - - ndr_err = ndr_pull_struct_blob(blob, mem_ctx, r, - (ndr_pull_flags_fn_t)ndr_pull_ncacn_packet_header); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - return ndr_map_error2ntstatus(ndr_err); - } - - if (DEBUGLEVEL >= 10) { - NDR_PRINT_DEBUG(ncacn_packet_header, r); - } - - return NT_STATUS_OK; -} - -/******************************************************************* - ********************************************************************/ - -static NTSTATUS dcerpc_push_schannel_bind(TALLOC_CTX *mem_ctx, - struct NL_AUTH_MESSAGE *r, - DATA_BLOB *blob) -{ - enum ndr_err_code ndr_err; - - ndr_err = ndr_push_struct_blob(blob, mem_ctx, r, - (ndr_push_flags_fn_t)ndr_push_NL_AUTH_MESSAGE); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - return ndr_map_error2ntstatus(ndr_err); - } - - if (DEBUGLEVEL >= 10) { - NDR_PRINT_DEBUG(NL_AUTH_MESSAGE, r); - } - - return NT_STATUS_OK; -} - -/******************************************************************* - ********************************************************************/ - -NTSTATUS dcerpc_pull_dcerpc_auth(TALLOC_CTX *mem_ctx, - const DATA_BLOB *blob, - struct dcerpc_auth *r) -{ - enum ndr_err_code ndr_err; - - ndr_err = ndr_pull_struct_blob(blob, mem_ctx, r, - (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - return ndr_map_error2ntstatus(ndr_err); - } - - if (DEBUGLEVEL >= 10) { - NDR_PRINT_DEBUG(dcerpc_auth, r); - } - - return NT_STATUS_OK; -} - /******************************************************************* Use SMBreadX to get rest of one fragment's worth of rpc data. Reads the whole size or give an error message @@ -627,42 +435,6 @@ static NTSTATUS rpc_write_recv(struct tevent_req *req) } -static NTSTATUS parse_rpc_header(struct rpc_pipe_client *cli, - struct ncacn_packet_header *prhdr, - prs_struct *pdu) -{ - NTSTATUS status; - DATA_BLOB blob = data_blob_const(prs_data_p(pdu), prs_data_size(pdu)); - - /* - * This next call sets the endian bit correctly in current_pdu. We - * will propagate this to rbuf later. - */ - - status = dcerpc_pull_ncacn_packet_header(cli, &blob, prhdr); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - if (!prs_set_offset(pdu, prs_offset(pdu) + RPC_HEADER_LEN)) { - return NT_STATUS_BUFFER_TOO_SMALL; - } - - if (UNMARSHALLING(pdu) && prhdr->drep[0] == 0) { - DEBUG(10,("parse_rpc_header: PDU data format is big-endian. Setting flag.\n")); - prs_set_endian_data(pdu, RPC_BIG_ENDIAN); - } - - if (prhdr->frag_length > cli->max_recv_frag) { - DEBUG(0, ("cli_pipe_get_current_pdu: Server sent fraglen %d," - " we only allow %d\n", (int)prhdr->frag_length, - (int)cli->max_recv_frag)); - return NT_STATUS_BUFFER_TOO_SMALL; - } - - return NT_STATUS_OK; -} - /**************************************************************************** Try and get a PDU's worth of data from current_pdu. If not, then read more from the wire. @@ -671,8 +443,8 @@ static NTSTATUS parse_rpc_header(struct rpc_pipe_client *cli, struct get_complete_frag_state { struct event_context *ev; struct rpc_pipe_client *cli; - struct ncacn_packet_header *prhdr; - prs_struct *pdu; + uint16_t frag_len; + DATA_BLOB *pdu; }; static void get_complete_frag_got_header(struct tevent_req *subreq); @@ -681,12 +453,11 @@ static void get_complete_frag_got_rest(struct tevent_req *subreq); static struct tevent_req *get_complete_frag_send(TALLOC_CTX *mem_ctx, struct event_context *ev, struct rpc_pipe_client *cli, - struct ncacn_packet_header *prhdr, - prs_struct *pdu) + DATA_BLOB *pdu) { struct tevent_req *req, *subreq; struct get_complete_frag_state *state; - uint32_t pdu_len; + size_t received; NTSTATUS status; req = tevent_req_create(mem_ctx, &state, @@ -696,20 +467,19 @@ static struct tevent_req *get_complete_frag_send(TALLOC_CTX *mem_ctx, } state->ev = ev; state->cli = cli; - state->prhdr = prhdr; + state->frag_len = RPC_HEADER_LEN; state->pdu = pdu; - pdu_len = prs_data_size(pdu); - if (pdu_len < RPC_HEADER_LEN) { - if (!rpc_grow_buffer(pdu, RPC_HEADER_LEN)) { + received = pdu->length; + if (received < RPC_HEADER_LEN) { + if (!data_blob_realloc(mem_ctx, pdu, RPC_HEADER_LEN)) { status = NT_STATUS_NO_MEMORY; goto post_status; } - subreq = rpc_read_send( - state, state->ev, - state->cli->transport, - (uint8_t *)(prs_data_p(state->pdu) + pdu_len), - RPC_HEADER_LEN - pdu_len); + subreq = rpc_read_send(state, state->ev, + state->cli->transport, + pdu->data + received, + RPC_HEADER_LEN - received); if (subreq == NULL) { status = NT_STATUS_NO_MEMORY; goto post_status; @@ -719,23 +489,20 @@ static struct tevent_req *get_complete_frag_send(TALLOC_CTX *mem_ctx, return req; } - status = parse_rpc_header(cli, prhdr, pdu); - if (!NT_STATUS_IS_OK(status)) { - goto post_status; - } + state->frag_len = dcerpc_get_frag_length(pdu); /* * Ensure we have frag_len bytes of data. */ - if (pdu_len < prhdr->frag_length) { - if (!rpc_grow_buffer(pdu, prhdr->frag_length)) { + if (received < state->frag_len) { + if (!data_blob_realloc(NULL, pdu, state->frag_len)) { status = NT_STATUS_NO_MEMORY; goto post_status; } subreq = rpc_read_send(state, state->ev, - state->cli->transport, - (uint8_t *)(prs_data_p(pdu) + pdu_len), - prhdr->frag_length - pdu_len); + state->cli->transport, + pdu->data + received, + state->frag_len - received); if (subreq == NULL) { status = NT_STATUS_NO_MEMORY; goto post_status; @@ -770,13 +537,9 @@ static void get_complete_frag_got_header(struct tevent_req *subreq) return; } - status = parse_rpc_header(state->cli, state->prhdr, state->pdu); - if (!NT_STATUS_IS_OK(status)) { - tevent_req_nterror(req, status); - return; - } + state->frag_len = dcerpc_get_frag_length(state->pdu); - if (!rpc_grow_buffer(state->pdu, state->prhdr->frag_length)) { + if (!data_blob_realloc(NULL, state->pdu, state->frag_len)) { tevent_req_nterror(req, NT_STATUS_NO_MEMORY); return; } @@ -786,10 +549,9 @@ static void get_complete_frag_got_header(struct tevent_req *subreq) * RPC_HEADER_LEN bytes into state->pdu. */ - subreq = rpc_read_send( - state, state->ev, state->cli->transport, - (uint8_t *)(prs_data_p(state->pdu) + RPC_HEADER_LEN), - state->prhdr->frag_length - RPC_HEADER_LEN); + subreq = rpc_read_send(state, state->ev, state->cli->transport, + state->pdu->data + RPC_HEADER_LEN, + state->frag_len - RPC_HEADER_LEN); if (tevent_req_nomem(subreq, req)) { return; } @@ -823,19 +585,11 @@ static NTSTATUS get_complete_frag_recv(struct tevent_req *req) ****************************************************************************/ static NTSTATUS cli_pipe_verify_ntlmssp(struct rpc_pipe_client *cli, - struct ncacn_packet_header *prhdr, - prs_struct *current_pdu, - uint8 *p_ss_padding_len) + struct ncacn_packet *pkt, + DATA_BLOB *pdu, + uint8 *p_ss_padding_len) { struct dcerpc_auth auth_info; - uint32 save_offset = prs_offset(current_pdu); - uint32_t auth_len = prhdr->auth_length; - struct ntlmssp_state *ntlmssp_state = cli->auth->a_u.ntlmssp_state; - unsigned char *data = NULL; - size_t data_len; - unsigned char *full_packet_data = NULL; - size_t full_packet_data_len; - DATA_BLOB auth_blob; DATA_BLOB blob; NTSTATUS status; @@ -844,44 +598,26 @@ static NTSTATUS cli_pipe_verify_ntlmssp(struct rpc_pipe_client *cli, return NT_STATUS_OK; } - if (!ntlmssp_state) { + if (!cli->auth->a_u.ntlmssp_state) { return NT_STATUS_INVALID_PARAMETER; } /* Ensure there's enough data for an authenticated response. */ - if (auth_len > RPC_MAX_PDU_FRAG_LEN || - prhdr->frag_length < RPC_HEADER_LEN + - RPC_HDR_RESP_LEN + - RPC_HDR_AUTH_LEN + auth_len) { - DEBUG(0,("cli_pipe_verify_ntlmssp: auth_len %u is too large.\n", - (unsigned int)auth_len )); + if ((pkt->auth_length > RPC_MAX_PDU_FRAG_LEN) || + (pkt->frag_length < DCERPC_RESPONSE_LENGTH + + DCERPC_AUTH_TRAILER_LENGTH + + pkt->auth_length)) { + DEBUG(0, ("auth_len %u is too long.\n", + (unsigned int)pkt->auth_length)); return NT_STATUS_BUFFER_TOO_SMALL; } - /* - * We need the full packet data + length (minus auth stuff) as well as the packet data + length - * after the RPC header. - * We need to pass in the full packet (minus auth len) to the NTLMSSP sign and check seal - * functions as NTLMv2 checks the rpc headers also. - */ - - data = (unsigned char *)(prs_data_p(current_pdu) + RPC_HEADER_LEN + RPC_HDR_RESP_LEN); - data_len = (size_t)(prhdr->frag_length - RPC_HEADER_LEN - RPC_HDR_RESP_LEN - RPC_HDR_AUTH_LEN - auth_len); - - full_packet_data = (unsigned char *)prs_data_p(current_pdu); - full_packet_data_len = prhdr->frag_length - auth_len; - - /* Pull the auth header and the following data into a blob. */ - /* NB. The offset of the auth_header is relative to the *end* - * of the packet, not the start. */ - if(!prs_set_offset(current_pdu, prhdr->frag_length - RPC_HDR_AUTH_LEN - auth_len)) { - DEBUG(0,("cli_pipe_verify_ntlmssp: cannot move offset to %u.\n", - (unsigned int)RPC_HEADER_LEN + (unsigned int)RPC_HDR_RESP_LEN + (unsigned int)data_len )); - return NT_STATUS_BUFFER_TOO_SMALL; - } - - blob = data_blob_const(prs_data_p(current_pdu) + prs_offset(current_pdu), - prs_data_size(current_pdu) - prs_offset(current_pdu)); + /* get the auth blob at the end of the packet */ + blob = data_blob_const(pdu->data + pkt->frag_length + - DCERPC_AUTH_TRAILER_LENGTH + - pkt->auth_length, + DCERPC_AUTH_TRAILER_LENGTH + + pkt->auth_length); status = dcerpc_pull_dcerpc_auth(cli, &blob, &auth_info); if (!NT_STATUS_IS_OK(status)) { @@ -890,64 +626,72 @@ static NTSTATUS cli_pipe_verify_ntlmssp(struct rpc_pipe_client *cli, } /* Ensure auth_pad_len fits into the packet. */ - if (RPC_HEADER_LEN + RPC_HDR_REQ_LEN + auth_info.auth_pad_length + - RPC_HDR_AUTH_LEN + auth_len > prhdr->frag_length) { + if (pkt->frag_length < DCERPC_RESPONSE_LENGTH + + auth_info.auth_pad_length + + DCERPC_AUTH_TRAILER_LENGTH + + pkt->auth_length) { DEBUG(0,("cli_pipe_verify_ntlmssp: auth_info.auth_pad_len " "too large (%u), auth_len (%u), frag_len = (%u).\n", (unsigned int)auth_info.auth_pad_length, - (unsigned int)auth_len, - (unsigned int)prhdr->frag_length)); + (unsigned int)pkt->auth_length, + (unsigned int)pkt->frag_length)); return NT_STATUS_BUFFER_TOO_SMALL; } - - auth_blob = auth_info.credentials; + /* + * We need the full packet data + length (minus auth stuff) as well as the packet data + length + * after the RPC header. + * We need to pass in the full packet (minus auth len) to the NTLMSSP sign and check seal + * functions as NTLMv2 checks the rpc headers also. + */ switch (cli->auth->auth_level) { - case DCERPC_AUTH_LEVEL_PRIVACY: - /* Data is encrypted. */ - status = ntlmssp_unseal_packet(ntlmssp_state, - data, data_len, - full_packet_data, - full_packet_data_len, - &auth_blob); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("cli_pipe_verify_ntlmssp: failed to unseal " - "packet from %s. Error was %s.\n", - rpccli_pipe_txt(talloc_tos(), cli), - nt_errstr(status) )); - return status; - } - break; - case DCERPC_AUTH_LEVEL_INTEGRITY: - /* Data is signed. */ - status = ntlmssp_check_packet(ntlmssp_state, - data, data_len, - full_packet_data, - full_packet_data_len, - &auth_blob); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("cli_pipe_verify_ntlmssp: check signing failed on " - "packet from %s. Error was %s.\n", - rpccli_pipe_txt(talloc_tos(), cli), - nt_errstr(status) )); - return status; - } - break; - default: - DEBUG(0, ("cli_pipe_verify_ntlmssp: unknown internal " - "auth level %d\n", cli->auth->auth_level)); - return NT_STATUS_INVALID_INFO_CLASS; - } + case DCERPC_AUTH_LEVEL_PRIVACY: + /* Data is encrypted. */ + status = ntlmssp_unseal_packet( + cli->auth->a_u.ntlmssp_state, + pdu->data + DCERPC_RESPONSE_LENGTH, + pkt->frag_length + - DCERPC_RESPONSE_LENGTH + - DCERPC_AUTH_TRAILER_LENGTH + - pkt->auth_length, + pdu->data, + pkt->frag_length - pkt->auth_length, + &auth_info.credentials); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("failed to unseal packet from %s." + " Error was %s.\n", + rpccli_pipe_txt(talloc_tos(), cli), + nt_errstr(status))); + return status; + } + break; - /* - * Return the current pointer to the data offset. - */ + case DCERPC_AUTH_LEVEL_INTEGRITY: + /* Data is signed. */ + status = ntlmssp_check_packet( + cli->auth->a_u.ntlmssp_state, + pdu->data + DCERPC_RESPONSE_LENGTH, + pkt->frag_length + - DCERPC_RESPONSE_LENGTH + - DCERPC_AUTH_TRAILER_LENGTH + - pkt->auth_length, + pdu->data, + pkt->frag_length - pkt->auth_length, + &auth_info.credentials); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("check signing failed on packet from %s." + " Error was %s.\n", + rpccli_pipe_txt(talloc_tos(), cli), + nt_errstr(status))); + return status; + } + break; - if(!prs_set_offset(current_pdu, save_offset)) { - DEBUG(0,("api_pipe_auth_process: failed to set offset back to %u\n", - (unsigned int)save_offset )); - return NT_STATUS_BUFFER_TOO_SMALL; + default: + DEBUG(0, ("cli_pipe_verify_ntlmssp: unknown internal " + "auth level %d\n", cli->auth->auth_level)); + return NT_STATUS_INVALID_INFO_CLASS; } /* @@ -965,17 +709,11 @@ static NTSTATUS cli_pipe_verify_ntlmssp(struct rpc_pipe_client *cli, ****************************************************************************/ static NTSTATUS cli_pipe_verify_schannel(struct rpc_pipe_client *cli, - struct ncacn_packet_header *prhdr, - prs_struct *current_pdu, - uint8 *p_ss_padding_len) + struct ncacn_packet *pkt, + DATA_BLOB *pdu, + uint8 *p_ss_padding_len) { struct dcerpc_auth auth_info; - uint32_t auth_len = prhdr->auth_length; - uint32 save_offset = prs_offset(current_pdu); - struct schannel_state *schannel_auth = - cli->auth->a_u.schannel_auth; - uint8_t *data; - uint32 data_len; DATA_BLOB blob; NTSTATUS status; @@ -984,41 +722,32 @@ static NTSTATUS cli_pipe_verify_schannel(struct rpc_pipe_client *cli, return NT_STATUS_OK; } - if (auth_len < RPC_AUTH_SCHANNEL_SIGN_OR_SEAL_CHK_LEN) { - DEBUG(0,("cli_pipe_verify_schannel: auth_len %u.\n", (unsigned int)auth_len )); + if (pkt->auth_length < SCHANNEL_SIG_SIZE) { + DEBUG(0, ("auth_len %u.\n", (unsigned int)pkt->auth_length)); return NT_STATUS_INVALID_PARAMETER; } - if (!schannel_auth) { + if (!cli->auth->a_u.schannel_auth) { return NT_STATUS_INVALID_PARAMETER; } /* Ensure there's enough data for an authenticated response. */ - if ((auth_len > RPC_MAX_PDU_FRAG_LEN) || - (RPC_HEADER_LEN + RPC_HDR_RESP_LEN + RPC_HDR_AUTH_LEN + auth_len > prhdr->frag_length)) { - DEBUG(0,("cli_pipe_verify_schannel: auth_len %u is too large.\n", - (unsigned int)auth_len )); + if ((pkt->auth_length > RPC_MAX_PDU_FRAG_LEN) || + (pkt->frag_length < DCERPC_RESPONSE_LENGTH + + DCERPC_AUTH_TRAILER_LENGTH + + pkt->auth_length)) { + DEBUG(0, ("auth_len %u is too long.\n", + (unsigned int)pkt->auth_length)); return NT_STATUS_INVALID_PARAMETER; } - data_len = prhdr->frag_length - RPC_HEADER_LEN - RPC_HDR_RESP_LEN - RPC_HDR_AUTH_LEN - auth_len; - - /* Pull the auth header and the following data into a blob. */ - /* NB. The offset of the auth_header is relative to the *end* - * of the packet, not the start. */ - if(!prs_set_offset(current_pdu, - prhdr->frag_length - RPC_HDR_AUTH_LEN - auth_len)) { - DEBUG(0,("cli_pipe_verify_schannel: cannot move " - "offset to %u.\n", - (unsigned int)(prhdr->frag_length - - RPC_HDR_AUTH_LEN - auth_len) )); - return NT_STATUS_BUFFER_TOO_SMALL; - } + /* get the auth blob at the end of the packet */ + blob = data_blob_const(pdu->data + pkt->frag_length + - DCERPC_AUTH_TRAILER_LENGTH + - pkt->auth_length, + DCERPC_AUTH_TRAILER_LENGTH + + pkt->auth_length); - blob = data_blob_const(prs_data_p(current_pdu) - + prs_offset(current_pdu), - prs_data_size(current_pdu) - - prs_offset(current_pdu)); status = dcerpc_pull_dcerpc_auth(cli, &blob, &auth_info); if (!NT_STATUS_IS_OK(status)) { @@ -1027,48 +756,52 @@ static NTSTATUS cli_pipe_verify_schannel(struct rpc_pipe_client *cli, } /* Ensure auth_pad_len fits into the packet. */ - if (RPC_HEADER_LEN + RPC_HDR_REQ_LEN + auth_info.auth_pad_length + - RPC_HDR_AUTH_LEN + auth_len > prhdr->frag_length) { + if (pkt->frag_length < DCERPC_RESPONSE_LENGTH + + auth_info.auth_pad_length + + DCERPC_AUTH_TRAILER_LENGTH + + pkt->auth_length) { DEBUG(0,("cli_pipe_verify_schannel: auth_info.auth_pad_len " "too large (%u), auth_len (%u), frag_len = (%u).\n", (unsigned int)auth_info.auth_pad_length, - (unsigned int)auth_len, - (unsigned int)prhdr->frag_length)); + (unsigned int)pkt->auth_length, + (unsigned int)pkt->frag_length)); return NT_STATUS_BUFFER_TOO_SMALL; } if (auth_info.auth_type != DCERPC_AUTH_TYPE_SCHANNEL) { - DEBUG(0,("cli_pipe_verify_schannel: Invalid auth info %d on schannel\n", - auth_info.auth_type)); + DEBUG(0, ("Invalid auth info %d on schannel\n", + auth_info.auth_type)); return NT_STATUS_BUFFER_TOO_SMALL; } - blob = data_blob_const(prs_data_p(current_pdu) + - prs_offset(current_pdu) + - RPC_HDR_AUTH_LEN, auth_len); - if (DEBUGLEVEL >= 10) { - dump_NL_AUTH_SIGNATURE(talloc_tos(), &blob); + dump_NL_AUTH_SIGNATURE(talloc_tos(), &auth_info.credentials); } - data = (uint8_t *)prs_data_p(current_pdu)+RPC_HEADER_LEN+RPC_HDR_RESP_LEN; - switch (cli->auth->auth_level) { case DCERPC_AUTH_LEVEL_PRIVACY: - status = netsec_incoming_packet(schannel_auth, - talloc_tos(), - true, - data, - data_len, - &blob); + status = netsec_incoming_packet( + cli->auth->a_u.schannel_auth, + talloc_tos(), + true, + pdu->data + DCERPC_RESPONSE_LENGTH, + pkt->frag_length + - DCERPC_RESPONSE_LENGTH + - DCERPC_AUTH_TRAILER_LENGTH + - pkt->auth_length, + &auth_info.credentials); break; case DCERPC_AUTH_LEVEL_INTEGRITY: - status = netsec_incoming_packet(schannel_auth, - talloc_tos(), - false, - data, - data_len, - &blob); + status = netsec_incoming_packet( + cli->auth->a_u.schannel_auth, + talloc_tos(), + false, + pdu->data + DCERPC_RESPONSE_LENGTH, + pkt->frag_length + - DCERPC_RESPONSE_LENGTH + - DCERPC_AUTH_TRAILER_LENGTH + - pkt->auth_length, + &auth_info.credentials); break; default: status = NT_STATUS_INTERNAL_ERROR; @@ -1084,16 +817,6 @@ static NTSTATUS cli_pipe_verify_schannel(struct rpc_pipe_client *cli, } /* - * Return the current pointer to the data offset. - */ - - if(!prs_set_offset(current_pdu, save_offset)) { - DEBUG(0,("api_pipe_auth_process: failed to set offset back to %u\n", - (unsigned int)save_offset )); - return NT_STATUS_BUFFER_TOO_SMALL; - } - - /* * Remember the padding length. We must remove it from the real data * stream once the sign/seal is done. */ @@ -1108,20 +831,24 @@ static NTSTATUS cli_pipe_verify_schannel(struct rpc_pipe_client *cli, ****************************************************************************/ static NTSTATUS cli_pipe_validate_rpc_response(struct rpc_pipe_client *cli, - struct ncacn_packet_header *prhdr, - prs_struct *current_pdu, - uint8 *p_ss_padding_len) + struct ncacn_packet *pkt, + DATA_BLOB *pdu, + uint8 *p_ss_padding_len) { NTSTATUS ret = NT_STATUS_OK; /* Paranioa checks for auth_len. */ - if (prhdr->auth_length) { - if (prhdr->auth_length > prhdr->frag_length) { + if (pkt->auth_length) { + if (pkt->auth_length > pkt->frag_length) { return NT_STATUS_INVALID_PARAMETER; } - if (prhdr->auth_length + (unsigned int)RPC_HDR_AUTH_LEN < prhdr->auth_length || - prhdr->auth_length + (unsigned int)RPC_HDR_AUTH_LEN < (unsigned int)RPC_HDR_AUTH_LEN) { + if ((pkt->auth_length + + (unsigned int)DCERPC_AUTH_TRAILER_LENGTH + < pkt->auth_length) || + (pkt->auth_length + + (unsigned int)DCERPC_AUTH_TRAILER_LENGTH + < (unsigned int)DCERPC_AUTH_TRAILER_LENGTH)) { /* Integer wrap attempt. */ return NT_STATUS_INVALID_PARAMETER; } @@ -1132,40 +859,42 @@ static NTSTATUS cli_pipe_validate_rpc_response(struct rpc_pipe_client *cli, */ switch(cli->auth->auth_type) { - case PIPE_AUTH_TYPE_NONE: - if (prhdr->auth_length) { - DEBUG(3, ("cli_pipe_validate_rpc_response: " - "Connection to %s - got non-zero " - "auth len %u.\n", - rpccli_pipe_txt(talloc_tos(), cli), - (unsigned int)prhdr->auth_length)); - return NT_STATUS_INVALID_PARAMETER; - } - break; + case PIPE_AUTH_TYPE_NONE: + if (pkt->auth_length) { + DEBUG(3, ("cli_pipe_validate_rpc_response: " + "Connection to %s - got non-zero " + "auth len %u.\n", + rpccli_pipe_txt(talloc_tos(), cli), + (unsigned int)pkt->auth_length)); + return NT_STATUS_INVALID_PARAMETER; + } + break; - case PIPE_AUTH_TYPE_NTLMSSP: - case PIPE_AUTH_TYPE_SPNEGO_NTLMSSP: - ret = cli_pipe_verify_ntlmssp(cli, prhdr, current_pdu, p_ss_padding_len); - if (!NT_STATUS_IS_OK(ret)) { - return ret; - } - break; + case PIPE_AUTH_TYPE_NTLMSSP: + case PIPE_AUTH_TYPE_SPNEGO_NTLMSSP: + ret = cli_pipe_verify_ntlmssp(cli, pkt, pdu, + p_ss_padding_len); + if (!NT_STATUS_IS_OK(ret)) { + return ret; + } + break; - case PIPE_AUTH_TYPE_SCHANNEL: - ret = cli_pipe_verify_schannel(cli, prhdr, current_pdu, p_ss_padding_len); - if (!NT_STATUS_IS_OK(ret)) { - return ret; - } - break; + case PIPE_AUTH_TYPE_SCHANNEL: + ret = cli_pipe_verify_schannel(cli, pkt, pdu, + p_ss_padding_len); + if (!NT_STATUS_IS_OK(ret)) { + return ret; + } + break; - case PIPE_AUTH_TYPE_KRB5: - case PIPE_AUTH_TYPE_SPNEGO_KRB5: - default: - DEBUG(3, ("cli_pipe_validate_rpc_response: Connection " - "to %s - unknown internal auth type %u.\n", - rpccli_pipe_txt(talloc_tos(), cli), - cli->auth->auth_type )); - return NT_STATUS_INVALID_INFO_CLASS; + case PIPE_AUTH_TYPE_KRB5: + case PIPE_AUTH_TYPE_SPNEGO_KRB5: + default: + DEBUG(3, ("cli_pipe_validate_rpc_response: Connection " + "to %s - unknown internal auth type %u.\n", + rpccli_pipe_txt(talloc_tos(), cli), + cli->auth->auth_type )); + return NT_STATUS_INVALID_INFO_CLASS; } return NT_STATUS_OK; @@ -1175,21 +904,26 @@ static NTSTATUS cli_pipe_validate_rpc_response(struct rpc_pipe_client *cli, Do basic authentication checks on an incoming pdu. ****************************************************************************/ -static NTSTATUS cli_pipe_validate_current_pdu(struct rpc_pipe_client *cli, - struct ncacn_packet_header *prhdr, - prs_struct *current_pdu, - uint8 expected_pkt_type, - char **ppdata, - uint32 *pdata_len, - prs_struct *return_data) +static NTSTATUS cli_pipe_validate_current_pdu(TALLOC_CTX *mem_ctx, + struct rpc_pipe_client *cli, + struct ncacn_packet *pkt, + DATA_BLOB *pdu, + uint8_t expected_pkt_type, + DATA_BLOB *rdata, + DATA_BLOB *reply_pdu) { - NTSTATUS ret = NT_STATUS_OK; - uint32 current_pdu_len = prs_data_size(current_pdu); + uint8 ss_padding_len = 0; + + ret = dcerpc_pull_ncacn_packet(cli, pdu, pkt); + if (!NT_STATUS_IS_OK(ret)) { + return ret; + } - if (current_pdu_len != prhdr->frag_length) { - DEBUG(5,("cli_pipe_validate_current_pdu: incorrect pdu length %u, expected %u\n", - (unsigned int)current_pdu_len, (unsigned int)prhdr->frag_length)); + if (pdu->length != pkt->frag_length) { + DEBUG(5, ("Incorrect pdu length %u, expected %u\n", + (unsigned int)pdu->length, + (unsigned int)pkt->frag_length)); return NT_STATUS_INVALID_PARAMETER; } @@ -1197,126 +931,106 @@ static NTSTATUS cli_pipe_validate_current_pdu(struct rpc_pipe_client *cli, * Point the return values at the real data including the RPC * header. Just in case the caller wants it. */ - *ppdata = prs_data_p(current_pdu); - *pdata_len = current_pdu_len; + *rdata = *pdu; /* Ensure we have the correct type. */ - switch (prhdr->ptype) { - case DCERPC_PKT_ALTER_RESP: - case DCERPC_PKT_BIND_ACK: - - /* Alter context and bind ack share the same packet definitions. */ - break; + switch (pkt->ptype) { + case DCERPC_PKT_ALTER_RESP: + case DCERPC_PKT_BIND_ACK: + /* Alter context and bind ack share the same packet definitions. */ + break; - case DCERPC_PKT_RESPONSE: - { - uint8 ss_padding_len = 0; - DATA_BLOB blob; - struct ncacn_packet r; - blob = data_blob_const(prs_data_p(current_pdu), - prs_data_size(current_pdu)); + case DCERPC_PKT_RESPONSE: - ret = dcerpc_pull_ncacn_packet(cli, &blob, &r); - if (!NT_STATUS_IS_OK(ret)) { - return ret; - } + /* Here's where we deal with incoming sign/seal. */ + ret = cli_pipe_validate_rpc_response(cli, pkt, pdu, + &ss_padding_len); + if (!NT_STATUS_IS_OK(ret)) { + return ret; + } - if (!prs_set_offset(current_pdu, prs_offset(current_pdu) + RPC_HDR_RESP_LEN)) { - return NT_STATUS_BUFFER_TOO_SMALL; - } + /* Point the return values at the NDR data. + * Remember to remove any ss padding. */ + rdata->data = pdu->data + DCERPC_RESPONSE_LENGTH; - /* Here's where we deal with incoming sign/seal. */ - ret = cli_pipe_validate_rpc_response(cli, prhdr, - current_pdu, &ss_padding_len); - if (!NT_STATUS_IS_OK(ret)) { - return ret; - } + if (pdu->length < DCERPC_RESPONSE_LENGTH + ss_padding_len) { + return NT_STATUS_BUFFER_TOO_SMALL; + } - /* Point the return values at the NDR data. Remember to remove any ss padding. */ - *ppdata = prs_data_p(current_pdu) + RPC_HEADER_LEN + RPC_HDR_RESP_LEN; + rdata->length = pdu->length + - DCERPC_RESPONSE_LENGTH + - ss_padding_len; - if (current_pdu_len < RPC_HEADER_LEN + RPC_HDR_RESP_LEN + ss_padding_len) { + /* Remember to remove the auth footer. */ + if (pkt->auth_length) { + /* We've already done integer wrap tests on auth_len in + cli_pipe_validate_rpc_response(). */ + if (rdata->length < DCERPC_AUTH_TRAILER_LENGTH + + pkt->auth_length) { return NT_STATUS_BUFFER_TOO_SMALL; } + rdata->length -= (DCERPC_AUTH_TRAILER_LENGTH + + pkt->auth_length); + } - *pdata_len = current_pdu_len - RPC_HEADER_LEN - RPC_HDR_RESP_LEN - ss_padding_len; + DEBUG(10, ("Got pdu len %lu, data_len %lu, ss_len %u\n", + pdu->length, rdata->length, ss_padding_len)); - /* Remember to remove the auth footer. */ - if (prhdr->auth_length) { - /* We've already done integer wrap tests on auth_len in - cli_pipe_validate_rpc_response(). */ - if (*pdata_len < RPC_HDR_AUTH_LEN + prhdr->auth_length) { - return NT_STATUS_BUFFER_TOO_SMALL; - } - *pdata_len -= (RPC_HDR_AUTH_LEN + prhdr->auth_length); - } + /* + * If this is the first reply, and the allocation hint is + * reasonable, try and set up the reply_pdu DATA_BLOB to the + * correct size. + */ - DEBUG(10,("cli_pipe_validate_current_pdu: got pdu len %u, data_len %u, ss_len %u\n", - current_pdu_len, *pdata_len, ss_padding_len )); - - /* - * If this is the first reply, and the allocation hint is reasonably, try and - * set up the return_data parse_struct to the correct size. - */ - - if ((prs_data_size(return_data) == 0) && r.u.response.alloc_hint && (r.u.response.alloc_hint < 15*1024*1024)) { - if (!prs_set_buffer_size(return_data, r.u.response.alloc_hint)) { - DEBUG(0,("cli_pipe_validate_current_pdu: reply alloc hint %u " - "too large to allocate\n", - (unsigned int)r.u.response.alloc_hint )); - return NT_STATUS_NO_MEMORY; - } + if ((reply_pdu->length == 0) && + pkt->u.response.alloc_hint && + (pkt->u.response.alloc_hint < 15*1024*1024)) { + if (!data_blob_realloc(mem_ctx, reply_pdu, + pkt->u.response.alloc_hint)) { + DEBUG(0, ("reply alloc hint %d too " + "large to allocate\n", + (int)pkt->u.response.alloc_hint)); + return NT_STATUS_NO_MEMORY; } - - break; } - case DCERPC_PKT_BIND_NAK: - DEBUG(1, ("cli_pipe_validate_current_pdu: Bind NACK " - "received from %s!\n", - rpccli_pipe_txt(talloc_tos(), cli))); - /* Use this for now... */ - return NT_STATUS_NETWORK_ACCESS_DENIED; - - case DCERPC_PKT_FAULT: - { - DATA_BLOB blob; - struct ncacn_packet r; - - blob = data_blob_const(prs_data_p(current_pdu), - prs_data_size(current_pdu)); + break; - ret = dcerpc_pull_ncacn_packet(cli, &blob, &r); - if (!NT_STATUS_IS_OK(ret)) { - return ret; - } - DEBUG(1, ("cli_pipe_validate_current_pdu: RPC fault " - "code %s received from %s!\n", - dcerpc_errstr(talloc_tos(), r.u.fault.status), - rpccli_pipe_txt(talloc_tos(), cli))); - - if (NT_STATUS_IS_OK(NT_STATUS(r.u.fault.status))) { - return NT_STATUS_UNSUCCESSFUL; - } else { - return NT_STATUS(r.u.fault.status); - } + case DCERPC_PKT_BIND_NAK: + DEBUG(1, ("cli_pipe_validate_current_pdu: Bind NACK " + "received from %s!\n", + rpccli_pipe_txt(talloc_tos(), cli))); + /* Use this for now... */ + return NT_STATUS_NETWORK_ACCESS_DENIED; + + case DCERPC_PKT_FAULT: + + DEBUG(1, ("cli_pipe_validate_current_pdu: RPC fault " + "code %s received from %s!\n", + dcerpc_errstr(talloc_tos(), + pkt->u.fault.status), + rpccli_pipe_txt(talloc_tos(), cli))); + + if (NT_STATUS_IS_OK(NT_STATUS(pkt->u.fault.status))) { + return NT_STATUS_UNSUCCESSFUL; + } else { + return NT_STATUS(pkt->u.fault.status); } - default: - DEBUG(0, ("cli_pipe_validate_current_pdu: unknown packet type %u received " - "from %s!\n", - (unsigned int)prhdr->ptype, - rpccli_pipe_txt(talloc_tos(), cli))); - return NT_STATUS_INVALID_INFO_CLASS; + default: + DEBUG(0, ("Unknown packet type %u received from %s!\n", + (unsigned int)pkt->ptype, + rpccli_pipe_txt(talloc_tos(), cli))); + return NT_STATUS_INVALID_INFO_CLASS; } - if (prhdr->ptype != expected_pkt_type) { + if (pkt->ptype != expected_pkt_type) { DEBUG(3, ("cli_pipe_validate_current_pdu: Connection to %s " "got an unexpected RPC packet type - %u, not %u\n", rpccli_pipe_txt(talloc_tos(), cli), - prhdr->ptype, + pkt->ptype, expected_pkt_type)); return NT_STATUS_INVALID_INFO_CLASS; } @@ -1325,55 +1039,12 @@ static NTSTATUS cli_pipe_validate_current_pdu(struct rpc_pipe_client *cli, data before now as we may have needed to do cryptographic actions on it before. */ - if ((prhdr->ptype == DCERPC_PKT_BIND_ACK) && !(prhdr->pfc_flags & DCERPC_PFC_FLAG_LAST)) { + if ((pkt->ptype == DCERPC_PKT_BIND_ACK) && + !(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) { DEBUG(5,("cli_pipe_validate_current_pdu: bug in server (AS/U?), " "setting fragment first/last ON.\n")); - prhdr->pfc_flags |= DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST; - } - - return NT_STATUS_OK; -} - -/**************************************************************************** - Ensure we eat the just processed pdu from the current_pdu prs_struct. - Normally the frag_len and buffer size will match, but on the first trans - reply there is a theoretical chance that buffer size > frag_len, so we must - deal with that. - ****************************************************************************/ - -static NTSTATUS cli_pipe_reset_current_pdu(struct rpc_pipe_client *cli, - struct ncacn_packet_header *prhdr, - prs_struct *current_pdu) -{ - uint32 current_pdu_len = prs_data_size(current_pdu); - - if (current_pdu_len < prhdr->frag_length) { - return NT_STATUS_BUFFER_TOO_SMALL; - } - - /* Common case. */ - if (current_pdu_len == (uint32)prhdr->frag_length) { - prs_mem_free(current_pdu); - prs_init_empty(current_pdu, prs_get_mem_context(current_pdu), UNMARSHALL); - /* Make current_pdu dynamic with no memory. */ - prs_give_memory(current_pdu, 0, 0, True); - return NT_STATUS_OK; - } - - /* - * Oh no ! More data in buffer than we processed in current pdu. - * Cheat. Move the data down and shrink the buffer. - */ - - memcpy(prs_data_p(current_pdu), prs_data_p(current_pdu) + prhdr->frag_length, - current_pdu_len - prhdr->frag_length); - - /* Remember to set the read offset back to zero. */ - prs_set_offset(current_pdu, 0); - - /* Shrink the buffer. */ - if (!prs_set_buffer_size(current_pdu, current_pdu_len - prhdr->frag_length)) { - return NT_STATUS_BUFFER_TOO_SMALL; + pkt->pfc_flags |= DCERPC_PFC_FLAG_FIRST | + DCERPC_PFC_FLAG_LAST; } return NT_STATUS_OK; @@ -1539,7 +1210,7 @@ static NTSTATUS cli_api_pipe_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, } /**************************************************************************** - Send data on an rpc pipe via trans. The prs_struct data must be the last + Send data on an rpc pipe via trans. The data must be the last pdu fragment of an NDR data stream. Receive response data from an rpc pipe, which may be large... @@ -1569,11 +1240,13 @@ struct rpc_api_pipe_state { struct rpc_pipe_client *cli; uint8_t expected_pkt_type; - prs_struct incoming_frag; - struct ncacn_packet_header rhdr; + DATA_BLOB incoming_frag; + struct ncacn_packet *pkt; - prs_struct incoming_pdu; /* Incoming reply */ - uint32_t incoming_pdu_offset; + /* Incoming reply */ + DATA_BLOB reply_pdu; + size_t reply_pdu_offset; + uint8_t endianess; }; static void rpc_api_pipe_trans_done(struct tevent_req *subreq); @@ -1582,7 +1255,7 @@ static void rpc_api_pipe_got_pdu(struct tevent_req *subreq); static struct tevent_req *rpc_api_pipe_send(TALLOC_CTX *mem_ctx, struct event_context *ev, struct rpc_pipe_client *cli, - prs_struct *data, /* Outgoing PDU */ + DATA_BLOB *data, /* Outgoing PDU */ uint8_t expected_pkt_type) { struct tevent_req *req, *subreq; @@ -1597,33 +1270,27 @@ static struct tevent_req *rpc_api_pipe_send(TALLOC_CTX *mem_ctx, state->ev = ev; state->cli = cli; state->expected_pkt_type = expected_pkt_type; - state->incoming_pdu_offset = 0; - - prs_init_empty(&state->incoming_frag, state, UNMARSHALL); - - prs_init_empty(&state->incoming_pdu, state, UNMARSHALL); - /* Make incoming_pdu dynamic with no memory. */ - prs_give_memory(&state->incoming_pdu, NULL, 0, true); + state->incoming_frag = data_blob_null; + state->reply_pdu = data_blob_null; + state->reply_pdu_offset = 0; + state->endianess = DCERPC_DREP_LE; /* * Ensure we're not sending too much. */ - if (prs_offset(data) > cli->max_xmit_frag) { + if (data->length > cli->max_xmit_frag) { status = NT_STATUS_INVALID_PARAMETER; goto post_status; } DEBUG(5,("rpc_api_pipe: %s\n", rpccli_pipe_txt(talloc_tos(), cli))); - max_recv_frag = cli->max_recv_frag; - -#if 0 - max_recv_frag = RPC_HEADER_LEN + 10 + (sys_random() % 32); -#endif + /* get the header first, then fetch the rest once we have + * the frag_length available */ + max_recv_frag = RPC_HEADER_LEN; subreq = cli_api_pipe_send(state, ev, cli->transport, - (uint8_t *)prs_data_p(data), - prs_offset(data), max_recv_frag); + data->data, data->length, max_recv_frag); if (subreq == NULL) { goto fail; } @@ -1664,15 +1331,18 @@ static void rpc_api_pipe_trans_done(struct tevent_req *subreq) } /* - * This is equivalent to a talloc_steal - gives rdata to - * the prs_struct state->incoming_frag. + * Move data on state->incoming_frag. */ - prs_give_memory(&state->incoming_frag, (char *)rdata, rdata_len, true); - rdata = NULL; + state->incoming_frag.data = talloc_move(state, &rdata); + state->incoming_frag.length = rdata_len; + if (!state->incoming_frag.data) { + tevent_req_nterror(req, NT_STATUS_NO_MEMORY); + return; + } /* Ensure we have enough data for a pdu. */ subreq = get_complete_frag_send(state, state->ev, state->cli, - &state->rhdr, &state->incoming_frag); + &state->incoming_frag); if (tevent_req_nomem(subreq, req)) { return; } @@ -1686,8 +1356,7 @@ static void rpc_api_pipe_got_pdu(struct tevent_req *subreq) struct rpc_api_pipe_state *state = tevent_req_data( req, struct rpc_api_pipe_state); NTSTATUS status; - char *rdata = NULL; - uint32_t rdata_len = 0; + DATA_BLOB rdata = data_blob_null; status = get_complete_frag_recv(subreq); TALLOC_FREE(subreq); @@ -1698,14 +1367,22 @@ static void rpc_api_pipe_got_pdu(struct tevent_req *subreq) return; } - status = cli_pipe_validate_current_pdu( - state->cli, &state->rhdr, &state->incoming_frag, - state->expected_pkt_type, &rdata, &rdata_len, - &state->incoming_pdu); + state->pkt = talloc(state, struct ncacn_packet); + if (!state->pkt) { + tevent_req_nterror(req, NT_STATUS_NO_MEMORY); + return; + } + + status = cli_pipe_validate_current_pdu(state, + state->cli, state->pkt, + &state->incoming_frag, + state->expected_pkt_type, + &rdata, + &state->reply_pdu); DEBUG(10,("rpc_api_pipe: got frag len of %u at offset %u: %s\n", - (unsigned)prs_data_size(&state->incoming_frag), - (unsigned)state->incoming_pdu_offset, + (unsigned)state->incoming_frag.length, + (unsigned)state->reply_pdu_offset, nt_errstr(status))); if (!NT_STATUS_IS_OK(status)) { @@ -1713,8 +1390,8 @@ static void rpc_api_pipe_got_pdu(struct tevent_req *subreq) return; } - if ((state->rhdr.pfc_flags & DCERPC_PFC_FLAG_FIRST) - && (state->rhdr.drep[0] == 0)) { + if ((state->pkt->pfc_flags & DCERPC_PFC_FLAG_FIRST) + && (state->pkt->drep[0] != DCERPC_DREP_LE)) { /* * Set the data type correctly for big-endian data on the * first packet. @@ -1722,48 +1399,52 @@ static void rpc_api_pipe_got_pdu(struct tevent_req *subreq) DEBUG(10,("rpc_api_pipe: On %s PDU data format is " "big-endian.\n", rpccli_pipe_txt(talloc_tos(), state->cli))); - prs_set_endian_data(&state->incoming_pdu, RPC_BIG_ENDIAN); + state->endianess = 0x00; /* BIG ENDIAN */ } /* * Check endianness on subsequent packets. */ - if (state->incoming_frag.bigendian_data - != state->incoming_pdu.bigendian_data) { + if (state->endianess != state->pkt->drep[0]) { DEBUG(0,("rpc_api_pipe: Error : Endianness changed from %s to " "%s\n", - state->incoming_pdu.bigendian_data?"big":"little", - state->incoming_frag.bigendian_data?"big":"little")); + state->endianess?"little":"big", + state->pkt->drep[0]?"little":"big")); tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); return; } /* Now copy the data portion out of the pdu into rbuf. */ - if (!prs_force_grow(&state->incoming_pdu, rdata_len)) { - tevent_req_nterror(req, NT_STATUS_NO_MEMORY); - return; + if (state->reply_pdu.length < state->reply_pdu_offset + rdata.length) { + if (!data_blob_realloc(NULL, &state->reply_pdu, + state->reply_pdu_offset + rdata.length)) { + tevent_req_nterror(req, NT_STATUS_NO_MEMORY); + return; + } } - memcpy(prs_data_p(&state->incoming_pdu) + state->incoming_pdu_offset, - rdata, (size_t)rdata_len); - state->incoming_pdu_offset += rdata_len; + memcpy(state->reply_pdu.data + state->reply_pdu_offset, + rdata.data, rdata.length); + state->reply_pdu_offset += rdata.length; - status = cli_pipe_reset_current_pdu(state->cli, &state->rhdr, - &state->incoming_frag); - if (!NT_STATUS_IS_OK(status)) { - tevent_req_nterror(req, status); - return; - } + /* reset state->incoming_frag, there is no need to free it, + * it will be reallocated to the right size the next time + * it is used */ + state->incoming_frag.length = 0; - if (state->rhdr.pfc_flags & DCERPC_PFC_FLAG_LAST) { + if (state->pkt->pfc_flags & DCERPC_PFC_FLAG_LAST) { + /* make sure the pdu length is right now that we + * have all the data available (alloc hint may + * have allocated more than was actually used) */ + state->reply_pdu.length = state->reply_pdu_offset; DEBUG(10,("rpc_api_pipe: %s returned %u bytes.\n", rpccli_pipe_txt(talloc_tos(), state->cli), - (unsigned)prs_data_size(&state->incoming_pdu))); + (unsigned)state->reply_pdu.length)); tevent_req_done(req); return; } subreq = get_complete_frag_send(state, state->ev, state->cli, - &state->rhdr, &state->incoming_frag); + &state->incoming_frag); if (tevent_req_nomem(subreq, req)) { return; } @@ -1771,7 +1452,8 @@ static void rpc_api_pipe_got_pdu(struct tevent_req *subreq) } static NTSTATUS rpc_api_pipe_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, - prs_struct *reply_pdu) + struct ncacn_packet **pkt, + DATA_BLOB *reply_pdu) { struct rpc_api_pipe_state *state = tevent_req_data( req, struct rpc_api_pipe_state); @@ -1781,49 +1463,17 @@ static NTSTATUS rpc_api_pipe_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, return status; } - *reply_pdu = state->incoming_pdu; - reply_pdu->mem_ctx = mem_ctx; - - /* - * Prevent state->incoming_pdu from being freed - * when state is freed. - */ - talloc_steal(mem_ctx, prs_data_p(reply_pdu)); - prs_init_empty(&state->incoming_pdu, state, UNMARSHALL); - - return NT_STATUS_OK; -} - -/******************************************************************* - Creates an auth_data blob. - ********************************************************************/ - -NTSTATUS dcerpc_push_dcerpc_auth(TALLOC_CTX *mem_ctx, - enum dcerpc_AuthType auth_type, - enum dcerpc_AuthLevel auth_level, - uint8_t auth_pad_length, - uint32_t auth_context_id, - const DATA_BLOB *credentials, - DATA_BLOB *blob) -{ - struct dcerpc_auth r; - enum ndr_err_code ndr_err; - - r.auth_type = auth_type; - r.auth_level = auth_level; - r.auth_pad_length = auth_pad_length; - r.auth_reserved = 0; - r.auth_context_id = auth_context_id; - r.credentials = *credentials; - - ndr_err = ndr_push_struct_blob(blob, mem_ctx, &r, - (ndr_push_flags_fn_t)ndr_push_dcerpc_auth); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - return ndr_map_error2ntstatus(ndr_err); + /* return data to caller and assign it ownership of memory */ + if (reply_pdu) { + reply_pdu->data = talloc_move(mem_ctx, &state->reply_pdu.data); + reply_pdu->length = state->reply_pdu.length; + state->reply_pdu.length = 0; + } else { + data_blob_free(&state->reply_pdu); } - if (DEBUGLEVEL >= 10) { - NDR_PRINT_DEBUG(dcerpc_auth, &r); + if (pkt) { + *pkt = talloc_steal(mem_ctx, state->pkt); } return NT_STATUS_OK; @@ -2025,79 +1675,51 @@ static NTSTATUS create_schannel_auth_rpc_bind_req(struct rpc_pipe_client *cli, } /******************************************************************* - ********************************************************************/ - -static NTSTATUS init_dcerpc_ctx_list(TALLOC_CTX *mem_ctx, - const struct ndr_syntax_id *abstract_syntax, - const struct ndr_syntax_id *transfer_syntax, - struct dcerpc_ctx_list **ctx_list_p) -{ - struct dcerpc_ctx_list *ctx_list; - - ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1); - NT_STATUS_HAVE_NO_MEMORY(ctx_list); - - ctx_list[0].context_id = 0; - ctx_list[0].num_transfer_syntaxes = 1; - ctx_list[0].abstract_syntax = *abstract_syntax; - ctx_list[0].transfer_syntaxes = talloc_array(ctx_list, - struct ndr_syntax_id, - ctx_list[0].num_transfer_syntaxes); - NT_STATUS_HAVE_NO_MEMORY(ctx_list[0].transfer_syntaxes); - ctx_list[0].transfer_syntaxes[0] = *transfer_syntax; - - *ctx_list_p = ctx_list; - - return NT_STATUS_OK; -} - -/******************************************************************* Creates the internals of a DCE/RPC bind request or alter context PDU. ********************************************************************/ -static NTSTATUS create_bind_or_alt_ctx_internal(enum dcerpc_pkt_type ptype, - prs_struct *rpc_out, +static NTSTATUS create_bind_or_alt_ctx_internal(TALLOC_CTX *mem_ctx, + enum dcerpc_pkt_type ptype, uint32 rpc_call_id, const struct ndr_syntax_id *abstract, const struct ndr_syntax_id *transfer, - const DATA_BLOB *auth_info) + const DATA_BLOB *auth_info, + DATA_BLOB *blob) { uint16 auth_len = auth_info->length; NTSTATUS status; union dcerpc_payload u; - DATA_BLOB blob; - struct dcerpc_ctx_list *ctx_list; + struct dcerpc_ctx_list ctx_list; - status = init_dcerpc_ctx_list(rpc_out->mem_ctx, abstract, transfer, - &ctx_list); - if (!NT_STATUS_IS_OK(status)) { - return status; + if (auth_len) { + auth_len -= DCERPC_AUTH_TRAILER_LENGTH; } + ctx_list.context_id = 0; + ctx_list.num_transfer_syntaxes = 1; + ctx_list.abstract_syntax = *abstract; + ctx_list.transfer_syntaxes = (struct ndr_syntax_id *)discard_const(transfer); + u.bind.max_xmit_frag = RPC_MAX_PDU_FRAG_LEN; u.bind.max_recv_frag = RPC_MAX_PDU_FRAG_LEN; u.bind.assoc_group_id = 0x0; u.bind.num_contexts = 1; - u.bind.ctx_list = ctx_list; + u.bind.ctx_list = &ctx_list; u.bind.auth_info = *auth_info; - status = dcerpc_push_ncacn_packet(rpc_out->mem_ctx, + status = dcerpc_push_ncacn_packet(mem_ctx, ptype, DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST, - auth_len ? auth_len - RPC_HDR_AUTH_LEN : 0, + auth_len, rpc_call_id, &u, - &blob); + blob); if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("create_bind_or_alt_ctx_internal: failed to marshall RPC_HDR_RB.\n")); + DEBUG(0, ("Failed to marshall bind/alter ncacn_packet.\n")); return status; } - if (!prs_copy_data_in(rpc_out, (char *)blob.data, blob.length)) { - return NT_STATUS_NO_MEMORY; - } - return NT_STATUS_OK; } @@ -2105,13 +1727,14 @@ static NTSTATUS create_bind_or_alt_ctx_internal(enum dcerpc_pkt_type ptype, Creates a DCE/RPC bind request. ********************************************************************/ -static NTSTATUS create_rpc_bind_req(struct rpc_pipe_client *cli, - prs_struct *rpc_out, +static NTSTATUS create_rpc_bind_req(TALLOC_CTX *mem_ctx, + struct rpc_pipe_client *cli, uint32 rpc_call_id, const struct ndr_syntax_id *abstract, const struct ndr_syntax_id *transfer, enum pipe_auth_type auth_type, - enum dcerpc_AuthLevel auth_level) + enum dcerpc_AuthLevel auth_level, + DATA_BLOB *rpc_out) { DATA_BLOB auth_info = data_blob_null; NTSTATUS ret = NT_STATUS_OK; @@ -2153,12 +1776,13 @@ static NTSTATUS create_rpc_bind_req(struct rpc_pipe_client *cli, return NT_STATUS_INVALID_INFO_CLASS; } - ret = create_bind_or_alt_ctx_internal(DCERPC_PKT_BIND, - rpc_out, + ret = create_bind_or_alt_ctx_internal(mem_ctx, + DCERPC_PKT_BIND, rpc_call_id, abstract, transfer, - &auth_info); + &auth_info, + rpc_out); return ret; } @@ -2168,13 +1792,12 @@ static NTSTATUS create_rpc_bind_req(struct rpc_pipe_client *cli, static NTSTATUS add_ntlmssp_auth_footer(struct rpc_pipe_client *cli, uint32 ss_padding_len, - prs_struct *rpc_out) + DATA_BLOB *rpc_out) { DATA_BLOB auth_info; NTSTATUS status; DATA_BLOB auth_blob = data_blob_null; - uint16_t data_and_pad_len = - prs_offset(rpc_out) - RPC_HEADER_LEN - RPC_HDR_RESP_LEN; + uint16_t data_and_pad_len = rpc_out->length - DCERPC_RESPONSE_LENGTH; if (!cli->auth->a_u.ntlmssp_state) { return NT_STATUS_INVALID_PARAMETER; @@ -2183,7 +1806,7 @@ static NTSTATUS add_ntlmssp_auth_footer(struct rpc_pipe_client *cli, /* marshall the dcerpc_auth with an actually empty auth_blob. * this is needed because the ntmlssp signature includes the * auth header */ - status = dcerpc_push_dcerpc_auth(prs_get_mem_context(rpc_out), + status = dcerpc_push_dcerpc_auth(rpc_out->data, map_pipe_auth_type_to_rpc_auth_type(cli->auth->auth_type), cli->auth->auth_level, ss_padding_len, @@ -2195,26 +1818,25 @@ static NTSTATUS add_ntlmssp_auth_footer(struct rpc_pipe_client *cli, } /* append the header */ - if (!prs_copy_data_in(rpc_out, - (char *)auth_info.data, - auth_info.length)) { + if (!data_blob_append(NULL, rpc_out, + auth_info.data, auth_info.length)) { DEBUG(0, ("Failed to add %u bytes auth blob.\n", (unsigned int)auth_info.length)); return NT_STATUS_NO_MEMORY; } + data_blob_free(&auth_info); switch (cli->auth->auth_level) { case DCERPC_AUTH_LEVEL_PRIVACY: /* Data portion is encrypted. */ status = ntlmssp_seal_packet(cli->auth->a_u.ntlmssp_state, - prs_get_mem_context(rpc_out), - (unsigned char *)prs_data_p(rpc_out) - + RPC_HEADER_LEN - + RPC_HDR_RESP_LEN, - data_and_pad_len, - (unsigned char *)prs_data_p(rpc_out), - (size_t)prs_offset(rpc_out), - &auth_blob); + rpc_out->data, + rpc_out->data + + DCERPC_RESPONSE_LENGTH, + data_and_pad_len, + rpc_out->data, + rpc_out->length, + &auth_blob); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -2223,14 +1845,13 @@ static NTSTATUS add_ntlmssp_auth_footer(struct rpc_pipe_client *cli, case DCERPC_AUTH_LEVEL_INTEGRITY: /* Data is signed. */ status = ntlmssp_sign_packet(cli->auth->a_u.ntlmssp_state, - prs_get_mem_context(rpc_out), - (unsigned char *)prs_data_p(rpc_out) - + RPC_HEADER_LEN - + RPC_HDR_RESP_LEN, - data_and_pad_len, - (unsigned char *)prs_data_p(rpc_out), - (size_t)prs_offset(rpc_out), - &auth_blob); + rpc_out->data, + rpc_out->data + + DCERPC_RESPONSE_LENGTH, + data_and_pad_len, + rpc_out->data, + rpc_out->length, + &auth_blob); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -2244,13 +1865,13 @@ static NTSTATUS add_ntlmssp_auth_footer(struct rpc_pipe_client *cli, } /* Finally attach the blob. */ - if (!prs_copy_data_in(rpc_out, - (char *)auth_blob.data, - auth_blob.length)) { + if (!data_blob_append(NULL, rpc_out, + auth_blob.data, auth_blob.length)) { DEBUG(0, ("Failed to add %u bytes auth blob.\n", (unsigned int)auth_info.length)); return NT_STATUS_NO_MEMORY; } + data_blob_free(&auth_blob); return NT_STATUS_OK; } @@ -2261,12 +1882,13 @@ static NTSTATUS add_ntlmssp_auth_footer(struct rpc_pipe_client *cli, static NTSTATUS add_schannel_auth_footer(struct rpc_pipe_client *cli, uint32 ss_padding_len, - prs_struct *rpc_out) + DATA_BLOB *rpc_out) { DATA_BLOB auth_info; struct schannel_state *sas = cli->auth->a_u.schannel_auth; - char *data_p = prs_data_p(rpc_out) + RPC_HEADER_LEN + RPC_HDR_RESP_LEN; - size_t data_and_pad_len = prs_offset(rpc_out) - RPC_HEADER_LEN - RPC_HDR_RESP_LEN; + uint8_t *data_p = rpc_out->data + DCERPC_RESPONSE_LENGTH; + size_t data_and_pad_len = rpc_out->length + - DCERPC_RESPONSE_LENGTH; DATA_BLOB blob; NTSTATUS status; @@ -2280,17 +1902,17 @@ static NTSTATUS add_schannel_auth_footer(struct rpc_pipe_client *cli, switch (cli->auth->auth_level) { case DCERPC_AUTH_LEVEL_PRIVACY: status = netsec_outgoing_packet(sas, - talloc_tos(), + rpc_out->data, true, - (uint8_t *)data_p, + data_p, data_and_pad_len, &blob); break; case DCERPC_AUTH_LEVEL_INTEGRITY: status = netsec_outgoing_packet(sas, - talloc_tos(), + rpc_out->data, false, - (uint8_t *)data_p, + data_p, data_and_pad_len, &blob); break; @@ -2310,8 +1932,8 @@ static NTSTATUS add_schannel_auth_footer(struct rpc_pipe_client *cli, } /* Finally marshall the blob. */ - status = dcerpc_push_dcerpc_auth(prs_get_mem_context(rpc_out), - map_pipe_auth_type_to_rpc_auth_type(cli->auth->auth_type), + status = dcerpc_push_dcerpc_auth(rpc_out->data, + map_pipe_auth_type_to_rpc_auth_type(cli->auth->auth_type), cli->auth->auth_level, ss_padding_len, 1 /* context id. */, @@ -2320,10 +1942,13 @@ static NTSTATUS add_schannel_auth_footer(struct rpc_pipe_client *cli, if (!NT_STATUS_IS_OK(status)) { return status; } + data_blob_free(&blob); - if (!prs_copy_data_in(rpc_out, (const char *)auth_info.data, auth_info.length)) { + if (!data_blob_append(NULL, rpc_out, + auth_info.data, auth_info.length)) { return NT_STATUS_NO_MEMORY; } + data_blob_free(&auth_info); return NT_STATUS_OK; } @@ -2350,11 +1975,11 @@ static uint32 calculate_data_len_tosend(struct rpc_pipe_client *cli, switch (cli->auth->auth_level) { case DCERPC_AUTH_LEVEL_NONE: case DCERPC_AUTH_LEVEL_CONNECT: - data_space = cli->max_xmit_frag - RPC_HEADER_LEN - RPC_HDR_REQ_LEN; + data_space = cli->max_xmit_frag - DCERPC_REQUEST_LENGTH; data_len = MIN(data_space, data_left); *p_ss_padding = 0; *p_auth_len = 0; - *p_frag_len = RPC_HEADER_LEN + RPC_HDR_REQ_LEN + data_len; + *p_frag_len = DCERPC_REQUEST_LENGTH + data_len; return data_len; case DCERPC_AUTH_LEVEL_INTEGRITY: @@ -2366,24 +1991,27 @@ static uint32 calculate_data_len_tosend(struct rpc_pipe_client *cli, *p_auth_len = NTLMSSP_SIG_SIZE; break; case PIPE_AUTH_TYPE_SCHANNEL: - *p_auth_len = RPC_AUTH_SCHANNEL_SIGN_OR_SEAL_CHK_LEN; + *p_auth_len = SCHANNEL_SIG_SIZE; break; default: smb_panic("bad auth type"); break; } - data_space = cli->max_xmit_frag - RPC_HEADER_LEN - RPC_HDR_REQ_LEN - - RPC_HDR_AUTH_LEN - *p_auth_len; + data_space = cli->max_xmit_frag + - DCERPC_REQUEST_LENGTH + - DCERPC_AUTH_TRAILER_LENGTH + - *p_auth_len; data_len = MIN(data_space, data_left); *p_ss_padding = 0; if (data_len % CLIENT_NDR_PADDING_SIZE) { *p_ss_padding = CLIENT_NDR_PADDING_SIZE - (data_len % CLIENT_NDR_PADDING_SIZE); } - *p_frag_len = RPC_HEADER_LEN + RPC_HDR_REQ_LEN + /* Normal headers. */ - data_len + *p_ss_padding + /* data plus padding. */ - RPC_HDR_AUTH_LEN + *p_auth_len; /* Auth header and auth data. */ + *p_frag_len = DCERPC_REQUEST_LENGTH + + data_len + *p_ss_padding + + DCERPC_AUTH_TRAILER_LENGTH + + *p_auth_len; return data_len; default: @@ -2405,10 +2033,10 @@ struct rpc_api_pipe_req_state { struct rpc_pipe_client *cli; uint8_t op_num; uint32_t call_id; - prs_struct *req_data; + DATA_BLOB *req_data; uint32_t req_data_sent; - prs_struct outgoing_frag; - prs_struct reply_pdu; + DATA_BLOB rpc_out; + DATA_BLOB reply_pdu; }; static void rpc_api_pipe_req_write_done(struct tevent_req *subreq); @@ -2420,7 +2048,7 @@ struct tevent_req *rpc_api_pipe_req_send(TALLOC_CTX *mem_ctx, struct event_context *ev, struct rpc_pipe_client *cli, uint8_t op_num, - prs_struct *req_data) + DATA_BLOB *req_data) { struct tevent_req *req, *subreq; struct rpc_api_pipe_req_state *state; @@ -2438,21 +2066,16 @@ struct tevent_req *rpc_api_pipe_req_send(TALLOC_CTX *mem_ctx, state->req_data = req_data; state->req_data_sent = 0; state->call_id = get_rpc_call_id(); + state->reply_pdu = data_blob_null; + state->rpc_out = data_blob_null; - if (cli->max_xmit_frag - < RPC_HEADER_LEN + RPC_HDR_REQ_LEN + RPC_MAX_SIGN_SIZE) { + if (cli->max_xmit_frag < DCERPC_REQUEST_LENGTH + + RPC_MAX_SIGN_SIZE) { /* Server is screwed up ! */ status = NT_STATUS_INVALID_PARAMETER; goto post_status; } - prs_init_empty(&state->reply_pdu, state, UNMARSHALL); - - if (!prs_init(&state->outgoing_frag, cli->max_xmit_frag, - state, MARSHALL)) { - goto fail; - } - status = prepare_next_frag(state, &is_last_frag); if (!NT_STATUS_IS_OK(status)) { goto post_status; @@ -2460,17 +2083,16 @@ struct tevent_req *rpc_api_pipe_req_send(TALLOC_CTX *mem_ctx, if (is_last_frag) { subreq = rpc_api_pipe_send(state, ev, state->cli, - &state->outgoing_frag, + &state->rpc_out, DCERPC_PKT_RESPONSE); if (subreq == NULL) { goto fail; } tevent_req_set_callback(subreq, rpc_api_pipe_req_done, req); } else { - subreq = rpc_write_send( - state, ev, cli->transport, - (uint8_t *)prs_data_p(&state->outgoing_frag), - prs_offset(&state->outgoing_frag)); + subreq = rpc_write_send(state, ev, cli->transport, + state->rpc_out.data, + state->rpc_out.length); if (subreq == NULL) { goto fail; } @@ -2499,9 +2121,8 @@ static NTSTATUS prepare_next_frag(struct rpc_api_pipe_req_state *state, char pad[8] = { 0, }; NTSTATUS status; union dcerpc_payload u; - DATA_BLOB blob; - data_left = prs_offset(state->req_data) - state->req_data_sent; + data_left = state->req_data->length - state->req_data_sent; data_sent_thistime = calculate_data_len_tosend( state->cli, data_left, &frag_len, &auth_len, &ss_padding); @@ -2514,45 +2135,42 @@ static NTSTATUS prepare_next_frag(struct rpc_api_pipe_req_state *state, flags |= DCERPC_PFC_FLAG_LAST; } - if (!prs_set_offset(&state->outgoing_frag, 0)) { - return NT_STATUS_NO_MEMORY; - } + data_blob_free(&state->rpc_out); ZERO_STRUCT(u.request); - u.request.alloc_hint = prs_offset(state->req_data); + u.request.alloc_hint = state->req_data->length; u.request.context_id = 0; u.request.opnum = state->op_num; - status = dcerpc_push_ncacn_packet(prs_get_mem_context(&state->outgoing_frag), + status = dcerpc_push_ncacn_packet(state, DCERPC_PKT_REQUEST, flags, auth_len, state->call_id, &u, - &blob); + &state->rpc_out); if (!NT_STATUS_IS_OK(status)) { return status; } /* explicitly set frag_len here as dcerpc_push_ncacn_packet() can't * compute it right for requests */ - dcerpc_set_frag_length(&blob, frag_len); - - if (!prs_copy_data_in(&state->outgoing_frag, (const char *)blob.data, blob.length)) { - return NT_STATUS_NO_MEMORY; - } + dcerpc_set_frag_length(&state->rpc_out, frag_len); /* Copy in the data, plus any ss padding. */ - if (!prs_append_some_prs_data(&state->outgoing_frag, - state->req_data, state->req_data_sent, - data_sent_thistime)) { + if (!data_blob_append(NULL, &state->rpc_out, + state->req_data->data + state->req_data_sent, + data_sent_thistime)) { return NT_STATUS_NO_MEMORY; } - /* Copy the sign/seal padding data. */ - if (!prs_copy_data_in(&state->outgoing_frag, pad, ss_padding)) { - return NT_STATUS_NO_MEMORY; + if (ss_padding) { + /* Copy the sign/seal padding data. */ + if (!data_blob_append(NULL, &state->rpc_out, + pad, ss_padding)) { + return NT_STATUS_NO_MEMORY; + } } /* Generate any auth sign/seal and add the auth footer. */ @@ -2563,11 +2181,11 @@ static NTSTATUS prepare_next_frag(struct rpc_api_pipe_req_state *state, case PIPE_AUTH_TYPE_NTLMSSP: case PIPE_AUTH_TYPE_SPNEGO_NTLMSSP: status = add_ntlmssp_auth_footer(state->cli, ss_padding, - &state->outgoing_frag); + &state->rpc_out); break; case PIPE_AUTH_TYPE_SCHANNEL: status = add_schannel_auth_footer(state->cli, ss_padding, - &state->outgoing_frag); + &state->rpc_out); break; default: status = NT_STATUS_INVALID_PARAMETER; @@ -2604,18 +2222,17 @@ static void rpc_api_pipe_req_write_done(struct tevent_req *subreq) if (is_last_frag) { subreq = rpc_api_pipe_send(state, state->ev, state->cli, - &state->outgoing_frag, + &state->rpc_out, DCERPC_PKT_RESPONSE); if (tevent_req_nomem(subreq, req)) { return; } tevent_req_set_callback(subreq, rpc_api_pipe_req_done, req); } else { - subreq = rpc_write_send( - state, state->ev, - state->cli->transport, - (uint8_t *)prs_data_p(&state->outgoing_frag), - prs_offset(&state->outgoing_frag)); + subreq = rpc_write_send(state, state->ev, + state->cli->transport, + state->rpc_out.data, + state->rpc_out.length); if (tevent_req_nomem(subreq, req)) { return; } @@ -2632,7 +2249,7 @@ static void rpc_api_pipe_req_done(struct tevent_req *subreq) req, struct rpc_api_pipe_req_state); NTSTATUS status; - status = rpc_api_pipe_recv(subreq, state, &state->reply_pdu); + status = rpc_api_pipe_recv(subreq, state, NULL, &state->reply_pdu); TALLOC_FREE(subreq); if (!NT_STATUS_IS_OK(status)) { tevent_req_nterror(req, status); @@ -2642,7 +2259,7 @@ static void rpc_api_pipe_req_done(struct tevent_req *subreq) } NTSTATUS rpc_api_pipe_req_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, - prs_struct *reply_pdu) + DATA_BLOB *reply_pdu) { struct rpc_api_pipe_req_state *state = tevent_req_data( req, struct rpc_api_pipe_req_state); @@ -2653,19 +2270,14 @@ NTSTATUS rpc_api_pipe_req_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, * We always have to initialize to reply pdu, even if there is * none. The rpccli_* caller routines expect this. */ - prs_init_empty(reply_pdu, mem_ctx, UNMARSHALL); + *reply_pdu = data_blob_null; return status; } - *reply_pdu = state->reply_pdu; - reply_pdu->mem_ctx = mem_ctx; - - /* - * Prevent state->req_pdu from being freed - * when state is freed. - */ - talloc_steal(mem_ctx, prs_data_p(reply_pdu)); - prs_init_empty(&state->reply_pdu, state, UNMARSHALL); + /* return data to caller and assign it ownership of memory */ + reply_pdu->data = talloc_move(mem_ctx, &state->reply_pdu.data); + reply_pdu->length = state->reply_pdu.length; + state->reply_pdu.length = 0; return NT_STATUS_OK; } @@ -2759,20 +2371,20 @@ static bool check_bind_response(const struct dcerpc_bind_ack *r, the authentication handshake. ********************************************************************/ -static NTSTATUS create_rpc_bind_auth3(struct rpc_pipe_client *cli, +static NTSTATUS create_rpc_bind_auth3(TALLOC_CTX *mem_ctx, + struct rpc_pipe_client *cli, uint32 rpc_call_id, enum pipe_auth_type auth_type, enum dcerpc_AuthLevel auth_level, DATA_BLOB *pauth_blob, - prs_struct *rpc_out) + DATA_BLOB *rpc_out) { NTSTATUS status; union dcerpc_payload u; - DATA_BLOB blob; u.auth3._pad = 0; - status = dcerpc_push_dcerpc_auth(prs_get_mem_context(rpc_out), + status = dcerpc_push_dcerpc_auth(mem_ctx, map_pipe_auth_type_to_rpc_auth_type(auth_type), auth_level, 0, /* auth_pad_length */ @@ -2783,23 +2395,20 @@ static NTSTATUS create_rpc_bind_auth3(struct rpc_pipe_client *cli, return status; } - status = dcerpc_push_ncacn_packet(prs_get_mem_context(rpc_out), + status = dcerpc_push_ncacn_packet(mem_ctx, DCERPC_PKT_AUTH3, DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST, pauth_blob->length, rpc_call_id, &u, - &blob); + rpc_out); + data_blob_free(&u.auth3.auth_info); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("create_bind_or_alt_ctx_internal: failed to marshall RPC_HDR_RB.\n")); return status; } - if (!prs_copy_data_in(rpc_out, (char *)blob.data, blob.length)) { - return NT_STATUS_NO_MEMORY; - } - return NT_STATUS_OK; } @@ -2808,17 +2417,18 @@ static NTSTATUS create_rpc_bind_auth3(struct rpc_pipe_client *cli, may contain a spnego auth blobl ********************************************************************/ -static NTSTATUS create_rpc_alter_context(uint32 rpc_call_id, +static NTSTATUS create_rpc_alter_context(TALLOC_CTX *mem_ctx, + uint32 rpc_call_id, const struct ndr_syntax_id *abstract, const struct ndr_syntax_id *transfer, enum dcerpc_AuthLevel auth_level, const DATA_BLOB *pauth_blob, /* spnego auth blob already created. */ - prs_struct *rpc_out) + DATA_BLOB *rpc_out) { DATA_BLOB auth_info; NTSTATUS status; - status = dcerpc_push_dcerpc_auth(prs_get_mem_context(rpc_out), + status = dcerpc_push_dcerpc_auth(mem_ctx, DCERPC_AUTH_TYPE_SPNEGO, auth_level, 0, /* auth_pad_length */ @@ -2829,17 +2439,14 @@ static NTSTATUS create_rpc_alter_context(uint32 rpc_call_id, return status; } - - status = create_bind_or_alt_ctx_internal(DCERPC_PKT_ALTER, - rpc_out, + status = create_bind_or_alt_ctx_internal(mem_ctx, + DCERPC_PKT_ALTER, rpc_call_id, abstract, transfer, - &auth_info); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - + &auth_info, + rpc_out); + data_blob_free(&auth_info); return status; } @@ -2850,20 +2457,19 @@ static NTSTATUS create_rpc_alter_context(uint32 rpc_call_id, struct rpc_pipe_bind_state { struct event_context *ev; struct rpc_pipe_client *cli; - prs_struct rpc_out; + DATA_BLOB rpc_out; uint32_t rpc_call_id; }; static void rpc_pipe_bind_step_one_done(struct tevent_req *subreq); static NTSTATUS rpc_finish_auth3_bind_send(struct tevent_req *req, struct rpc_pipe_bind_state *state, - struct ncacn_packet *r, - prs_struct *reply_pdu); + struct ncacn_packet *r); static void rpc_bind_auth3_write_done(struct tevent_req *subreq); static NTSTATUS rpc_finish_spnego_ntlmssp_bind_send(struct tevent_req *req, struct rpc_pipe_bind_state *state, struct ncacn_packet *r, - prs_struct *reply_pdu); + DATA_BLOB *reply_pdu); static void rpc_bind_ntlmssp_api_done(struct tevent_req *subreq); struct tevent_req *rpc_pipe_bind_send(TALLOC_CTX *mem_ctx, @@ -2888,18 +2494,18 @@ struct tevent_req *rpc_pipe_bind_send(TALLOC_CTX *mem_ctx, state->ev = ev; state->cli = cli; state->rpc_call_id = get_rpc_call_id(); - - prs_init_empty(&state->rpc_out, state, MARSHALL); + state->rpc_out = data_blob_null; cli->auth = talloc_move(cli, &auth); /* Marshall the outgoing data. */ - status = create_rpc_bind_req(cli, &state->rpc_out, + status = create_rpc_bind_req(state, cli, state->rpc_call_id, &cli->abstract_syntax, &cli->transfer_syntax, cli->auth->auth_type, - cli->auth->auth_level); + cli->auth->auth_level, + &state->rpc_out); if (!NT_STATUS_IS_OK(status)) { goto post_status; @@ -2927,12 +2533,11 @@ static void rpc_pipe_bind_step_one_done(struct tevent_req *subreq) subreq, struct tevent_req); struct rpc_pipe_bind_state *state = tevent_req_data( req, struct rpc_pipe_bind_state); - prs_struct reply_pdu; - DATA_BLOB blob; - struct ncacn_packet r; + DATA_BLOB reply_pdu; + struct ncacn_packet *pkt; NTSTATUS status; - status = rpc_api_pipe_recv(subreq, talloc_tos(), &reply_pdu); + status = rpc_api_pipe_recv(subreq, talloc_tos(), &pkt, &reply_pdu); TALLOC_FREE(subreq); if (!NT_STATUS_IS_OK(status)) { DEBUG(3, ("rpc_pipe_bind: %s bind request returned %s\n", @@ -2942,23 +2547,14 @@ static void rpc_pipe_bind_step_one_done(struct tevent_req *subreq) return; } - blob = data_blob_const(prs_data_p(&reply_pdu), - prs_data_size(&reply_pdu)); - - status = dcerpc_pull_ncacn_packet(talloc_tos(), &blob, &r); - if (!NT_STATUS_IS_OK(status)) { - tevent_req_nterror(req, status); - return; - } - - if (!check_bind_response(&r.u.bind_ack, &state->cli->transfer_syntax)) { + if (!check_bind_response(&pkt->u.bind_ack, &state->cli->transfer_syntax)) { DEBUG(2, ("rpc_pipe_bind: check_bind_response failed.\n")); tevent_req_nterror(req, NT_STATUS_BUFFER_TOO_SMALL); return; } - state->cli->max_xmit_frag = r.u.bind_ack.max_xmit_frag; - state->cli->max_recv_frag = r.u.bind_ack.max_recv_frag; + state->cli->max_xmit_frag = pkt->u.bind_ack.max_xmit_frag; + state->cli->max_recv_frag = pkt->u.bind_ack.max_recv_frag; /* * For authenticated binds we may need to do 3 or 4 leg binds. @@ -2974,8 +2570,7 @@ static void rpc_pipe_bind_step_one_done(struct tevent_req *subreq) case PIPE_AUTH_TYPE_NTLMSSP: /* Need to send AUTH3 packet - no reply. */ - status = rpc_finish_auth3_bind_send(req, state, &r, - &reply_pdu); + status = rpc_finish_auth3_bind_send(req, state, pkt); if (!NT_STATUS_IS_OK(status)) { tevent_req_nterror(req, status); } @@ -2983,7 +2578,7 @@ static void rpc_pipe_bind_step_one_done(struct tevent_req *subreq) case PIPE_AUTH_TYPE_SPNEGO_NTLMSSP: /* Need to send alter context request and reply. */ - status = rpc_finish_spnego_ntlmssp_bind_send(req, state, &r, + status = rpc_finish_spnego_ntlmssp_bind_send(req, state, pkt, &reply_pdu); if (!NT_STATUS_IS_OK(status)) { tevent_req_nterror(req, status); @@ -3002,38 +2597,32 @@ static void rpc_pipe_bind_step_one_done(struct tevent_req *subreq) static NTSTATUS rpc_finish_auth3_bind_send(struct tevent_req *req, struct rpc_pipe_bind_state *state, - struct ncacn_packet *r, - prs_struct *reply_pdu) + struct ncacn_packet *r) { - DATA_BLOB server_response = data_blob_null; DATA_BLOB client_reply = data_blob_null; - struct rpc_hdr_auth_info hdr_auth; + struct dcerpc_auth auth; struct tevent_req *subreq; NTSTATUS status; if ((r->auth_length == 0) - || (r->frag_length < r->auth_length + RPC_HDR_AUTH_LEN)) { - return NT_STATUS_INVALID_PARAMETER; - } - - if (!prs_set_offset( - reply_pdu, - r->frag_length - r->auth_length - RPC_HDR_AUTH_LEN)) { + || (r->frag_length < DCERPC_AUTH_TRAILER_LENGTH + + r->auth_length)) { return NT_STATUS_INVALID_PARAMETER; } - if (!smb_io_rpc_hdr_auth("hdr_auth", &hdr_auth, reply_pdu, 0)) { - return NT_STATUS_INVALID_PARAMETER; + status = dcerpc_pull_dcerpc_auth(talloc_tos(), + &r->u.bind_ack.auth_info, + &auth); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("Failed to pull dcerpc auth: %s.\n", + nt_errstr(status))); + return status; } /* TODO - check auth_type/auth_level match. */ - server_response = data_blob_talloc(talloc_tos(), NULL, r->auth_length); - prs_copy_data_out((char *)server_response.data, reply_pdu, - r->auth_length); - status = ntlmssp_update(state->cli->auth->a_u.ntlmssp_state, - server_response, &client_reply); + auth.credentials, &client_reply); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("rpc_finish_auth3_bind: NTLMSSP update using server " @@ -3041,9 +2630,10 @@ static NTSTATUS rpc_finish_auth3_bind_send(struct tevent_req *req, return status; } - prs_init_empty(&state->rpc_out, talloc_tos(), MARSHALL); + data_blob_free(&state->rpc_out); - status = create_rpc_bind_auth3(state->cli, state->rpc_call_id, + status = create_rpc_bind_auth3(state, + state->cli, state->rpc_call_id, state->cli->auth->auth_type, state->cli->auth->auth_level, &client_reply, &state->rpc_out); @@ -3054,8 +2644,7 @@ static NTSTATUS rpc_finish_auth3_bind_send(struct tevent_req *req, } subreq = rpc_write_send(state, state->ev, state->cli->transport, - (uint8_t *)prs_data_p(&state->rpc_out), - prs_offset(&state->rpc_out)); + state->rpc_out.data, state->rpc_out.length); if (subreq == NULL) { return NT_STATUS_NO_MEMORY; } @@ -3081,7 +2670,7 @@ static void rpc_bind_auth3_write_done(struct tevent_req *subreq) static NTSTATUS rpc_finish_spnego_ntlmssp_bind_send(struct tevent_req *req, struct rpc_pipe_bind_state *state, struct ncacn_packet *r, - prs_struct *rpc_in) + DATA_BLOB *reply_pdu) { DATA_BLOB server_ntlm_response = data_blob_null; DATA_BLOB client_reply = data_blob_null; @@ -3092,19 +2681,18 @@ static NTSTATUS rpc_finish_spnego_ntlmssp_bind_send(struct tevent_req *req, NTSTATUS status; if ((r->auth_length == 0) - || (r->frag_length < r->auth_length + RPC_HDR_AUTH_LEN)) { + || (r->frag_length < DCERPC_AUTH_TRAILER_LENGTH + + r->auth_length)) { return NT_STATUS_INVALID_PARAMETER; } /* Process the returned NTLMSSP blob first. */ - if (!prs_set_offset( - rpc_in, - r->frag_length - r->auth_length - RPC_HDR_AUTH_LEN)) { - return NT_STATUS_INVALID_PARAMETER; - } - - auth_blob = data_blob_const(prs_data_p(rpc_in) + prs_offset(rpc_in), - prs_data_size(rpc_in) - prs_offset(rpc_in)); + auth_blob = data_blob_const(reply_pdu->data + + r->frag_length + - DCERPC_AUTH_TRAILER_LENGTH + - r->auth_length, + DCERPC_AUTH_TRAILER_LENGTH + + r->auth_length); status = dcerpc_pull_dcerpc_auth(state, &auth_blob, &auth_info); if (!NT_STATUS_IS_OK(status)) { @@ -3146,9 +2734,10 @@ static NTSTATUS rpc_finish_spnego_ntlmssp_bind_send(struct tevent_req *req, tmp_blob = data_blob_null; /* Now prepare the alter context pdu. */ - prs_init_empty(&state->rpc_out, state, MARSHALL); + data_blob_free(&state->rpc_out); - status = create_rpc_alter_context(state->rpc_call_id, + status = create_rpc_alter_context(state, + state->rpc_call_id, &state->cli->abstract_syntax, &state->cli->transfer_syntax, state->cli->auth->auth_level, @@ -3175,52 +2764,35 @@ static void rpc_bind_ntlmssp_api_done(struct tevent_req *subreq) subreq, struct tevent_req); struct rpc_pipe_bind_state *state = tevent_req_data( req, struct rpc_pipe_bind_state); - DATA_BLOB server_spnego_response = data_blob_null; DATA_BLOB tmp_blob = data_blob_null; - prs_struct reply_pdu; - struct ncacn_packet_header hdr; - struct rpc_hdr_auth_info hdr_auth; + struct ncacn_packet *pkt; + struct dcerpc_auth auth; NTSTATUS status; - status = rpc_api_pipe_recv(subreq, talloc_tos(), &reply_pdu); + status = rpc_api_pipe_recv(subreq, talloc_tos(), &pkt, NULL); TALLOC_FREE(subreq); if (!NT_STATUS_IS_OK(status)) { tevent_req_nterror(req, status); return; } - status = parse_rpc_header(state->cli, &hdr, &reply_pdu); + status = dcerpc_pull_dcerpc_auth(pkt, + &pkt->u.alter_resp.auth_info, + &auth); if (!NT_STATUS_IS_OK(status)) { tevent_req_nterror(req, status); return; } - if (!prs_set_offset( - &reply_pdu, - hdr.frag_length - hdr.auth_length - RPC_HDR_AUTH_LEN)) { - tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; - } - - if (!smb_io_rpc_hdr_auth("hdr_auth", &hdr_auth, &reply_pdu, 0)) { - tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; - } - - server_spnego_response = data_blob(NULL, hdr.auth_length); - prs_copy_data_out((char *)server_spnego_response.data, &reply_pdu, - hdr.auth_length); - /* Check we got a valid auth response. */ - if (!spnego_parse_auth_response(server_spnego_response, NT_STATUS_OK, + if (!spnego_parse_auth_response(auth.credentials, + NT_STATUS_OK, OID_NTLMSSP, &tmp_blob)) { - data_blob_free(&server_spnego_response); data_blob_free(&tmp_blob); tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); return; } - data_blob_free(&server_spnego_response); data_blob_free(&tmp_blob); DEBUG(5,("rpc_finish_spnego_ntlmssp_bind: alter context request to " diff --git a/source3/rpc_client/ndr.c b/source3/rpc_client/ndr.c index 8e03f2e015..a1642c03ff 100644 --- a/source3/rpc_client/ndr.c +++ b/source3/rpc_client/ndr.c @@ -24,7 +24,8 @@ struct cli_do_rpc_ndr_state { const struct ndr_interface_call *call; - prs_struct q_ps, r_ps; + DATA_BLOB q_pdu; + DATA_BLOB r_pdu; void *r; }; @@ -40,9 +41,7 @@ struct tevent_req *cli_do_rpc_ndr_send(TALLOC_CTX *mem_ctx, struct tevent_req *req, *subreq; struct cli_do_rpc_ndr_state *state; struct ndr_push *push; - DATA_BLOB blob; enum ndr_err_code ndr_err; - bool ret; req = tevent_req_create(mem_ctx, &state, struct cli_do_rpc_ndr_state); @@ -64,7 +63,7 @@ struct tevent_req *cli_do_rpc_ndr_send(TALLOC_CTX *mem_ctx, state->call->name, NDR_IN, r); } - push = ndr_push_init_ctx(talloc_tos()); + push = ndr_push_init_ctx(state); if (tevent_req_nomem(push, req)) { return tevent_req_post(req, ev); } @@ -76,16 +75,11 @@ struct tevent_req *cli_do_rpc_ndr_send(TALLOC_CTX *mem_ctx, return tevent_req_post(req, ev); } - blob = ndr_push_blob(push); - ret = prs_init_data_blob(&state->q_ps, &blob, state); + state->q_pdu = ndr_push_blob(push); + talloc_steal(mem_ctx, state->q_pdu.data); TALLOC_FREE(push); - if (!ret) { - tevent_req_nterror(req, NT_STATUS_NO_MEMORY); - return tevent_req_post(req, ev); - } - - subreq = rpc_api_pipe_req_send(state, ev, cli, opnum, &state->q_ps); + subreq = rpc_api_pipe_req_send(state, ev, cli, opnum, &state->q_pdu); if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } @@ -101,7 +95,7 @@ static void cli_do_rpc_ndr_done(struct tevent_req *subreq) req, struct cli_do_rpc_ndr_state); NTSTATUS status; - status = rpc_api_pipe_req_recv(subreq, state, &state->r_ps); + status = rpc_api_pipe_req_recv(subreq, state, &state->r_pdu); TALLOC_FREE(subreq); if (!NT_STATUS_IS_OK(status)) { tevent_req_nterror(req, status); @@ -117,19 +111,12 @@ NTSTATUS cli_do_rpc_ndr_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx) struct ndr_pull *pull; enum ndr_err_code ndr_err; NTSTATUS status; - DATA_BLOB blob; - bool ret; if (tevent_req_is_nterror(req, &status)) { return status; } - ret = prs_data_blob(&state->r_ps, &blob, talloc_tos()); - if (!ret) { - return NT_STATUS_NO_MEMORY; - } - - pull = ndr_pull_init_blob(&blob, mem_ctx); + pull = ndr_pull_init_blob(&state->r_pdu, mem_ctx); if (pull == NULL) { return NT_STATUS_NO_MEMORY; } diff --git a/source3/rpc_parse/parse_misc.c b/source3/rpc_parse/parse_misc.c deleted file mode 100644 index c000923b9e..0000000000 --- a/source3/rpc_parse/parse_misc.c +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * RPC Pipe client / server routines - * Copyright (C) Andrew Tridgell 1992-1997, - * Copyright (C) Luke Kenneth Casson Leighton 1996-1997, - * Copyright (C) Paul Ashton 1997. - * Copyright (C) Gerald (Jerry) Carter 2005 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "includes.h" - -#undef DBGC_CLASS -#define DBGC_CLASS DBGC_RPC_PARSE - -/******************************************************************* - Reads or writes an NTTIME structure. -********************************************************************/ - -bool smb_io_time(const char *desc, NTTIME *nttime, prs_struct *ps, int depth) -{ - uint32 low, high; - if (nttime == NULL) - return False; - - prs_debug(ps, depth, desc, "smb_io_time"); - depth++; - - if(!prs_align(ps)) - return False; - - if (MARSHALLING(ps)) { - low = *nttime & 0xFFFFFFFF; - high = *nttime >> 32; - } - - if(!prs_uint32("low ", ps, depth, &low)) /* low part */ - return False; - if(!prs_uint32("high", ps, depth, &high)) /* high part */ - return False; - - if (UNMARSHALLING(ps)) { - *nttime = (((uint64_t)high << 32) + low); - } - - return True; -} - -/******************************************************************* - Reads or writes a struct GUID -********************************************************************/ - -bool smb_io_uuid(const char *desc, struct GUID *uuid, - prs_struct *ps, int depth) -{ - if (uuid == NULL) - return False; - - prs_debug(ps, depth, desc, "smb_io_uuid"); - depth++; - - if(!prs_uint32 ("data ", ps, depth, &uuid->time_low)) - return False; - if(!prs_uint16 ("data ", ps, depth, &uuid->time_mid)) - return False; - if(!prs_uint16 ("data ", ps, depth, &uuid->time_hi_and_version)) - return False; - - if(!prs_uint8s (False, "data ", ps, depth, uuid->clock_seq, sizeof(uuid->clock_seq))) - return False; - if(!prs_uint8s (False, "data ", ps, depth, uuid->node, sizeof(uuid->node))) - return False; - - return True; -} diff --git a/source3/rpc_parse/parse_rpc.c b/source3/rpc_parse/parse_rpc.c deleted file mode 100644 index 8ece183251..0000000000 --- a/source3/rpc_parse/parse_rpc.c +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * RPC Pipe client / server routines - * Copyright (C) Andrew Tridgell 1992-1997, - * Copyright (C) Luke Kenneth Casson Leighton 1996-1997, - * Copyright (C) Paul Ashton 1997. - * Copyright (C) Jeremy Allison 1999. - * Copyright (C) Simo Sorce 2010 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "includes.h" -#include "librpc/gen_ndr/ndr_dcerpc.h" - -#undef DBGC_CLASS -#define DBGC_CLASS DBGC_RPC_PARSE - -NTSTATUS dcerpc_pull_dcerpc_bind(TALLOC_CTX *mem_ctx, - const DATA_BLOB *blob, - struct dcerpc_bind *r) -{ - enum ndr_err_code ndr_err; - - ndr_err = ndr_pull_struct_blob(blob, mem_ctx, r, - (ndr_pull_flags_fn_t)ndr_pull_dcerpc_bind); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - return ndr_map_error2ntstatus(ndr_err); - } - - return NT_STATUS_OK; -} - -/******************************************************************* - Reads or writes an RPC_HDR_RESP structure. -********************************************************************/ - -bool smb_io_rpc_hdr_resp(const char *desc, RPC_HDR_RESP *rpc, prs_struct *ps, int depth) -{ - if (rpc == NULL) - return False; - - prs_debug(ps, depth, desc, "smb_io_rpc_hdr_resp"); - depth++; - - if(!prs_uint32("alloc_hint", ps, depth, &rpc->alloc_hint)) - return False; - if(!prs_uint16("context_id", ps, depth, &rpc->context_id)) - return False; - if(!prs_uint8 ("cancel_ct ", ps, depth, &rpc->cancel_count)) - return False; - if(!prs_uint8 ("reserved ", ps, depth, &rpc->reserved)) - return False; - return True; -} - -/******************************************************************* - Inits an RPC_HDR_AUTH structure. -********************************************************************/ - -void init_rpc_hdr_auth(RPC_HDR_AUTH *rai, - uint8 auth_type, uint8 auth_level, - uint8 auth_pad_len, - uint32 auth_context_id) -{ - rai->auth_type = auth_type; - rai->auth_level = auth_level; - rai->auth_pad_len = auth_pad_len; - rai->auth_reserved = 0; - rai->auth_context_id = auth_context_id; -} - -/******************************************************************* - Reads or writes an RPC_HDR_AUTH structure. - NB This writes UNALIGNED. Ensure you're correctly aligned before - calling. -********************************************************************/ - -bool smb_io_rpc_hdr_auth(const char *desc, RPC_HDR_AUTH *rai, prs_struct *ps, int depth) -{ - if (rai == NULL) - return False; - - prs_debug(ps, depth, desc, "smb_io_rpc_hdr_auth"); - depth++; - - if(!prs_uint8 ("auth_type ", ps, depth, &rai->auth_type)) - return False; - if(!prs_uint8 ("auth_level ", ps, depth, &rai->auth_level)) - return False; - if(!prs_uint8 ("auth_pad_len ", ps, depth, &rai->auth_pad_len)) - return False; - if(!prs_uint8 ("auth_reserved", ps, depth, &rai->auth_reserved)) - return False; - if(!prs_uint32("auth_context_id", ps, depth, &rai->auth_context_id)) - return False; - - return True; -} diff --git a/source3/rpc_server/rpc_ncacn_np_internal.c b/source3/rpc_server/rpc_ncacn_np_internal.c index 22e03525ff..b79b479a08 100644 --- a/source3/rpc_server/rpc_ncacn_np_internal.c +++ b/source3/rpc_server/rpc_ncacn_np_internal.c @@ -144,20 +144,6 @@ struct pipes_struct *make_internal_rpc_pipe_p(TALLOC_CTX *mem_ctx, return NULL; } - /* - * Initialize the incoming RPC data buffer with one PDU worth of memory. - * We cheat here and say we're marshalling, as we intend to add incoming - * data directly into the prs_struct and we want it to auto grow. We will - * change the type to UNMARSALLING before processing the stream. - */ - - if(!prs_init(&p->in_data.data, 128, p->mem_ctx, MARSHALL)) { - DEBUG(0,("open_rpc_pipe_p: malloc fail for in_data struct.\n")); - close_policy_by_pipe(p); - TALLOC_FREE(p); - return NULL; - } - p->server_info = copy_serverinfo(p, server_info); if (p->server_info == NULL) { DEBUG(0, ("open_rpc_pipe_p: copy_serverinfo failed\n")); @@ -172,11 +158,6 @@ struct pipes_struct *make_internal_rpc_pipe_p(TALLOC_CTX *mem_ctx, p->endian = RPC_LITTLE_ENDIAN; - /* - * Initialize the outgoing RPC data buffer with no memory. - */ - prs_init_empty(&p->out_data.rdata, p->mem_ctx, MARSHALL); - p->syntax = *syntax; DEBUG(4,("Created internal pipe %s (pipes_open=%d)\n", @@ -199,8 +180,6 @@ static NTSTATUS internal_ndr_push(TALLOC_CTX *mem_ctx, const struct ndr_interface_call *call; struct ndr_push *push; enum ndr_err_code ndr_err; - DATA_BLOB blob; - bool ret; if (!ndr_syntax_id_equal(&table->syntax_id, &cli->abstract_syntax) || (opnum >= table->num_calls)) { @@ -225,12 +204,10 @@ static NTSTATUS internal_ndr_push(TALLOC_CTX *mem_ctx, return ndr_map_error2ntstatus(ndr_err); } - blob = ndr_push_blob(push); - ret = prs_init_data_blob(&cli->pipes_struct->in_data.data, &blob, mem_ctx); + cli->pipes_struct->in_data.data = ndr_push_blob(push); + talloc_steal(cli->pipes_struct->mem_ctx, + cli->pipes_struct->in_data.data.data); TALLOC_FREE(push); - if (!ret) { - return NT_STATUS_NO_MEMORY; - } return NT_STATUS_OK; } @@ -247,8 +224,6 @@ static NTSTATUS internal_ndr_pull(TALLOC_CTX *mem_ctx, const struct ndr_interface_call *call; struct ndr_pull *pull; enum ndr_err_code ndr_err; - DATA_BLOB blob; - bool ret; if (!ndr_syntax_id_equal(&table->syntax_id, &cli->abstract_syntax) || (opnum >= table->num_calls)) { @@ -257,12 +232,8 @@ static NTSTATUS internal_ndr_pull(TALLOC_CTX *mem_ctx, call = &table->calls[opnum]; - ret = prs_data_blob(&cli->pipes_struct->out_data.rdata, &blob, mem_ctx); - if (!ret) { - return NT_STATUS_NO_MEMORY; - } - - pull = ndr_pull_init_blob(&blob, mem_ctx); + pull = ndr_pull_init_blob(&cli->pipes_struct->out_data.rdata, + mem_ctx); if (pull == NULL) { return NT_STATUS_NO_MEMORY; } @@ -314,8 +285,6 @@ static NTSTATUS rpc_pipe_internal_dispatch(struct rpc_pipe_client *cli, return NT_STATUS_INVALID_PARAMETER; } - prs_init_empty(&cli->pipes_struct->out_data.rdata, cli->pipes_struct->mem_ctx, MARSHALL); - status = internal_ndr_push(mem_ctx, cli, table, opnum, r); if (!NT_STATUS_IS_OK(status)) { return status; @@ -330,8 +299,8 @@ static NTSTATUS rpc_pipe_internal_dispatch(struct rpc_pipe_client *cli, return status; } - prs_mem_free(&cli->pipes_struct->in_data.data); - prs_mem_free(&cli->pipes_struct->out_data.rdata); + data_blob_free(&cli->pipes_struct->in_data.data); + data_blob_free(&cli->pipes_struct->out_data.rdata); return NT_STATUS_OK; } diff --git a/source3/rpc_server/srv_pipe.c b/source3/rpc_server/srv_pipe.c index 85c212aa93..6d37ec2bc2 100644 --- a/source3/rpc_server/srv_pipe.c +++ b/source3/rpc_server/srv_pipe.c @@ -37,6 +37,51 @@ #undef DBGC_CLASS #define DBGC_CLASS DBGC_RPC_SRV +/** + * Dump everything from the start of the end up of the provided data + * into a file, but only at debug level >= 50 + **/ +static void dump_pdu_region(const char *name, int v, + DATA_BLOB *data, size_t start, size_t end) +{ + int fd, i; + char *fname = NULL; + ssize_t sz; + + if (DEBUGLEVEL < 50) return; + + if (start > data->length || end > data->length || start > end) return; + + for (i = 1; i < 100; i++) { + if (v != -1) { + fname = talloc_asprintf(talloc_tos(), + "/tmp/%s_%d.%d.prs", + name, v, i); + } else { + fname = talloc_asprintf(talloc_tos(), + "/tmp/%s_%d.prs", + name, i); + } + if (!fname) { + return; + } + fd = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0644); + if (fd != -1 || errno != EEXIST) break; + } + if (fd != -1) { + sz = write(fd, data->data + start, end - start); + i = close(fd); + if ((sz != end - start) || (i != 0) ) { + DEBUG(0, ("Error writing/closing %s: %ld!=%ld %d\n", + fname, (unsigned long)sz, + (unsigned long)end - start, i)); + } else { + DEBUG(0,("created %s\n", fname)); + } + } + TALLOC_FREE(fname); +} + static void free_pipe_ntlmssp_auth_data(struct pipe_auth_data *auth) { struct auth_ntlmssp_state *a = auth->a_u.auth_ntlmssp_state; @@ -53,625 +98,350 @@ static DATA_BLOB generic_session_key(void) } /******************************************************************* - Generate the next PDU to be returned from the data in p->rdata. Handle NTLMSSP. ********************************************************************/ -static bool create_next_pdu_ntlmssp(pipes_struct *p) +static bool add_ntlmssp_auth(pipes_struct *p) { - DATA_BLOB hdr; - uint8_t hdr_flags; - RPC_HDR_RESP hdr_resp; - uint32 ss_padding_len = 0; - uint32 data_space_available; - uint32 data_len_left; - uint32 data_len; + enum dcerpc_AuthLevel auth_level = p->auth.auth_level; + DATA_BLOB auth_blob = data_blob_null; NTSTATUS status; - DATA_BLOB auth_blob; - RPC_HDR_AUTH auth_info; - uint8 auth_type, auth_level; - struct auth_ntlmssp_state *a = p->auth.a_u.auth_ntlmssp_state; - TALLOC_CTX *frame; - /* - * If we're in the fault state, keep returning fault PDU's until - * the pipe gets closed. JRA. + /* FIXME: Is this right ? + * Keeping only to avoid changing semantics during refactoring + * --simo */ - - if(p->fault_state) { - setup_fault_pdu(p, NT_STATUS(DCERPC_FAULT_OP_RNG_ERROR)); - return True; - } - - memset((char *)&hdr_resp, '\0', sizeof(hdr_resp)); - - /* Set up rpc header flags. */ - if (p->out_data.data_sent_length == 0) { - hdr_flags = DCERPC_PFC_FLAG_FIRST; - } else { - hdr_flags = 0; - } - - /* - * Work out how much we can fit in a single PDU. - */ - - data_len_left = prs_offset(&p->out_data.rdata) - p->out_data.data_sent_length; - - /* - * Ensure there really is data left to send. - */ - - if(!data_len_left) { - DEBUG(0,("create_next_pdu_ntlmssp: no data left to send !\n")); - return False; - } - - /* Space available - not including padding. */ - data_space_available = RPC_MAX_PDU_FRAG_LEN - RPC_HEADER_LEN - - RPC_HDR_RESP_LEN - RPC_HDR_AUTH_LEN - NTLMSSP_SIG_SIZE; - - /* - * The amount we send is the minimum of the available - * space and the amount left to send. - */ - - data_len = MIN(data_len_left, data_space_available); - - /* Work out any padding alignment requirements. */ - if ((RPC_HEADER_LEN + RPC_HDR_RESP_LEN + data_len) % SERVER_NDR_PADDING_SIZE) { - ss_padding_len = SERVER_NDR_PADDING_SIZE - - ((RPC_HEADER_LEN + RPC_HDR_RESP_LEN + data_len) % SERVER_NDR_PADDING_SIZE); - DEBUG(10,("create_next_pdu_ntlmssp: adding sign/seal padding of %u\n", - ss_padding_len )); - /* If we're over filling the packet, we need to make space - * for the padding at the end of the data. */ - if (data_len + ss_padding_len > data_space_available) { - data_len -= SERVER_NDR_PADDING_SIZE; - } + if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) { + auth_level = DCERPC_AUTH_LEVEL_INTEGRITY; } - /* - * Set up the alloc hint. This should be the data left to - * send. - */ + /* Generate the auth blob. */ + switch (auth_level) { + case DCERPC_AUTH_LEVEL_PRIVACY: + /* Data portion is encrypted. */ + status = auth_ntlmssp_seal_packet( + p->auth.a_u.auth_ntlmssp_state, + (TALLOC_CTX *)p->out_data.frag.data, + &p->out_data.frag.data[DCERPC_RESPONSE_LENGTH], + p->out_data.frag.length + - DCERPC_RESPONSE_LENGTH + - DCERPC_AUTH_TRAILER_LENGTH, + p->out_data.frag.data, + p->out_data.frag.length, + &auth_blob); + break; - hdr_resp.alloc_hint = data_len_left; + case DCERPC_AUTH_LEVEL_INTEGRITY: + /* Data is signed. */ + status = auth_ntlmssp_sign_packet( + p->auth.a_u.auth_ntlmssp_state, + (TALLOC_CTX *)p->out_data.frag.data, + &p->out_data.frag.data[DCERPC_RESPONSE_LENGTH], + p->out_data.frag.length + - DCERPC_RESPONSE_LENGTH + - DCERPC_AUTH_TRAILER_LENGTH, + p->out_data.frag.data, + p->out_data.frag.length, + &auth_blob); + break; - /* - * Work out if this PDU will be the last. - */ - if (p->out_data.data_sent_length + data_len >= - prs_offset(&p->out_data.rdata)) { - hdr_flags |= DCERPC_PFC_FLAG_LAST; + default: + status = NT_STATUS_INTERNAL_ERROR; + return false; } - /* - * Init the parse struct to point at the outgoing - * data. - */ - prs_init_empty(&p->out_data.frag, p->mem_ctx, MARSHALL); - - status = dcerpc_push_ncacn_packet_header( - prs_get_mem_context(&p->out_data.frag), - DCERPC_PKT_RESPONSE, - hdr_flags, - RPC_HEADER_LEN + RPC_HDR_RESP_LEN + - data_len + ss_padding_len + - RPC_HDR_AUTH_LEN + NTLMSSP_SIG_SIZE, - NTLMSSP_SIG_SIZE, - p->call_id, - &hdr); if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("Failed to marshall RPC Header.\n")); - prs_mem_free(&p->out_data.frag); - return False; - } - - /* Store the header in the data stream. */ - if (!prs_copy_data_in(&p->out_data.frag, - (char *)hdr.data, hdr.length)) { - DEBUG(0, ("Out of memory.\n")); - prs_mem_free(&p->out_data.frag); - return False; + DEBUG(0, ("Failed to add NTLMSSP auth blob: %s\n", + nt_errstr(status))); + data_blob_free(&p->out_data.frag); + return false; } - if(!smb_io_rpc_hdr_resp("resp", &hdr_resp, &p->out_data.frag, 0)) { - DEBUG(0,("create_next_pdu_ntlmssp: failed to marshall RPC_HDR_RESP.\n")); - prs_mem_free(&p->out_data.frag); + /* Finally append the auth blob. */ + if (!data_blob_append(p->mem_ctx, &p->out_data.frag, + auth_blob.data, auth_blob.length)) { + DEBUG(0, ("Failed to add %u bytes auth blob.\n", + (unsigned int)auth_blob.length)); + data_blob_free(&p->out_data.frag); return False; } + data_blob_free(&auth_blob); - /* Copy the data into the PDU. */ + return true; +} - if(!prs_append_some_prs_data(&p->out_data.frag, &p->out_data.rdata, - p->out_data.data_sent_length, data_len)) { - DEBUG(0,("create_next_pdu_ntlmssp: failed to copy %u bytes of data.\n", (unsigned int)data_len)); - prs_mem_free(&p->out_data.frag); - return False; - } +/******************************************************************* + Append a schannel authenticated fragment. + ********************************************************************/ - /* Copy the sign/seal padding data. */ - if (ss_padding_len) { - char pad[SERVER_NDR_PADDING_SIZE]; +static bool add_schannel_auth(pipes_struct *p) +{ + DATA_BLOB auth_blob = data_blob_null; + NTSTATUS status; - memset(pad, '\0', SERVER_NDR_PADDING_SIZE); - if (!prs_copy_data_in(&p->out_data.frag, pad, - ss_padding_len)) { - DEBUG(0,("create_next_pdu_ntlmssp: failed to add %u bytes of pad data.\n", - (unsigned int)ss_padding_len)); - prs_mem_free(&p->out_data.frag); - return False; - } - } + /* Schannel processing. */ + switch (p->auth.auth_level) { + case DCERPC_AUTH_LEVEL_PRIVACY: + status = netsec_outgoing_packet( + p->auth.a_u.schannel_auth, + (TALLOC_CTX *)p->out_data.frag.data, + true, + &p->out_data.frag.data[DCERPC_RESPONSE_LENGTH], + p->out_data.frag.length + - DCERPC_RESPONSE_LENGTH + - DCERPC_AUTH_TRAILER_LENGTH, + &auth_blob); + break; + case DCERPC_AUTH_LEVEL_INTEGRITY: + status = netsec_outgoing_packet( + p->auth.a_u.schannel_auth, + (TALLOC_CTX *)p->out_data.frag.data, + false, + &p->out_data.frag.data[DCERPC_RESPONSE_LENGTH], + p->out_data.frag.length + - DCERPC_RESPONSE_LENGTH + - DCERPC_AUTH_TRAILER_LENGTH, + &auth_blob); + break; - /* Now write out the auth header and null blob. */ - if (p->auth.auth_type == PIPE_AUTH_TYPE_NTLMSSP) { - auth_type = DCERPC_AUTH_TYPE_NTLMSSP; - } else { - auth_type = DCERPC_AUTH_TYPE_SPNEGO; - } - if (p->auth.auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { - auth_level = DCERPC_AUTH_LEVEL_PRIVACY; - } else { - auth_level = DCERPC_AUTH_LEVEL_INTEGRITY; + default: + status = NT_STATUS_INTERNAL_ERROR; + break; } - init_rpc_hdr_auth(&auth_info, auth_type, auth_level, ss_padding_len, 1 /* context id. */); - - if (!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, - &p->out_data.frag, 0)) { - DEBUG(0,("create_next_pdu_ntlmssp: failed to marshall RPC_HDR_AUTH.\n")); - prs_mem_free(&p->out_data.frag); - return False; + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("Failed to add SCHANNEL auth blob: %s\n", + nt_errstr(status))); + data_blob_free(&p->out_data.frag); + return false; } - /* Generate the sign blob. */ - - frame = talloc_stackframe(); - switch (p->auth.auth_level) { - case DCERPC_AUTH_LEVEL_PRIVACY: - /* Data portion is encrypted. */ - status = auth_ntlmssp_seal_packet( - a, frame, - (uint8_t *)prs_data_p(&p->out_data.frag) - + RPC_HEADER_LEN + RPC_HDR_RESP_LEN, - data_len + ss_padding_len, - (unsigned char *)prs_data_p(&p->out_data.frag), - (size_t)prs_offset(&p->out_data.frag), - &auth_blob); - if (!NT_STATUS_IS_OK(status)) { - talloc_free(frame); - prs_mem_free(&p->out_data.frag); - return False; - } - break; - case DCERPC_AUTH_LEVEL_INTEGRITY: - /* Data is signed. */ - status = auth_ntlmssp_sign_packet( - a, frame, - (unsigned char *)prs_data_p(&p->out_data.frag) - + RPC_HEADER_LEN + RPC_HDR_RESP_LEN, - data_len + ss_padding_len, - (unsigned char *)prs_data_p(&p->out_data.frag), - (size_t)prs_offset(&p->out_data.frag), - &auth_blob); - if (!NT_STATUS_IS_OK(status)) { - talloc_free(frame); - prs_mem_free(&p->out_data.frag); - return False; - } - break; - default: - talloc_free(frame); - prs_mem_free(&p->out_data.frag); - return False; + if (DEBUGLEVEL >= 10) { + dump_NL_AUTH_SIGNATURE(talloc_tos(), &auth_blob); } - /* Append the auth blob. */ - if (!prs_copy_data_in(&p->out_data.frag, (char *)auth_blob.data, - NTLMSSP_SIG_SIZE)) { - DEBUG(0,("create_next_pdu_ntlmssp: failed to add %u bytes auth blob.\n", - (unsigned int)NTLMSSP_SIG_SIZE)); - talloc_free(frame); - prs_mem_free(&p->out_data.frag); - return False; + if (!data_blob_append(p->mem_ctx, &p->out_data.frag, + auth_blob.data, auth_blob.length)) { + DEBUG(0, ("Failed to add %u bytes auth blob.\n", + (unsigned int)auth_blob.length)); + data_blob_free(&p->out_data.frag); + return false; } - talloc_free(frame); - - /* - * Setup the counts for this PDU. - */ - - p->out_data.data_sent_length += data_len; - p->out_data.current_pdu_sent = 0; + data_blob_free(&auth_blob); - return True; + return true; } /******************************************************************* - Generate the next PDU to be returned from the data in p->rdata. - Return an schannel authenticated fragment. - ********************************************************************/ + Generate the next PDU to be returned from the data. +********************************************************************/ -static bool create_next_pdu_schannel(pipes_struct *p) +static bool create_next_packet(pipes_struct *p, + enum dcerpc_AuthType auth_type, + enum dcerpc_AuthLevel auth_level, + size_t auth_length) { - DATA_BLOB hdr; - uint8_t hdr_flags; - RPC_HDR_RESP hdr_resp; - uint32 ss_padding_len = 0; - uint32 data_len; - uint32 data_space_available; - uint32 data_len_left; - uint32 data_pos; + union dcerpc_payload u; + uint8_t pfc_flags; + size_t data_len_left; + size_t data_len; + size_t max_len; + size_t pad_len = 0; NTSTATUS status; - /* - * If we're in the fault state, keep returning fault PDU's until - * the pipe gets closed. JRA. - */ - - if(p->fault_state) { - setup_fault_pdu(p, NT_STATUS(DCERPC_FAULT_OP_RNG_ERROR)); - return True; - } - - memset((char *)&hdr_resp, '\0', sizeof(hdr_resp)); + ZERO_STRUCT(u.response); - /* Set up rpc header flags. */ + /* Set up rpc packet pfc flags. */ if (p->out_data.data_sent_length == 0) { - hdr_flags = DCERPC_PFC_FLAG_FIRST; + pfc_flags = DCERPC_PFC_FLAG_FIRST; } else { - hdr_flags = 0; + pfc_flags = 0; } - /* - * Work out how much we can fit in a single PDU. - */ - - data_len_left = prs_offset(&p->out_data.rdata) - p->out_data.data_sent_length; + /* Work out how much we can fit in a single PDU. */ + data_len_left = p->out_data.rdata.length - + p->out_data.data_sent_length; - /* - * Ensure there really is data left to send. - */ - - if(!data_len_left) { - DEBUG(0,("create_next_pdu_schannel: no data left to send !\n")); - return False; + /* Ensure there really is data left to send. */ + if (!data_len_left) { + DEBUG(0, ("No data left to send !\n")); + return false; } - /* Space available - not including padding. */ - data_space_available = RPC_MAX_PDU_FRAG_LEN - RPC_HEADER_LEN - - RPC_HDR_RESP_LEN - RPC_HDR_AUTH_LEN - - RPC_AUTH_SCHANNEL_SIGN_OR_SEAL_CHK_LEN; - - /* - * The amount we send is the minimum of the available - * space and the amount left to send. - */ - - data_len = MIN(data_len_left, data_space_available); - - /* Work out any padding alignment requirements. */ - if ((RPC_HEADER_LEN + RPC_HDR_RESP_LEN + data_len) % SERVER_NDR_PADDING_SIZE) { - ss_padding_len = SERVER_NDR_PADDING_SIZE - - ((RPC_HEADER_LEN + RPC_HDR_RESP_LEN + data_len) % SERVER_NDR_PADDING_SIZE); - DEBUG(10,("create_next_pdu_schannel: adding sign/seal padding of %u\n", - ss_padding_len )); - /* If we're over filling the packet, we need to make space - * for the padding at the end of the data. */ - if (data_len + ss_padding_len > data_space_available) { - data_len -= SERVER_NDR_PADDING_SIZE; - } + /* Max space available - not including padding. */ + if (auth_length) { + max_len = RPC_MAX_PDU_FRAG_LEN + - DCERPC_RESPONSE_LENGTH + - DCERPC_AUTH_TRAILER_LENGTH + - auth_length; + } else { + max_len = RPC_MAX_PDU_FRAG_LEN - DCERPC_RESPONSE_LENGTH; } /* - * Set up the alloc hint. This should be the data left to - * send. + * The amount we send is the minimum of the max_len + * and the amount left to send. */ + data_len = MIN(data_len_left, max_len); - hdr_resp.alloc_hint = data_len_left; - - /* - * Work out if this PDU will be the last. - */ - if (p->out_data.data_sent_length + data_len >= - prs_offset(&p->out_data.rdata)) { - hdr_flags |= DCERPC_PFC_FLAG_LAST; - } - - /* - * Init the parse struct to point at the outgoing - * data. - */ - prs_init_empty(&p->out_data.frag, p->mem_ctx, MARSHALL); - - status = dcerpc_push_ncacn_packet_header( - prs_get_mem_context(&p->out_data.frag), - DCERPC_PKT_RESPONSE, - hdr_flags, - RPC_HEADER_LEN + RPC_HDR_RESP_LEN + - data_len + ss_padding_len + - RPC_HDR_AUTH_LEN + - RPC_AUTH_SCHANNEL_SIGN_OR_SEAL_CHK_LEN, - RPC_AUTH_SCHANNEL_SIGN_OR_SEAL_CHK_LEN, - p->call_id, - &hdr); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("Failed to marshall RPC Header.\n")); - prs_mem_free(&p->out_data.frag); - return False; + if (auth_length) { + /* Work out any padding alignment requirements. */ + pad_len = (DCERPC_RESPONSE_LENGTH + data_len) % + SERVER_NDR_PADDING_SIZE; + if (pad_len) { + pad_len = SERVER_NDR_PADDING_SIZE - pad_len; + DEBUG(10, ("Padding size is: %d\n", (int)pad_len)); + /* If we're over filling the packet, we need to make + * space for the padding at the end of the data. */ + if (data_len + pad_len > max_len) { + data_len -= SERVER_NDR_PADDING_SIZE; + } + } } - /* Store the header in the data stream. */ - if (!prs_copy_data_in(&p->out_data.frag, - (char *)hdr.data, hdr.length)) { - DEBUG(0, ("Out of memory.\n")); - prs_mem_free(&p->out_data.frag); - return False; - } + /* Set up the alloc hint. This should be the data left to send. */ + u.response.alloc_hint = data_len_left; - if(!smb_io_rpc_hdr_resp("resp", &hdr_resp, &p->out_data.frag, 0)) { - DEBUG(0,("create_next_pdu_schannel: failed to marshall RPC_HDR_RESP.\n")); - prs_mem_free(&p->out_data.frag); - return False; + /* Work out if this PDU will be the last. */ + if (p->out_data.data_sent_length + + data_len >= p->out_data.rdata.length) { + pfc_flags |= DCERPC_PFC_FLAG_LAST; } - /* Store the current offset. */ - data_pos = prs_offset(&p->out_data.frag); - - /* Copy the data into the PDU. */ + /* Prepare data to be NDR encoded. */ + u.response.stub_and_verifier = + data_blob_const(p->out_data.rdata.data + + p->out_data.data_sent_length, data_len); - if(!prs_append_some_prs_data(&p->out_data.frag, &p->out_data.rdata, - p->out_data.data_sent_length, data_len)) { - DEBUG(0,("create_next_pdu_schannel: failed to copy %u bytes of data.\n", (unsigned int)data_len)); - prs_mem_free(&p->out_data.frag); - return False; - } - - /* Copy the sign/seal padding data. */ - if (ss_padding_len) { - char pad[SERVER_NDR_PADDING_SIZE]; - memset(pad, '\0', SERVER_NDR_PADDING_SIZE); - if (!prs_copy_data_in(&p->out_data.frag, pad, - ss_padding_len)) { - DEBUG(0,("create_next_pdu_schannel: failed to add %u bytes of pad data.\n", (unsigned int)ss_padding_len)); - prs_mem_free(&p->out_data.frag); - return False; - } + /* Store the packet in the data stream. */ + status = dcerpc_push_ncacn_packet(p->mem_ctx, + DCERPC_PKT_RESPONSE, + pfc_flags, + auth_length, + p->call_id, + &u, + &p->out_data.frag); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("Failed to marshall RPC Packet.\n")); + return false; } - { - /* - * Schannel processing. - */ - RPC_HDR_AUTH auth_info; - DATA_BLOB blob; - uint8_t *data; - - /* Check it's the type of reply we were expecting to decode */ - - init_rpc_hdr_auth(&auth_info, - DCERPC_AUTH_TYPE_SCHANNEL, - p->auth.auth_level == DCERPC_AUTH_LEVEL_PRIVACY ? - DCERPC_AUTH_LEVEL_PRIVACY : DCERPC_AUTH_LEVEL_INTEGRITY, - ss_padding_len, 1); - - if (!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, - &p->out_data.frag, 0)) { - DEBUG(0,("create_next_pdu_schannel: failed to marshall RPC_HDR_AUTH.\n")); - prs_mem_free(&p->out_data.frag); - return False; - } + if (auth_length) { + DATA_BLOB empty = data_blob_null; + DATA_BLOB auth_hdr; - data = (uint8_t *)prs_data_p(&p->out_data.frag) + data_pos; + /* Set the proper length on the pdu, including padding. + * Only needed if an auth trailer will be appended. */ + dcerpc_set_frag_length(&p->out_data.frag, + p->out_data.frag.length + + pad_len + + DCERPC_AUTH_TRAILER_LENGTH + + auth_length); - switch (p->auth.auth_level) { - case DCERPC_AUTH_LEVEL_PRIVACY: - status = netsec_outgoing_packet(p->auth.a_u.schannel_auth, - talloc_tos(), - true, - data, - data_len + ss_padding_len, - &blob); - break; - case DCERPC_AUTH_LEVEL_INTEGRITY: - status = netsec_outgoing_packet(p->auth.a_u.schannel_auth, - talloc_tos(), - false, - data, - data_len + ss_padding_len, - &blob); - break; - default: - status = NT_STATUS_INTERNAL_ERROR; - break; + if (pad_len) { + size_t offset = p->out_data.frag.length; + + if (!data_blob_realloc(p->mem_ctx, + &p->out_data.frag, + offset + pad_len)) { + DEBUG(0, ("Failed to add padding!\n")); + data_blob_free(&p->out_data.frag); + return false; + } + memset(&p->out_data.frag.data[offset], '\0', pad_len); } + /* auth blob is intentionally empty, + * it will be appended later */ + status = dcerpc_push_dcerpc_auth(p->out_data.frag.data, + auth_type, + auth_level, + pad_len, + 1, /* context id. */ + &empty, + &auth_hdr); if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("create_next_pdu_schannel: failed to process packet: %s\n", - nt_errstr(status))); - prs_mem_free(&p->out_data.frag); + DEBUG(0, ("Failed to marshall RPC Auth.\n")); return false; } - /* Finally marshall the blob. */ - - if (DEBUGLEVEL >= 10) { - dump_NL_AUTH_SIGNATURE(talloc_tos(), &blob); - } - - if (!prs_copy_data_in(&p->out_data.frag, (const char *)blob.data, blob.length)) { - prs_mem_free(&p->out_data.frag); + /* Store auth header in the data stream. */ + if (!data_blob_append(p->mem_ctx, &p->out_data.frag, + auth_hdr.data, auth_hdr.length)) { + DEBUG(0, ("Out of memory.\n")); + data_blob_free(&p->out_data.frag); return false; } + data_blob_free(&auth_hdr); } - /* - * Setup the counts for this PDU. - */ - + /* Setup the counts for this PDU. */ p->out_data.data_sent_length += data_len; p->out_data.current_pdu_sent = 0; - - return True; + return true; } /******************************************************************* Generate the next PDU to be returned from the data in p->rdata. - No authentication done. ********************************************************************/ -static bool create_next_pdu_noauth(pipes_struct *p) +bool create_next_pdu(pipes_struct *p) { - DATA_BLOB hdr; - uint8_t hdr_flags; - NTSTATUS status; - RPC_HDR_RESP hdr_resp; - uint32 data_len; - uint32 data_space_available; - uint32 data_len_left; + enum dcerpc_AuthType auth_type = + map_pipe_auth_type_to_rpc_auth_type(p->auth.auth_type); /* * If we're in the fault state, keep returning fault PDU's until * the pipe gets closed. JRA. */ - - if(p->fault_state) { + if (p->fault_state) { setup_fault_pdu(p, NT_STATUS(DCERPC_FAULT_OP_RNG_ERROR)); - return True; - } - - memset((char *)&hdr_resp, '\0', sizeof(hdr_resp)); - - /* Set up rpc header flags. */ - if (p->out_data.data_sent_length == 0) { - hdr_flags = DCERPC_PFC_FLAG_FIRST; - } else { - hdr_flags = 0; - } - - /* - * Work out how much we can fit in a single PDU. - */ - - data_len_left = prs_offset(&p->out_data.rdata) - p->out_data.data_sent_length; - - /* - * Ensure there really is data left to send. - */ - - if(!data_len_left) { - DEBUG(0,("create_next_pdu_noath: no data left to send !\n")); - return False; - } - - data_space_available = RPC_MAX_PDU_FRAG_LEN - RPC_HEADER_LEN - - RPC_HDR_RESP_LEN; - - /* - * The amount we send is the minimum of the available - * space and the amount left to send. - */ - - data_len = MIN(data_len_left, data_space_available); - - /* - * Set up the alloc hint. This should be the data left to - * send. - */ - - hdr_resp.alloc_hint = data_len_left; - - /* - * Work out if this PDU will be the last. - */ - if(p->out_data.data_sent_length + data_len >= prs_offset(&p->out_data.rdata)) { - hdr_flags |= DCERPC_PFC_FLAG_LAST; - } - - /* - * Init the parse struct to point at the outgoing - * data. - */ - prs_init_empty(&p->out_data.frag, p->mem_ctx, MARSHALL); - - status = dcerpc_push_ncacn_packet_header( - prs_get_mem_context(&p->out_data.frag), - DCERPC_PKT_RESPONSE, - hdr_flags, - RPC_HEADER_LEN + RPC_HDR_RESP_LEN + data_len, - 0, - p->call_id, - &hdr); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("Failed to marshall RPC Header.\n")); - prs_mem_free(&p->out_data.frag); - return False; - } - - /* Store the header in the data stream. */ - if (!prs_copy_data_in(&p->out_data.frag, - (char *)hdr.data, hdr.length)) { - DEBUG(0, ("Out of memory.\n")); - prs_mem_free(&p->out_data.frag); - return False; - } - - if(!smb_io_rpc_hdr_resp("resp", &hdr_resp, &p->out_data.frag, 0)) { - DEBUG(0,("create_next_pdu_noath: failed to marshall RPC_HDR_RESP.\n")); - prs_mem_free(&p->out_data.frag); - return False; - } - - /* Copy the data into the PDU. */ - - if(!prs_append_some_prs_data(&p->out_data.frag, &p->out_data.rdata, - p->out_data.data_sent_length, data_len)) { - DEBUG(0,("create_next_pdu_noauth: failed to copy %u bytes of data.\n", (unsigned int)data_len)); - prs_mem_free(&p->out_data.frag); - return False; + return true; } - /* - * Setup the counts for this PDU. - */ - - p->out_data.data_sent_length += data_len; - p->out_data.current_pdu_sent = 0; + switch (p->auth.auth_level) { + case DCERPC_AUTH_LEVEL_NONE: + case DCERPC_AUTH_LEVEL_CONNECT: + /* This is incorrect for auth level connect. Fixme. JRA */ - return True; -} + /* No authentication done. */ + return create_next_packet(p, auth_type, + p->auth.auth_level, 0); -/******************************************************************* - Generate the next PDU to be returned from the data in p->rdata. -********************************************************************/ + case DCERPC_AUTH_LEVEL_CALL: + case DCERPC_AUTH_LEVEL_PACKET: + case DCERPC_AUTH_LEVEL_INTEGRITY: + case DCERPC_AUTH_LEVEL_PRIVACY: -bool create_next_pdu(pipes_struct *p) -{ - switch(p->auth.auth_level) { - case DCERPC_AUTH_LEVEL_NONE: - case DCERPC_AUTH_LEVEL_CONNECT: - /* This is incorrect for auth level connect. Fixme. JRA */ - return create_next_pdu_noauth(p); + switch(p->auth.auth_type) { + case PIPE_AUTH_TYPE_NTLMSSP: + case PIPE_AUTH_TYPE_SPNEGO_NTLMSSP: + if (!create_next_packet(p, auth_type, + p->auth.auth_level, + NTLMSSP_SIG_SIZE)) { + return false; + } + return add_ntlmssp_auth(p); - default: - switch(p->auth.auth_type) { - case PIPE_AUTH_TYPE_NTLMSSP: - case PIPE_AUTH_TYPE_SPNEGO_NTLMSSP: - return create_next_pdu_ntlmssp(p); - case PIPE_AUTH_TYPE_SCHANNEL: - return create_next_pdu_schannel(p); - default: - break; + case PIPE_AUTH_TYPE_SCHANNEL: + if (!create_next_packet(p, auth_type, + p->auth.auth_level, + SCHANNEL_SIG_SIZE)) { + return false; } + return add_schannel_auth(p); + default: + break; + } + default: + break; } - DEBUG(0,("create_next_pdu: invalid internal auth level %u / type %u", - (unsigned int)p->auth.auth_level, - (unsigned int)p->auth.auth_type)); - return False; + DEBUG(0, ("Invalid internal auth level %u / type %u\n", + (unsigned int)p->auth.auth_level, + (unsigned int)p->auth.auth_type)); + return false; } /******************************************************************* @@ -773,22 +543,22 @@ static bool pipe_ntlmssp_verify_final(pipes_struct *p, DATA_BLOB *p_resp_blob) bool api_pipe_bind_auth3(pipes_struct *p, struct ncacn_packet *pkt) { struct dcerpc_auth auth_info; - uint32_t auth_len = pkt->auth_length; NTSTATUS status; - DEBUG(5,("api_pipe_bind_auth3: decode request. %d\n", __LINE__)); + DEBUG(5, ("api_pipe_bind_auth3: decode request. %d\n", __LINE__)); - if (auth_len == 0) { - DEBUG(0,("api_pipe_bind_auth3: No auth field sent !\n")); + if (pkt->auth_length == 0) { + DEBUG(0, ("No auth field sent for bind request!\n")); goto err; } /* Ensure there's enough data for an authenticated request. */ - if (RPC_HEADER_LEN + RPC_HDR_AUTH_LEN + auth_len > - pkt->frag_length) { + if (pkt->frag_length < RPC_HEADER_LEN + + DCERPC_AUTH_TRAILER_LENGTH + + pkt->auth_length) { DEBUG(0,("api_pipe_ntlmssp_auth_process: auth_len " "%u is too large.\n", - (unsigned int)auth_len )); + (unsigned int)pkt->auth_length)); goto err; } @@ -844,18 +614,9 @@ static bool setup_bind_nak(pipes_struct *p, struct ncacn_packet *pkt) { NTSTATUS status; union dcerpc_payload u; - DATA_BLOB blob; /* Free any memory in the current return data buffer. */ - prs_mem_free(&p->out_data.rdata); - - /* - * Marshall directly into the outgoing PDU space. We - * must do this as we need to set to the bind response - * header and are never sending more than one PDU here. - */ - - prs_init_empty(&p->out_data.frag, p->mem_ctx, MARSHALL); + data_blob_free(&p->out_data.rdata); /* * Initialize a bind_nak header. @@ -865,6 +626,12 @@ static bool setup_bind_nak(pipes_struct *p, struct ncacn_packet *pkt) u.bind_nak.reject_reason = 0; + /* + * Marshall directly into the outgoing PDU space. We + * must do this as we need to set to the bind response + * header and are never sending more than one PDU here. + */ + status = dcerpc_push_ncacn_packet(p->mem_ctx, DCERPC_PKT_BIND_NAK, DCERPC_PFC_FLAG_FIRST | @@ -872,15 +639,8 @@ static bool setup_bind_nak(pipes_struct *p, struct ncacn_packet *pkt) 0, pkt->call_id, &u, - &blob); + &p->out_data.frag); if (!NT_STATUS_IS_OK(status)) { - prs_mem_free(&p->out_data.frag); - return False; - } - - if (!prs_copy_data_in(&p->out_data.frag, - (char *)blob.data, blob.length)) { - prs_mem_free(&p->out_data.frag); return False; } @@ -905,18 +665,9 @@ bool setup_fault_pdu(pipes_struct *p, NTSTATUS fault_status) { NTSTATUS status; union dcerpc_payload u; - DATA_BLOB blob; /* Free any memory in the current return data buffer. */ - prs_mem_free(&p->out_data.rdata); - - /* - * Marshall directly into the outgoing PDU space. We - * must do this as we need to set to the bind response - * header and are never sending more than one PDU here. - */ - - prs_init_empty(&p->out_data.frag, p->mem_ctx, MARSHALL); + data_blob_free(&p->out_data.rdata); /* * Initialize a fault header. @@ -927,6 +678,12 @@ bool setup_fault_pdu(pipes_struct *p, NTSTATUS fault_status) u.fault.status = NT_STATUS_V(fault_status); u.fault._pad = data_blob_talloc_zero(p->mem_ctx, 4); + /* + * Marshall directly into the outgoing PDU space. We + * must do this as we need to set to the bind response + * header and are never sending more than one PDU here. + */ + status = dcerpc_push_ncacn_packet(p->mem_ctx, DCERPC_PKT_FAULT, DCERPC_PFC_FLAG_FIRST | @@ -935,15 +692,8 @@ bool setup_fault_pdu(pipes_struct *p, NTSTATUS fault_status) 0, p->call_id, &u, - &blob); + &p->out_data.frag); if (!NT_STATUS_IS_OK(status)) { - prs_mem_free(&p->out_data.frag); - return False; - } - - if (!prs_copy_data_in(&p->out_data.frag, - (char *)blob.data, blob.length)) { - prs_mem_free(&p->out_data.frag); return False; } @@ -1441,8 +1191,6 @@ bool api_pipe_bind_req(pipes_struct *p, struct ncacn_packet *pkt) struct dcerpc_ack_ctx bind_ack_ctx; DATA_BLOB auth_resp = data_blob_null; DATA_BLOB auth_blob = data_blob_null; - DATA_BLOB blob = data_blob_null; - int pad_len = 0; /* No rebinds on a bound pipe - use alter context. */ if (p->pipe_bound) { @@ -1508,14 +1256,6 @@ bool api_pipe_bind_req(pipes_struct *p, struct ncacn_packet *pkt) } /* - * Marshall directly into the outgoing PDU space. We - * must do this as we need to set to the bind response - * header and are never sending more than one PDU here. - */ - - prs_init_empty(&p->out_data.frag, p->mem_ctx, MARSHALL); - - /* * Create the bind response struct. */ @@ -1549,7 +1289,7 @@ bool api_pipe_bind_req(pipes_struct *p, struct ncacn_packet *pkt) * prevents overrun. */ if (pkt->frag_length < RPC_HEADER_LEN + - RPC_HDR_AUTH_LEN + + DCERPC_AUTH_TRAILER_LENGTH + pkt->auth_length) { DEBUG(0,("api_pipe_bind_req: auth_len (%u) " "too long for fragment %u.\n", @@ -1650,12 +1390,20 @@ bool api_pipe_bind_req(pipes_struct *p, struct ncacn_packet *pkt) /* NOTE: We leave the auth_info empty so we can calculate the padding * later and then append the auth_info --simo */ - status = dcerpc_push_ncacn_packet(pkt, DCERPC_PKT_BIND_ACK, + /* + * Marshall directly into the outgoing PDU space. We + * must do this as we need to set to the bind response + * header and are never sending more than one PDU here. + */ + + status = dcerpc_push_ncacn_packet(p->mem_ctx, + DCERPC_PKT_BIND_ACK, DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST, auth_resp.length, pkt->call_id, - &u, &blob); + &u, + &p->out_data.frag); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Failed to marshall bind_ack packet. (%s)\n", nt_errstr(status))); @@ -1663,18 +1411,10 @@ bool api_pipe_bind_req(pipes_struct *p, struct ncacn_packet *pkt) if (auth_resp.length) { - /* Work out any padding needed before the auth footer. */ - pad_len = blob.length % SERVER_NDR_PADDING_SIZE; - if (pad_len) { - pad_len = SERVER_NDR_PADDING_SIZE - pad_len; - DEBUG(10, ("auth pad_len = %u\n", - (unsigned int)pad_len)); - } - status = dcerpc_push_dcerpc_auth(pkt, auth_type, auth_info.auth_level, - pad_len, + 0, 1, /* auth_context_id */ &auth_resp, &auth_blob); @@ -1686,30 +1426,13 @@ bool api_pipe_bind_req(pipes_struct *p, struct ncacn_packet *pkt) /* Now that we have the auth len store it into the right place in * the dcerpc header */ - dcerpc_set_frag_length(&blob, blob.length + pad_len + auth_blob.length); - - /* And finally copy all bits in the output pdu */ - if (!prs_copy_data_in(&p->out_data.frag, - (char *)blob.data, blob.length)) { - DEBUG(0, ("Failed to copy data to output buffer.\n")); - goto err_exit; - } + dcerpc_set_frag_length(&p->out_data.frag, + p->out_data.frag.length + auth_blob.length); if (auth_blob.length) { - if (pad_len) { - char pad[SERVER_NDR_PADDING_SIZE]; - memset(pad, '\0', SERVER_NDR_PADDING_SIZE); - if (!prs_copy_data_in(&p->out_data.frag, pad, pad_len)) { - DEBUG(0, ("api_pipe_bind_req: failed to add " - "%u bytes of pad data.\n", - (unsigned int)pad_len)); - goto err_exit; - } - } - if (!prs_copy_data_in(&p->out_data.frag, - (char *)auth_blob.data, - auth_blob.length)) { + if (!data_blob_append(p->mem_ctx, &p->out_data.frag, + auth_blob.data, auth_blob.length)) { DEBUG(0, ("Append of auth info failed.\n")); goto err_exit; } @@ -1723,14 +1446,12 @@ bool api_pipe_bind_req(pipes_struct *p, struct ncacn_packet *pkt) p->out_data.current_pdu_sent = 0; TALLOC_FREE(auth_blob.data); - TALLOC_FREE(blob.data); return True; err_exit: - prs_mem_free(&p->out_data.frag); + data_blob_free(&p->out_data.frag); TALLOC_FREE(auth_blob.data); - TALLOC_FREE(blob.data); return setup_bind_nak(p, pkt); } @@ -1748,7 +1469,6 @@ bool api_pipe_alter_context(pipes_struct *p, struct ncacn_packet *pkt) struct dcerpc_ack_ctx bind_ack_ctx; DATA_BLOB auth_resp = data_blob_null; DATA_BLOB auth_blob = data_blob_null; - DATA_BLOB blob = data_blob_null; int pad_len = 0; DEBUG(5,("api_pipe_alter_context: make response. %d\n", __LINE__)); @@ -1760,14 +1480,6 @@ bool api_pipe_alter_context(pipes_struct *p, struct ncacn_packet *pkt) } /* - * Marshall directly into the outgoing PDU space. We - * must do this as we need to set to the bind response - * header and are never sending more than one PDU here. - */ - - prs_init_empty(&p->out_data.frag, p->mem_ctx, MARSHALL); - - /* * Create the bind response struct. */ @@ -1801,7 +1513,7 @@ bool api_pipe_alter_context(pipes_struct *p, struct ncacn_packet *pkt) * prevents overrun. */ if (pkt->frag_length < RPC_HEADER_LEN + - RPC_HDR_AUTH_LEN + + DCERPC_AUTH_TRAILER_LENGTH + pkt->auth_length) { DEBUG(0,("api_pipe_alter_context: auth_len (%u) " "too long for fragment %u.\n", @@ -1856,12 +1568,20 @@ bool api_pipe_alter_context(pipes_struct *p, struct ncacn_packet *pkt) /* NOTE: We leave the auth_info empty so we can calculate the padding * later and then append the auth_info --simo */ - status = dcerpc_push_ncacn_packet(pkt, DCERPC_PKT_ALTER_RESP, + /* + * Marshall directly into the outgoing PDU space. We + * must do this as we need to set to the bind response + * header and are never sending more than one PDU here. + */ + + status = dcerpc_push_ncacn_packet(p->mem_ctx, + DCERPC_PKT_ALTER_RESP, DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST, auth_resp.length, pkt->call_id, - &u, &blob); + &u, + &p->out_data.frag); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Failed to marshall bind_ack packet. (%s)\n", nt_errstr(status))); @@ -1870,7 +1590,7 @@ bool api_pipe_alter_context(pipes_struct *p, struct ncacn_packet *pkt) if (auth_resp.length) { /* Work out any padding needed before the auth footer. */ - pad_len = blob.length % SERVER_NDR_PADDING_SIZE; + pad_len = p->out_data.frag.length % SERVER_NDR_PADDING_SIZE; if (pad_len) { pad_len = SERVER_NDR_PADDING_SIZE - pad_len; DEBUG(10, ("auth pad_len = %u\n", @@ -1892,20 +1612,17 @@ bool api_pipe_alter_context(pipes_struct *p, struct ncacn_packet *pkt) /* Now that we have the auth len store it into the right place in * the dcerpc header */ - dcerpc_set_frag_length(&blob, blob.length + pad_len + auth_blob.length); - - /* And finally copy all bits in the output pdu */ - if (!prs_copy_data_in(&p->out_data.frag, - (char *)blob.data, blob.length)) { - DEBUG(0, ("Failed to copy data to output buffer.\n")); - goto err_exit; - } + dcerpc_set_frag_length(&p->out_data.frag, + p->out_data.frag.length + + pad_len + auth_blob.length); if (auth_resp.length) { if (pad_len) { char pad[SERVER_NDR_PADDING_SIZE]; memset(pad, '\0', SERVER_NDR_PADDING_SIZE); - if (!prs_copy_data_in(&p->out_data.frag, pad, pad_len)) { + if (!data_blob_append(p->mem_ctx, + &p->out_data.frag, + pad, pad_len)) { DEBUG(0, ("api_pipe_bind_req: failed to add " "%u bytes of pad data.\n", (unsigned int)pad_len)); @@ -1913,9 +1630,8 @@ bool api_pipe_alter_context(pipes_struct *p, struct ncacn_packet *pkt) } } - if (!prs_copy_data_in(&p->out_data.frag, - (char *)auth_blob.data, - auth_blob.length)) { + if (!data_blob_append(p->mem_ctx, &p->out_data.frag, + auth_blob.data, auth_blob.length)) { DEBUG(0, ("Append of auth info failed.\n")); goto err_exit; } @@ -1929,14 +1645,12 @@ bool api_pipe_alter_context(pipes_struct *p, struct ncacn_packet *pkt) p->out_data.current_pdu_sent = 0; TALLOC_FREE(auth_blob.data); - TALLOC_FREE(blob.data); return True; err_exit: - prs_mem_free(&p->out_data.frag); + data_blob_free(&p->out_data.frag); TALLOC_FREE(auth_blob.data); - TALLOC_FREE(blob.data); return setup_bind_nak(p, pkt); } @@ -1997,7 +1711,7 @@ bool api_pipe_request(pipes_struct *p, struct ncacn_packet *pkt) ((p->auth.auth_type == PIPE_AUTH_TYPE_NTLMSSP) || (p->auth.auth_type == PIPE_AUTH_TYPE_SPNEGO_NTLMSSP))) { if(!become_authenticated_pipe_user(p)) { - prs_mem_free(&p->out_data.rdata); + data_blob_free(&p->out_data.rdata); return False; } changed_user = True; @@ -2039,7 +1753,7 @@ static bool api_rpcTNP(pipes_struct *p, struct ncacn_packet *pkt, const struct api_struct *api_rpc_cmds, int n_cmds) { int fn_num; - uint32 offset1, offset2; + uint32_t offset1; /* interpret the command */ DEBUG(4,("api_rpcTNP: %s op 0x%x - ", @@ -2050,7 +1764,9 @@ static bool api_rpcTNP(pipes_struct *p, struct ncacn_packet *pkt, fstring name; slprintf(name, sizeof(name)-1, "in_%s", get_pipe_name_from_syntax(talloc_tos(), &p->syntax)); - prs_dump(name, pkt->u.request.opnum, &p->in_data.data); + dump_pdu_region(name, pkt->u.request.opnum, + &p->in_data.data, 0, + p->in_data.data.length); } for (fn_num = 0; fn_num < n_cmds; fn_num++) { @@ -2073,7 +1789,7 @@ static bool api_rpcTNP(pipes_struct *p, struct ncacn_packet *pkt, return True; } - offset1 = prs_offset(&p->out_data.rdata); + offset1 = p->out_data.rdata.length; DEBUG(6, ("api_rpc_cmds[%d].fn == %p\n", fn_num, api_rpc_cmds[fn_num].fn)); @@ -2082,7 +1798,7 @@ static bool api_rpcTNP(pipes_struct *p, struct ncacn_packet *pkt, DEBUG(0,("api_rpcTNP: %s: %s failed.\n", get_pipe_name_from_syntax(talloc_tos(), &p->syntax), api_rpc_cmds[fn_num].name)); - prs_mem_free(&p->out_data.rdata); + data_blob_free(&p->out_data.rdata); return False; } @@ -2100,32 +1816,24 @@ static bool api_rpcTNP(pipes_struct *p, struct ncacn_packet *pkt, return True; } - offset2 = prs_offset(&p->out_data.rdata); - prs_set_offset(&p->out_data.rdata, offset1); if (DEBUGLEVEL >= 50) { fstring name; slprintf(name, sizeof(name)-1, "out_%s", get_pipe_name_from_syntax(talloc_tos(), &p->syntax)); - prs_dump(name, pkt->u.request.opnum, &p->out_data.rdata); + dump_pdu_region(name, pkt->u.request.opnum, + &p->out_data.rdata, offset1, + p->out_data.rdata.length); } - prs_set_offset(&p->out_data.rdata, offset2); DEBUG(5,("api_rpcTNP: called %s successfully\n", get_pipe_name_from_syntax(talloc_tos(), &p->syntax))); /* Check for buffer underflow in rpc parsing */ - - if ((DEBUGLEVEL >= 10) && - (prs_offset(&p->in_data.data) != prs_data_size(&p->in_data.data))) { - size_t data_len = prs_data_size(&p->in_data.data) - prs_offset(&p->in_data.data); - char *data = (char *)SMB_MALLOC(data_len); - + if ((DEBUGLEVEL >= 10) && + (pkt->frag_length < p->in_data.data.length)) { DEBUG(10, ("api_rpcTNP: rpc input buffer underflow (parse error?)\n")); - if (data) { - prs_uint8s(False, "", &p->in_data.data, 0, (unsigned char *)data, (uint32)data_len); - SAFE_FREE(data); - } - + dump_data(10, p->in_data.data.data + pkt->frag_length, + p->in_data.data.length - pkt->frag_length); } return True; diff --git a/source3/rpc_server/srv_pipe_hnd.c b/source3/rpc_server/srv_pipe_hnd.c index b86a83bf07..3055e1a29c 100644 --- a/source3/rpc_server/srv_pipe_hnd.c +++ b/source3/rpc_server/srv_pipe_hnd.c @@ -42,19 +42,10 @@ static bool pipe_init_outgoing_data(pipes_struct *p) o_data->data_sent_length = 0; o_data->current_pdu_sent = 0; - prs_mem_free(&o_data->frag); + data_blob_free(&o_data->frag); /* Free any memory in the current return data buffer. */ - prs_mem_free(&o_data->rdata); - - /* - * Initialize the outgoing RPC data buffer. - * we will use this as the raw data area for replying to rpc requests. - */ - if(!prs_init(&o_data->rdata, 128, p->mem_ctx, MARSHALL)) { - DEBUG(0,("pipe_init_outgoing_data: malloc fail.\n")); - return False; - } + data_blob_free(&o_data->rdata); return True; } @@ -65,7 +56,7 @@ static bool pipe_init_outgoing_data(pipes_struct *p) static void set_incoming_fault(pipes_struct *p) { - prs_mem_free(&p->in_data.data); + data_blob_free(&p->in_data.data); p->in_data.pdu_needed_len = 0; p->in_data.pdu.length = 0; p->fault_state = True; @@ -152,23 +143,14 @@ static bool get_pdu_size(pipes_struct *p) static void free_pipe_context(pipes_struct *p) { - prs_mem_free(&p->out_data.frag); - prs_mem_free(&p->out_data.rdata); - prs_mem_free(&p->in_data.data); + data_blob_free(&p->out_data.frag); + data_blob_free(&p->out_data.rdata); + data_blob_free(&p->in_data.data); DEBUG(3, ("free_pipe_context: " "destroying talloc pool of size %lu\n", (unsigned long)talloc_total_size(p->mem_ctx))); talloc_free_children(p->mem_ctx); - /* - * Re-initialize to set back to marshalling and set the - * offset back to the start of the buffer. - */ - if(!prs_init(&p->in_data.data, 128, p->mem_ctx, MARSHALL)) { - DEBUG(0, ("free_pipe_context: " - "rps_init failed!\n")); - p->fault_state = True; - } } /**************************************************************************** @@ -357,10 +339,10 @@ static bool process_request_pdu(pipes_struct *p, struct ncacn_packet *pkt) * will not fit in the initial buffer of size 0x1068 --jerry 22/01/2002 */ - if (prs_offset(&p->in_data.data) + data.length > MAX_RPC_DATA_SIZE) { + if (p->in_data.data.length + data.length > MAX_RPC_DATA_SIZE) { DEBUG(0, ("process_request_pdu: " "rpc data buffer too large (%u) + (%u)\n", - (unsigned int)prs_data_size(&p->in_data.data), + (unsigned int)p->in_data.data.length, (unsigned int)data.length)); set_incoming_fault(p); return False; @@ -370,14 +352,16 @@ static bool process_request_pdu(pipes_struct *p, struct ncacn_packet *pkt) * Append the data portion into the buffer and return. */ - if (!prs_copy_data_in(&p->in_data.data, - (char *)data.data, data.length)) { - DEBUG(0, ("process_request_pdu: Unable to append data size %u " - "to parse buffer of size %u.\n", - (unsigned int)data.length, - (unsigned int)prs_data_size(&p->in_data.data))); - set_incoming_fault(p); - return False; + if (data.length) { + if (!data_blob_append(p->mem_ctx, &p->in_data.data, + data.data, data.length)) { + DEBUG(0, ("Unable to append data size %u " + "to parse buffer of size %u.\n", + (unsigned int)data.length, + (unsigned int)p->in_data.data.length)); + set_incoming_fault(p); + return False; + } } if (pkt->pfc_flags & DCERPC_PFC_FLAG_LAST) { @@ -388,30 +372,8 @@ static bool process_request_pdu(pipes_struct *p, struct ncacn_packet *pkt) */ /* - * Ensure the internal prs buffer size is *exactly* the same - * size as the current offset. - */ - - if (!prs_set_buffer_size(&p->in_data.data, - prs_offset(&p->in_data.data))) { - DEBUG(0, ("process_request_pdu: " - "Call to prs_set_buffer_size failed!\n")); - set_incoming_fault(p); - return False; - } - - /* - * Set the parse offset to the start of the data and set the - * prs_struct to UNMARSHALL. - */ - - prs_set_offset(&p->in_data.data, 0); - prs_switch_type(&p->in_data.data, UNMARSHALL); - - /* * Process the complete data stream here. */ - if (pipe_init_outgoing_data(p)) { ret = api_pipe_request(p, pkt); } @@ -463,7 +425,6 @@ static void process_complete_pdu(pipes_struct *p) } else { p->endian = RPC_BIG_ENDIAN; } - prs_set_endian_data(&p->in_data.data, p->endian); DEBUG(10, ("Processing packet type %d\n", (int)pkt->ptype)); @@ -600,10 +561,6 @@ static void process_complete_pdu(pipes_struct *p) } done: - /* Reset to little endian. - * Probably don't need this but it won't hurt. */ - prs_set_endian_data(&p->in_data.data, RPC_LITTLE_ENDIAN); - if (!reply) { DEBUG(3,("process_complete_pdu: DCE/RPC fault sent on " "pipe %s\n", get_pipe_name_from_syntax(talloc_tos(), @@ -812,7 +769,7 @@ static ssize_t read_from_internal_pipe(struct pipes_struct *p, char *data, * PDU. */ - pdu_remaining = prs_offset(&p->out_data.frag) + pdu_remaining = p->out_data.frag.length - p->out_data.current_pdu_sent; if (pdu_remaining > 0) { @@ -821,12 +778,12 @@ static ssize_t read_from_internal_pipe(struct pipes_struct *p, char *data, DEBUG(10,("read_from_pipe: %s: current_pdu_len = %u, " "current_pdu_sent = %u returning %d bytes.\n", get_pipe_name_from_syntax(talloc_tos(), &p->syntax), - (unsigned int)prs_offset(&p->out_data.frag), + (unsigned int)p->out_data.frag.length, (unsigned int)p->out_data.current_pdu_sent, (int)data_returned)); memcpy(data, - prs_data_p(&p->out_data.frag) + p->out_data.frag.data + p->out_data.current_pdu_sent, data_returned); @@ -840,13 +797,13 @@ static ssize_t read_from_internal_pipe(struct pipes_struct *p, char *data, */ DEBUG(10,("read_from_pipe: %s: fault_state = %d : data_sent_length " - "= %u, prs_offset(&p->out_data.rdata) = %u.\n", + "= %u, p->out_data.rdata.length = %u.\n", get_pipe_name_from_syntax(talloc_tos(), &p->syntax), (int)p->fault_state, (unsigned int)p->out_data.data_sent_length, - (unsigned int)prs_offset(&p->out_data.rdata) )); + (unsigned int)p->out_data.rdata.length)); - if(p->out_data.data_sent_length >= prs_offset(&p->out_data.rdata)) { + if (p->out_data.data_sent_length >= p->out_data.rdata.length) { /* * We have sent all possible data, return 0. */ @@ -867,23 +824,22 @@ static ssize_t read_from_internal_pipe(struct pipes_struct *p, char *data, return -1; } - data_returned = MIN(n, prs_offset(&p->out_data.frag)); + data_returned = MIN(n, p->out_data.frag.length); - memcpy( data, prs_data_p(&p->out_data.frag), (size_t)data_returned); + memcpy(data, p->out_data.frag.data, (size_t)data_returned); p->out_data.current_pdu_sent += (uint32)data_returned; out: - (*is_data_outstanding) = prs_offset(&p->out_data.frag) > n; + (*is_data_outstanding) = p->out_data.frag.length > n; - if (p->out_data.current_pdu_sent == prs_offset(&p->out_data.frag)) { + if (p->out_data.current_pdu_sent == p->out_data.frag.length) { /* We've returned everything in the out_data.frag * so we're done with this pdu. Free it and reset * current_pdu_sent. */ p->out_data.current_pdu_sent = 0; - prs_mem_free(&p->out_data.frag); + data_blob_free(&p->out_data.frag); - if (p->out_data.data_sent_length - >= prs_offset(&p->out_data.rdata)) { + if (p->out_data.data_sent_length >= p->out_data.rdata.length) { /* * We're completely finished with both outgoing and * incoming data streams. It's safe to free all diff --git a/source3/rpc_server/srv_winreg_nt.c b/source3/rpc_server/srv_winreg_nt.c index 209deadd70..73d2775b16 100644 --- a/source3/rpc_server/srv_winreg_nt.c +++ b/source3/rpc_server/srv_winreg_nt.c @@ -22,6 +22,7 @@ #include "includes.h" #include "../librpc/gen_ndr/srv_winreg.h" +#include "registry/reg_parse_prs.h" #include "registry.h" #include "registry/reg_perfcount.h" diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c index 433de8aea3..03de7e85de 100644 --- a/source3/smbd/msdfs.c +++ b/source3/smbd/msdfs.c @@ -255,6 +255,9 @@ NTSTATUS create_conn_struct(TALLOC_CTX *ctx, conn->params->service = snum; + conn->sconn = smbd_server_conn; + conn->sconn->smb1.tcons.num_open += 1; + if (server_info != NULL) { conn->server_info = copy_serverinfo(conn, server_info); if (conn->server_info == NULL) { diff --git a/source3/winbindd/winbindd_dual_ndr.c b/source3/winbindd/winbindd_dual_ndr.c index aee5052687..f67a48dfeb 100644 --- a/source3/winbindd/winbindd_dual_ndr.c +++ b/source3/winbindd/winbindd_dual_ndr.c @@ -264,21 +264,22 @@ enum winbindd_result winbindd_dual_ndrcmd(struct winbindd_domain *domain, ZERO_STRUCT(p); p.mem_ctx = talloc_stackframe(); - p.in_data.data.buffer_size = state->request->extra_len; - p.in_data.data.data_p = state->request->extra_data.data; - prs_init(&p.out_data.rdata, 0, state->mem_ctx, MARSHALL); + p.in_data.data = data_blob_const(state->request->extra_data.data, + state->request->extra_len); ret = fns[state->request->data.ndrcmd].fn(&p); - TALLOC_FREE(p.mem_ctx); if (!ret) { + TALLOC_FREE(p.mem_ctx); return WINBINDD_ERROR; } state->response->extra_data.data = - talloc_memdup(state->mem_ctx, p.out_data.rdata.data_p, - p.out_data.rdata.data_offset); - state->response->length += p.out_data.rdata.data_offset; - prs_mem_free(&p.out_data.rdata); + talloc_move(state->mem_ctx, &p.out_data.rdata.data); + state->response->length += p.out_data.rdata.length; + p.out_data.rdata.length = 0; + + TALLOC_FREE(p.mem_ctx); + if (state->response->extra_data.data == NULL) { return WINBINDD_ERROR; } diff --git a/source3/wscript_build b/source3/wscript_build index 8f18c3e47b..38d680518f 100644 --- a/source3/wscript_build +++ b/source3/wscript_build @@ -88,10 +88,9 @@ LIBNDR_GEN_SRC = '''../librpc/gen_ndr/ndr_wkssvc.c # this includes only the low level parse code, not stuff # that requires knowledge of security contexts -RPC_PARSE_SRC1 = '''rpc_parse/parse_prs.c rpc_parse/parse_misc.c''' +REG_PARSE_PRS_SRC = '''registry/reg_parse_prs.c''' -RPC_PARSE_SRC2 = '''rpc_parse/parse_rpc.c - rpc_client/init_netlogon.c +RPC_PARSE_SRC2 = '''rpc_client/init_netlogon.c rpc_client/init_lsa.c''' LIBREPLACE_SRC = '''${LIBREPLACE_SRCS}''' @@ -233,7 +232,7 @@ LIBSMB_ERR_SRC0 = '''${NTERR_SRC} ${DOSERR_SRC} ${ERRORMAP_SRC} ${DCE_RPC_ERR_SR LIBSMB_ERR_SRC1 = '''../libcli/auth/smbdes.c ../libcli/auth/smbencrypt.c ../libcli/auth/msrpc_parse.c ../libcli/auth/session.c''' -LIBSMB_ERR_SRC = '${LIBSMB_ERR_SRC0} ${LIBSMB_ERR_SRC1} ${RPC_PARSE_SRC1}' +LIBSMB_ERR_SRC = '${LIBSMB_ERR_SRC0} ${LIBSMB_ERR_SRC1} ${REG_PARSE_PRS_SRC}' LIBSMB_SRC0 = ''' ../libcli/auth/ntlm_check.c @@ -302,6 +301,7 @@ LIBMSRPC_GEN_SRC = '''../librpc/gen_ndr/cli_lsa.c ../librpc/gen_ndr/cli_drsuapi.c ../librpc/gen_ndr/cli_spoolss.c ../librpc/rpc/dcerpc_util.c + librpc/rpc/dcerpc_helpers.c ${LIBNDR_GEN_SRC} ${RPCCLIENT_NDR_SRC}''' |