summaryrefslogtreecommitdiff
path: root/source4/librpc/rpc
diff options
context:
space:
mode:
authorbubulle <bubulle@alioth.debian.org>2011-11-12 13:00:54 +0000
committerbubulle <bubulle@alioth.debian.org>2011-11-12 13:00:54 +0000
commit6fba685eec3a1165ec0b82d72d3ae71e946a1404 (patch)
treef3c0543c8f9df4a22ed62e3bd99d9d7bc1054c14 /source4/librpc/rpc
parent77a7925c0509068d5cd2affd94a3996d0a86035a (diff)
downloadsamba-6fba685eec3a1165ec0b82d72d3ae71e946a1404.tar.gz
Merge upstream 3.6.1 source
git-svn-id: svn://svn.debian.org/svn/pkg-samba/trunk/samba@3972 fc4039ab-9d04-0410-8cac-899223bdd6b0
Diffstat (limited to 'source4/librpc/rpc')
-rw-r--r--source4/librpc/rpc/dcerpc.c940
-rw-r--r--source4/librpc/rpc/dcerpc.h204
-rw-r--r--source4/librpc/rpc/dcerpc.py2
-rw-r--r--source4/librpc/rpc/dcerpc_auth.c15
-rw-r--r--source4/librpc/rpc/dcerpc_connect.c36
-rw-r--r--source4/librpc/rpc/dcerpc_schannel.c53
-rw-r--r--source4/librpc/rpc/dcerpc_secondary.c3
-rw-r--r--source4/librpc/rpc/dcerpc_smb.c41
-rw-r--r--source4/librpc/rpc/dcerpc_smb2.c37
-rw-r--r--source4/librpc/rpc/dcerpc_sock.c72
-rw-r--r--source4/librpc/rpc/dcerpc_util.c96
-rw-r--r--source4/librpc/rpc/pyrpc.c241
-rw-r--r--source4/librpc/rpc/pyrpc.h45
-rw-r--r--source4/librpc/rpc/pyrpc_util.c310
-rw-r--r--source4/librpc/rpc/pyrpc_util.h58
15 files changed, 1278 insertions, 875 deletions
diff --git a/source4/librpc/rpc/dcerpc.c b/source4/librpc/rpc/dcerpc.c
index 87d44384ce..cc72866866 100644
--- a/source4/librpc/rpc/dcerpc.c
+++ b/source4/librpc/rpc/dcerpc.c
@@ -30,17 +30,83 @@
#include "libcli/composite/composite.h"
#include "auth/gensec/gensec.h"
#include "param/param.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "librpc/rpc/rpc_common.h"
+
+enum rpc_request_state {
+ RPC_REQUEST_QUEUED,
+ RPC_REQUEST_PENDING,
+ RPC_REQUEST_DONE
+};
+
+/*
+ handle for an async dcerpc request
+*/
+struct rpc_request {
+ struct rpc_request *next, *prev;
+ struct dcerpc_pipe *p;
+ NTSTATUS status;
+ uint32_t call_id;
+ enum rpc_request_state state;
+ DATA_BLOB payload;
+ uint32_t flags;
+ uint32_t fault_code;
+
+ /* this is used to distinguish bind and alter_context requests
+ from normal requests */
+ void (*recv_handler)(struct rpc_request *conn,
+ DATA_BLOB *blob, struct ncacn_packet *pkt);
+
+ const struct GUID *object;
+ uint16_t opnum;
+ DATA_BLOB request_data;
+ bool ignore_timeout;
+
+ /* use by the ndr level async recv call */
+ struct {
+ const struct ndr_interface_table *table;
+ uint32_t opnum;
+ void *struct_ptr;
+ TALLOC_CTX *mem_ctx;
+ } ndr;
+
+ struct {
+ void (*callback)(struct rpc_request *);
+ void *private_data;
+ } async;
+};
_PUBLIC_ NTSTATUS dcerpc_init(struct loadparm_context *lp_ctx)
{
return gensec_init(lp_ctx);
}
-static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status);
-static void dcerpc_ship_next_request(struct dcerpc_connection *c);
+static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status);
+static void dcerpc_ship_next_request(struct dcecli_connection *c);
+
+static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
+ const struct GUID *object,
+ uint16_t opnum,
+ DATA_BLOB *stub_data);
+static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *stub_data);
+static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB blob,
+ size_t struct_size,
+ ndr_push_flags_fn_t ndr_push,
+ ndr_pull_flags_fn_t ndr_pull);
+static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
+ struct ndr_pull *pull_in,
+ void *struct_ptr,
+ size_t struct_size,
+ ndr_push_flags_fn_t ndr_push,
+ ndr_pull_flags_fn_t ndr_pull,
+ ndr_print_function_t ndr_print);
/* destroy a dcerpc connection */
-static int dcerpc_connection_destructor(struct dcerpc_connection *conn)
+static int dcerpc_connection_destructor(struct dcecli_connection *conn)
{
if (conn->dead) {
conn->free_skipped = true;
@@ -54,19 +120,16 @@ static int dcerpc_connection_destructor(struct dcerpc_connection *conn)
/* initialise a dcerpc connection.
the event context is optional
*/
-static struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- struct smb_iconv_convenience *ic)
+static struct dcecli_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev)
{
- struct dcerpc_connection *c;
+ struct dcecli_connection *c;
- c = talloc_zero(mem_ctx, struct dcerpc_connection);
+ c = talloc_zero(mem_ctx, struct dcecli_connection);
if (!c) {
return NULL;
}
- c->iconv_convenience = talloc_reference(c, ic);
-
c->event_ctx = ev;
if (c->event_ctx == NULL) {
@@ -89,18 +152,424 @@ static struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
return c;
}
+struct dcerpc_bh_state {
+ struct dcerpc_pipe *p;
+};
+
+static bool dcerpc_bh_is_connected(struct dcerpc_binding_handle *h)
+{
+ struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
+ struct dcerpc_bh_state);
+
+ if (!hs->p) {
+ return false;
+ }
+
+ return true;
+}
+
+static uint32_t dcerpc_bh_set_timeout(struct dcerpc_binding_handle *h,
+ uint32_t timeout)
+{
+ struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
+ struct dcerpc_bh_state);
+ uint32_t old;
+
+ if (!hs->p) {
+ return DCERPC_REQUEST_TIMEOUT;
+ }
+
+ old = hs->p->request_timeout;
+ hs->p->request_timeout = timeout;
+
+ return old;
+}
+
+struct dcerpc_bh_raw_call_state {
+ struct dcerpc_binding_handle *h;
+ DATA_BLOB in_data;
+ DATA_BLOB out_data;
+ uint32_t out_flags;
+};
+
+static void dcerpc_bh_raw_call_done(struct rpc_request *subreq);
+
+static struct tevent_req *dcerpc_bh_raw_call_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct dcerpc_binding_handle *h,
+ const struct GUID *object,
+ uint32_t opnum,
+ uint32_t in_flags,
+ const uint8_t *in_data,
+ size_t in_length)
+{
+ struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
+ struct dcerpc_bh_state);
+ struct tevent_req *req;
+ struct dcerpc_bh_raw_call_state *state;
+ bool ok;
+ struct rpc_request *subreq;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct dcerpc_bh_raw_call_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->h = h;
+ state->in_data.data = discard_const_p(uint8_t, in_data);
+ state->in_data.length = in_length;
+
+ ok = dcerpc_bh_is_connected(h);
+ if (!ok) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_CONNECTION);
+ return tevent_req_post(req, ev);
+ }
+
+ subreq = dcerpc_request_send(hs->p,
+ object,
+ opnum,
+ &state->in_data);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ subreq->async.callback = dcerpc_bh_raw_call_done;
+ subreq->async.private_data = req;
+
+ return req;
+}
+
+static void dcerpc_bh_raw_call_done(struct rpc_request *subreq)
+{
+ struct tevent_req *req =
+ talloc_get_type_abort(subreq->async.private_data,
+ struct tevent_req);
+ struct dcerpc_bh_raw_call_state *state =
+ tevent_req_data(req,
+ struct dcerpc_bh_raw_call_state);
+ NTSTATUS status;
+ uint32_t fault_code;
+
+ state->out_flags = 0;
+ if (subreq->flags & DCERPC_PULL_BIGENDIAN) {
+ state->out_flags |= LIBNDR_FLAG_BIGENDIAN;
+ }
+
+ fault_code = subreq->fault_code;
+
+ status = dcerpc_request_recv(subreq, state, &state->out_data);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
+ status = dcerpc_fault_to_nt_status(fault_code);
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+static NTSTATUS dcerpc_bh_raw_call_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **out_data,
+ size_t *out_length,
+ uint32_t *out_flags)
+{
+ struct dcerpc_bh_raw_call_state *state =
+ tevent_req_data(req,
+ struct dcerpc_bh_raw_call_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ *out_data = talloc_move(mem_ctx, &state->out_data.data);
+ *out_length = state->out_data.length;
+ *out_flags = state->out_flags;
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+struct dcerpc_bh_disconnect_state {
+ uint8_t _dummy;
+};
+
+static struct tevent_req *dcerpc_bh_disconnect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct dcerpc_binding_handle *h)
+{
+ struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
+ struct dcerpc_bh_state);
+ struct tevent_req *req;
+ struct dcerpc_bh_disconnect_state *state;
+ bool ok;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct dcerpc_bh_disconnect_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ ok = dcerpc_bh_is_connected(h);
+ if (!ok) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_CONNECTION);
+ return tevent_req_post(req, ev);
+ }
+
+ /* TODO: do a real disconnect ... */
+ hs->p = NULL;
+
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
+}
+
+static NTSTATUS dcerpc_bh_disconnect_recv(struct tevent_req *req)
+{
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+static bool dcerpc_bh_push_bigendian(struct dcerpc_binding_handle *h)
+{
+ struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
+ struct dcerpc_bh_state);
+
+ if (hs->p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
+ return true;
+ }
+
+ return false;
+}
+
+static bool dcerpc_bh_ref_alloc(struct dcerpc_binding_handle *h)
+{
+ struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
+ struct dcerpc_bh_state);
+
+ if (hs->p->conn->flags & DCERPC_NDR_REF_ALLOC) {
+ return true;
+ }
+
+ return false;
+}
+
+static bool dcerpc_bh_use_ndr64(struct dcerpc_binding_handle *h)
+{
+ struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
+ struct dcerpc_bh_state);
+
+ if (hs->p->conn->flags & DCERPC_NDR64) {
+ return true;
+ }
+
+ return false;
+}
+
+static void dcerpc_bh_do_ndr_print(struct dcerpc_binding_handle *h,
+ int ndr_flags,
+ const void *_struct_ptr,
+ const struct ndr_interface_call *call)
+{
+ struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
+ struct dcerpc_bh_state);
+ void *struct_ptr = discard_const(_struct_ptr);
+
+ if (ndr_flags & NDR_IN) {
+ if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_IN) {
+ ndr_print_function_debug(call->ndr_print,
+ call->name,
+ ndr_flags,
+ struct_ptr);
+ }
+ }
+ if (ndr_flags & NDR_OUT) {
+ if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
+ ndr_print_function_debug(call->ndr_print,
+ call->name,
+ ndr_flags,
+ struct_ptr);
+ }
+ }
+}
+
+static void dcerpc_bh_ndr_push_failed(struct dcerpc_binding_handle *h,
+ NTSTATUS error,
+ const void *struct_ptr,
+ const struct ndr_interface_call *call)
+{
+ DEBUG(2,("Unable to ndr_push structure for %s - %s\n",
+ call->name, nt_errstr(error)));
+}
+
+static void dcerpc_bh_ndr_pull_failed(struct dcerpc_binding_handle *h,
+ NTSTATUS error,
+ const DATA_BLOB *blob,
+ const struct ndr_interface_call *call)
+{
+ struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
+ struct dcerpc_bh_state);
+ const uint32_t num_examples = 20;
+ uint32_t i;
+
+ DEBUG(2,("Unable to ndr_pull structure for %s - %s\n",
+ call->name, nt_errstr(error)));
+
+ if (hs->p->conn->packet_log_dir == NULL) return;
+
+ for (i=0;i<num_examples;i++) {
+ char *name=NULL;
+ asprintf(&name, "%s/rpclog/%s-out.%d",
+ hs->p->conn->packet_log_dir,
+ call->name, i);
+ if (name == NULL) {
+ return;
+ }
+ if (!file_exist(name)) {
+ if (file_save(name, blob->data, blob->length)) {
+ DEBUG(10,("Logged rpc packet to %s\n", name));
+ }
+ free(name);
+ break;
+ }
+ free(name);
+ }
+}
+
+static NTSTATUS dcerpc_bh_ndr_validate_in(struct dcerpc_binding_handle *h,
+ TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *blob,
+ const struct ndr_interface_call *call)
+{
+ struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
+ struct dcerpc_bh_state);
+
+ if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
+ NTSTATUS status;
+
+ status = dcerpc_ndr_validate_in(hs->p->conn,
+ mem_ctx,
+ *blob,
+ call->struct_size,
+ call->ndr_push,
+ call->ndr_pull);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("Validation [in] failed for %s - %s\n",
+ call->name, nt_errstr(status)));
+ return status;
+ }
+ }
+
+ DEBUG(10,("rpc request data:\n"));
+ dump_data(10, blob->data, blob->length);
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS dcerpc_bh_ndr_validate_out(struct dcerpc_binding_handle *h,
+ struct ndr_pull *pull_in,
+ const void *_struct_ptr,
+ const struct ndr_interface_call *call)
+{
+ struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
+ struct dcerpc_bh_state);
+ void *struct_ptr = discard_const(_struct_ptr);
+
+ DEBUG(10,("rpc reply data:\n"));
+ dump_data(10, pull_in->data, pull_in->data_size);
+
+ if (pull_in->offset != pull_in->data_size) {
+ DEBUG(0,("Warning! ignoring %u unread bytes at ofs:%u (0x%08X) for %s!\n",
+ pull_in->data_size - pull_in->offset,
+ pull_in->offset, pull_in->offset,
+ call->name));
+ /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
+ but it turns out that early versions of NT
+ (specifically NT3.1) add junk onto the end of rpc
+ packets, so if we want to interoperate at all with
+ those versions then we need to ignore this error */
+ }
+
+ if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
+ NTSTATUS status;
+
+ status = dcerpc_ndr_validate_out(hs->p->conn,
+ pull_in,
+ struct_ptr,
+ call->struct_size,
+ call->ndr_push,
+ call->ndr_pull,
+ call->ndr_print);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(2,("Validation [out] failed for %s - %s\n",
+ call->name, nt_errstr(status)));
+ return status;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+static const struct dcerpc_binding_handle_ops dcerpc_bh_ops = {
+ .name = "dcerpc",
+ .is_connected = dcerpc_bh_is_connected,
+ .set_timeout = dcerpc_bh_set_timeout,
+ .raw_call_send = dcerpc_bh_raw_call_send,
+ .raw_call_recv = dcerpc_bh_raw_call_recv,
+ .disconnect_send = dcerpc_bh_disconnect_send,
+ .disconnect_recv = dcerpc_bh_disconnect_recv,
+
+ .push_bigendian = dcerpc_bh_push_bigendian,
+ .ref_alloc = dcerpc_bh_ref_alloc,
+ .use_ndr64 = dcerpc_bh_use_ndr64,
+ .do_ndr_print = dcerpc_bh_do_ndr_print,
+ .ndr_push_failed = dcerpc_bh_ndr_push_failed,
+ .ndr_pull_failed = dcerpc_bh_ndr_pull_failed,
+ .ndr_validate_in = dcerpc_bh_ndr_validate_in,
+ .ndr_validate_out = dcerpc_bh_ndr_validate_out,
+};
+
/* initialise a dcerpc pipe. */
-_PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
- struct smb_iconv_convenience *ic)
+struct dcerpc_binding_handle *dcerpc_pipe_binding_handle(struct dcerpc_pipe *p)
+{
+ struct dcerpc_binding_handle *h;
+ struct dcerpc_bh_state *hs;
+
+ h = dcerpc_binding_handle_create(p,
+ &dcerpc_bh_ops,
+ NULL,
+ NULL, /* TODO */
+ &hs,
+ struct dcerpc_bh_state,
+ __location__);
+ if (h == NULL) {
+ return NULL;
+ }
+ hs->p = p;
+
+ dcerpc_binding_handle_set_sync_ev(h, p->conn->event_ctx);
+
+ return h;
+}
+
+/* initialise a dcerpc pipe. */
+_PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev)
{
struct dcerpc_pipe *p;
- p = talloc(mem_ctx, struct dcerpc_pipe);
+ p = talloc_zero(mem_ctx, struct dcerpc_pipe);
if (!p) {
return NULL;
}
- p->conn = dcerpc_connection_init(p, ev, ic);
+ p->conn = dcerpc_connection_init(p, ev);
if (p->conn == NULL) {
talloc_free(p);
return NULL;
@@ -118,6 +587,12 @@ _PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent
p->conn->flags |= DCERPC_DEBUG_PRINT_BOTH;
}
+ p->binding_handle = dcerpc_pipe_binding_handle(p);
+ if (p->binding_handle == NULL) {
+ talloc_free(p);
+ return NULL;
+ }
+
return p;
}
@@ -125,7 +600,7 @@ _PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent
/*
choose the next call id to use
*/
-static uint32_t next_call_id(struct dcerpc_connection *c)
+static uint32_t next_call_id(struct dcecli_connection *c)
{
c->call_id++;
if (c->call_id == 0) {
@@ -134,43 +609,13 @@ static uint32_t next_call_id(struct dcerpc_connection *c)
return c->call_id;
}
-/* we need to be able to get/set the fragment length without doing a full
- decode */
-void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
-{
- if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
- SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
- } else {
- RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
- }
-}
-
-uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
-{
- if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
- return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
- } else {
- return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
- }
-}
-
-void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
-{
- if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
- SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
- } else {
- RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
- }
-}
-
-
/**
setup for a ndr pull, also setting up any flags from the binding string
*/
-static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c,
+static struct ndr_pull *ndr_pull_init_flags(struct dcecli_connection *c,
DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
{
- struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx, c->iconv_convenience);
+ struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
if (ndr == NULL) return ndr;
@@ -193,7 +638,7 @@ static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c,
parse a data blob into a ncacn_packet structure. This handles both
input and output packets
*/
-static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
+static NTSTATUS ncacn_pull(struct dcecli_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
struct ncacn_packet *pkt)
{
struct ndr_pull *ndr;
@@ -219,15 +664,13 @@ static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_
/*
parse the authentication information on a dcerpc response packet
*/
-static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX *mem_ctx,
+static NTSTATUS ncacn_pull_request_auth(struct dcecli_connection *c, TALLOC_CTX *mem_ctx,
DATA_BLOB *raw_packet,
struct ncacn_packet *pkt)
{
- struct ndr_pull *ndr;
NTSTATUS status;
struct dcerpc_auth auth;
- DATA_BLOB auth_blob;
- enum ndr_err_code ndr_err;
+ uint32_t auth_length;
if (!c->security_state.auth_info ||
!c->security_state.generic_state) {
@@ -254,33 +697,12 @@ static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX
return NT_STATUS_INVALID_LEVEL;
}
- auth_blob.length = 8 + pkt->auth_length;
+ status = dcerpc_pull_auth_trailer(pkt, mem_ctx,
+ &pkt->u.response.stub_and_verifier,
+ &auth, &auth_length, false);
+ NT_STATUS_NOT_OK_RETURN(status);
- /* check for a valid length */
- if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
- return NT_STATUS_INFO_LENGTH_MISMATCH;
- }
-
- auth_blob.data =
- pkt->u.response.stub_and_verifier.data +
- pkt->u.response.stub_and_verifier.length - auth_blob.length;
- pkt->u.response.stub_and_verifier.length -= auth_blob.length;
-
- /* pull the auth structure */
- ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);
- if (!ndr) {
- return NT_STATUS_NO_MEMORY;
- }
-
- if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
- ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
- }
-
- ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
- return ndr_map_error2ntstatus(ndr_err);
- }
- status = NT_STATUS_OK;
+ pkt->u.response.stub_and_verifier.length -= auth_length;
/* check signature or unseal the packet */
switch (c->security_state.auth_info->auth_level) {
@@ -317,7 +739,7 @@ static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX
break;
}
- /* remove the indicated amount of paddiing */
+ /* remove the indicated amount of padding */
if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
return NT_STATUS_INFO_LENGTH_MISMATCH;
}
@@ -330,7 +752,7 @@ static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX
/*
push a dcerpc request packet into a blob, possibly signing it.
*/
-static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
+static NTSTATUS ncacn_push_request_sign(struct dcecli_connection *c,
DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
size_t sig_size,
struct ncacn_packet *pkt)
@@ -344,7 +766,7 @@ static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
/* non-signed packets are simpler */
if (sig_size == 0) {
- return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
+ return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
}
switch (c->security_state.auth_info->auth_level) {
@@ -354,16 +776,16 @@ static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
case DCERPC_AUTH_LEVEL_CONNECT:
/* TODO: let the gensec mech decide if it wants to generate a signature */
- return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
+ return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
case DCERPC_AUTH_LEVEL_NONE:
- return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
+ return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
default:
return NT_STATUS_INVALID_LEVEL;
}
- ndr = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
+ ndr = ndr_push_init_ctx(mem_ctx);
if (!ndr) {
return NT_STATUS_NO_MEMORY;
}
@@ -385,17 +807,18 @@ static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
return ndr_map_error2ntstatus(ndr_err);
}
- status = NT_STATUS_OK;
/* pad to 16 byte multiple in the payload portion of the
- packet. This matches what w2k3 does */
- c->security_state.auth_info->auth_pad_length =
+ packet. This matches what w2k3 does. Note that we can't use
+ ndr_push_align() as that is relative to the start of the
+ whole packet, whereas w2k8 wants it relative to the start
+ of the stub */
+ c->security_state.auth_info->auth_pad_length =
(16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
ndr_err = ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
return ndr_map_error2ntstatus(ndr_err);
}
- status = NT_STATUS_OK;
payload_length = pkt->u.request.stub_and_verifier.length +
c->security_state.auth_info->auth_pad_length;
@@ -408,7 +831,6 @@ static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
return ndr_map_error2ntstatus(ndr_err);
}
- status = NT_STATUS_OK;
/* extract the whole packet as a blob */
*blob = ndr_push_blob(ndr);
@@ -456,11 +878,17 @@ static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
}
if (creds2.length != sig_size) {
- DEBUG(0,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
- creds2.length, (uint32_t)sig_size,
- c->security_state.auth_info->auth_pad_length,
- pkt->u.request.stub_and_verifier.length));
- return NT_STATUS_INTERNAL_ERROR;
+ /* this means the sig_size estimate for the signature
+ was incorrect. We have to correct the packet
+ sizes. That means we could go over the max fragment
+ length */
+ DEBUG(3,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
+ (unsigned) creds2.length,
+ (unsigned) sig_size,
+ (unsigned) c->security_state.auth_info->auth_pad_length,
+ (unsigned) pkt->u.request.stub_and_verifier.length));
+ dcerpc_set_frag_length(blob, blob->length + creds2.length);
+ dcerpc_set_auth_length(blob, creds2.length);
}
if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
@@ -474,7 +902,7 @@ static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
/*
fill in the fixed values in a dcerpc header
*/
-static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
+static void init_ncacn_hdr(struct dcecli_connection *c, struct ncacn_packet *pkt)
{
pkt->rpc_vers = 5;
pkt->rpc_vers_minor = 0;
@@ -534,7 +962,7 @@ static int dcerpc_req_dequeue(struct rpc_request *req)
/*
mark the dcerpc connection dead. All outstanding requests get an error
*/
-static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
+static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status)
{
if (conn->dead) return;
@@ -565,7 +993,7 @@ static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS stat
forward declarations of the recv_data handlers for the types of
packets we need to handle
*/
-static void dcerpc_request_recv_data(struct dcerpc_connection *c,
+static void dcerpc_request_recv_data(struct dcecli_connection *c,
DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
/*
@@ -573,7 +1001,7 @@ static void dcerpc_request_recv_data(struct dcerpc_connection *c,
type of reply it is (normal request, bind or alter context) and
dispatch to the appropriate handler
*/
-static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NTSTATUS status)
+static void dcerpc_recv_data(struct dcecli_connection *conn, DATA_BLOB *blob, NTSTATUS status)
{
struct ncacn_packet pkt;
@@ -599,7 +1027,6 @@ static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NT
dcerpc_request_recv_data(conn, blob, &pkt);
}
-
/*
Receive a bind reply from the transport
*/
@@ -607,7 +1034,7 @@ static void dcerpc_bind_recv_handler(struct rpc_request *req,
DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
{
struct composite_context *c;
- struct dcerpc_connection *conn;
+ struct dcecli_connection *conn;
c = talloc_get_type(req->async.private_data, struct composite_context);
@@ -622,6 +1049,7 @@ static void dcerpc_bind_recv_handler(struct rpc_request *req,
if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
(pkt->u.bind_ack.num_results == 0) ||
(pkt->u.bind_ack.ctx_list[0].result != 0)) {
+ req->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
composite_error(c, NT_STATUS_NET_WRITE_FAULT);
return;
}
@@ -642,17 +1070,14 @@ static void dcerpc_bind_recv_handler(struct rpc_request *req,
}
/* the bind_ack might contain a reply set of credentials */
- if (conn->security_state.auth_info &&
- pkt->u.bind_ack.auth_info.length) {
- enum ndr_err_code ndr_err;
- ndr_err = ndr_pull_struct_blob(
- &pkt->u.bind_ack.auth_info, conn,
- NULL,
- conn->security_state.auth_info,
- (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
- c->status = ndr_map_error2ntstatus(ndr_err);
- if (!composite_is_ok(c)) return;
+ if (conn->security_state.auth_info && pkt->u.bind_ack.auth_info.length) {
+ NTSTATUS status;
+ uint32_t auth_length;
+ status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.bind_ack.auth_info,
+ conn->security_state.auth_info, &auth_length, true);
+ if (!NT_STATUS_IS_OK(status)) {
+ composite_error(c, status);
+ return;
}
}
@@ -731,7 +1156,7 @@ struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
pkt.u.bind.auth_info = data_blob(NULL, 0);
/* construct the NDR form of the packet */
- c->status = ncacn_push_auth(&blob, c, p->conn->iconv_convenience, &pkt,
+ c->status = ncacn_push_auth(&blob, c, &pkt,
p->conn->security_state.auth_info);
if (!composite_is_ok(c)) return c;
@@ -790,7 +1215,6 @@ NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
pkt.call_id = next_call_id(p->conn);
pkt.auth_length = 0;
- pkt.u.auth3._pad = 0;
pkt.u.auth3.auth_info = data_blob(NULL, 0);
if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
@@ -803,7 +1227,6 @@ NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
/* construct the NDR form of the packet */
status = ncacn_push_auth(&blob, mem_ctx,
- p->conn->iconv_convenience,
&pkt,
p->conn->security_state.auth_info);
if (!NT_STATUS_IS_OK(status)) {
@@ -826,11 +1249,11 @@ NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
This function frees the data
*/
-static void dcerpc_request_recv_data(struct dcerpc_connection *c,
+static void dcerpc_request_recv_data(struct dcecli_connection *c,
DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
{
struct rpc_request *req;
- uint_t length;
+ unsigned int length;
NTSTATUS status = NT_STATUS_OK;
/*
@@ -946,7 +1369,6 @@ req_done:
static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
const struct GUID *object,
uint16_t opnum,
- bool async,
DATA_BLOB *stub_data)
{
struct rpc_request *req;
@@ -965,7 +1387,6 @@ static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
req->payload = data_blob(NULL, 0);
req->flags = 0;
req->fault_code = 0;
- req->async_call = async;
req->ignore_timeout = false;
req->async.callback = NULL;
req->async.private_data = NULL;
@@ -1006,7 +1427,7 @@ static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
Send a request using the transport
*/
-static void dcerpc_ship_next_request(struct dcerpc_connection *c)
+static void dcerpc_ship_next_request(struct dcecli_connection *c)
{
struct rpc_request *req;
struct dcerpc_pipe *p;
@@ -1016,6 +1437,7 @@ static void dcerpc_ship_next_request(struct dcerpc_connection *c)
uint32_t remaining, chunk_size;
bool first_packet = true;
size_t sig_size = 0;
+ bool need_async = false;
req = c->request_queue;
if (req == NULL) {
@@ -1025,8 +1447,8 @@ static void dcerpc_ship_next_request(struct dcerpc_connection *c)
p = req->p;
stub_data = &req->request_data;
- if (!req->async_call && (c->pending != NULL)) {
- return;
+ if (c->pending) {
+ need_async = true;
}
DLIST_REMOVE(c->request_queue, req);
@@ -1063,7 +1485,7 @@ static void dcerpc_ship_next_request(struct dcerpc_connection *c)
if (req->object) {
pkt.u.request.object.object = *req->object;
pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
- chunk_size -= ndr_size_GUID(req->object,NULL,0);
+ chunk_size -= ndr_size_GUID(req->object,0);
}
/* we send a series of pdus without waiting for a reply */
@@ -1094,7 +1516,7 @@ static void dcerpc_ship_next_request(struct dcerpc_connection *c)
return;
}
- if (last_frag && !req->async_call) {
+ if (last_frag && !need_async) {
do_trans = true;
}
@@ -1132,9 +1554,9 @@ _PUBLIC_ struct tevent_context *dcerpc_event_context(struct dcerpc_pipe *p)
/*
perform the receive side of a async dcerpc request
*/
-NTSTATUS dcerpc_request_recv(struct rpc_request *req,
- TALLOC_CTX *mem_ctx,
- DATA_BLOB *stub_data)
+static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *stub_data)
{
NTSTATUS status;
@@ -1157,33 +1579,12 @@ NTSTATUS dcerpc_request_recv(struct rpc_request *req,
}
/*
- perform a full request/response pair on a dcerpc pipe
-*/
-NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
- struct GUID *object,
- uint16_t opnum,
- TALLOC_CTX *mem_ctx,
- DATA_BLOB *stub_data_in,
- DATA_BLOB *stub_data_out)
-{
- struct rpc_request *req;
-
- req = dcerpc_request_send(p, object, opnum, false, stub_data_in);
- if (req == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
-
- return dcerpc_request_recv(req, mem_ctx, stub_data_out);
-}
-
-
-/*
this is a paranoid NDR validator. For every packet we push onto the wire
we pull it back again, then push it again. Then we compare the raw NDR data
for that to the NDR we initially generated. If they don't match then we know
we must have a bug in either the pull or push side of our code
*/
-static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
+static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
TALLOC_CTX *mem_ctx,
DATA_BLOB blob,
size_t struct_size,
@@ -1207,6 +1608,14 @@ static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
}
pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ if (c->flags & DCERPC_PUSH_BIGENDIAN) {
+ pull->flags |= LIBNDR_FLAG_BIGENDIAN;
+ }
+
+ if (c->flags & DCERPC_NDR64) {
+ pull->flags |= LIBNDR_FLAG_NDR64;
+ }
+
ndr_err = ndr_pull(pull, NDR_IN, st);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
@@ -1216,11 +1625,19 @@ static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
return ndr_map_error2ntstatus(ndr_err);
}
- push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
+ push = ndr_push_init_ctx(mem_ctx);
if (!push) {
return NT_STATUS_NO_MEMORY;
}
+ if (c->flags & DCERPC_PUSH_BIGENDIAN) {
+ push->flags |= LIBNDR_FLAG_BIGENDIAN;
+ }
+
+ if (c->flags & DCERPC_NDR64) {
+ push->flags |= LIBNDR_FLAG_NDR64;
+ }
+
ndr_err = ndr_push(push, NDR_IN, st);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
@@ -1252,7 +1669,7 @@ static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
initially generated. If they don't match then we know we must have a
bug in either the pull or push side of our code
*/
-static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
+static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
struct ndr_pull *pull_in,
void *struct_ptr,
size_t struct_size,
@@ -1274,7 +1691,7 @@ static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
}
memcpy(st, struct_ptr, struct_size);
- push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
+ push = ndr_push_init_ctx(mem_ctx);
if (!push) {
return NT_STATUS_NO_MEMORY;
}
@@ -1305,7 +1722,7 @@ static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
return ndr_map_error2ntstatus(ndr_err);
}
- push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
+ push = ndr_push_init_ctx(mem_ctx);
if (!push) {
return NT_STATUS_NO_MEMORY;
}
@@ -1355,195 +1772,6 @@ static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
return NT_STATUS_OK;
}
-
-/**
- send a rpc request given a dcerpc_call structure
- */
-struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
- const struct GUID *object,
- const struct ndr_interface_table *table,
- uint32_t opnum,
- bool async,
- TALLOC_CTX *mem_ctx,
- void *r)
-{
- const struct ndr_interface_call *call;
- struct ndr_push *push;
- NTSTATUS status;
- DATA_BLOB request;
- struct rpc_request *req;
- enum ndr_err_code ndr_err;
-
- call = &table->calls[opnum];
-
- /* setup for a ndr_push_* call */
- push = ndr_push_init_ctx(mem_ctx, p->conn->iconv_convenience);
- if (!push) {
- return NULL;
- }
-
- if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
- push->flags |= LIBNDR_FLAG_BIGENDIAN;
- }
-
- if (p->conn->flags & DCERPC_NDR64) {
- push->flags |= LIBNDR_FLAG_NDR64;
- }
-
- /* push the structure into a blob */
- ndr_err = call->ndr_push(push, NDR_IN, r);
- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
- status = ndr_map_error2ntstatus(ndr_err);
- DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
- nt_errstr(status)));
- talloc_free(push);
- return NULL;
- }
-
- /* retrieve the blob */
- request = ndr_push_blob(push);
-
- if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
- status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
- call->ndr_push, call->ndr_pull);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
- nt_errstr(status)));
- talloc_free(push);
- return NULL;
- }
- }
-
- DEBUG(10,("rpc request data:\n"));
- dump_data(10, request.data, request.length);
-
- /* make the actual dcerpc request */
- req = dcerpc_request_send(p, object, opnum, async, &request);
-
- if (req != NULL) {
- req->ndr.table = table;
- req->ndr.opnum = opnum;
- req->ndr.struct_ptr = r;
- req->ndr.mem_ctx = mem_ctx;
- }
-
- talloc_free(push);
-
- return req;
-}
-
-/*
- receive the answer from a dcerpc_ndr_request_send()
-*/
-_PUBLIC_ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
-{
- struct dcerpc_pipe *p = req->p;
- NTSTATUS status;
- DATA_BLOB response;
- struct ndr_pull *pull;
- uint_t flags;
- TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
- void *r = req->ndr.struct_ptr;
- uint32_t opnum = req->ndr.opnum;
- const struct ndr_interface_table *table = req->ndr.table;
- const struct ndr_interface_call *call = &table->calls[opnum];
- enum ndr_err_code ndr_err;
-
- /* make sure the recv code doesn't free the request, as we
- need to grab the flags element before it is freed */
- if (talloc_reference(p, req) == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
-
- status = dcerpc_request_recv(req, mem_ctx, &response);
- if (!NT_STATUS_IS_OK(status)) {
- talloc_unlink(p, req);
- return status;
- }
-
- flags = req->flags;
-
- /* prepare for ndr_pull_* */
- pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
- if (!pull) {
- talloc_unlink(p, req);
- return NT_STATUS_NO_MEMORY;
- }
-
- if (pull->data) {
- pull->data = talloc_steal(pull, pull->data);
- }
- talloc_unlink(p, req);
-
- if (flags & DCERPC_PULL_BIGENDIAN) {
- pull->flags |= LIBNDR_FLAG_BIGENDIAN;
- }
-
- DEBUG(10,("rpc reply data:\n"));
- dump_data(10, pull->data, pull->data_size);
-
- /* pull the structure from the blob */
- ndr_err = call->ndr_pull(pull, NDR_OUT, r);
- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
- status = ndr_map_error2ntstatus(ndr_err);
- dcerpc_log_packet(p->conn->packet_log_dir,
- table, opnum, NDR_OUT,
- &response);
- return status;
- }
-
- if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
- status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
- call->ndr_push, call->ndr_pull,
- call->ndr_print);
- if (!NT_STATUS_IS_OK(status)) {
- dcerpc_log_packet(p->conn->packet_log_dir,
- table, opnum, NDR_OUT,
- &response);
- return status;
- }
- }
-
- if (pull->offset != pull->data_size) {
- DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
- pull->data_size - pull->offset));
- /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
- but it turns out that early versions of NT
- (specifically NT3.1) add junk onto the end of rpc
- packets, so if we want to interoperate at all with
- those versions then we need to ignore this error */
- }
-
- /* TODO: make pull context independent from the output mem_ctx and free the pull context */
-
- return NT_STATUS_OK;
-}
-
-
-/*
- a useful helper function for synchronous rpc requests
-
- this can be used when you have ndr push/pull functions in the
- standard format
-*/
-_PUBLIC_ NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
- const struct GUID *object,
- const struct ndr_interface_table *table,
- uint32_t opnum,
- TALLOC_CTX *mem_ctx,
- void *r)
-{
- struct rpc_request *req;
-
- req = dcerpc_ndr_request_send(p, object, table, opnum, false, mem_ctx, r);
- if (req == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
-
- return dcerpc_ndr_request_recv(req);
-}
-
-
/*
a useful function for retrieving the server name we connected to
*/
@@ -1562,7 +1790,7 @@ _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
/*
get the dcerpc auth_level for a open connection
*/
-uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
+uint32_t dcerpc_auth_level(struct dcecli_connection *c)
{
uint8_t auth_level;
@@ -1599,9 +1827,17 @@ static void dcerpc_alter_recv_handler(struct rpc_request *req,
return;
}
+ if (pkt->ptype == DCERPC_PKT_FAULT) {
+ DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
+ recv_pipe->last_fault_code = pkt->u.fault.status;
+ composite_error(c, NT_STATUS_NET_WRITE_FAULT);
+ return;
+ }
+
if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
pkt->u.alter_resp.num_results == 0 ||
pkt->u.alter_resp.ctx_list[0].result != 0) {
+ recv_pipe->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
composite_error(c, NT_STATUS_NET_WRITE_FAULT);
return;
}
@@ -1609,15 +1845,14 @@ static void dcerpc_alter_recv_handler(struct rpc_request *req,
/* the alter_resp might contain a reply set of credentials */
if (recv_pipe->conn->security_state.auth_info &&
pkt->u.alter_resp.auth_info.length) {
- enum ndr_err_code ndr_err;
- ndr_err = ndr_pull_struct_blob(
- &pkt->u.alter_resp.auth_info, recv_pipe,
- NULL,
- recv_pipe->conn->security_state.auth_info,
- (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
- c->status = ndr_map_error2ntstatus(ndr_err);
- if (!composite_is_ok(c)) return;
+ struct dcecli_connection *conn = recv_pipe->conn;
+ NTSTATUS status;
+ uint32_t auth_length;
+ status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.alter_resp.auth_info,
+ conn->security_state.auth_info, &auth_length, true);
+ if (!NT_STATUS_IS_OK(status)) {
+ composite_error(c, status);
+ return;
}
}
@@ -1673,7 +1908,7 @@ struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
pkt.u.alter.auth_info = data_blob(NULL, 0);
/* construct the NDR form of the packet */
- c->status = ncacn_push_auth(&blob, mem_ctx, p->conn->iconv_convenience, &pkt,
+ c->status = ncacn_push_auth(&blob, mem_ctx, &pkt,
p->conn->security_state.auth_info);
if (!composite_is_ok(c)) return c;
@@ -1724,3 +1959,4 @@ _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
return dcerpc_alter_context_recv(creq);
}
+
diff --git a/source4/librpc/rpc/dcerpc.h b/source4/librpc/rpc/dcerpc.h
index b539fc2620..5ca6246343 100644
--- a/source4/librpc/rpc/dcerpc.h
+++ b/source4/librpc/rpc/dcerpc.h
@@ -24,43 +24,44 @@
* If you remove any functions or change their signature, update
* the so version number. */
-#ifndef __DCERPC_H__
-#define __DCERPC_H__
+#ifndef __S4_DCERPC_H__
+#define __S4_DCERPC_H__
#include "../lib/util/data_blob.h"
#include "librpc/gen_ndr/dcerpc.h"
#include "../librpc/ndr/libndr.h"
+#include "../librpc/rpc/rpc_common.h"
-enum dcerpc_transport_t {
- NCA_UNKNOWN, NCACN_NP, NCACN_IP_TCP, NCACN_IP_UDP, NCACN_VNS_IPC,
- NCACN_VNS_SPP, NCACN_AT_DSP, NCADG_AT_DDP, NCALRPC, NCACN_UNIX_STREAM,
- NCADG_UNIX_DGRAM, NCACN_HTTP, NCADG_IPX, NCACN_SPX };
+struct tevent_context;
+struct tevent_req;
+struct dcerpc_binding_handle;
+struct tstream_context;
/*
this defines a generic security context for signed/sealed dcerpc pipes.
*/
-struct dcerpc_connection;
+struct dcecli_connection;
struct gensec_settings;
-struct dcerpc_security {
+struct dcecli_security {
struct dcerpc_auth *auth_info;
struct gensec_security *generic_state;
/* get the session key */
- NTSTATUS (*session_key)(struct dcerpc_connection *, DATA_BLOB *);
+ NTSTATUS (*session_key)(struct dcecli_connection *, DATA_BLOB *);
};
/*
this holds the information that is not specific to a particular rpc context_id
*/
-struct dcerpc_connection {
+struct rpc_request;
+struct dcecli_connection {
uint32_t call_id;
uint32_t srv_max_xmit_frag;
uint32_t srv_max_recv_frag;
uint32_t flags;
- struct dcerpc_security security_state;
+ struct dcecli_security security_state;
const char *binding_string;
struct tevent_context *event_ctx;
- struct smb_iconv_convenience *iconv_convenience;
/** Directory in which to save ndrdump-parseable files */
const char *packet_log_dir;
@@ -72,21 +73,21 @@ struct dcerpc_connection {
enum dcerpc_transport_t transport;
void *private_data;
- NTSTATUS (*shutdown_pipe)(struct dcerpc_connection *, NTSTATUS status);
+ NTSTATUS (*shutdown_pipe)(struct dcecli_connection *, NTSTATUS status);
- const char *(*peer_name)(struct dcerpc_connection *);
+ const char *(*peer_name)(struct dcecli_connection *);
- const char *(*target_hostname)(struct dcerpc_connection *);
+ const char *(*target_hostname)(struct dcecli_connection *);
/* send a request to the server */
- NTSTATUS (*send_request)(struct dcerpc_connection *, DATA_BLOB *, bool trigger_read);
+ NTSTATUS (*send_request)(struct dcecli_connection *, DATA_BLOB *, bool trigger_read);
/* send a read request to the server */
- NTSTATUS (*send_read)(struct dcerpc_connection *);
+ NTSTATUS (*send_read)(struct dcecli_connection *);
/* a callback to the dcerpc code when a full fragment
has been received */
- void (*recv_data)(struct dcerpc_connection *, DATA_BLOB *, NTSTATUS status);
+ void (*recv_data)(struct dcecli_connection *, DATA_BLOB *, NTSTATUS status);
} transport;
/* Requests that have been sent, waiting for a reply */
@@ -103,6 +104,8 @@ struct dcerpc_connection {
this encapsulates a full dcerpc client side pipe
*/
struct dcerpc_pipe {
+ struct dcerpc_binding_handle *binding_handle;
+
uint32_t context_id;
uint32_t assoc_group_id;
@@ -110,7 +113,7 @@ struct dcerpc_pipe {
struct ndr_syntax_id syntax;
struct ndr_syntax_id transfer_syntax;
- struct dcerpc_connection *conn;
+ struct dcecli_connection *conn;
struct dcerpc_binding *binding;
/** the last fault code from a DCERPC fault */
@@ -124,70 +127,6 @@ struct dcerpc_pipe {
#define DCERPC_REQUEST_TIMEOUT 60
-/* dcerpc pipe flags */
-#define DCERPC_DEBUG_PRINT_IN (1<<0)
-#define DCERPC_DEBUG_PRINT_OUT (1<<1)
-#define DCERPC_DEBUG_PRINT_BOTH (DCERPC_DEBUG_PRINT_IN | DCERPC_DEBUG_PRINT_OUT)
-
-#define DCERPC_DEBUG_VALIDATE_IN (1<<2)
-#define DCERPC_DEBUG_VALIDATE_OUT (1<<3)
-#define DCERPC_DEBUG_VALIDATE_BOTH (DCERPC_DEBUG_VALIDATE_IN | DCERPC_DEBUG_VALIDATE_OUT)
-
-#define DCERPC_CONNECT (1<<4)
-#define DCERPC_SIGN (1<<5)
-#define DCERPC_SEAL (1<<6)
-
-#define DCERPC_PUSH_BIGENDIAN (1<<7)
-#define DCERPC_PULL_BIGENDIAN (1<<8)
-
-#define DCERPC_SCHANNEL (1<<9)
-
-#define DCERPC_ANON_FALLBACK (1<<10)
-
-/* use a 128 bit session key */
-#define DCERPC_SCHANNEL_128 (1<<12)
-
-/* check incoming pad bytes */
-#define DCERPC_DEBUG_PAD_CHECK (1<<13)
-
-/* set LIBNDR_FLAG_REF_ALLOC flag when decoding NDR */
-#define DCERPC_NDR_REF_ALLOC (1<<14)
-
-#define DCERPC_AUTH_OPTIONS (DCERPC_SEAL|DCERPC_SIGN|DCERPC_SCHANNEL|DCERPC_AUTH_SPNEGO|DCERPC_AUTH_KRB5|DCERPC_AUTH_NTLM)
-
-/* select spnego auth */
-#define DCERPC_AUTH_SPNEGO (1<<15)
-
-/* select krb5 auth */
-#define DCERPC_AUTH_KRB5 (1<<16)
-
-#define DCERPC_SMB2 (1<<17)
-
-/* select NTLM auth */
-#define DCERPC_AUTH_NTLM (1<<18)
-
-/* this triggers the DCERPC_PFC_FLAG_CONC_MPX flag in the bind request */
-#define DCERPC_CONCURRENT_MULTIPLEX (1<<19)
-
-/* this triggers the DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN flag in the bind request */
-#define DCERPC_HEADER_SIGNING (1<<20)
-
-/* use NDR64 transport */
-#define DCERPC_NDR64 (1<<21)
-
-/* this describes a binding to a particular transport/pipe */
-struct dcerpc_binding {
- enum dcerpc_transport_t transport;
- struct ndr_syntax_id object;
- const char *host;
- const char *target_hostname;
- const char *endpoint;
- const char **options;
- uint32_t flags;
- uint32_t assoc_group_id;
-};
-
-
struct dcerpc_pipe_connect {
struct dcerpc_pipe *pipe;
struct dcerpc_binding *binding;
@@ -198,50 +137,6 @@ struct dcerpc_pipe_connect {
};
-enum rpc_request_state {
- RPC_REQUEST_QUEUED,
- RPC_REQUEST_PENDING,
- RPC_REQUEST_DONE
-};
-
-/*
- handle for an async dcerpc request
-*/
-struct rpc_request {
- struct rpc_request *next, *prev;
- struct dcerpc_pipe *p;
- NTSTATUS status;
- uint32_t call_id;
- enum rpc_request_state state;
- DATA_BLOB payload;
- uint32_t flags;
- uint32_t fault_code;
-
- /* this is used to distinguish bind and alter_context requests
- from normal requests */
- void (*recv_handler)(struct rpc_request *conn,
- DATA_BLOB *blob, struct ncacn_packet *pkt);
-
- const struct GUID *object;
- uint16_t opnum;
- DATA_BLOB request_data;
- bool async_call;
- bool ignore_timeout;
-
- /* use by the ndr level async recv call */
- struct {
- const struct ndr_interface_table *table;
- uint32_t opnum;
- void *struct_ptr;
- TALLOC_CTX *mem_ctx;
- } ndr;
-
- struct {
- void (*callback)(struct rpc_request *);
- void *private_data;
- } async;
-};
-
struct epm_tower;
struct epm_floor;
@@ -256,17 +151,8 @@ NTSTATUS dcerpc_pipe_connect(TALLOC_CTX *parent_ctx,
struct cli_credentials *credentials,
struct tevent_context *ev,
struct loadparm_context *lp_ctx);
-NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req);
-struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
- const struct GUID *object,
- const struct ndr_interface_table *table,
- uint32_t opnum,
- bool async,
- TALLOC_CTX *mem_ctx,
- void *r);
const char *dcerpc_server_name(struct dcerpc_pipe *p);
-struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
- struct smb_iconv_convenience *ic);
+struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev);
NTSTATUS dcerpc_pipe_open_smb(struct dcerpc_pipe *p,
struct smbcli_tree *tree,
const char *pipe_name);
@@ -277,7 +163,6 @@ NTSTATUS dcerpc_fetch_session_key(struct dcerpc_pipe *p,
struct composite_context;
NTSTATUS dcerpc_secondary_connection_recv(struct composite_context *c,
struct dcerpc_pipe **p2);
-NTSTATUS dcerpc_parse_binding(TALLOC_CTX *mem_ctx, const char *s, struct dcerpc_binding **b_out);
struct composite_context* dcerpc_pipe_connect_b_send(TALLOC_CTX *parent_ctx,
struct dcerpc_binding *binding,
@@ -296,7 +181,6 @@ NTSTATUS dcerpc_pipe_connect_b(TALLOC_CTX *parent_ctx,
struct cli_credentials *credentials,
struct tevent_context *ev,
struct loadparm_context *lp_ctx);
-const char *dcerpc_errstr(TALLOC_CTX *mem_ctx, uint32_t fault_code);
NTSTATUS dcerpc_pipe_auth(TALLOC_CTX *mem_ctx,
struct dcerpc_pipe **p,
@@ -304,7 +188,6 @@ NTSTATUS dcerpc_pipe_auth(TALLOC_CTX *mem_ctx,
const struct ndr_interface_table *table,
struct cli_credentials *credentials,
struct loadparm_context *lp_ctx);
-char *dcerpc_binding_string(TALLOC_CTX *mem_ctx, const struct dcerpc_binding *b);
NTSTATUS dcerpc_secondary_connection(struct dcerpc_pipe *p,
struct dcerpc_pipe **p2,
struct dcerpc_binding *b);
@@ -316,8 +199,8 @@ NTSTATUS dcerpc_bind_auth_schannel(TALLOC_CTX *tmp_ctx,
uint8_t auth_level);
struct tevent_context *dcerpc_event_context(struct dcerpc_pipe *p);
NTSTATUS dcerpc_init(struct loadparm_context *lp_ctx);
-struct smbcli_tree *dcerpc_smb_tree(struct dcerpc_connection *c);
-uint16_t dcerpc_smb_fnum(struct dcerpc_connection *c);
+struct smbcli_tree *dcerpc_smb_tree(struct dcecli_connection *c);
+uint16_t dcerpc_smb_fnum(struct dcecli_connection *c);
NTSTATUS dcerpc_secondary_context(struct dcerpc_pipe *p,
struct dcerpc_pipe **pp2,
const struct ndr_interface_table *table);
@@ -356,40 +239,13 @@ NTSTATUS dcerpc_secondary_auth_connection_recv(struct composite_context *c,
struct composite_context* dcerpc_secondary_connection_send(struct dcerpc_pipe *p,
struct dcerpc_binding *b);
void dcerpc_log_packet(const char *lockdir,
- const struct ndr_interface_table *ndr,
- uint32_t opnum, uint32_t flags,
- DATA_BLOB *pkt);
-NTSTATUS dcerpc_binding_build_tower(TALLOC_CTX *mem_ctx,
- const struct dcerpc_binding *binding,
- struct epm_tower *tower);
-
-NTSTATUS dcerpc_floor_get_lhs_data(const struct epm_floor *epm_floor, struct ndr_syntax_id *syntax);
-
-enum dcerpc_transport_t dcerpc_transport_by_tower(const struct epm_tower *tower);
-const char *derpc_transport_string_by_transport(enum dcerpc_transport_t t);
-
-NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
- const struct GUID *object,
- const struct ndr_interface_table *table,
- uint32_t opnum,
- TALLOC_CTX *mem_ctx,
- void *r);
-
-NTSTATUS dcerpc_binding_from_tower(TALLOC_CTX *mem_ctx,
- struct epm_tower *tower,
- struct dcerpc_binding **b_out);
-
-NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
- struct GUID *object,
- uint16_t opnum,
- TALLOC_CTX *mem_ctx,
- DATA_BLOB *stub_data_in,
- DATA_BLOB *stub_data_out);
-
-typedef NTSTATUS (*dcerpc_call_fn) (struct dcerpc_pipe *, TALLOC_CTX *, void *);
+ const struct ndr_interface_table *ndr,
+ uint32_t opnum, uint32_t flags,
+ const DATA_BLOB *pkt);
+
enum dcerpc_transport_t dcerpc_transport_by_endpoint_protocol(int prot);
const char *dcerpc_floor_get_rhs_data(TALLOC_CTX *mem_ctx, struct epm_floor *epm_floor);
-#endif /* __DCERPC_H__ */
+#endif /* __S4_DCERPC_H__ */
diff --git a/source4/librpc/rpc/dcerpc.py b/source4/librpc/rpc/dcerpc.py
index 1a76ecca8e..7ce423beba 100644
--- a/source4/librpc/rpc/dcerpc.py
+++ b/source4/librpc/rpc/dcerpc.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
# Unix SMB/CIFS implementation.
# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008
diff --git a/source4/librpc/rpc/dcerpc_auth.c b/source4/librpc/rpc/dcerpc_auth.c
index bca7a8d186..fb2f4fb680 100644
--- a/source4/librpc/rpc/dcerpc_auth.c
+++ b/source4/librpc/rpc/dcerpc_auth.c
@@ -114,7 +114,7 @@ static void bind_auth_recv_alter(struct composite_context *creq);
static void bind_auth_next_step(struct composite_context *c)
{
struct bind_auth_state *state;
- struct dcerpc_security *sec;
+ struct dcecli_security *sec;
struct composite_context *creq;
bool more_processing = false;
@@ -233,7 +233,7 @@ struct composite_context *dcerpc_bind_auth_send(TALLOC_CTX *mem_ctx,
{
struct composite_context *c, *creq;
struct bind_auth_state *state;
- struct dcerpc_security *sec;
+ struct dcecli_security *sec;
struct ndr_syntax_id syntax, transfer_syntax;
@@ -292,6 +292,17 @@ struct composite_context *dcerpc_bind_auth_send(TALLOC_CTX *mem_ctx,
}
}
+ if (p->binding && p->binding->target_principal) {
+ c->status = gensec_set_target_principal(sec->generic_state,
+ p->binding->target_principal);
+ if (!NT_STATUS_IS_OK(c->status)) {
+ DEBUG(1, ("Failed to set GENSEC target principal to %s: %s\n",
+ p->binding->target_principal, nt_errstr(c->status)));
+ composite_error(c, c->status);
+ return c;
+ }
+ }
+
c->status = gensec_start_mech_by_authtype(sec->generic_state,
auth_type, auth_level);
if (!NT_STATUS_IS_OK(c->status)) {
diff --git a/source4/librpc/rpc/dcerpc_connect.c b/source4/librpc/rpc/dcerpc_connect.c
index 1b1f039004..842ef43206 100644
--- a/source4/librpc/rpc/dcerpc_connect.c
+++ b/source4/librpc/rpc/dcerpc_connect.c
@@ -111,20 +111,19 @@ static struct composite_context *dcerpc_pipe_connect_ncacn_np_smb_send(TALLOC_CT
/* prepare smb connection parameters: we're connecting to IPC$ share on
remote rpc server */
conn->in.dest_host = s->io.binding->host;
- conn->in.dest_ports = lp_smb_ports(lp_ctx);
+ conn->in.dest_ports = lpcfg_smb_ports(lp_ctx);
if (s->io.binding->target_hostname == NULL)
conn->in.called_name = "*SMBSERVER"; /* FIXME: This is invalid */
else
conn->in.called_name = s->io.binding->target_hostname;
- conn->in.socket_options = lp_socket_options(lp_ctx);
+ conn->in.socket_options = lpcfg_socket_options(lp_ctx);
conn->in.service = "IPC$";
conn->in.service_type = NULL;
- conn->in.workgroup = lp_workgroup(lp_ctx);
- conn->in.gensec_settings = lp_gensec_settings(conn, lp_ctx);
- conn->in.iconv_convenience = lp_iconv_convenience(lp_ctx);
+ conn->in.workgroup = lpcfg_workgroup(lp_ctx);
+ conn->in.gensec_settings = lpcfg_gensec_settings(conn, lp_ctx);
- lp_smbcli_options(lp_ctx, &conn->in.options);
- lp_smbcli_session_options(lp_ctx, &conn->in.session_options);
+ lpcfg_smbcli_options(lp_ctx, &conn->in.options);
+ lpcfg_smbcli_session_options(lp_ctx, &conn->in.session_options);
/*
* provide proper credentials - user supplied, but allow a
@@ -245,18 +244,18 @@ static struct composite_context *dcerpc_pipe_connect_ncacn_np_smb2_send(
cli_credentials_guess(s->io.creds, lp_ctx);
}
- lp_smbcli_options(lp_ctx, &options);
+ lpcfg_smbcli_options(lp_ctx, &options);
/* send smb2 connect request */
conn_req = smb2_connect_send(mem_ctx, s->io.binding->host,
- lp_parm_string_list(mem_ctx, lp_ctx, NULL, "smb2", "ports", NULL),
+ lpcfg_parm_string_list(mem_ctx, lp_ctx, NULL, "smb2", "ports", NULL),
"IPC$",
s->io.resolve_ctx,
s->io.creds,
c->event_ctx,
&options,
- lp_socket_options(lp_ctx),
- lp_gensec_settings(mem_ctx, lp_ctx)
+ lpcfg_socket_options(lp_ctx),
+ lpcfg_gensec_settings(mem_ctx, lp_ctx)
);
composite_continue(c, conn_req, continue_smb2_connect, c);
return c;
@@ -277,6 +276,7 @@ static NTSTATUS dcerpc_pipe_connect_ncacn_np_smb2_recv(struct composite_context
struct pipe_ip_tcp_state {
struct dcerpc_pipe_connect io;
+ const char *localaddr;
const char *host;
const char *target_hostname;
uint32_t port;
@@ -320,13 +320,14 @@ static struct composite_context* dcerpc_pipe_connect_ncacn_ip_tcp_send(TALLOC_CT
/* store input parameters in state structure */
s->io = *io;
+ s->localaddr = talloc_reference(c, io->binding->localaddress);
s->host = talloc_reference(c, io->binding->host);
s->target_hostname = talloc_reference(c, io->binding->target_hostname);
/* port number is a binding endpoint here */
s->port = atoi(io->binding->endpoint);
/* send pipe open request on tcp/ip */
- pipe_req = dcerpc_pipe_open_tcp_send(s->io.pipe->conn, s->host, s->target_hostname,
+ pipe_req = dcerpc_pipe_open_tcp_send(s->io.pipe->conn, s->localaddr, s->host, s->target_hostname,
s->port, io->resolve_ctx);
composite_continue(c, pipe_req, continue_pipe_open_ncacn_ip_tcp, c);
return c;
@@ -463,7 +464,7 @@ static struct composite_context* dcerpc_pipe_connect_ncalrpc_send(TALLOC_CTX *me
s->io = *io;
/* send pipe open request */
- pipe_req = dcerpc_pipe_open_pipe_send(s->io.pipe->conn, lp_ncalrpc_dir(lp_ctx),
+ pipe_req = dcerpc_pipe_open_pipe_send(s->io.pipe->conn, lpcfg_ncalrpc_dir(lp_ctx),
s->io.binding->endpoint);
composite_continue(c, pipe_req, continue_pipe_open_ncalrpc, c);
return c;
@@ -515,7 +516,7 @@ static void continue_map_binding(struct composite_context *ctx)
c->status = dcerpc_epm_map_binding_recv(ctx);
if (!composite_is_ok(c)) return;
- DEBUG(2,("Mapped to DCERPC endpoint %s\n", s->binding->endpoint));
+ DEBUG(4,("Mapped to DCERPC endpoint %s\n", s->binding->endpoint));
continue_connect(c, s);
}
@@ -538,9 +539,10 @@ static void continue_connect(struct composite_context *c, struct pipe_connect_st
/* dcerpc pipe connect input parameters */
pc.pipe = s->pipe;
pc.binding = s->binding;
+ pc.pipe_name = NULL;
pc.interface = s->table;
pc.creds = s->credentials;
- pc.resolve_ctx = lp_resolve_context(s->lp_ctx);
+ pc.resolve_ctx = lpcfg_resolve_context(s->lp_ctx);
/* connect dcerpc pipe depending on required transport */
switch (s->binding->transport) {
@@ -743,11 +745,11 @@ _PUBLIC_ struct composite_context* dcerpc_pipe_connect_b_send(TALLOC_CTX *parent
c->private_data = s;
/* initialise dcerpc pipe structure */
- s->pipe = dcerpc_pipe_init(c, ev, lp_iconv_convenience(lp_ctx));
+ s->pipe = dcerpc_pipe_init(c, ev);
if (composite_nomem(s->pipe, c)) return c;
if (DEBUGLEVEL >= 10)
- s->pipe->conn->packet_log_dir = lp_lockdir(lp_ctx);
+ s->pipe->conn->packet_log_dir = lpcfg_lockdir(lp_ctx);
/* store parameters in state structure */
s->binding = binding;
diff --git a/source4/librpc/rpc/dcerpc_schannel.c b/source4/librpc/rpc/dcerpc_schannel.c
index c678a674c1..fc56eccf7c 100644
--- a/source4/librpc/rpc/dcerpc_schannel.c
+++ b/source4/librpc/rpc/dcerpc_schannel.c
@@ -22,6 +22,7 @@
*/
#include "includes.h"
+#include <tevent.h>
#include "auth/auth.h"
#include "libcli/composite/composite.h"
#include "libcli/auth/libcli_auth.h"
@@ -49,8 +50,8 @@ struct schannel_key_state {
static void continue_secondary_connection(struct composite_context *ctx);
static void continue_bind_auth_none(struct composite_context *ctx);
-static void continue_srv_challenge(struct rpc_request *req);
-static void continue_srv_auth2(struct rpc_request *req);
+static void continue_srv_challenge(struct tevent_req *subreq);
+static void continue_srv_auth2(struct tevent_req *subreq);
/*
@@ -119,7 +120,7 @@ static void continue_bind_auth_none(struct composite_context *ctx)
{
struct composite_context *c;
struct schannel_key_state *s;
- struct rpc_request *srv_challenge_req;
+ struct tevent_req *subreq;
c = talloc_get_type(ctx->async.private_data, struct composite_context);
s = talloc_get_type(c->private_data, struct schannel_key_state);
@@ -140,10 +141,12 @@ static void continue_bind_auth_none(struct composite_context *ctx)
/*
request a netlogon challenge - a rpc request over opened secondary pipe
*/
- srv_challenge_req = dcerpc_netr_ServerReqChallenge_send(s->pipe2, c, &s->r);
- if (composite_nomem(srv_challenge_req, c)) return;
+ subreq = dcerpc_netr_ServerReqChallenge_r_send(s, c->event_ctx,
+ s->pipe2->binding_handle,
+ &s->r);
+ if (composite_nomem(subreq, c)) return;
- composite_continue_rpc(c, srv_challenge_req, continue_srv_challenge, c);
+ tevent_req_set_callback(subreq, continue_srv_challenge, c);
}
@@ -151,17 +154,17 @@ static void continue_bind_auth_none(struct composite_context *ctx)
Stage 5 of schannel_key: Receive a challenge and perform authentication
on the netlogon pipe
*/
-static void continue_srv_challenge(struct rpc_request *req)
+static void continue_srv_challenge(struct tevent_req *subreq)
{
struct composite_context *c;
struct schannel_key_state *s;
- struct rpc_request *srv_auth2_req;
- c = talloc_get_type(req->async.private_data, struct composite_context);
+ c = tevent_req_callback_data(subreq, struct composite_context);
s = talloc_get_type(c->private_data, struct schannel_key_state);
/* receive rpc request result - netlogon challenge */
- c->status = dcerpc_ndr_request_recv(req);
+ c->status = dcerpc_netr_ServerReqChallenge_r_recv(subreq, s);
+ TALLOC_FREE(subreq);
if (!composite_is_ok(c)) return;
/* prepare credentials for auth2 request */
@@ -189,10 +192,12 @@ static void continue_srv_challenge(struct rpc_request *req)
/*
authenticate on the netlogon pipe - a rpc request over secondary pipe
*/
- srv_auth2_req = dcerpc_netr_ServerAuthenticate2_send(s->pipe2, c, &s->a);
- if (composite_nomem(srv_auth2_req, c)) return;
+ subreq = dcerpc_netr_ServerAuthenticate2_r_send(s, c->event_ctx,
+ s->pipe2->binding_handle,
+ &s->a);
+ if (composite_nomem(subreq, c)) return;
- composite_continue_rpc(c, srv_auth2_req, continue_srv_auth2, c);
+ tevent_req_set_callback(subreq, continue_srv_auth2, c);
}
@@ -200,16 +205,17 @@ static void continue_srv_challenge(struct rpc_request *req)
Stage 6 of schannel_key: Receive authentication request result and verify
received credentials
*/
-static void continue_srv_auth2(struct rpc_request *req)
+static void continue_srv_auth2(struct tevent_req *subreq)
{
struct composite_context *c;
struct schannel_key_state *s;
- c = talloc_get_type(req->async.private_data, struct composite_context);
+ c = tevent_req_callback_data(subreq, struct composite_context);
s = talloc_get_type(c->private_data, struct schannel_key_state);
/* receive rpc request result - auth2 credentials */
- c->status = dcerpc_ndr_request_recv(req);
+ c->status = dcerpc_netr_ServerAuthenticate2_r_recv(subreq, s);
+ TALLOC_FREE(subreq);
if (!composite_is_ok(c)) return;
/* verify credentials */
@@ -237,6 +243,7 @@ struct composite_context *dcerpc_schannel_key_send(TALLOC_CTX *mem_ctx,
struct composite_context *c;
struct schannel_key_state *s;
struct composite_context *epm_map_req;
+ enum netr_SchannelType schannel_type = cli_credentials_get_secure_channel_type(credentials);
/* composite context allocation and setup */
c = composite_create(mem_ctx, p->conn->event_ctx);
@@ -252,14 +259,16 @@ struct composite_context *dcerpc_schannel_key_send(TALLOC_CTX *mem_ctx,
/* allocate credentials */
/* type of authentication depends on schannel type */
- if (s->pipe->conn->flags & DCERPC_SCHANNEL_128) {
+ if (schannel_type == SEC_CHAN_RODC) {
+ s->negotiate_flags = NETLOGON_NEG_AUTH2_RODC_FLAGS;
+ } else if (s->pipe->conn->flags & DCERPC_SCHANNEL_128) {
s->negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
} else {
s->negotiate_flags = NETLOGON_NEG_AUTH2_FLAGS;
}
/* allocate binding structure */
- s->binding = talloc(c, struct dcerpc_binding);
+ s->binding = talloc_zero(c, struct dcerpc_binding);
if (composite_nomem(s->binding, c)) return c;
*s->binding = *s->pipe->binding;
@@ -311,18 +320,18 @@ static void continue_schannel_key(struct composite_context *ctx)
struct composite_context);
struct auth_schannel_state *s = talloc_get_type(c->private_data,
struct auth_schannel_state);
+ NTSTATUS status;
/* receive schannel key */
- c->status = dcerpc_schannel_key_recv(ctx);
+ status = c->status = dcerpc_schannel_key_recv(ctx);
if (!composite_is_ok(c)) {
- DEBUG(1, ("Failed to setup credentials for account %s: %s\n",
- cli_credentials_get_username(s->credentials), nt_errstr(c->status)));
+ DEBUG(1, ("Failed to setup credentials: %s\n", nt_errstr(status)));
return;
}
/* send bind auth request with received creds */
auth_req = dcerpc_bind_auth_send(c, s->pipe, s->table, s->credentials,
- lp_gensec_settings(c, s->lp_ctx),
+ lpcfg_gensec_settings(c, s->lp_ctx),
DCERPC_AUTH_TYPE_SCHANNEL, s->auth_level,
NULL);
if (composite_nomem(auth_req, c)) return;
diff --git a/source4/librpc/rpc/dcerpc_secondary.c b/source4/librpc/rpc/dcerpc_secondary.c
index 1d76c65f40..65466e45e0 100644
--- a/source4/librpc/rpc/dcerpc_secondary.c
+++ b/source4/librpc/rpc/dcerpc_secondary.c
@@ -73,7 +73,7 @@ _PUBLIC_ struct composite_context* dcerpc_secondary_connection_send(struct dcerp
s->binding = b;
/* initialise second dcerpc pipe based on primary pipe's event context */
- s->pipe2 = dcerpc_pipe_init(c, s->pipe->conn->event_ctx, s->pipe->conn->iconv_convenience);
+ s->pipe2 = dcerpc_pipe_init(c, s->pipe->conn->event_ctx);
if (composite_nomem(s->pipe2, c)) return c;
if (DEBUGLEVEL >= 10)
@@ -102,6 +102,7 @@ _PUBLIC_ struct composite_context* dcerpc_secondary_connection_send(struct dcerp
}
pipe_tcp_req = dcerpc_pipe_open_tcp_send(s->pipe2->conn,
+ s->binding->localaddress,
s->peer_addr->addr,
s->binding->target_hostname,
atoi(s->binding->endpoint),
diff --git a/source4/librpc/rpc/dcerpc_smb.c b/source4/librpc/rpc/dcerpc_smb.c
index f4e6b8c3dd..395e067255 100644
--- a/source4/librpc/rpc/dcerpc_smb.c
+++ b/source4/librpc/rpc/dcerpc_smb.c
@@ -25,6 +25,7 @@
#include "libcli/composite/composite.h"
#include "librpc/rpc/dcerpc.h"
#include "librpc/rpc/dcerpc_proto.h"
+#include "librpc/rpc/rpc_common.h"
/* transport private information used by SMB pipe transport */
struct smb_private {
@@ -38,7 +39,7 @@ struct smb_private {
/*
tell the dcerpc layer that the transport is dead
*/
-static void pipe_dead(struct dcerpc_connection *c, NTSTATUS status)
+static void pipe_dead(struct dcecli_connection *c, NTSTATUS status)
{
struct smb_private *smb = (struct smb_private *)c->transport.private_data;
@@ -66,7 +67,7 @@ static void pipe_dead(struct dcerpc_connection *c, NTSTATUS status)
this holds the state of an in-flight call
*/
struct smb_read_state {
- struct dcerpc_connection *c;
+ struct dcecli_connection *c;
struct smbcli_request *req;
size_t received;
DATA_BLOB data;
@@ -109,7 +110,7 @@ static void smb_read_callback(struct smbcli_request *req)
if (frag_length <= state->received) {
DATA_BLOB data = state->data;
- struct dcerpc_connection *c = state->c;
+ struct dcecli_connection *c = state->c;
data.length = state->received;
talloc_steal(state->c, data.data);
talloc_free(state);
@@ -140,7 +141,7 @@ static void smb_read_callback(struct smbcli_request *req)
trigger a read request from the server, possibly with some initial
data in the read buffer
*/
-static NTSTATUS send_read_request_continue(struct dcerpc_connection *c, DATA_BLOB *blob)
+static NTSTATUS send_read_request_continue(struct dcecli_connection *c, DATA_BLOB *blob)
{
struct smb_private *smb = (struct smb_private *)c->transport.private_data;
union smb_read *io;
@@ -196,7 +197,7 @@ static NTSTATUS send_read_request_continue(struct dcerpc_connection *c, DATA_BLO
/*
trigger a read request from the server
*/
-static NTSTATUS send_read_request(struct dcerpc_connection *c)
+static NTSTATUS send_read_request(struct dcecli_connection *c)
{
struct smb_private *smb = (struct smb_private *)c->transport.private_data;
@@ -211,7 +212,7 @@ static NTSTATUS send_read_request(struct dcerpc_connection *c)
this holds the state of an in-flight trans call
*/
struct smb_trans_state {
- struct dcerpc_connection *c;
+ struct dcecli_connection *c;
struct smbcli_request *req;
struct smb_trans2 *trans;
};
@@ -222,7 +223,7 @@ struct smb_trans_state {
static void smb_trans_callback(struct smbcli_request *req)
{
struct smb_trans_state *state = (struct smb_trans_state *)req->async.private_data;
- struct dcerpc_connection *c = state->c;
+ struct dcecli_connection *c = state->c;
NTSTATUS status;
status = smb_raw_trans_recv(req, state, state->trans);
@@ -248,7 +249,7 @@ static void smb_trans_callback(struct smbcli_request *req)
/*
send a SMBtrans style request
*/
-static NTSTATUS smb_send_trans_request(struct dcerpc_connection *c, DATA_BLOB *blob)
+static NTSTATUS smb_send_trans_request(struct dcecli_connection *c, DATA_BLOB *blob)
{
struct smb_private *smb = (struct smb_private *)c->transport.private_data;
struct smb_trans2 *trans;
@@ -305,7 +306,7 @@ static NTSTATUS smb_send_trans_request(struct dcerpc_connection *c, DATA_BLOB *b
*/
static void smb_write_callback(struct smbcli_request *req)
{
- struct dcerpc_connection *c = (struct dcerpc_connection *)req->async.private_data;
+ struct dcecli_connection *c = (struct dcecli_connection *)req->async.private_data;
if (!NT_STATUS_IS_OK(req->status)) {
DEBUG(0,("dcerpc_smb: write callback error\n"));
@@ -318,7 +319,7 @@ static void smb_write_callback(struct smbcli_request *req)
/*
send a packet to the server
*/
-static NTSTATUS smb_send_request(struct dcerpc_connection *c, DATA_BLOB *blob,
+static NTSTATUS smb_send_request(struct dcecli_connection *c, DATA_BLOB *blob,
bool trigger_read)
{
struct smb_private *smb = (struct smb_private *)c->transport.private_data;
@@ -369,7 +370,7 @@ static void free_request(struct smbcli_request *req)
/*
shutdown SMB pipe connection
*/
-static NTSTATUS smb_shutdown_pipe(struct dcerpc_connection *c, NTSTATUS status)
+static NTSTATUS smb_shutdown_pipe(struct dcecli_connection *c, NTSTATUS status)
{
struct smb_private *smb = (struct smb_private *)c->transport.private_data;
union smb_close io;
@@ -396,7 +397,7 @@ static NTSTATUS smb_shutdown_pipe(struct dcerpc_connection *c, NTSTATUS status)
/*
return SMB server name (called name)
*/
-static const char *smb_peer_name(struct dcerpc_connection *c)
+static const char *smb_peer_name(struct dcecli_connection *c)
{
struct smb_private *smb = (struct smb_private *)c->transport.private_data;
if (smb == NULL) return "";
@@ -406,7 +407,7 @@ static const char *smb_peer_name(struct dcerpc_connection *c)
/*
return remote name we make the actual connection (good for kerberos)
*/
-static const char *smb_target_hostname(struct dcerpc_connection *c)
+static const char *smb_target_hostname(struct dcecli_connection *c)
{
struct smb_private *smb = talloc_get_type(c->transport.private_data, struct smb_private);
if (smb == NULL) return "";
@@ -416,7 +417,7 @@ static const char *smb_target_hostname(struct dcerpc_connection *c)
/*
fetch the user session key
*/
-static NTSTATUS smb_session_key(struct dcerpc_connection *c, DATA_BLOB *session_key)
+static NTSTATUS smb_session_key(struct dcecli_connection *c, DATA_BLOB *session_key)
{
struct smb_private *smb = (struct smb_private *)c->transport.private_data;
@@ -430,7 +431,7 @@ static NTSTATUS smb_session_key(struct dcerpc_connection *c, DATA_BLOB *session_
struct pipe_open_smb_state {
union smb_open *open;
- struct dcerpc_connection *c;
+ struct dcecli_connection *c;
struct smbcli_tree *tree;
struct composite_context *ctx;
};
@@ -444,7 +445,7 @@ struct composite_context *dcerpc_pipe_open_smb_send(struct dcerpc_pipe *p,
struct composite_context *ctx;
struct pipe_open_smb_state *state;
struct smbcli_request *req;
- struct dcerpc_connection *c = p->conn;
+ struct dcecli_connection *c = p->conn;
/* if we don't have a binding on this pipe yet, then create one */
if (p->binding == NULL) {
@@ -476,7 +477,7 @@ struct composite_context *dcerpc_pipe_open_smb_send(struct dcerpc_pipe *p,
state->open->ntcreatex.level = RAW_OPEN_NTCREATEX;
state->open->ntcreatex.in.flags = 0;
- state->open->ntcreatex.in.root_fid = 0;
+ state->open->ntcreatex.in.root_fid.fnum = 0;
state->open->ntcreatex.in.access_mask =
SEC_STD_READ_CONTROL |
SEC_FILE_WRITE_ATTRIBUTE |
@@ -514,7 +515,7 @@ static void pipe_open_recv(struct smbcli_request *req)
struct pipe_open_smb_state *state = talloc_get_type(req->async.private_data,
struct pipe_open_smb_state);
struct composite_context *ctx = state->ctx;
- struct dcerpc_connection *c = state->c;
+ struct dcecli_connection *c = state->c;
struct smb_private *smb;
ctx->status = smb_raw_open_recv(req, state, state->open);
@@ -570,7 +571,7 @@ _PUBLIC_ NTSTATUS dcerpc_pipe_open_smb(struct dcerpc_pipe *p,
/*
return the SMB tree used for a dcerpc over SMB pipe
*/
-_PUBLIC_ struct smbcli_tree *dcerpc_smb_tree(struct dcerpc_connection *c)
+_PUBLIC_ struct smbcli_tree *dcerpc_smb_tree(struct dcecli_connection *c)
{
struct smb_private *smb;
@@ -585,7 +586,7 @@ _PUBLIC_ struct smbcli_tree *dcerpc_smb_tree(struct dcerpc_connection *c)
/*
return the SMB fnum used for a dcerpc over SMB pipe (hack for torture operations)
*/
-_PUBLIC_ uint16_t dcerpc_smb_fnum(struct dcerpc_connection *c)
+_PUBLIC_ uint16_t dcerpc_smb_fnum(struct dcecli_connection *c)
{
struct smb_private *smb;
diff --git a/source4/librpc/rpc/dcerpc_smb2.c b/source4/librpc/rpc/dcerpc_smb2.c
index fbd847680f..50aed8cfd8 100644
--- a/source4/librpc/rpc/dcerpc_smb2.c
+++ b/source4/librpc/rpc/dcerpc_smb2.c
@@ -27,6 +27,7 @@
#include "libcli/raw/ioctl.h"
#include "librpc/rpc/dcerpc.h"
#include "librpc/rpc/dcerpc_proto.h"
+#include "librpc/rpc/rpc_common.h"
/* transport private information used by SMB2 pipe transport */
struct smb2_private {
@@ -40,7 +41,7 @@ struct smb2_private {
/*
tell the dcerpc layer that the transport is dead
*/
-static void pipe_dead(struct dcerpc_connection *c, NTSTATUS status)
+static void pipe_dead(struct dcecli_connection *c, NTSTATUS status)
{
struct smb2_private *smb = (struct smb2_private *)c->transport.private_data;
@@ -68,7 +69,7 @@ static void pipe_dead(struct dcerpc_connection *c, NTSTATUS status)
this holds the state of an in-flight call
*/
struct smb2_read_state {
- struct dcerpc_connection *c;
+ struct dcecli_connection *c;
DATA_BLOB data;
};
@@ -112,7 +113,7 @@ static void smb2_read_callback(struct smb2_request *req)
if (frag_length <= state->data.length) {
DATA_BLOB data = state->data;
- struct dcerpc_connection *c = state->c;
+ struct dcecli_connection *c = state->c;
talloc_steal(c, data.data);
talloc_free(state);
c->transport.recv_data(c, &data, NT_STATUS_OK);
@@ -144,7 +145,7 @@ static void smb2_read_callback(struct smb2_request *req)
trigger a read request from the server, possibly with some initial
data in the read buffer
*/
-static NTSTATUS send_read_request_continue(struct dcerpc_connection *c, DATA_BLOB *blob)
+static NTSTATUS send_read_request_continue(struct dcecli_connection *c, DATA_BLOB *blob)
{
struct smb2_private *smb = (struct smb2_private *)c->transport.private_data;
struct smb2_read io;
@@ -189,7 +190,7 @@ static NTSTATUS send_read_request_continue(struct dcerpc_connection *c, DATA_BLO
/*
trigger a read request from the server
*/
-static NTSTATUS send_read_request(struct dcerpc_connection *c)
+static NTSTATUS send_read_request(struct dcecli_connection *c)
{
struct smb2_private *smb = (struct smb2_private *)c->transport.private_data;
@@ -204,7 +205,7 @@ static NTSTATUS send_read_request(struct dcerpc_connection *c)
this holds the state of an in-flight trans call
*/
struct smb2_trans_state {
- struct dcerpc_connection *c;
+ struct dcecli_connection *c;
};
/*
@@ -214,7 +215,7 @@ static void smb2_trans_callback(struct smb2_request *req)
{
struct smb2_trans_state *state = talloc_get_type(req->async.private_data,
struct smb2_trans_state);
- struct dcerpc_connection *c = state->c;
+ struct dcecli_connection *c = state->c;
NTSTATUS status;
struct smb2_ioctl io;
@@ -240,7 +241,7 @@ static void smb2_trans_callback(struct smb2_request *req)
/*
send a SMBtrans style request, using a named pipe read_write fsctl
*/
-static NTSTATUS smb2_send_trans_request(struct dcerpc_connection *c, DATA_BLOB *blob)
+static NTSTATUS smb2_send_trans_request(struct dcecli_connection *c, DATA_BLOB *blob)
{
struct smb2_private *smb = talloc_get_type(c->transport.private_data,
struct smb2_private);
@@ -281,7 +282,7 @@ static NTSTATUS smb2_send_trans_request(struct dcerpc_connection *c, DATA_BLOB *
*/
static void smb2_write_callback(struct smb2_request *req)
{
- struct dcerpc_connection *c = (struct dcerpc_connection *)req->async.private_data;
+ struct dcecli_connection *c = (struct dcecli_connection *)req->async.private_data;
if (!NT_STATUS_IS_OK(req->status)) {
DEBUG(0,("dcerpc_smb2: write callback error\n"));
@@ -294,7 +295,7 @@ static void smb2_write_callback(struct smb2_request *req)
/*
send a packet to the server
*/
-static NTSTATUS smb2_send_request(struct dcerpc_connection *c, DATA_BLOB *blob,
+static NTSTATUS smb2_send_request(struct dcecli_connection *c, DATA_BLOB *blob,
bool trigger_read)
{
struct smb2_private *smb = (struct smb2_private *)c->transport.private_data;
@@ -332,7 +333,7 @@ static void free_request(struct smb2_request *req)
/*
shutdown SMB pipe connection
*/
-static NTSTATUS smb2_shutdown_pipe(struct dcerpc_connection *c, NTSTATUS status)
+static NTSTATUS smb2_shutdown_pipe(struct dcecli_connection *c, NTSTATUS status)
{
struct smb2_private *smb = (struct smb2_private *)c->transport.private_data;
struct smb2_close io;
@@ -357,7 +358,7 @@ static NTSTATUS smb2_shutdown_pipe(struct dcerpc_connection *c, NTSTATUS status)
/*
return SMB server name
*/
-static const char *smb2_peer_name(struct dcerpc_connection *c)
+static const char *smb2_peer_name(struct dcecli_connection *c)
{
struct smb2_private *smb = talloc_get_type(c->transport.private_data,
struct smb2_private);
@@ -367,7 +368,7 @@ static const char *smb2_peer_name(struct dcerpc_connection *c)
/*
return remote name we make the actual connection (good for kerberos)
*/
-static const char *smb2_target_hostname(struct dcerpc_connection *c)
+static const char *smb2_target_hostname(struct dcecli_connection *c)
{
struct smb2_private *smb = talloc_get_type(c->transport.private_data,
struct smb2_private);
@@ -377,7 +378,7 @@ static const char *smb2_target_hostname(struct dcerpc_connection *c)
/*
fetch the user session key
*/
-static NTSTATUS smb2_session_key(struct dcerpc_connection *c, DATA_BLOB *session_key)
+static NTSTATUS smb2_session_key(struct dcecli_connection *c, DATA_BLOB *session_key)
{
struct smb2_private *smb = talloc_get_type(c->transport.private_data,
struct smb2_private);
@@ -389,7 +390,7 @@ static NTSTATUS smb2_session_key(struct dcerpc_connection *c, DATA_BLOB *session
}
struct pipe_open_smb2_state {
- struct dcerpc_connection *c;
+ struct dcecli_connection *c;
struct composite_context *ctx;
};
@@ -403,7 +404,7 @@ struct composite_context *dcerpc_pipe_open_smb2_send(struct dcerpc_pipe *p,
struct pipe_open_smb2_state *state;
struct smb2_create io;
struct smb2_request *req;
- struct dcerpc_connection *c = p->conn;
+ struct dcecli_connection *c = p->conn;
ctx = composite_create(c, c->event_ctx);
if (ctx == NULL) return NULL;
@@ -452,7 +453,7 @@ static void pipe_open_recv(struct smb2_request *req)
talloc_get_type(req->async.private_data,
struct pipe_open_smb2_state);
struct composite_context *ctx = state->ctx;
- struct dcerpc_connection *c = state->c;
+ struct dcecli_connection *c = state->c;
struct smb2_tree *tree = req->tree;
struct smb2_private *smb;
struct smb2_create io;
@@ -509,7 +510,7 @@ NTSTATUS dcerpc_pipe_open_smb2(struct dcerpc_pipe *p,
/*
return the SMB2 tree used for a dcerpc over SMB2 pipe
*/
-struct smb2_tree *dcerpc_smb2_tree(struct dcerpc_connection *c)
+struct smb2_tree *dcerpc_smb2_tree(struct dcecli_connection *c)
{
struct smb2_private *smb = talloc_get_type(c->transport.private_data,
struct smb2_private);
diff --git a/source4/librpc/rpc/dcerpc_sock.c b/source4/librpc/rpc/dcerpc_sock.c
index d8bd6d2938..f0451ac674 100644
--- a/source4/librpc/rpc/dcerpc_sock.c
+++ b/source4/librpc/rpc/dcerpc_sock.c
@@ -29,6 +29,7 @@
#include "librpc/rpc/dcerpc.h"
#include "librpc/rpc/dcerpc_proto.h"
#include "libcli/resolve/resolve.h"
+#include "librpc/rpc/rpc_common.h"
/* transport private information used by general socket pipe transports */
struct sock_private {
@@ -46,7 +47,7 @@ struct sock_private {
/*
mark the socket dead
*/
-static void sock_dead(struct dcerpc_connection *p, NTSTATUS status)
+static void sock_dead(struct dcecli_connection *p, NTSTATUS status)
{
struct sock_private *sock = (struct sock_private *)p->transport.private_data;
@@ -87,8 +88,8 @@ static void sock_dead(struct dcerpc_connection *p, NTSTATUS status)
*/
static void sock_error_handler(void *private_data, NTSTATUS status)
{
- struct dcerpc_connection *p = talloc_get_type(private_data,
- struct dcerpc_connection);
+ struct dcecli_connection *p = talloc_get_type(private_data,
+ struct dcecli_connection);
sock_dead(p, status);
}
@@ -112,8 +113,8 @@ static NTSTATUS sock_complete_packet(void *private_data, DATA_BLOB blob, size_t
*/
static NTSTATUS sock_process_recv(void *private_data, DATA_BLOB blob)
{
- struct dcerpc_connection *p = talloc_get_type(private_data,
- struct dcerpc_connection);
+ struct dcecli_connection *p = talloc_get_type(private_data,
+ struct dcecli_connection);
struct sock_private *sock = (struct sock_private *)p->transport.private_data;
sock->pending_reads--;
if (sock->pending_reads == 0) {
@@ -129,8 +130,8 @@ static NTSTATUS sock_process_recv(void *private_data, DATA_BLOB blob)
static void sock_io_handler(struct tevent_context *ev, struct tevent_fd *fde,
uint16_t flags, void *private_data)
{
- struct dcerpc_connection *p = talloc_get_type(private_data,
- struct dcerpc_connection);
+ struct dcecli_connection *p = talloc_get_type(private_data,
+ struct dcecli_connection);
struct sock_private *sock = (struct sock_private *)p->transport.private_data;
if (flags & EVENT_FD_WRITE) {
@@ -150,7 +151,7 @@ static void sock_io_handler(struct tevent_context *ev, struct tevent_fd *fde,
/*
initiate a read request - not needed for dcerpc sockets
*/
-static NTSTATUS sock_send_read(struct dcerpc_connection *p)
+static NTSTATUS sock_send_read(struct dcecli_connection *p)
{
struct sock_private *sock = (struct sock_private *)p->transport.private_data;
sock->pending_reads++;
@@ -163,7 +164,7 @@ static NTSTATUS sock_send_read(struct dcerpc_connection *p)
/*
send an initial pdu in a multi-pdu sequence
*/
-static NTSTATUS sock_send_request(struct dcerpc_connection *p, DATA_BLOB *data,
+static NTSTATUS sock_send_request(struct dcecli_connection *p, DATA_BLOB *data,
bool trigger_read)
{
struct sock_private *sock = (struct sock_private *)p->transport.private_data;
@@ -194,7 +195,7 @@ static NTSTATUS sock_send_request(struct dcerpc_connection *p, DATA_BLOB *data,
/*
shutdown sock pipe connection
*/
-static NTSTATUS sock_shutdown_pipe(struct dcerpc_connection *p, NTSTATUS status)
+static NTSTATUS sock_shutdown_pipe(struct dcecli_connection *p, NTSTATUS status)
{
struct sock_private *sock = (struct sock_private *)p->transport.private_data;
@@ -208,7 +209,7 @@ static NTSTATUS sock_shutdown_pipe(struct dcerpc_connection *p, NTSTATUS status)
/*
return sock server name
*/
-static const char *sock_peer_name(struct dcerpc_connection *p)
+static const char *sock_peer_name(struct dcecli_connection *p)
{
struct sock_private *sock = talloc_get_type(p->transport.private_data, struct sock_private);
return sock->server_name;
@@ -217,7 +218,7 @@ static const char *sock_peer_name(struct dcerpc_connection *p)
/*
return remote name we make the actual connection (good for kerberos)
*/
-static const char *sock_target_hostname(struct dcerpc_connection *p)
+static const char *sock_target_hostname(struct dcecli_connection *p)
{
struct sock_private *sock = talloc_get_type(p->transport.private_data, struct sock_private);
return sock->server_name;
@@ -225,9 +226,10 @@ static const char *sock_target_hostname(struct dcerpc_connection *p)
struct pipe_open_socket_state {
- struct dcerpc_connection *conn;
+ struct dcecli_connection *conn;
struct socket_context *socket_ctx;
struct sock_private *sock;
+ struct socket_address *localaddr;
struct socket_address *server;
const char *target_hostname;
enum dcerpc_transport_t transport;
@@ -236,7 +238,7 @@ struct pipe_open_socket_state {
static void continue_socket_connect(struct composite_context *ctx)
{
- struct dcerpc_connection *conn;
+ struct dcecli_connection *conn;
struct sock_private *sock;
struct composite_context *c = talloc_get_type(ctx->async.private_data,
struct composite_context);
@@ -304,7 +306,8 @@ static void continue_socket_connect(struct composite_context *ctx)
static struct composite_context *dcerpc_pipe_open_socket_send(TALLOC_CTX *mem_ctx,
- struct dcerpc_connection *cn,
+ struct dcecli_connection *cn,
+ struct socket_address *localaddr,
struct socket_address *server,
const char *target_hostname,
const char *full_path,
@@ -323,6 +326,10 @@ static struct composite_context *dcerpc_pipe_open_socket_send(TALLOC_CTX *mem_ct
s->conn = cn;
s->transport = transport;
+ if (localaddr) {
+ s->localaddr = talloc_reference(c, localaddr);
+ if (composite_nomem(s->localaddr, c)) return c;
+ }
s->server = talloc_reference(c, server);
if (composite_nomem(s->server, c)) return c;
s->target_hostname = talloc_reference(s, target_hostname);
@@ -337,7 +344,7 @@ static struct composite_context *dcerpc_pipe_open_socket_send(TALLOC_CTX *mem_ct
s->sock->path = talloc_reference(s->sock, full_path);
- conn_req = socket_connect_send(s->socket_ctx, NULL, s->server, 0,
+ conn_req = socket_connect_send(s->socket_ctx, s->localaddr, s->server, 0,
c->event_ctx);
composite_continue(c, conn_req, continue_socket_connect, c);
return c;
@@ -357,9 +364,10 @@ struct pipe_tcp_state {
const char *target_hostname;
const char *address;
uint32_t port;
+ struct socket_address *localaddr;
struct socket_address *srvaddr;
struct resolve_context *resolve_ctx;
- struct dcerpc_connection *conn;
+ struct dcecli_connection *conn;
};
@@ -385,7 +393,7 @@ static void continue_ip_resolve_name(struct composite_context *ctx)
if (composite_nomem(s->srvaddr, c)) return;
/* resolve_nbt_name gives only ipv4 ... - send socket open request */
- sock_ipv4_req = dcerpc_pipe_open_socket_send(c, s->conn,
+ sock_ipv4_req = dcerpc_pipe_open_socket_send(c, s->conn, s->localaddr,
s->srvaddr, s->target_hostname,
NULL,
NCACN_IP_TCP);
@@ -419,7 +427,7 @@ static void continue_ipv6_open_socket(struct composite_context *ctx)
if (composite_nomem(s->srvaddr, c)) return;
/* try IPv4 if IPv6 fails */
- sock_ipv4_req = dcerpc_pipe_open_socket_send(c, s->conn,
+ sock_ipv4_req = dcerpc_pipe_open_socket_send(c, s->conn, s->localaddr,
s->srvaddr, s->target_hostname,
NCACN_IP_TCP);
composite_continue(c, sock_ipv4_req, continue_ipv4_open_socket, c);
@@ -452,12 +460,12 @@ static void continue_ipv4_open_socket(struct composite_context *ctx)
composite_done(c);
}
-
/*
Send rpc pipe open request to given host:port using
tcp/ip transport
*/
-struct composite_context* dcerpc_pipe_open_tcp_send(struct dcerpc_connection *conn,
+struct composite_context* dcerpc_pipe_open_tcp_send(struct dcecli_connection *conn,
+ const char *localaddr,
const char *server,
const char *target_hostname,
uint32_t port,
@@ -486,6 +494,12 @@ struct composite_context* dcerpc_pipe_open_tcp_send(struct dcerpc_connection *co
s->port = port;
s->conn = conn;
s->resolve_ctx = resolve_ctx;
+ if (localaddr) {
+ s->localaddr = socket_address_from_strings(s, "ip", localaddr, 0);
+ /* if there is no localaddr, we pass NULL for
+ s->localaddr, which is handled by the socket libraries as
+ meaning no local binding address specified */
+ }
make_nbt_name_server(&name, server);
resolve_req = resolve_name_send(resolve_ctx, s, &name, c->event_ctx);
@@ -509,7 +523,7 @@ NTSTATUS dcerpc_pipe_open_tcp_recv(struct composite_context *c)
struct pipe_unix_state {
const char *path;
struct socket_address *srvaddr;
- struct dcerpc_connection *conn;
+ struct dcecli_connection *conn;
};
@@ -535,7 +549,7 @@ static void continue_unix_open_socket(struct composite_context *ctx)
/*
Send pipe open request on unix socket
*/
-struct composite_context *dcerpc_pipe_open_unix_stream_send(struct dcerpc_connection *conn,
+struct composite_context *dcerpc_pipe_open_unix_stream_send(struct dcecli_connection *conn,
const char *path)
{
struct composite_context *c;
@@ -560,7 +574,7 @@ struct composite_context *dcerpc_pipe_open_unix_stream_send(struct dcerpc_connec
if (composite_nomem(s->srvaddr, c)) return c;
/* send socket open request */
- sock_unix_req = dcerpc_pipe_open_socket_send(c, s->conn,
+ sock_unix_req = dcerpc_pipe_open_socket_send(c, s->conn, NULL,
s->srvaddr, NULL,
s->path,
NCALRPC);
@@ -599,7 +613,7 @@ static void continue_np_open_socket(struct composite_context *ctx)
/*
Send pipe open request on ncalrpc
*/
-struct composite_context* dcerpc_pipe_open_pipe_send(struct dcerpc_connection *conn,
+struct composite_context* dcerpc_pipe_open_pipe_send(struct dcecli_connection *conn,
const char *ncalrpc_dir,
const char *identifier)
{
@@ -631,7 +645,7 @@ struct composite_context* dcerpc_pipe_open_pipe_send(struct dcerpc_connection *c
if (composite_nomem(s->srvaddr, c)) return c;
/* send socket open request */
- sock_np_req = dcerpc_pipe_open_socket_send(c, s->conn, s->srvaddr, NULL, s->path, NCALRPC);
+ sock_np_req = dcerpc_pipe_open_socket_send(c, s->conn, NULL, s->srvaddr, NULL, s->path, NCALRPC);
composite_continue(c, sock_np_req, continue_np_open_socket, c);
return c;
}
@@ -652,19 +666,19 @@ NTSTATUS dcerpc_pipe_open_pipe_recv(struct composite_context *c)
/*
Open a rpc pipe on a named pipe - sync version
*/
-NTSTATUS dcerpc_pipe_open_pipe(struct dcerpc_connection *conn, const char *ncalrpc_dir, const char *identifier)
+NTSTATUS dcerpc_pipe_open_pipe(struct dcecli_connection *conn, const char *ncalrpc_dir, const char *identifier)
{
struct composite_context *c = dcerpc_pipe_open_pipe_send(conn, ncalrpc_dir, identifier);
return dcerpc_pipe_open_pipe_recv(c);
}
-const char *dcerpc_unix_socket_path(struct dcerpc_connection *p)
+const char *dcerpc_unix_socket_path(struct dcecli_connection *p)
{
struct sock_private *sock = (struct sock_private *)p->transport.private_data;
return sock->path;
}
-struct socket_address *dcerpc_socket_peer_addr(struct dcerpc_connection *p, TALLOC_CTX *mem_ctx)
+struct socket_address *dcerpc_socket_peer_addr(struct dcecli_connection *p, TALLOC_CTX *mem_ctx)
{
struct sock_private *sock = (struct sock_private *)p->transport.private_data;
return socket_get_peer_addr(sock->sock, mem_ctx);
diff --git a/source4/librpc/rpc/dcerpc_util.c b/source4/librpc/rpc/dcerpc_util.c
index 86c91535e7..2cd94999e3 100644
--- a/source4/librpc/rpc/dcerpc_util.c
+++ b/source4/librpc/rpc/dcerpc_util.c
@@ -31,6 +31,7 @@
#include "librpc/rpc/dcerpc_proto.h"
#include "auth/credentials/credentials.h"
#include "param/param.h"
+#include "librpc/rpc/rpc_common.h"
/*
find a dcerpc call on an interface by name
@@ -51,14 +52,13 @@ const struct ndr_interface_call *dcerpc_iface_find_call(const struct ndr_interfa
push a ncacn_packet into a blob, potentially with auth info
*/
NTSTATUS ncacn_push_auth(DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
- struct smb_iconv_convenience *iconv_convenience,
- struct ncacn_packet *pkt,
- struct dcerpc_auth *auth_info)
+ struct ncacn_packet *pkt,
+ struct dcerpc_auth *auth_info)
{
struct ndr_push *ndr;
enum ndr_err_code ndr_err;
- ndr = ndr_push_init_ctx(mem_ctx, iconv_convenience);
+ ndr = ndr_push_init_ctx(mem_ctx);
if (!ndr) {
return NT_STATUS_NO_MEMORY;
}
@@ -83,6 +83,19 @@ NTSTATUS ncacn_push_auth(DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
}
if (auth_info) {
+#if 0
+ /* the s3 rpc server doesn't handle auth padding in
+ bind requests. Use zero auth padding to keep us
+ working with old servers */
+ uint32_t offset = ndr->offset;
+ ndr_err = ndr_push_align(ndr, 16);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+ auth_info->auth_pad_length = ndr->offset - offset;
+#else
+ auth_info->auth_pad_length = 0;
+#endif
ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, auth_info);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
return ndr_map_error2ntstatus(ndr_err);
@@ -106,12 +119,13 @@ struct epm_map_binding_state {
struct GUID guid;
struct epm_twr_t twr;
struct epm_twr_t *twr_r;
+ uint32_t num_towers;
struct epm_Map r;
};
static void continue_epm_recv_binding(struct composite_context *ctx);
-static void continue_epm_map(struct rpc_request *req);
+static void continue_epm_map(struct tevent_req *subreq);
/*
@@ -120,19 +134,16 @@ static void continue_epm_map(struct rpc_request *req);
*/
static void continue_epm_recv_binding(struct composite_context *ctx)
{
- struct rpc_request *map_req;
-
struct composite_context *c = talloc_get_type(ctx->async.private_data,
struct composite_context);
struct epm_map_binding_state *s = talloc_get_type(c->private_data,
struct epm_map_binding_state);
+ struct tevent_req *subreq;
/* receive result of rpc pipe connect request */
c->status = dcerpc_pipe_connect_b_recv(ctx, c, &s->pipe);
if (!composite_is_ok(c)) return;
- s->pipe->conn->flags |= DCERPC_NDR_REF_ALLOC;
-
/* prepare requested binding parameters */
s->binding->object = s->table->syntax_id;
@@ -145,27 +156,31 @@ static void continue_epm_recv_binding(struct composite_context *ctx)
s->r.in.entry_handle = &s->handle;
s->r.in.max_towers = 1;
s->r.out.entry_handle = &s->handle;
+ s->r.out.num_towers = &s->num_towers;
/* send request for an endpoint mapping - a rpc request on connected pipe */
- map_req = dcerpc_epm_Map_send(s->pipe, c, &s->r);
- if (composite_nomem(map_req, c)) return;
+ subreq = dcerpc_epm_Map_r_send(s, c->event_ctx,
+ s->pipe->binding_handle,
+ &s->r);
+ if (composite_nomem(subreq, c)) return;
- composite_continue_rpc(c, map_req, continue_epm_map, c);
+ tevent_req_set_callback(subreq, continue_epm_map, c);
}
/*
Stage 3 of epm_map_binding: Receive endpoint mapping and provide binding details
*/
-static void continue_epm_map(struct rpc_request *req)
+static void continue_epm_map(struct tevent_req *subreq)
{
- struct composite_context *c = talloc_get_type(req->async.private_data,
- struct composite_context);
+ struct composite_context *c = tevent_req_callback_data(subreq,
+ struct composite_context);
struct epm_map_binding_state *s = talloc_get_type(c->private_data,
struct epm_map_binding_state);
/* receive result of a rpc request */
- c->status = dcerpc_ndr_request_recv(req);
+ c->status = dcerpc_epm_Map_r_recv(subreq, s);
+ TALLOC_FREE(subreq);
if (!composite_is_ok(c)) return;
/* check the details */
@@ -271,6 +286,7 @@ struct composite_context *dcerpc_epm_map_binding_send(TALLOC_CTX *mem_ctx,
epmapper_binding->host = talloc_reference(epmapper_binding, binding->host);
epmapper_binding->target_hostname = epmapper_binding->host;
epmapper_binding->options = NULL;
+ epmapper_binding->localaddress = talloc_reference(epmapper_binding, binding->localaddress);
epmapper_binding->flags = 0;
epmapper_binding->assoc_group_id = 0;
epmapper_binding->endpoint = NULL;
@@ -407,6 +423,7 @@ static void continue_ntlmssp_connection(struct composite_context *ctx)
struct pipe_auth_state *s;
struct composite_context *auth_req;
struct dcerpc_pipe *p2;
+ void *pp;
c = talloc_get_type(ctx->async.private_data, struct composite_context);
s = talloc_get_type(c->private_data, struct pipe_auth_state);
@@ -415,14 +432,37 @@ static void continue_ntlmssp_connection(struct composite_context *ctx)
c->status = dcerpc_secondary_connection_recv(ctx, &p2);
if (!composite_is_ok(c)) return;
+
+ /* this is a rather strange situation. When
+ we come into the routine, s is a child of s->pipe, and
+ when we created p2 above, it also became a child of
+ s->pipe.
+
+ Now we want p2 to be a parent of s->pipe, and we want s to
+ be a parent of both of them! If we don't do this very
+ carefully we end up creating a talloc loop
+ */
+
+ /* we need the new contexts to hang off the same context
+ that s->pipe is on, but the only way to get that is
+ via talloc_parent() */
+ pp = talloc_parent(s->pipe);
+
+ /* promote s to be at the top */
+ talloc_steal(pp, s);
+
+ /* and put p2 under s */
talloc_steal(s, p2);
+
+ /* now put s->pipe under p2 */
talloc_steal(p2, s->pipe);
+
s->pipe = p2;
/* initiate a authenticated bind */
auth_req = dcerpc_bind_auth_send(c, s->pipe, s->table,
s->credentials,
- lp_gensec_settings(c, s->lp_ctx),
+ lpcfg_gensec_settings(c, s->lp_ctx),
DCERPC_AUTH_TYPE_NTLMSSP,
dcerpc_auth_level(s->pipe->conn),
s->table->authservices->names[0]);
@@ -455,7 +495,7 @@ static void continue_spnego_after_wrong_pass(struct composite_context *ctx)
/* initiate a authenticated bind */
auth_req = dcerpc_bind_auth_send(c, s->pipe, s->table,
s->credentials,
- lp_gensec_settings(c, s->lp_ctx),
+ lpcfg_gensec_settings(c, s->lp_ctx),
DCERPC_AUTH_TYPE_SPNEGO,
dcerpc_auth_level(s->pipe->conn),
s->table->authservices->names[0]);
@@ -493,7 +533,7 @@ struct composite_context *dcerpc_pipe_auth_send(struct dcerpc_pipe *p,
struct composite_context *auth_schannel_req;
struct composite_context *auth_req;
struct composite_context *auth_none_req;
- struct dcerpc_connection *conn;
+ struct dcecli_connection *conn;
uint8_t auth_type;
/* composite context allocation and setup */
@@ -580,7 +620,7 @@ struct composite_context *dcerpc_pipe_auth_send(struct dcerpc_pipe *p,
/* try SPNEGO with fallback to NTLMSSP */
auth_req = dcerpc_bind_auth_send(c, s->pipe, s->table,
s->credentials,
- lp_gensec_settings(c, s->lp_ctx),
+ lpcfg_gensec_settings(c, s->lp_ctx),
DCERPC_AUTH_TYPE_SPNEGO,
dcerpc_auth_level(conn),
s->table->authservices->names[0]);
@@ -590,7 +630,7 @@ struct composite_context *dcerpc_pipe_auth_send(struct dcerpc_pipe *p,
auth_req = dcerpc_bind_auth_send(c, s->pipe, s->table,
s->credentials,
- lp_gensec_settings(c, s->lp_ctx),
+ lpcfg_gensec_settings(c, s->lp_ctx),
auth_type,
dcerpc_auth_level(conn),
s->table->authservices->names[0]);
@@ -647,7 +687,7 @@ _PUBLIC_ NTSTATUS dcerpc_pipe_auth(TALLOC_CTX *mem_ctx,
}
-NTSTATUS dcerpc_generic_session_key(struct dcerpc_connection *c,
+NTSTATUS dcerpc_generic_session_key(struct dcecli_connection *c,
DATA_BLOB *session_key)
{
/* this took quite a few CPU cycles to find ... */
@@ -683,9 +723,9 @@ _PUBLIC_ NTSTATUS dcerpc_fetch_session_key(struct dcerpc_pipe *p,
this triggers on a debug level of >= 10
*/
_PUBLIC_ void dcerpc_log_packet(const char *lockdir,
- const struct ndr_interface_table *ndr,
- uint32_t opnum, uint32_t flags,
- DATA_BLOB *pkt)
+ const struct ndr_interface_table *ndr,
+ uint32_t opnum, uint32_t flags,
+ const DATA_BLOB *pkt)
{
const int num_examples = 20;
int i;
@@ -740,6 +780,12 @@ _PUBLIC_ NTSTATUS dcerpc_secondary_context(struct dcerpc_pipe *p,
p2->binding = talloc_reference(p2, p->binding);
+ p2->binding_handle = dcerpc_pipe_binding_handle(p2);
+ if (p2->binding_handle == NULL) {
+ talloc_free(p2);
+ return NT_STATUS_NO_MEMORY;
+ }
+
status = dcerpc_alter_context(p2, p2, &p2->syntax, &p2->transfer_syntax);
if (!NT_STATUS_IS_OK(status)) {
talloc_free(p2);
diff --git a/source4/librpc/rpc/pyrpc.c b/source4/librpc/rpc/pyrpc.c
index e50a077625..2d6e1f6c61 100644
--- a/source4/librpc/rpc/pyrpc.c
+++ b/source4/librpc/rpc/pyrpc.c
@@ -2,107 +2,34 @@
Unix SMB/CIFS implementation.
Samba utility functions
Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008
-
+
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 <Python.h>
+#include "includes.h"
#include <structmember.h>
#include "librpc/rpc/pyrpc.h"
-#include "librpc/rpc/dcerpc.h"
#include "lib/events/events.h"
#include "param/pyparam.h"
+#include "librpc/rpc/dcerpc.h"
+#include "librpc/rpc/pyrpc_util.h"
#include "auth/credentials/pycredentials.h"
-#ifndef Py_RETURN_NONE
-#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None
-#endif
-
-static PyObject *py_dcerpc_run_function(dcerpc_InterfaceObject *iface,
- const struct PyNdrRpcMethodDef *md,
- PyObject *args, PyObject *kwargs)
-{
- TALLOC_CTX *mem_ctx;
- NTSTATUS status;
- void *r;
- PyObject *result = Py_None;
-
- if (md->pack_in_data == NULL || md->unpack_out_data == NULL) {
- PyErr_SetString(PyExc_NotImplementedError, "No marshalling code available yet");
- return NULL;
- }
-
- mem_ctx = talloc_new(NULL);
- if (mem_ctx == NULL) {
- PyErr_NoMemory();
- return NULL;
- }
-
- r = talloc_zero_size(mem_ctx, md->table->calls[md->opnum].struct_size);
- if (r == NULL) {
- PyErr_NoMemory();
- return NULL;
- }
-
- if (!md->pack_in_data(args, kwargs, r)) {
- talloc_free(mem_ctx);
- return NULL;
- }
-
- status = md->call(iface->pipe, mem_ctx, r);
- if (NT_STATUS_IS_ERR(status)) {
- PyErr_SetDCERPCStatus(iface->pipe, status);
- talloc_free(mem_ctx);
- return NULL;
- }
-
- result = md->unpack_out_data(r);
+void initbase(void);
- talloc_free(mem_ctx);
- return result;
-}
-
-static PyObject *py_dcerpc_call_wrapper(PyObject *self, PyObject *args, void *wrapped, PyObject *kwargs)
-{
- dcerpc_InterfaceObject *iface = (dcerpc_InterfaceObject *)self;
- const struct PyNdrRpcMethodDef *md = (const struct PyNdrRpcMethodDef *)wrapped;
-
- return py_dcerpc_run_function(iface, md, args, kwargs);
-}
-
-
-bool PyInterface_AddNdrRpcMethods(PyTypeObject *ifacetype, const struct PyNdrRpcMethodDef *mds)
-{
- int i;
- for (i = 0; mds[i].name; i++) {
- PyObject *ret;
- struct wrapperbase *wb = (struct wrapperbase *)calloc(sizeof(struct wrapperbase), 1);
-
- wb->name = discard_const_p(char, mds[i].name);
- wb->flags = PyWrapperFlag_KEYWORDS;
- wb->wrapper = (wrapperfunc)py_dcerpc_call_wrapper;
- wb->doc = discard_const_p(char, mds[i].doc);
-
- ret = PyDescr_NewWrapper(ifacetype, wb, discard_const_p(void, &mds[i]));
-
- PyDict_SetItemString(ifacetype->tp_dict, mds[i].name,
- (PyObject *)ret);
- }
-
- return true;
-}
+staticforward PyTypeObject dcerpc_InterfaceType;
static bool PyString_AsGUID(PyObject *object, struct GUID *uuid)
{
@@ -146,13 +73,13 @@ static bool ndr_syntax_from_py_object(PyObject *object, struct ndr_syntax_id *sy
PyErr_SetString(PyExc_TypeError, "Expected UUID or syntax id tuple");
return false;
-}
+}
static PyObject *py_iface_server_name(PyObject *obj, void *closure)
{
const char *server_name;
dcerpc_InterfaceObject *iface = (dcerpc_InterfaceObject *)obj;
-
+
server_name = dcerpc_server_name(iface->pipe);
if (server_name == NULL)
Py_RETURN_NONE;
@@ -207,18 +134,6 @@ static PyMemberDef dcerpc_interface_members[] = {
{ NULL }
};
-void PyErr_SetDCERPCStatus(struct dcerpc_pipe *p, NTSTATUS status)
-{
- if (p != NULL && NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
- const char *errstr = dcerpc_errstr(NULL, p->last_fault_code);
- PyErr_SetObject(PyExc_RuntimeError,
- Py_BuildValue("(i,s)", p->last_fault_code,
- errstr));
- } else {
- PyErr_SetNTSTATUS(status);
- }
-}
-
static PyObject *py_iface_request(PyObject *self, PyObject *args, PyObject *kwargs)
{
dcerpc_InterfaceObject *iface = (dcerpc_InterfaceObject *)self;
@@ -231,10 +146,12 @@ static PyObject *py_iface_request(PyObject *self, PyObject *args, PyObject *kwar
PyObject *object = NULL;
struct GUID object_guid;
TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ uint32_t out_flags = 0;
const char *kwnames[] = { "opnum", "data", "object", NULL };
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "is#|O:request",
discard_const_p(char *, kwnames), &opnum, &in_data, &in_length, &object)) {
+ talloc_free(mem_ctx);
return NULL;
}
@@ -244,13 +161,21 @@ static PyObject *py_iface_request(PyObject *self, PyObject *args, PyObject *kwar
ZERO_STRUCT(data_out);
if (object != NULL && !PyString_AsGUID(object, &object_guid)) {
+ talloc_free(mem_ctx);
return NULL;
}
- status = dcerpc_request(iface->pipe, object?&object_guid:NULL,
- opnum, mem_ctx, &data_in, &data_out);
-
- if (NT_STATUS_IS_ERR(status)) {
+ status = dcerpc_binding_handle_raw_call(iface->binding_handle,
+ object?&object_guid:NULL,
+ opnum,
+ 0, /* in_flags */
+ data_in.data,
+ data_in.length,
+ mem_ctx,
+ &data_out.data,
+ &data_out.length,
+ &out_flags);
+ if (!NT_STATUS_IS_OK(status)) {
PyErr_SetDCERPCStatus(iface->pipe, status);
talloc_free(mem_ctx);
return NULL;
@@ -290,7 +215,7 @@ static PyObject *py_iface_alter_context(PyObject *self, PyObject *args, PyObject
status = dcerpc_alter_context(iface->pipe, iface->pipe, &abstract_syntax,
&transfer_syntax);
- if (NT_STATUS_IS_ERR(status)) {
+ if (!NT_STATUS_IS_OK(status)) {
PyErr_SetDCERPCStatus(iface->pipe, status);
return NULL;
}
@@ -298,93 +223,27 @@ static PyObject *py_iface_alter_context(PyObject *self, PyObject *args, PyObject
Py_RETURN_NONE;
}
-PyObject *py_dcerpc_interface_init_helper(PyTypeObject *type, PyObject *args, PyObject *kwargs, const struct ndr_interface_table *table)
-{
- dcerpc_InterfaceObject *ret;
- const char *binding_string;
- struct cli_credentials *credentials;
- struct loadparm_context *lp_ctx = NULL;
- PyObject *py_lp_ctx = Py_None, *py_credentials = Py_None, *py_basis = Py_None;
- TALLOC_CTX *mem_ctx = NULL;
- struct tevent_context *event_ctx;
- NTSTATUS status;
-
- const char *kwnames[] = {
- "binding", "lp_ctx", "credentials", "basis_connection", NULL
- };
-
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|OOO:samr", discard_const_p(char *, kwnames), &binding_string, &py_lp_ctx, &py_credentials, &py_basis)) {
- return NULL;
- }
-
- lp_ctx = lp_from_py_object(py_lp_ctx);
- if (lp_ctx == NULL) {
- PyErr_SetString(PyExc_TypeError, "Expected loadparm context");
- return NULL;
- }
-
- status = dcerpc_init(lp_ctx);
- if (!NT_STATUS_IS_OK(status)) {
- PyErr_SetNTSTATUS(status);
- return NULL;
- }
- credentials = cli_credentials_from_py_object(py_credentials);
- if (credentials == NULL) {
- PyErr_SetString(PyExc_TypeError, "Expected credentials");
- return NULL;
- }
- ret = PyObject_New(dcerpc_InterfaceObject, type);
-
- event_ctx = event_context_init(mem_ctx);
-
- if (py_basis != Py_None) {
- struct dcerpc_pipe *base_pipe;
-
- if (!PyObject_TypeCheck(py_basis, &dcerpc_InterfaceType)) {
- PyErr_SetString(PyExc_ValueError, "basis_connection must be a DCE/RPC connection");
- talloc_free(mem_ctx);
- return NULL;
- }
-
- base_pipe = ((dcerpc_InterfaceObject *)py_basis)->pipe;
-
- status = dcerpc_secondary_context(base_pipe, &ret->pipe, table);
- } else {
- status = dcerpc_pipe_connect(NULL, &ret->pipe, binding_string,
- table, credentials, event_ctx, lp_ctx);
- }
- if (NT_STATUS_IS_ERR(status)) {
- PyErr_SetNTSTATUS(status);
- talloc_free(mem_ctx);
- return NULL;
- }
-
- ret->pipe->conn->flags |= DCERPC_NDR_REF_ALLOC;
- return (PyObject *)ret;
-}
-
static PyMethodDef dcerpc_interface_methods[] = {
{ "request", (PyCFunction)py_iface_request, METH_VARARGS|METH_KEYWORDS, "S.request(opnum, data, object=None) -> data\nMake a raw request" },
{ "alter_context", (PyCFunction)py_iface_alter_context, METH_VARARGS|METH_KEYWORDS, "S.alter_context(syntax)\nChange to a different interface" },
{ NULL, NULL, 0, NULL },
};
-
static void dcerpc_interface_dealloc(PyObject* self)
{
dcerpc_InterfaceObject *interface = (dcerpc_InterfaceObject *)self;
- talloc_free(interface->pipe);
- PyObject_Del(self);
+ talloc_free(interface->mem_ctx);
+ self->ob_type->tp_free(self);
}
-static PyObject *dcerpc_interface_new(PyTypeObject *self, PyObject *args, PyObject *kwargs)
+static PyObject *dcerpc_interface_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
{
dcerpc_InterfaceObject *ret;
const char *binding_string;
struct cli_credentials *credentials;
struct loadparm_context *lp_ctx = NULL;
PyObject *py_lp_ctx = Py_None, *py_credentials = Py_None;
- TALLOC_CTX *mem_ctx = NULL;
+ TALLOC_CTX *mem_ctx;
struct tevent_context *event_ctx;
NTSTATUS status;
@@ -398,37 +257,49 @@ static PyObject *dcerpc_interface_new(PyTypeObject *self, PyObject *args, PyObje
return NULL;
}
- lp_ctx = lp_from_py_object(py_lp_ctx);
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ lp_ctx = lpcfg_from_py_object(mem_ctx, py_lp_ctx);
if (lp_ctx == NULL) {
PyErr_SetString(PyExc_TypeError, "Expected loadparm context");
+ talloc_free(mem_ctx);
return NULL;
}
credentials = cli_credentials_from_py_object(py_credentials);
if (credentials == NULL) {
PyErr_SetString(PyExc_TypeError, "Expected credentials");
+ talloc_free(mem_ctx);
return NULL;
}
- ret = PyObject_New(dcerpc_InterfaceObject, &dcerpc_InterfaceType);
+ ret = PyObject_New(dcerpc_InterfaceObject, type);
+ ret->mem_ctx = mem_ctx;
- event_ctx = s4_event_context_init(mem_ctx);
+ event_ctx = s4_event_context_init(ret->mem_ctx);
- /* Create a dummy interface table struct. TODO: In the future, we should rather just allow
- * connecting without requiring an interface table.
+ /* Create a dummy interface table struct. TODO: In the future, we should
+ * rather just allow connecting without requiring an interface table.
*/
- table = talloc_zero(mem_ctx, struct ndr_interface_table);
+ table = talloc_zero(ret->mem_ctx, struct ndr_interface_table);
if (table == NULL) {
PyErr_SetString(PyExc_MemoryError, "Allocating interface table");
+ talloc_free(mem_ctx);
return NULL;
}
if (!ndr_syntax_from_py_object(syntax, &table->syntax_id)) {
+ talloc_free(mem_ctx);
return NULL;
}
ret->pipe = NULL;
+ ret->binding_handle = NULL;
if (py_basis != Py_None) {
struct dcerpc_pipe *base_pipe;
@@ -439,26 +310,28 @@ static PyObject *dcerpc_interface_new(PyTypeObject *self, PyObject *args, PyObje
return NULL;
}
- base_pipe = ((dcerpc_InterfaceObject *)py_basis)->pipe;
+ base_pipe = talloc_reference(ret->mem_ctx,
+ ((dcerpc_InterfaceObject *)py_basis)->pipe);
+
+ status = dcerpc_secondary_context(base_pipe, &ret->pipe, table);
- status = dcerpc_secondary_context(base_pipe, &ret->pipe,
- table);
- ret->pipe = talloc_steal(NULL, ret->pipe);
+ ret->pipe = talloc_steal(ret->mem_ctx, ret->pipe);
} else {
- status = dcerpc_pipe_connect(NULL, &ret->pipe, binding_string,
+ status = dcerpc_pipe_connect(ret->mem_ctx, &ret->pipe, binding_string,
table, credentials, event_ctx, lp_ctx);
}
- if (NT_STATUS_IS_ERR(status)) {
+ if (!NT_STATUS_IS_OK(status)) {
PyErr_SetDCERPCStatus(ret->pipe, status);
- talloc_free(mem_ctx);
+ talloc_free(ret->mem_ctx);
return NULL;
}
ret->pipe->conn->flags |= DCERPC_NDR_REF_ALLOC;
+ ret->binding_handle = ret->pipe->binding_handle;
return (PyObject *)ret;
}
-PyTypeObject dcerpc_InterfaceType = {
+static PyTypeObject dcerpc_InterfaceType = {
PyObject_HEAD_INIT(NULL) 0,
.tp_name = "dcerpc.ClientConnection",
.tp_basicsize = sizeof(dcerpc_InterfaceObject),
diff --git a/source4/librpc/rpc/pyrpc.h b/source4/librpc/rpc/pyrpc.h
index ae622b562c..52f4f4d3d3 100644
--- a/source4/librpc/rpc/pyrpc.h
+++ b/source4/librpc/rpc/pyrpc.h
@@ -21,11 +21,14 @@
#define _PYRPC_H_
#include "libcli/util/pyerrors.h"
-#include "librpc/rpc/dcerpc.h"
+
+#ifndef Py_TYPE /* Py_TYPE is only available on Python > 2.6 */
+#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
+#endif
#define PY_CHECK_TYPE(type, var, fail) \
if (!PyObject_TypeCheck(var, type)) {\
- PyErr_Format(PyExc_TypeError, "Expected type %s", (type)->tp_name); \
+ PyErr_Format(PyExc_TypeError, __location__ ": Expected type '%s' for '%s' of type '%s'", (type)->tp_name, #var, Py_TYPE(var)->tp_name); \
fail; \
}
@@ -36,39 +39,21 @@
#define dom_sid2_Check dom_sid_Check
#define dom_sid28_Check dom_sid_Check
-/* This macro is only provided by Python >= 2.3 */
-#ifndef PyAPI_DATA
-# define PyAPI_DATA(RTYPE) extern RTYPE
-#endif
-
typedef struct {
PyObject_HEAD
+ TALLOC_CTX *mem_ctx;
struct dcerpc_pipe *pipe;
+ struct dcerpc_binding_handle *binding_handle;
} dcerpc_InterfaceObject;
-PyAPI_DATA(PyTypeObject) dcerpc_InterfaceType;
-
-#define PyErr_FromNdrError(err) Py_BuildValue("(is)", err, ndr_map_error2string(err))
-
-#define PyErr_SetNdrError(err) \
- PyErr_SetObject(PyExc_RuntimeError, PyErr_FromNdrError(err))
-
-void PyErr_SetDCERPCStatus(struct dcerpc_pipe *pipe, NTSTATUS status);
-
-typedef bool (*py_data_pack_fn) (PyObject *args, PyObject *kwargs, void *r);
-typedef PyObject *(*py_data_unpack_fn) (void *r);
-
-struct PyNdrRpcMethodDef {
- const char *name;
- const char *doc;
- dcerpc_call_fn call;
- py_data_pack_fn pack_in_data;
- py_data_unpack_fn unpack_out_data;
- uint32_t opnum;
- const struct ndr_interface_table *table;
-};
-bool PyInterface_AddNdrRpcMethods(PyTypeObject *object, const struct PyNdrRpcMethodDef *mds);
-PyObject *py_dcerpc_interface_init_helper(PyTypeObject *type, PyObject *args, PyObject *kwargs, const struct ndr_interface_table *table);
+/*
+ these prototypes should be generated by the python pidl backend, but
+ aren't yet. They are needed when one module that has python access
+ is accessed by another module
+ */
+union netr_LogonLevel *py_export_netr_LogonLevel(TALLOC_CTX *mem_ctx, int level, PyObject *in);
+union netr_Validation;
+PyObject *py_import_netr_Validation(TALLOC_CTX *mem_ctx, int level, union netr_Validation *in);
#endif /* _PYRPC_H_ */
diff --git a/source4/librpc/rpc/pyrpc_util.c b/source4/librpc/rpc/pyrpc_util.c
new file mode 100644
index 0000000000..3821638fb3
--- /dev/null
+++ b/source4/librpc/rpc/pyrpc_util.c
@@ -0,0 +1,310 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Python interface to DCE/RPC library - utility functions.
+
+ Copyright (C) 2010 Jelmer Vernooij <jelmer@samba.org>
+ Copyright (C) 2010 Andrew Tridgell <tridge@samba.org>
+
+ 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 <Python.h>
+#include "includes.h"
+#include "librpc/rpc/pyrpc_util.h"
+#include "librpc/rpc/dcerpc.h"
+#include "librpc/rpc/pyrpc.h"
+#include "param/pyparam.h"
+#include "auth/credentials/pycredentials.h"
+#include "lib/events/events.h"
+#include "lib/messaging/messaging.h"
+#include "lib/messaging/irpc.h"
+
+bool py_check_dcerpc_type(PyObject *obj, const char *module, const char *type_name)
+{
+ PyObject *mod;
+ PyTypeObject *type;
+ bool ret;
+
+ mod = PyImport_ImportModule(module);
+
+ if (mod == NULL) {
+ PyErr_Format(PyExc_RuntimeError, "Unable to import %s to check type %s",
+ module, type_name);
+ return NULL;
+ }
+
+ type = (PyTypeObject *)PyObject_GetAttrString(mod, type_name);
+ Py_DECREF(mod);
+ if (type == NULL) {
+ PyErr_Format(PyExc_RuntimeError, "Unable to find type %s in module %s",
+ module, type_name);
+ return NULL;
+ }
+
+ ret = PyObject_TypeCheck(obj, type);
+ Py_DECREF(type);
+
+ if (!ret)
+ PyErr_Format(PyExc_TypeError, "Expected type %s.%s, got %s",
+ module, type_name, Py_TYPE(obj)->tp_name);
+
+ return ret;
+}
+
+/*
+ connect to a IRPC pipe from python
+ */
+static NTSTATUS pyrpc_irpc_connect(TALLOC_CTX *mem_ctx, const char *irpc_server,
+ const struct ndr_interface_table *table,
+ struct tevent_context *event_ctx,
+ struct loadparm_context *lp_ctx,
+ struct dcerpc_binding_handle **binding_handle)
+{
+ struct messaging_context *msg;
+
+ msg = messaging_client_init(mem_ctx, lpcfg_messaging_path(mem_ctx, lp_ctx), event_ctx);
+ NT_STATUS_HAVE_NO_MEMORY(msg);
+
+ *binding_handle = irpc_binding_handle_by_name(mem_ctx, msg, irpc_server, table);
+ if (*binding_handle == NULL) {
+ talloc_free(msg);
+ return NT_STATUS_INVALID_PIPE_STATE;
+ }
+
+ return NT_STATUS_OK;
+}
+
+PyObject *py_dcerpc_interface_init_helper(PyTypeObject *type, PyObject *args, PyObject *kwargs,
+ const struct ndr_interface_table *table)
+{
+ dcerpc_InterfaceObject *ret;
+ const char *binding_string;
+ struct cli_credentials *credentials;
+ struct loadparm_context *lp_ctx = NULL;
+ PyObject *py_lp_ctx = Py_None, *py_credentials = Py_None, *py_basis = Py_None;
+ TALLOC_CTX *mem_ctx = NULL;
+ struct tevent_context *event_ctx;
+ NTSTATUS status;
+
+ const char *kwnames[] = {
+ "binding", "lp_ctx", "credentials", "basis_connection", NULL
+ };
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|OOO:samr", discard_const_p(char *, kwnames), &binding_string, &py_lp_ctx, &py_credentials, &py_basis)) {
+ return NULL;
+ }
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ lp_ctx = lpcfg_from_py_object(mem_ctx, py_lp_ctx);
+ if (lp_ctx == NULL) {
+ PyErr_SetString(PyExc_TypeError, "Expected loadparm context");
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+
+ status = dcerpc_init(lp_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_SetNTSTATUS(status);
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+
+ ret = PyObject_New(dcerpc_InterfaceObject, type);
+ ret->mem_ctx = mem_ctx;
+
+ event_ctx = s4_event_context_init(ret->mem_ctx);
+
+ if (strncmp(binding_string, "irpc:", 5) == 0) {
+ ret->pipe = NULL;
+ status = pyrpc_irpc_connect(ret->mem_ctx, binding_string+5, table,
+ event_ctx, lp_ctx, &ret->binding_handle);
+ } else if (py_basis != Py_None) {
+ struct dcerpc_pipe *base_pipe;
+ PyObject *py_base;
+ PyTypeObject *ClientConnection_Type;
+
+ py_base = PyImport_ImportModule("samba.dcerpc.base");
+ if (py_base == NULL) {
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+
+ ClientConnection_Type = (PyTypeObject *)PyObject_GetAttrString(py_base, "ClientConnection");
+ if (ClientConnection_Type == NULL) {
+ PyErr_SetNone(PyExc_TypeError);
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+
+ if (!PyObject_TypeCheck(py_basis, ClientConnection_Type)) {
+ PyErr_SetString(PyExc_TypeError, "basis_connection must be a DCE/RPC connection");
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+
+ base_pipe = talloc_reference(mem_ctx, ((dcerpc_InterfaceObject *)py_basis)->pipe);
+
+ status = dcerpc_secondary_context(base_pipe, &ret->pipe, table);
+
+ ret->pipe = talloc_steal(ret->mem_ctx, ret->pipe);
+ } else {
+ credentials = cli_credentials_from_py_object(py_credentials);
+ if (credentials == NULL) {
+ PyErr_SetString(PyExc_TypeError, "Expected credentials");
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+ status = dcerpc_pipe_connect(event_ctx, &ret->pipe, binding_string,
+ table, credentials, event_ctx, lp_ctx);
+ }
+ if (NT_STATUS_IS_ERR(status)) {
+ PyErr_SetNTSTATUS(status);
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+
+ if (ret->pipe) {
+ ret->pipe->conn->flags |= DCERPC_NDR_REF_ALLOC;
+ ret->binding_handle = ret->pipe->binding_handle;
+ }
+ return (PyObject *)ret;
+}
+
+static PyObject *py_dcerpc_run_function(dcerpc_InterfaceObject *iface,
+ const struct PyNdrRpcMethodDef *md,
+ PyObject *args, PyObject *kwargs)
+{
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS status;
+ void *r;
+ PyObject *result = Py_None;
+
+ if (md->pack_in_data == NULL || md->unpack_out_data == NULL) {
+ PyErr_SetString(PyExc_NotImplementedError, "No marshalling code available yet");
+ return NULL;
+ }
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ r = talloc_zero_size(mem_ctx, md->table->calls[md->opnum].struct_size);
+ if (r == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ if (!md->pack_in_data(args, kwargs, r)) {
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+
+ status = md->call(iface->binding_handle, mem_ctx, r);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_SetDCERPCStatus(iface->pipe, status);
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+
+ result = md->unpack_out_data(r);
+
+ talloc_free(mem_ctx);
+ return result;
+}
+
+static PyObject *py_dcerpc_call_wrapper(PyObject *self, PyObject *args, void *wrapped, PyObject *kwargs)
+{
+ dcerpc_InterfaceObject *iface = (dcerpc_InterfaceObject *)self;
+ const struct PyNdrRpcMethodDef *md = (const struct PyNdrRpcMethodDef *)wrapped;
+
+ return py_dcerpc_run_function(iface, md, args, kwargs);
+}
+
+bool PyInterface_AddNdrRpcMethods(PyTypeObject *ifacetype, const struct PyNdrRpcMethodDef *mds)
+{
+ int i;
+ for (i = 0; mds[i].name; i++) {
+ PyObject *ret;
+ struct wrapperbase *wb = (struct wrapperbase *)calloc(sizeof(struct wrapperbase), 1);
+
+ wb->name = discard_const_p(char, mds[i].name);
+ wb->flags = PyWrapperFlag_KEYWORDS;
+ wb->wrapper = (wrapperfunc)py_dcerpc_call_wrapper;
+ wb->doc = discard_const_p(char, mds[i].doc);
+
+ ret = PyDescr_NewWrapper(ifacetype, wb, discard_const_p(void, &mds[i]));
+
+ PyDict_SetItemString(ifacetype->tp_dict, mds[i].name,
+ (PyObject *)ret);
+ }
+
+ return true;
+}
+
+void PyErr_SetDCERPCStatus(struct dcerpc_pipe *p, NTSTATUS status)
+{
+ if (p && NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
+ status = dcerpc_fault_to_nt_status(p->last_fault_code);
+ }
+ PyErr_SetNTSTATUS(status);
+}
+
+
+/*
+ take a NDR structure that has a type in a python module and return
+ it as a python object
+
+ r is the NDR structure pointer (a C structure)
+
+ r_ctx is the context that is a parent of r. It will be referenced by
+ the resulting python object
+ */
+PyObject *py_return_ndr_struct(const char *module_name, const char *type_name,
+ TALLOC_CTX *r_ctx, void *r)
+{
+ PyTypeObject *py_type;
+ PyObject *module;
+
+ if (r == NULL) {
+ Py_RETURN_NONE;
+ }
+
+ module = PyImport_ImportModule(module_name);
+ if (module == NULL) {
+ return NULL;
+ }
+
+ py_type = (PyTypeObject *)PyObject_GetAttrString(module, type_name);
+ if (py_type == NULL) {
+ return NULL;
+ }
+
+ return py_talloc_reference_ex(py_type, r_ctx, r);
+}
+
+PyObject *PyString_FromStringOrNULL(const char *str)
+{
+ if (str == NULL) {
+ Py_RETURN_NONE;
+ }
+ return PyString_FromString(str);
+}
diff --git a/source4/librpc/rpc/pyrpc_util.h b/source4/librpc/rpc/pyrpc_util.h
new file mode 100644
index 0000000000..837a33be16
--- /dev/null
+++ b/source4/librpc/rpc/pyrpc_util.h
@@ -0,0 +1,58 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Python interface to DCE/RPC library - utility functions.
+
+ Copyright (C) 2010 Jelmer Vernooij <jelmer@samba.org>
+ Copyright (C) 2010 Andrew Tridgell <tridge@samba.org>
+
+ 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 __PYRPC_UTIL_H__
+#define __PYRPC_UTIL_H__
+
+#include "librpc/rpc/pyrpc.h"
+
+#define PyErr_FromNdrError(err) Py_BuildValue("(is)", err, ndr_map_error2string(err))
+
+#define PyErr_SetNdrError(err) \
+ PyErr_SetObject(PyExc_RuntimeError, PyErr_FromNdrError(err))
+
+void PyErr_SetDCERPCStatus(struct dcerpc_pipe *p, NTSTATUS status);
+
+typedef NTSTATUS (*py_dcerpc_call_fn) (struct dcerpc_binding_handle *, TALLOC_CTX *, void *);
+typedef bool (*py_data_pack_fn) (PyObject *args, PyObject *kwargs, void *r);
+typedef PyObject *(*py_data_unpack_fn) (void *r);
+
+struct PyNdrRpcMethodDef {
+ const char *name;
+ const char *doc;
+ py_dcerpc_call_fn call;
+ py_data_pack_fn pack_in_data;
+ py_data_unpack_fn unpack_out_data;
+ uint32_t opnum;
+ const struct ndr_interface_table *table;
+};
+
+bool py_check_dcerpc_type(PyObject *obj, const char *module, const char *type_name);
+bool PyInterface_AddNdrRpcMethods(PyTypeObject *object, const struct PyNdrRpcMethodDef *mds);
+PyObject *py_dcerpc_interface_init_helper(PyTypeObject *type, PyObject *args, PyObject *kwargs, const struct ndr_interface_table *table);
+
+PyObject *py_return_ndr_struct(const char *module_name, const char *type_name,
+ TALLOC_CTX *r_ctx, void *r);
+
+PyObject *PyString_FromStringOrNULL(const char *str);
+
+#endif /* __PYRPC_UTIL_H__ */