source: vendor/3.6.24/source4/librpc/rpc/dcerpc.c

Last change on this file was 860, checked in by Silvan Scherrer, 11 years ago

Samba 3.6: updated vendor to latest version

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