r22470: merge handling of broken connections from wins replication client code
[Samba.git] / source / librpc / rpc / dcerpc.c
blob79e897313dd842a5a26078974c5cf3e4571d1d73
1 /*
2 Unix SMB/CIFS implementation.
3 raw dcerpc operations
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 2 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, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "includes.h"
25 #include "lib/util/dlinklist.h"
26 #include "lib/events/events.h"
27 #include "librpc/rpc/dcerpc.h"
28 #include "librpc/gen_ndr/ndr_misc.h"
29 #include "librpc/gen_ndr/ndr_dcerpc.h"
30 #include "libcli/composite/composite.h"
31 #include "auth/gensec/gensec.h"
33 NTSTATUS dcerpc_init(void)
35 gensec_init();
37 return NT_STATUS_OK;
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)
46 if (conn->dead) {
47 conn->free_skipped = True;
48 return -1;
50 dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
51 return 0;
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);
64 if (!c) {
65 return NULL;
68 if (ev == NULL) {
69 ev = event_context_init(c);
70 if (ev == NULL) {
71 talloc_free(c);
72 return NULL;
76 c->event_ctx = ev;
78 if (!talloc_reference(c, ev)) {
79 talloc_free(c);
80 return NULL;
82 c->call_id = 1;
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;
87 c->flags = 0;
88 c->srv_max_xmit_frag = 0;
89 c->srv_max_recv_frag = 0;
90 c->pending = NULL;
92 talloc_set_destructor(c, dcerpc_connection_destructor);
94 return c;
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);
103 if (!p) {
104 return NULL;
107 p->conn = dcerpc_connection_init(p, ev);
108 if (p->conn == NULL) {
109 talloc_free(p);
110 return NULL;
113 p->last_fault_code = 0;
114 p->context_id = 0;
115 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
116 p->binding = NULL;
118 ZERO_STRUCT(p->syntax);
119 ZERO_STRUCT(p->transfer_syntax);
121 return p;
126 choose the next call id to use
128 static uint32_t next_call_id(struct dcerpc_connection *c)
130 c->call_id++;
131 if (c->call_id == 0) {
132 c->call_id++;
134 return c->call_id;
137 /* we need to be able to get/set the fragment length without doing a full
138 decode */
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);
143 } else {
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);
152 } else {
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);
161 } else {
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;
185 return ndr;
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;
197 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
198 if (!ndr) {
199 return NT_STATUS_NO_MEMORY;
202 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
203 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
206 return ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
210 generate a CONNECT level verifier
212 static NTSTATUS dcerpc_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
214 *blob = data_blob_talloc(mem_ctx, NULL, 16);
215 if (blob->data == NULL) {
216 return NT_STATUS_NO_MEMORY;
218 SIVAL(blob->data, 0, 1);
219 memset(blob->data+4, 0, 12);
220 return NT_STATUS_OK;
224 check a CONNECT level verifier
226 static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob)
228 if (blob->length != 16 ||
229 IVAL(blob->data, 0) != 1) {
230 return NT_STATUS_ACCESS_DENIED;
232 return NT_STATUS_OK;
236 parse the authentication information on a dcerpc response packet
238 static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX *mem_ctx,
239 DATA_BLOB *raw_packet,
240 struct ncacn_packet *pkt)
242 struct ndr_pull *ndr;
243 NTSTATUS status;
244 struct dcerpc_auth auth;
245 DATA_BLOB auth_blob;
247 if (pkt->auth_length == 0 &&
248 c->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
249 return NT_STATUS_OK;
252 auth_blob.length = 8 + pkt->auth_length;
254 /* check for a valid length */
255 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
256 return NT_STATUS_INFO_LENGTH_MISMATCH;
259 auth_blob.data =
260 pkt->u.response.stub_and_verifier.data +
261 pkt->u.response.stub_and_verifier.length - auth_blob.length;
262 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
264 /* pull the auth structure */
265 ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);
266 if (!ndr) {
267 return NT_STATUS_NO_MEMORY;
270 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
271 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
274 status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
275 if (!NT_STATUS_IS_OK(status)) {
276 return status;
279 /* check signature or unseal the packet */
280 switch (c->security_state.auth_info->auth_level) {
281 case DCERPC_AUTH_LEVEL_PRIVACY:
282 status = gensec_unseal_packet(c->security_state.generic_state,
283 mem_ctx,
284 raw_packet->data + DCERPC_REQUEST_LENGTH,
285 pkt->u.response.stub_and_verifier.length,
286 raw_packet->data,
287 raw_packet->length - auth.credentials.length,
288 &auth.credentials);
289 memcpy(pkt->u.response.stub_and_verifier.data,
290 raw_packet->data + DCERPC_REQUEST_LENGTH,
291 pkt->u.response.stub_and_verifier.length);
292 break;
294 case DCERPC_AUTH_LEVEL_INTEGRITY:
295 status = gensec_check_packet(c->security_state.generic_state,
296 mem_ctx,
297 pkt->u.response.stub_and_verifier.data,
298 pkt->u.response.stub_and_verifier.length,
299 raw_packet->data,
300 raw_packet->length - auth.credentials.length,
301 &auth.credentials);
302 break;
304 case DCERPC_AUTH_LEVEL_CONNECT:
305 status = dcerpc_check_connect_verifier(&auth.credentials);
306 break;
308 case DCERPC_AUTH_LEVEL_NONE:
309 break;
311 default:
312 status = NT_STATUS_INVALID_LEVEL;
313 break;
316 /* remove the indicated amount of paddiing */
317 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
318 return NT_STATUS_INFO_LENGTH_MISMATCH;
320 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
322 return status;
327 push a dcerpc request packet into a blob, possibly signing it.
329 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
330 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
331 struct ncacn_packet *pkt)
333 NTSTATUS status;
334 struct ndr_push *ndr;
335 DATA_BLOB creds2;
336 size_t payload_length;
338 /* non-signed packets are simpler */
339 if (!c->security_state.auth_info ||
340 !c->security_state.generic_state) {
341 return ncacn_push_auth(blob, mem_ctx, pkt, c->security_state.auth_info);
344 ndr = ndr_push_init_ctx(mem_ctx);
345 if (!ndr) {
346 return NT_STATUS_NO_MEMORY;
349 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
350 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
353 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
354 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
357 status = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
358 if (!NT_STATUS_IS_OK(status)) {
359 return status;
362 /* pad to 16 byte multiple in the payload portion of the
363 packet. This matches what w2k3 does */
364 c->security_state.auth_info->auth_pad_length =
365 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
366 ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
368 payload_length = pkt->u.request.stub_and_verifier.length +
369 c->security_state.auth_info->auth_pad_length;
371 /* sign or seal the packet */
372 switch (c->security_state.auth_info->auth_level) {
373 case DCERPC_AUTH_LEVEL_PRIVACY:
374 case DCERPC_AUTH_LEVEL_INTEGRITY:
375 /* We hope this length is accruate. If must be if the
376 * GENSEC mech does AEAD signing of the packet
377 * headers */
378 c->security_state.auth_info->credentials
379 = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(c->security_state.generic_state,
380 payload_length));
381 data_blob_clear(&c->security_state.auth_info->credentials);
382 break;
384 case DCERPC_AUTH_LEVEL_CONNECT:
385 status = dcerpc_connect_verifier(mem_ctx, &c->security_state.auth_info->credentials);
386 break;
388 case DCERPC_AUTH_LEVEL_NONE:
389 c->security_state.auth_info->credentials = data_blob(NULL, 0);
390 break;
392 default:
393 status = NT_STATUS_INVALID_LEVEL;
394 break;
397 if (!NT_STATUS_IS_OK(status)) {
398 return status;
401 /* add the auth verifier */
402 status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
403 if (!NT_STATUS_IS_OK(status)) {
404 return status;
407 /* extract the whole packet as a blob */
408 *blob = ndr_push_blob(ndr);
410 /* fill in the fragment length and auth_length, we can't fill
411 in these earlier as we don't know the signature length (it
412 could be variable length) */
413 dcerpc_set_frag_length(blob, blob->length);
414 /* We hope this value is accruate. If must be if the GENSEC
415 * mech does AEAD signing of the packet headers */
416 dcerpc_set_auth_length(blob, c->security_state.auth_info->credentials.length);
418 /* sign or seal the packet */
419 switch (c->security_state.auth_info->auth_level) {
420 case DCERPC_AUTH_LEVEL_PRIVACY:
421 status = gensec_seal_packet(c->security_state.generic_state,
422 mem_ctx,
423 blob->data + DCERPC_REQUEST_LENGTH,
424 payload_length,
425 blob->data,
426 blob->length -
427 c->security_state.auth_info->credentials.length,
428 &creds2);
429 if (!NT_STATUS_IS_OK(status)) {
430 return status;
432 blob->length -= c->security_state.auth_info->credentials.length;
433 status = data_blob_append(mem_ctx, blob,
434 creds2.data, creds2.length);
435 if (!NT_STATUS_IS_OK(status)) {
436 return status;
438 dcerpc_set_auth_length(blob, creds2.length);
439 if (c->security_state.auth_info->credentials.length == 0) {
440 /* this is needed for krb5 only, to correct the total packet
441 length */
442 dcerpc_set_frag_length(blob,
443 dcerpc_get_frag_length(blob)
444 +creds2.length);
446 break;
448 case DCERPC_AUTH_LEVEL_INTEGRITY:
449 status = gensec_sign_packet(c->security_state.generic_state,
450 mem_ctx,
451 blob->data + DCERPC_REQUEST_LENGTH,
452 payload_length,
453 blob->data,
454 blob->length -
455 c->security_state.auth_info->credentials.length,
456 &creds2);
457 if (!NT_STATUS_IS_OK(status)) {
458 return status;
460 blob->length -= c->security_state.auth_info->credentials.length;
461 status = data_blob_append(mem_ctx, blob,
462 creds2.data, creds2.length);
463 if (!NT_STATUS_IS_OK(status)) {
464 return status;
466 dcerpc_set_auth_length(blob, creds2.length);
467 if (c->security_state.auth_info->credentials.length == 0) {
468 /* this is needed for krb5 only, to correct the total packet
469 length */
470 dcerpc_set_frag_length(blob,
471 dcerpc_get_frag_length(blob)
472 +creds2.length);
474 break;
476 case DCERPC_AUTH_LEVEL_CONNECT:
477 break;
479 case DCERPC_AUTH_LEVEL_NONE:
480 c->security_state.auth_info->credentials = data_blob(NULL, 0);
481 break;
483 default:
484 status = NT_STATUS_INVALID_LEVEL;
485 break;
488 data_blob_free(&c->security_state.auth_info->credentials);
490 return NT_STATUS_OK;
495 fill in the fixed values in a dcerpc header
497 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
499 pkt->rpc_vers = 5;
500 pkt->rpc_vers_minor = 0;
501 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
502 pkt->drep[0] = 0;
503 } else {
504 pkt->drep[0] = DCERPC_DREP_LE;
506 pkt->drep[1] = 0;
507 pkt->drep[2] = 0;
508 pkt->drep[3] = 0;
512 map a bind nak reason to a NTSTATUS
514 static NTSTATUS dcerpc_map_reason(uint16_t reason)
516 switch (reason) {
517 case DCERPC_BIND_REASON_ASYNTAX:
518 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
519 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
520 return NT_STATUS_INVALID_PARAMETER;
522 return NT_STATUS_UNSUCCESSFUL;
526 a bind or alter context has failed
528 static void dcerpc_composite_fail(struct rpc_request *req)
530 struct composite_context *c = talloc_get_type(req->async.private,
531 struct composite_context);
532 composite_error(c, req->status);
536 remove requests from the pending or queued queues
538 static int dcerpc_req_dequeue(struct rpc_request *req)
540 switch (req->state) {
541 case RPC_REQUEST_QUEUED:
542 DLIST_REMOVE(req->p->conn->request_queue, req);
543 break;
544 case RPC_REQUEST_PENDING:
545 DLIST_REMOVE(req->p->conn->pending, req);
546 break;
547 case RPC_REQUEST_DONE:
548 break;
550 return 0;
555 mark the dcerpc connection dead. All outstanding requests get an error
557 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
559 if (conn->dead) return;
561 conn->dead = true;
563 if (conn->transport.shutdown_pipe) {
564 conn->transport.shutdown_pipe(conn, status);
567 /* all pending requests get the error */
568 while (conn->pending) {
569 struct rpc_request *req = conn->pending;
570 dcerpc_req_dequeue(req);
571 req->state = RPC_REQUEST_DONE;
572 req->status = status;
573 if (req->async.callback) {
574 req->async.callback(req);
578 talloc_set_destructor(conn, NULL);
579 if (conn->free_skipped) {
580 talloc_free(conn);
585 forward declarations of the recv_data handlers for the types of
586 packets we need to handle
588 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
589 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
592 receive a dcerpc reply from the transport. Here we work out what
593 type of reply it is (normal request, bind or alter context) and
594 dispatch to the appropriate handler
596 static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NTSTATUS status)
598 struct ncacn_packet pkt;
600 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
601 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
604 /* the transport may be telling us of a severe error, such as
605 a dropped socket */
606 if (!NT_STATUS_IS_OK(status)) {
607 data_blob_free(blob);
608 dcerpc_connection_dead(conn, status);
609 return;
612 /* parse the basic packet to work out what type of response this is */
613 status = ncacn_pull(conn, blob, blob->data, &pkt);
614 if (!NT_STATUS_IS_OK(status)) {
615 data_blob_free(blob);
616 dcerpc_connection_dead(conn, status);
619 dcerpc_request_recv_data(conn, blob, &pkt);
624 Receive a bind reply from the transport
626 static void dcerpc_bind_recv_handler(struct rpc_request *req,
627 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
629 struct composite_context *c;
630 struct dcerpc_connection *conn;
632 c = talloc_get_type(req->async.private, struct composite_context);
634 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
635 DEBUG(2,("dcerpc: bind_nak reason %d\n",
636 pkt->u.bind_nak.reject_reason));
637 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
638 reject_reason));
639 return;
642 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
643 (pkt->u.bind_ack.num_results == 0) ||
644 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
645 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
646 return;
649 conn = req->p->conn;
651 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
652 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
654 /* the bind_ack might contain a reply set of credentials */
655 if (conn->security_state.auth_info &&
656 pkt->u.bind_ack.auth_info.length) {
657 c->status = ndr_pull_struct_blob(
658 &pkt->u.bind_ack.auth_info, conn,
659 conn->security_state.auth_info,
660 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
661 if (!composite_is_ok(c)) return;
664 req->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
666 composite_done(c);
670 handle timeouts of individual dcerpc requests
672 static void dcerpc_timeout_handler(struct event_context *ev, struct timed_event *te,
673 struct timeval t, void *private)
675 struct rpc_request *req = talloc_get_type(private, struct rpc_request);
676 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
680 send a async dcerpc bind request
682 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
683 TALLOC_CTX *mem_ctx,
684 const struct dcerpc_syntax_id *syntax,
685 const struct dcerpc_syntax_id *transfer_syntax)
687 struct composite_context *c;
688 struct ncacn_packet pkt;
689 DATA_BLOB blob;
690 struct rpc_request *req;
692 c = composite_create(mem_ctx,p->conn->event_ctx);
693 if (c == NULL) return NULL;
695 c->private_data = p;
697 p->syntax = *syntax;
698 p->transfer_syntax = *transfer_syntax;
700 init_ncacn_hdr(p->conn, &pkt);
702 pkt.ptype = DCERPC_PKT_BIND;
703 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
704 pkt.call_id = p->conn->call_id;
705 pkt.auth_length = 0;
707 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
708 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
711 pkt.u.bind.max_xmit_frag = 5840;
712 pkt.u.bind.max_recv_frag = 5840;
713 pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
714 pkt.u.bind.num_contexts = 1;
715 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
716 if (composite_nomem(pkt.u.bind.ctx_list, c)) return c;
717 pkt.u.bind.ctx_list[0].context_id = p->context_id;
718 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
719 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
720 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
721 pkt.u.bind.auth_info = data_blob(NULL, 0);
723 /* construct the NDR form of the packet */
724 c->status = ncacn_push_auth(&blob, c, &pkt,
725 p->conn->security_state.auth_info);
726 if (!composite_is_ok(c)) return c;
728 p->conn->transport.recv_data = dcerpc_recv_data;
731 * we allocate a dcerpc_request so we can be in the same
732 * request queue as normal requests
734 req = talloc_zero(c, struct rpc_request);
735 if (composite_nomem(req, c)) return c;
737 req->state = RPC_REQUEST_PENDING;
738 req->call_id = pkt.call_id;
739 req->async.private = c;
740 req->async.callback = dcerpc_composite_fail;
741 req->p = p;
742 req->recv_handler = dcerpc_bind_recv_handler;
743 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
744 talloc_set_destructor(req, dcerpc_req_dequeue);
746 c->status = p->conn->transport.send_request(p->conn, &blob,
747 True);
748 if (!composite_is_ok(c)) return c;
750 event_add_timed(c->event_ctx, req,
751 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
752 dcerpc_timeout_handler, req);
754 return c;
758 recv side of async dcerpc bind request
760 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
762 NTSTATUS result = composite_wait(ctx);
763 talloc_free(ctx);
764 return result;
768 perform a continued bind (and auth3)
770 NTSTATUS dcerpc_auth3(struct dcerpc_connection *c,
771 TALLOC_CTX *mem_ctx)
773 struct ncacn_packet pkt;
774 NTSTATUS status;
775 DATA_BLOB blob;
777 init_ncacn_hdr(c, &pkt);
779 pkt.ptype = DCERPC_PKT_AUTH3;
780 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
781 pkt.call_id = next_call_id(c);
782 pkt.auth_length = 0;
783 pkt.u.auth3._pad = 0;
784 pkt.u.auth3.auth_info = data_blob(NULL, 0);
786 /* construct the NDR form of the packet */
787 status = ncacn_push_auth(&blob, mem_ctx, &pkt, c->security_state.auth_info);
788 if (!NT_STATUS_IS_OK(status)) {
789 return status;
792 /* send it on its way */
793 status = c->transport.send_request(c, &blob, False);
794 if (!NT_STATUS_IS_OK(status)) {
795 return status;
798 return status;
803 process a fragment received from the transport layer during a
804 request
806 This function frees the data
808 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
809 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
811 struct rpc_request *req;
812 uint_t length;
813 NTSTATUS status = NT_STATUS_OK;
816 if this is an authenticated connection then parse and check
817 the auth info. We have to do this before finding the
818 matching packet, as the request structure might have been
819 removed due to a timeout, but if it has been we still need
820 to run the auth routines so that we don't get the sign/seal
821 info out of step with the server
823 if (c->security_state.auth_info && c->security_state.generic_state &&
824 pkt->ptype == DCERPC_PKT_RESPONSE) {
825 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
828 /* find the matching request */
829 for (req=c->pending;req;req=req->next) {
830 if (pkt->call_id == req->call_id) break;
833 #if 0
834 /* useful for testing certain vendors RPC servers */
835 if (req == NULL && c->pending && pkt->call_id == 0) {
836 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
837 req = c->pending;
839 #endif
841 if (req == NULL) {
842 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
843 data_blob_free(raw_packet);
844 return;
847 talloc_steal(req, raw_packet->data);
849 if (req->recv_handler != NULL) {
850 dcerpc_req_dequeue(req);
851 req->state = RPC_REQUEST_DONE;
852 req->recv_handler(req, raw_packet, pkt);
853 return;
856 if (pkt->ptype == DCERPC_PKT_FAULT) {
857 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
858 req->fault_code = pkt->u.fault.status;
859 req->status = NT_STATUS_NET_WRITE_FAULT;
860 goto req_done;
863 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
864 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
865 (int)pkt->ptype));
866 req->fault_code = DCERPC_FAULT_OTHER;
867 req->status = NT_STATUS_NET_WRITE_FAULT;
868 goto req_done;
871 /* now check the status from the auth routines, and if it failed then fail
872 this request accordingly */
873 if (!NT_STATUS_IS_OK(status)) {
874 req->status = status;
875 goto req_done;
878 length = pkt->u.response.stub_and_verifier.length;
880 if (length > 0) {
881 req->payload.data = talloc_realloc(req,
882 req->payload.data,
883 uint8_t,
884 req->payload.length + length);
885 if (!req->payload.data) {
886 req->status = NT_STATUS_NO_MEMORY;
887 goto req_done;
889 memcpy(req->payload.data+req->payload.length,
890 pkt->u.response.stub_and_verifier.data, length);
891 req->payload.length += length;
894 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
895 c->transport.send_read(c);
896 return;
899 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
900 req->flags |= DCERPC_PULL_BIGENDIAN;
901 } else {
902 req->flags &= ~DCERPC_PULL_BIGENDIAN;
906 req_done:
907 /* we've got the full payload */
908 req->state = RPC_REQUEST_DONE;
909 DLIST_REMOVE(c->pending, req);
911 if (c->request_queue != NULL) {
912 /* We have to look at shipping further requests before calling
913 * the async function, that one might close the pipe */
914 dcerpc_ship_next_request(c);
917 if (req->async.callback) {
918 req->async.callback(req);
923 perform the send side of a async dcerpc request
925 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
926 const struct GUID *object,
927 uint16_t opnum,
928 BOOL async,
929 DATA_BLOB *stub_data)
931 struct rpc_request *req;
933 p->conn->transport.recv_data = dcerpc_recv_data;
935 req = talloc(p, struct rpc_request);
936 if (req == NULL) {
937 return NULL;
940 req->p = p;
941 req->call_id = next_call_id(p->conn);
942 req->status = NT_STATUS_OK;
943 req->state = RPC_REQUEST_QUEUED;
944 req->payload = data_blob(NULL, 0);
945 req->flags = 0;
946 req->fault_code = 0;
947 req->async_call = async;
948 req->async.callback = NULL;
949 req->async.private = NULL;
950 req->recv_handler = NULL;
952 if (object != NULL) {
953 req->object = talloc_memdup(req, object, sizeof(*object));
954 if (req->object == NULL) {
955 talloc_free(req);
956 return NULL;
958 } else {
959 req->object = NULL;
962 req->opnum = opnum;
963 req->request_data.length = stub_data->length;
964 req->request_data.data = talloc_reference(req, stub_data->data);
965 if (req->request_data.length && req->request_data.data == NULL) {
966 return NULL;
969 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
970 talloc_set_destructor(req, dcerpc_req_dequeue);
972 dcerpc_ship_next_request(p->conn);
974 if (p->request_timeout) {
975 event_add_timed(dcerpc_event_context(p), req,
976 timeval_current_ofs(p->request_timeout, 0),
977 dcerpc_timeout_handler, req);
980 return req;
984 Send a request using the transport
987 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
989 struct rpc_request *req;
990 struct dcerpc_pipe *p;
991 DATA_BLOB *stub_data;
992 struct ncacn_packet pkt;
993 DATA_BLOB blob;
994 uint32_t remaining, chunk_size;
995 BOOL first_packet = True;
997 req = c->request_queue;
998 if (req == NULL) {
999 return;
1002 p = req->p;
1003 stub_data = &req->request_data;
1005 if (!req->async_call && (c->pending != NULL)) {
1006 return;
1009 DLIST_REMOVE(c->request_queue, req);
1010 DLIST_ADD(c->pending, req);
1011 req->state = RPC_REQUEST_PENDING;
1013 init_ncacn_hdr(p->conn, &pkt);
1015 remaining = stub_data->length;
1017 /* we can write a full max_recv_frag size, minus the dcerpc
1018 request header size */
1019 chunk_size = p->conn->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
1021 pkt.ptype = DCERPC_PKT_REQUEST;
1022 pkt.call_id = req->call_id;
1023 pkt.auth_length = 0;
1024 pkt.pfc_flags = 0;
1025 pkt.u.request.alloc_hint = remaining;
1026 pkt.u.request.context_id = p->context_id;
1027 pkt.u.request.opnum = req->opnum;
1029 if (req->object) {
1030 pkt.u.request.object.object = *req->object;
1031 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1032 chunk_size -= ndr_size_GUID(req->object,0);
1035 /* we send a series of pdus without waiting for a reply */
1036 while (remaining > 0 || first_packet) {
1037 uint32_t chunk = MIN(chunk_size, remaining);
1038 BOOL last_frag = False;
1040 first_packet = False;
1041 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1043 if (remaining == stub_data->length) {
1044 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1046 if (chunk == remaining) {
1047 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1048 last_frag = True;
1051 pkt.u.request.stub_and_verifier.data = stub_data->data +
1052 (stub_data->length - remaining);
1053 pkt.u.request.stub_and_verifier.length = chunk;
1055 req->status = ncacn_push_request_sign(p->conn, &blob, req, &pkt);
1056 if (!NT_STATUS_IS_OK(req->status)) {
1057 req->state = RPC_REQUEST_DONE;
1058 DLIST_REMOVE(p->conn->pending, req);
1059 return;
1062 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
1063 if (!NT_STATUS_IS_OK(req->status)) {
1064 req->state = RPC_REQUEST_DONE;
1065 DLIST_REMOVE(p->conn->pending, req);
1066 return;
1069 remaining -= chunk;
1074 return the event context for a dcerpc pipe
1075 used by callers who wish to operate asynchronously
1077 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
1079 return p->conn->event_ctx;
1085 perform the receive side of a async dcerpc request
1087 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1088 TALLOC_CTX *mem_ctx,
1089 DATA_BLOB *stub_data)
1091 NTSTATUS status;
1093 while (req->state != RPC_REQUEST_DONE) {
1094 struct event_context *ctx = dcerpc_event_context(req->p);
1095 if (event_loop_once(ctx) != 0) {
1096 return NT_STATUS_CONNECTION_DISCONNECTED;
1099 *stub_data = req->payload;
1100 status = req->status;
1101 if (stub_data->data) {
1102 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1104 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1105 req->p->last_fault_code = req->fault_code;
1107 talloc_free(req);
1108 return status;
1112 perform a full request/response pair on a dcerpc pipe
1114 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1115 struct GUID *object,
1116 uint16_t opnum,
1117 BOOL async,
1118 TALLOC_CTX *mem_ctx,
1119 DATA_BLOB *stub_data_in,
1120 DATA_BLOB *stub_data_out)
1122 struct rpc_request *req;
1124 req = dcerpc_request_send(p, object, opnum, async, stub_data_in);
1125 if (req == NULL) {
1126 return NT_STATUS_NO_MEMORY;
1129 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1134 this is a paranoid NDR validator. For every packet we push onto the wire
1135 we pull it back again, then push it again. Then we compare the raw NDR data
1136 for that to the NDR we initially generated. If they don't match then we know
1137 we must have a bug in either the pull or push side of our code
1139 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1140 TALLOC_CTX *mem_ctx,
1141 DATA_BLOB blob,
1142 size_t struct_size,
1143 ndr_push_flags_fn_t ndr_push,
1144 ndr_pull_flags_fn_t ndr_pull)
1146 void *st;
1147 struct ndr_pull *pull;
1148 struct ndr_push *push;
1149 NTSTATUS status;
1150 DATA_BLOB blob2;
1152 st = talloc_size(mem_ctx, struct_size);
1153 if (!st) {
1154 return NT_STATUS_NO_MEMORY;
1157 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1158 if (!pull) {
1159 return NT_STATUS_NO_MEMORY;
1161 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1163 status = ndr_pull(pull, NDR_IN, st);
1164 if (!NT_STATUS_IS_OK(status)) {
1165 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1166 "failed input validation pull - %s",
1167 nt_errstr(status));
1170 push = ndr_push_init_ctx(mem_ctx);
1171 if (!push) {
1172 return NT_STATUS_NO_MEMORY;
1175 status = ndr_push(push, NDR_IN, st);
1176 if (!NT_STATUS_IS_OK(status)) {
1177 return ndr_push_error(push, NDR_ERR_VALIDATE,
1178 "failed input validation push - %s",
1179 nt_errstr(status));
1182 blob2 = ndr_push_blob(push);
1184 if (!data_blob_equal(&blob, &blob2)) {
1185 DEBUG(3,("original:\n"));
1186 dump_data(3, blob.data, blob.length);
1187 DEBUG(3,("secondary:\n"));
1188 dump_data(3, blob2.data, blob2.length);
1189 return ndr_push_error(push, NDR_ERR_VALIDATE,
1190 "failed input validation data - %s",
1191 nt_errstr(status));
1194 return NT_STATUS_OK;
1198 this is a paranoid NDR input validator. For every packet we pull
1199 from the wire we push it back again then pull and push it
1200 again. Then we compare the raw NDR data for that to the NDR we
1201 initially generated. If they don't match then we know we must have a
1202 bug in either the pull or push side of our code
1204 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1205 struct ndr_pull *pull_in,
1206 void *struct_ptr,
1207 size_t struct_size,
1208 ndr_push_flags_fn_t ndr_push,
1209 ndr_pull_flags_fn_t ndr_pull,
1210 ndr_print_function_t ndr_print)
1212 void *st;
1213 struct ndr_pull *pull;
1214 struct ndr_push *push;
1215 NTSTATUS status;
1216 DATA_BLOB blob, blob2;
1217 TALLOC_CTX *mem_ctx = pull_in;
1218 char *s1, *s2;
1220 st = talloc_size(mem_ctx, struct_size);
1221 if (!st) {
1222 return NT_STATUS_NO_MEMORY;
1224 memcpy(st, struct_ptr, struct_size);
1226 push = ndr_push_init_ctx(mem_ctx);
1227 if (!push) {
1228 return NT_STATUS_NO_MEMORY;
1231 status = ndr_push(push, NDR_OUT, struct_ptr);
1232 if (!NT_STATUS_IS_OK(status)) {
1233 return ndr_push_error(push, NDR_ERR_VALIDATE,
1234 "failed output validation push - %s",
1235 nt_errstr(status));
1238 blob = ndr_push_blob(push);
1240 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1241 if (!pull) {
1242 return NT_STATUS_NO_MEMORY;
1245 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1246 status = ndr_pull(pull, NDR_OUT, st);
1247 if (!NT_STATUS_IS_OK(status)) {
1248 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1249 "failed output validation pull - %s",
1250 nt_errstr(status));
1253 push = ndr_push_init_ctx(mem_ctx);
1254 if (!push) {
1255 return NT_STATUS_NO_MEMORY;
1258 status = ndr_push(push, NDR_OUT, st);
1259 if (!NT_STATUS_IS_OK(status)) {
1260 return ndr_push_error(push, NDR_ERR_VALIDATE,
1261 "failed output validation push2 - %s",
1262 nt_errstr(status));
1265 blob2 = ndr_push_blob(push);
1267 if (!data_blob_equal(&blob, &blob2)) {
1268 DEBUG(3,("original:\n"));
1269 dump_data(3, blob.data, blob.length);
1270 DEBUG(3,("secondary:\n"));
1271 dump_data(3, blob2.data, blob2.length);
1272 return ndr_push_error(push, NDR_ERR_VALIDATE,
1273 "failed output validation data - %s",
1274 nt_errstr(status));
1277 /* this checks the printed forms of the two structures, which effectively
1278 tests all of the value() attributes */
1279 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1280 NDR_OUT, struct_ptr);
1281 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1282 NDR_OUT, st);
1283 if (strcmp(s1, s2) != 0) {
1284 #if 1
1285 printf("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2);
1286 #else
1287 /* this is sometimes useful */
1288 printf("VALIDATE ERROR\n");
1289 file_save("wire.dat", s1, strlen(s1));
1290 file_save("gen.dat", s2, strlen(s2));
1291 system("diff -u wire.dat gen.dat");
1292 #endif
1295 return NT_STATUS_OK;
1300 send a rpc request given a dcerpc_call structure
1302 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1303 const struct GUID *object,
1304 const struct dcerpc_interface_table *table,
1305 uint32_t opnum,
1306 TALLOC_CTX *mem_ctx,
1307 void *r)
1309 const struct dcerpc_interface_call *call;
1310 struct ndr_push *push;
1311 NTSTATUS status;
1312 DATA_BLOB request;
1313 struct rpc_request *req;
1315 call = &table->calls[opnum];
1317 /* setup for a ndr_push_* call */
1318 push = ndr_push_init_ctx(mem_ctx);
1319 if (!push) {
1320 return NULL;
1323 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1324 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1327 /* push the structure into a blob */
1328 status = call->ndr_push(push, NDR_IN, r);
1329 if (!NT_STATUS_IS_OK(status)) {
1330 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1331 nt_errstr(status)));
1332 talloc_free(push);
1333 return NULL;
1336 /* retrieve the blob */
1337 request = ndr_push_blob(push);
1339 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1340 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1341 call->ndr_push, call->ndr_pull);
1342 if (!NT_STATUS_IS_OK(status)) {
1343 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1344 nt_errstr(status)));
1345 talloc_free(push);
1346 return NULL;
1350 DEBUG(10,("rpc request data:\n"));
1351 dump_data(10, request.data, request.length);
1353 /* make the actual dcerpc request */
1354 req = dcerpc_request_send(p, object, opnum, table->calls[opnum].async,
1355 &request);
1357 if (req != NULL) {
1358 req->ndr.table = table;
1359 req->ndr.opnum = opnum;
1360 req->ndr.struct_ptr = r;
1361 req->ndr.mem_ctx = mem_ctx;
1364 talloc_free(push);
1366 return req;
1370 receive the answer from a dcerpc_ndr_request_send()
1372 _PUBLIC_ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1374 struct dcerpc_pipe *p = req->p;
1375 NTSTATUS status;
1376 DATA_BLOB response;
1377 struct ndr_pull *pull;
1378 uint_t flags;
1379 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1380 void *r = req->ndr.struct_ptr;
1381 uint32_t opnum = req->ndr.opnum;
1382 const struct dcerpc_interface_table *table = req->ndr.table;
1383 const struct dcerpc_interface_call *call = &table->calls[opnum];
1385 /* make sure the recv code doesn't free the request, as we
1386 need to grab the flags element before it is freed */
1387 if (talloc_reference(p, req) == NULL) {
1388 return NT_STATUS_NO_MEMORY;
1391 status = dcerpc_request_recv(req, mem_ctx, &response);
1392 if (!NT_STATUS_IS_OK(status)) {
1393 talloc_unlink(p, req);
1394 return status;
1397 flags = req->flags;
1399 /* prepare for ndr_pull_* */
1400 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1401 if (!pull) {
1402 talloc_unlink(p, req);
1403 return NT_STATUS_NO_MEMORY;
1406 if (pull->data) {
1407 pull->data = talloc_steal(pull, pull->data);
1409 talloc_unlink(p, req);
1411 if (flags & DCERPC_PULL_BIGENDIAN) {
1412 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1415 DEBUG(10,("rpc reply data:\n"));
1416 dump_data(10, pull->data, pull->data_size);
1418 /* pull the structure from the blob */
1419 status = call->ndr_pull(pull, NDR_OUT, r);
1420 if (!NT_STATUS_IS_OK(status)) {
1421 dcerpc_log_packet(table, opnum, NDR_OUT,
1422 &response);
1423 return status;
1426 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1427 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1428 call->ndr_push, call->ndr_pull,
1429 call->ndr_print);
1430 if (!NT_STATUS_IS_OK(status)) {
1431 dcerpc_log_packet(table, opnum, NDR_OUT,
1432 &response);
1433 return status;
1437 if (pull->offset != pull->data_size) {
1438 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1439 pull->data_size - pull->offset));
1440 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1441 but it turns out that early versions of NT
1442 (specifically NT3.1) add junk onto the end of rpc
1443 packets, so if we want to interoperate at all with
1444 those versions then we need to ignore this error */
1447 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1449 return NT_STATUS_OK;
1454 a useful helper function for synchronous rpc requests
1456 this can be used when you have ndr push/pull functions in the
1457 standard format
1459 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1460 const struct GUID *object,
1461 const struct dcerpc_interface_table *table,
1462 uint32_t opnum,
1463 TALLOC_CTX *mem_ctx,
1464 void *r)
1466 struct rpc_request *req;
1468 req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1469 if (req == NULL) {
1470 return NT_STATUS_NO_MEMORY;
1473 return dcerpc_ndr_request_recv(req);
1478 a useful function for retrieving the server name we connected to
1480 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1482 if (!p->conn->transport.peer_name) {
1483 return "";
1485 return p->conn->transport.peer_name(p->conn);
1490 get the dcerpc auth_level for a open connection
1492 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1494 uint8_t auth_level;
1496 if (c->flags & DCERPC_SEAL) {
1497 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1498 } else if (c->flags & DCERPC_SIGN) {
1499 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1500 } else if (c->flags & DCERPC_CONNECT) {
1501 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1502 } else {
1503 auth_level = DCERPC_AUTH_LEVEL_NONE;
1505 return auth_level;
1509 Receive an alter reply from the transport
1511 static void dcerpc_alter_recv_handler(struct rpc_request *req,
1512 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1514 struct composite_context *c;
1515 struct dcerpc_pipe *recv_pipe;
1517 c = talloc_get_type(req->async.private, struct composite_context);
1518 recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1520 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1521 pkt->u.alter_resp.num_results == 1 &&
1522 pkt->u.alter_resp.ctx_list[0].result != 0) {
1523 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1524 pkt->u.alter_resp.ctx_list[0].reason));
1525 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1526 return;
1529 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1530 pkt->u.alter_resp.num_results == 0 ||
1531 pkt->u.alter_resp.ctx_list[0].result != 0) {
1532 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1533 return;
1536 /* the alter_resp might contain a reply set of credentials */
1537 if (recv_pipe->conn->security_state.auth_info &&
1538 pkt->u.alter_resp.auth_info.length) {
1539 c->status = ndr_pull_struct_blob(
1540 &pkt->u.alter_resp.auth_info, recv_pipe,
1541 recv_pipe->conn->security_state.auth_info,
1542 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
1543 if (!composite_is_ok(c)) return;
1546 composite_done(c);
1550 send a dcerpc alter_context request
1552 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
1553 TALLOC_CTX *mem_ctx,
1554 const struct dcerpc_syntax_id *syntax,
1555 const struct dcerpc_syntax_id *transfer_syntax)
1557 struct composite_context *c;
1558 struct ncacn_packet pkt;
1559 DATA_BLOB blob;
1560 struct rpc_request *req;
1562 c = composite_create(mem_ctx, p->conn->event_ctx);
1563 if (c == NULL) return NULL;
1565 c->private_data = p;
1567 p->syntax = *syntax;
1568 p->transfer_syntax = *transfer_syntax;
1570 init_ncacn_hdr(p->conn, &pkt);
1572 pkt.ptype = DCERPC_PKT_ALTER;
1573 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1574 pkt.call_id = p->conn->call_id;
1575 pkt.auth_length = 0;
1577 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1578 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1581 pkt.u.alter.max_xmit_frag = 5840;
1582 pkt.u.alter.max_recv_frag = 5840;
1583 pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
1584 pkt.u.alter.num_contexts = 1;
1585 pkt.u.alter.ctx_list = talloc_array(c, struct dcerpc_ctx_list, 1);
1586 if (composite_nomem(pkt.u.alter.ctx_list, c)) return c;
1587 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1588 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1589 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1590 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1591 pkt.u.alter.auth_info = data_blob(NULL, 0);
1593 /* construct the NDR form of the packet */
1594 c->status = ncacn_push_auth(&blob, mem_ctx, &pkt,
1595 p->conn->security_state.auth_info);
1596 if (!composite_is_ok(c)) return c;
1598 p->conn->transport.recv_data = dcerpc_recv_data;
1601 * we allocate a dcerpc_request so we can be in the same
1602 * request queue as normal requests
1604 req = talloc_zero(c, struct rpc_request);
1605 if (composite_nomem(req, c)) return c;
1607 req->state = RPC_REQUEST_PENDING;
1608 req->call_id = pkt.call_id;
1609 req->async.private = c;
1610 req->async.callback = dcerpc_composite_fail;
1611 req->p = p;
1612 req->recv_handler = dcerpc_alter_recv_handler;
1613 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1614 talloc_set_destructor(req, dcerpc_req_dequeue);
1616 c->status = p->conn->transport.send_request(p->conn, &blob, True);
1617 if (!composite_is_ok(c)) return c;
1619 event_add_timed(c->event_ctx, req,
1620 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1621 dcerpc_timeout_handler, req);
1623 return c;
1626 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1628 NTSTATUS result = composite_wait(ctx);
1629 talloc_free(ctx);
1630 return result;
1634 send a dcerpc alter_context request
1636 NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1637 TALLOC_CTX *mem_ctx,
1638 const struct dcerpc_syntax_id *syntax,
1639 const struct dcerpc_syntax_id *transfer_syntax)
1641 struct composite_context *creq;
1642 creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1643 return dcerpc_alter_context_recv(creq);