Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : dcerpc binding handle functions
5 :
6 : Copyright (C) Stefan Metzmacher 2010
7 :
8 : This program is free software; you can redistribute it and/or modify
9 : it under the terms of the GNU General Public License as published by
10 : the Free Software Foundation; either version 3 of the License, or
11 : (at your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful,
14 : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : GNU General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program. If not, see <http://www.gnu.org/licenses/>.
20 : */
21 :
22 : #include "includes.h"
23 : #include <tevent.h>
24 : #include "../lib/util/tevent_ntstatus.h"
25 : #include "librpc/rpc/dcerpc.h"
26 : #include "rpc_common.h"
27 :
28 : struct dcerpc_binding_handle {
29 : void *private_data;
30 : const struct dcerpc_binding_handle_ops *ops;
31 : const char *location;
32 : const struct GUID *object;
33 : const struct ndr_interface_table *table;
34 : struct tevent_context *sync_ev;
35 : };
36 :
37 69900 : static int dcerpc_binding_handle_destructor(struct dcerpc_binding_handle *b)
38 : {
39 69900 : return 0;
40 : }
41 :
42 70516 : struct dcerpc_binding_handle *_dcerpc_binding_handle_create(TALLOC_CTX *mem_ctx,
43 : const struct dcerpc_binding_handle_ops *ops,
44 : const struct GUID *object,
45 : const struct ndr_interface_table *table,
46 : void *pstate,
47 : size_t psize,
48 : const char *type,
49 : const char *location)
50 : {
51 905 : struct dcerpc_binding_handle *h;
52 70516 : void **ppstate = (void **)pstate;
53 905 : void *state;
54 :
55 70516 : h = talloc_zero(mem_ctx, struct dcerpc_binding_handle);
56 70516 : if (h == NULL) {
57 0 : return NULL;
58 : }
59 70516 : h->ops = ops;
60 70516 : h->location = location;
61 70516 : h->object = object;
62 70516 : h->table = table;
63 :
64 70516 : state = talloc_zero_size(h, psize);
65 70516 : if (state == NULL) {
66 0 : talloc_free(h);
67 0 : return NULL;
68 : }
69 70516 : talloc_set_name_const(state, type);
70 :
71 70516 : h->private_data = state;
72 :
73 70516 : talloc_set_destructor(h, dcerpc_binding_handle_destructor);
74 :
75 70516 : *ppstate = state;
76 70516 : return h;
77 : }
78 :
79 4335939 : void *_dcerpc_binding_handle_data(struct dcerpc_binding_handle *h)
80 : {
81 4335939 : return h->private_data;
82 : }
83 :
84 20221 : void dcerpc_binding_handle_set_sync_ev(struct dcerpc_binding_handle *h,
85 : struct tevent_context *ev)
86 : {
87 20221 : h->sync_ev = ev;
88 20221 : }
89 :
90 5064 : bool dcerpc_binding_handle_is_connected(struct dcerpc_binding_handle *h)
91 : {
92 5064 : return h->ops->is_connected(h);
93 : }
94 :
95 5965 : uint32_t dcerpc_binding_handle_set_timeout(struct dcerpc_binding_handle *h,
96 : uint32_t timeout)
97 : {
98 5965 : return h->ops->set_timeout(h, timeout);
99 : }
100 :
101 1788 : void dcerpc_binding_handle_auth_info(struct dcerpc_binding_handle *h,
102 : enum dcerpc_AuthType *auth_type,
103 : enum dcerpc_AuthLevel *auth_level)
104 : {
105 256 : enum dcerpc_AuthType _auth_type;
106 256 : enum dcerpc_AuthLevel _auth_level;
107 :
108 1788 : if (auth_type == NULL) {
109 1196 : auth_type = &_auth_type;
110 : }
111 :
112 1788 : if (auth_level == NULL) {
113 0 : auth_level = &_auth_level;
114 : }
115 :
116 1788 : *auth_type = DCERPC_AUTH_TYPE_NONE;
117 1788 : *auth_level = DCERPC_AUTH_LEVEL_NONE;
118 :
119 1788 : if (h->ops->auth_info == NULL) {
120 0 : return;
121 : }
122 :
123 1788 : h->ops->auth_info(h, auth_type, auth_level);
124 : }
125 :
126 : struct dcerpc_binding_handle_raw_call_state {
127 : const struct dcerpc_binding_handle_ops *ops;
128 : uint8_t *out_data;
129 : size_t out_length;
130 : uint32_t out_flags;
131 : };
132 :
133 : static void dcerpc_binding_handle_raw_call_done(struct tevent_req *subreq);
134 :
135 1114550 : struct tevent_req *dcerpc_binding_handle_raw_call_send(TALLOC_CTX *mem_ctx,
136 : struct tevent_context *ev,
137 : struct dcerpc_binding_handle *h,
138 : const struct GUID *object,
139 : uint32_t opnum,
140 : uint32_t in_flags,
141 : const uint8_t *in_data,
142 : size_t in_length)
143 : {
144 23437 : struct tevent_req *req;
145 23437 : struct dcerpc_binding_handle_raw_call_state *state;
146 23437 : struct tevent_req *subreq;
147 :
148 1114550 : req = tevent_req_create(mem_ctx, &state,
149 : struct dcerpc_binding_handle_raw_call_state);
150 1114550 : if (req == NULL) {
151 0 : return NULL;
152 : }
153 1114550 : state->ops = h->ops;
154 1114550 : state->out_data = NULL;
155 1114550 : state->out_length = 0;
156 1114550 : state->out_flags = 0;
157 :
158 1114550 : if (h->object != NULL) {
159 : /*
160 : * If an object is set on the binding handle,
161 : * per request object passing is not allowed.
162 : */
163 256 : if (object != NULL) {
164 0 : tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
165 0 : return tevent_req_post(req, ev);
166 : }
167 :
168 : /*
169 : * We use the object from the binding handle
170 : */
171 200 : object = h->object;
172 : }
173 :
174 1114550 : subreq = state->ops->raw_call_send(state, ev, h,
175 : object, opnum,
176 : in_flags, in_data, in_length);
177 1114550 : if (tevent_req_nomem(subreq, req)) {
178 0 : return tevent_req_post(req, ev);
179 : }
180 1114550 : tevent_req_set_callback(subreq, dcerpc_binding_handle_raw_call_done, req);
181 :
182 1114550 : return req;
183 : }
184 :
185 1109886 : static void dcerpc_binding_handle_raw_call_done(struct tevent_req *subreq)
186 : {
187 1109886 : struct tevent_req *req = tevent_req_callback_data(subreq,
188 : struct tevent_req);
189 23437 : struct dcerpc_binding_handle_raw_call_state *state =
190 1109886 : tevent_req_data(req,
191 : struct dcerpc_binding_handle_raw_call_state);
192 23437 : NTSTATUS error;
193 :
194 1109886 : error = state->ops->raw_call_recv(subreq, state,
195 : &state->out_data,
196 : &state->out_length,
197 : &state->out_flags);
198 1109886 : TALLOC_FREE(subreq);
199 1109886 : if (tevent_req_nterror(req, error)) {
200 3044 : return;
201 : }
202 :
203 1106842 : tevent_req_done(req);
204 : }
205 :
206 1109886 : NTSTATUS dcerpc_binding_handle_raw_call_recv(struct tevent_req *req,
207 : TALLOC_CTX *mem_ctx,
208 : uint8_t **out_data,
209 : size_t *out_length,
210 : uint32_t *out_flags)
211 : {
212 23437 : struct dcerpc_binding_handle_raw_call_state *state =
213 1109886 : tevent_req_data(req,
214 : struct dcerpc_binding_handle_raw_call_state);
215 23437 : NTSTATUS error;
216 :
217 1109886 : if (tevent_req_is_nterror(req, &error)) {
218 3044 : tevent_req_received(req);
219 3044 : return error;
220 : }
221 :
222 1106842 : *out_data = talloc_move(mem_ctx, &state->out_data);
223 1106842 : *out_length = state->out_length;
224 1106842 : *out_flags = state->out_flags;
225 1106842 : tevent_req_received(req);
226 1106842 : return NT_STATUS_OK;
227 : }
228 :
229 7 : NTSTATUS dcerpc_binding_handle_raw_call(struct dcerpc_binding_handle *h,
230 : const struct GUID *object,
231 : uint32_t opnum,
232 : uint32_t in_flags,
233 : const uint8_t *in_data,
234 : size_t in_length,
235 : TALLOC_CTX *mem_ctx,
236 : uint8_t **out_data,
237 : size_t *out_length,
238 : uint32_t *out_flags)
239 : {
240 7 : TALLOC_CTX *frame = talloc_stackframe();
241 0 : struct tevent_context *ev;
242 0 : struct tevent_req *subreq;
243 7 : NTSTATUS status = NT_STATUS_NO_MEMORY;
244 :
245 : /*
246 : * TODO: allow only one sync call
247 : */
248 :
249 7 : if (h->sync_ev) {
250 7 : ev = h->sync_ev;
251 : } else {
252 0 : ev = samba_tevent_context_init(frame);
253 : }
254 7 : if (ev == NULL) {
255 0 : goto fail;
256 : }
257 :
258 7 : subreq = dcerpc_binding_handle_raw_call_send(frame, ev,
259 : h, object, opnum,
260 : in_flags,
261 : in_data,
262 : in_length);
263 7 : if (subreq == NULL) {
264 0 : goto fail;
265 : }
266 :
267 7 : if (!tevent_req_poll_ntstatus(subreq, ev, &status)) {
268 0 : goto fail;
269 : }
270 :
271 7 : status = dcerpc_binding_handle_raw_call_recv(subreq,
272 : mem_ctx,
273 : out_data,
274 : out_length,
275 : out_flags);
276 7 : fail:
277 7 : TALLOC_FREE(frame);
278 7 : return status;
279 : }
280 :
281 : struct dcerpc_binding_handle_disconnect_state {
282 : const struct dcerpc_binding_handle_ops *ops;
283 : };
284 :
285 : static void dcerpc_binding_handle_disconnect_done(struct tevent_req *subreq);
286 :
287 0 : struct tevent_req *dcerpc_binding_handle_disconnect_send(TALLOC_CTX *mem_ctx,
288 : struct tevent_context *ev,
289 : struct dcerpc_binding_handle *h)
290 : {
291 0 : struct tevent_req *req;
292 0 : struct dcerpc_binding_handle_disconnect_state *state;
293 0 : struct tevent_req *subreq;
294 :
295 0 : req = tevent_req_create(mem_ctx, &state,
296 : struct dcerpc_binding_handle_disconnect_state);
297 0 : if (req == NULL) {
298 0 : return NULL;
299 : }
300 :
301 0 : state->ops = h->ops;
302 :
303 0 : subreq = state->ops->disconnect_send(state, ev, h);
304 0 : if (tevent_req_nomem(subreq, req)) {
305 0 : return tevent_req_post(req, ev);
306 : }
307 0 : tevent_req_set_callback(subreq, dcerpc_binding_handle_disconnect_done, req);
308 :
309 0 : return req;
310 : }
311 :
312 0 : static void dcerpc_binding_handle_disconnect_done(struct tevent_req *subreq)
313 : {
314 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
315 : struct tevent_req);
316 0 : struct dcerpc_binding_handle_disconnect_state *state =
317 0 : tevent_req_data(req,
318 : struct dcerpc_binding_handle_disconnect_state);
319 0 : NTSTATUS error;
320 :
321 0 : error = state->ops->disconnect_recv(subreq);
322 0 : TALLOC_FREE(subreq);
323 0 : if (tevent_req_nterror(req, error)) {
324 0 : return;
325 : }
326 :
327 0 : tevent_req_done(req);
328 : }
329 :
330 0 : NTSTATUS dcerpc_binding_handle_disconnect_recv(struct tevent_req *req)
331 : {
332 0 : NTSTATUS error;
333 :
334 0 : if (tevent_req_is_nterror(req, &error)) {
335 0 : tevent_req_received(req);
336 0 : return error;
337 : }
338 :
339 0 : tevent_req_received(req);
340 0 : return NT_STATUS_OK;
341 : }
342 :
343 : struct dcerpc_binding_handle_call_state {
344 : struct dcerpc_binding_handle *h;
345 : const struct ndr_interface_call *call;
346 : TALLOC_CTX *r_mem;
347 : void *r_ptr;
348 : struct ndr_push *push;
349 : DATA_BLOB request;
350 : DATA_BLOB response;
351 : struct ndr_pull *pull;
352 : };
353 :
354 : static void dcerpc_binding_handle_call_done(struct tevent_req *subreq);
355 :
356 1114633 : struct tevent_req *dcerpc_binding_handle_call_send(TALLOC_CTX *mem_ctx,
357 : struct tevent_context *ev,
358 : struct dcerpc_binding_handle *h,
359 : const struct GUID *object,
360 : const struct ndr_interface_table *table,
361 : uint32_t opnum,
362 : TALLOC_CTX *r_mem,
363 : void *r_ptr)
364 : {
365 23437 : struct tevent_req *req;
366 23437 : struct dcerpc_binding_handle_call_state *state;
367 23437 : struct tevent_req *subreq;
368 23437 : enum ndr_err_code ndr_err;
369 :
370 1114633 : req = tevent_req_create(mem_ctx, &state,
371 : struct dcerpc_binding_handle_call_state);
372 1114633 : if (req == NULL) {
373 0 : return NULL;
374 : }
375 :
376 1114633 : if (table != h->table) {
377 0 : tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
378 0 : return tevent_req_post(req, ev);
379 : }
380 :
381 1114633 : if (opnum >= table->num_calls) {
382 0 : tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
383 0 : return tevent_req_post(req, ev);
384 : }
385 :
386 1114633 : state->h = h;
387 1114633 : state->call = &table->calls[opnum];
388 :
389 1114633 : state->r_mem = r_mem;
390 1114633 : state->r_ptr = r_ptr;
391 :
392 : /* setup for a ndr_push_* call */
393 1114633 : state->push = ndr_push_init_ctx(state);
394 1114633 : if (tevent_req_nomem(state->push, req)) {
395 0 : return tevent_req_post(req, ev);
396 : }
397 :
398 1114633 : if (h->ops->ref_alloc && h->ops->ref_alloc(h)) {
399 838761 : state->push->flags |= LIBNDR_FLAG_REF_ALLOC;
400 : }
401 :
402 1114633 : if (h->ops->push_bigendian && h->ops->push_bigendian(h)) {
403 28440 : state->push->flags |= LIBNDR_FLAG_BIGENDIAN;
404 : }
405 :
406 1114633 : if (h->ops->use_ndr64 && h->ops->use_ndr64(h)) {
407 0 : state->push->flags |= LIBNDR_FLAG_NDR64;
408 : }
409 :
410 1114633 : if (h->ops->do_ndr_print) {
411 1114633 : h->ops->do_ndr_print(h, NDR_IN | NDR_SET_VALUES,
412 1114633 : state->r_ptr, state->call);
413 : }
414 :
415 : /* push the structure into a blob */
416 1114633 : ndr_err = state->call->ndr_push(state->push, NDR_IN, state->r_ptr);
417 1114633 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
418 0 : NTSTATUS error;
419 90 : error = ndr_map_error2ntstatus(ndr_err);
420 90 : if (h->ops->ndr_push_failed) {
421 90 : h->ops->ndr_push_failed(h, error,
422 90 : state->r_ptr,
423 90 : state->call);
424 : }
425 90 : tevent_req_nterror(req, error);
426 90 : return tevent_req_post(req, ev);
427 : }
428 :
429 : /* retrieve the blob */
430 1114543 : state->request = ndr_push_blob(state->push);
431 :
432 1114543 : if (h->ops->ndr_validate_in) {
433 6881 : NTSTATUS error;
434 299535 : error = h->ops->ndr_validate_in(h, state,
435 299535 : &state->request,
436 299535 : state->call);
437 299535 : if (!NT_STATUS_IS_OK(error)) {
438 0 : tevent_req_nterror(req, error);
439 0 : return tevent_req_post(req, ev);
440 : }
441 : }
442 :
443 1137980 : subreq = dcerpc_binding_handle_raw_call_send(state, ev,
444 : h, object, opnum,
445 1114543 : state->push->flags,
446 1114543 : state->request.data,
447 1114543 : state->request.length);
448 1114543 : if (tevent_req_nomem(subreq, req)) {
449 0 : return tevent_req_post(req, ev);
450 : }
451 1114543 : tevent_req_set_callback(subreq, dcerpc_binding_handle_call_done, req);
452 :
453 1114543 : return req;
454 : }
455 :
456 1109879 : static void dcerpc_binding_handle_call_done(struct tevent_req *subreq)
457 : {
458 1109879 : struct tevent_req *req = tevent_req_callback_data(subreq,
459 : struct tevent_req);
460 23437 : struct dcerpc_binding_handle_call_state *state =
461 1109879 : tevent_req_data(req,
462 : struct dcerpc_binding_handle_call_state);
463 1109879 : struct dcerpc_binding_handle *h = state->h;
464 23437 : NTSTATUS error;
465 1109879 : uint32_t out_flags = 0;
466 23437 : enum ndr_err_code ndr_err;
467 :
468 1109879 : error = dcerpc_binding_handle_raw_call_recv(subreq, state,
469 : &state->response.data,
470 : &state->response.length,
471 : &out_flags);
472 1109879 : TALLOC_FREE(subreq);
473 1109879 : if (tevent_req_nterror(req, error)) {
474 3044 : return;
475 : }
476 :
477 1106835 : state->pull = ndr_pull_init_blob(&state->response, state);
478 1106835 : if (tevent_req_nomem(state->pull, req)) {
479 0 : return;
480 : }
481 1106835 : state->pull->flags = state->push->flags;
482 :
483 1106835 : if (out_flags & LIBNDR_FLAG_BIGENDIAN) {
484 0 : state->pull->flags |= LIBNDR_FLAG_BIGENDIAN;
485 : } else {
486 1106835 : state->pull->flags &= ~LIBNDR_FLAG_BIGENDIAN;
487 : }
488 :
489 1106835 : state->pull->current_mem_ctx = state->r_mem;
490 :
491 : /* pull the structure from the blob */
492 1106835 : ndr_err = state->call->ndr_pull(state->pull, NDR_OUT, state->r_ptr);
493 1106835 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
494 0 : error = ndr_map_error2ntstatus(ndr_err);
495 0 : if (h->ops->ndr_pull_failed) {
496 0 : h->ops->ndr_pull_failed(h, error,
497 0 : &state->response,
498 : state->call);
499 : }
500 0 : tevent_req_nterror(req, error);
501 0 : return;
502 : }
503 :
504 1106835 : if (h->ops->do_ndr_print) {
505 1106835 : h->ops->do_ndr_print(h, NDR_OUT,
506 1106835 : state->r_ptr, state->call);
507 : }
508 :
509 1106835 : if (h->ops->ndr_validate_out) {
510 296937 : error = h->ops->ndr_validate_out(h,
511 : state->pull,
512 296937 : state->r_ptr,
513 : state->call);
514 296937 : if (!NT_STATUS_IS_OK(error)) {
515 0 : tevent_req_nterror(req, error);
516 0 : return;
517 : }
518 : }
519 :
520 1106835 : tevent_req_done(req);
521 : }
522 :
523 1109969 : NTSTATUS dcerpc_binding_handle_call_recv(struct tevent_req *req)
524 : {
525 1109969 : return tevent_req_simple_recv_ntstatus(req);
526 : }
527 :
528 829003 : NTSTATUS dcerpc_binding_handle_call(struct dcerpc_binding_handle *h,
529 : const struct GUID *object,
530 : const struct ndr_interface_table *table,
531 : uint32_t opnum,
532 : TALLOC_CTX *r_mem,
533 : void *r_ptr)
534 : {
535 829003 : TALLOC_CTX *frame = talloc_stackframe();
536 6426 : struct tevent_context *ev;
537 6426 : struct tevent_req *subreq;
538 829003 : NTSTATUS status = NT_STATUS_NO_MEMORY;
539 :
540 : /*
541 : * TODO: allow only one sync call
542 : */
543 :
544 829003 : if (h->sync_ev) {
545 275993 : ev = h->sync_ev;
546 : } else {
547 546584 : ev = samba_tevent_context_init(frame);
548 : }
549 829003 : if (ev == NULL) {
550 0 : goto fail;
551 : }
552 :
553 829003 : subreq = dcerpc_binding_handle_call_send(frame, ev,
554 : h, object, table,
555 : opnum, r_mem, r_ptr);
556 829003 : if (subreq == NULL) {
557 0 : goto fail;
558 : }
559 :
560 829003 : if (!tevent_req_poll_ntstatus(subreq, ev, &status)) {
561 0 : goto fail;
562 : }
563 :
564 829003 : status = dcerpc_binding_handle_call_recv(subreq);
565 829003 : fail:
566 829003 : TALLOC_FREE(frame);
567 829003 : return status;
568 : }
|