• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt/router/samba-3.5.8/source4/librpc/rpc/
1/*
2   Unix SMB/CIFS implementation.
3   raw dcerpc operations
4
5   Copyright (C) Tim Potter 2003
6   Copyright (C) Andrew Tridgell 2003-2005
7   Copyright (C) Jelmer Vernooij 2004-2005
8
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.
13
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.
18
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/>.
21*/
22
23#include "includes.h"
24#include "../lib/util/dlinklist.h"
25#include "lib/events/events.h"
26#include "librpc/rpc/dcerpc.h"
27#include "librpc/rpc/dcerpc_proto.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"
32#include "param/param.h"
33
34_PUBLIC_ NTSTATUS dcerpc_init(struct loadparm_context *lp_ctx)
35{
36	return gensec_init(lp_ctx);
37}
38
39static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status);
40static void dcerpc_ship_next_request(struct dcerpc_connection *c);
41
42/* destroy a dcerpc connection */
43static int dcerpc_connection_destructor(struct dcerpc_connection *conn)
44{
45	if (conn->dead) {
46		conn->free_skipped = true;
47		return -1;
48	}
49	dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
50	return 0;
51}
52
53
54/* initialise a dcerpc connection.
55   the event context is optional
56*/
57static struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
58						 struct tevent_context *ev,
59						 struct smb_iconv_convenience *ic)
60{
61	struct dcerpc_connection *c;
62
63	c = talloc_zero(mem_ctx, struct dcerpc_connection);
64	if (!c) {
65		return NULL;
66	}
67
68	c->iconv_convenience = talloc_reference(c, ic);
69
70	c->event_ctx = ev;
71
72	if (c->event_ctx == NULL) {
73		talloc_free(c);
74		return NULL;
75	}
76
77	c->call_id = 1;
78	c->security_state.auth_info = NULL;
79	c->security_state.session_key = dcerpc_generic_session_key;
80	c->security_state.generic_state = NULL;
81	c->binding_string = NULL;
82	c->flags = 0;
83	c->srv_max_xmit_frag = 0;
84	c->srv_max_recv_frag = 0;
85	c->pending = NULL;
86
87	talloc_set_destructor(c, dcerpc_connection_destructor);
88
89	return c;
90}
91
92/* initialise a dcerpc pipe. */
93_PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
94				     struct smb_iconv_convenience *ic)
95{
96	struct dcerpc_pipe *p;
97
98	p = talloc(mem_ctx, struct dcerpc_pipe);
99	if (!p) {
100		return NULL;
101	}
102
103	p->conn = dcerpc_connection_init(p, ev, ic);
104	if (p->conn == NULL) {
105		talloc_free(p);
106		return NULL;
107	}
108
109	p->last_fault_code = 0;
110	p->context_id = 0;
111	p->request_timeout = DCERPC_REQUEST_TIMEOUT;
112	p->binding = NULL;
113
114	ZERO_STRUCT(p->syntax);
115	ZERO_STRUCT(p->transfer_syntax);
116
117	if (DEBUGLVL(100)) {
118		p->conn->flags |= DCERPC_DEBUG_PRINT_BOTH;
119	}
120
121	return p;
122}
123
124
125/*
126   choose the next call id to use
127*/
128static uint32_t next_call_id(struct dcerpc_connection *c)
129{
130	c->call_id++;
131	if (c->call_id == 0) {
132		c->call_id++;
133	}
134	return c->call_id;
135}
136
137/* we need to be able to get/set the fragment length without doing a full
138   decode */
139void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
140{
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);
145	}
146}
147
148uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
149{
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);
154	}
155}
156
157void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
158{
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);
163	}
164}
165
166
167/**
168  setup for a ndr pull, also setting up any flags from the binding string
169*/
170static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c,
171					    DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
172{
173	struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx, c->iconv_convenience);
174
175	if (ndr == NULL) return ndr;
176
177	if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
178		ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
179	}
180
181	if (c->flags & DCERPC_NDR_REF_ALLOC) {
182		ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
183	}
184
185	if (c->flags & DCERPC_NDR64) {
186		ndr->flags |= LIBNDR_FLAG_NDR64;
187	}
188
189	return ndr;
190}
191
192/*
193   parse a data blob into a ncacn_packet structure. This handles both
194   input and output packets
195*/
196static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
197			    struct ncacn_packet *pkt)
198{
199	struct ndr_pull *ndr;
200	enum ndr_err_code ndr_err;
201
202	ndr = ndr_pull_init_flags(c, blob, mem_ctx);
203	if (!ndr) {
204		return NT_STATUS_NO_MEMORY;
205	}
206
207	if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
208		ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
209	}
210
211	ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
212	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
213		return ndr_map_error2ntstatus(ndr_err);
214	}
215
216	return NT_STATUS_OK;
217}
218
219/*
220   parse the authentication information on a dcerpc response packet
221*/
222static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX *mem_ctx,
223					DATA_BLOB *raw_packet,
224					struct ncacn_packet *pkt)
225{
226	struct ndr_pull *ndr;
227	NTSTATUS status;
228	struct dcerpc_auth auth;
229	DATA_BLOB auth_blob;
230	enum ndr_err_code ndr_err;
231
232	if (!c->security_state.auth_info ||
233	    !c->security_state.generic_state) {
234		return NT_STATUS_OK;
235	}
236
237	switch (c->security_state.auth_info->auth_level) {
238	case DCERPC_AUTH_LEVEL_PRIVACY:
239	case DCERPC_AUTH_LEVEL_INTEGRITY:
240		break;
241
242	case DCERPC_AUTH_LEVEL_CONNECT:
243		if (pkt->auth_length != 0) {
244			break;
245		}
246		return NT_STATUS_OK;
247	case DCERPC_AUTH_LEVEL_NONE:
248		if (pkt->auth_length != 0) {
249			return NT_STATUS_INVALID_NETWORK_RESPONSE;
250		}
251		return NT_STATUS_OK;
252
253	default:
254		return NT_STATUS_INVALID_LEVEL;
255	}
256
257	auth_blob.length = 8 + pkt->auth_length;
258
259	/* check for a valid length */
260	if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
261		return NT_STATUS_INFO_LENGTH_MISMATCH;
262	}
263
264	auth_blob.data =
265		pkt->u.response.stub_and_verifier.data +
266		pkt->u.response.stub_and_verifier.length - auth_blob.length;
267	pkt->u.response.stub_and_verifier.length -= auth_blob.length;
268
269	/* pull the auth structure */
270	ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);
271	if (!ndr) {
272		return NT_STATUS_NO_MEMORY;
273	}
274
275	if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
276		ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
277	}
278
279	ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
280	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
281		return ndr_map_error2ntstatus(ndr_err);
282	}
283	status = NT_STATUS_OK;
284
285	/* check signature or unseal the packet */
286	switch (c->security_state.auth_info->auth_level) {
287	case DCERPC_AUTH_LEVEL_PRIVACY:
288		status = gensec_unseal_packet(c->security_state.generic_state,
289					      mem_ctx,
290					      raw_packet->data + DCERPC_REQUEST_LENGTH,
291					      pkt->u.response.stub_and_verifier.length,
292					      raw_packet->data,
293					      raw_packet->length - auth.credentials.length,
294					      &auth.credentials);
295		memcpy(pkt->u.response.stub_and_verifier.data,
296		       raw_packet->data + DCERPC_REQUEST_LENGTH,
297		       pkt->u.response.stub_and_verifier.length);
298		break;
299
300	case DCERPC_AUTH_LEVEL_INTEGRITY:
301		status = gensec_check_packet(c->security_state.generic_state,
302					     mem_ctx,
303					     pkt->u.response.stub_and_verifier.data,
304					     pkt->u.response.stub_and_verifier.length,
305					     raw_packet->data,
306					     raw_packet->length - auth.credentials.length,
307					     &auth.credentials);
308		break;
309
310	case DCERPC_AUTH_LEVEL_CONNECT:
311		/* for now we ignore possible signatures here */
312		status = NT_STATUS_OK;
313		break;
314
315	default:
316		status = NT_STATUS_INVALID_LEVEL;
317		break;
318	}
319
320	/* remove the indicated amount of paddiing */
321	if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
322		return NT_STATUS_INFO_LENGTH_MISMATCH;
323	}
324	pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
325
326	return status;
327}
328
329
330/*
331   push a dcerpc request packet into a blob, possibly signing it.
332*/
333static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
334					 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
335					 size_t sig_size,
336					 struct ncacn_packet *pkt)
337{
338	NTSTATUS status;
339	struct ndr_push *ndr;
340	DATA_BLOB creds2;
341	size_t payload_length;
342	enum ndr_err_code ndr_err;
343	size_t hdr_size = DCERPC_REQUEST_LENGTH;
344
345	/* non-signed packets are simpler */
346	if (sig_size == 0) {
347		return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
348	}
349
350	switch (c->security_state.auth_info->auth_level) {
351	case DCERPC_AUTH_LEVEL_PRIVACY:
352	case DCERPC_AUTH_LEVEL_INTEGRITY:
353		break;
354
355	case DCERPC_AUTH_LEVEL_CONNECT:
356		/* TODO: let the gensec mech decide if it wants to generate a signature */
357		return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
358
359	case DCERPC_AUTH_LEVEL_NONE:
360		return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
361
362	default:
363		return NT_STATUS_INVALID_LEVEL;
364	}
365
366	ndr = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
367	if (!ndr) {
368		return NT_STATUS_NO_MEMORY;
369	}
370
371	if (c->flags & DCERPC_PUSH_BIGENDIAN) {
372		ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
373	}
374
375	if (c->flags & DCERPC_NDR64) {
376		ndr->flags |= LIBNDR_FLAG_NDR64;
377	}
378
379	if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
380		ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
381		hdr_size += 16;
382	}
383
384	ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
385	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
386		return ndr_map_error2ntstatus(ndr_err);
387	}
388	status = NT_STATUS_OK;
389
390	/* pad to 16 byte multiple in the payload portion of the
391	   packet. This matches what w2k3 does */
392	c->security_state.auth_info->auth_pad_length =
393		(16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
394	ndr_err = ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
395	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
396		return ndr_map_error2ntstatus(ndr_err);
397	}
398	status = NT_STATUS_OK;
399
400	payload_length = pkt->u.request.stub_and_verifier.length +
401		c->security_state.auth_info->auth_pad_length;
402
403	/* we start without signature, it will appended later */
404	c->security_state.auth_info->credentials = data_blob(NULL,0);
405
406	/* add the auth verifier */
407	ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
408	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
409		return ndr_map_error2ntstatus(ndr_err);
410	}
411	status = NT_STATUS_OK;
412
413	/* extract the whole packet as a blob */
414	*blob = ndr_push_blob(ndr);
415
416	/*
417	 * Setup the frag and auth length in the packet buffer.
418	 * This is needed if the GENSEC mech does AEAD signing
419	 * of the packet headers. The signature itself will be
420	 * appended later.
421	 */
422	dcerpc_set_frag_length(blob, blob->length + sig_size);
423	dcerpc_set_auth_length(blob, sig_size);
424
425	/* sign or seal the packet */
426	switch (c->security_state.auth_info->auth_level) {
427	case DCERPC_AUTH_LEVEL_PRIVACY:
428		status = gensec_seal_packet(c->security_state.generic_state,
429					    mem_ctx,
430					    blob->data + hdr_size,
431					    payload_length,
432					    blob->data,
433					    blob->length,
434					    &creds2);
435		if (!NT_STATUS_IS_OK(status)) {
436			return status;
437		}
438		break;
439
440	case DCERPC_AUTH_LEVEL_INTEGRITY:
441		status = gensec_sign_packet(c->security_state.generic_state,
442					    mem_ctx,
443					    blob->data + hdr_size,
444					    payload_length,
445					    blob->data,
446					    blob->length,
447					    &creds2);
448		if (!NT_STATUS_IS_OK(status)) {
449			return status;
450		}
451		break;
452
453	default:
454		status = NT_STATUS_INVALID_LEVEL;
455		break;
456	}
457
458	if (creds2.length != sig_size) {
459		DEBUG(0,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
460			creds2.length, (uint32_t)sig_size,
461			c->security_state.auth_info->auth_pad_length,
462			pkt->u.request.stub_and_verifier.length));
463		return NT_STATUS_INTERNAL_ERROR;
464	}
465
466	if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
467		return NT_STATUS_NO_MEMORY;
468	}
469
470	return NT_STATUS_OK;
471}
472
473
474/*
475   fill in the fixed values in a dcerpc header
476*/
477static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
478{
479	pkt->rpc_vers = 5;
480	pkt->rpc_vers_minor = 0;
481	if (c->flags & DCERPC_PUSH_BIGENDIAN) {
482		pkt->drep[0] = 0;
483	} else {
484		pkt->drep[0] = DCERPC_DREP_LE;
485	}
486	pkt->drep[1] = 0;
487	pkt->drep[2] = 0;
488	pkt->drep[3] = 0;
489}
490
491/*
492  map a bind nak reason to a NTSTATUS
493*/
494static NTSTATUS dcerpc_map_reason(uint16_t reason)
495{
496	switch (reason) {
497	case DCERPC_BIND_REASON_ASYNTAX:
498		return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
499	case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
500		return NT_STATUS_INVALID_PARAMETER;
501	}
502	return NT_STATUS_UNSUCCESSFUL;
503}
504
505/*
506  a bind or alter context has failed
507*/
508static void dcerpc_composite_fail(struct rpc_request *req)
509{
510	struct composite_context *c = talloc_get_type(req->async.private_data,
511						      struct composite_context);
512	composite_error(c, req->status);
513}
514
515/*
516  remove requests from the pending or queued queues
517 */
518static int dcerpc_req_dequeue(struct rpc_request *req)
519{
520	switch (req->state) {
521	case RPC_REQUEST_QUEUED:
522		DLIST_REMOVE(req->p->conn->request_queue, req);
523		break;
524	case RPC_REQUEST_PENDING:
525		DLIST_REMOVE(req->p->conn->pending, req);
526		break;
527	case RPC_REQUEST_DONE:
528		break;
529	}
530	return 0;
531}
532
533
534/*
535  mark the dcerpc connection dead. All outstanding requests get an error
536*/
537static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
538{
539	if (conn->dead) return;
540
541	conn->dead = true;
542
543	if (conn->transport.shutdown_pipe) {
544		conn->transport.shutdown_pipe(conn, status);
545	}
546
547	/* all pending requests get the error */
548	while (conn->pending) {
549		struct rpc_request *req = conn->pending;
550		dcerpc_req_dequeue(req);
551		req->state = RPC_REQUEST_DONE;
552		req->status = status;
553		if (req->async.callback) {
554			req->async.callback(req);
555		}
556	}
557
558	talloc_set_destructor(conn, NULL);
559	if (conn->free_skipped) {
560		talloc_free(conn);
561	}
562}
563
564/*
565  forward declarations of the recv_data handlers for the types of
566  packets we need to handle
567*/
568static void dcerpc_request_recv_data(struct dcerpc_connection *c,
569				     DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
570
571/*
572  receive a dcerpc reply from the transport. Here we work out what
573  type of reply it is (normal request, bind or alter context) and
574  dispatch to the appropriate handler
575*/
576static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NTSTATUS status)
577{
578	struct ncacn_packet pkt;
579
580	if (NT_STATUS_IS_OK(status) && blob->length == 0) {
581		status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
582	}
583
584	/* the transport may be telling us of a severe error, such as
585	   a dropped socket */
586	if (!NT_STATUS_IS_OK(status)) {
587		data_blob_free(blob);
588		dcerpc_connection_dead(conn, status);
589		return;
590	}
591
592	/* parse the basic packet to work out what type of response this is */
593	status = ncacn_pull(conn, blob, blob->data, &pkt);
594	if (!NT_STATUS_IS_OK(status)) {
595		data_blob_free(blob);
596		dcerpc_connection_dead(conn, status);
597	}
598
599	dcerpc_request_recv_data(conn, blob, &pkt);
600}
601
602
603/*
604  Receive a bind reply from the transport
605*/
606static void dcerpc_bind_recv_handler(struct rpc_request *req,
607				     DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
608{
609	struct composite_context *c;
610	struct dcerpc_connection *conn;
611
612	c = talloc_get_type(req->async.private_data, struct composite_context);
613
614	if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
615		DEBUG(2,("dcerpc: bind_nak reason %d\n",
616			 pkt->u.bind_nak.reject_reason));
617		composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
618						     reject_reason));
619		return;
620	}
621
622	if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
623	    (pkt->u.bind_ack.num_results == 0) ||
624	    (pkt->u.bind_ack.ctx_list[0].result != 0)) {
625		composite_error(c, NT_STATUS_NET_WRITE_FAULT);
626		return;
627	}
628
629	conn = req->p->conn;
630
631	conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
632	conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
633
634	if ((req->p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) &&
635	    (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
636		conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
637	}
638
639	if ((req->p->binding->flags & DCERPC_HEADER_SIGNING) &&
640	    (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
641		conn->flags |= DCERPC_HEADER_SIGNING;
642	}
643
644	/* the bind_ack might contain a reply set of credentials */
645	if (conn->security_state.auth_info &&
646	    pkt->u.bind_ack.auth_info.length) {
647		enum ndr_err_code ndr_err;
648		ndr_err = ndr_pull_struct_blob(
649			&pkt->u.bind_ack.auth_info, conn,
650			NULL,
651			conn->security_state.auth_info,
652			(ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
653		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
654			c->status = ndr_map_error2ntstatus(ndr_err);
655			if (!composite_is_ok(c)) return;
656		}
657	}
658
659	req->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
660
661	composite_done(c);
662}
663
664/*
665  handle timeouts of individual dcerpc requests
666*/
667static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
668				   struct timeval t, void *private_data)
669{
670	struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
671
672	if (req->ignore_timeout) {
673		dcerpc_req_dequeue(req);
674		req->state = RPC_REQUEST_DONE;
675		req->status = NT_STATUS_IO_TIMEOUT;
676		if (req->async.callback) {
677			req->async.callback(req);
678		}
679		return;
680	}
681
682	dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
683}
684
685/*
686  send a async dcerpc bind request
687*/
688struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
689					   TALLOC_CTX *mem_ctx,
690					   const struct ndr_syntax_id *syntax,
691					   const struct ndr_syntax_id *transfer_syntax)
692{
693	struct composite_context *c;
694	struct ncacn_packet pkt;
695	DATA_BLOB blob;
696	struct rpc_request *req;
697
698	c = composite_create(mem_ctx,p->conn->event_ctx);
699	if (c == NULL) return NULL;
700
701	c->private_data = p;
702
703	p->syntax = *syntax;
704	p->transfer_syntax = *transfer_syntax;
705
706	init_ncacn_hdr(p->conn, &pkt);
707
708	pkt.ptype = DCERPC_PKT_BIND;
709	pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
710	pkt.call_id = p->conn->call_id;
711	pkt.auth_length = 0;
712
713	if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
714		pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
715	}
716
717	if (p->binding->flags & DCERPC_HEADER_SIGNING) {
718		pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
719	}
720
721	pkt.u.bind.max_xmit_frag = 5840;
722	pkt.u.bind.max_recv_frag = 5840;
723	pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
724	pkt.u.bind.num_contexts = 1;
725	pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
726	if (composite_nomem(pkt.u.bind.ctx_list, c)) return c;
727	pkt.u.bind.ctx_list[0].context_id = p->context_id;
728	pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
729	pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
730	pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
731	pkt.u.bind.auth_info = data_blob(NULL, 0);
732
733	/* construct the NDR form of the packet */
734	c->status = ncacn_push_auth(&blob, c, p->conn->iconv_convenience, &pkt,
735				    p->conn->security_state.auth_info);
736	if (!composite_is_ok(c)) return c;
737
738	p->conn->transport.recv_data = dcerpc_recv_data;
739
740	/*
741	 * we allocate a dcerpc_request so we can be in the same
742	 * request queue as normal requests
743	 */
744	req = talloc_zero(c, struct rpc_request);
745	if (composite_nomem(req, c)) return c;
746
747	req->state = RPC_REQUEST_PENDING;
748	req->call_id = pkt.call_id;
749	req->async.private_data = c;
750	req->async.callback = dcerpc_composite_fail;
751	req->p = p;
752	req->recv_handler = dcerpc_bind_recv_handler;
753	DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
754	talloc_set_destructor(req, dcerpc_req_dequeue);
755
756	c->status = p->conn->transport.send_request(p->conn, &blob,
757						    true);
758	if (!composite_is_ok(c)) return c;
759
760	event_add_timed(c->event_ctx, req,
761			timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
762			dcerpc_timeout_handler, req);
763
764	return c;
765}
766
767/*
768  recv side of async dcerpc bind request
769*/
770NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
771{
772	NTSTATUS result = composite_wait(ctx);
773	talloc_free(ctx);
774	return result;
775}
776
777/*
778   perform a continued bind (and auth3)
779*/
780NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
781		      TALLOC_CTX *mem_ctx)
782{
783	struct ncacn_packet pkt;
784	NTSTATUS status;
785	DATA_BLOB blob;
786
787	init_ncacn_hdr(p->conn, &pkt);
788
789	pkt.ptype = DCERPC_PKT_AUTH3;
790	pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
791	pkt.call_id = next_call_id(p->conn);
792	pkt.auth_length = 0;
793	pkt.u.auth3._pad = 0;
794	pkt.u.auth3.auth_info = data_blob(NULL, 0);
795
796	if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
797		pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
798	}
799
800	if (p->binding->flags & DCERPC_HEADER_SIGNING) {
801		pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
802	}
803
804	/* construct the NDR form of the packet */
805	status = ncacn_push_auth(&blob, mem_ctx,
806				 p->conn->iconv_convenience,
807				 &pkt,
808				 p->conn->security_state.auth_info);
809	if (!NT_STATUS_IS_OK(status)) {
810		return status;
811	}
812
813	/* send it on its way */
814	status = p->conn->transport.send_request(p->conn, &blob, false);
815	if (!NT_STATUS_IS_OK(status)) {
816		return status;
817	}
818
819	return NT_STATUS_OK;
820}
821
822
823/*
824  process a fragment received from the transport layer during a
825  request
826
827  This function frees the data
828*/
829static void dcerpc_request_recv_data(struct dcerpc_connection *c,
830				     DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
831{
832	struct rpc_request *req;
833	uint_t length;
834	NTSTATUS status = NT_STATUS_OK;
835
836	/*
837	  if this is an authenticated connection then parse and check
838	  the auth info. We have to do this before finding the
839	  matching packet, as the request structure might have been
840	  removed due to a timeout, but if it has been we still need
841	  to run the auth routines so that we don't get the sign/seal
842	  info out of step with the server
843	*/
844	if (c->security_state.auth_info && c->security_state.generic_state &&
845	    pkt->ptype == DCERPC_PKT_RESPONSE) {
846		status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
847	}
848
849	/* find the matching request */
850	for (req=c->pending;req;req=req->next) {
851		if (pkt->call_id == req->call_id) break;
852	}
853
854#if 0
855	/* useful for testing certain vendors RPC servers */
856	if (req == NULL && c->pending && pkt->call_id == 0) {
857		DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
858		req = c->pending;
859	}
860#endif
861
862	if (req == NULL) {
863		DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
864		data_blob_free(raw_packet);
865		return;
866	}
867
868	talloc_steal(req, raw_packet->data);
869
870	if (req->recv_handler != NULL) {
871		dcerpc_req_dequeue(req);
872		req->state = RPC_REQUEST_DONE;
873		req->recv_handler(req, raw_packet, pkt);
874		return;
875	}
876
877	if (pkt->ptype == DCERPC_PKT_FAULT) {
878		DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
879		req->fault_code = pkt->u.fault.status;
880		req->status = NT_STATUS_NET_WRITE_FAULT;
881		goto req_done;
882	}
883
884	if (pkt->ptype != DCERPC_PKT_RESPONSE) {
885		DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
886			 (int)pkt->ptype));
887		req->fault_code = DCERPC_FAULT_OTHER;
888		req->status = NT_STATUS_NET_WRITE_FAULT;
889		goto req_done;
890	}
891
892	/* now check the status from the auth routines, and if it failed then fail
893	   this request accordingly */
894	if (!NT_STATUS_IS_OK(status)) {
895		req->status = status;
896		goto req_done;
897	}
898
899	length = pkt->u.response.stub_and_verifier.length;
900
901	if (length > 0) {
902		req->payload.data = talloc_realloc(req,
903						   req->payload.data,
904						   uint8_t,
905						   req->payload.length + length);
906		if (!req->payload.data) {
907			req->status = NT_STATUS_NO_MEMORY;
908			goto req_done;
909		}
910		memcpy(req->payload.data+req->payload.length,
911		       pkt->u.response.stub_and_verifier.data, length);
912		req->payload.length += length;
913	}
914
915	if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
916		c->transport.send_read(c);
917		return;
918	}
919
920	if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
921		req->flags |= DCERPC_PULL_BIGENDIAN;
922	} else {
923		req->flags &= ~DCERPC_PULL_BIGENDIAN;
924	}
925
926
927req_done:
928	/* we've got the full payload */
929	req->state = RPC_REQUEST_DONE;
930	DLIST_REMOVE(c->pending, req);
931
932	if (c->request_queue != NULL) {
933		/* We have to look at shipping further requests before calling
934		 * the async function, that one might close the pipe */
935		dcerpc_ship_next_request(c);
936	}
937
938	if (req->async.callback) {
939		req->async.callback(req);
940	}
941}
942
943/*
944  perform the send side of a async dcerpc request
945*/
946static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
947					       const struct GUID *object,
948					       uint16_t opnum,
949					       bool async,
950					       DATA_BLOB *stub_data)
951{
952	struct rpc_request *req;
953
954	p->conn->transport.recv_data = dcerpc_recv_data;
955
956	req = talloc(p, struct rpc_request);
957	if (req == NULL) {
958		return NULL;
959	}
960
961	req->p = p;
962	req->call_id = next_call_id(p->conn);
963	req->status = NT_STATUS_OK;
964	req->state = RPC_REQUEST_QUEUED;
965	req->payload = data_blob(NULL, 0);
966	req->flags = 0;
967	req->fault_code = 0;
968	req->async_call = async;
969	req->ignore_timeout = false;
970	req->async.callback = NULL;
971	req->async.private_data = NULL;
972	req->recv_handler = NULL;
973
974	if (object != NULL) {
975		req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
976		if (req->object == NULL) {
977			talloc_free(req);
978			return NULL;
979		}
980	} else {
981		req->object = NULL;
982	}
983
984	req->opnum = opnum;
985	req->request_data.length = stub_data->length;
986	req->request_data.data = talloc_reference(req, stub_data->data);
987	if (req->request_data.length && req->request_data.data == NULL) {
988		return NULL;
989	}
990
991	DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
992	talloc_set_destructor(req, dcerpc_req_dequeue);
993
994	dcerpc_ship_next_request(p->conn);
995
996	if (p->request_timeout) {
997		event_add_timed(dcerpc_event_context(p), req,
998				timeval_current_ofs(p->request_timeout, 0),
999				dcerpc_timeout_handler, req);
1000	}
1001
1002	return req;
1003}
1004
1005/*
1006  Send a request using the transport
1007*/
1008
1009static void dcerpc_ship_next_request(struct dcerpc_connection *c)
1010{
1011	struct rpc_request *req;
1012	struct dcerpc_pipe *p;
1013	DATA_BLOB *stub_data;
1014	struct ncacn_packet pkt;
1015	DATA_BLOB blob;
1016	uint32_t remaining, chunk_size;
1017	bool first_packet = true;
1018	size_t sig_size = 0;
1019
1020	req = c->request_queue;
1021	if (req == NULL) {
1022		return;
1023	}
1024
1025	p = req->p;
1026	stub_data = &req->request_data;
1027
1028	if (!req->async_call && (c->pending != NULL)) {
1029		return;
1030	}
1031
1032	DLIST_REMOVE(c->request_queue, req);
1033	DLIST_ADD(c->pending, req);
1034	req->state = RPC_REQUEST_PENDING;
1035
1036	init_ncacn_hdr(p->conn, &pkt);
1037
1038	remaining = stub_data->length;
1039
1040	/* we can write a full max_recv_frag size, minus the dcerpc
1041	   request header size */
1042	chunk_size = p->conn->srv_max_recv_frag;
1043	chunk_size -= DCERPC_REQUEST_LENGTH;
1044	if (c->security_state.auth_info &&
1045	    c->security_state.generic_state) {
1046		sig_size = gensec_sig_size(c->security_state.generic_state,
1047					   p->conn->srv_max_recv_frag);
1048		if (sig_size) {
1049			chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1050			chunk_size -= sig_size;
1051		}
1052	}
1053	chunk_size -= (chunk_size % 16);
1054
1055	pkt.ptype = DCERPC_PKT_REQUEST;
1056	pkt.call_id = req->call_id;
1057	pkt.auth_length = 0;
1058	pkt.pfc_flags = 0;
1059	pkt.u.request.alloc_hint = remaining;
1060	pkt.u.request.context_id = p->context_id;
1061	pkt.u.request.opnum = req->opnum;
1062
1063	if (req->object) {
1064		pkt.u.request.object.object = *req->object;
1065		pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1066		chunk_size -= ndr_size_GUID(req->object,NULL,0);
1067	}
1068
1069	/* we send a series of pdus without waiting for a reply */
1070	while (remaining > 0 || first_packet) {
1071		uint32_t chunk = MIN(chunk_size, remaining);
1072		bool last_frag = false;
1073		bool do_trans = false;
1074
1075		first_packet = false;
1076		pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1077
1078		if (remaining == stub_data->length) {
1079			pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1080		}
1081		if (chunk == remaining) {
1082			pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1083			last_frag = true;
1084		}
1085
1086		pkt.u.request.stub_and_verifier.data = stub_data->data +
1087			(stub_data->length - remaining);
1088		pkt.u.request.stub_and_verifier.length = chunk;
1089
1090		req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1091		if (!NT_STATUS_IS_OK(req->status)) {
1092			req->state = RPC_REQUEST_DONE;
1093			DLIST_REMOVE(p->conn->pending, req);
1094			return;
1095		}
1096
1097		if (last_frag && !req->async_call) {
1098			do_trans = true;
1099		}
1100
1101		req->status = p->conn->transport.send_request(p->conn, &blob, do_trans);
1102		if (!NT_STATUS_IS_OK(req->status)) {
1103			req->state = RPC_REQUEST_DONE;
1104			DLIST_REMOVE(p->conn->pending, req);
1105			return;
1106		}
1107
1108		if (last_frag && !do_trans) {
1109			req->status = p->conn->transport.send_read(p->conn);
1110			if (!NT_STATUS_IS_OK(req->status)) {
1111				req->state = RPC_REQUEST_DONE;
1112				DLIST_REMOVE(p->conn->pending, req);
1113				return;
1114			}
1115		}
1116
1117		remaining -= chunk;
1118	}
1119}
1120
1121/*
1122  return the event context for a dcerpc pipe
1123  used by callers who wish to operate asynchronously
1124*/
1125_PUBLIC_ struct tevent_context *dcerpc_event_context(struct dcerpc_pipe *p)
1126{
1127	return p->conn->event_ctx;
1128}
1129
1130
1131
1132/*
1133  perform the receive side of a async dcerpc request
1134*/
1135NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1136			     TALLOC_CTX *mem_ctx,
1137			     DATA_BLOB *stub_data)
1138{
1139	NTSTATUS status;
1140
1141	while (req->state != RPC_REQUEST_DONE) {
1142		struct tevent_context *ctx = dcerpc_event_context(req->p);
1143		if (event_loop_once(ctx) != 0) {
1144			return NT_STATUS_CONNECTION_DISCONNECTED;
1145		}
1146	}
1147	*stub_data = req->payload;
1148	status = req->status;
1149	if (stub_data->data) {
1150		stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1151	}
1152	if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1153		req->p->last_fault_code = req->fault_code;
1154	}
1155	talloc_unlink(talloc_parent(req), req);
1156	return status;
1157}
1158
1159/*
1160  perform a full request/response pair on a dcerpc pipe
1161*/
1162NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1163			struct GUID *object,
1164			uint16_t opnum,
1165			TALLOC_CTX *mem_ctx,
1166			DATA_BLOB *stub_data_in,
1167			DATA_BLOB *stub_data_out)
1168{
1169	struct rpc_request *req;
1170
1171	req = dcerpc_request_send(p, object, opnum, false, stub_data_in);
1172	if (req == NULL) {
1173		return NT_STATUS_NO_MEMORY;
1174	}
1175
1176	return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1177}
1178
1179
1180/*
1181  this is a paranoid NDR validator. For every packet we push onto the wire
1182  we pull it back again, then push it again. Then we compare the raw NDR data
1183  for that to the NDR we initially generated. If they don't match then we know
1184  we must have a bug in either the pull or push side of our code
1185*/
1186static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1187				       TALLOC_CTX *mem_ctx,
1188				       DATA_BLOB blob,
1189				       size_t struct_size,
1190				       ndr_push_flags_fn_t ndr_push,
1191				       ndr_pull_flags_fn_t ndr_pull)
1192{
1193	void *st;
1194	struct ndr_pull *pull;
1195	struct ndr_push *push;
1196	DATA_BLOB blob2;
1197	enum ndr_err_code ndr_err;
1198
1199	st = talloc_size(mem_ctx, struct_size);
1200	if (!st) {
1201		return NT_STATUS_NO_MEMORY;
1202	}
1203
1204	pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1205	if (!pull) {
1206		return NT_STATUS_NO_MEMORY;
1207	}
1208	pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1209
1210	ndr_err = ndr_pull(pull, NDR_IN, st);
1211	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1212		NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1213		ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1214					 "failed input validation pull - %s",
1215					 nt_errstr(status));
1216		return ndr_map_error2ntstatus(ndr_err);
1217	}
1218
1219	push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1220	if (!push) {
1221		return NT_STATUS_NO_MEMORY;
1222	}
1223
1224	ndr_err = ndr_push(push, NDR_IN, st);
1225	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1226		NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1227		ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1228					 "failed input validation push - %s",
1229					 nt_errstr(status));
1230		return ndr_map_error2ntstatus(ndr_err);
1231	}
1232
1233	blob2 = ndr_push_blob(push);
1234
1235	if (data_blob_cmp(&blob, &blob2) != 0) {
1236		DEBUG(3,("original:\n"));
1237		dump_data(3, blob.data, blob.length);
1238		DEBUG(3,("secondary:\n"));
1239		dump_data(3, blob2.data, blob2.length);
1240		ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1241					 "failed input validation blobs doesn't match");
1242		return ndr_map_error2ntstatus(ndr_err);
1243	}
1244
1245	return NT_STATUS_OK;
1246}
1247
1248/*
1249  this is a paranoid NDR input validator. For every packet we pull
1250  from the wire we push it back again then pull and push it
1251  again. Then we compare the raw NDR data for that to the NDR we
1252  initially generated. If they don't match then we know we must have a
1253  bug in either the pull or push side of our code
1254*/
1255static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1256					struct ndr_pull *pull_in,
1257					void *struct_ptr,
1258					size_t struct_size,
1259					ndr_push_flags_fn_t ndr_push,
1260					ndr_pull_flags_fn_t ndr_pull,
1261					ndr_print_function_t ndr_print)
1262{
1263	void *st;
1264	struct ndr_pull *pull;
1265	struct ndr_push *push;
1266	DATA_BLOB blob, blob2;
1267	TALLOC_CTX *mem_ctx = pull_in;
1268	char *s1, *s2;
1269	enum ndr_err_code ndr_err;
1270
1271	st = talloc_size(mem_ctx, struct_size);
1272	if (!st) {
1273		return NT_STATUS_NO_MEMORY;
1274	}
1275	memcpy(st, struct_ptr, struct_size);
1276
1277	push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1278	if (!push) {
1279		return NT_STATUS_NO_MEMORY;
1280	}
1281
1282	ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1283	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1284		NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1285		ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1286					 "failed output validation push - %s",
1287					 nt_errstr(status));
1288		return ndr_map_error2ntstatus(ndr_err);
1289	}
1290
1291	blob = ndr_push_blob(push);
1292
1293	pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1294	if (!pull) {
1295		return NT_STATUS_NO_MEMORY;
1296	}
1297
1298	pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1299	ndr_err = ndr_pull(pull, NDR_OUT, st);
1300	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1301		NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1302		ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1303					 "failed output validation pull - %s",
1304					 nt_errstr(status));
1305		return ndr_map_error2ntstatus(ndr_err);
1306	}
1307
1308	push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1309	if (!push) {
1310		return NT_STATUS_NO_MEMORY;
1311	}
1312
1313	ndr_err = ndr_push(push, NDR_OUT, st);
1314	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1315		NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1316		ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1317					 "failed output validation push2 - %s",
1318					 nt_errstr(status));
1319		return ndr_map_error2ntstatus(ndr_err);
1320	}
1321
1322	blob2 = ndr_push_blob(push);
1323
1324	if (data_blob_cmp(&blob, &blob2) != 0) {
1325		DEBUG(3,("original:\n"));
1326		dump_data(3, blob.data, blob.length);
1327		DEBUG(3,("secondary:\n"));
1328		dump_data(3, blob2.data, blob2.length);
1329		ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1330					 "failed output validation blobs doesn't match");
1331		return ndr_map_error2ntstatus(ndr_err);
1332	}
1333
1334	/* this checks the printed forms of the two structures, which effectively
1335	   tests all of the value() attributes */
1336	s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1337				       NDR_OUT, struct_ptr);
1338	s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1339				       NDR_OUT, st);
1340	if (strcmp(s1, s2) != 0) {
1341#if 1
1342		DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
1343#else
1344		/* this is sometimes useful */
1345		printf("VALIDATE ERROR\n");
1346		file_save("wire.dat", s1, strlen(s1));
1347		file_save("gen.dat", s2, strlen(s2));
1348		system("diff -u wire.dat gen.dat");
1349#endif
1350		ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1351					 "failed output validation strings doesn't match");
1352		return ndr_map_error2ntstatus(ndr_err);
1353	}
1354
1355	return NT_STATUS_OK;
1356}
1357
1358
1359/**
1360 send a rpc request given a dcerpc_call structure
1361 */
1362struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1363					    const struct GUID *object,
1364					    const struct ndr_interface_table *table,
1365					    uint32_t opnum,
1366					    bool async,
1367					    TALLOC_CTX *mem_ctx,
1368					    void *r)
1369{
1370	const struct ndr_interface_call *call;
1371	struct ndr_push *push;
1372	NTSTATUS status;
1373	DATA_BLOB request;
1374	struct rpc_request *req;
1375	enum ndr_err_code ndr_err;
1376
1377	call = &table->calls[opnum];
1378
1379	/* setup for a ndr_push_* call */
1380	push = ndr_push_init_ctx(mem_ctx, p->conn->iconv_convenience);
1381	if (!push) {
1382		return NULL;
1383	}
1384
1385	if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1386		push->flags |= LIBNDR_FLAG_BIGENDIAN;
1387	}
1388
1389	if (p->conn->flags & DCERPC_NDR64) {
1390		push->flags |= LIBNDR_FLAG_NDR64;
1391	}
1392
1393	/* push the structure into a blob */
1394	ndr_err = call->ndr_push(push, NDR_IN, r);
1395	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1396		status = ndr_map_error2ntstatus(ndr_err);
1397		DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1398			 nt_errstr(status)));
1399		talloc_free(push);
1400		return NULL;
1401	}
1402
1403	/* retrieve the blob */
1404	request = ndr_push_blob(push);
1405
1406	if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1407		status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1408						call->ndr_push, call->ndr_pull);
1409		if (!NT_STATUS_IS_OK(status)) {
1410			DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1411				 nt_errstr(status)));
1412			talloc_free(push);
1413			return NULL;
1414		}
1415	}
1416
1417	DEBUG(10,("rpc request data:\n"));
1418	dump_data(10, request.data, request.length);
1419
1420	/* make the actual dcerpc request */
1421	req = dcerpc_request_send(p, object, opnum, async, &request);
1422
1423	if (req != NULL) {
1424		req->ndr.table = table;
1425		req->ndr.opnum = opnum;
1426		req->ndr.struct_ptr = r;
1427		req->ndr.mem_ctx = mem_ctx;
1428	}
1429
1430	talloc_free(push);
1431
1432	return req;
1433}
1434
1435/*
1436  receive the answer from a dcerpc_ndr_request_send()
1437*/
1438_PUBLIC_ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1439{
1440	struct dcerpc_pipe *p = req->p;
1441	NTSTATUS status;
1442	DATA_BLOB response;
1443	struct ndr_pull *pull;
1444	uint_t flags;
1445	TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1446	void *r = req->ndr.struct_ptr;
1447	uint32_t opnum = req->ndr.opnum;
1448	const struct ndr_interface_table *table = req->ndr.table;
1449	const struct ndr_interface_call *call = &table->calls[opnum];
1450	enum ndr_err_code ndr_err;
1451
1452	/* make sure the recv code doesn't free the request, as we
1453	   need to grab the flags element before it is freed */
1454	if (talloc_reference(p, req) == NULL) {
1455		return NT_STATUS_NO_MEMORY;
1456	}
1457
1458	status = dcerpc_request_recv(req, mem_ctx, &response);
1459	if (!NT_STATUS_IS_OK(status)) {
1460		talloc_unlink(p, req);
1461		return status;
1462	}
1463
1464	flags = req->flags;
1465
1466	/* prepare for ndr_pull_* */
1467	pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1468	if (!pull) {
1469		talloc_unlink(p, req);
1470		return NT_STATUS_NO_MEMORY;
1471	}
1472
1473	if (pull->data) {
1474		pull->data = talloc_steal(pull, pull->data);
1475	}
1476	talloc_unlink(p, req);
1477
1478	if (flags & DCERPC_PULL_BIGENDIAN) {
1479		pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1480	}
1481
1482	DEBUG(10,("rpc reply data:\n"));
1483	dump_data(10, pull->data, pull->data_size);
1484
1485	/* pull the structure from the blob */
1486	ndr_err = call->ndr_pull(pull, NDR_OUT, r);
1487	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1488		status = ndr_map_error2ntstatus(ndr_err);
1489		dcerpc_log_packet(p->conn->packet_log_dir,
1490						  table, opnum, NDR_OUT,
1491						  &response);
1492		return status;
1493	}
1494
1495	if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1496		status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1497						 call->ndr_push, call->ndr_pull,
1498						 call->ndr_print);
1499		if (!NT_STATUS_IS_OK(status)) {
1500			dcerpc_log_packet(p->conn->packet_log_dir,
1501							  table, opnum, NDR_OUT,
1502				  &response);
1503			return status;
1504		}
1505	}
1506
1507	if (pull->offset != pull->data_size) {
1508		DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1509			 pull->data_size - pull->offset));
1510		/* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1511		   but it turns out that early versions of NT
1512		   (specifically NT3.1) add junk onto the end of rpc
1513		   packets, so if we want to interoperate at all with
1514		   those versions then we need to ignore this error */
1515	}
1516
1517	/* TODO: make pull context independent from the output mem_ctx and free the pull context */
1518
1519	return NT_STATUS_OK;
1520}
1521
1522
1523/*
1524  a useful helper function for synchronous rpc requests
1525
1526  this can be used when you have ndr push/pull functions in the
1527  standard format
1528*/
1529_PUBLIC_ NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1530			    const struct GUID *object,
1531			    const struct ndr_interface_table *table,
1532			    uint32_t opnum,
1533			    TALLOC_CTX *mem_ctx,
1534			    void *r)
1535{
1536	struct rpc_request *req;
1537
1538	req = dcerpc_ndr_request_send(p, object, table, opnum, false, mem_ctx, r);
1539	if (req == NULL) {
1540		return NT_STATUS_NO_MEMORY;
1541	}
1542
1543	return dcerpc_ndr_request_recv(req);
1544}
1545
1546
1547/*
1548  a useful function for retrieving the server name we connected to
1549*/
1550_PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
1551{
1552	if (!p->conn->transport.target_hostname) {
1553		if (!p->conn->transport.peer_name) {
1554			return "";
1555		}
1556		return p->conn->transport.peer_name(p->conn);
1557	}
1558	return p->conn->transport.target_hostname(p->conn);
1559}
1560
1561
1562/*
1563  get the dcerpc auth_level for a open connection
1564*/
1565uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1566{
1567	uint8_t auth_level;
1568
1569	if (c->flags & DCERPC_SEAL) {
1570		auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1571	} else if (c->flags & DCERPC_SIGN) {
1572		auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1573	} else if (c->flags & DCERPC_CONNECT) {
1574		auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1575	} else {
1576		auth_level = DCERPC_AUTH_LEVEL_NONE;
1577	}
1578	return auth_level;
1579}
1580
1581/*
1582  Receive an alter reply from the transport
1583*/
1584static void dcerpc_alter_recv_handler(struct rpc_request *req,
1585				      DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1586{
1587	struct composite_context *c;
1588	struct dcerpc_pipe *recv_pipe;
1589
1590	c = talloc_get_type(req->async.private_data, struct composite_context);
1591	recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1592
1593	if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1594	    pkt->u.alter_resp.num_results == 1 &&
1595	    pkt->u.alter_resp.ctx_list[0].result != 0) {
1596		DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1597			 pkt->u.alter_resp.ctx_list[0].reason));
1598		composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1599		return;
1600	}
1601
1602	if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1603	    pkt->u.alter_resp.num_results == 0 ||
1604	    pkt->u.alter_resp.ctx_list[0].result != 0) {
1605		composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1606		return;
1607	}
1608
1609	/* the alter_resp might contain a reply set of credentials */
1610	if (recv_pipe->conn->security_state.auth_info &&
1611	    pkt->u.alter_resp.auth_info.length) {
1612		enum ndr_err_code ndr_err;
1613		ndr_err = ndr_pull_struct_blob(
1614			&pkt->u.alter_resp.auth_info, recv_pipe,
1615			NULL,
1616			recv_pipe->conn->security_state.auth_info,
1617			(ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
1618		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1619			c->status = ndr_map_error2ntstatus(ndr_err);
1620			if (!composite_is_ok(c)) return;
1621		}
1622	}
1623
1624	composite_done(c);
1625}
1626
1627/*
1628   send a dcerpc alter_context request
1629*/
1630struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
1631						    TALLOC_CTX *mem_ctx,
1632						    const struct ndr_syntax_id *syntax,
1633						    const struct ndr_syntax_id *transfer_syntax)
1634{
1635	struct composite_context *c;
1636	struct ncacn_packet pkt;
1637	DATA_BLOB blob;
1638	struct rpc_request *req;
1639
1640	c = composite_create(mem_ctx, p->conn->event_ctx);
1641	if (c == NULL) return NULL;
1642
1643	c->private_data = p;
1644
1645	p->syntax = *syntax;
1646	p->transfer_syntax = *transfer_syntax;
1647
1648	init_ncacn_hdr(p->conn, &pkt);
1649
1650	pkt.ptype = DCERPC_PKT_ALTER;
1651	pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1652	pkt.call_id = p->conn->call_id;
1653	pkt.auth_length = 0;
1654
1655	if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1656		pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1657	}
1658
1659	if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1660		pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1661	}
1662
1663	pkt.u.alter.max_xmit_frag = 5840;
1664	pkt.u.alter.max_recv_frag = 5840;
1665	pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
1666	pkt.u.alter.num_contexts = 1;
1667	pkt.u.alter.ctx_list = talloc_array(c, struct dcerpc_ctx_list, 1);
1668	if (composite_nomem(pkt.u.alter.ctx_list, c)) return c;
1669	pkt.u.alter.ctx_list[0].context_id = p->context_id;
1670	pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1671	pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1672	pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1673	pkt.u.alter.auth_info = data_blob(NULL, 0);
1674
1675	/* construct the NDR form of the packet */
1676	c->status = ncacn_push_auth(&blob, mem_ctx, p->conn->iconv_convenience, &pkt,
1677				    p->conn->security_state.auth_info);
1678	if (!composite_is_ok(c)) return c;
1679
1680	p->conn->transport.recv_data = dcerpc_recv_data;
1681
1682	/*
1683	 * we allocate a dcerpc_request so we can be in the same
1684	 * request queue as normal requests
1685	 */
1686	req = talloc_zero(c, struct rpc_request);
1687	if (composite_nomem(req, c)) return c;
1688
1689	req->state = RPC_REQUEST_PENDING;
1690	req->call_id = pkt.call_id;
1691	req->async.private_data = c;
1692	req->async.callback = dcerpc_composite_fail;
1693	req->p = p;
1694	req->recv_handler = dcerpc_alter_recv_handler;
1695	DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1696	talloc_set_destructor(req, dcerpc_req_dequeue);
1697
1698	c->status = p->conn->transport.send_request(p->conn, &blob, true);
1699	if (!composite_is_ok(c)) return c;
1700
1701	event_add_timed(c->event_ctx, req,
1702			timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1703			dcerpc_timeout_handler, req);
1704
1705	return c;
1706}
1707
1708NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1709{
1710	NTSTATUS result = composite_wait(ctx);
1711	talloc_free(ctx);
1712	return result;
1713}
1714
1715/*
1716   send a dcerpc alter_context request
1717*/
1718_PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1719			      TALLOC_CTX *mem_ctx,
1720			      const struct ndr_syntax_id *syntax,
1721			      const struct ndr_syntax_id *transfer_syntax)
1722{
1723	struct composite_context *creq;
1724	creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1725	return dcerpc_alter_context_recv(creq);
1726}
1727