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

Last change on this file was 989, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.7

File size: 69.9 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 "system/filesys.h"
25#include "../lib/util/dlinklist.h"
26#include "lib/events/events.h"
27#include "librpc/rpc/dcerpc.h"
28#include "librpc/rpc/dcerpc_proto.h"
29#include "librpc/gen_ndr/ndr_misc.h"
30#include "librpc/gen_ndr/ndr_dcerpc.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#include "lib/tsocket/tsocket.h"
36#include "libcli/smb/tstream_smbXcli_np.h"
37
38
39enum rpc_request_state {
40 RPC_REQUEST_QUEUED,
41 RPC_REQUEST_PENDING,
42 RPC_REQUEST_DONE
43};
44
45/*
46 handle for an async dcerpc request
47*/
48struct rpc_request {
49 struct rpc_request *next, *prev;
50 struct dcerpc_pipe *p;
51 NTSTATUS status;
52 uint32_t call_id;
53 enum rpc_request_state state;
54 DATA_BLOB payload;
55 uint32_t flags;
56 uint32_t fault_code;
57
58 /* this is used to distinguish bind and alter_context requests
59 from normal requests */
60 void (*recv_handler)(struct rpc_request *conn,
61 DATA_BLOB *blob, struct ncacn_packet *pkt);
62
63 const struct GUID *object;
64 uint16_t opnum;
65 DATA_BLOB request_data;
66 bool ignore_timeout;
67 bool wait_for_sync;
68 bool verify_bitmask1;
69 bool verify_pcontext;
70
71 struct {
72 void (*callback)(struct rpc_request *);
73 void *private_data;
74 } async;
75};
76
77_PUBLIC_ NTSTATUS dcerpc_init(void)
78{
79 return gensec_init();
80}
81
82static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status);
83static void dcerpc_schedule_io_trigger(struct dcecli_connection *c);
84
85static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
86 struct dcerpc_pipe *p,
87 const struct GUID *object,
88 uint16_t opnum,
89 DATA_BLOB *stub_data);
90static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
91 TALLOC_CTX *mem_ctx,
92 DATA_BLOB *stub_data);
93static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
94 TALLOC_CTX *mem_ctx,
95 DATA_BLOB blob,
96 size_t struct_size,
97 ndr_push_flags_fn_t ndr_push,
98 ndr_pull_flags_fn_t ndr_pull);
99static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
100 struct ndr_pull *pull_in,
101 void *struct_ptr,
102 size_t struct_size,
103 ndr_push_flags_fn_t ndr_push,
104 ndr_pull_flags_fn_t ndr_pull,
105 ndr_print_function_t ndr_print);
106static NTSTATUS dcerpc_shutdown_pipe(struct dcecli_connection *p, NTSTATUS status);
107static NTSTATUS dcerpc_send_request(struct dcecli_connection *p, DATA_BLOB *data,
108 bool trigger_read);
109static NTSTATUS dcerpc_send_read(struct dcecli_connection *p);
110
111/* destroy a dcerpc connection */
112static int dcerpc_connection_destructor(struct dcecli_connection *conn)
113{
114 if (conn->dead) {
115 conn->free_skipped = true;
116 return -1;
117 }
118 dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
119 return 0;
120}
121
122
123/* initialise a dcerpc connection.
124 the event context is optional
125*/
126static struct dcecli_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
127 struct tevent_context *ev)
128{
129 struct dcecli_connection *c;
130
131 c = talloc_zero(mem_ctx, struct dcecli_connection);
132 if (!c) {
133 return NULL;
134 }
135
136 c->event_ctx = ev;
137
138 if (c->event_ctx == NULL) {
139 talloc_free(c);
140 return NULL;
141 }
142
143 c->call_id = 1;
144 c->security_state.auth_type = DCERPC_AUTH_TYPE_NONE;
145 c->security_state.auth_level = DCERPC_AUTH_LEVEL_NONE;
146 c->security_state.auth_context_id = 0;
147 c->security_state.session_key = dcerpc_generic_session_key;
148 c->security_state.generic_state = NULL;
149 c->flags = 0;
150 /*
151 * Windows uses 5840 for ncacn_ip_tcp,
152 * so we also use it (for every transport)
153 * by default. But we give the transport
154 * the chance to overwrite it.
155 */
156 c->srv_max_xmit_frag = 5840;
157 c->srv_max_recv_frag = 5840;
158 c->max_total_response_size = DCERPC_NCACN_RESPONSE_DEFAULT_MAX_SIZE;
159 c->pending = NULL;
160
161 c->io_trigger = tevent_create_immediate(c);
162 if (c->io_trigger == NULL) {
163 talloc_free(c);
164 return NULL;
165 }
166
167 talloc_set_destructor(c, dcerpc_connection_destructor);
168
169 return c;
170}
171
172struct dcerpc_bh_state {
173 struct dcerpc_pipe *p;
174};
175
176static bool dcerpc_bh_is_connected(struct dcerpc_binding_handle *h)
177{
178 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
179 struct dcerpc_bh_state);
180
181 if (!hs->p) {
182 return false;
183 }
184
185 if (!hs->p->conn) {
186 return false;
187 }
188
189 if (hs->p->conn->dead) {
190 return false;
191 }
192
193 return true;
194}
195
196static uint32_t dcerpc_bh_set_timeout(struct dcerpc_binding_handle *h,
197 uint32_t timeout)
198{
199 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
200 struct dcerpc_bh_state);
201 uint32_t old;
202
203 if (!hs->p) {
204 return DCERPC_REQUEST_TIMEOUT;
205 }
206
207 old = hs->p->request_timeout;
208 hs->p->request_timeout = timeout;
209
210 return old;
211}
212
213static void dcerpc_bh_auth_info(struct dcerpc_binding_handle *h,
214 enum dcerpc_AuthType *auth_type,
215 enum dcerpc_AuthLevel *auth_level)
216{
217 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
218 struct dcerpc_bh_state);
219
220 if (hs->p == NULL) {
221 return;
222 }
223
224 if (hs->p->conn == NULL) {
225 return;
226 }
227
228 *auth_type = hs->p->conn->security_state.auth_type;
229 *auth_level = hs->p->conn->security_state.auth_level;
230}
231
232struct dcerpc_bh_raw_call_state {
233 struct tevent_context *ev;
234 struct dcerpc_binding_handle *h;
235 DATA_BLOB in_data;
236 DATA_BLOB out_data;
237 uint32_t out_flags;
238};
239
240static void dcerpc_bh_raw_call_done(struct rpc_request *subreq);
241
242static struct tevent_req *dcerpc_bh_raw_call_send(TALLOC_CTX *mem_ctx,
243 struct tevent_context *ev,
244 struct dcerpc_binding_handle *h,
245 const struct GUID *object,
246 uint32_t opnum,
247 uint32_t in_flags,
248 const uint8_t *in_data,
249 size_t in_length)
250{
251 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
252 struct dcerpc_bh_state);
253 struct tevent_req *req;
254 struct dcerpc_bh_raw_call_state *state;
255 bool ok;
256 struct rpc_request *subreq;
257
258 req = tevent_req_create(mem_ctx, &state,
259 struct dcerpc_bh_raw_call_state);
260 if (req == NULL) {
261 return NULL;
262 }
263 state->ev = ev;
264 state->h = h;
265 state->in_data.data = discard_const_p(uint8_t, in_data);
266 state->in_data.length = in_length;
267
268 ok = dcerpc_bh_is_connected(h);
269 if (!ok) {
270 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
271 return tevent_req_post(req, ev);
272 }
273
274 subreq = dcerpc_request_send(state,
275 hs->p,
276 object,
277 opnum,
278 &state->in_data);
279 if (tevent_req_nomem(subreq, req)) {
280 return tevent_req_post(req, ev);
281 }
282 subreq->async.callback = dcerpc_bh_raw_call_done;
283 subreq->async.private_data = req;
284
285 return req;
286}
287
288static void dcerpc_bh_raw_call_done(struct rpc_request *subreq)
289{
290 struct tevent_req *req =
291 talloc_get_type_abort(subreq->async.private_data,
292 struct tevent_req);
293 struct dcerpc_bh_raw_call_state *state =
294 tevent_req_data(req,
295 struct dcerpc_bh_raw_call_state);
296 NTSTATUS status;
297 uint32_t fault_code;
298
299 state->out_flags = 0;
300 if (subreq->flags & DCERPC_PULL_BIGENDIAN) {
301 state->out_flags |= LIBNDR_FLAG_BIGENDIAN;
302 }
303
304 fault_code = subreq->fault_code;
305
306 status = dcerpc_request_recv(subreq, state, &state->out_data);
307 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
308 status = dcerpc_fault_to_nt_status(fault_code);
309 }
310
311 /*
312 * We trigger the callback in the next event run
313 * because the code in this file might trigger
314 * multiple request callbacks from within a single
315 * while loop.
316 *
317 * In order to avoid segfaults from within
318 * dcerpc_connection_dead() we call
319 * tevent_req_defer_callback().
320 */
321 tevent_req_defer_callback(req, state->ev);
322
323 if (!NT_STATUS_IS_OK(status)) {
324 tevent_req_nterror(req, status);
325 return;
326 }
327
328 tevent_req_done(req);
329}
330
331static NTSTATUS dcerpc_bh_raw_call_recv(struct tevent_req *req,
332 TALLOC_CTX *mem_ctx,
333 uint8_t **out_data,
334 size_t *out_length,
335 uint32_t *out_flags)
336{
337 struct dcerpc_bh_raw_call_state *state =
338 tevent_req_data(req,
339 struct dcerpc_bh_raw_call_state);
340 NTSTATUS status;
341
342 if (tevent_req_is_nterror(req, &status)) {
343 tevent_req_received(req);
344 return status;
345 }
346
347 *out_data = talloc_move(mem_ctx, &state->out_data.data);
348 *out_length = state->out_data.length;
349 *out_flags = state->out_flags;
350 tevent_req_received(req);
351 return NT_STATUS_OK;
352}
353
354struct dcerpc_bh_disconnect_state {
355 uint8_t _dummy;
356};
357
358static struct tevent_req *dcerpc_bh_disconnect_send(TALLOC_CTX *mem_ctx,
359 struct tevent_context *ev,
360 struct dcerpc_binding_handle *h)
361{
362 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
363 struct dcerpc_bh_state);
364 struct tevent_req *req;
365 struct dcerpc_bh_disconnect_state *state;
366 bool ok;
367
368 req = tevent_req_create(mem_ctx, &state,
369 struct dcerpc_bh_disconnect_state);
370 if (req == NULL) {
371 return NULL;
372 }
373
374 ok = dcerpc_bh_is_connected(h);
375 if (!ok) {
376 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
377 return tevent_req_post(req, ev);
378 }
379
380 /* TODO: do a real disconnect ... */
381 hs->p = NULL;
382
383 tevent_req_done(req);
384 return tevent_req_post(req, ev);
385}
386
387static NTSTATUS dcerpc_bh_disconnect_recv(struct tevent_req *req)
388{
389 NTSTATUS status;
390
391 if (tevent_req_is_nterror(req, &status)) {
392 tevent_req_received(req);
393 return status;
394 }
395
396 tevent_req_received(req);
397 return NT_STATUS_OK;
398}
399
400static bool dcerpc_bh_push_bigendian(struct dcerpc_binding_handle *h)
401{
402 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
403 struct dcerpc_bh_state);
404
405 if (hs->p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
406 return true;
407 }
408
409 return false;
410}
411
412static bool dcerpc_bh_ref_alloc(struct dcerpc_binding_handle *h)
413{
414 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
415 struct dcerpc_bh_state);
416
417 if (hs->p->conn->flags & DCERPC_NDR_REF_ALLOC) {
418 return true;
419 }
420
421 return false;
422}
423
424static bool dcerpc_bh_use_ndr64(struct dcerpc_binding_handle *h)
425{
426 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
427 struct dcerpc_bh_state);
428
429 if (hs->p->conn->flags & DCERPC_NDR64) {
430 return true;
431 }
432
433 return false;
434}
435
436static void dcerpc_bh_do_ndr_print(struct dcerpc_binding_handle *h,
437 int ndr_flags,
438 const void *_struct_ptr,
439 const struct ndr_interface_call *call)
440{
441 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
442 struct dcerpc_bh_state);
443 void *struct_ptr = discard_const(_struct_ptr);
444
445 if (ndr_flags & NDR_IN) {
446 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_IN) {
447 ndr_print_function_debug(call->ndr_print,
448 call->name,
449 ndr_flags,
450 struct_ptr);
451 }
452 }
453 if (ndr_flags & NDR_OUT) {
454 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
455 ndr_print_function_debug(call->ndr_print,
456 call->name,
457 ndr_flags,
458 struct_ptr);
459 }
460 }
461}
462
463static void dcerpc_bh_ndr_push_failed(struct dcerpc_binding_handle *h,
464 NTSTATUS error,
465 const void *struct_ptr,
466 const struct ndr_interface_call *call)
467{
468 DEBUG(2,("Unable to ndr_push structure for %s - %s\n",
469 call->name, nt_errstr(error)));
470}
471
472static void dcerpc_bh_ndr_pull_failed(struct dcerpc_binding_handle *h,
473 NTSTATUS error,
474 const DATA_BLOB *blob,
475 const struct ndr_interface_call *call)
476{
477 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
478 struct dcerpc_bh_state);
479 const uint32_t num_examples = 20;
480 uint32_t i;
481
482 DEBUG(2,("Unable to ndr_pull structure for %s - %s\n",
483 call->name, nt_errstr(error)));
484
485 if (hs->p->conn->packet_log_dir == NULL) return;
486
487 for (i=0;i<num_examples;i++) {
488 char *name=NULL;
489 int ret;
490
491 ret = asprintf(&name, "%s/rpclog/%s-out.%d",
492 hs->p->conn->packet_log_dir,
493 call->name, i);
494 if (ret == -1) {
495 return;
496 }
497 if (!file_exist(name)) {
498 if (file_save(name, blob->data, blob->length)) {
499 DEBUG(10,("Logged rpc packet to %s\n", name));
500 }
501 free(name);
502 break;
503 }
504 free(name);
505 }
506}
507
508static NTSTATUS dcerpc_bh_ndr_validate_in(struct dcerpc_binding_handle *h,
509 TALLOC_CTX *mem_ctx,
510 const DATA_BLOB *blob,
511 const struct ndr_interface_call *call)
512{
513 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
514 struct dcerpc_bh_state);
515
516 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
517 NTSTATUS status;
518
519 status = dcerpc_ndr_validate_in(hs->p->conn,
520 mem_ctx,
521 *blob,
522 call->struct_size,
523 call->ndr_push,
524 call->ndr_pull);
525 if (!NT_STATUS_IS_OK(status)) {
526 DEBUG(0,("Validation [in] failed for %s - %s\n",
527 call->name, nt_errstr(status)));
528 return status;
529 }
530 }
531
532 DEBUG(10,("rpc request data:\n"));
533 dump_data(10, blob->data, blob->length);
534
535 return NT_STATUS_OK;
536}
537
538static NTSTATUS dcerpc_bh_ndr_validate_out(struct dcerpc_binding_handle *h,
539 struct ndr_pull *pull_in,
540 const void *_struct_ptr,
541 const struct ndr_interface_call *call)
542{
543 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
544 struct dcerpc_bh_state);
545 void *struct_ptr = discard_const(_struct_ptr);
546
547 DEBUG(10,("rpc reply data:\n"));
548 dump_data(10, pull_in->data, pull_in->data_size);
549
550 if (pull_in->offset != pull_in->data_size) {
551 DEBUG(0,("Warning! ignoring %u unread bytes at ofs:%u (0x%08X) for %s!\n",
552 pull_in->data_size - pull_in->offset,
553 pull_in->offset, pull_in->offset,
554 call->name));
555 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
556 but it turns out that early versions of NT
557 (specifically NT3.1) add junk onto the end of rpc
558 packets, so if we want to interoperate at all with
559 those versions then we need to ignore this error */
560 }
561
562 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
563 NTSTATUS status;
564
565 status = dcerpc_ndr_validate_out(hs->p->conn,
566 pull_in,
567 struct_ptr,
568 call->struct_size,
569 call->ndr_push,
570 call->ndr_pull,
571 call->ndr_print);
572 if (!NT_STATUS_IS_OK(status)) {
573 DEBUG(2,("Validation [out] failed for %s - %s\n",
574 call->name, nt_errstr(status)));
575 return status;
576 }
577 }
578
579 return NT_STATUS_OK;
580}
581
582static const struct dcerpc_binding_handle_ops dcerpc_bh_ops = {
583 .name = "dcerpc",
584 .is_connected = dcerpc_bh_is_connected,
585 .set_timeout = dcerpc_bh_set_timeout,
586 .auth_info = dcerpc_bh_auth_info,
587 .raw_call_send = dcerpc_bh_raw_call_send,
588 .raw_call_recv = dcerpc_bh_raw_call_recv,
589 .disconnect_send = dcerpc_bh_disconnect_send,
590 .disconnect_recv = dcerpc_bh_disconnect_recv,
591
592 .push_bigendian = dcerpc_bh_push_bigendian,
593 .ref_alloc = dcerpc_bh_ref_alloc,
594 .use_ndr64 = dcerpc_bh_use_ndr64,
595 .do_ndr_print = dcerpc_bh_do_ndr_print,
596 .ndr_push_failed = dcerpc_bh_ndr_push_failed,
597 .ndr_pull_failed = dcerpc_bh_ndr_pull_failed,
598 .ndr_validate_in = dcerpc_bh_ndr_validate_in,
599 .ndr_validate_out = dcerpc_bh_ndr_validate_out,
600};
601
602/* initialise a dcerpc pipe. */
603struct dcerpc_binding_handle *dcerpc_pipe_binding_handle(struct dcerpc_pipe *p)
604{
605 struct dcerpc_binding_handle *h;
606 struct dcerpc_bh_state *hs;
607
608 h = dcerpc_binding_handle_create(p,
609 &dcerpc_bh_ops,
610 NULL,
611 NULL, /* TODO */
612 &hs,
613 struct dcerpc_bh_state,
614 __location__);
615 if (h == NULL) {
616 return NULL;
617 }
618 hs->p = p;
619
620 dcerpc_binding_handle_set_sync_ev(h, p->conn->event_ctx);
621
622 return h;
623}
624
625/* initialise a dcerpc pipe. */
626_PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev)
627{
628 struct dcerpc_pipe *p;
629
630 p = talloc_zero(mem_ctx, struct dcerpc_pipe);
631 if (!p) {
632 return NULL;
633 }
634
635 p->conn = dcerpc_connection_init(p, ev);
636 if (p->conn == NULL) {
637 talloc_free(p);
638 return NULL;
639 }
640
641 p->last_fault_code = 0;
642 p->context_id = 0;
643 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
644 p->binding = NULL;
645
646 ZERO_STRUCT(p->syntax);
647 ZERO_STRUCT(p->transfer_syntax);
648
649 if (DEBUGLVL(100)) {
650 p->conn->flags |= DCERPC_DEBUG_PRINT_BOTH;
651 }
652
653 p->binding_handle = dcerpc_pipe_binding_handle(p);
654 if (p->binding_handle == NULL) {
655 talloc_free(p);
656 return NULL;
657 }
658
659 return p;
660}
661
662
663/*
664 choose the next call id to use
665*/
666static uint32_t next_call_id(struct dcecli_connection *c)
667{
668 c->call_id++;
669 if (c->call_id == 0) {
670 c->call_id++;
671 }
672 return c->call_id;
673}
674
675/**
676 setup for a ndr pull, also setting up any flags from the binding string
677*/
678static struct ndr_pull *ndr_pull_init_flags(struct dcecli_connection *c,
679 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
680{
681 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
682
683 if (ndr == NULL) return ndr;
684
685 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
686 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
687 }
688
689 if (c->flags & DCERPC_NDR_REF_ALLOC) {
690 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
691 }
692
693 if (c->flags & DCERPC_NDR64) {
694 ndr->flags |= LIBNDR_FLAG_NDR64;
695 }
696
697 return ndr;
698}
699
700/*
701 parse a data blob into a ncacn_packet structure. This handles both
702 input and output packets
703*/
704static NTSTATUS ncacn_pull(struct dcecli_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
705 struct ncacn_packet *pkt)
706{
707 struct ndr_pull *ndr;
708 enum ndr_err_code ndr_err;
709
710 ndr = ndr_pull_init_blob(blob, mem_ctx);
711 if (!ndr) {
712 return NT_STATUS_NO_MEMORY;
713 }
714
715 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
716 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
717 }
718
719 if (CVAL(blob->data, DCERPC_PFC_OFFSET) & DCERPC_PFC_FLAG_OBJECT_UUID) {
720 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
721 }
722
723 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
724 TALLOC_FREE(ndr);
725 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
726 return ndr_map_error2ntstatus(ndr_err);
727 }
728
729 if (pkt->frag_length != blob->length) {
730 return NT_STATUS_RPC_PROTOCOL_ERROR;
731 }
732
733 return NT_STATUS_OK;
734}
735
736/*
737 parse the authentication information on a dcerpc response packet
738*/
739static NTSTATUS ncacn_pull_request_auth(struct dcecli_connection *c, TALLOC_CTX *mem_ctx,
740 DATA_BLOB *raw_packet,
741 struct ncacn_packet *pkt)
742{
743 NTSTATUS status;
744 struct dcerpc_auth auth;
745 uint32_t auth_length;
746
747 status = dcerpc_verify_ncacn_packet_header(pkt, DCERPC_PKT_RESPONSE,
748 pkt->u.response.stub_and_verifier.length,
749 0, /* required_flags */
750 DCERPC_PFC_FLAG_FIRST |
751 DCERPC_PFC_FLAG_LAST);
752 if (!NT_STATUS_IS_OK(status)) {
753 return status;
754 }
755
756 switch (c->security_state.auth_level) {
757 case DCERPC_AUTH_LEVEL_PRIVACY:
758 case DCERPC_AUTH_LEVEL_INTEGRITY:
759 break;
760
761 case DCERPC_AUTH_LEVEL_CONNECT:
762 if (pkt->auth_length != 0) {
763 break;
764 }
765 return NT_STATUS_OK;
766 case DCERPC_AUTH_LEVEL_NONE:
767 if (pkt->auth_length != 0) {
768 return NT_STATUS_INVALID_NETWORK_RESPONSE;
769 }
770 return NT_STATUS_OK;
771
772 default:
773 return NT_STATUS_INVALID_LEVEL;
774 }
775
776 if (pkt->auth_length == 0) {
777 return NT_STATUS_INVALID_NETWORK_RESPONSE;
778 }
779
780 if (c->security_state.generic_state == NULL) {
781 return NT_STATUS_INTERNAL_ERROR;
782 }
783
784 status = dcerpc_pull_auth_trailer(pkt, mem_ctx,
785 &pkt->u.response.stub_and_verifier,
786 &auth, &auth_length, false);
787 NT_STATUS_NOT_OK_RETURN(status);
788
789 pkt->u.response.stub_and_verifier.length -= auth_length;
790
791 if (auth.auth_type != c->security_state.auth_type) {
792 return NT_STATUS_RPC_PROTOCOL_ERROR;
793 }
794
795 if (auth.auth_level != c->security_state.auth_level) {
796 return NT_STATUS_RPC_PROTOCOL_ERROR;
797 }
798
799 if (auth.auth_context_id != c->security_state.auth_context_id) {
800 return NT_STATUS_RPC_PROTOCOL_ERROR;
801 }
802
803 /* check signature or unseal the packet */
804 switch (c->security_state.auth_level) {
805 case DCERPC_AUTH_LEVEL_PRIVACY:
806 status = gensec_unseal_packet(c->security_state.generic_state,
807 raw_packet->data + DCERPC_REQUEST_LENGTH,
808 pkt->u.response.stub_and_verifier.length,
809 raw_packet->data,
810 raw_packet->length - auth.credentials.length,
811 &auth.credentials);
812 memcpy(pkt->u.response.stub_and_verifier.data,
813 raw_packet->data + DCERPC_REQUEST_LENGTH,
814 pkt->u.response.stub_and_verifier.length);
815 break;
816
817 case DCERPC_AUTH_LEVEL_INTEGRITY:
818 status = gensec_check_packet(c->security_state.generic_state,
819 pkt->u.response.stub_and_verifier.data,
820 pkt->u.response.stub_and_verifier.length,
821 raw_packet->data,
822 raw_packet->length - auth.credentials.length,
823 &auth.credentials);
824 break;
825
826 case DCERPC_AUTH_LEVEL_CONNECT:
827 /* for now we ignore possible signatures here */
828 status = NT_STATUS_OK;
829 break;
830
831 default:
832 status = NT_STATUS_INVALID_LEVEL;
833 break;
834 }
835
836 /* remove the indicated amount of padding */
837 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
838 return NT_STATUS_INFO_LENGTH_MISMATCH;
839 }
840 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
841
842 return status;
843}
844
845
846/*
847 push a dcerpc request packet into a blob, possibly signing it.
848*/
849static NTSTATUS ncacn_push_request_sign(struct dcecli_connection *c,
850 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
851 size_t sig_size,
852 struct ncacn_packet *pkt)
853{
854 NTSTATUS status;
855 struct ndr_push *ndr;
856 DATA_BLOB creds2;
857 size_t payload_length;
858 enum ndr_err_code ndr_err;
859 size_t hdr_size = DCERPC_REQUEST_LENGTH;
860 struct dcerpc_auth auth_info = {
861 .auth_type = c->security_state.auth_type,
862 .auth_level = c->security_state.auth_level,
863 .auth_context_id = c->security_state.auth_context_id,
864 };
865
866 switch (c->security_state.auth_level) {
867 case DCERPC_AUTH_LEVEL_PRIVACY:
868 case DCERPC_AUTH_LEVEL_INTEGRITY:
869 if (sig_size == 0) {
870 return NT_STATUS_INTERNAL_ERROR;
871 }
872 break;
873
874 case DCERPC_AUTH_LEVEL_CONNECT:
875 /* TODO: let the gensec mech decide if it wants to generate a signature */
876 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
877
878 case DCERPC_AUTH_LEVEL_NONE:
879 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
880
881 default:
882 return NT_STATUS_INVALID_LEVEL;
883 }
884
885 ndr = ndr_push_init_ctx(mem_ctx);
886 if (!ndr) {
887 return NT_STATUS_NO_MEMORY;
888 }
889
890 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
891 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
892 }
893
894 if (c->flags & DCERPC_NDR64) {
895 ndr->flags |= LIBNDR_FLAG_NDR64;
896 }
897
898 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
899 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
900 hdr_size += 16;
901 }
902
903 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
904 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
905 return ndr_map_error2ntstatus(ndr_err);
906 }
907
908 /* pad to 16 byte multiple in the payload portion of the
909 packet. This matches what w2k3 does. Note that we can't use
910 ndr_push_align() as that is relative to the start of the
911 whole packet, whereas w2k8 wants it relative to the start
912 of the stub */
913 auth_info.auth_pad_length =
914 DCERPC_AUTH_PAD_LENGTH(pkt->u.request.stub_and_verifier.length);
915 ndr_err = ndr_push_zero(ndr, auth_info.auth_pad_length);
916 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
917 return ndr_map_error2ntstatus(ndr_err);
918 }
919
920 payload_length = pkt->u.request.stub_and_verifier.length +
921 auth_info.auth_pad_length;
922
923 /* add the auth verifier */
924 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth_info);
925 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
926 return ndr_map_error2ntstatus(ndr_err);
927 }
928
929 /* extract the whole packet as a blob */
930 *blob = ndr_push_blob(ndr);
931
932 /*
933 * Setup the frag and auth length in the packet buffer.
934 * This is needed if the GENSEC mech does AEAD signing
935 * of the packet headers. The signature itself will be
936 * appended later.
937 */
938 dcerpc_set_frag_length(blob, blob->length + sig_size);
939 dcerpc_set_auth_length(blob, sig_size);
940
941 /* sign or seal the packet */
942 switch (c->security_state.auth_level) {
943 case DCERPC_AUTH_LEVEL_PRIVACY:
944 status = gensec_seal_packet(c->security_state.generic_state,
945 mem_ctx,
946 blob->data + hdr_size,
947 payload_length,
948 blob->data,
949 blob->length,
950 &creds2);
951 if (!NT_STATUS_IS_OK(status)) {
952 return status;
953 }
954 break;
955
956 case DCERPC_AUTH_LEVEL_INTEGRITY:
957 status = gensec_sign_packet(c->security_state.generic_state,
958 mem_ctx,
959 blob->data + hdr_size,
960 payload_length,
961 blob->data,
962 blob->length,
963 &creds2);
964 if (!NT_STATUS_IS_OK(status)) {
965 return status;
966 }
967 break;
968
969 default:
970 status = NT_STATUS_INVALID_LEVEL;
971 break;
972 }
973
974 if (creds2.length != sig_size) {
975 /* this means the sig_size estimate for the signature
976 was incorrect. We have to correct the packet
977 sizes. That means we could go over the max fragment
978 length */
979 DEBUG(3,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
980 (unsigned) creds2.length,
981 (unsigned) sig_size,
982 (unsigned) auth_info.auth_pad_length,
983 (unsigned) pkt->u.request.stub_and_verifier.length));
984 dcerpc_set_frag_length(blob, blob->length + creds2.length);
985 dcerpc_set_auth_length(blob, creds2.length);
986 }
987
988 if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
989 return NT_STATUS_NO_MEMORY;
990 }
991
992 return NT_STATUS_OK;
993}
994
995
996/*
997 fill in the fixed values in a dcerpc header
998*/
999static void init_ncacn_hdr(struct dcecli_connection *c, struct ncacn_packet *pkt)
1000{
1001 pkt->rpc_vers = 5;
1002 pkt->rpc_vers_minor = 0;
1003 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1004 pkt->drep[0] = 0;
1005 } else {
1006 pkt->drep[0] = DCERPC_DREP_LE;
1007 }
1008 pkt->drep[1] = 0;
1009 pkt->drep[2] = 0;
1010 pkt->drep[3] = 0;
1011}
1012
1013/*
1014 map a bind nak reason to a NTSTATUS
1015*/
1016static NTSTATUS dcerpc_map_nak_reason(enum dcerpc_bind_nak_reason reason)
1017{
1018 switch (reason) {
1019 case DCERPC_BIND_NAK_REASON_PROTOCOL_VERSION_NOT_SUPPORTED:
1020 return NT_STATUS_REVISION_MISMATCH;
1021 case DCERPC_BIND_NAK_REASON_INVALID_AUTH_TYPE:
1022 return NT_STATUS_INVALID_PARAMETER;
1023 default:
1024 break;
1025 }
1026 return NT_STATUS_UNSUCCESSFUL;
1027}
1028
1029static NTSTATUS dcerpc_map_ack_reason(const struct dcerpc_ack_ctx *ack)
1030{
1031 if (ack == NULL) {
1032 return NT_STATUS_RPC_PROTOCOL_ERROR;
1033 }
1034
1035 switch (ack->result) {
1036 case DCERPC_BIND_ACK_RESULT_NEGOTIATE_ACK:
1037 /*
1038 * We have not asked for this...
1039 */
1040 return NT_STATUS_RPC_PROTOCOL_ERROR;
1041 default:
1042 break;
1043 }
1044
1045 switch (ack->reason.value) {
1046 case DCERPC_BIND_ACK_REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED:
1047 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
1048 case DCERPC_BIND_ACK_REASON_TRANSFER_SYNTAXES_NOT_SUPPORTED:
1049 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
1050 default:
1051 break;
1052 }
1053 return NT_STATUS_UNSUCCESSFUL;
1054}
1055
1056/*
1057 remove requests from the pending or queued queues
1058 */
1059static int dcerpc_req_dequeue(struct rpc_request *req)
1060{
1061 switch (req->state) {
1062 case RPC_REQUEST_QUEUED:
1063 DLIST_REMOVE(req->p->conn->request_queue, req);
1064 break;
1065 case RPC_REQUEST_PENDING:
1066 DLIST_REMOVE(req->p->conn->pending, req);
1067 break;
1068 case RPC_REQUEST_DONE:
1069 break;
1070 }
1071 return 0;
1072}
1073
1074
1075/*
1076 mark the dcerpc connection dead. All outstanding requests get an error
1077*/
1078static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status)
1079{
1080 if (conn->dead) return;
1081
1082 conn->dead = true;
1083
1084 TALLOC_FREE(conn->io_trigger);
1085 conn->io_trigger_pending = false;
1086
1087 dcerpc_shutdown_pipe(conn, status);
1088
1089 /* all pending requests get the error */
1090 while (conn->pending) {
1091 struct rpc_request *req = conn->pending;
1092 dcerpc_req_dequeue(req);
1093 req->state = RPC_REQUEST_DONE;
1094 req->status = status;
1095 if (req->async.callback) {
1096 req->async.callback(req);
1097 }
1098 }
1099
1100 /* all requests, which are not shipped */
1101 while (conn->request_queue) {
1102 struct rpc_request *req = conn->request_queue;
1103 dcerpc_req_dequeue(req);
1104 req->state = RPC_REQUEST_DONE;
1105 req->status = status;
1106 if (req->async.callback) {
1107 req->async.callback(req);
1108 }
1109 }
1110
1111 talloc_set_destructor(conn, NULL);
1112 if (conn->free_skipped) {
1113 talloc_free(conn);
1114 }
1115}
1116
1117/*
1118 forward declarations of the recv_data handlers for the types of
1119 packets we need to handle
1120*/
1121static void dcerpc_request_recv_data(struct dcecli_connection *c,
1122 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
1123
1124/*
1125 receive a dcerpc reply from the transport. Here we work out what
1126 type of reply it is (normal request, bind or alter context) and
1127 dispatch to the appropriate handler
1128*/
1129static void dcerpc_recv_data(struct dcecli_connection *conn, DATA_BLOB *blob, NTSTATUS status)
1130{
1131 struct ncacn_packet pkt;
1132
1133 if (conn->dead) {
1134 return;
1135 }
1136
1137 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
1138 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1139 }
1140
1141 /* the transport may be telling us of a severe error, such as
1142 a dropped socket */
1143 if (!NT_STATUS_IS_OK(status)) {
1144 data_blob_free(blob);
1145 dcerpc_connection_dead(conn, status);
1146 return;
1147 }
1148
1149 /* parse the basic packet to work out what type of response this is */
1150 status = ncacn_pull(conn, blob, blob->data, &pkt);
1151 if (!NT_STATUS_IS_OK(status)) {
1152 data_blob_free(blob);
1153 dcerpc_connection_dead(conn, status);
1154 return;
1155 }
1156
1157 dcerpc_request_recv_data(conn, blob, &pkt);
1158}
1159
1160/*
1161 handle timeouts of individual dcerpc requests
1162*/
1163static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
1164 struct timeval t, void *private_data)
1165{
1166 struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
1167
1168 if (req->ignore_timeout) {
1169 dcerpc_req_dequeue(req);
1170 req->state = RPC_REQUEST_DONE;
1171 req->status = NT_STATUS_IO_TIMEOUT;
1172 if (req->async.callback) {
1173 req->async.callback(req);
1174 }
1175 return;
1176 }
1177
1178 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
1179}
1180
1181struct dcerpc_bind_state {
1182 struct tevent_context *ev;
1183 struct dcerpc_pipe *p;
1184};
1185
1186static void dcerpc_bind_fail_handler(struct rpc_request *subreq);
1187static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1188 DATA_BLOB *raw_packet,
1189 struct ncacn_packet *pkt);
1190
1191struct tevent_req *dcerpc_bind_send(TALLOC_CTX *mem_ctx,
1192 struct tevent_context *ev,
1193 struct dcerpc_pipe *p,
1194 const struct ndr_syntax_id *syntax,
1195 const struct ndr_syntax_id *transfer_syntax)
1196{
1197 struct tevent_req *req;
1198 struct dcerpc_bind_state *state;
1199 struct ncacn_packet pkt;
1200 DATA_BLOB blob;
1201 NTSTATUS status;
1202 struct rpc_request *subreq;
1203 uint32_t flags;
1204
1205 req = tevent_req_create(mem_ctx, &state,
1206 struct dcerpc_bind_state);
1207 if (req == NULL) {
1208 return NULL;
1209 }
1210
1211 state->ev = ev;
1212 state->p = p;
1213
1214 p->syntax = *syntax;
1215 p->transfer_syntax = *transfer_syntax;
1216
1217 flags = dcerpc_binding_get_flags(p->binding);
1218
1219 init_ncacn_hdr(p->conn, &pkt);
1220
1221 pkt.ptype = DCERPC_PKT_BIND;
1222 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1223 pkt.call_id = p->conn->call_id;
1224 pkt.auth_length = 0;
1225
1226 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
1227 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1228 }
1229
1230 if (p->conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) {
1231 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1232 }
1233
1234 pkt.u.bind.max_xmit_frag = p->conn->srv_max_xmit_frag;
1235 pkt.u.bind.max_recv_frag = p->conn->srv_max_recv_frag;
1236 pkt.u.bind.assoc_group_id = dcerpc_binding_get_assoc_group_id(p->binding);
1237 pkt.u.bind.num_contexts = 1;
1238 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
1239 if (tevent_req_nomem(pkt.u.bind.ctx_list, req)) {
1240 return tevent_req_post(req, ev);
1241 }
1242 pkt.u.bind.ctx_list[0].context_id = p->context_id;
1243 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
1244 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
1245 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1246 pkt.u.bind.auth_info = data_blob(NULL, 0);
1247
1248 /* construct the NDR form of the packet */
1249 status = ncacn_push_auth(&blob, state, &pkt,
1250 p->conn->security_state.tmp_auth_info.out);
1251 if (tevent_req_nterror(req, status)) {
1252 return tevent_req_post(req, ev);
1253 }
1254
1255 /*
1256 * we allocate a dcerpc_request so we can be in the same
1257 * request queue as normal requests
1258 */
1259 subreq = talloc_zero(state, struct rpc_request);
1260 if (tevent_req_nomem(subreq, req)) {
1261 return tevent_req_post(req, ev);
1262 }
1263
1264 subreq->state = RPC_REQUEST_PENDING;
1265 subreq->call_id = pkt.call_id;
1266 subreq->async.private_data = req;
1267 subreq->async.callback = dcerpc_bind_fail_handler;
1268 subreq->p = p;
1269 subreq->recv_handler = dcerpc_bind_recv_handler;
1270 DLIST_ADD_END(p->conn->pending, subreq);
1271 talloc_set_destructor(subreq, dcerpc_req_dequeue);
1272
1273 status = dcerpc_send_request(p->conn, &blob, true);
1274 if (tevent_req_nterror(req, status)) {
1275 return tevent_req_post(req, ev);
1276 }
1277
1278 tevent_add_timer(ev, subreq,
1279 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1280 dcerpc_timeout_handler, subreq);
1281
1282 return req;
1283}
1284
1285static void dcerpc_bind_fail_handler(struct rpc_request *subreq)
1286{
1287 struct tevent_req *req =
1288 talloc_get_type_abort(subreq->async.private_data,
1289 struct tevent_req);
1290 struct dcerpc_bind_state *state =
1291 tevent_req_data(req,
1292 struct dcerpc_bind_state);
1293 NTSTATUS status = subreq->status;
1294
1295 TALLOC_FREE(subreq);
1296
1297 /*
1298 * We trigger the callback in the next event run
1299 * because the code in this file might trigger
1300 * multiple request callbacks from within a single
1301 * while loop.
1302 *
1303 * In order to avoid segfaults from within
1304 * dcerpc_connection_dead() we call
1305 * tevent_req_defer_callback().
1306 */
1307 tevent_req_defer_callback(req, state->ev);
1308
1309 tevent_req_nterror(req, status);
1310}
1311
1312static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1313 DATA_BLOB *raw_packet,
1314 struct ncacn_packet *pkt)
1315{
1316 struct tevent_req *req =
1317 talloc_get_type_abort(subreq->async.private_data,
1318 struct tevent_req);
1319 struct dcerpc_bind_state *state =
1320 tevent_req_data(req,
1321 struct dcerpc_bind_state);
1322 struct dcecli_connection *conn = state->p->conn;
1323 struct dcecli_security *sec = &conn->security_state;
1324 struct dcerpc_binding *b = NULL;
1325 NTSTATUS status;
1326 uint32_t flags;
1327
1328 /*
1329 * Note that pkt is allocated under raw_packet->data,
1330 * while raw_packet->data is a child of subreq.
1331 */
1332 talloc_steal(state, raw_packet->data);
1333 TALLOC_FREE(subreq);
1334
1335 /*
1336 * We trigger the callback in the next event run
1337 * because the code in this file might trigger
1338 * multiple request callbacks from within a single
1339 * while loop.
1340 *
1341 * In order to avoid segfaults from within
1342 * dcerpc_connection_dead() we call
1343 * tevent_req_defer_callback().
1344 */
1345 tevent_req_defer_callback(req, state->ev);
1346
1347 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
1348 status = dcerpc_map_nak_reason(pkt->u.bind_nak.reject_reason);
1349
1350 DEBUG(2,("dcerpc: bind_nak reason %d - %s\n",
1351 pkt->u.bind_nak.reject_reason, nt_errstr(status)));
1352
1353 tevent_req_nterror(req, status);
1354 return;
1355 }
1356
1357 status = dcerpc_verify_ncacn_packet_header(pkt,
1358 DCERPC_PKT_BIND_ACK,
1359 pkt->u.bind_ack.auth_info.length,
1360 DCERPC_PFC_FLAG_FIRST |
1361 DCERPC_PFC_FLAG_LAST,
1362 DCERPC_PFC_FLAG_CONC_MPX |
1363 DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN);
1364 if (!NT_STATUS_IS_OK(status)) {
1365 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1366 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1367 return;
1368 }
1369
1370 if (pkt->u.bind_ack.num_results != 1) {
1371 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1372 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1373 return;
1374 }
1375
1376 if (pkt->u.bind_ack.ctx_list[0].result != 0) {
1377 status = dcerpc_map_ack_reason(&pkt->u.bind_ack.ctx_list[0]);
1378 DEBUG(2,("dcerpc: bind_ack failed - reason %d - %s\n",
1379 pkt->u.bind_ack.ctx_list[0].reason.value,
1380 nt_errstr(status)));
1381 tevent_req_nterror(req, status);
1382 return;
1383 }
1384
1385 /*
1386 * DCE-RPC 1.1 (c706) specifies
1387 * CONST_MUST_RCV_FRAG_SIZE as 1432
1388 */
1389 if (pkt->u.bind_ack.max_xmit_frag < 1432) {
1390 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1391 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1392 return;
1393 }
1394 if (pkt->u.bind_ack.max_recv_frag < 1432) {
1395 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1396 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1397 return;
1398 }
1399 conn->srv_max_xmit_frag = MIN(conn->srv_max_xmit_frag,
1400 pkt->u.bind_ack.max_xmit_frag);
1401 conn->srv_max_recv_frag = MIN(conn->srv_max_recv_frag,
1402 pkt->u.bind_ack.max_recv_frag);
1403
1404 flags = dcerpc_binding_get_flags(state->p->binding);
1405
1406 if ((flags & DCERPC_CONCURRENT_MULTIPLEX) &&
1407 (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
1408 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
1409 }
1410
1411 if ((conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) &&
1412 (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
1413 conn->flags |= DCERPC_HEADER_SIGNING;
1414 }
1415
1416 /* the bind_ack might contain a reply set of credentials */
1417 if (pkt->auth_length != 0 && sec->tmp_auth_info.in != NULL) {
1418 status = dcerpc_pull_auth_trailer(pkt, sec->tmp_auth_info.mem,
1419 &pkt->u.bind_ack.auth_info,
1420 sec->tmp_auth_info.in,
1421 NULL, true);
1422 if (tevent_req_nterror(req, status)) {
1423 return;
1424 }
1425 }
1426
1427 /*
1428 * We're the owner of the binding, so we're allowed to modify it.
1429 */
1430 b = discard_const_p(struct dcerpc_binding, state->p->binding);
1431 status = dcerpc_binding_set_assoc_group_id(b,
1432 pkt->u.bind_ack.assoc_group_id);
1433 if (tevent_req_nterror(req, status)) {
1434 return;
1435 }
1436
1437 tevent_req_done(req);
1438}
1439
1440NTSTATUS dcerpc_bind_recv(struct tevent_req *req)
1441{
1442 return tevent_req_simple_recv_ntstatus(req);
1443}
1444
1445/*
1446 perform a continued bind (and auth3)
1447*/
1448NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
1449 TALLOC_CTX *mem_ctx)
1450{
1451 struct ncacn_packet pkt;
1452 NTSTATUS status;
1453 DATA_BLOB blob;
1454 uint32_t flags;
1455
1456 flags = dcerpc_binding_get_flags(p->binding);
1457
1458 init_ncacn_hdr(p->conn, &pkt);
1459
1460 pkt.ptype = DCERPC_PKT_AUTH3;
1461 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1462 pkt.call_id = next_call_id(p->conn);
1463 pkt.auth_length = 0;
1464 pkt.u.auth3.auth_info = data_blob(NULL, 0);
1465
1466 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
1467 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1468 }
1469
1470 /* construct the NDR form of the packet */
1471 status = ncacn_push_auth(&blob, mem_ctx, &pkt,
1472 p->conn->security_state.tmp_auth_info.out);
1473 if (!NT_STATUS_IS_OK(status)) {
1474 return status;
1475 }
1476
1477 /* send it on its way */
1478 status = dcerpc_send_request(p->conn, &blob, false);
1479 if (!NT_STATUS_IS_OK(status)) {
1480 return status;
1481 }
1482
1483 return NT_STATUS_OK;
1484}
1485
1486
1487/*
1488 process a fragment received from the transport layer during a
1489 request
1490
1491 This function frees the data
1492*/
1493static void dcerpc_request_recv_data(struct dcecli_connection *c,
1494 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1495{
1496 struct rpc_request *req;
1497 unsigned int length;
1498 NTSTATUS status = NT_STATUS_OK;
1499
1500 /*
1501 if this is an authenticated connection then parse and check
1502 the auth info. We have to do this before finding the
1503 matching packet, as the request structure might have been
1504 removed due to a timeout, but if it has been we still need
1505 to run the auth routines so that we don't get the sign/seal
1506 info out of step with the server
1507 */
1508 if (pkt->ptype == DCERPC_PKT_RESPONSE) {
1509 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
1510 }
1511
1512 /* find the matching request */
1513 for (req=c->pending;req;req=req->next) {
1514 if (pkt->call_id == req->call_id) break;
1515 }
1516
1517#if 0
1518 /* useful for testing certain vendors RPC servers */
1519 if (req == NULL && c->pending && pkt->call_id == 0) {
1520 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
1521 req = c->pending;
1522 }
1523#endif
1524
1525 if (req == NULL) {
1526 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
1527 data_blob_free(raw_packet);
1528 return;
1529 }
1530
1531 talloc_steal(req, raw_packet->data);
1532
1533 if (req->recv_handler != NULL) {
1534 dcerpc_req_dequeue(req);
1535 req->state = RPC_REQUEST_DONE;
1536
1537 /*
1538 * We have to look at shipping further requests before calling
1539 * the async function, that one might close the pipe
1540 */
1541 dcerpc_schedule_io_trigger(c);
1542
1543 req->recv_handler(req, raw_packet, pkt);
1544 return;
1545 }
1546
1547 if (pkt->ptype == DCERPC_PKT_FAULT) {
1548 status = dcerpc_fault_to_nt_status(pkt->u.fault.status);
1549 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
1550 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTOCOL_ERROR)) {
1551 dcerpc_connection_dead(c, status);
1552 return;
1553 }
1554 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1555 dcerpc_connection_dead(c, status);
1556 return;
1557 }
1558 req->fault_code = pkt->u.fault.status;
1559 req->status = NT_STATUS_NET_WRITE_FAULT;
1560 goto req_done;
1561 }
1562
1563 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
1564 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
1565 (int)pkt->ptype));
1566 dcerpc_connection_dead(c, NT_STATUS_RPC_PROTOCOL_ERROR);
1567 return;
1568 }
1569
1570 /* now check the status from the auth routines, and if it failed then fail
1571 this request accordingly */
1572 if (!NT_STATUS_IS_OK(status)) {
1573 dcerpc_connection_dead(c, status);
1574 return;
1575 }
1576
1577 length = pkt->u.response.stub_and_verifier.length;
1578
1579 if (req->payload.length + length > c->max_total_response_size) {
1580 DEBUG(2,("Unexpected total payload 0x%X > 0x%X dcerpc response\n",
1581 (unsigned)req->payload.length + length,
1582 (unsigned)c->max_total_response_size));
1583 dcerpc_connection_dead(c, NT_STATUS_RPC_PROTOCOL_ERROR);
1584 return;
1585 }
1586
1587 if (length > 0) {
1588 req->payload.data = talloc_realloc(req,
1589 req->payload.data,
1590 uint8_t,
1591 req->payload.length + length);
1592 if (!req->payload.data) {
1593 req->status = NT_STATUS_NO_MEMORY;
1594 goto req_done;
1595 }
1596 memcpy(req->payload.data+req->payload.length,
1597 pkt->u.response.stub_and_verifier.data, length);
1598 req->payload.length += length;
1599 }
1600
1601 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1602 data_blob_free(raw_packet);
1603 dcerpc_send_read(c);
1604 return;
1605 }
1606
1607 if (req->verify_bitmask1) {
1608 req->p->conn->security_state.verified_bitmask1 = true;
1609 }
1610 if (req->verify_pcontext) {
1611 req->p->verified_pcontext = true;
1612 }
1613
1614 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
1615 req->flags |= DCERPC_PULL_BIGENDIAN;
1616 } else {
1617 req->flags &= ~DCERPC_PULL_BIGENDIAN;
1618 }
1619
1620req_done:
1621 data_blob_free(raw_packet);
1622
1623 /* we've got the full payload */
1624 dcerpc_req_dequeue(req);
1625 req->state = RPC_REQUEST_DONE;
1626
1627 /*
1628 * We have to look at shipping further requests before calling
1629 * the async function, that one might close the pipe
1630 */
1631 dcerpc_schedule_io_trigger(c);
1632
1633 if (req->async.callback) {
1634 req->async.callback(req);
1635 }
1636}
1637
1638static NTSTATUS dcerpc_request_prepare_vt(struct rpc_request *req);
1639
1640/*
1641 perform the send side of a async dcerpc request
1642*/
1643static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
1644 struct dcerpc_pipe *p,
1645 const struct GUID *object,
1646 uint16_t opnum,
1647 DATA_BLOB *stub_data)
1648{
1649 struct rpc_request *req;
1650 NTSTATUS status;
1651
1652 req = talloc_zero(mem_ctx, struct rpc_request);
1653 if (req == NULL) {
1654 return NULL;
1655 }
1656
1657 req->p = p;
1658 req->call_id = next_call_id(p->conn);
1659 req->state = RPC_REQUEST_QUEUED;
1660
1661 if (object != NULL) {
1662 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
1663 if (req->object == NULL) {
1664 talloc_free(req);
1665 return NULL;
1666 }
1667 }
1668
1669 req->opnum = opnum;
1670 req->request_data.length = stub_data->length;
1671 req->request_data.data = stub_data->data;
1672
1673 status = dcerpc_request_prepare_vt(req);
1674 if (!NT_STATUS_IS_OK(status)) {
1675 talloc_free(req);
1676 return NULL;
1677 }
1678
1679 DLIST_ADD_END(p->conn->request_queue, req);
1680 talloc_set_destructor(req, dcerpc_req_dequeue);
1681
1682 dcerpc_schedule_io_trigger(p->conn);
1683
1684 if (p->request_timeout) {
1685 tevent_add_timer(p->conn->event_ctx, req,
1686 timeval_current_ofs(p->request_timeout, 0),
1687 dcerpc_timeout_handler, req);
1688 }
1689
1690 return req;
1691}
1692
1693static NTSTATUS dcerpc_request_prepare_vt(struct rpc_request *req)
1694{
1695 struct dcecli_security *sec = &req->p->conn->security_state;
1696 struct dcerpc_sec_verification_trailer *t;
1697 struct dcerpc_sec_vt *c = NULL;
1698 struct ndr_push *ndr = NULL;
1699 enum ndr_err_code ndr_err;
1700
1701 if (sec->auth_level < DCERPC_AUTH_LEVEL_INTEGRITY) {
1702 return NT_STATUS_OK;
1703 }
1704
1705 t = talloc_zero(req, struct dcerpc_sec_verification_trailer);
1706 if (t == NULL) {
1707 return NT_STATUS_NO_MEMORY;
1708 }
1709
1710 if (!sec->verified_bitmask1) {
1711 t->commands = talloc_realloc(t, t->commands,
1712 struct dcerpc_sec_vt,
1713 t->count.count + 1);
1714 if (t->commands == NULL) {
1715 return NT_STATUS_NO_MEMORY;
1716 }
1717 c = &t->commands[t->count.count++];
1718 ZERO_STRUCTP(c);
1719
1720 c->command = DCERPC_SEC_VT_COMMAND_BITMASK1;
1721 if (req->p->conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) {
1722 c->u.bitmask1 = DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING;
1723 }
1724 req->verify_bitmask1 = true;
1725 }
1726
1727 if (!req->p->verified_pcontext) {
1728 t->commands = talloc_realloc(t, t->commands,
1729 struct dcerpc_sec_vt,
1730 t->count.count + 1);
1731 if (t->commands == NULL) {
1732 return NT_STATUS_NO_MEMORY;
1733 }
1734 c = &t->commands[t->count.count++];
1735 ZERO_STRUCTP(c);
1736
1737 c->command = DCERPC_SEC_VT_COMMAND_PCONTEXT;
1738 c->u.pcontext.abstract_syntax = req->p->syntax;
1739 c->u.pcontext.transfer_syntax = req->p->transfer_syntax;
1740
1741 req->verify_pcontext = true;
1742 }
1743
1744 if (!(req->p->conn->flags & DCERPC_HEADER_SIGNING)) {
1745 t->commands = talloc_realloc(t, t->commands,
1746 struct dcerpc_sec_vt,
1747 t->count.count + 1);
1748 if (t->commands == NULL) {
1749 return NT_STATUS_NO_MEMORY;
1750 }
1751 c = &t->commands[t->count.count++];
1752 ZERO_STRUCTP(c);
1753
1754 c->command = DCERPC_SEC_VT_COMMAND_HEADER2;
1755 c->u.header2.ptype = DCERPC_PKT_REQUEST;
1756 if (req->p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1757 c->u.header2.drep[0] = 0;
1758 } else {
1759 c->u.header2.drep[0] = DCERPC_DREP_LE;
1760 }
1761 c->u.header2.drep[1] = 0;
1762 c->u.header2.drep[2] = 0;
1763 c->u.header2.drep[3] = 0;
1764 c->u.header2.call_id = req->call_id;
1765 c->u.header2.context_id = req->p->context_id;
1766 c->u.header2.opnum = req->opnum;
1767 }
1768
1769 if (t->count.count == 0) {
1770 TALLOC_FREE(t);
1771 return NT_STATUS_OK;
1772 }
1773
1774 c = &t->commands[t->count.count - 1];
1775 c->command |= DCERPC_SEC_VT_COMMAND_END;
1776
1777 if (DEBUGLEVEL >= 10) {
1778 NDR_PRINT_DEBUG(dcerpc_sec_verification_trailer, t);
1779 }
1780
1781 ndr = ndr_push_init_ctx(req);
1782 if (ndr == NULL) {
1783 return NT_STATUS_NO_MEMORY;
1784 }
1785
1786 /*
1787 * for now we just copy and append
1788 */
1789
1790 ndr_err = ndr_push_bytes(ndr, req->request_data.data,
1791 req->request_data.length);
1792 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1793 return ndr_map_error2ntstatus(ndr_err);
1794 }
1795
1796 ndr_err = ndr_push_dcerpc_sec_verification_trailer(ndr,
1797 NDR_SCALARS | NDR_BUFFERS,
1798 t);
1799 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1800 return ndr_map_error2ntstatus(ndr_err);
1801 }
1802 req->request_data = ndr_push_blob(ndr);
1803
1804 return NT_STATUS_OK;
1805}
1806
1807/*
1808 Send a request using the transport
1809*/
1810
1811static void dcerpc_ship_next_request(struct dcecli_connection *c)
1812{
1813 struct rpc_request *req;
1814 struct dcerpc_pipe *p;
1815 DATA_BLOB *stub_data;
1816 struct ncacn_packet pkt;
1817 DATA_BLOB blob;
1818 uint32_t remaining, chunk_size;
1819 bool first_packet = true;
1820 size_t sig_size = 0;
1821 bool need_async = false;
1822 bool can_async = true;
1823
1824 req = c->request_queue;
1825 if (req == NULL) {
1826 return;
1827 }
1828
1829 p = req->p;
1830 stub_data = &req->request_data;
1831
1832 if (c->pending) {
1833 need_async = true;
1834 }
1835
1836 if (c->security_state.auth_level >= DCERPC_AUTH_LEVEL_INTEGRITY) {
1837 can_async = gensec_have_feature(c->security_state.generic_state,
1838 GENSEC_FEATURE_ASYNC_REPLIES);
1839 }
1840
1841 if (need_async && !can_async) {
1842 req->wait_for_sync = true;
1843 return;
1844 }
1845
1846 DLIST_REMOVE(c->request_queue, req);
1847 DLIST_ADD(c->pending, req);
1848 req->state = RPC_REQUEST_PENDING;
1849
1850 init_ncacn_hdr(p->conn, &pkt);
1851
1852 remaining = stub_data->length;
1853
1854 /* we can write a full max_recv_frag size, minus the dcerpc
1855 request header size */
1856 chunk_size = p->conn->srv_max_recv_frag;
1857 chunk_size -= DCERPC_REQUEST_LENGTH;
1858 if (c->security_state.auth_level >= DCERPC_AUTH_LEVEL_INTEGRITY) {
1859 size_t max_payload = chunk_size;
1860
1861 max_payload -= DCERPC_AUTH_TRAILER_LENGTH;
1862 max_payload -= (max_payload % DCERPC_AUTH_PAD_ALIGNMENT);
1863
1864 sig_size = gensec_sig_size(c->security_state.generic_state,
1865 max_payload);
1866 if (sig_size) {
1867 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1868 chunk_size -= sig_size;
1869 }
1870 }
1871 chunk_size -= (chunk_size % DCERPC_AUTH_PAD_ALIGNMENT);
1872
1873 pkt.ptype = DCERPC_PKT_REQUEST;
1874 pkt.call_id = req->call_id;
1875 pkt.auth_length = 0;
1876 pkt.pfc_flags = 0;
1877 pkt.u.request.context_id = p->context_id;
1878 pkt.u.request.opnum = req->opnum;
1879
1880 if (req->object) {
1881 pkt.u.request.object.object = *req->object;
1882 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1883 chunk_size -= ndr_size_GUID(req->object,0);
1884 }
1885
1886 /* we send a series of pdus without waiting for a reply */
1887 while (remaining > 0 || first_packet) {
1888 uint32_t chunk = MIN(chunk_size, remaining);
1889 bool last_frag = false;
1890 bool do_trans = false;
1891
1892 first_packet = false;
1893 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1894
1895 if (remaining == stub_data->length) {
1896 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1897 }
1898 if (chunk == remaining) {
1899 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1900 last_frag = true;
1901 }
1902
1903 pkt.u.request.alloc_hint = remaining;
1904 pkt.u.request.stub_and_verifier.data = stub_data->data +
1905 (stub_data->length - remaining);
1906 pkt.u.request.stub_and_verifier.length = chunk;
1907
1908 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1909 if (!NT_STATUS_IS_OK(req->status)) {
1910 req->state = RPC_REQUEST_DONE;
1911 DLIST_REMOVE(p->conn->pending, req);
1912 return;
1913 }
1914
1915 if (last_frag && !need_async) {
1916 do_trans = true;
1917 }
1918
1919 req->status = dcerpc_send_request(p->conn, &blob, do_trans);
1920 if (!NT_STATUS_IS_OK(req->status)) {
1921 req->state = RPC_REQUEST_DONE;
1922 DLIST_REMOVE(p->conn->pending, req);
1923 return;
1924 }
1925
1926 if (last_frag && !do_trans) {
1927 req->status = dcerpc_send_read(p->conn);
1928 if (!NT_STATUS_IS_OK(req->status)) {
1929 req->state = RPC_REQUEST_DONE;
1930 DLIST_REMOVE(p->conn->pending, req);
1931 return;
1932 }
1933 }
1934
1935 remaining -= chunk;
1936 }
1937}
1938
1939static void dcerpc_io_trigger(struct tevent_context *ctx,
1940 struct tevent_immediate *im,
1941 void *private_data)
1942{
1943 struct dcecli_connection *c =
1944 talloc_get_type_abort(private_data,
1945 struct dcecli_connection);
1946
1947 c->io_trigger_pending = false;
1948
1949 dcerpc_schedule_io_trigger(c);
1950
1951 dcerpc_ship_next_request(c);
1952}
1953
1954static void dcerpc_schedule_io_trigger(struct dcecli_connection *c)
1955{
1956 if (c->dead) {
1957 return;
1958 }
1959
1960 if (c->request_queue == NULL) {
1961 return;
1962 }
1963
1964 if (c->request_queue->wait_for_sync && c->pending) {
1965 return;
1966 }
1967
1968 if (c->io_trigger_pending) {
1969 return;
1970 }
1971
1972 c->io_trigger_pending = true;
1973
1974 tevent_schedule_immediate(c->io_trigger,
1975 c->event_ctx,
1976 dcerpc_io_trigger,
1977 c);
1978}
1979
1980/*
1981 perform the receive side of a async dcerpc request
1982*/
1983static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1984 TALLOC_CTX *mem_ctx,
1985 DATA_BLOB *stub_data)
1986{
1987 NTSTATUS status;
1988
1989 while (req->state != RPC_REQUEST_DONE) {
1990 struct tevent_context *ctx = req->p->conn->event_ctx;
1991 if (tevent_loop_once(ctx) != 0) {
1992 return NT_STATUS_CONNECTION_DISCONNECTED;
1993 }
1994 }
1995 *stub_data = req->payload;
1996 status = req->status;
1997 if (stub_data->data) {
1998 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1999 }
2000 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
2001 req->p->last_fault_code = req->fault_code;
2002 }
2003 talloc_unlink(talloc_parent(req), req);
2004 return status;
2005}
2006
2007/*
2008 this is a paranoid NDR validator. For every packet we push onto the wire
2009 we pull it back again, then push it again. Then we compare the raw NDR data
2010 for that to the NDR we initially generated. If they don't match then we know
2011 we must have a bug in either the pull or push side of our code
2012*/
2013static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
2014 TALLOC_CTX *mem_ctx,
2015 DATA_BLOB blob,
2016 size_t struct_size,
2017 ndr_push_flags_fn_t ndr_push,
2018 ndr_pull_flags_fn_t ndr_pull)
2019{
2020 void *st;
2021 struct ndr_pull *pull;
2022 struct ndr_push *push;
2023 DATA_BLOB blob2;
2024 enum ndr_err_code ndr_err;
2025
2026 st = talloc_size(mem_ctx, struct_size);
2027 if (!st) {
2028 return NT_STATUS_NO_MEMORY;
2029 }
2030
2031 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
2032 if (!pull) {
2033 return NT_STATUS_NO_MEMORY;
2034 }
2035 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
2036
2037 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
2038 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
2039 }
2040
2041 if (c->flags & DCERPC_NDR64) {
2042 pull->flags |= LIBNDR_FLAG_NDR64;
2043 }
2044
2045 ndr_err = ndr_pull(pull, NDR_IN, st);
2046 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2047 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2048 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
2049 "failed input validation pull - %s",
2050 nt_errstr(status));
2051 return ndr_map_error2ntstatus(ndr_err);
2052 }
2053
2054 push = ndr_push_init_ctx(mem_ctx);
2055 if (!push) {
2056 return NT_STATUS_NO_MEMORY;
2057 }
2058
2059 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
2060 push->flags |= LIBNDR_FLAG_BIGENDIAN;
2061 }
2062
2063 if (c->flags & DCERPC_NDR64) {
2064 push->flags |= LIBNDR_FLAG_NDR64;
2065 }
2066
2067 ndr_err = ndr_push(push, NDR_IN, st);
2068 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2069 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2070 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
2071 "failed input validation push - %s",
2072 nt_errstr(status));
2073 return ndr_map_error2ntstatus(ndr_err);
2074 }
2075
2076 blob2 = ndr_push_blob(push);
2077
2078 if (data_blob_cmp(&blob, &blob2) != 0) {
2079 DEBUG(3,("original:\n"));
2080 dump_data(3, blob.data, blob.length);
2081 DEBUG(3,("secondary:\n"));
2082 dump_data(3, blob2.data, blob2.length);
2083 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
2084 "failed input validation blobs doesn't match");
2085 return ndr_map_error2ntstatus(ndr_err);
2086 }
2087
2088 return NT_STATUS_OK;
2089}
2090
2091/*
2092 this is a paranoid NDR input validator. For every packet we pull
2093 from the wire we push it back again then pull and push it
2094 again. Then we compare the raw NDR data for that to the NDR we
2095 initially generated. If they don't match then we know we must have a
2096 bug in either the pull or push side of our code
2097*/
2098static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
2099 struct ndr_pull *pull_in,
2100 void *struct_ptr,
2101 size_t struct_size,
2102 ndr_push_flags_fn_t ndr_push,
2103 ndr_pull_flags_fn_t ndr_pull,
2104 ndr_print_function_t ndr_print)
2105{
2106 void *st;
2107 struct ndr_pull *pull;
2108 struct ndr_push *push;
2109 DATA_BLOB blob, blob2;
2110 TALLOC_CTX *mem_ctx = pull_in;
2111 char *s1, *s2;
2112 enum ndr_err_code ndr_err;
2113
2114 st = talloc_size(mem_ctx, struct_size);
2115 if (!st) {
2116 return NT_STATUS_NO_MEMORY;
2117 }
2118 memcpy(st, struct_ptr, struct_size);
2119
2120 push = ndr_push_init_ctx(mem_ctx);
2121 if (!push) {
2122 return NT_STATUS_NO_MEMORY;
2123 }
2124
2125 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
2126 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2127 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2128 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2129 "failed output validation push - %s",
2130 nt_errstr(status));
2131 return ndr_map_error2ntstatus(ndr_err);
2132 }
2133
2134 blob = ndr_push_blob(push);
2135
2136 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
2137 if (!pull) {
2138 return NT_STATUS_NO_MEMORY;
2139 }
2140
2141 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
2142 ndr_err = ndr_pull(pull, NDR_OUT, st);
2143 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2144 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2145 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
2146 "failed output validation pull - %s",
2147 nt_errstr(status));
2148 return ndr_map_error2ntstatus(ndr_err);
2149 }
2150
2151 push = ndr_push_init_ctx(mem_ctx);
2152 if (!push) {
2153 return NT_STATUS_NO_MEMORY;
2154 }
2155
2156 ndr_err = ndr_push(push, NDR_OUT, st);
2157 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2158 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2159 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2160 "failed output validation push2 - %s",
2161 nt_errstr(status));
2162 return ndr_map_error2ntstatus(ndr_err);
2163 }
2164
2165 blob2 = ndr_push_blob(push);
2166
2167 if (data_blob_cmp(&blob, &blob2) != 0) {
2168 DEBUG(3,("original:\n"));
2169 dump_data(3, blob.data, blob.length);
2170 DEBUG(3,("secondary:\n"));
2171 dump_data(3, blob2.data, blob2.length);
2172 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2173 "failed output validation blobs doesn't match");
2174 return ndr_map_error2ntstatus(ndr_err);
2175 }
2176
2177 /* this checks the printed forms of the two structures, which effectively
2178 tests all of the value() attributes */
2179 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
2180 NDR_OUT, struct_ptr);
2181 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
2182 NDR_OUT, st);
2183 if (strcmp(s1, s2) != 0) {
2184#if 1
2185 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
2186#else
2187 /* this is sometimes useful */
2188 printf("VALIDATE ERROR\n");
2189 file_save("wire.dat", s1, strlen(s1));
2190 file_save("gen.dat", s2, strlen(s2));
2191 system("diff -u wire.dat gen.dat");
2192#endif
2193 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2194 "failed output validation strings doesn't match");
2195 return ndr_map_error2ntstatus(ndr_err);
2196 }
2197
2198 return NT_STATUS_OK;
2199}
2200
2201/*
2202 a useful function for retrieving the server name we connected to
2203*/
2204_PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
2205{
2206 return p->conn ? p->conn->server_name : NULL;
2207}
2208
2209
2210/*
2211 get the dcerpc auth_level for a open connection
2212*/
2213uint32_t dcerpc_auth_level(struct dcecli_connection *c)
2214{
2215 uint8_t auth_level;
2216
2217 if (c->flags & DCERPC_SEAL) {
2218 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
2219 } else if (c->flags & DCERPC_SIGN) {
2220 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
2221 } else if (c->flags & DCERPC_CONNECT) {
2222 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
2223 } else {
2224 auth_level = DCERPC_AUTH_LEVEL_NONE;
2225 }
2226 return auth_level;
2227}
2228
2229struct dcerpc_alter_context_state {
2230 struct tevent_context *ev;
2231 struct dcerpc_pipe *p;
2232};
2233
2234static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq);
2235static void dcerpc_alter_context_recv_handler(struct rpc_request *req,
2236 DATA_BLOB *raw_packet,
2237 struct ncacn_packet *pkt);
2238
2239struct tevent_req *dcerpc_alter_context_send(TALLOC_CTX *mem_ctx,
2240 struct tevent_context *ev,
2241 struct dcerpc_pipe *p,
2242 const struct ndr_syntax_id *syntax,
2243 const struct ndr_syntax_id *transfer_syntax)
2244{
2245 struct tevent_req *req;
2246 struct dcerpc_alter_context_state *state;
2247 struct ncacn_packet pkt;
2248 DATA_BLOB blob;
2249 NTSTATUS status;
2250 struct rpc_request *subreq;
2251 uint32_t flags;
2252
2253 req = tevent_req_create(mem_ctx, &state,
2254 struct dcerpc_alter_context_state);
2255 if (req == NULL) {
2256 return NULL;
2257 }
2258
2259 state->ev = ev;
2260 state->p = p;
2261
2262 p->syntax = *syntax;
2263 p->transfer_syntax = *transfer_syntax;
2264
2265 flags = dcerpc_binding_get_flags(p->binding);
2266
2267 init_ncacn_hdr(p->conn, &pkt);
2268
2269 pkt.ptype = DCERPC_PKT_ALTER;
2270 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
2271 pkt.call_id = p->conn->call_id;
2272 pkt.auth_length = 0;
2273
2274 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
2275 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
2276 }
2277
2278 pkt.u.alter.max_xmit_frag = p->conn->srv_max_xmit_frag;
2279 pkt.u.alter.max_recv_frag = p->conn->srv_max_recv_frag;
2280 pkt.u.alter.assoc_group_id = dcerpc_binding_get_assoc_group_id(p->binding);
2281 pkt.u.alter.num_contexts = 1;
2282 pkt.u.alter.ctx_list = talloc_array(state, struct dcerpc_ctx_list, 1);
2283 if (tevent_req_nomem(pkt.u.alter.ctx_list, req)) {
2284 return tevent_req_post(req, ev);
2285 }
2286 pkt.u.alter.ctx_list[0].context_id = p->context_id;
2287 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
2288 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
2289 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
2290 pkt.u.alter.auth_info = data_blob(NULL, 0);
2291
2292 /* construct the NDR form of the packet */
2293 status = ncacn_push_auth(&blob, state, &pkt,
2294 p->conn->security_state.tmp_auth_info.out);
2295 if (tevent_req_nterror(req, status)) {
2296 return tevent_req_post(req, ev);
2297 }
2298
2299 /*
2300 * we allocate a dcerpc_request so we can be in the same
2301 * request queue as normal requests
2302 */
2303 subreq = talloc_zero(state, struct rpc_request);
2304 if (tevent_req_nomem(subreq, req)) {
2305 return tevent_req_post(req, ev);
2306 }
2307
2308 subreq->state = RPC_REQUEST_PENDING;
2309 subreq->call_id = pkt.call_id;
2310 subreq->async.private_data = req;
2311 subreq->async.callback = dcerpc_alter_context_fail_handler;
2312 subreq->p = p;
2313 subreq->recv_handler = dcerpc_alter_context_recv_handler;
2314 DLIST_ADD_END(p->conn->pending, subreq);
2315 talloc_set_destructor(subreq, dcerpc_req_dequeue);
2316
2317 status = dcerpc_send_request(p->conn, &blob, true);
2318 if (tevent_req_nterror(req, status)) {
2319 return tevent_req_post(req, ev);
2320 }
2321
2322 tevent_add_timer(ev, subreq,
2323 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
2324 dcerpc_timeout_handler, subreq);
2325
2326 return req;
2327}
2328
2329static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq)
2330{
2331 struct tevent_req *req =
2332 talloc_get_type_abort(subreq->async.private_data,
2333 struct tevent_req);
2334 struct dcerpc_alter_context_state *state =
2335 tevent_req_data(req,
2336 struct dcerpc_alter_context_state);
2337 NTSTATUS status = subreq->status;
2338
2339 TALLOC_FREE(subreq);
2340
2341 /*
2342 * We trigger the callback in the next event run
2343 * because the code in this file might trigger
2344 * multiple request callbacks from within a single
2345 * while loop.
2346 *
2347 * In order to avoid segfaults from within
2348 * dcerpc_connection_dead() we call
2349 * tevent_req_defer_callback().
2350 */
2351 tevent_req_defer_callback(req, state->ev);
2352
2353 tevent_req_nterror(req, status);
2354}
2355
2356static void dcerpc_alter_context_recv_handler(struct rpc_request *subreq,
2357 DATA_BLOB *raw_packet,
2358 struct ncacn_packet *pkt)
2359{
2360 struct tevent_req *req =
2361 talloc_get_type_abort(subreq->async.private_data,
2362 struct tevent_req);
2363 struct dcerpc_alter_context_state *state =
2364 tevent_req_data(req,
2365 struct dcerpc_alter_context_state);
2366 struct dcecli_connection *conn = state->p->conn;
2367 struct dcecli_security *sec = &conn->security_state;
2368 NTSTATUS status;
2369
2370 /*
2371 * Note that pkt is allocated under raw_packet->data,
2372 * while raw_packet->data is a child of subreq.
2373 */
2374 talloc_steal(state, raw_packet->data);
2375 TALLOC_FREE(subreq);
2376
2377 /*
2378 * We trigger the callback in the next event run
2379 * because the code in this file might trigger
2380 * multiple request callbacks from within a single
2381 * while loop.
2382 *
2383 * In order to avoid segfaults from within
2384 * dcerpc_connection_dead() we call
2385 * tevent_req_defer_callback().
2386 */
2387 tevent_req_defer_callback(req, state->ev);
2388
2389 if (pkt->ptype == DCERPC_PKT_FAULT) {
2390 DEBUG(5,("dcerpc: alter_resp - rpc fault: %s\n",
2391 dcerpc_errstr(state, pkt->u.fault.status)));
2392 if (pkt->u.fault.status == DCERPC_FAULT_ACCESS_DENIED) {
2393 state->p->last_fault_code = pkt->u.fault.status;
2394 tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
2395 } else if (pkt->u.fault.status == DCERPC_FAULT_SEC_PKG_ERROR) {
2396 state->p->last_fault_code = pkt->u.fault.status;
2397 tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
2398 } else {
2399 state->p->last_fault_code = pkt->u.fault.status;
2400 status = dcerpc_fault_to_nt_status(pkt->u.fault.status);
2401 tevent_req_nterror(req, status);
2402 }
2403 return;
2404 }
2405
2406 status = dcerpc_verify_ncacn_packet_header(pkt,
2407 DCERPC_PKT_ALTER_RESP,
2408 pkt->u.alter_resp.auth_info.length,
2409 DCERPC_PFC_FLAG_FIRST |
2410 DCERPC_PFC_FLAG_LAST,
2411 DCERPC_PFC_FLAG_CONC_MPX |
2412 DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN);
2413 if (!NT_STATUS_IS_OK(status)) {
2414 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
2415 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2416 return;
2417 }
2418
2419 if (pkt->u.alter_resp.num_results != 1) {
2420 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
2421 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2422 return;
2423 }
2424
2425 if (pkt->u.alter_resp.ctx_list[0].result != 0) {
2426 status = dcerpc_map_ack_reason(&pkt->u.alter_resp.ctx_list[0]);
2427 DEBUG(2,("dcerpc: alter_resp failed - reason %d - %s\n",
2428 pkt->u.alter_resp.ctx_list[0].reason.value,
2429 nt_errstr(status)));
2430 tevent_req_nterror(req, status);
2431 return;
2432 }
2433
2434 /* the alter_resp might contain a reply set of credentials */
2435 if (pkt->auth_length != 0 && sec->tmp_auth_info.in != NULL) {
2436 status = dcerpc_pull_auth_trailer(pkt, sec->tmp_auth_info.mem,
2437 &pkt->u.alter_resp.auth_info,
2438 sec->tmp_auth_info.in,
2439 NULL, true);
2440 if (tevent_req_nterror(req, status)) {
2441 return;
2442 }
2443 }
2444
2445 tevent_req_done(req);
2446}
2447
2448NTSTATUS dcerpc_alter_context_recv(struct tevent_req *req)
2449{
2450 return tevent_req_simple_recv_ntstatus(req);
2451}
2452
2453/*
2454 send a dcerpc alter_context request
2455*/
2456_PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
2457 TALLOC_CTX *mem_ctx,
2458 const struct ndr_syntax_id *syntax,
2459 const struct ndr_syntax_id *transfer_syntax)
2460{
2461 struct tevent_req *subreq;
2462 struct tevent_context *ev = p->conn->event_ctx;
2463 bool ok;
2464
2465 /* TODO: create a new event context here */
2466
2467 subreq = dcerpc_alter_context_send(mem_ctx, ev,
2468 p, syntax, transfer_syntax);
2469 if (subreq == NULL) {
2470 return NT_STATUS_NO_MEMORY;
2471 }
2472
2473 ok = tevent_req_poll(subreq, ev);
2474 if (!ok) {
2475 NTSTATUS status;
2476 status = map_nt_error_from_unix_common(errno);
2477 return status;
2478 }
2479
2480 return dcerpc_alter_context_recv(subreq);
2481}
2482
2483static void dcerpc_transport_dead(struct dcecli_connection *c, NTSTATUS status)
2484{
2485 if (c->transport.stream == NULL) {
2486 return;
2487 }
2488
2489 tevent_queue_stop(c->transport.write_queue);
2490 TALLOC_FREE(c->transport.read_subreq);
2491 TALLOC_FREE(c->transport.stream);
2492
2493 if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) {
2494 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
2495 }
2496
2497 if (NT_STATUS_EQUAL(NT_STATUS_OK, status)) {
2498 status = NT_STATUS_END_OF_FILE;
2499 }
2500
2501 dcerpc_recv_data(c, NULL, status);
2502}
2503
2504
2505/*
2506 shutdown SMB pipe connection
2507*/
2508struct dcerpc_shutdown_pipe_state {
2509 struct dcecli_connection *c;
2510 NTSTATUS status;
2511};
2512
2513static void dcerpc_shutdown_pipe_done(struct tevent_req *subreq);
2514
2515static NTSTATUS dcerpc_shutdown_pipe(struct dcecli_connection *c, NTSTATUS status)
2516{
2517 struct dcerpc_shutdown_pipe_state *state;
2518 struct tevent_req *subreq;
2519
2520 if (c->transport.stream == NULL) {
2521 return NT_STATUS_OK;
2522 }
2523
2524 state = talloc_zero(c, struct dcerpc_shutdown_pipe_state);
2525 if (state == NULL) {
2526 return NT_STATUS_NO_MEMORY;
2527 }
2528 state->c = c;
2529 state->status = status;
2530
2531 subreq = tstream_disconnect_send(state, c->event_ctx, c->transport.stream);
2532 if (subreq == NULL) {
2533 return NT_STATUS_NO_MEMORY;
2534 }
2535 tevent_req_set_callback(subreq, dcerpc_shutdown_pipe_done, state);
2536
2537 return status;
2538}
2539
2540static void dcerpc_shutdown_pipe_done(struct tevent_req *subreq)
2541{
2542 struct dcerpc_shutdown_pipe_state *state =
2543 tevent_req_callback_data(subreq, struct dcerpc_shutdown_pipe_state);
2544 struct dcecli_connection *c = state->c;
2545 NTSTATUS status = state->status;
2546 int error;
2547
2548 /*
2549 * here we ignore the return values...
2550 */
2551 tstream_disconnect_recv(subreq, &error);
2552 TALLOC_FREE(subreq);
2553
2554 TALLOC_FREE(state);
2555
2556 dcerpc_transport_dead(c, status);
2557}
2558
2559
2560
2561struct dcerpc_send_read_state {
2562 struct dcecli_connection *p;
2563};
2564
2565static int dcerpc_send_read_state_destructor(struct dcerpc_send_read_state *state)
2566{
2567 struct dcecli_connection *p = state->p;
2568
2569 p->transport.read_subreq = NULL;
2570
2571 return 0;
2572}
2573
2574static void dcerpc_send_read_done(struct tevent_req *subreq);
2575
2576static NTSTATUS dcerpc_send_read(struct dcecli_connection *p)
2577{
2578 struct dcerpc_send_read_state *state;
2579
2580 if (p->transport.read_subreq != NULL) {
2581 p->transport.pending_reads++;
2582 return NT_STATUS_OK;
2583 }
2584
2585 state = talloc_zero(p, struct dcerpc_send_read_state);
2586 if (state == NULL) {
2587 return NT_STATUS_NO_MEMORY;
2588 }
2589 state->p = p;
2590
2591 talloc_set_destructor(state, dcerpc_send_read_state_destructor);
2592
2593 p->transport.read_subreq = dcerpc_read_ncacn_packet_send(state,
2594 p->event_ctx,
2595 p->transport.stream);
2596 if (p->transport.read_subreq == NULL) {
2597 return NT_STATUS_NO_MEMORY;
2598 }
2599 tevent_req_set_callback(p->transport.read_subreq, dcerpc_send_read_done, state);
2600
2601 return NT_STATUS_OK;
2602}
2603
2604static void dcerpc_send_read_done(struct tevent_req *subreq)
2605{
2606 struct dcerpc_send_read_state *state =
2607 tevent_req_callback_data(subreq,
2608 struct dcerpc_send_read_state);
2609 struct dcecli_connection *p = state->p;
2610 NTSTATUS status;
2611 struct ncacn_packet *pkt;
2612 DATA_BLOB blob;
2613
2614 status = dcerpc_read_ncacn_packet_recv(subreq, state,
2615 &pkt, &blob);
2616 TALLOC_FREE(subreq);
2617 if (!NT_STATUS_IS_OK(status)) {
2618 TALLOC_FREE(state);
2619 dcerpc_transport_dead(p, status);
2620 return;
2621 }
2622
2623 /*
2624 * here we steal into thet connection context,
2625 * but p->transport.recv_data() will steal or free it again
2626 */
2627 talloc_steal(p, blob.data);
2628 TALLOC_FREE(state);
2629
2630 if (p->transport.pending_reads > 0) {
2631 p->transport.pending_reads--;
2632
2633 status = dcerpc_send_read(p);
2634 if (!NT_STATUS_IS_OK(status)) {
2635 dcerpc_transport_dead(p, status);
2636 return;
2637 }
2638 }
2639
2640 dcerpc_recv_data(p, &blob, NT_STATUS_OK);
2641}
2642
2643struct dcerpc_send_request_state {
2644 struct dcecli_connection *p;
2645 DATA_BLOB blob;
2646 struct iovec iov;
2647};
2648
2649static int dcerpc_send_request_state_destructor(struct dcerpc_send_request_state *state)
2650{
2651 struct dcecli_connection *p = state->p;
2652
2653 p->transport.read_subreq = NULL;
2654
2655 return 0;
2656}
2657
2658static void dcerpc_send_request_wait_done(struct tevent_req *subreq);
2659static void dcerpc_send_request_done(struct tevent_req *subreq);
2660
2661static NTSTATUS dcerpc_send_request(struct dcecli_connection *p, DATA_BLOB *data,
2662 bool trigger_read)
2663{
2664 struct dcerpc_send_request_state *state;
2665 struct tevent_req *subreq;
2666 bool use_trans = trigger_read;
2667
2668 if (p->transport.stream == NULL) {
2669 return NT_STATUS_CONNECTION_DISCONNECTED;
2670 }
2671
2672 state = talloc_zero(p, struct dcerpc_send_request_state);
2673 if (state == NULL) {
2674 return NT_STATUS_NO_MEMORY;
2675 }
2676 state->p = p;
2677
2678 state->blob = data_blob_talloc(state, data->data, data->length);
2679 if (state->blob.data == NULL) {
2680 TALLOC_FREE(state);
2681 return NT_STATUS_NO_MEMORY;
2682 }
2683 state->iov.iov_base = (void *)state->blob.data;
2684 state->iov.iov_len = state->blob.length;
2685
2686 if (p->transport.read_subreq != NULL) {
2687 use_trans = false;
2688 }
2689
2690 if (!tstream_is_smbXcli_np(p->transport.stream)) {
2691 use_trans = false;
2692 }
2693
2694 if (use_trans) {
2695 /*
2696 * we need to block reads until our write is
2697 * the next in the write queue.
2698 */
2699 p->transport.read_subreq = tevent_queue_wait_send(state, p->event_ctx,
2700 p->transport.write_queue);
2701 if (p->transport.read_subreq == NULL) {
2702 TALLOC_FREE(state);
2703 return NT_STATUS_NO_MEMORY;
2704 }
2705 tevent_req_set_callback(p->transport.read_subreq,
2706 dcerpc_send_request_wait_done,
2707 state);
2708
2709 talloc_set_destructor(state, dcerpc_send_request_state_destructor);
2710
2711 trigger_read = false;
2712 }
2713
2714 subreq = tstream_writev_queue_send(state, p->event_ctx,
2715 p->transport.stream,
2716 p->transport.write_queue,
2717 &state->iov, 1);
2718 if (subreq == NULL) {
2719 TALLOC_FREE(state);
2720 return NT_STATUS_NO_MEMORY;
2721 }
2722 tevent_req_set_callback(subreq, dcerpc_send_request_done, state);
2723
2724 if (trigger_read) {
2725 dcerpc_send_read(p);
2726 }
2727
2728 return NT_STATUS_OK;
2729}
2730
2731static void dcerpc_send_request_wait_done(struct tevent_req *subreq)
2732{
2733 struct dcerpc_send_request_state *state =
2734 tevent_req_callback_data(subreq,
2735 struct dcerpc_send_request_state);
2736 struct dcecli_connection *p = state->p;
2737 NTSTATUS status;
2738 bool ok;
2739
2740 p->transport.read_subreq = NULL;
2741 talloc_set_destructor(state, NULL);
2742
2743 ok = tevent_queue_wait_recv(subreq);
2744 if (!ok) {
2745 TALLOC_FREE(state);
2746 dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
2747 return;
2748 }
2749
2750 if (tevent_queue_length(p->transport.write_queue) <= 2) {
2751 status = tstream_smbXcli_np_use_trans(p->transport.stream);
2752 if (!NT_STATUS_IS_OK(status)) {
2753 TALLOC_FREE(state);
2754 dcerpc_transport_dead(p, status);
2755 return;
2756 }
2757 }
2758
2759 /* we free subreq after tstream_cli_np_use_trans */
2760 TALLOC_FREE(subreq);
2761
2762 dcerpc_send_read(p);
2763}
2764
2765static void dcerpc_send_request_done(struct tevent_req *subreq)
2766{
2767 struct dcerpc_send_request_state *state =
2768 tevent_req_callback_data(subreq,
2769 struct dcerpc_send_request_state);
2770 int ret;
2771 int error;
2772
2773 ret = tstream_writev_queue_recv(subreq, &error);
2774 TALLOC_FREE(subreq);
2775 if (ret == -1) {
2776 struct dcecli_connection *p = state->p;
2777 NTSTATUS status = map_nt_error_from_unix_common(error);
2778
2779 TALLOC_FREE(state);
2780 dcerpc_transport_dead(p, status);
2781 return;
2782 }
2783
2784 TALLOC_FREE(state);
2785}
Note: See TracBrowser for help on using the repository browser.