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"
31 #include "param/param.h"
33 NTSTATUS dcerpc_init(void)
35 gensec_init(global_loadparm);
40 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status);
41 static void dcerpc_ship_next_request(struct dcerpc_connection *c);
43 /* destroy a dcerpc connection */
44 static int dcerpc_connection_destructor(struct dcerpc_connection *conn)
47 conn->free_skipped = true;
50 dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
55 /* initialise a dcerpc connection.
56 the event context is optional
58 static struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
59 struct event_context *ev)
61 struct dcerpc_connection *c;
63 c = talloc_zero(mem_ctx, struct dcerpc_connection);
69 ev = event_context_init(c);
78 if (!talloc_reference(c, ev)) {
83 c->security_state.auth_info = NULL;
84 c->security_state.session_key = dcerpc_generic_session_key;
85 c->security_state.generic_state = NULL;
86 c->binding_string = NULL;
88 c->srv_max_xmit_frag = 0;
89 c->srv_max_recv_frag = 0;
92 talloc_set_destructor(c, dcerpc_connection_destructor);
97 /* initialise a dcerpc pipe. */
98 struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct event_context *ev)
100 struct dcerpc_pipe *p;
102 p = talloc(mem_ctx, struct dcerpc_pipe);
107 p->conn = dcerpc_connection_init(p, ev);
108 if (p->conn == NULL) {
113 p->last_fault_code = 0;
115 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
118 ZERO_STRUCT(p->syntax);
119 ZERO_STRUCT(p->transfer_syntax);
126 choose the next call id to use
128 static uint32_t next_call_id(struct dcerpc_connection *c)
131 if (c->call_id == 0) {
137 /* we need to be able to get/set the fragment length without doing a full
139 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
141 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
142 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
144 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
148 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
150 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
151 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
153 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
157 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
159 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
160 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
162 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
168 setup for a ndr pull, also setting up any flags from the binding string
170 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c,
171 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
173 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
175 if (ndr == NULL) return ndr;
177 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
178 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
181 if (c->flags & DCERPC_NDR_REF_ALLOC) {
182 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
189 parse a data blob into a ncacn_packet structure. This handles both
190 input and output packets
192 static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
193 struct ncacn_packet *pkt)
195 struct ndr_pull *ndr;
196 enum ndr_err_code ndr_err;
198 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
200 return NT_STATUS_NO_MEMORY;
203 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
204 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
207 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
208 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
209 return ndr_map_error2ntstatus(ndr_err);
216 generate a CONNECT level verifier
218 static NTSTATUS dcerpc_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
220 *blob = data_blob_talloc(mem_ctx, NULL, 16);
221 if (blob->data == NULL) {
222 return NT_STATUS_NO_MEMORY;
224 SIVAL(blob->data, 0, 1);
225 memset(blob->data+4, 0, 12);
230 check a CONNECT level verifier
232 static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob)
234 if (blob->length != 16 ||
235 IVAL(blob->data, 0) != 1) {
236 return NT_STATUS_ACCESS_DENIED;
242 parse the authentication information on a dcerpc response packet
244 static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX *mem_ctx,
245 DATA_BLOB *raw_packet,
246 struct ncacn_packet *pkt)
248 struct ndr_pull *ndr;
250 struct dcerpc_auth auth;
252 enum ndr_err_code ndr_err;
254 if (pkt->auth_length == 0 &&
255 c->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
259 auth_blob.length = 8 + pkt->auth_length;
261 /* check for a valid length */
262 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
263 return NT_STATUS_INFO_LENGTH_MISMATCH;
267 pkt->u.response.stub_and_verifier.data +
268 pkt->u.response.stub_and_verifier.length - auth_blob.length;
269 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
271 /* pull the auth structure */
272 ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);
274 return NT_STATUS_NO_MEMORY;
277 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
278 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
281 ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
282 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
283 return ndr_map_error2ntstatus(ndr_err);
285 status = NT_STATUS_OK;
287 /* check signature or unseal the packet */
288 switch (c->security_state.auth_info->auth_level) {
289 case DCERPC_AUTH_LEVEL_PRIVACY:
290 status = gensec_unseal_packet(c->security_state.generic_state,
292 raw_packet->data + DCERPC_REQUEST_LENGTH,
293 pkt->u.response.stub_and_verifier.length,
295 raw_packet->length - auth.credentials.length,
297 memcpy(pkt->u.response.stub_and_verifier.data,
298 raw_packet->data + DCERPC_REQUEST_LENGTH,
299 pkt->u.response.stub_and_verifier.length);
302 case DCERPC_AUTH_LEVEL_INTEGRITY:
303 status = gensec_check_packet(c->security_state.generic_state,
305 pkt->u.response.stub_and_verifier.data,
306 pkt->u.response.stub_and_verifier.length,
308 raw_packet->length - auth.credentials.length,
312 case DCERPC_AUTH_LEVEL_CONNECT:
313 status = dcerpc_check_connect_verifier(&auth.credentials);
316 case DCERPC_AUTH_LEVEL_NONE:
320 status = NT_STATUS_INVALID_LEVEL;
324 /* remove the indicated amount of paddiing */
325 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
326 return NT_STATUS_INFO_LENGTH_MISMATCH;
328 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
335 push a dcerpc request packet into a blob, possibly signing it.
337 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
338 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
339 struct ncacn_packet *pkt)
342 struct ndr_push *ndr;
344 size_t payload_length;
345 enum ndr_err_code ndr_err;
347 /* non-signed packets are simpler */
348 if (!c->security_state.auth_info ||
349 !c->security_state.generic_state) {
350 return ncacn_push_auth(blob, mem_ctx, pkt, c->security_state.auth_info);
353 ndr = ndr_push_init_ctx(mem_ctx);
355 return NT_STATUS_NO_MEMORY;
358 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
359 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
362 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
363 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
366 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
367 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
368 return ndr_map_error2ntstatus(ndr_err);
370 status = NT_STATUS_OK;
372 /* pad to 16 byte multiple in the payload portion of the
373 packet. This matches what w2k3 does */
374 c->security_state.auth_info->auth_pad_length =
375 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
376 ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
378 payload_length = pkt->u.request.stub_and_verifier.length +
379 c->security_state.auth_info->auth_pad_length;
381 /* sign or seal the packet */
382 switch (c->security_state.auth_info->auth_level) {
383 case DCERPC_AUTH_LEVEL_PRIVACY:
384 case DCERPC_AUTH_LEVEL_INTEGRITY:
385 /* We hope this length is accruate. If must be if the
386 * GENSEC mech does AEAD signing of the packet
388 c->security_state.auth_info->credentials
389 = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(c->security_state.generic_state,
391 data_blob_clear(&c->security_state.auth_info->credentials);
394 case DCERPC_AUTH_LEVEL_CONNECT:
395 status = dcerpc_connect_verifier(mem_ctx, &c->security_state.auth_info->credentials);
398 case DCERPC_AUTH_LEVEL_NONE:
399 c->security_state.auth_info->credentials = data_blob(NULL, 0);
403 status = NT_STATUS_INVALID_LEVEL;
407 if (!NT_STATUS_IS_OK(status)) {
411 /* add the auth verifier */
412 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
413 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
414 return ndr_map_error2ntstatus(ndr_err);
416 status = NT_STATUS_OK;
418 /* extract the whole packet as a blob */
419 *blob = ndr_push_blob(ndr);
421 /* fill in the fragment length and auth_length, we can't fill
422 in these earlier as we don't know the signature length (it
423 could be variable length) */
424 dcerpc_set_frag_length(blob, blob->length);
425 /* We hope this value is accruate. If must be if the GENSEC
426 * mech does AEAD signing of the packet headers */
427 dcerpc_set_auth_length(blob, c->security_state.auth_info->credentials.length);
429 /* sign or seal the packet */
430 switch (c->security_state.auth_info->auth_level) {
431 case DCERPC_AUTH_LEVEL_PRIVACY:
432 status = gensec_seal_packet(c->security_state.generic_state,
434 blob->data + DCERPC_REQUEST_LENGTH,
438 c->security_state.auth_info->credentials.length,
440 if (!NT_STATUS_IS_OK(status)) {
443 blob->length -= c->security_state.auth_info->credentials.length;
444 if (!data_blob_append(mem_ctx, blob,
445 creds2.data, creds2.length)) {
446 return NT_STATUS_NO_MEMORY;
448 dcerpc_set_auth_length(blob, creds2.length);
449 if (c->security_state.auth_info->credentials.length == 0) {
450 /* this is needed for krb5 only, to correct the total packet
452 dcerpc_set_frag_length(blob,
453 dcerpc_get_frag_length(blob)
458 case DCERPC_AUTH_LEVEL_INTEGRITY:
459 status = gensec_sign_packet(c->security_state.generic_state,
461 blob->data + DCERPC_REQUEST_LENGTH,
465 c->security_state.auth_info->credentials.length,
467 if (!NT_STATUS_IS_OK(status)) {
470 blob->length -= c->security_state.auth_info->credentials.length;
471 if (!data_blob_append(mem_ctx, blob,
472 creds2.data, creds2.length)) {
473 return NT_STATUS_NO_MEMORY;
475 dcerpc_set_auth_length(blob, creds2.length);
476 if (c->security_state.auth_info->credentials.length == 0) {
477 /* this is needed for krb5 only, to correct the total packet
479 dcerpc_set_frag_length(blob,
480 dcerpc_get_frag_length(blob)
485 case DCERPC_AUTH_LEVEL_CONNECT:
488 case DCERPC_AUTH_LEVEL_NONE:
489 c->security_state.auth_info->credentials = data_blob(NULL, 0);
493 status = NT_STATUS_INVALID_LEVEL;
497 data_blob_free(&c->security_state.auth_info->credentials);
504 fill in the fixed values in a dcerpc header
506 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
509 pkt->rpc_vers_minor = 0;
510 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
513 pkt->drep[0] = DCERPC_DREP_LE;
521 map a bind nak reason to a NTSTATUS
523 static NTSTATUS dcerpc_map_reason(uint16_t reason)
526 case DCERPC_BIND_REASON_ASYNTAX:
527 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
528 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
529 return NT_STATUS_INVALID_PARAMETER;
531 return NT_STATUS_UNSUCCESSFUL;
535 a bind or alter context has failed
537 static void dcerpc_composite_fail(struct rpc_request *req)
539 struct composite_context *c = talloc_get_type(req->async.private_data,
540 struct composite_context);
541 composite_error(c, req->status);
545 remove requests from the pending or queued queues
547 static int dcerpc_req_dequeue(struct rpc_request *req)
549 switch (req->state) {
550 case RPC_REQUEST_QUEUED:
551 DLIST_REMOVE(req->p->conn->request_queue, req);
553 case RPC_REQUEST_PENDING:
554 DLIST_REMOVE(req->p->conn->pending, req);
556 case RPC_REQUEST_DONE:
564 mark the dcerpc connection dead. All outstanding requests get an error
566 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
568 if (conn->dead) return;
572 if (conn->transport.shutdown_pipe) {
573 conn->transport.shutdown_pipe(conn, status);
576 /* all pending requests get the error */
577 while (conn->pending) {
578 struct rpc_request *req = conn->pending;
579 dcerpc_req_dequeue(req);
580 req->state = RPC_REQUEST_DONE;
581 req->status = status;
582 if (req->async.callback) {
583 req->async.callback(req);
587 talloc_set_destructor(conn, NULL);
588 if (conn->free_skipped) {
594 forward declarations of the recv_data handlers for the types of
595 packets we need to handle
597 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
598 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
601 receive a dcerpc reply from the transport. Here we work out what
602 type of reply it is (normal request, bind or alter context) and
603 dispatch to the appropriate handler
605 static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NTSTATUS status)
607 struct ncacn_packet pkt;
609 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
610 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
613 /* the transport may be telling us of a severe error, such as
615 if (!NT_STATUS_IS_OK(status)) {
616 data_blob_free(blob);
617 dcerpc_connection_dead(conn, status);
621 /* parse the basic packet to work out what type of response this is */
622 status = ncacn_pull(conn, blob, blob->data, &pkt);
623 if (!NT_STATUS_IS_OK(status)) {
624 data_blob_free(blob);
625 dcerpc_connection_dead(conn, status);
628 dcerpc_request_recv_data(conn, blob, &pkt);
633 Receive a bind reply from the transport
635 static void dcerpc_bind_recv_handler(struct rpc_request *req,
636 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
638 struct composite_context *c;
639 struct dcerpc_connection *conn;
641 c = talloc_get_type(req->async.private_data, struct composite_context);
643 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
644 DEBUG(2,("dcerpc: bind_nak reason %d\n",
645 pkt->u.bind_nak.reject_reason));
646 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
651 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
652 (pkt->u.bind_ack.num_results == 0) ||
653 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
654 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
660 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
661 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
663 /* the bind_ack might contain a reply set of credentials */
664 if (conn->security_state.auth_info &&
665 pkt->u.bind_ack.auth_info.length) {
666 enum ndr_err_code ndr_err;
667 ndr_err = ndr_pull_struct_blob(
668 &pkt->u.bind_ack.auth_info, conn,
669 conn->security_state.auth_info,
670 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
671 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
672 c->status = ndr_map_error2ntstatus(ndr_err);
673 if (!composite_is_ok(c)) return;
677 req->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
683 handle timeouts of individual dcerpc requests
685 static void dcerpc_timeout_handler(struct event_context *ev, struct timed_event *te,
686 struct timeval t, void *private)
688 struct rpc_request *req = talloc_get_type(private, struct rpc_request);
690 if (req->ignore_timeout) {
691 dcerpc_req_dequeue(req);
692 req->state = RPC_REQUEST_DONE;
693 req->status = NT_STATUS_IO_TIMEOUT;
694 if (req->async.callback) {
695 req->async.callback(req);
700 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
704 send a async dcerpc bind request
706 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
708 const struct ndr_syntax_id *syntax,
709 const struct ndr_syntax_id *transfer_syntax)
711 struct composite_context *c;
712 struct ncacn_packet pkt;
714 struct rpc_request *req;
716 c = composite_create(mem_ctx,p->conn->event_ctx);
717 if (c == NULL) return NULL;
722 p->transfer_syntax = *transfer_syntax;
724 init_ncacn_hdr(p->conn, &pkt);
726 pkt.ptype = DCERPC_PKT_BIND;
727 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
728 pkt.call_id = p->conn->call_id;
731 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
732 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
735 pkt.u.bind.max_xmit_frag = 5840;
736 pkt.u.bind.max_recv_frag = 5840;
737 pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
738 pkt.u.bind.num_contexts = 1;
739 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
740 if (composite_nomem(pkt.u.bind.ctx_list, c)) return c;
741 pkt.u.bind.ctx_list[0].context_id = p->context_id;
742 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
743 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
744 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
745 pkt.u.bind.auth_info = data_blob(NULL, 0);
747 /* construct the NDR form of the packet */
748 c->status = ncacn_push_auth(&blob, c, &pkt,
749 p->conn->security_state.auth_info);
750 if (!composite_is_ok(c)) return c;
752 p->conn->transport.recv_data = dcerpc_recv_data;
755 * we allocate a dcerpc_request so we can be in the same
756 * request queue as normal requests
758 req = talloc_zero(c, struct rpc_request);
759 if (composite_nomem(req, c)) return c;
761 req->state = RPC_REQUEST_PENDING;
762 req->call_id = pkt.call_id;
763 req->async.private_data = c;
764 req->async.callback = dcerpc_composite_fail;
766 req->recv_handler = dcerpc_bind_recv_handler;
767 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
768 talloc_set_destructor(req, dcerpc_req_dequeue);
770 c->status = p->conn->transport.send_request(p->conn, &blob,
772 if (!composite_is_ok(c)) return c;
774 event_add_timed(c->event_ctx, req,
775 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
776 dcerpc_timeout_handler, req);
782 recv side of async dcerpc bind request
784 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
786 NTSTATUS result = composite_wait(ctx);
792 perform a continued bind (and auth3)
794 NTSTATUS dcerpc_auth3(struct dcerpc_connection *c,
797 struct ncacn_packet pkt;
801 init_ncacn_hdr(c, &pkt);
803 pkt.ptype = DCERPC_PKT_AUTH3;
804 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
805 pkt.call_id = next_call_id(c);
807 pkt.u.auth3._pad = 0;
808 pkt.u.auth3.auth_info = data_blob(NULL, 0);
810 /* construct the NDR form of the packet */
811 status = ncacn_push_auth(&blob, mem_ctx, &pkt, c->security_state.auth_info);
812 if (!NT_STATUS_IS_OK(status)) {
816 /* send it on its way */
817 status = c->transport.send_request(c, &blob, false);
818 if (!NT_STATUS_IS_OK(status)) {
827 process a fragment received from the transport layer during a
830 This function frees the data
832 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
833 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
835 struct rpc_request *req;
837 NTSTATUS status = NT_STATUS_OK;
840 if this is an authenticated connection then parse and check
841 the auth info. We have to do this before finding the
842 matching packet, as the request structure might have been
843 removed due to a timeout, but if it has been we still need
844 to run the auth routines so that we don't get the sign/seal
845 info out of step with the server
847 if (c->security_state.auth_info && c->security_state.generic_state &&
848 pkt->ptype == DCERPC_PKT_RESPONSE) {
849 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
852 /* find the matching request */
853 for (req=c->pending;req;req=req->next) {
854 if (pkt->call_id == req->call_id) break;
858 /* useful for testing certain vendors RPC servers */
859 if (req == NULL && c->pending && pkt->call_id == 0) {
860 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
866 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
867 data_blob_free(raw_packet);
871 talloc_steal(req, raw_packet->data);
873 if (req->recv_handler != NULL) {
874 dcerpc_req_dequeue(req);
875 req->state = RPC_REQUEST_DONE;
876 req->recv_handler(req, raw_packet, pkt);
880 if (pkt->ptype == DCERPC_PKT_FAULT) {
881 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
882 req->fault_code = pkt->u.fault.status;
883 req->status = NT_STATUS_NET_WRITE_FAULT;
887 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
888 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
890 req->fault_code = DCERPC_FAULT_OTHER;
891 req->status = NT_STATUS_NET_WRITE_FAULT;
895 /* now check the status from the auth routines, and if it failed then fail
896 this request accordingly */
897 if (!NT_STATUS_IS_OK(status)) {
898 req->status = status;
902 length = pkt->u.response.stub_and_verifier.length;
905 req->payload.data = talloc_realloc(req,
908 req->payload.length + length);
909 if (!req->payload.data) {
910 req->status = NT_STATUS_NO_MEMORY;
913 memcpy(req->payload.data+req->payload.length,
914 pkt->u.response.stub_and_verifier.data, length);
915 req->payload.length += length;
918 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
919 c->transport.send_read(c);
923 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
924 req->flags |= DCERPC_PULL_BIGENDIAN;
926 req->flags &= ~DCERPC_PULL_BIGENDIAN;
931 /* we've got the full payload */
932 req->state = RPC_REQUEST_DONE;
933 DLIST_REMOVE(c->pending, req);
935 if (c->request_queue != NULL) {
936 /* We have to look at shipping further requests before calling
937 * the async function, that one might close the pipe */
938 dcerpc_ship_next_request(c);
941 if (req->async.callback) {
942 req->async.callback(req);
947 perform the send side of a async dcerpc request
949 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
950 const struct GUID *object,
953 DATA_BLOB *stub_data)
955 struct rpc_request *req;
957 p->conn->transport.recv_data = dcerpc_recv_data;
959 req = talloc(p, struct rpc_request);
965 req->call_id = next_call_id(p->conn);
966 req->status = NT_STATUS_OK;
967 req->state = RPC_REQUEST_QUEUED;
968 req->payload = data_blob(NULL, 0);
971 req->async_call = async;
972 req->ignore_timeout = false;
973 req->async.callback = NULL;
974 req->async.private_data = NULL;
975 req->recv_handler = NULL;
977 if (object != NULL) {
978 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
979 if (req->object == NULL) {
988 req->request_data.length = stub_data->length;
989 req->request_data.data = talloc_reference(req, stub_data->data);
990 if (req->request_data.length && req->request_data.data == NULL) {
994 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
995 talloc_set_destructor(req, dcerpc_req_dequeue);
997 dcerpc_ship_next_request(p->conn);
999 if (p->request_timeout) {
1000 event_add_timed(dcerpc_event_context(p), req,
1001 timeval_current_ofs(p->request_timeout, 0),
1002 dcerpc_timeout_handler, req);
1009 Send a request using the transport
1012 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
1014 struct rpc_request *req;
1015 struct dcerpc_pipe *p;
1016 DATA_BLOB *stub_data;
1017 struct ncacn_packet pkt;
1019 uint32_t remaining, chunk_size;
1020 bool first_packet = true;
1022 req = c->request_queue;
1028 stub_data = &req->request_data;
1030 if (!req->async_call && (c->pending != NULL)) {
1034 DLIST_REMOVE(c->request_queue, req);
1035 DLIST_ADD(c->pending, req);
1036 req->state = RPC_REQUEST_PENDING;
1038 init_ncacn_hdr(p->conn, &pkt);
1040 remaining = stub_data->length;
1042 /* we can write a full max_recv_frag size, minus the dcerpc
1043 request header size */
1044 chunk_size = p->conn->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
1046 pkt.ptype = DCERPC_PKT_REQUEST;
1047 pkt.call_id = req->call_id;
1048 pkt.auth_length = 0;
1050 pkt.u.request.alloc_hint = remaining;
1051 pkt.u.request.context_id = p->context_id;
1052 pkt.u.request.opnum = req->opnum;
1055 pkt.u.request.object.object = *req->object;
1056 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1057 chunk_size -= ndr_size_GUID(req->object,0);
1060 /* we send a series of pdus without waiting for a reply */
1061 while (remaining > 0 || first_packet) {
1062 uint32_t chunk = MIN(chunk_size, remaining);
1063 bool last_frag = false;
1065 first_packet = false;
1066 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1068 if (remaining == stub_data->length) {
1069 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1071 if (chunk == remaining) {
1072 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1076 pkt.u.request.stub_and_verifier.data = stub_data->data +
1077 (stub_data->length - remaining);
1078 pkt.u.request.stub_and_verifier.length = chunk;
1080 req->status = ncacn_push_request_sign(p->conn, &blob, req, &pkt);
1081 if (!NT_STATUS_IS_OK(req->status)) {
1082 req->state = RPC_REQUEST_DONE;
1083 DLIST_REMOVE(p->conn->pending, req);
1087 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
1088 if (!NT_STATUS_IS_OK(req->status)) {
1089 req->state = RPC_REQUEST_DONE;
1090 DLIST_REMOVE(p->conn->pending, req);
1099 return the event context for a dcerpc pipe
1100 used by callers who wish to operate asynchronously
1102 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
1104 return p->conn->event_ctx;
1110 perform the receive side of a async dcerpc request
1112 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1113 TALLOC_CTX *mem_ctx,
1114 DATA_BLOB *stub_data)
1118 while (req->state != RPC_REQUEST_DONE) {
1119 struct event_context *ctx = dcerpc_event_context(req->p);
1120 if (event_loop_once(ctx) != 0) {
1121 return NT_STATUS_CONNECTION_DISCONNECTED;
1124 *stub_data = req->payload;
1125 status = req->status;
1126 if (stub_data->data) {
1127 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1129 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1130 req->p->last_fault_code = req->fault_code;
1137 perform a full request/response pair on a dcerpc pipe
1139 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1140 struct GUID *object,
1143 TALLOC_CTX *mem_ctx,
1144 DATA_BLOB *stub_data_in,
1145 DATA_BLOB *stub_data_out)
1147 struct rpc_request *req;
1149 req = dcerpc_request_send(p, object, opnum, async, stub_data_in);
1151 return NT_STATUS_NO_MEMORY;
1154 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1159 this is a paranoid NDR validator. For every packet we push onto the wire
1160 we pull it back again, then push it again. Then we compare the raw NDR data
1161 for that to the NDR we initially generated. If they don't match then we know
1162 we must have a bug in either the pull or push side of our code
1164 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1165 TALLOC_CTX *mem_ctx,
1168 ndr_push_flags_fn_t ndr_push,
1169 ndr_pull_flags_fn_t ndr_pull)
1172 struct ndr_pull *pull;
1173 struct ndr_push *push;
1175 enum ndr_err_code ndr_err;
1177 st = talloc_size(mem_ctx, struct_size);
1179 return NT_STATUS_NO_MEMORY;
1182 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1184 return NT_STATUS_NO_MEMORY;
1186 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1188 ndr_err = ndr_pull(pull, NDR_IN, st);
1189 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1190 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1191 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1192 "failed input validation pull - %s",
1194 return ndr_map_error2ntstatus(ndr_err);
1197 push = ndr_push_init_ctx(mem_ctx);
1199 return NT_STATUS_NO_MEMORY;
1202 ndr_err = ndr_push(push, NDR_IN, st);
1203 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1204 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1205 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1206 "failed input validation push - %s",
1208 return ndr_map_error2ntstatus(ndr_err);
1211 blob2 = ndr_push_blob(push);
1213 if (data_blob_cmp(&blob, &blob2) != 0) {
1214 DEBUG(3,("original:\n"));
1215 dump_data(3, blob.data, blob.length);
1216 DEBUG(3,("secondary:\n"));
1217 dump_data(3, blob2.data, blob2.length);
1218 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1219 "failed input validation blobs doesn't match");
1220 return ndr_map_error2ntstatus(ndr_err);
1223 return NT_STATUS_OK;
1227 this is a paranoid NDR input validator. For every packet we pull
1228 from the wire we push it back again then pull and push it
1229 again. Then we compare the raw NDR data for that to the NDR we
1230 initially generated. If they don't match then we know we must have a
1231 bug in either the pull or push side of our code
1233 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1234 struct ndr_pull *pull_in,
1237 ndr_push_flags_fn_t ndr_push,
1238 ndr_pull_flags_fn_t ndr_pull,
1239 ndr_print_function_t ndr_print)
1242 struct ndr_pull *pull;
1243 struct ndr_push *push;
1244 DATA_BLOB blob, blob2;
1245 TALLOC_CTX *mem_ctx = pull_in;
1247 enum ndr_err_code ndr_err;
1249 st = talloc_size(mem_ctx, struct_size);
1251 return NT_STATUS_NO_MEMORY;
1253 memcpy(st, struct_ptr, struct_size);
1255 push = ndr_push_init_ctx(mem_ctx);
1257 return NT_STATUS_NO_MEMORY;
1260 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1261 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1262 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1263 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1264 "failed output validation push - %s",
1266 return ndr_map_error2ntstatus(ndr_err);
1269 blob = ndr_push_blob(push);
1271 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1273 return NT_STATUS_NO_MEMORY;
1276 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1277 ndr_err = ndr_pull(pull, NDR_OUT, st);
1278 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1279 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1280 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1281 "failed output validation pull - %s",
1283 return ndr_map_error2ntstatus(ndr_err);
1286 push = ndr_push_init_ctx(mem_ctx);
1288 return NT_STATUS_NO_MEMORY;
1291 ndr_err = ndr_push(push, NDR_OUT, st);
1292 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1293 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1294 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1295 "failed output validation push2 - %s",
1297 return ndr_map_error2ntstatus(ndr_err);
1300 blob2 = ndr_push_blob(push);
1302 if (data_blob_cmp(&blob, &blob2) != 0) {
1303 DEBUG(3,("original:\n"));
1304 dump_data(3, blob.data, blob.length);
1305 DEBUG(3,("secondary:\n"));
1306 dump_data(3, blob2.data, blob2.length);
1307 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1308 "failed output validation blobs doesn't match");
1309 return ndr_map_error2ntstatus(ndr_err);
1312 /* this checks the printed forms of the two structures, which effectively
1313 tests all of the value() attributes */
1314 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1315 NDR_OUT, struct_ptr);
1316 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1318 if (strcmp(s1, s2) != 0) {
1320 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
1322 /* this is sometimes useful */
1323 printf("VALIDATE ERROR\n");
1324 file_save("wire.dat", s1, strlen(s1));
1325 file_save("gen.dat", s2, strlen(s2));
1326 system("diff -u wire.dat gen.dat");
1328 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1329 "failed output validation strings doesn't match");
1330 return ndr_map_error2ntstatus(ndr_err);
1333 return NT_STATUS_OK;
1338 send a rpc request given a dcerpc_call structure
1340 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1341 const struct GUID *object,
1342 const struct ndr_interface_table *table,
1344 TALLOC_CTX *mem_ctx,
1347 const struct ndr_interface_call *call;
1348 struct ndr_push *push;
1351 struct rpc_request *req;
1352 enum ndr_err_code ndr_err;
1354 call = &table->calls[opnum];
1356 /* setup for a ndr_push_* call */
1357 push = ndr_push_init_ctx(mem_ctx);
1362 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1363 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1366 /* push the structure into a blob */
1367 ndr_err = call->ndr_push(push, NDR_IN, r);
1368 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1369 status = ndr_map_error2ntstatus(ndr_err);
1370 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1371 nt_errstr(status)));
1376 /* retrieve the blob */
1377 request = ndr_push_blob(push);
1379 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1380 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1381 call->ndr_push, call->ndr_pull);
1382 if (!NT_STATUS_IS_OK(status)) {
1383 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1384 nt_errstr(status)));
1390 DEBUG(10,("rpc request data:\n"));
1391 dump_data(10, request.data, request.length);
1393 /* make the actual dcerpc request */
1394 req = dcerpc_request_send(p, object, opnum, table->calls[opnum].async,
1398 req->ndr.table = table;
1399 req->ndr.opnum = opnum;
1400 req->ndr.struct_ptr = r;
1401 req->ndr.mem_ctx = mem_ctx;
1410 receive the answer from a dcerpc_ndr_request_send()
1412 _PUBLIC_ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1414 struct dcerpc_pipe *p = req->p;
1417 struct ndr_pull *pull;
1419 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1420 void *r = req->ndr.struct_ptr;
1421 uint32_t opnum = req->ndr.opnum;
1422 const struct ndr_interface_table *table = req->ndr.table;
1423 const struct ndr_interface_call *call = &table->calls[opnum];
1424 enum ndr_err_code ndr_err;
1426 /* make sure the recv code doesn't free the request, as we
1427 need to grab the flags element before it is freed */
1428 if (talloc_reference(p, req) == NULL) {
1429 return NT_STATUS_NO_MEMORY;
1432 status = dcerpc_request_recv(req, mem_ctx, &response);
1433 if (!NT_STATUS_IS_OK(status)) {
1434 talloc_unlink(p, req);
1440 /* prepare for ndr_pull_* */
1441 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1443 talloc_unlink(p, req);
1444 return NT_STATUS_NO_MEMORY;
1448 pull->data = talloc_steal(pull, pull->data);
1450 talloc_unlink(p, req);
1452 if (flags & DCERPC_PULL_BIGENDIAN) {
1453 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1456 DEBUG(10,("rpc reply data:\n"));
1457 dump_data(10, pull->data, pull->data_size);
1459 /* pull the structure from the blob */
1460 ndr_err = call->ndr_pull(pull, NDR_OUT, r);
1461 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1462 status = ndr_map_error2ntstatus(ndr_err);
1463 dcerpc_log_packet(table, opnum, NDR_OUT,
1468 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1469 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1470 call->ndr_push, call->ndr_pull,
1472 if (!NT_STATUS_IS_OK(status)) {
1473 dcerpc_log_packet(table, opnum, NDR_OUT,
1479 if (pull->offset != pull->data_size) {
1480 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1481 pull->data_size - pull->offset));
1482 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1483 but it turns out that early versions of NT
1484 (specifically NT3.1) add junk onto the end of rpc
1485 packets, so if we want to interoperate at all with
1486 those versions then we need to ignore this error */
1489 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1491 return NT_STATUS_OK;
1496 a useful helper function for synchronous rpc requests
1498 this can be used when you have ndr push/pull functions in the
1501 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1502 const struct GUID *object,
1503 const struct ndr_interface_table *table,
1505 TALLOC_CTX *mem_ctx,
1508 struct rpc_request *req;
1510 req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1512 return NT_STATUS_NO_MEMORY;
1515 return dcerpc_ndr_request_recv(req);
1520 a useful function for retrieving the server name we connected to
1522 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1524 if (!p->conn->transport.target_hostname) {
1525 if (!p->conn->transport.peer_name) {
1528 return p->conn->transport.peer_name(p->conn);
1530 return p->conn->transport.target_hostname(p->conn);
1535 get the dcerpc auth_level for a open connection
1537 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1541 if (c->flags & DCERPC_SEAL) {
1542 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1543 } else if (c->flags & DCERPC_SIGN) {
1544 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1545 } else if (c->flags & DCERPC_CONNECT) {
1546 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1548 auth_level = DCERPC_AUTH_LEVEL_NONE;
1554 Receive an alter reply from the transport
1556 static void dcerpc_alter_recv_handler(struct rpc_request *req,
1557 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1559 struct composite_context *c;
1560 struct dcerpc_pipe *recv_pipe;
1562 c = talloc_get_type(req->async.private_data, struct composite_context);
1563 recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1565 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1566 pkt->u.alter_resp.num_results == 1 &&
1567 pkt->u.alter_resp.ctx_list[0].result != 0) {
1568 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1569 pkt->u.alter_resp.ctx_list[0].reason));
1570 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1574 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1575 pkt->u.alter_resp.num_results == 0 ||
1576 pkt->u.alter_resp.ctx_list[0].result != 0) {
1577 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1581 /* the alter_resp might contain a reply set of credentials */
1582 if (recv_pipe->conn->security_state.auth_info &&
1583 pkt->u.alter_resp.auth_info.length) {
1584 enum ndr_err_code ndr_err;
1585 ndr_err = ndr_pull_struct_blob(
1586 &pkt->u.alter_resp.auth_info, recv_pipe,
1587 recv_pipe->conn->security_state.auth_info,
1588 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
1589 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1590 c->status = ndr_map_error2ntstatus(ndr_err);
1591 if (!composite_is_ok(c)) return;
1599 send a dcerpc alter_context request
1601 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
1602 TALLOC_CTX *mem_ctx,
1603 const struct ndr_syntax_id *syntax,
1604 const struct ndr_syntax_id *transfer_syntax)
1606 struct composite_context *c;
1607 struct ncacn_packet pkt;
1609 struct rpc_request *req;
1611 c = composite_create(mem_ctx, p->conn->event_ctx);
1612 if (c == NULL) return NULL;
1614 c->private_data = p;
1616 p->syntax = *syntax;
1617 p->transfer_syntax = *transfer_syntax;
1619 init_ncacn_hdr(p->conn, &pkt);
1621 pkt.ptype = DCERPC_PKT_ALTER;
1622 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1623 pkt.call_id = p->conn->call_id;
1624 pkt.auth_length = 0;
1626 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1627 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1630 pkt.u.alter.max_xmit_frag = 5840;
1631 pkt.u.alter.max_recv_frag = 5840;
1632 pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
1633 pkt.u.alter.num_contexts = 1;
1634 pkt.u.alter.ctx_list = talloc_array(c, struct dcerpc_ctx_list, 1);
1635 if (composite_nomem(pkt.u.alter.ctx_list, c)) return c;
1636 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1637 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1638 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1639 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1640 pkt.u.alter.auth_info = data_blob(NULL, 0);
1642 /* construct the NDR form of the packet */
1643 c->status = ncacn_push_auth(&blob, mem_ctx, &pkt,
1644 p->conn->security_state.auth_info);
1645 if (!composite_is_ok(c)) return c;
1647 p->conn->transport.recv_data = dcerpc_recv_data;
1650 * we allocate a dcerpc_request so we can be in the same
1651 * request queue as normal requests
1653 req = talloc_zero(c, struct rpc_request);
1654 if (composite_nomem(req, c)) return c;
1656 req->state = RPC_REQUEST_PENDING;
1657 req->call_id = pkt.call_id;
1658 req->async.private_data = c;
1659 req->async.callback = dcerpc_composite_fail;
1661 req->recv_handler = dcerpc_alter_recv_handler;
1662 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1663 talloc_set_destructor(req, dcerpc_req_dequeue);
1665 c->status = p->conn->transport.send_request(p->conn, &blob, true);
1666 if (!composite_is_ok(c)) return c;
1668 event_add_timed(c->event_ctx, req,
1669 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1670 dcerpc_timeout_handler, req);
1675 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1677 NTSTATUS result = composite_wait(ctx);
1683 send a dcerpc alter_context request
1685 NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1686 TALLOC_CTX *mem_ctx,
1687 const struct ndr_syntax_id *syntax,
1688 const struct ndr_syntax_id *transfer_syntax)
1690 struct composite_context *creq;
1691 creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1692 return dcerpc_alter_context_recv(creq);