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 | |
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
44 files changed, 2411 insertions, 2576 deletions
diff --git a/libcli/netlogon.c b/libcli/netlogon.c index e32842ec0a..d9b01964af 100644 --- a/libcli/netlogon.c +++ b/libcli/netlogon.c @@ -22,13 +22,6 @@ #include "includes.h" #include "../libcli/netlogon.h" -#undef DEBUG -#define DEBUG(x, y) -#undef DEBUGLVL -#define DEBUGLVL(x) false -#undef DEBUGLEVEL -#define DEBUGLEVEL 0 - NTSTATUS push_netlogon_samlogon_response(DATA_BLOB *data, TALLOC_CTX *mem_ctx, struct netlogon_samlogon_response *response) { diff --git a/librpc/idl/dcerpc.idl b/librpc/idl/dcerpc.idl index 68def36c5f..d98d7bd76f 100644 --- a/librpc/idl/dcerpc.idl +++ b/librpc/idl/dcerpc.idl @@ -317,18 +317,6 @@ interface dcerpc /* little-endian flag */ const uint8 DCERPC_DREP_LE = 0x10; - /* header only version of ncacn_packet */ - typedef [public] struct { - uint8 rpc_vers; /* RPC version */ - uint8 rpc_vers_minor; /* Minor version */ - dcerpc_pkt_type ptype; /* Packet type */ - uint8 pfc_flags; /* Fragmentation flags */ - uint8 drep[4]; /* NDR data representation */ - uint16 frag_length; /* Total length of fragment */ - uint16 auth_length; /* authenticator length */ - uint32 call_id; /* Call identifier */ - } ncacn_packet_header; - typedef [public] struct { uint8 rpc_vers; /* RPC version */ uint8 rpc_vers_minor; /* Minor version */ diff --git a/pidl/lib/Parse/Pidl/Samba3/ServerNDR.pm b/pidl/lib/Parse/Pidl/Samba3/ServerNDR.pm index a25d12bfea..0ea43e48ad 100644 --- a/pidl/lib/Parse/Pidl/Samba3/ServerNDR.pm +++ b/pidl/lib/Parse/Pidl/Samba3/ServerNDR.pm @@ -145,7 +145,6 @@ sub ParseFunction($$) pidl "struct ndr_pull *pull;"; pidl "struct ndr_push *push;"; pidl "enum ndr_err_code ndr_err;"; - pidl "DATA_BLOB blob;"; pidl "struct $fn->{NAME} *r;"; pidl ""; pidl "call = &ndr_table_$if->{NAME}.calls[$op];"; @@ -155,12 +154,7 @@ sub ParseFunction($$) pidl "\treturn false;"; pidl "}"; pidl ""; - pidl "if (!prs_data_blob(&p->in_data.data, &blob, r)) {"; - pidl "\ttalloc_free(r);"; - pidl "\treturn false;"; - pidl "}"; - pidl ""; - pidl "pull = ndr_pull_init_blob(&blob, r);"; + pidl "pull = ndr_pull_init_blob(&p->in_data.data, r);"; pidl "if (pull == NULL) {"; pidl "\ttalloc_free(r);"; pidl "\treturn false;"; @@ -211,11 +205,8 @@ sub ParseFunction($$) pidl "\treturn false;"; pidl "}"; pidl ""; - pidl "blob = ndr_push_blob(push);"; - pidl "if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32_t)blob.length)) {"; - pidl "\ttalloc_free(r);"; - pidl "\treturn false;"; - pidl "}"; + pidl "p->out_data.rdata = ndr_push_blob(push);"; + pidl "talloc_steal(p->mem_ctx, p->out_data.rdata.data);"; pidl ""; pidl "talloc_free(r);"; pidl ""; 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}''' diff --git a/source4/dsdb/samdb/ldb_modules/objectclass_attrs.c b/source4/dsdb/samdb/ldb_modules/objectclass_attrs.c index 6cfecc0d72..b9436e3a04 100644 --- a/source4/dsdb/samdb/ldb_modules/objectclass_attrs.c +++ b/source4/dsdb/samdb/ldb_modules/objectclass_attrs.c @@ -153,6 +153,12 @@ static int attr_handler(struct oc_context *ac) return ldb_next_request(ac->module, child_req); } +/* + these are attributes which are left over from old ways of doing + things in ldb, and are harmless + */ +static const char *harmless_attrs[] = { "parentGUID", NULL }; + static int attr_handler2(struct oc_context *ac) { struct ldb_context *ldb; @@ -219,6 +225,9 @@ static int attr_handler2(struct oc_context *ac) found = str_list_check(may_contain, attr->lDAPDisplayName); } if (!found) { + found = str_list_check(harmless_attrs, attr->lDAPDisplayName); + } + if (!found) { ldb_asprintf_errstring(ldb, "objectclass_attrs: attribute '%s' on entry '%s' does not exist in the specified objectclasses!", msg->elements[i].name, ldb_dn_get_linearized(msg->dn)); diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 90af17f7ec..2205be07c1 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -5,6 +5,7 @@ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005 Copyright (C) Andrew Tridgell 2005 Copyright (C) Stefan Metzmacher <metze@samba.org> 2007 + Copyright (C) Matthieu Patou <mat@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 @@ -1073,6 +1074,20 @@ static int replmd_update_rpmd_element(struct ldb_context *ldb, return LDB_SUCCESS; } +static uint64_t find_max_local_usn(struct replPropertyMetaDataBlob omd) +{ + uint32_t count = omd.ctr.ctr1.count; + uint64_t max = 0; + uint32_t i; + for (i=0; i < count; i++) { + struct replPropertyMetaData1 m = omd.ctr.ctr1.array[i]; + if (max < m.local_usn) { + max = m.local_usn; + } + } + return max; +} + /* * update the replPropertyMetaData object each time we modify an * object. This is needed for DRS replication, as the merge on the @@ -1093,11 +1108,12 @@ static int replmd_update_rpmd(struct ldb_module *module, const struct GUID *our_invocation_id; int ret; const char *attrs[] = { "replPropertyMetaData", "*", NULL }; + const char *attrs2[] = { "uSNChanged", "objectClass", NULL }; struct ldb_result *res; struct ldb_context *ldb; struct ldb_message_element *objectclass_el; enum urgent_situation situation; - bool rodc; + bool rodc, rmd_is_provided; ldb = ldb_module_get_ctx(module); @@ -1111,21 +1127,10 @@ static int replmd_update_rpmd(struct ldb_module *module, unix_to_nt_time(&now, t); - /* search for the existing replPropertyMetaDataBlob. We need - * to use REVEAL and ask for DNs in storage format to support - * the check for values being the same in - * replmd_update_rpmd_element() - */ - ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs, - DSDB_FLAG_NEXT_MODULE | - DSDB_SEARCH_SHOW_DELETED | - DSDB_SEARCH_SHOW_EXTENDED_DN | - DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT | - DSDB_SEARCH_REVEAL_INTERNALS); - if (ret != LDB_SUCCESS || res->count != 1) { - DEBUG(0,(__location__ ": Object %s failed to find replPropertyMetaData\n", - ldb_dn_get_linearized(msg->dn))); - return LDB_ERR_OPERATIONS_ERROR; + if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_OID)) { + rmd_is_provided = true; + } else { + rmd_is_provided = false; } /* if isDeleted is present and is TRUE, then we consider we are deleting, @@ -1136,62 +1141,140 @@ static int replmd_update_rpmd(struct ldb_module *module, situation = REPL_URGENT_ON_UPDATE; } - objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass"); - if (is_urgent && replmd_check_urgent_objectclass(objectclass_el, - situation)) { - *is_urgent = true; - } + if (rmd_is_provided) { + /* In this case the change_replmetadata control was supplied */ + /* We check that it's the only attribute that is provided + * (it's a rare case so it's better to keep the code simplier) + * We also check that the highest local_usn is bigger than + * uSNChanged. */ + uint64_t db_seq; + if( msg->num_elements != 1 || + strncmp(msg->elements[0].name, + "replPropertyMetaData", 20) ) { + DEBUG(0,(__location__ ": changereplmetada control called without "\ + "a specified replPropertyMetaData attribute or with others\n")); + return LDB_ERR_OPERATIONS_ERROR; + } + if (situation == REPL_URGENT_ON_DELETE) { + DEBUG(0,(__location__ ": changereplmetada control can't be called when deleting an object\n")); + return LDB_ERR_OPERATIONS_ERROR; + } + omd_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData"); + if (!omd_value) { + DEBUG(0,(__location__ ": replPropertyMetaData was not specified for Object %s\n", + ldb_dn_get_linearized(msg->dn))); + return LDB_ERR_OPERATIONS_ERROR; + } + ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd, + (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n", + ldb_dn_get_linearized(msg->dn))); + return LDB_ERR_OPERATIONS_ERROR; + } + *seq_num = find_max_local_usn(omd); - omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData"); - if (!omd_value) { - DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n", - ldb_dn_get_linearized(msg->dn))); - return LDB_ERR_OPERATIONS_ERROR; - } + ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs2, + DSDB_FLAG_NEXT_MODULE | + DSDB_SEARCH_SHOW_DELETED | + DSDB_SEARCH_SHOW_EXTENDED_DN | + DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT | + DSDB_SEARCH_REVEAL_INTERNALS); - ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd, - (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n", - ldb_dn_get_linearized(msg->dn))); - return LDB_ERR_OPERATIONS_ERROR; - } + if (ret != LDB_SUCCESS || res->count != 1) { + DEBUG(0,(__location__ ": Object %s failed to find uSNChanged\n", + ldb_dn_get_linearized(msg->dn))); + return LDB_ERR_OPERATIONS_ERROR; + } - if (omd.version != 1) { - DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n", - omd.version, ldb_dn_get_linearized(msg->dn))); - return LDB_ERR_OPERATIONS_ERROR; - } + objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass"); + if (is_urgent && replmd_check_urgent_objectclass(objectclass_el, + situation)) { + *is_urgent = true; + } - /*we have elements that will be modified*/ - if (msg->num_elements > 0) { - /*if we are RODC and this is a DRSR update then its ok*/ - if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)) { - ret = samdb_rodc(ldb, &rodc); - if (ret != LDB_SUCCESS) { - DEBUG(4, (__location__ ": unable to tell if we are an RODC\n")); - } else if (rodc) { - ldb_asprintf_errstring(ldb, "RODC modify is forbidden\n"); - return LDB_ERR_REFERRAL; - } + db_seq = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNChanged", 0); + if (*seq_num <= db_seq) { + DEBUG(0,(__location__ ": changereplmetada control provided but max(local_usn)"\ + " is less or equal to uSNChanged (max = %lld uSNChanged = %lld)\n", + *seq_num, db_seq)); + return LDB_ERR_OPERATIONS_ERROR; } - } - for (i=0; i<msg->num_elements; i++) { - struct ldb_message_element *old_el; - old_el = ldb_msg_find_element(res->msgs[0], msg->elements[i].name); - ret = replmd_update_rpmd_element(ldb, msg, &msg->elements[i], old_el, &omd, schema, seq_num, - our_invocation_id, now); - if (ret != LDB_SUCCESS) { - return ret; + } else { + /* search for the existing replPropertyMetaDataBlob. We need + * to use REVEAL and ask for DNs in storage format to support + * the check for values being the same in + * replmd_update_rpmd_element() + */ + ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs, + DSDB_FLAG_NEXT_MODULE | + DSDB_SEARCH_SHOW_DELETED | + DSDB_SEARCH_SHOW_EXTENDED_DN | + DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT | + DSDB_SEARCH_REVEAL_INTERNALS); + if (ret != LDB_SUCCESS || res->count != 1) { + DEBUG(0,(__location__ ": Object %s failed to find replPropertyMetaData\n", + ldb_dn_get_linearized(msg->dn))); + return LDB_ERR_OPERATIONS_ERROR; } - if (is_urgent && !*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) { - *is_urgent = replmd_check_urgent_attribute(&msg->elements[i]); + objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass"); + if (is_urgent && replmd_check_urgent_objectclass(objectclass_el, + situation)) { + *is_urgent = true; } - } + omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData"); + if (!omd_value) { + DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n", + ldb_dn_get_linearized(msg->dn))); + return LDB_ERR_OPERATIONS_ERROR; + } + ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd, + (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n", + ldb_dn_get_linearized(msg->dn))); + return LDB_ERR_OPERATIONS_ERROR; + } + + if (omd.version != 1) { + DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n", + omd.version, ldb_dn_get_linearized(msg->dn))); + return LDB_ERR_OPERATIONS_ERROR; + } + + /*we have elements that will be modified*/ + if (msg->num_elements > 0) { + /*if we are RODC and this is a DRSR update then its ok*/ + if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)) { + ret = samdb_rodc(ldb, &rodc); + if (ret != LDB_SUCCESS) { + DEBUG(4, (__location__ ": unable to tell if we are an RODC\n")); + } else if (rodc) { + ldb_asprintf_errstring(ldb, "RODC modify is forbidden\n"); + return LDB_ERR_REFERRAL; + } + } + } + + for (i=0; i<msg->num_elements; i++) { + struct ldb_message_element *old_el; + old_el = ldb_msg_find_element(res->msgs[0], msg->elements[i].name); + ret = replmd_update_rpmd_element(ldb, msg, &msg->elements[i], old_el, &omd, schema, seq_num, + our_invocation_id, now); + if (ret != LDB_SUCCESS) { + return ret; + } + + if (is_urgent && !*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) { + *is_urgent = replmd_check_urgent_attribute(&msg->elements[i]); + } + + } + } /* * replmd_update_rpmd_element has done an update if the * seq_num is set diff --git a/source4/dsdb/samdb/samdb.h b/source4/dsdb/samdb/samdb.h index 8b45cd0180..75aae7f108 100644 --- a/source4/dsdb/samdb/samdb.h +++ b/source4/dsdb/samdb/samdb.h @@ -92,6 +92,12 @@ struct dsdb_control_password_change_status { */ #define DSDB_CONTROL_BYPASS_PASSWORD_HASH_OID "1.3.6.1.4.1.7165.4.3.12" +/** + OID used to allow the replacement of replPropertyMetaData. + It is used when the current replmetadata needs to be edited. +*/ +#define DSDB_CONTROL_CHANGEREPLMETADATA_OID "1.3.6.1.4.1.7165.4.3.14" + #define DSDB_EXTENDED_REPLICATED_OBJECTS_OID "1.3.6.1.4.1.7165.4.4.1" struct dsdb_extended_replicated_object { struct ldb_message *msg; diff --git a/source4/lib/ldb/pyldb.c b/source4/lib/ldb/pyldb.c index b886a4b81c..f27ab3dd95 100644 --- a/source4/lib/ldb/pyldb.c +++ b/source4/lib/ldb/pyldb.c @@ -1249,6 +1249,26 @@ static PyObject *py_ldb_modules(PyLdbObject *self) return ret; } +static PyObject *py_ldb_sequence_number(PyLdbObject *self, PyObject *args) +{ + struct ldb_context *ldb = PyLdb_AsLdbContext(self); + int type, ret; + uint64_t value; + + /* type "int" rather than "enum" for "scope" is intentional */ + if (!PyArg_ParseTuple(args, "i", &type)) + return NULL; + + /* FIXME: More interpretation */ + + ret = ldb_sequence_number(ldb, type, &value); + + if (ret != LDB_SUCCESS) { + PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, ldb); + return NULL; + } + return PyLong_FromLongLong(value); +} static PyMethodDef py_ldb_methods[] = { { "set_debug", (PyCFunction)py_ldb_set_debug, METH_VARARGS, "S.set_debug(callback) -> None\n" @@ -1335,6 +1355,9 @@ static PyMethodDef py_ldb_methods[] = { { "modules", (PyCFunction)py_ldb_modules, METH_NOARGS, "S.modules() -> list\n" "Return the list of modules on this LDB connection " }, + { "sequence_number", (PyCFunction)py_ldb_sequence_number, METH_VARARGS, + "S.sequence_number(type) -> value\n" + "Return the value of the sequence according to the requested type" }, { NULL }, }; @@ -1635,9 +1658,14 @@ struct ldb_message_element *PyObject_AsMessageElement(TALLOC_CTX *mem_ctx, { struct ldb_message_element *me; - if (PyLdbMessageElement_Check(set_obj)) - return talloc_reference(mem_ctx, - PyLdbMessageElement_AsMessageElement(set_obj)); + if (PyLdbMessageElement_Check(set_obj)) { + PyLdbMessageElementObject *set_obj_as_me = (PyLdbMessageElementObject *)set_obj; + /* We have to talloc_reference() the memory context, not the pointer which may not actually be it's own context */ + if (talloc_reference(mem_ctx, set_obj_as_me->mem_ctx)) { + return PyLdbMessageElement_AsMessageElement(set_obj); + } + return NULL; + } me = talloc(mem_ctx, struct ldb_message_element); @@ -1941,7 +1969,7 @@ static PyObject *py_ldb_msg_getitem_helper(PyLdbMessageObject *self, PyObject *p if (el == NULL) { return NULL; } - return (PyObject *)PyLdbMessageElement_FromMessageElement(el, msg); + return (PyObject *)PyLdbMessageElement_FromMessageElement(el, msg->elements); } static PyObject *py_ldb_msg_getitem(PyLdbMessageObject *self, PyObject *py_name) @@ -1980,7 +2008,7 @@ static PyObject *py_ldb_msg_items(PyLdbMessageObject *self) j++; } for (i = 0; i < msg->num_elements; i++, j++) { - PyList_SetItem(l, j, Py_BuildValue("(sO)", msg->elements[i].name, PyLdbMessageElement_FromMessageElement(&msg->elements[i], self->msg))); + PyList_SetItem(l, j, Py_BuildValue("(sO)", msg->elements[i].name, PyLdbMessageElement_FromMessageElement(&msg->elements[i], msg->elements))); } return l; } @@ -2018,7 +2046,7 @@ static int py_ldb_msg_setitem(PyLdbMessageObject *self, PyObject *name, PyObject ldb_msg_remove_attr(self->msg, attr_name); } else { struct ldb_message_element *el = PyObject_AsMessageElement(self->msg, - value, 0, attr_name); + value, 0, attr_name); if (el == NULL) return -1; ldb_msg_remove_attr(PyLdbMessage_AsMessage(self), attr_name); @@ -2594,6 +2622,9 @@ void initldb(void) if (m == NULL) return; + PyModule_AddObject(m, "SEQ_HIGHEST_SEQ", PyInt_FromLong(LDB_SEQ_HIGHEST_SEQ)); + PyModule_AddObject(m, "SEQ_HIGHEST_TIMESTAMP", PyInt_FromLong(LDB_SEQ_HIGHEST_TIMESTAMP)); + PyModule_AddObject(m, "SEQ_NEXT", PyInt_FromLong(LDB_SEQ_NEXT)); PyModule_AddObject(m, "SCOPE_DEFAULT", PyInt_FromLong(LDB_SCOPE_DEFAULT)); PyModule_AddObject(m, "SCOPE_BASE", PyInt_FromLong(LDB_SCOPE_BASE)); PyModule_AddObject(m, "SCOPE_ONELEVEL", PyInt_FromLong(LDB_SCOPE_ONELEVEL)); diff --git a/source4/scripting/bin/upgradeprovision b/source4/scripting/bin/upgradeprovision index 48c4ce63b8..deb50e36fb 100755 --- a/source4/scripting/bin/upgradeprovision +++ b/source4/scripting/bin/upgradeprovision @@ -43,20 +43,22 @@ from ldb import (SCOPE_SUBTREE, SCOPE_BASE, MessageElement, Message, Dn) from samba import param from samba.provision import (find_setup_dir, get_domain_descriptor, - get_config_descriptor, secretsdb_self_join, + get_config_descriptor, ProvisioningError, get_last_provision_usn, get_max_usn, update_provision_usn) from samba.schema import get_linked_attributes, Schema, get_schema_descriptor -from samba.dcerpc import security, drsblobs +from samba.dcerpc import security, drsblobs, xattr from samba.ndr import ndr_unpack -from samba.dcerpc.misc import SEC_CHAN_BDC from samba.upgradehelpers import (dn_sort, get_paths, newprovision, find_provision_key_parameters, get_ldbs, usn_in_range, identic_rename, get_diff_sddls, update_secrets, CHANGE, ERROR, SIMPLE, CHANGEALL, GUESS, CHANGESD, PROVISION, updateOEMInfo, getOEMInfo, update_gpo, - delta_update_basesamdb, update_policyids) + delta_update_basesamdb, update_policyids, + update_machine_account_password, + search_constructed_attrs_stored, + increment_calculated_keyversion_number) replace=2**FLAG_MOD_REPLACE add=2**FLAG_MOD_ADD @@ -103,7 +105,9 @@ hashOverwrittenAtt = { "prefixMap": replace, "systemMayContain": replace, "wellKnownObjects":replace, "privilege":never, "defaultSecurityDescriptor": replace, "rIDAvailablePool": never, - "defaultSecurityDescriptor": replace + add } + "defaultSecurityDescriptor": replace + add, + "isMemberOfPartialAttributeSet": delete, + "attributeDisplayNames": replace + add} backlinked = [] @@ -285,7 +289,7 @@ def print_provision_key_parameters(names): message(GUESS, "domainlevel :" + str(names.domainlevel)) -def handle_special_case(att, delta, new, old, usn): +def handle_special_case(att, delta, new, old, usn, basedn, aldb): """Define more complicate update rules for some attributes :param att: The attribute to be updated @@ -294,6 +298,8 @@ def handle_special_case(att, delta, new, old, usn): :param new: The reference object :param old: The Updated object :param usn: The highest usn modified by a previous (upgrade)provision + :param basedn: The base DN of the provision + :param aldb: An ldb object used to build DN :return: True to indicate that the attribute should be kept, False for discarding it""" @@ -302,6 +308,23 @@ def handle_special_case(att, delta, new, old, usn): # highest usn as otherwise the replPropertyMetaData will guide us more # correctly if usn is None: + if (att == "sPNMappings" and flag == FLAG_MOD_REPLACE and + ldb.Dn(aldb, "CN=Directory Service,CN=Windows NT," + "CN=Services,CN=Configuration,%s" % basedn) + == old[0].dn): + return True + if (att == "userAccountControl" and flag == FLAG_MOD_REPLACE and + ldb.Dn(aldb, "CN=Administrator,CN=Users,%s" % basedn) + == old[0].dn): + message(SIMPLE, "We suggest that you change the userAccountControl" + " for user Administrator from value %d to %d" % + (int(str(old[0][att])), int(str(new[0][att])))) + return False + if (att == "minPwdAge" and flag == FLAG_MOD_REPLACE): + if (long(str(old[0][att])) == 0): + delta[att] = MessageElement(new[0][att], FLAG_MOD_REPLACE, att) + return True + if (att == "member" and flag == FLAG_MOD_REPLACE): hash = {} newval = [] @@ -320,7 +343,7 @@ def handle_special_case(att, delta, new, old, usn): delta.remove(att) return True - if (att in ("gPLink", "gPCFileSysPath") and + if (att in ("gPLink", "gPCFileSysPath") and flag == FLAG_MOD_REPLACE and str(new[0].dn).lower() == str(old[0].dn).lower()): delta.remove(att) @@ -516,30 +539,40 @@ def add_missing_object(ref_samdb, samdb, dn, names, basedn, hash, index): empty = Message() delta = samdb.msg_diff(empty, reference[0]) delta.dn - if delta.get("objectSid"): - sid = str(ndr_unpack(security.dom_sid, str(reference[0]["objectSid"]))) - m = re.match(r".*-(\d+)$", sid) - if m and int(m.group(1))>999: - delta.remove("objectSid") - for att in hashAttrNotCopied.keys(): - delta.remove(att) - for att in backlinked: - delta.remove(att) - depend_on_yettobecreated = None - for att in dn_syntax_att: - depend_on_yet_tobecreated = check_dn_nottobecreated(hash, index, - delta.get(str(att))) - if depend_on_yet_tobecreated is not None: - message(CHANGE, "Object %s depends on %s in attribute %s," - "delaying the creation" % (dn, - depend_on_yet_tobecreated, att)) - return False + skip = False + try: + if str(reference[0].get("cn")) == "RID Set": + for klass in reference[0].get("objectClass"): + if str(klass).lower == "ridset": + skip = True + finally: + if delta.get("objectSid"): + sid = str(ndr_unpack(security.dom_sid, str(reference[0]["objectSid"]))) + m = re.match(r".*-(\d+)$", sid) + if m and int(m.group(1))>999: + delta.remove("objectSid") + for att in hashAttrNotCopied.keys(): + delta.remove(att) + for att in backlinked: + delta.remove(att) + depend_on_yettobecreated = None + for att in dn_syntax_att: + depend_on_yet_tobecreated = check_dn_nottobecreated(hash, index, + delta.get(str(att))) + if depend_on_yet_tobecreated is not None: + message(CHANGE, "Object %s depends on %s in attribute %s," + "delaying the creation" % (dn, + depend_on_yet_tobecreated, att)) + return False - delta.dn = dn - message(CHANGE,"Object %s will be added" % dn) - samdb.add(delta, ["relax:0"]) + delta.dn = dn + if not skip: + message(CHANGE,"Object %s will be added" % dn) + samdb.add(delta, ["relax:0"]) + else: + message(CHANGE,"Object %s was skipped" % dn) - return True + return True def gen_dn_index_hash(listMissing): """Generate a hash associating the DN to its creation order @@ -813,7 +846,7 @@ def update_present(ref_samdb, samdb, basedn, listPresent, usns, invocationid): # idea to change it delta.remove(att) continue - if handle_special_case(att, delta, reference, current, usns): + if handle_special_case(att, delta, reference, current, usns, basedn, samdb): # This attribute is "complicated" to handle and handling # was done in handle_special_case continue @@ -827,16 +860,16 @@ def update_present(ref_samdb, samdb, basedn, listPresent, usns, invocationid): if attrUSN == -1: # This attribute was last modified by another DC forget # about it - message(CHANGE, "%sAttribute: %s has been" + message(CHANGE, "%sAttribute: %s has been" "created/modified/deleted by another DC," " do nothing" % (txt, att )) txt = "" delta.remove(att) continue elif not usn_in_range(int(attrUSN), usns): - message(CHANGE, "%sAttribute: %s has been" - "created/modified/deleted not during a" - " provision or upgradeprovision: current" + message(CHANGE, "%sAttribute: %s has been" + "created/modified/deleted not during a" + " provision or upgradeprovision: current" " usn %d , do nothing" % (txt, att, attrUSN)) txt = "" delta.remove(att) @@ -845,13 +878,13 @@ def update_present(ref_samdb, samdb, basedn, listPresent, usns, invocationid): if att == "defaultSecurityDescriptor": defSDmodified = True if attrUSN: - message(CHANGE, "%sAttribute: %s will be modified" - "/deleted it was last modified" - "during a provision, current usn:" + message(CHANGE, "%sAttribute: %s will be modified" + "/deleted it was last modified" + "during a provision, current usn:" "%d" % (txt, att, attrUSN)) txt = "" else: - message(CHANGE, "%sAttribute: %s will be added because" + message(CHANGE, "%sAttribute: %s will be added because" " it hasn't existed before " % (txt, att)) txt = "" continue @@ -871,7 +904,7 @@ def update_present(ref_samdb, samdb, basedn, listPresent, usns, invocationid): if not hashOverwrittenAtt.has_key(att): if msgElt.flags() != FLAG_MOD_ADD: if not handle_special_case(att, delta, reference, current, - usns): + usns, basedn, samdb): if opts.debugchange or opts.debugall: try: dump_denied_change(dn, att, @@ -893,7 +926,7 @@ def update_present(ref_samdb, samdb, basedn, listPresent, usns, invocationid): delta.dn = dn if len(delta.items()) >1: attributes=", ".join(delta.keys()) - message(CHANGE, "%s is different from the reference one, changed" + message(CHANGE, "%s is different from the reference one, changed" " attributes: %s\n" % (dn, attributes)) changed += 1 samdb.modify(delta) @@ -1002,6 +1035,7 @@ def check_updated_sd(ref_sam, cur_sam, names): str(reference[i]["nTSecurityDescriptor"])) hash[str(reference[i]["dn"]).lower()] = refsd.as_sddl(names.domainsid) + for i in range(0, len(current)): key = str(current[i]["dn"]).lower() if hash.has_key(key): @@ -1073,7 +1107,7 @@ def rebuild_sd(samdb, names): controls=["search_options:1:2"]) for obj in res: if not (str(obj["dn"]) == str(names.rootdn) or - str(obj["dn"]) == str(names.configdn) or + str(obj["dn"]) == str(names.configdn) or str(obj["dn"]) == str(names.schemadn)): hash[str(obj["dn"])] = obj["whenCreated"] @@ -1113,6 +1147,18 @@ def removeProvisionUSN(samdb): delta.dn = entry[0].dn samdb.modify(delta) +def remove_stored_generated_attrs(paths, creds, session, lp): + """Remove previously stored constructed attributes + + :param paths: List of paths for different provision objects + from the upgraded provision + :param creds: A credential object + :param session: A session object + :param lp: A line parser object + :return: An associative array whose key are the different constructed + attributes and the value the dn where this attributes were found. + """ + def simple_update_basesamdb(newpaths, paths, names): """Update the provision container db: sam.ldb @@ -1185,49 +1231,114 @@ def update_samdb(ref_samdb, samdb, names, highestUSN, schema): return 0 -def update_machine_account_password(samdb, secrets_ldb, names): - """Update (change) the password of the current DC both in the SAM db and in - secret one +def copyxattrs(dir, refdir): + """ Copy owner, groups, extended ACL and NT acls from + a reference dir to a destination dir + + Both dir are supposed to hold the same files + :param dir: Destination dir + :param refdir: Reference directory""" + + noxattr = 0 + for root, dirs, files in os.walk(dir, topdown=True): + for name in files: + subdir=root[len(dir):] + ref = os.path.join("%s%s" % (refdir, subdir), name) + statsinfo = os.stat(ref) + tgt = os.path.join(root, name) + try: + + os.chown(tgt, statsinfo.st_uid, statsinfo.st_gid) + # Get the xattr attributes if any + try: + attribute = samba.xattr_native.wrap_getxattr(ref, + xattr.XATTR_NTACL_NAME) + samba.xattr_native.wrap_setxattr(tgt, + xattr.XATTR_NTACL_NAME, + attribute) + except: + noxattr = 1 + attribute = samba.xattr_native.wrap_getxattr(ref, + "system.posix_acl_access") + samba.xattr_native.wrap_setxattr(tgt, + "system.posix_acl_access", + attribute) + except: + continue + for name in dirs: + subdir=root[len(dir):] + ref = os.path.join("%s%s" % (refdir, subdir), name) + statsinfo = os.stat(ref) + tgt = os.path.join(root, name) + try: + os.chown(os.path.join(root, name), statsinfo.st_uid, + statsinfo.st_gid) + try: + attribute = samba.xattr_native.wrap_getxattr(ref, + xattr.XATTR_NTACL_NAME) + samba.xattr_native.wrap_setxattr(tgt, + xattr.XATTR_NTACL_NAME, + attribute) + except: + noxattr = 1 + attribute = samba.xattr_native.wrap_getxattr(ref, + "system.posix_acl_access") + samba.xattr_native.wrap_setxattr(tgt, + "system.posix_acl_access", + attribute) + + except: + continue + + +def backup_provision(paths, dir): + """This function backup the provision files so that a rollback + is possible + + :param paths: Paths to different objects + :param dir: Directory where to store the backup + """ - :param samdb: An LDB object related to the sam.ldb file of a given provision - :param secrets_ldb: An LDB object related to the secrets.ldb file of a given - provision - :param names: List of key provision parameters""" + shutil.copytree(paths.sysvol, os.path.join(dir, "sysvol")) + copyxattrs(os.path.join(dir, "sysvol"), paths.sysvol) + shutil.copy2(paths.samdb, dir) + shutil.copy2(paths.secrets, dir) + shutil.copy2(paths.idmapdb, dir) + shutil.copy2(paths.privilege, dir) + if os.path.isfile(os.path.join(paths.private_dir,"eadb.tdb")): + shutil.copy2(os.path.join(paths.private_dir,"eadb.tdb"), dir) + shutil.copy2(paths.smbconf, dir) + shutil.copy2(os.path.join(paths.private_dir,"secrets.keytab"), dir) - message(SIMPLE, "Update machine account") - expression = "samAccountName=%s$" % names.netbiosname - secrets_msg = secrets_ldb.search(expression=expression, - attrs=["secureChannelType"]) - if int(secrets_msg[0]["secureChannelType"][0]) == SEC_CHAN_BDC: - res = samdb.search(expression=expression, attrs=[]) - assert(len(res) == 1) - - msg = Message(res[0].dn) - machinepass = samba.generate_random_password(128, 255) - msg["userPassword"] = MessageElement(machinepass, FLAG_MOD_REPLACE, - "userPassword") - samdb.modify(msg) - - res = samdb.search(expression=("samAccountName=%s$" % names.netbiosname), - attrs=["msDs-keyVersionNumber"]) - assert(len(res) == 1) - kvno = int(str(res[0]["msDs-keyVersionNumber"])) - secChanType = int(secrets_msg[0]["secureChannelType"][0]) - - secretsdb_self_join(secrets_ldb, domain=names.domain, - realm=names.realm or sambaopts._lp.get('realm'), - domainsid=names.domainsid, - dnsdomain=names.dnsdomain, - netbiosname=names.netbiosname, - machinepass=machinepass, - key_version_number=kvno, - secure_channel_type=secChanType) + samldbdir = os.path.join(paths.private_dir, "sam.ldb.d") + if not os.path.isdir(samldbdir): + samldbdir = paths.private_dir + schemaldb = os.path.join(paths.private_dir, "schema.ldb") + configldb = os.path.join(paths.private_dir, "configuration.ldb") + usersldb = os.path.join(paths.private_dir, "users.ldb") + shutil.copy2(schemaldb, dir) + shutil.copy2(usersldb, dir) + shutil.copy2(configldb, dir) else: - raise ProvisioningError("Unable to find a Secure Channel" - "of type SEC_CHAN_BDC") + shutil.copytree(samldbdir, os.path.join(dir, "sam.ldb.d")) + +def sync_calculated_attributes(samdb, names): + """Synchronize attributes used for constructed ones, with the + old constructed that were stored in the database. + + This apply for instance to msds-keyversionnumber that was + stored and that is now constructed from replpropertymetadata. + + :param samdb: An LDB object attached to the currently upgraded samdb + :param names: Various key parameter about current provision. + """ + listAttrs = ["msDs-KeyVersionAttribute"] + hash = search_constructed_attrs_stored(samdb, names.rootdn, listAttrs) + increment_calculated_keyversion_number(samdb, names.rootdn, hash) + def setup_path(file): return os.path.join(setup_dir, file) @@ -1252,12 +1363,13 @@ def setup_path(file): # A) When alpha9 or alphaxx is present # The base sam.ldb file is updated by looking at the difference between # referrence one and the current one. Everything is copied with the -# exception of lastProvisionUSN attributes. The highest used USN -# is fetched so that changed by upgradeprovision usn can be tracked +# exception of lastProvisionUSN attributes. # B) Other case (it reflect that that provision was done before alpha9) # The base sam.ldb of the reference provision is copied over # the current one, if necessary ldb related to partitions are moved # and renamed +# The highest used USN is fetched so that changed by upgradeprovision +# usn can be tracked # 12)A Schema object is created, it will be used to provide a complete # schema to current provision during update (as the schema of the # current provision might not be complete and so won't allow some @@ -1380,157 +1492,172 @@ if __name__ == '__main__': minUSN = 0 # 2) ldbs = get_ldbs(paths, creds, session, lp) - ldbs.startTransactions() - - # 3) Guess all the needed names (variables in fact) from the current - # provision. - names = find_provision_key_parameters(ldbs.sam, ldbs.secrets, ldbs.idmap, - paths, smbconf, lp) - # 4) - lastProvisionUSNs = get_last_provision_usn(ldbs.sam) - if lastProvisionUSNs is not None: - message(CHANGE, - "Find a last provision USN, %d range(s)" % len(lastProvisionUSNs)) - - # Objects will be created with the admin session - # (not anymore system session) - adm_session = admin_session(lp, str(names.domainsid)) - # So we reget handle on objects - # ldbs = get_ldbs(paths, creds, adm_session, lp) - - if not sanitychecks(ldbs.sam, names): - message(SIMPLE, "Sanity checks for the upgrade fails, checks messages" - " and correct them before rerunning upgradeprovision") - sys.exit(1) - - # Let's see provision parameters - print_provision_key_parameters(names) - - # 5) With all this information let's create a fresh new provision used as - # reference - message(SIMPLE, "Creating a reference provision") - provisiondir = tempfile.mkdtemp(dir=paths.private_dir, - prefix="referenceprovision") - newprovision(names, setup_dir, creds, session, smbconf, provisiondir, - provision_logger) - - # TODO - # 6) and 7) - # We need to get a list of object which SD is directly computed from - # defaultSecurityDescriptor. - # This will allow us to know which object we can rebuild the SD in case - # of change of the parent's SD or of the defaultSD. - # Get file paths of this new provision - newpaths = get_paths(param, targetdir=provisiondir) - new_ldbs = get_ldbs(newpaths, creds, session, lp) - new_ldbs.startTransactions() - - # 8) Populate some associative array to ease the update process - # List of attribute which are link and backlink - populate_links(new_ldbs.sam, names.schemadn) - # List of attribute with ASN DN synthax) - populate_dnsyntax(new_ldbs.sam, names.schemadn) - # 9) - update_privilege(newpaths.private_dir, paths.private_dir) - # 10) - oem = getOEMInfo(ldbs.sam, str(names.rootdn)) - # Do some modification on sam.ldb - ldbs.groupedCommit() - # 11) - if re.match(".*alpha((9)|(\d\d+)).*", str(oem)): - # 11) A - # Starting from alpha9 we can consider that the structure is quite ok - # and that we should do only dela + backupdir = tempfile.mkdtemp(dir=paths.private_dir, + prefix="backupprovision") + backup_provision(paths, backupdir) + try: + ldbs.startTransactions() + + # 3) Guess all the needed names (variables in fact) from the current + # provision. + names = find_provision_key_parameters(ldbs.sam, ldbs.secrets, ldbs.idmap, + paths, smbconf, lp) + # 4) + lastProvisionUSNs = get_last_provision_usn(ldbs.sam) + if lastProvisionUSNs is not None: + message(CHANGE, + "Find a last provision USN, %d range(s)" % len(lastProvisionUSNs)) + + # Objects will be created with the admin session + # (not anymore system session) + adm_session = admin_session(lp, str(names.domainsid)) + # So we reget handle on objects + # ldbs = get_ldbs(paths, creds, adm_session, lp) + + if not sanitychecks(ldbs.sam, names): + message(SIMPLE, "Sanity checks for the upgrade fails, checks messages" + " and correct them before rerunning upgradeprovision") + sys.exit(1) + + # Let's see provision parameters + print_provision_key_parameters(names) + + # 5) With all this information let's create a fresh new provision used as + # reference + message(SIMPLE, "Creating a reference provision") + provisiondir = tempfile.mkdtemp(dir=paths.private_dir, + prefix="referenceprovision") + newprovision(names, setup_dir, creds, session, smbconf, provisiondir, + provision_logger) + + # TODO + # 6) and 7) + # We need to get a list of object which SD is directly computed from + # defaultSecurityDescriptor. + # This will allow us to know which object we can rebuild the SD in case + # of change of the parent's SD or of the defaultSD. + # Get file paths of this new provision + newpaths = get_paths(param, targetdir=provisiondir) + new_ldbs = get_ldbs(newpaths, creds, session, lp) + new_ldbs.startTransactions() + + # 8) Populate some associative array to ease the update process + # List of attribute which are link and backlink + populate_links(new_ldbs.sam, names.schemadn) + # List of attribute with ASN DN synthax) + populate_dnsyntax(new_ldbs.sam, names.schemadn) + # 9) + update_privilege(newpaths.private_dir, paths.private_dir) + # 10) + oem = getOEMInfo(ldbs.sam, str(names.rootdn)) + # Do some modification on sam.ldb + ldbs.groupedCommit() new_ldbs.groupedCommit() - delta_update_basesamdb(newpaths.samdb, paths.samdb, creds, session, lp, message) + + # 11) + if re.match(".*alpha((9)|(\d\d+)).*", str(oem)): + # 11) A + # Starting from alpha9 we can consider that the structure is quite ok + # and that we should do only dela + delta_update_basesamdb(newpaths.samdb, paths.samdb, creds, session, lp, message) + else: + # 11) B + simple_update_basesamdb(newpaths, paths, names) + ldbs = get_ldbs(paths, creds, session, lp) + removeProvisionUSN(ldbs.sam) + ldbs.startTransactions() minUSN = int(str(get_max_usn(ldbs.sam, str(names.rootdn)))) + 1 new_ldbs.startTransactions() - else: - # 11) B - simple_update_basesamdb(newpaths, paths, names) - ldbs = get_ldbs(paths, creds, session, lp) - removeProvisionUSN(ldbs.sam) - ldbs.startTransactions() - # 12) - schema = Schema(setup_path, names.domainsid, schemadn=str(names.schemadn), - serverdn=str(names.serverdn)) - # 13) - if opts.full: - if not update_samdb(new_ldbs.sam, ldbs.sam, names, lastProvisionUSNs, - schema): - message(SIMPLE, "Rollbacking every changes. Check the reason" - " of the problem") - message(SIMPLE, "In any case your system as it was before" - " the upgrade") - ldbs.groupedRollback() - new_ldbs.groupedRollback() - shutil.rmtree(provisiondir) - sys.exit(1) - # 14) - update_secrets(new_ldbs.secrets, ldbs.secrets, message) - # 15) - update_machine_account_password(ldbs.sam, ldbs.secrets, names) - - # 16) SD should be created with admin but as some previous acl were so wrong - # that admin can't modify them we have first to recreate them with the good - # form but with system account and then give the ownership to admin ... - if not re.match(r'.*alpha(9|\d\d+)', str(oem)): - message(SIMPLE, "Fixing old povision SD") - fix_partition_sd(ldbs.sam, names) - rebuild_sd(ldbs.sam, names) - - # We calculate the max USN before recalculating the SD because we might - # touch object that have been modified after a provision and we do not - # want that the next upgradeprovision thinks that it has a green light - # to modify them - - # 17) - maxUSN = get_max_usn(ldbs.sam, str(names.rootdn)) - - # 18) We rebuild SD only if defaultSecurityDescriptor is modified - # But in fact we should do it also if one object has its SD modified as - # child might need rebuild - if defSDmodified: - message(SIMPLE, "Updating SD") - ldbs.sam.set_session_info(adm_session) - # Alpha10 was a bit broken still - if re.match(r'.*alpha(\d|10)', str(oem)): + # 12) + schema = Schema(setup_path, names.domainsid, schemadn=str(names.schemadn), + serverdn=str(names.serverdn)) + + # 13) + if opts.full: + if not update_samdb(new_ldbs.sam, ldbs.sam, names, lastProvisionUSNs, + schema): + message(SIMPLE, "Rollbacking every changes. Check the reason" + " of the problem") + message(SIMPLE, "In any case your system as it was before" + " the upgrade") + ldbs.groupedRollback() + new_ldbs.groupedRollback() + shutil.rmtree(provisiondir) + sys.exit(1) + else: + sync_calculated_attributes(ldbs.sam, names) + # 14) + update_secrets(new_ldbs.secrets, ldbs.secrets, message) + # 15) + message(SIMPLE, "Update machine account") + update_machine_account_password(ldbs.sam, ldbs.secrets, names) + + # 16) SD should be created with admin but as some previous acl were so wrong + # that admin can't modify them we have first to recreate them with the good + # form but with system account and then give the ownership to admin ... + if not re.match(r'.*alpha(9|\d\d+)', str(oem)): + message(SIMPLE, "Fixing old povision SD") fix_partition_sd(ldbs.sam, names) - rebuild_sd(ldbs.sam, names) - - # 19) - # Now we are quite confident in the recalculate process of the SD, we make - # it optional. - # Also the check must be done in a clever way as for the moment we just - # compare SDDL - if opts.debugchangesd: - check_updated_sd(new_ldbs.sam, ldbs.sam, names) - - # 20) - updateOEMInfo(ldbs.sam, str(names.rootdn)) - # 21) - check_for_DNS(newpaths.private_dir, paths.private_dir) - # 22) - if lastProvisionUSNs is not None: - update_provision_usn(ldbs.sam, minUSN, maxUSN) - if opts.full and (names.policyid is None or names.policyid_dc is None): - update_policyids(names, ldbs.sam) - if opts.full or opts.resetfileacl: - try: - update_gpo(paths, ldbs.sam, names, lp, message, 1) - except ProvisioningError, e: - message(ERROR, "The policy for domain controller is missing," - " you should restart upgradeprovision with --full") - else: - try: - update_gpo(paths, ldbs.sam, names, lp, message, 0) - except ProvisioningError, e: - message(ERROR, "The policy for domain controller is missing," - " you should restart upgradeprovision with --full") - ldbs.groupedCommit() - new_ldbs.groupedCommit() - message(SIMPLE, "Upgrade finished !") - # remove reference provision now that everything is done ! - shutil.rmtree(provisiondir) + rebuild_sd(ldbs.sam, names) + + # We calculate the max USN before recalculating the SD because we might + # touch object that have been modified after a provision and we do not + # want that the next upgradeprovision thinks that it has a green light + # to modify them + + # 17) + maxUSN = get_max_usn(ldbs.sam, str(names.rootdn)) + + # 18) We rebuild SD only if defaultSecurityDescriptor is modified + # But in fact we should do it also if one object has its SD modified as + # child might need rebuild + if defSDmodified: + message(SIMPLE, "Updating SD") + ldbs.sam.set_session_info(adm_session) + # Alpha10 was a bit broken still + if re.match(r'.*alpha(\d|10)', str(oem)): + fix_partition_sd(ldbs.sam, names) + rebuild_sd(ldbs.sam, names) + + # 19) + # Now we are quite confident in the recalculate process of the SD, we make + # it optional. + # Also the check must be done in a clever way as for the moment we just + # compare SDDL + if opts.debugchangesd: + check_updated_sd(new_ldbs.sam, ldbs.sam, names) + + # 20) + updateOEMInfo(ldbs.sam, str(names.rootdn)) + # 21) + check_for_DNS(newpaths.private_dir, paths.private_dir) + # 22) + if lastProvisionUSNs is not None: + update_provision_usn(ldbs.sam, minUSN, maxUSN) + if opts.full and (names.policyid is None or names.policyid_dc is None): + update_policyids(names, ldbs.sam) + if opts.full or opts.resetfileacl: + try: + update_gpo(paths, ldbs.sam, names, lp, message, 1) + except ProvisioningError, e: + message(ERROR, "The policy for domain controller is missing," + " you should restart upgradeprovision with --full") + else: + try: + update_gpo(paths, ldbs.sam, names, lp, message, 0) + except ProvisioningError, e: + message(ERROR, "The policy for domain controller is missing," + " you should restart upgradeprovision with --full") + ldbs.groupedCommit() + new_ldbs.groupedCommit() + message(SIMPLE, "Upgrade finished !") + # remove reference provision now that everything is done ! + shutil.rmtree(provisiondir) + except StandardError, err: + message(ERROR,"A problem has occured when trying to upgrade your provision," + " a full backup is located at %s" % backupdir) + if opts.changeall: + (typ, val, tb) = sys.exc_info() + traceback.print_exception(typ, val, tb) diff --git a/source4/scripting/devel/chgtdcpass b/source4/scripting/devel/chgtdcpass new file mode 100755 index 0000000000..1030531363 --- /dev/null +++ b/source4/scripting/devel/chgtdcpass @@ -0,0 +1,63 @@ +#!/usr/bin/env python +# +# Copyright (C) Matthieu Patou <mat@matws.net> 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/>. + + +import optparse +import sys +# Allow to run from s4 source directory (without installing samba) +sys.path.insert(0, "bin/python") + +import samba.getopt as options +from samba.credentials import DONT_USE_KERBEROS +from samba.auth import system_session +from samba import param +from samba.upgradehelpers import (get_paths, + find_provision_key_parameters, get_ldbs, + update_machine_account_password) + +__docformat__ = "restructuredText" + + +parser = optparse.OptionParser("provision [options]") +sambaopts = options.SambaOptions(parser) +parser.add_option_group(sambaopts) +parser.add_option_group(options.VersionOptions(parser)) +credopts = options.CredentialsOptions(parser) +parser.add_option_group(credopts) + +opts = parser.parse_args()[0] + + +lp = sambaopts.get_loadparm() +smbconf = lp.configfile +creds = credopts.get_credentials(lp) +creds.set_kerberos_state(DONT_USE_KERBEROS) + + +if __name__ == '__main__': + paths = get_paths(param, smbconf=smbconf) + session = system_session() + + ldbs = get_ldbs(paths, creds, session, lp) + ldbs.startTransactions() + + names = find_provision_key_parameters(ldbs.sam, ldbs.secrets, ldbs.idmap, + paths, smbconf, lp) + + update_machine_account_password(ldbs.sam, ldbs.secrets, names) + ldbs.groupedCommit() diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 5ede869015..8be3f655d2 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -680,17 +680,16 @@ def secretsdb_self_join(secretsdb, domain, "krb5Keytab", "privateKeytab"] - + #We don't need to set msg["flatname"] here, because rdn_name will handle it, and it causes problems for modifies anyway msg = ldb.Message(ldb.Dn(secretsdb, "flatname=%s,cn=Primary Domains" % domain)) - msg["secureChannelType"] = str(secure_channel_type) - msg["flatname"] = [domain] + msg["secureChannelType"] = [str(secure_channel_type)] msg["objectClass"] = ["top", "primaryDomain"] if realm is not None: if dnsdomain is None: dnsdomain = realm.lower() msg["objectClass"] = ["top", "primaryDomain", "kerberosSecret"] - msg["realm"] = realm - msg["saltPrincipal"] = "host/%s.%s@%s" % (netbiosname.lower(), dnsdomain.lower(), realm.upper()) + msg["realm"] = [realm] + msg["saltPrincipal"] = ["host/%s.%s@%s" % (netbiosname.lower(), dnsdomain.lower(), realm.upper())] msg["msDS-KeyVersionNumber"] = [str(key_version_number)] msg["privateKeytab"] = ["secrets.keytab"] @@ -701,30 +700,39 @@ def secretsdb_self_join(secretsdb, domain, if domainsid is not None: msg["objectSid"] = [ndr_pack(domainsid)] + # This complex expression tries to ensure that we don't have more + # than one record for this SID, realm or netbios domain at a time, + # but we don't delete the old record that we are about to modify, + # because that would delete the keytab and previous password. res = secretsdb.search(base="cn=Primary Domains", attrs=attrs, - expression=("(&(|(flatname=%s)(realm=%s)(objectSid=%s))(objectclass=primaryDomain))" % (domain, realm, str(domainsid))), + expression=("(&(|(flatname=%s)(realm=%s)(objectSid=%s))(objectclass=primaryDomain)(!(dn=%s)))" % (domain, realm, str(domainsid), str(msg.dn))), scope=ldb.SCOPE_ONELEVEL) for del_msg in res: - if del_msg.dn is not msg.dn: secretsdb.delete(del_msg.dn) res = secretsdb.search(base=msg.dn, attrs=attrs, scope=ldb.SCOPE_BASE) if len(res) == 1: - msg["priorSecret"] = res[0]["secret"] - msg["priorWhenChanged"] = res[0]["whenChanged"] + msg["priorSecret"] = [res[0]["secret"][0]] + msg["priorWhenChanged"] = [res[0]["whenChanged"][0]] - if res["privateKeytab"] is not None: - msg["privateKeytab"] = res[0]["privateKeytab"] + try: + msg["privateKeytab"] = [res[0]["privateKeytab"][0]] + except KeyError: + pass - if res["krb5Keytab"] is not None: - msg["krb5Keytab"] = res[0]["krb5Keytab"] + try: + msg["krb5Keytab"] = [res[0]["krb5Keytab"][0]] + except KeyError: + pass for el in msg: - el.set_flags(ldb.FLAG_MOD_REPLACE) - secretsdb.modify(msg) + if el != 'dn': + msg[el].set_flags(ldb.FLAG_MOD_REPLACE) + secretsdb.modify(msg) + secretsdb.rename(res[0].dn, msg.dn) else: secretsdb.add(msg) diff --git a/source4/scripting/python/samba/samdb.py b/source4/scripting/python/samba/samdb.py index f810926710..f358747b51 100644 --- a/source4/scripting/python/samba/samdb.py +++ b/source4/scripting/python/samba/samdb.py @@ -28,12 +28,16 @@ import samba import ldb import time import base64 +from samba.ndr import ndr_unpack, ndr_pack +from samba.dcerpc import drsblobs, misc __docformat__ = "restructuredText" class SamDB(samba.Ldb): """The SAM database.""" + hash_oid_name = {} + def __init__(self, url=None, lp=None, modules_dir=None, session_info=None, credentials=None, flags=0, options=None, global_schema=True, auto_connect=True, am_rodc=False): @@ -470,5 +474,104 @@ accountExpires: %u def set_schema_from_ldb(self, ldb): dsdb._dsdb_set_schema_from_ldb(self, ldb) + def get_attribute_from_attid(self, attid): + """ Get from an attid the associated attribute + + :param attid: The attribute id for searched attribute + :return: The name of the attribute associated with this id + """ + if len(self.hash_oid_name.keys()) == 0: + self._populate_oid_attid() + if self.hash_oid_name.has_key(self.get_oid_from_attid(attid)): + return self.hash_oid_name[self.get_oid_from_attid(attid)] + else: + return None + + + def _populate_oid_attid(self): + """Populate the hash hash_oid_name + + This hash contains the oid of the attribute as a key and + its display name as a value + """ + self.hash_oid_name = {} + res = self.search(expression="objectClass=attributeSchema", + controls=["search_options:1:2"], + attrs=["attributeID", + "lDAPDisplayName"]) + if len(res) > 0: + for e in res: + strDisplay = str(e.get("lDAPDisplayName")) + self.hash_oid_name[str(e.get("attributeID"))] = strDisplay + + + def get_attribute_replmetadata_version(self, dn, att): + """ Get the version field trom the replPropertyMetaData for + the given field + + :param dn: The on which we want to get the version + :param att: The name of the attribute + :return: The value of the version field in the replPropertyMetaData + for the given attribute. None if the attribute is not replicated + """ + + res = self.search(expression="dn=%s" % dn, + scope=ldb.SCOPE_SUBTREE, + controls=["search_options:1:2"], + attrs=["replPropertyMetaData"]) + if len(res) == 0: + return None + + repl = ndr_unpack(drsblobs.replPropertyMetaDataBlob, + str(res[0]["replPropertyMetaData"])) + ctr = repl.ctr + if len(self.hash_oid_name.keys()) == 0: + self._populate_oid_attid() + for o in ctr.array: + # Search for Description + att_oid = self.get_oid_from_attid(o.attid) + if self.hash_oid_name.has_key(att_oid) and\ + att.lower() == self.hash_oid_name[att_oid].lower(): + return o.version + return None + + + def set_attribute_replmetadata_version(self, dn, att, value): + res = self.search(expression="dn=%s" % dn, + scope=ldb.SCOPE_SUBTREE, + controls=["search_options:1:2"], + attrs=["replPropertyMetaData"]) + if len(res) == 0: + return None + + repl = ndr_unpack(drsblobs.replPropertyMetaDataBlob, + str(res[0]["replPropertyMetaData"])) + ctr = repl.ctr + now = samba.unix2nttime(int(time.time())) + found = False + if len(self.hash_oid_name.keys()) == 0: + self._populate_oid_attid() + for o in ctr.array: + # Search for Description + att_oid = self.get_oid_from_attid(o.attid) + if self.hash_oid_name.has_key(att_oid) and\ + att.lower() == self.hash_oid_name[att_oid].lower(): + found = True + seq = self.sequence_number(ldb.SEQ_NEXT) + o.version = value + o.originating_change_time = now + o.originating_invocation_id = misc.GUID(self.get_invocation_id()) + o.originating_usn = seq + o.local_usn = seq + if found : + replBlob = ndr_pack(repl) + msg = ldb.Message() + msg.dn = res[0].dn + msg["replPropertyMetaData"] = ldb.MessageElement(replBlob, + ldb.FLAG_MOD_REPLACE, + "replPropertyMetaData") + self.modify(msg, ["local_oid:1.3.6.1.4.1.7165.4.3.14:0"]) + + def write_prefixes_from_schema(self): dsdb._dsdb_write_prefixes_from_schema_to_ldb(self) diff --git a/source4/scripting/python/samba/tests/dsdb.py b/source4/scripting/python/samba/tests/dsdb.py index c19dbaab47..4a50c96e25 100644 --- a/source4/scripting/python/samba/tests/dsdb.py +++ b/source4/scripting/python/samba/tests/dsdb.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -# Unix SMB/CIFS implementation. Tests for dsdb +# Unix SMB/CIFS implementation. Tests for dsdb # Copyright (C) Matthieu Patou <mat@matws.net> 2010 # # This program is free software; you can redistribute it and/or modify @@ -17,26 +17,117 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # -import samba.dsdb from samba.credentials import Credentials from samba.samdb import SamDB from samba.auth import system_session from testtools.testcase import TestCase +from samba.ndr import ndr_unpack, ndr_pack +from samba.dcerpc import drsblobs +import ldb import os +import samba class DsdbTests(TestCase): - def _baseprovpath(self): + + def setUp(self): + super(DsdbTests, self).setUp() + self.lp = samba.param.LoadParm() + self.lp.load(os.path.join(os.path.join(self.baseprovpath(), "etc"), "smb.conf")) + self.creds = Credentials() + self.creds.guess(self.lp) + self.session = system_session() + self.samdb = SamDB(os.path.join(self.baseprovpath(), "private", "sam.ldb"), + session_info=self.session, credentials=self.creds,lp=self.lp) + + + def baseprovpath(self): return os.path.join(os.environ['SELFTEST_PREFIX'], "dc") + def test_get_oid_from_attrid(self): - lp = samba.param.LoadParm() - lp.load(os.path.join(os.path.join(self._baseprovpath(), "etc"), "smb.conf")) - creds = Credentials() - creds.guess(lp) - session = system_session() - test_ldb = SamDB(os.path.join(self._baseprovpath(), "private", "sam.ldb"), - session_info=session, credentials=creds,lp=lp) - oid = test_ldb.get_oid_from_attid(591614) + oid = self.samdb.get_oid_from_attid(591614) self.assertEquals(oid, "1.2.840.113556.1.4.1790") + + def test_error_replpropertymetadata(self): + res = self.samdb.search(expression="cn=Administrator", + scope=ldb.SCOPE_SUBTREE, + attrs=["replPropertyMetaData"]) + repl = ndr_unpack(drsblobs.replPropertyMetaDataBlob, + str(res[0]["replPropertyMetaData"])) + ctr = repl.ctr + for o in ctr.array: + # Search for Description + if o.attid == 13: + old_version = o.version + o.version = o.version + 1 + replBlob = ndr_pack(repl) + msg = ldb.Message() + msg.dn = res[0].dn + msg["replPropertyMetaData"] = ldb.MessageElement(replBlob, ldb.FLAG_MOD_REPLACE, "replPropertyMetaData") + self.assertRaises(ldb.LdbError, self.samdb.modify, msg, ["local_oid:1.3.6.1.4.1.7165.4.3.14:0"]) + + def test_twoatt_replpropertymetadata(self): + res = self.samdb.search(expression="cn=Administrator", + scope=ldb.SCOPE_SUBTREE, + attrs=["replPropertyMetaData", "uSNChanged"]) + repl = ndr_unpack(drsblobs.replPropertyMetaDataBlob, + str(res[0]["replPropertyMetaData"])) + ctr = repl.ctr + for o in ctr.array: + # Search for Description + if o.attid == 13: + old_version = o.version + o.version = o.version + 1 + o.local_usn = long(str(res[0]["uSNChanged"])) + 1 + replBlob = ndr_pack(repl) + msg = ldb.Message() + msg.dn = res[0].dn + msg["replPropertyMetaData"] = ldb.MessageElement(replBlob, ldb.FLAG_MOD_REPLACE, "replPropertyMetaData") + msg["description"] = ldb.MessageElement("new val", ldb.FLAG_MOD_REPLACE, "description") + self.assertRaises(ldb.LdbError, self.samdb.modify, msg, ["local_oid:1.3.6.1.4.1.7165.4.3.14:0"]) + + def test_set_replpropertymetadata(self): + res = self.samdb.search(expression="cn=Administrator", + scope=ldb.SCOPE_SUBTREE, + attrs=["replPropertyMetaData", "uSNChanged"]) + repl = ndr_unpack(drsblobs.replPropertyMetaDataBlob, + str(res[0]["replPropertyMetaData"])) + ctr = repl.ctr + for o in ctr.array: + # Search for Description + if o.attid == 13: + old_version = o.version + o.version = o.version + 1 + o.local_usn = long(str(res[0]["uSNChanged"])) + 1 + o.originating_usn = long(str(res[0]["uSNChanged"])) + 1 + replBlob = ndr_pack(repl) + msg = ldb.Message() + msg.dn = res[0].dn + msg["replPropertyMetaData"] = ldb.MessageElement(replBlob, ldb.FLAG_MOD_REPLACE, "replPropertyMetaData") + self.samdb.modify(msg, ["local_oid:1.3.6.1.4.1.7165.4.3.14:0"]) + + def test_ok_get_attribute_from_attid(self): + self.assertEquals(self.samdb.get_attribute_from_attid(13), "description") + + def test_ko_get_attribute_from_attid(self): + self.assertEquals(self.samdb.get_attribute_from_attid(11979), None) + + def test_get_attribute_replmetadata_version(self): + res = self.samdb.search(expression="cn=Administrator", + scope=ldb.SCOPE_SUBTREE, + attrs=["dn"]) + self.assertEquals(len(res), 1) + dn = str(res[0].dn) + self.assertEqual(self.samdb.get_attribute_replmetadata_version(dn, "unicodePwd"), 1) + + def test_set_attribute_replmetadata_version(self): + res = self.samdb.search(expression="cn=Administrator", + scope=ldb.SCOPE_SUBTREE, + attrs=["dn"]) + self.assertEquals(len(res), 1) + dn = str(res[0].dn) + version = self.samdb.get_attribute_replmetadata_version(dn, "description") + self.samdb.set_attribute_replmetadata_version(dn, "description", version + 2) + self.assertEqual(self.samdb.get_attribute_replmetadata_version(dn, "description"), version + 2) diff --git a/source4/scripting/python/samba/tests/upgradeprovisionneeddc.py b/source4/scripting/python/samba/tests/upgradeprovisionneeddc.py index b32ffc6155..e30906fc6b 100644 --- a/source4/scripting/python/samba/tests/upgradeprovisionneeddc.py +++ b/source4/scripting/python/samba/tests/upgradeprovisionneeddc.py @@ -29,7 +29,8 @@ from samba.upgradehelpers import (get_paths, get_ldbs, find_provision_key_parameters, identic_rename, updateOEMInfo, getOEMInfo, update_gpo, delta_update_basesamdb, - search_constructed_attrs_stored) + search_constructed_attrs_stored, + increment_calculated_keyversion_number) from samba.tests import env_loadparm, TestCaseInTempDir from samba.tests.provision import create_dummy_secretsdb import ldb @@ -91,6 +92,29 @@ class UpgradeProvisionWithLdbTestCase(TestCaseInTempDir): ["msds-KeyVersionNumber"]) self.assertFalse(hashAtt.has_key("msds-KeyVersionNumber")) + def test_increment_calculated_keyversion_number(self): + dn = "CN=Administrator,CN=Users,%s" % self.names.rootdn + # We conctruct a simple hash for the user administrator + hash = {} + # And we want the version to be 140 + hash[dn.lower()] = 140 + + increment_calculated_keyversion_number(self.ldbs.sam, + self.names.rootdn, + hash) + self.assertEqual(self.ldbs.sam.get_attribute_replmetadata_version(dn, + "unicodePwd"), + 140) + # This function should not decrement the version + hash[dn.lower()] = 130 + + increment_calculated_keyversion_number(self.ldbs.sam, + self.names.rootdn, + hash) + self.assertEqual(self.ldbs.sam.get_attribute_replmetadata_version(dn, + "unicodePwd"), + 140) + def test_identic_rename(self): rootdn = "DC=samba,DC=example,DC=com" diff --git a/source4/scripting/python/samba/upgradehelpers.py b/source4/scripting/python/samba/upgradehelpers.py index 74a157d041..58106e0a70 100755 --- a/source4/scripting/python/samba/upgradehelpers.py +++ b/source4/scripting/python/samba/upgradehelpers.py @@ -35,8 +35,9 @@ import ldb from samba.provision import (ProvisionNames, provision_paths_from_lp, getpolicypath, set_gpo_acl, create_gpo_struct, FILL_FULL, provision, ProvisioningError, - setsysvolacl) + setsysvolacl, secretsdb_self_join) from samba.dcerpc import misc, security, xattr +from samba.dcerpc.misc import SEC_CHAN_BDC from samba.ndr import ndr_unpack from samba.samdb import SamDB @@ -703,14 +704,48 @@ def update_gpo(paths, samdb, names, lp, message, force=0): set_gpo_acl(paths.sysvol, names.dnsdomain, names.domainsid, names.domaindn, samdb, lp) except TypeError, e: - message(ERROR, "Unable to set ACLs on policies related objects, if not using posix:eadb, you must be root to do it") + message(ERROR, "Unable to set ACLs on policies related objects," + " if not using posix:eadb, you must be root to do it") if resetacls: try: setsysvolacl(samdb, paths.netlogon, paths.sysvol, names.wheel_gid, names.domainsid, names.dnsdomain, names.domaindn, lp) except TypeError, e: - message(ERROR, "Unable to set ACLs on sysvol share, if not using posix:eadb, you must be root to do it") + message(ERROR, "Unable to set ACLs on sysvol share, if not using" + "posix:eadb, you must be root to do it") + +def increment_calculated_keyversion_number(samdb, rootdn, hashDns): + """For a given hash associating dn and a number, this function will + update the replPropertyMetaData of each dn in the hash, so that the + calculated value of the msDs-KeyVersionNumber is equal or superior to the + one associated to the given dn. + + :param samdb: An SamDB object pointing to the sam + :param rootdn: The base DN where we want to start + :param hashDns: A hash with dn as key and number representing the + minimum value of msDs-KeyVersionNumber that we want to + have + """ + entry = samdb.search(expression='(objectClass=user)', + base=ldb.Dn(samdb,str(rootdn)), + scope=SCOPE_SUBTREE, attrs=["msDs-KeyVersionNumber"], + controls=["search_options:1:2"]) + done = 0 + if len(entry) == 0: + raise ProvisioningError("Unable to find msDs-KeyVersionNumber") + else: + for e in entry: + if hashDns.has_key(str(e.dn).lower()): + done = done + 1 + val = e.get("msDs-KeyVersionNumber") + if not val: + continue + version = int(str(hashDns[str(e.dn).lower()])) + if int(str(val)) < version: + samdb.set_attribute_replmetadata_version(str(e.dn), + "unicodePwd", + version) def delta_update_basesamdb(refsam, sam, creds, session, lp, message): """Update the provision container db: sam.ldb @@ -770,6 +805,48 @@ def construct_existor_expr(attrs): expr = "%s)"%expr return expr +def update_machine_account_password(samdb, secrets_ldb, names): + """Update (change) the password of the current DC both in the SAM db and in + secret one + + :param samdb: An LDB object related to the sam.ldb file of a given provision + :param secrets_ldb: An LDB object related to the secrets.ldb file of a given + provision + :param names: List of key provision parameters""" + + expression = "samAccountName=%s$" % names.netbiosname + secrets_msg = secrets_ldb.search(expression=expression, + attrs=["secureChannelType"]) + if int(secrets_msg[0]["secureChannelType"][0]) == SEC_CHAN_BDC: + res = samdb.search(expression=expression, attrs=[]) + assert(len(res) == 1) + + msg = ldb.Message(res[0].dn) + machinepass = samba.generate_random_password(128, 255) + msg["userPassword"] = ldb.MessageElement(machinepass, + ldb.FLAG_MOD_REPLACE, + "userPassword") + samdb.modify(msg) + + res = samdb.search(expression=("samAccountName=%s$" % names.netbiosname), + attrs=["msDs-keyVersionNumber"]) + assert(len(res) == 1) + kvno = int(str(res[0]["msDs-keyVersionNumber"])) + secChanType = int(secrets_msg[0]["secureChannelType"][0]) + + secretsdb_self_join(secrets_ldb, domain=names.domain, + realm=names.realm, + domainsid=names.domainsid, + dnsdomain=names.dnsdomain, + netbiosname=names.netbiosname, + machinepass=machinepass, + key_version_number=kvno, + secure_channel_type=secChanType) + else: + raise ProvisioningError("Unable to find a Secure Channel" + "of type SEC_CHAN_BDC") + + def search_constructed_attrs_stored(samdb, rootdn, attrs): """Search a given sam DB for calculated attributes that are still stored in the db. @@ -786,7 +863,7 @@ def search_constructed_attrs_stored(samdb, rootdn, attrs): expr = construct_existor_expr(attrs) if expr == "": return hashAtt - entry = samdb.search(expression=expr, base=ldb.Dn(samdb,str(rootdn)), + entry = samdb.search(expression=expr, base=ldb.Dn(samdb, str(rootdn)), scope=SCOPE_SUBTREE, attrs=attrs, controls=["search_options:1:2","bypassoperational:0"]) if len(entry) == 0: diff --git a/source4/selftest/tests.sh b/source4/selftest/tests.sh index c70eb877cf..52d1d3963e 100755 --- a/source4/selftest/tests.sh +++ b/source4/selftest/tests.sh @@ -363,11 +363,11 @@ planperltestsuite "selftest.samba4.pl" none $samba4srcdir/../selftest/test_samba # work correctly. plantestsuite "blackbox.ndrdump" none $samba4srcdir/librpc/tests/test_ndrdump.sh -plantestsuite "blackbox.net" dc $samba4srcdir/utils/tests/test_net.sh "\$SERVER" "\$USERNAME" "\$PASSWORD" "\$DOMAIN" -plantestsuite "blackbox.pkinit" dc $bbdir/test_pkinit.sh "\$SERVER" "\$USERNAME" "\$PASSWORD" "\$REALM" "\$DOMAIN" "$PREFIX" aes256-cts-hmac-sha1-96 $CONFIGURATION -plantestsuite "blackbox.kinit" dc $bbdir/test_kinit.sh "\$SERVER" "\$USERNAME" "\$PASSWORD" "\$REALM" "\$DOMAIN" "$PREFIX" aes256-cts-hmac-sha1-96 $CONFIGURATION -plantestsuite "blackbox.kinit" fl2000dc $bbdir/test_kinit.sh "\$SERVER" "\$USERNAME" "\$PASSWORD" "\$REALM" "\$DOMAIN" "$PREFIX" arcfour-hmac-md5 $CONFIGURATION -plantestsuite "blackbox.kinit" fl2008r2dc $bbdir/test_kinit.sh "\$SERVER" "\$USERNAME" "\$PASSWORD" "\$REALM" "\$DOMAIN" "$PREFIX" aes256-cts-hmac-sha1-96 $CONFIGURATION +plantestsuite "blackbox.net" dc:local $samba4srcdir/utils/tests/test_net.sh "\$SERVER" "\$USERNAME" "\$PASSWORD" "\$DOMAIN" +plantestsuite "blackbox.pkinit" dc:local $bbdir/test_pkinit.sh "\$SERVER" "\$USERNAME" "\$PASSWORD" "\$REALM" "\$DOMAIN" "$PREFIX" aes256-cts-hmac-sha1-96 $CONFIGURATION +plantestsuite "blackbox.kinit" dc:local $bbdir/test_kinit.sh "\$SERVER" "\$USERNAME" "\$PASSWORD" "\$REALM" "\$DOMAIN" "$PREFIX" aes256-cts-hmac-sha1-96 $CONFIGURATION +plantestsuite "blackbox.kinit" fl2000dc:local $bbdir/test_kinit.sh "\$SERVER" "\$USERNAME" "\$PASSWORD" "\$REALM" "\$DOMAIN" "$PREFIX" arcfour-hmac-md5 $CONFIGURATION +plantestsuite "blackbox.kinit" fl2008r2dc:local $bbdir/test_kinit.sh "\$SERVER" "\$USERNAME" "\$PASSWORD" "\$REALM" "\$DOMAIN" "$PREFIX" aes256-cts-hmac-sha1-96 $CONFIGURATION plantestsuite "blackbox.passwords" dc:local $bbdir/test_passwords.sh "\$SERVER" "\$USERNAME" "\$PASSWORD" "\$REALM" "\$DOMAIN" "$PREFIX" plantestsuite "blackbox.export.keytab" dc:local $bbdir/test_export_keytab.sh "\$SERVER" "\$USERNAME" "\$REALM" "\$DOMAIN" "$PREFIX" plantestsuite "blackbox.cifsdd" dc $samba4srcdir/client/tests/test_cifsdd.sh "\$SERVER" "\$USERNAME" "\$PASSWORD" "\$DOMAIN" @@ -378,6 +378,7 @@ plantestsuite "blackbox.masktest" dc $samba4srcdir/torture/tests/test_masktest.s plantestsuite "blackbox.gentest" dc $samba4srcdir/torture/tests/test_gentest.sh "\$SERVER" "\$USERNAME" "\$PASSWORD" "\$DOMAIN" "$PREFIX" plantestsuite "blackbox.wbinfo" dc:local $samba4srcdir/../nsswitch/tests/test_wbinfo.sh "\$DOMAIN" "\$USERNAME" "\$PASSWORD" "dc" plantestsuite "blackbox.wbinfo" member:local $samba4srcdir/../nsswitch/tests/test_wbinfo.sh "\$DOMAIN" "\$DC_USERNAME" "\$DC_PASSWORD" "member" +plantestsuite "blackbox.chgdcpass" dc $bbdir/test_chgdcpass.sh "\$SERVER" "LOCALDC\\\$" "\$REALM" "\$DOMAIN" "$PREFIX" aes256-cts-hmac-sha1-96 $SELFTEST_PREFIX/dc # Tests using the "Simple" NTVFS backend diff --git a/source4/setup/schema_samba4.ldif b/source4/setup/schema_samba4.ldif index 681aa96898..aecd273a18 100644 --- a/source4/setup/schema_samba4.ldif +++ b/source4/setup/schema_samba4.ldif @@ -186,6 +186,7 @@ #Allocated: DSDB_CONTROL_APPLY_LINKS 1.3.6.1.4.1.7165.4.3.11 #Allocated: DSDB_CONTROL_BYPASS_PASSWORD_HASH_OID 1.3.6.1.4.1.7165.4.3.12 #Allocated: LDB_CONTROL_BYPASSOPERATIONAL_OID 1.3.6.1.4.1.7165.4.3.13 +#Allocated: DSDB_CONTROL_CHANGEREPLMETADATA_OID 1.3.6.1.4.1.7165.4.3.14 # Extended 1.3.6.1.4.1.7165.4.4.x #Allocated: DSDB_EXTENDED_REPLICATED_OBJECTS_OID 1.3.6.1.4.1.7165.4.4.1 diff --git a/source4/utils/tests/test_net.sh b/source4/utils/tests/test_net.sh index e49989ff81..09394f41be 100755 --- a/source4/utils/tests/test_net.sh +++ b/source4/utils/tests/test_net.sh @@ -29,8 +29,6 @@ testit() { return $status } -testit "domain join" $VALGRIND $net join $DOMAIN $CONFIGURATION -W "$DOMAIN" -U"$USERNAME%$PASSWORD" $@ - testit "Test login with --machine-pass without kerberos" $VALGRIND $smbclient -c 'ls' $CONFIGURATION //$SERVER/tmp --machine-pass -k no testit "Test login with --machine-pass and kerberos" $VALGRIND $smbclient -c 'ls' $CONFIGURATION //$SERVER/tmp --machine-pass -k yes diff --git a/testprogs/blackbox/test_chgdcpass.sh b/testprogs/blackbox/test_chgdcpass.sh new file mode 100755 index 0000000000..7b89e5dcdd --- /dev/null +++ b/testprogs/blackbox/test_chgdcpass.sh @@ -0,0 +1,66 @@ +#!/bin/sh +# Blackbox tests for kinit and kerberos integration with smbclient etc +# Copyright (C) 2006-2007 Jelmer Vernooij <jelmer@samba.org> +# Copyright (C) 2006-2008 Andrew Bartlett <abartlet@samba.org> + +if [ $# -lt 4 ]; then +cat <<EOF +Usage: test_kinit.sh SERVER USERNAME REALM DOMAIN PREFIX +EOF +exit 1; +fi + +SERVER=$1 +USERNAME=$2 +REALM=$3 +DOMAIN=$4 +PREFIX=$5 +ENCTYPE=$6 +PROVDIR=$7 +shift 7 +failed=0 + +samba4bindir="$BUILDDIR/bin" +smbclient="$samba4bindir/smbclient$EXEEXT" +samba4kinit="$samba4bindir/samba4kinit$EXEEXT" +machineaccountccache="$BUILDDIR/scripting/bin/machineaccountccache" + +. `dirname $0`/subunit.sh + +test_smbclient() { + name="$1" + cmd="$2" + shift + shift + echo "test: $name" + $VALGRIND $smbclient $CONFIGURATION //$SERVER/tmp -c "$cmd" -W "$DOMAIN" $@ + status=$? + if [ x$status = x0 ]; then + echo "success: $name" + else + echo "failure: $name" + fi + return $status +} + +enctype="-e $ENCTYPE" + +KRB5CCNAME="$PREFIX/tmpccache" +export KRB5CCNAME +rm -f $KRB5CCNAME +testit "kinit with keytab" $samba4kinit $enctype -t $PROVDIR/private/secrets.keytab --use-keytab $USERNAME || failed=`expr $failed + 1` + +#This is important because it puts the ticket for the old KVNO and password into a local ccache +test_smbclient "Test login with kerberos ccache before password change" 'ls' -k yes || failed=`expr $failed + 1` +testit "change dc password" ./scripting/devel/chgtdcpass -s $PROVDIR/etc/smb.conf || failed=`expr $failed + 1` + +#This is important because it shows that the old ticket remains valid (as it must) for incoming connections after the DC password is changed +test_smbclient "Test login with kerberos ccache after password change" 'ls' -k yes || failed=`expr $failed + 1` + +#This confirms that the DC password is valid for a kinit too +testit "kinit with keytab" $samba4kinit $enctype -t $PROVDIR/private/secrets.keytab --use-keytab $USERNAME || failed=`expr $failed + 1` +test_smbclient "Test login with kerberos ccache with fresh kinit" 'ls' -k yes || failed=`expr $failed + 1` +rm -f $KRB5CCNAME + +rm -f $PREFIX/tmpccache tmpccfile tmppassfile tmpuserpassfile tmpuserccache tmpkpasswdscript +exit $failed diff --git a/testprogs/blackbox/test_kinit.sh b/testprogs/blackbox/test_kinit.sh index a32d167cfe..c748b4d056 100755 --- a/testprogs/blackbox/test_kinit.sh +++ b/testprogs/blackbox/test_kinit.sh @@ -68,7 +68,6 @@ testit "kinit renew ticket" $samba4kinit $enctype --request-pac -R test_smbclient "Test login with kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1` -testit "domain join with kerberos ccache" $VALGRIND $net join $DOMAIN $CONFIGURATION -W "$DOMAIN" -k yes $@ || failed=`expr $failed + 1` testit "check time with kerberos ccache" $VALGRIND $net $CONFIGURATION -W "$DOMAIN" -k yes $@ time $SERVER || failed=`expr $failed + 1` USERPASS=testPass@12% |