2 Unix SMB/CIFS implementation.
5 Copyright (C) Tim Potter 2003
6 Copyright (C) Andrew Tridgell 2003-2005
7 Copyright (C) Jelmer Vernooij 2004-2005
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "lib/util/dlinklist.h"
25 #include "lib/events/events.h"
26 #include "librpc/rpc/dcerpc.h"
27 #include "librpc/gen_ndr/ndr_misc.h"
28 #include "librpc/gen_ndr/ndr_dcerpc.h"
29 #include "libcli/composite/composite.h"
30 #include "auth/gensec/gensec.h"
32 NTSTATUS dcerpc_init(void)
39 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status);
40 static void dcerpc_ship_next_request(struct dcerpc_connection *c);
42 /* destroy a dcerpc connection */
43 static int dcerpc_connection_destructor(struct dcerpc_connection *conn)
46 conn->free_skipped = true;
49 dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
54 /* initialise a dcerpc connection.
55 the event context is optional
57 static struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
58 struct event_context *ev)
60 struct dcerpc_connection *c;
62 c = talloc_zero(mem_ctx, struct dcerpc_connection);
68 ev = event_context_init(c);
77 if (!talloc_reference(c, ev)) {
82 c->security_state.auth_info = NULL;
83 c->security_state.session_key = dcerpc_generic_session_key;
84 c->security_state.generic_state = NULL;
85 c->binding_string = NULL;
87 c->srv_max_xmit_frag = 0;
88 c->srv_max_recv_frag = 0;
91 talloc_set_destructor(c, dcerpc_connection_destructor);
96 /* initialise a dcerpc pipe. */
97 struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct event_context *ev)
99 struct dcerpc_pipe *p;
101 p = talloc(mem_ctx, struct dcerpc_pipe);
106 p->conn = dcerpc_connection_init(p, ev);
107 if (p->conn == NULL) {
112 p->last_fault_code = 0;
114 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
117 ZERO_STRUCT(p->syntax);
118 ZERO_STRUCT(p->transfer_syntax);
125 choose the next call id to use
127 static uint32_t next_call_id(struct dcerpc_connection *c)
130 if (c->call_id == 0) {
136 /* we need to be able to get/set the fragment length without doing a full
138 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
140 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
141 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
143 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
147 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
149 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
150 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
152 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
156 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
158 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
159 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
161 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
167 setup for a ndr pull, also setting up any flags from the binding string
169 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c,
170 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
172 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
174 if (ndr == NULL) return ndr;
176 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
177 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
180 if (c->flags & DCERPC_NDR_REF_ALLOC) {
181 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
188 parse a data blob into a ncacn_packet structure. This handles both
189 input and output packets
191 static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
192 struct ncacn_packet *pkt)
194 struct ndr_pull *ndr;
195 enum ndr_err_code ndr_err;
197 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
199 return NT_STATUS_NO_MEMORY;
202 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
203 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
206 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
207 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
208 return ndr_map_error2ntstatus(ndr_err);
215 generate a CONNECT level verifier
217 static NTSTATUS dcerpc_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
219 *blob = data_blob_talloc(mem_ctx, NULL, 16);
220 if (blob->data == NULL) {
221 return NT_STATUS_NO_MEMORY;
223 SIVAL(blob->data, 0, 1);
224 memset(blob->data+4, 0, 12);
229 check a CONNECT level verifier
231 static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob)
233 if (blob->length != 16 ||
234 IVAL(blob->data, 0) != 1) {
235 return NT_STATUS_ACCESS_DENIED;
241 parse the authentication information on a dcerpc response packet
243 static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX *mem_ctx,
244 DATA_BLOB *raw_packet,
245 struct ncacn_packet *pkt)
247 struct ndr_pull *ndr;
249 struct dcerpc_auth auth;
251 enum ndr_err_code ndr_err;
253 if (pkt->auth_length == 0 &&
254 c->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
258 auth_blob.length = 8 + pkt->auth_length;
260 /* check for a valid length */
261 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
262 return NT_STATUS_INFO_LENGTH_MISMATCH;
266 pkt->u.response.stub_and_verifier.data +
267 pkt->u.response.stub_and_verifier.length - auth_blob.length;
268 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
270 /* pull the auth structure */
271 ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);
273 return NT_STATUS_NO_MEMORY;
276 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
277 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
280 ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
281 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
282 return ndr_map_error2ntstatus(ndr_err);
284 status = NT_STATUS_OK;
286 /* check signature or unseal the packet */
287 switch (c->security_state.auth_info->auth_level) {
288 case DCERPC_AUTH_LEVEL_PRIVACY:
289 status = gensec_unseal_packet(c->security_state.generic_state,
291 raw_packet->data + DCERPC_REQUEST_LENGTH,
292 pkt->u.response.stub_and_verifier.length,
294 raw_packet->length - auth.credentials.length,
296 memcpy(pkt->u.response.stub_and_verifier.data,
297 raw_packet->data + DCERPC_REQUEST_LENGTH,
298 pkt->u.response.stub_and_verifier.length);
301 case DCERPC_AUTH_LEVEL_INTEGRITY:
302 status = gensec_check_packet(c->security_state.generic_state,
304 pkt->u.response.stub_and_verifier.data,
305 pkt->u.response.stub_and_verifier.length,
307 raw_packet->length - auth.credentials.length,
311 case DCERPC_AUTH_LEVEL_CONNECT:
312 status = dcerpc_check_connect_verifier(&auth.credentials);
315 case DCERPC_AUTH_LEVEL_NONE:
319 status = NT_STATUS_INVALID_LEVEL;
323 /* remove the indicated amount of paddiing */
324 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
325 return NT_STATUS_INFO_LENGTH_MISMATCH;
327 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
334 push a dcerpc request packet into a blob, possibly signing it.
336 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
337 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
338 struct ncacn_packet *pkt)
341 struct ndr_push *ndr;
343 size_t payload_length;
344 enum ndr_err_code ndr_err;
346 /* non-signed packets are simpler */
347 if (!c->security_state.auth_info ||
348 !c->security_state.generic_state) {
349 return ncacn_push_auth(blob, mem_ctx, pkt, c->security_state.auth_info);
352 ndr = ndr_push_init_ctx(mem_ctx);
354 return NT_STATUS_NO_MEMORY;
357 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
358 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
361 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
362 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
365 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
366 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
367 return ndr_map_error2ntstatus(ndr_err);
369 status = NT_STATUS_OK;
371 /* pad to 16 byte multiple in the payload portion of the
372 packet. This matches what w2k3 does */
373 c->security_state.auth_info->auth_pad_length =
374 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
375 ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
377 payload_length = pkt->u.request.stub_and_verifier.length +
378 c->security_state.auth_info->auth_pad_length;
380 /* sign or seal the packet */
381 switch (c->security_state.auth_info->auth_level) {
382 case DCERPC_AUTH_LEVEL_PRIVACY:
383 case DCERPC_AUTH_LEVEL_INTEGRITY:
384 /* We hope this length is accruate. If must be if the
385 * GENSEC mech does AEAD signing of the packet
387 c->security_state.auth_info->credentials
388 = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(c->security_state.generic_state,
390 data_blob_clear(&c->security_state.auth_info->credentials);
393 case DCERPC_AUTH_LEVEL_CONNECT:
394 status = dcerpc_connect_verifier(mem_ctx, &c->security_state.auth_info->credentials);
397 case DCERPC_AUTH_LEVEL_NONE:
398 c->security_state.auth_info->credentials = data_blob(NULL, 0);
402 status = NT_STATUS_INVALID_LEVEL;
406 if (!NT_STATUS_IS_OK(status)) {
410 /* add the auth verifier */
411 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
412 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
413 return ndr_map_error2ntstatus(ndr_err);
415 status = NT_STATUS_OK;
417 /* extract the whole packet as a blob */
418 *blob = ndr_push_blob(ndr);
420 /* fill in the fragment length and auth_length, we can't fill
421 in these earlier as we don't know the signature length (it
422 could be variable length) */
423 dcerpc_set_frag_length(blob, blob->length);
424 /* We hope this value is accruate. If must be if the GENSEC
425 * mech does AEAD signing of the packet headers */
426 dcerpc_set_auth_length(blob, c->security_state.auth_info->credentials.length);
428 /* sign or seal the packet */
429 switch (c->security_state.auth_info->auth_level) {
430 case DCERPC_AUTH_LEVEL_PRIVACY:
431 status = gensec_seal_packet(c->security_state.generic_state,
433 blob->data + DCERPC_REQUEST_LENGTH,
437 c->security_state.auth_info->credentials.length,
439 if (!NT_STATUS_IS_OK(status)) {
442 blob->length -= c->security_state.auth_info->credentials.length;
443 if (!data_blob_append(mem_ctx, blob,
444 creds2.data, creds2.length)) {
445 return NT_STATUS_NO_MEMORY;
447 dcerpc_set_auth_length(blob, creds2.length);
448 if (c->security_state.auth_info->credentials.length == 0) {
449 /* this is needed for krb5 only, to correct the total packet
451 dcerpc_set_frag_length(blob,
452 dcerpc_get_frag_length(blob)
457 case DCERPC_AUTH_LEVEL_INTEGRITY:
458 status = gensec_sign_packet(c->security_state.generic_state,
460 blob->data + DCERPC_REQUEST_LENGTH,
464 c->security_state.auth_info->credentials.length,
466 if (!NT_STATUS_IS_OK(status)) {
469 blob->length -= c->security_state.auth_info->credentials.length;
470 if (!data_blob_append(mem_ctx, blob,
471 creds2.data, creds2.length)) {
472 return NT_STATUS_NO_MEMORY;
474 dcerpc_set_auth_length(blob, creds2.length);
475 if (c->security_state.auth_info->credentials.length == 0) {
476 /* this is needed for krb5 only, to correct the total packet
478 dcerpc_set_frag_length(blob,
479 dcerpc_get_frag_length(blob)
484 case DCERPC_AUTH_LEVEL_CONNECT:
487 case DCERPC_AUTH_LEVEL_NONE:
488 c->security_state.auth_info->credentials = data_blob(NULL, 0);
492 status = NT_STATUS_INVALID_LEVEL;
496 data_blob_free(&c->security_state.auth_info->credentials);
503 fill in the fixed values in a dcerpc header
505 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
508 pkt->rpc_vers_minor = 0;
509 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
512 pkt->drep[0] = DCERPC_DREP_LE;
520 map a bind nak reason to a NTSTATUS
522 static NTSTATUS dcerpc_map_reason(uint16_t reason)
525 case DCERPC_BIND_REASON_ASYNTAX:
526 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
527 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
528 return NT_STATUS_INVALID_PARAMETER;
530 return NT_STATUS_UNSUCCESSFUL;
534 a bind or alter context has failed
536 static void dcerpc_composite_fail(struct rpc_request *req)
538 struct composite_context *c = talloc_get_type(req->async.private_data,
539 struct composite_context);
540 composite_error(c, req->status);
544 remove requests from the pending or queued queues
546 static int dcerpc_req_dequeue(struct rpc_request *req)
548 switch (req->state) {
549 case RPC_REQUEST_QUEUED:
550 DLIST_REMOVE(req->p->conn->request_queue, req);
552 case RPC_REQUEST_PENDING:
553 DLIST_REMOVE(req->p->conn->pending, req);
555 case RPC_REQUEST_DONE:
563 mark the dcerpc connection dead. All outstanding requests get an error
565 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
567 if (conn->dead) return;
571 if (conn->transport.shutdown_pipe) {
572 conn->transport.shutdown_pipe(conn, status);
575 /* all pending requests get the error */
576 while (conn->pending) {
577 struct rpc_request *req = conn->pending;
578 dcerpc_req_dequeue(req);
579 req->state = RPC_REQUEST_DONE;
580 req->status = status;
581 if (req->async.callback) {
582 req->async.callback(req);
586 talloc_set_destructor(conn, NULL);
587 if (conn->free_skipped) {
593 forward declarations of the recv_data handlers for the types of
594 packets we need to handle
596 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
597 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
600 receive a dcerpc reply from the transport. Here we work out what
601 type of reply it is (normal request, bind or alter context) and
602 dispatch to the appropriate handler
604 static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NTSTATUS status)
606 struct ncacn_packet pkt;
608 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
609 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
612 /* the transport may be telling us of a severe error, such as
614 if (!NT_STATUS_IS_OK(status)) {
615 data_blob_free(blob);
616 dcerpc_connection_dead(conn, status);
620 /* parse the basic packet to work out what type of response this is */
621 status = ncacn_pull(conn, blob, blob->data, &pkt);
622 if (!NT_STATUS_IS_OK(status)) {
623 data_blob_free(blob);
624 dcerpc_connection_dead(conn, status);
627 dcerpc_request_recv_data(conn, blob, &pkt);
632 Receive a bind reply from the transport
634 static void dcerpc_bind_recv_handler(struct rpc_request *req,
635 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
637 struct composite_context *c;
638 struct dcerpc_connection *conn;
640 c = talloc_get_type(req->async.private_data, struct composite_context);
642 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
643 DEBUG(2,("dcerpc: bind_nak reason %d\n",
644 pkt->u.bind_nak.reject_reason));
645 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
650 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
651 (pkt->u.bind_ack.num_results == 0) ||
652 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
653 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
659 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
660 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
662 /* the bind_ack might contain a reply set of credentials */
663 if (conn->security_state.auth_info &&
664 pkt->u.bind_ack.auth_info.length) {
665 enum ndr_err_code ndr_err;
666 ndr_err = ndr_pull_struct_blob(
667 &pkt->u.bind_ack.auth_info, conn,
668 conn->security_state.auth_info,
669 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
670 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
671 c->status = ndr_map_error2ntstatus(ndr_err);
672 if (!composite_is_ok(c)) return;
676 req->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
682 handle timeouts of individual dcerpc requests
684 static void dcerpc_timeout_handler(struct event_context *ev, struct timed_event *te,
685 struct timeval t, void *private)
687 struct rpc_request *req = talloc_get_type(private, struct rpc_request);
689 if (req->ignore_timeout) {
690 dcerpc_req_dequeue(req);
691 req->state = RPC_REQUEST_DONE;
692 req->status = NT_STATUS_IO_TIMEOUT;
693 if (req->async.callback) {
694 req->async.callback(req);
699 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
703 send a async dcerpc bind request
705 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
707 const struct ndr_syntax_id *syntax,
708 const struct ndr_syntax_id *transfer_syntax)
710 struct composite_context *c;
711 struct ncacn_packet pkt;
713 struct rpc_request *req;
715 c = composite_create(mem_ctx,p->conn->event_ctx);
716 if (c == NULL) return NULL;
721 p->transfer_syntax = *transfer_syntax;
723 init_ncacn_hdr(p->conn, &pkt);
725 pkt.ptype = DCERPC_PKT_BIND;
726 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
727 pkt.call_id = p->conn->call_id;
730 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
731 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
734 pkt.u.bind.max_xmit_frag = 5840;
735 pkt.u.bind.max_recv_frag = 5840;
736 pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
737 pkt.u.bind.num_contexts = 1;
738 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
739 if (composite_nomem(pkt.u.bind.ctx_list, c)) return c;
740 pkt.u.bind.ctx_list[0].context_id = p->context_id;
741 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
742 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
743 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
744 pkt.u.bind.auth_info = data_blob(NULL, 0);
746 /* construct the NDR form of the packet */
747 c->status = ncacn_push_auth(&blob, c, &pkt,
748 p->conn->security_state.auth_info);
749 if (!composite_is_ok(c)) return c;
751 p->conn->transport.recv_data = dcerpc_recv_data;
754 * we allocate a dcerpc_request so we can be in the same
755 * request queue as normal requests
757 req = talloc_zero(c, struct rpc_request);
758 if (composite_nomem(req, c)) return c;
760 req->state = RPC_REQUEST_PENDING;
761 req->call_id = pkt.call_id;
762 req->async.private_data = c;
763 req->async.callback = dcerpc_composite_fail;
765 req->recv_handler = dcerpc_bind_recv_handler;
766 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
767 talloc_set_destructor(req, dcerpc_req_dequeue);
769 c->status = p->conn->transport.send_request(p->conn, &blob,
771 if (!composite_is_ok(c)) return c;
773 event_add_timed(c->event_ctx, req,
774 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
775 dcerpc_timeout_handler, req);
781 recv side of async dcerpc bind request
783 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
785 NTSTATUS result = composite_wait(ctx);
791 perform a continued bind (and auth3)
793 NTSTATUS dcerpc_auth3(struct dcerpc_connection *c,
796 struct ncacn_packet pkt;
800 init_ncacn_hdr(c, &pkt);
802 pkt.ptype = DCERPC_PKT_AUTH3;
803 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
804 pkt.call_id = next_call_id(c);
806 pkt.u.auth3._pad = 0;
807 pkt.u.auth3.auth_info = data_blob(NULL, 0);
809 /* construct the NDR form of the packet */
810 status = ncacn_push_auth(&blob, mem_ctx, &pkt, c->security_state.auth_info);
811 if (!NT_STATUS_IS_OK(status)) {
815 /* send it on its way */
816 status = c->transport.send_request(c, &blob, false);
817 if (!NT_STATUS_IS_OK(status)) {
826 process a fragment received from the transport layer during a
829 This function frees the data
831 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
832 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
834 struct rpc_request *req;
836 NTSTATUS status = NT_STATUS_OK;
839 if this is an authenticated connection then parse and check
840 the auth info. We have to do this before finding the
841 matching packet, as the request structure might have been
842 removed due to a timeout, but if it has been we still need
843 to run the auth routines so that we don't get the sign/seal
844 info out of step with the server
846 if (c->security_state.auth_info && c->security_state.generic_state &&
847 pkt->ptype == DCERPC_PKT_RESPONSE) {
848 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
851 /* find the matching request */
852 for (req=c->pending;req;req=req->next) {
853 if (pkt->call_id == req->call_id) break;
857 /* useful for testing certain vendors RPC servers */
858 if (req == NULL && c->pending && pkt->call_id == 0) {
859 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
865 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
866 data_blob_free(raw_packet);
870 talloc_steal(req, raw_packet->data);
872 if (req->recv_handler != NULL) {
873 dcerpc_req_dequeue(req);
874 req->state = RPC_REQUEST_DONE;
875 req->recv_handler(req, raw_packet, pkt);
879 if (pkt->ptype == DCERPC_PKT_FAULT) {
880 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
881 req->fault_code = pkt->u.fault.status;
882 req->status = NT_STATUS_NET_WRITE_FAULT;
886 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
887 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
889 req->fault_code = DCERPC_FAULT_OTHER;
890 req->status = NT_STATUS_NET_WRITE_FAULT;
894 /* now check the status from the auth routines, and if it failed then fail
895 this request accordingly */
896 if (!NT_STATUS_IS_OK(status)) {
897 req->status = status;
901 length = pkt->u.response.stub_and_verifier.length;
904 req->payload.data = talloc_realloc(req,
907 req->payload.length + length);
908 if (!req->payload.data) {
909 req->status = NT_STATUS_NO_MEMORY;
912 memcpy(req->payload.data+req->payload.length,
913 pkt->u.response.stub_and_verifier.data, length);
914 req->payload.length += length;
917 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
918 c->transport.send_read(c);
922 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
923 req->flags |= DCERPC_PULL_BIGENDIAN;
925 req->flags &= ~DCERPC_PULL_BIGENDIAN;
930 /* we've got the full payload */
931 req->state = RPC_REQUEST_DONE;
932 DLIST_REMOVE(c->pending, req);
934 if (c->request_queue != NULL) {
935 /* We have to look at shipping further requests before calling
936 * the async function, that one might close the pipe */
937 dcerpc_ship_next_request(c);
940 if (req->async.callback) {
941 req->async.callback(req);
946 perform the send side of a async dcerpc request
948 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
949 const struct GUID *object,
952 DATA_BLOB *stub_data)
954 struct rpc_request *req;
956 p->conn->transport.recv_data = dcerpc_recv_data;
958 req = talloc(p, struct rpc_request);
964 req->call_id = next_call_id(p->conn);
965 req->status = NT_STATUS_OK;
966 req->state = RPC_REQUEST_QUEUED;
967 req->payload = data_blob(NULL, 0);
970 req->async_call = async;
971 req->ignore_timeout = false;
972 req->async.callback = NULL;
973 req->async.private_data = NULL;
974 req->recv_handler = NULL;
976 if (object != NULL) {
977 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
978 if (req->object == NULL) {
987 req->request_data.length = stub_data->length;
988 req->request_data.data = talloc_reference(req, stub_data->data);
989 if (req->request_data.length && req->request_data.data == NULL) {
993 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
994 talloc_set_destructor(req, dcerpc_req_dequeue);
996 dcerpc_ship_next_request(p->conn);
998 if (p->request_timeout) {
999 event_add_timed(dcerpc_event_context(p), req,
1000 timeval_current_ofs(p->request_timeout, 0),
1001 dcerpc_timeout_handler, req);
1008 Send a request using the transport
1011 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
1013 struct rpc_request *req;
1014 struct dcerpc_pipe *p;
1015 DATA_BLOB *stub_data;
1016 struct ncacn_packet pkt;
1018 uint32_t remaining, chunk_size;
1019 bool first_packet = true;
1021 req = c->request_queue;
1027 stub_data = &req->request_data;
1029 if (!req->async_call && (c->pending != NULL)) {
1033 DLIST_REMOVE(c->request_queue, req);
1034 DLIST_ADD(c->pending, req);
1035 req->state = RPC_REQUEST_PENDING;
1037 init_ncacn_hdr(p->conn, &pkt);
1039 remaining = stub_data->length;
1041 /* we can write a full max_recv_frag size, minus the dcerpc
1042 request header size */
1043 chunk_size = p->conn->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
1045 pkt.ptype = DCERPC_PKT_REQUEST;
1046 pkt.call_id = req->call_id;
1047 pkt.auth_length = 0;
1049 pkt.u.request.alloc_hint = remaining;
1050 pkt.u.request.context_id = p->context_id;
1051 pkt.u.request.opnum = req->opnum;
1054 pkt.u.request.object.object = *req->object;
1055 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1056 chunk_size -= ndr_size_GUID(req->object,0);
1059 /* we send a series of pdus without waiting for a reply */
1060 while (remaining > 0 || first_packet) {
1061 uint32_t chunk = MIN(chunk_size, remaining);
1062 bool last_frag = false;
1064 first_packet = false;
1065 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1067 if (remaining == stub_data->length) {
1068 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1070 if (chunk == remaining) {
1071 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1075 pkt.u.request.stub_and_verifier.data = stub_data->data +
1076 (stub_data->length - remaining);
1077 pkt.u.request.stub_and_verifier.length = chunk;
1079 req->status = ncacn_push_request_sign(p->conn, &blob, req, &pkt);
1080 if (!NT_STATUS_IS_OK(req->status)) {
1081 req->state = RPC_REQUEST_DONE;
1082 DLIST_REMOVE(p->conn->pending, req);
1086 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
1087 if (!NT_STATUS_IS_OK(req->status)) {
1088 req->state = RPC_REQUEST_DONE;
1089 DLIST_REMOVE(p->conn->pending, req);
1098 return the event context for a dcerpc pipe
1099 used by callers who wish to operate asynchronously
1101 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
1103 return p->conn->event_ctx;
1109 perform the receive side of a async dcerpc request
1111 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1112 TALLOC_CTX *mem_ctx,
1113 DATA_BLOB *stub_data)
1117 while (req->state != RPC_REQUEST_DONE) {
1118 struct event_context *ctx = dcerpc_event_context(req->p);
1119 if (event_loop_once(ctx) != 0) {
1120 return NT_STATUS_CONNECTION_DISCONNECTED;
1123 *stub_data = req->payload;
1124 status = req->status;
1125 if (stub_data->data) {
1126 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1128 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1129 req->p->last_fault_code = req->fault_code;
1136 perform a full request/response pair on a dcerpc pipe
1138 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1139 struct GUID *object,
1142 TALLOC_CTX *mem_ctx,
1143 DATA_BLOB *stub_data_in,
1144 DATA_BLOB *stub_data_out)
1146 struct rpc_request *req;
1148 req = dcerpc_request_send(p, object, opnum, async, stub_data_in);
1150 return NT_STATUS_NO_MEMORY;
1153 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1158 this is a paranoid NDR validator. For every packet we push onto the wire
1159 we pull it back again, then push it again. Then we compare the raw NDR data
1160 for that to the NDR we initially generated. If they don't match then we know
1161 we must have a bug in either the pull or push side of our code
1163 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1164 TALLOC_CTX *mem_ctx,
1167 ndr_push_flags_fn_t ndr_push,
1168 ndr_pull_flags_fn_t ndr_pull)
1171 struct ndr_pull *pull;
1172 struct ndr_push *push;
1174 enum ndr_err_code ndr_err;
1176 st = talloc_size(mem_ctx, struct_size);
1178 return NT_STATUS_NO_MEMORY;
1181 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1183 return NT_STATUS_NO_MEMORY;
1185 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1187 ndr_err = ndr_pull(pull, NDR_IN, st);
1188 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1189 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1190 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1191 "failed input validation pull - %s",
1193 return ndr_map_error2ntstatus(ndr_err);
1196 push = ndr_push_init_ctx(mem_ctx);
1198 return NT_STATUS_NO_MEMORY;
1201 ndr_err = ndr_push(push, NDR_IN, st);
1202 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1203 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1204 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1205 "failed input validation push - %s",
1207 return ndr_map_error2ntstatus(ndr_err);
1210 blob2 = ndr_push_blob(push);
1212 if (data_blob_cmp(&blob, &blob2) != 0) {
1213 DEBUG(3,("original:\n"));
1214 dump_data(3, blob.data, blob.length);
1215 DEBUG(3,("secondary:\n"));
1216 dump_data(3, blob2.data, blob2.length);
1217 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1218 "failed input validation blobs doesn't match");
1219 return ndr_map_error2ntstatus(ndr_err);
1222 return NT_STATUS_OK;
1226 this is a paranoid NDR input validator. For every packet we pull
1227 from the wire we push it back again then pull and push it
1228 again. Then we compare the raw NDR data for that to the NDR we
1229 initially generated. If they don't match then we know we must have a
1230 bug in either the pull or push side of our code
1232 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1233 struct ndr_pull *pull_in,
1236 ndr_push_flags_fn_t ndr_push,
1237 ndr_pull_flags_fn_t ndr_pull,
1238 ndr_print_function_t ndr_print)
1241 struct ndr_pull *pull;
1242 struct ndr_push *push;
1243 DATA_BLOB blob, blob2;
1244 TALLOC_CTX *mem_ctx = pull_in;
1246 enum ndr_err_code ndr_err;
1248 st = talloc_size(mem_ctx, struct_size);
1250 return NT_STATUS_NO_MEMORY;
1252 memcpy(st, struct_ptr, struct_size);
1254 push = ndr_push_init_ctx(mem_ctx);
1256 return NT_STATUS_NO_MEMORY;
1259 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1260 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1261 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1262 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1263 "failed output validation push - %s",
1265 return ndr_map_error2ntstatus(ndr_err);
1268 blob = ndr_push_blob(push);
1270 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1272 return NT_STATUS_NO_MEMORY;
1275 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1276 ndr_err = ndr_pull(pull, NDR_OUT, st);
1277 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1278 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1279 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1280 "failed output validation pull - %s",
1282 return ndr_map_error2ntstatus(ndr_err);
1285 push = ndr_push_init_ctx(mem_ctx);
1287 return NT_STATUS_NO_MEMORY;
1290 ndr_err = ndr_push(push, NDR_OUT, st);
1291 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1292 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1293 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1294 "failed output validation push2 - %s",
1296 return ndr_map_error2ntstatus(ndr_err);
1299 blob2 = ndr_push_blob(push);
1301 if (data_blob_cmp(&blob, &blob2) != 0) {
1302 DEBUG(3,("original:\n"));
1303 dump_data(3, blob.data, blob.length);
1304 DEBUG(3,("secondary:\n"));
1305 dump_data(3, blob2.data, blob2.length);
1306 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1307 "failed output validation blobs doesn't match");
1308 return ndr_map_error2ntstatus(ndr_err);
1311 /* this checks the printed forms of the two structures, which effectively
1312 tests all of the value() attributes */
1313 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1314 NDR_OUT, struct_ptr);
1315 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1317 if (strcmp(s1, s2) != 0) {
1319 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
1321 /* this is sometimes useful */
1322 printf("VALIDATE ERROR\n");
1323 file_save("wire.dat", s1, strlen(s1));
1324 file_save("gen.dat", s2, strlen(s2));
1325 system("diff -u wire.dat gen.dat");
1327 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1328 "failed output validation strings doesn't match");
1329 return ndr_map_error2ntstatus(ndr_err);
1332 return NT_STATUS_OK;
1337 send a rpc request given a dcerpc_call structure
1339 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1340 const struct GUID *object,
1341 const struct ndr_interface_table *table,
1343 TALLOC_CTX *mem_ctx,
1346 const struct ndr_interface_call *call;
1347 struct ndr_push *push;
1350 struct rpc_request *req;
1351 enum ndr_err_code ndr_err;
1353 call = &table->calls[opnum];
1355 /* setup for a ndr_push_* call */
1356 push = ndr_push_init_ctx(mem_ctx);
1361 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1362 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1365 /* push the structure into a blob */
1366 ndr_err = call->ndr_push(push, NDR_IN, r);
1367 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1368 status = ndr_map_error2ntstatus(ndr_err);
1369 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1370 nt_errstr(status)));
1375 /* retrieve the blob */
1376 request = ndr_push_blob(push);
1378 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1379 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1380 call->ndr_push, call->ndr_pull);
1381 if (!NT_STATUS_IS_OK(status)) {
1382 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1383 nt_errstr(status)));
1389 DEBUG(10,("rpc request data:\n"));
1390 dump_data(10, request.data, request.length);
1392 /* make the actual dcerpc request */
1393 req = dcerpc_request_send(p, object, opnum, table->calls[opnum].async,
1397 req->ndr.table = table;
1398 req->ndr.opnum = opnum;
1399 req->ndr.struct_ptr = r;
1400 req->ndr.mem_ctx = mem_ctx;
1409 receive the answer from a dcerpc_ndr_request_send()
1411 _PUBLIC_ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1413 struct dcerpc_pipe *p = req->p;
1416 struct ndr_pull *pull;
1418 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1419 void *r = req->ndr.struct_ptr;
1420 uint32_t opnum = req->ndr.opnum;
1421 const struct ndr_interface_table *table = req->ndr.table;
1422 const struct ndr_interface_call *call = &table->calls[opnum];
1423 enum ndr_err_code ndr_err;
1425 /* make sure the recv code doesn't free the request, as we
1426 need to grab the flags element before it is freed */
1427 if (talloc_reference(p, req) == NULL) {
1428 return NT_STATUS_NO_MEMORY;
1431 status = dcerpc_request_recv(req, mem_ctx, &response);
1432 if (!NT_STATUS_IS_OK(status)) {
1433 talloc_unlink(p, req);
1439 /* prepare for ndr_pull_* */
1440 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1442 talloc_unlink(p, req);
1443 return NT_STATUS_NO_MEMORY;
1447 pull->data = talloc_steal(pull, pull->data);
1449 talloc_unlink(p, req);
1451 if (flags & DCERPC_PULL_BIGENDIAN) {
1452 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1455 DEBUG(10,("rpc reply data:\n"));
1456 dump_data(10, pull->data, pull->data_size);
1458 /* pull the structure from the blob */
1459 ndr_err = call->ndr_pull(pull, NDR_OUT, r);
1460 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1461 status = ndr_map_error2ntstatus(ndr_err);
1462 dcerpc_log_packet(table, opnum, NDR_OUT,
1467 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1468 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1469 call->ndr_push, call->ndr_pull,
1471 if (!NT_STATUS_IS_OK(status)) {
1472 dcerpc_log_packet(table, opnum, NDR_OUT,
1478 if (pull->offset != pull->data_size) {
1479 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1480 pull->data_size - pull->offset));
1481 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1482 but it turns out that early versions of NT
1483 (specifically NT3.1) add junk onto the end of rpc
1484 packets, so if we want to interoperate at all with
1485 those versions then we need to ignore this error */
1488 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1490 return NT_STATUS_OK;
1495 a useful helper function for synchronous rpc requests
1497 this can be used when you have ndr push/pull functions in the
1500 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1501 const struct GUID *object,
1502 const struct ndr_interface_table *table,
1504 TALLOC_CTX *mem_ctx,
1507 struct rpc_request *req;
1509 req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1511 return NT_STATUS_NO_MEMORY;
1514 return dcerpc_ndr_request_recv(req);
1519 a useful function for retrieving the server name we connected to
1521 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1523 if (!p->conn->transport.peer_name) {
1526 return p->conn->transport.peer_name(p->conn);
1531 get the dcerpc auth_level for a open connection
1533 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1537 if (c->flags & DCERPC_SEAL) {
1538 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1539 } else if (c->flags & DCERPC_SIGN) {
1540 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1541 } else if (c->flags & DCERPC_CONNECT) {
1542 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1544 auth_level = DCERPC_AUTH_LEVEL_NONE;
1550 Receive an alter reply from the transport
1552 static void dcerpc_alter_recv_handler(struct rpc_request *req,
1553 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1555 struct composite_context *c;
1556 struct dcerpc_pipe *recv_pipe;
1558 c = talloc_get_type(req->async.private_data, struct composite_context);
1559 recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1561 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1562 pkt->u.alter_resp.num_results == 1 &&
1563 pkt->u.alter_resp.ctx_list[0].result != 0) {
1564 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1565 pkt->u.alter_resp.ctx_list[0].reason));
1566 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1570 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1571 pkt->u.alter_resp.num_results == 0 ||
1572 pkt->u.alter_resp.ctx_list[0].result != 0) {
1573 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1577 /* the alter_resp might contain a reply set of credentials */
1578 if (recv_pipe->conn->security_state.auth_info &&
1579 pkt->u.alter_resp.auth_info.length) {
1580 enum ndr_err_code ndr_err;
1581 ndr_err = ndr_pull_struct_blob(
1582 &pkt->u.alter_resp.auth_info, recv_pipe,
1583 recv_pipe->conn->security_state.auth_info,
1584 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
1585 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1586 c->status = ndr_map_error2ntstatus(ndr_err);
1587 if (!composite_is_ok(c)) return;
1595 send a dcerpc alter_context request
1597 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
1598 TALLOC_CTX *mem_ctx,
1599 const struct ndr_syntax_id *syntax,
1600 const struct ndr_syntax_id *transfer_syntax)
1602 struct composite_context *c;
1603 struct ncacn_packet pkt;
1605 struct rpc_request *req;
1607 c = composite_create(mem_ctx, p->conn->event_ctx);
1608 if (c == NULL) return NULL;
1610 c->private_data = p;
1612 p->syntax = *syntax;
1613 p->transfer_syntax = *transfer_syntax;
1615 init_ncacn_hdr(p->conn, &pkt);
1617 pkt.ptype = DCERPC_PKT_ALTER;
1618 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1619 pkt.call_id = p->conn->call_id;
1620 pkt.auth_length = 0;
1622 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1623 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1626 pkt.u.alter.max_xmit_frag = 5840;
1627 pkt.u.alter.max_recv_frag = 5840;
1628 pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
1629 pkt.u.alter.num_contexts = 1;
1630 pkt.u.alter.ctx_list = talloc_array(c, struct dcerpc_ctx_list, 1);
1631 if (composite_nomem(pkt.u.alter.ctx_list, c)) return c;
1632 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1633 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1634 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1635 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1636 pkt.u.alter.auth_info = data_blob(NULL, 0);
1638 /* construct the NDR form of the packet */
1639 c->status = ncacn_push_auth(&blob, mem_ctx, &pkt,
1640 p->conn->security_state.auth_info);
1641 if (!composite_is_ok(c)) return c;
1643 p->conn->transport.recv_data = dcerpc_recv_data;
1646 * we allocate a dcerpc_request so we can be in the same
1647 * request queue as normal requests
1649 req = talloc_zero(c, struct rpc_request);
1650 if (composite_nomem(req, c)) return c;
1652 req->state = RPC_REQUEST_PENDING;
1653 req->call_id = pkt.call_id;
1654 req->async.private_data = c;
1655 req->async.callback = dcerpc_composite_fail;
1657 req->recv_handler = dcerpc_alter_recv_handler;
1658 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1659 talloc_set_destructor(req, dcerpc_req_dequeue);
1661 c->status = p->conn->transport.send_request(p->conn, &blob, true);
1662 if (!composite_is_ok(c)) return c;
1664 event_add_timed(c->event_ctx, req,
1665 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1666 dcerpc_timeout_handler, req);
1671 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1673 NTSTATUS result = composite_wait(ctx);
1679 send a dcerpc alter_context request
1681 NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1682 TALLOC_CTX *mem_ctx,
1683 const struct ndr_syntax_id *syntax,
1684 const struct ndr_syntax_id *transfer_syntax)
1686 struct composite_context *creq;
1687 creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1688 return dcerpc_alter_context_recv(creq);