41675e103607b2502a8424ed794bda9f9a653fb1
[metze/samba/wip.git] / librpc / rpc / binding_handle.c
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 static int dcerpc_binding_handle_destructor(struct dcerpc_binding_handle *b)
38 {
39         return 0;
40 }
41
42 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         struct dcerpc_binding_handle *h;
52         void **ppstate = (void **)pstate;
53         void *state;
54
55         h = talloc_zero(mem_ctx, struct dcerpc_binding_handle);
56         if (h == NULL) {
57                 return NULL;
58         }
59         h->ops          = ops;
60         h->location     = location;
61         h->object       = object;
62         h->table        = table;
63
64         state = talloc_zero_size(h, psize);
65         if (state == NULL) {
66                 talloc_free(h);
67                 return NULL;
68         }
69         talloc_set_name_const(state, type);
70
71         h->private_data = state;
72
73         talloc_set_destructor(h, dcerpc_binding_handle_destructor);
74
75         *ppstate = state;
76         return h;
77 }
78
79 void *_dcerpc_binding_handle_data(struct dcerpc_binding_handle *h)
80 {
81         return h->private_data;
82 }
83
84 void dcerpc_binding_handle_set_sync_ev(struct dcerpc_binding_handle *h,
85                                        struct tevent_context *ev)
86 {
87         h->sync_ev = ev;
88 }
89
90 bool dcerpc_binding_handle_is_connected(struct dcerpc_binding_handle *h)
91 {
92         return h->ops->is_connected(h);
93 }
94
95 uint32_t dcerpc_binding_handle_set_timeout(struct dcerpc_binding_handle *h,
96                                            uint32_t timeout)
97 {
98         return h->ops->set_timeout(h, timeout);
99 }
100
101 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         enum dcerpc_AuthType _auth_type;
106         enum dcerpc_AuthLevel _auth_level;
107
108         if (auth_type == NULL) {
109                 auth_type = &_auth_type;
110         }
111
112         if (auth_level == NULL) {
113                 auth_level = &_auth_level;
114         }
115
116         *auth_type = DCERPC_AUTH_TYPE_NONE;
117         *auth_level = DCERPC_AUTH_LEVEL_NONE;
118
119         if (h->ops->auth_info == NULL) {
120                 return;
121         }
122
123         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 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         struct tevent_req *req;
145         struct dcerpc_binding_handle_raw_call_state *state;
146         struct tevent_req *subreq;
147
148         req = tevent_req_create(mem_ctx, &state,
149                                 struct dcerpc_binding_handle_raw_call_state);
150         if (req == NULL) {
151                 return NULL;
152         }
153         state->ops = h->ops;
154         state->out_data = NULL;
155         state->out_length = 0;
156         state->out_flags = 0;
157
158         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                 if (object != NULL) {
164                         tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
165                         return tevent_req_post(req, ev);
166                 }
167
168                 /*
169                  * We use the object from the binding handle
170                  */
171                 object = h->object;
172         }
173
174         subreq = state->ops->raw_call_send(state, ev, h,
175                                            object, opnum,
176                                            in_flags, in_data, in_length);
177         if (tevent_req_nomem(subreq, req)) {
178                 return tevent_req_post(req, ev);
179         }
180         tevent_req_set_callback(subreq, dcerpc_binding_handle_raw_call_done, req);
181
182         return req;
183 }
184
185 static void dcerpc_binding_handle_raw_call_done(struct tevent_req *subreq)
186 {
187         struct tevent_req *req = tevent_req_callback_data(subreq,
188                                  struct tevent_req);
189         struct dcerpc_binding_handle_raw_call_state *state =
190                 tevent_req_data(req,
191                 struct dcerpc_binding_handle_raw_call_state);
192         NTSTATUS error;
193
194         error = state->ops->raw_call_recv(subreq, state,
195                                           &state->out_data,
196                                           &state->out_length,
197                                           &state->out_flags);
198         TALLOC_FREE(subreq);
199         if (tevent_req_nterror(req, error)) {
200                 return;
201         }
202
203         tevent_req_done(req);
204 }
205
206 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         struct dcerpc_binding_handle_raw_call_state *state =
213                 tevent_req_data(req,
214                 struct dcerpc_binding_handle_raw_call_state);
215         NTSTATUS error;
216
217         if (tevent_req_is_nterror(req, &error)) {
218                 tevent_req_received(req);
219                 return error;
220         }
221
222         *out_data = talloc_move(mem_ctx, &state->out_data);
223         *out_length = state->out_length;
224         *out_flags = state->out_flags;
225         tevent_req_received(req);
226         return NT_STATUS_OK;
227 }
228
229 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         TALLOC_CTX *frame = talloc_stackframe();
241         struct tevent_context *ev;
242         struct tevent_req *subreq;
243         NTSTATUS status = NT_STATUS_NO_MEMORY;
244
245         /*
246          * TODO: allow only one sync call
247          */
248
249         if (h->sync_ev) {
250                 ev = h->sync_ev;
251         } else {
252                 ev = samba_tevent_context_init(frame);
253         }
254         if (ev == NULL) {
255                 goto fail;
256         }
257
258         subreq = dcerpc_binding_handle_raw_call_send(frame, ev,
259                                                      h, object, opnum,
260                                                      in_flags,
261                                                      in_data,
262                                                      in_length);
263         if (subreq == NULL) {
264                 goto fail;
265         }
266
267         if (!tevent_req_poll_ntstatus(subreq, ev, &status)) {
268                 goto fail;
269         }
270
271         status = dcerpc_binding_handle_raw_call_recv(subreq,
272                                                      mem_ctx,
273                                                      out_data,
274                                                      out_length,
275                                                      out_flags);
276 fail:
277         TALLOC_FREE(frame);
278         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 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         struct tevent_req *req;
292         struct dcerpc_binding_handle_disconnect_state *state;
293         struct tevent_req *subreq;
294
295         req = tevent_req_create(mem_ctx, &state,
296                                 struct dcerpc_binding_handle_disconnect_state);
297         if (req == NULL) {
298                 return NULL;
299         }
300
301         state->ops = h->ops;
302
303         subreq = state->ops->disconnect_send(state, ev, h);
304         if (tevent_req_nomem(subreq, req)) {
305                 return tevent_req_post(req, ev);
306         }
307         tevent_req_set_callback(subreq, dcerpc_binding_handle_disconnect_done, req);
308
309         return req;
310 }
311
312 static void dcerpc_binding_handle_disconnect_done(struct tevent_req *subreq)
313 {
314         struct tevent_req *req = tevent_req_callback_data(subreq,
315                                  struct tevent_req);
316         struct dcerpc_binding_handle_disconnect_state *state =
317                 tevent_req_data(req,
318                 struct dcerpc_binding_handle_disconnect_state);
319         NTSTATUS error;
320
321         error = state->ops->disconnect_recv(subreq);
322         TALLOC_FREE(subreq);
323         if (tevent_req_nterror(req, error)) {
324                 return;
325         }
326
327         tevent_req_done(req);
328 }
329
330 NTSTATUS dcerpc_binding_handle_disconnect_recv(struct tevent_req *req)
331 {
332         NTSTATUS error;
333
334         if (tevent_req_is_nterror(req, &error)) {
335                 tevent_req_received(req);
336                 return error;
337         }
338
339         tevent_req_received(req);
340         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 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         struct tevent_req *req;
366         struct dcerpc_binding_handle_call_state *state;
367         struct tevent_req *subreq;
368         enum ndr_err_code ndr_err;
369
370         req = tevent_req_create(mem_ctx, &state,
371                                 struct dcerpc_binding_handle_call_state);
372         if (req == NULL) {
373                 return NULL;
374         }
375
376         if (table != h->table) {
377                 tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
378                 return tevent_req_post(req, ev);
379         }
380
381         if (opnum >= table->num_calls) {
382                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
383                 return tevent_req_post(req, ev);
384         }
385
386         state->h = h;
387         state->call = &table->calls[opnum];
388
389         state->r_mem = r_mem;
390         state->r_ptr = r_ptr;
391
392         /* setup for a ndr_push_* call */
393         state->push = ndr_push_init_ctx(state);
394         if (tevent_req_nomem(state->push, req)) {
395                 return tevent_req_post(req, ev);
396         }
397
398         if (h->ops->ref_alloc && h->ops->ref_alloc(h)) {
399                 state->push->flags |= LIBNDR_FLAG_REF_ALLOC;
400         }
401
402         if (h->ops->push_bigendian && h->ops->push_bigendian(h)) {
403                 state->push->flags |= LIBNDR_FLAG_BIGENDIAN;
404         }
405
406         if (h->ops->use_ndr64 && h->ops->use_ndr64(h)) {
407                 state->push->flags |= LIBNDR_FLAG_NDR64;
408         }
409
410         if (h->ops->do_ndr_print) {
411                 h->ops->do_ndr_print(h, NDR_IN | NDR_SET_VALUES,
412                                      state->r_ptr, state->call);
413         }
414
415         /* push the structure into a blob */
416         ndr_err = state->call->ndr_push(state->push, NDR_IN, state->r_ptr);
417         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
418                 NTSTATUS error;
419                 error = ndr_map_error2ntstatus(ndr_err);
420                 if (h->ops->ndr_push_failed) {
421                         h->ops->ndr_push_failed(h, error,
422                                                 state->r_ptr,
423                                                 state->call);
424                 }
425                 tevent_req_nterror(req, error);
426                 return tevent_req_post(req, ev);
427         }
428
429         /* retrieve the blob */
430         state->request = ndr_push_blob(state->push);
431
432         if (h->ops->ndr_validate_in) {
433                 NTSTATUS error;
434                 error = h->ops->ndr_validate_in(h, state,
435                                                 &state->request,
436                                                 state->call);
437                 if (!NT_STATUS_IS_OK(error)) {
438                         tevent_req_nterror(req, error);
439                         return tevent_req_post(req, ev);
440                 }
441         }
442
443         subreq = dcerpc_binding_handle_raw_call_send(state, ev,
444                                                      h, object, opnum,
445                                                      state->push->flags,
446                                                      state->request.data,
447                                                      state->request.length);
448         if (tevent_req_nomem(subreq, req)) {
449                 return tevent_req_post(req, ev);
450         }
451         tevent_req_set_callback(subreq, dcerpc_binding_handle_call_done, req);
452
453         return req;
454 }
455
456 static void dcerpc_binding_handle_call_done(struct tevent_req *subreq)
457 {
458         struct tevent_req *req = tevent_req_callback_data(subreq,
459                                  struct tevent_req);
460         struct dcerpc_binding_handle_call_state *state =
461                 tevent_req_data(req,
462                 struct dcerpc_binding_handle_call_state);
463         struct dcerpc_binding_handle *h = state->h;
464         NTSTATUS error;
465         uint32_t out_flags = 0;
466         enum ndr_err_code ndr_err;
467
468         error = dcerpc_binding_handle_raw_call_recv(subreq, state,
469                                                     &state->response.data,
470                                                     &state->response.length,
471                                                     &out_flags);
472         TALLOC_FREE(subreq);
473         if (tevent_req_nterror(req, error)) {
474                 return;
475         }
476
477         state->pull = ndr_pull_init_blob(&state->response, state);
478         if (tevent_req_nomem(state->pull, req)) {
479                 return;
480         }
481         state->pull->flags = state->push->flags;
482
483         if (out_flags & LIBNDR_FLAG_BIGENDIAN) {
484                 state->pull->flags |= LIBNDR_FLAG_BIGENDIAN;
485         } else {
486                 state->pull->flags &= ~LIBNDR_FLAG_BIGENDIAN;
487         }
488
489         state->pull->current_mem_ctx = state->r_mem;
490
491         /* pull the structure from the blob */
492         ndr_err = state->call->ndr_pull(state->pull, NDR_OUT, state->r_ptr);
493         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
494                 error = ndr_map_error2ntstatus(ndr_err);
495                 if (h->ops->ndr_pull_failed) {
496                         h->ops->ndr_pull_failed(h, error,
497                                                 &state->response,
498                                                 state->call);
499                 }
500                 tevent_req_nterror(req, error);
501                 return;
502         }
503
504         if (h->ops->do_ndr_print) {
505                 h->ops->do_ndr_print(h, NDR_OUT,
506                                      state->r_ptr, state->call);
507         }
508
509         if (h->ops->ndr_validate_out) {
510                 error = h->ops->ndr_validate_out(h,
511                                                  state->pull,
512                                                  state->r_ptr,
513                                                  state->call);
514                 if (!NT_STATUS_IS_OK(error)) {
515                         tevent_req_nterror(req, error);
516                         return;
517                 }
518         }
519
520         tevent_req_done(req);
521 }
522
523 NTSTATUS dcerpc_binding_handle_call_recv(struct tevent_req *req)
524 {
525         return tevent_req_simple_recv_ntstatus(req);
526 }
527
528 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         TALLOC_CTX *frame = talloc_stackframe();
536         struct tevent_context *ev;
537         struct tevent_req *subreq;
538         NTSTATUS status = NT_STATUS_NO_MEMORY;
539
540         /*
541          * TODO: allow only one sync call
542          */
543
544         if (h->sync_ev) {
545                 ev = h->sync_ev;
546         } else {
547                 ev = samba_tevent_context_init(frame);
548         }
549         if (ev == NULL) {
550                 goto fail;
551         }
552
553         subreq = dcerpc_binding_handle_call_send(frame, ev,
554                                                  h, object, table,
555                                                  opnum, r_mem, r_ptr);
556         if (subreq == NULL) {
557                 goto fail;
558         }
559
560         if (!tevent_req_poll_ntstatus(subreq, ev, &status)) {
561                 goto fail;
562         }
563
564         status = dcerpc_binding_handle_call_recv(subreq);
565 fail:
566         TALLOC_FREE(frame);
567         return status;
568 }