source: branches/samba-3.5.x/source4/librpc/rpc/dcerpc.c

Last change on this file was 414, checked in by Herwig Bauernfeind, 15 years ago

Samba 3.5.0: Initial import

File size: 44.5 KB
Line 
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}
Note: See TracBrowser for help on using the repository browser.