Merge branch 'master' of ctdb into 'master' of samba
[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         subreq = state->ops->raw_call_send(state, ev, h,
159                                            object, opnum,
160                                            in_flags, in_data, in_length);
161         if (tevent_req_nomem(subreq, req)) {
162                 return tevent_req_post(req, ev);
163         }
164         tevent_req_set_callback(subreq, dcerpc_binding_handle_raw_call_done, req);
165
166         return req;
167 }
168
169 static void dcerpc_binding_handle_raw_call_done(struct tevent_req *subreq)
170 {
171         struct tevent_req *req = tevent_req_callback_data(subreq,
172                                  struct tevent_req);
173         struct dcerpc_binding_handle_raw_call_state *state =
174                 tevent_req_data(req,
175                 struct dcerpc_binding_handle_raw_call_state);
176         NTSTATUS error;
177
178         error = state->ops->raw_call_recv(subreq, state,
179                                           &state->out_data,
180                                           &state->out_length,
181                                           &state->out_flags);
182         TALLOC_FREE(subreq);
183         if (!NT_STATUS_IS_OK(error)) {
184                 tevent_req_nterror(req, error);
185                 return;
186         }
187
188         tevent_req_done(req);
189 }
190
191 NTSTATUS dcerpc_binding_handle_raw_call_recv(struct tevent_req *req,
192                                              TALLOC_CTX *mem_ctx,
193                                              uint8_t **out_data,
194                                              size_t *out_length,
195                                              uint32_t *out_flags)
196 {
197         struct dcerpc_binding_handle_raw_call_state *state =
198                 tevent_req_data(req,
199                 struct dcerpc_binding_handle_raw_call_state);
200         NTSTATUS error;
201
202         if (tevent_req_is_nterror(req, &error)) {
203                 tevent_req_received(req);
204                 return error;
205         }
206
207         *out_data = talloc_move(mem_ctx, &state->out_data);
208         *out_length = state->out_length;
209         *out_flags = state->out_flags;
210         tevent_req_received(req);
211         return NT_STATUS_OK;
212 }
213
214 NTSTATUS dcerpc_binding_handle_raw_call(struct dcerpc_binding_handle *h,
215                                         const struct GUID *object,
216                                         uint32_t opnum,
217                                         uint32_t in_flags,
218                                         const uint8_t *in_data,
219                                         size_t in_length,
220                                         TALLOC_CTX *mem_ctx,
221                                         uint8_t **out_data,
222                                         size_t *out_length,
223                                         uint32_t *out_flags)
224 {
225         TALLOC_CTX *frame = talloc_stackframe();
226         struct tevent_context *ev;
227         struct tevent_req *subreq;
228         NTSTATUS status;
229
230         /*
231          * TODO: allow only one sync call
232          */
233
234         if (h->sync_ev) {
235                 ev = h->sync_ev;
236         } else {
237                 ev = samba_tevent_context_init(frame);
238         }
239         if (ev == NULL) {
240                 talloc_free(frame);
241                 return NT_STATUS_NO_MEMORY;
242         }
243
244         subreq = dcerpc_binding_handle_raw_call_send(frame, ev,
245                                                      h, object, opnum,
246                                                      in_flags,
247                                                      in_data,
248                                                      in_length);
249         if (subreq == NULL) {
250                 talloc_free(frame);
251                 return NT_STATUS_NO_MEMORY;
252         }
253
254         if (!tevent_req_poll(subreq, ev)) {
255                 status = map_nt_error_from_unix_common(errno);
256                 talloc_free(frame);
257                 return status;
258         }
259
260         status = dcerpc_binding_handle_raw_call_recv(subreq,
261                                                      mem_ctx,
262                                                      out_data,
263                                                      out_length,
264                                                      out_flags);
265         if (!NT_STATUS_IS_OK(status)) {
266                 talloc_free(frame);
267                 return status;
268         }
269
270         TALLOC_FREE(frame);
271         return NT_STATUS_OK;
272 }
273
274 struct dcerpc_binding_handle_disconnect_state {
275         const struct dcerpc_binding_handle_ops *ops;
276 };
277
278 static void dcerpc_binding_handle_disconnect_done(struct tevent_req *subreq);
279
280 struct tevent_req *dcerpc_binding_handle_disconnect_send(TALLOC_CTX *mem_ctx,
281                                                 struct tevent_context *ev,
282                                                 struct dcerpc_binding_handle *h)
283 {
284         struct tevent_req *req;
285         struct dcerpc_binding_handle_disconnect_state *state;
286         struct tevent_req *subreq;
287
288         req = tevent_req_create(mem_ctx, &state,
289                                 struct dcerpc_binding_handle_disconnect_state);
290         if (req == NULL) {
291                 return NULL;
292         }
293
294         state->ops = h->ops;
295
296         subreq = state->ops->disconnect_send(state, ev, h);
297         if (tevent_req_nomem(subreq, req)) {
298                 return tevent_req_post(req, ev);
299         }
300         tevent_req_set_callback(subreq, dcerpc_binding_handle_disconnect_done, req);
301
302         return req;
303 }
304
305 static void dcerpc_binding_handle_disconnect_done(struct tevent_req *subreq)
306 {
307         struct tevent_req *req = tevent_req_callback_data(subreq,
308                                  struct tevent_req);
309         struct dcerpc_binding_handle_disconnect_state *state =
310                 tevent_req_data(req,
311                 struct dcerpc_binding_handle_disconnect_state);
312         NTSTATUS error;
313
314         error = state->ops->disconnect_recv(subreq);
315         TALLOC_FREE(subreq);
316         if (!NT_STATUS_IS_OK(error)) {
317                 tevent_req_nterror(req, error);
318                 return;
319         }
320
321         tevent_req_done(req);
322 }
323
324 NTSTATUS dcerpc_binding_handle_disconnect_recv(struct tevent_req *req)
325 {
326         NTSTATUS error;
327
328         if (tevent_req_is_nterror(req, &error)) {
329                 tevent_req_received(req);
330                 return error;
331         }
332
333         tevent_req_received(req);
334         return NT_STATUS_OK;
335 }
336
337 struct dcerpc_binding_handle_call_state {
338         struct dcerpc_binding_handle *h;
339         const struct ndr_interface_call *call;
340         TALLOC_CTX *r_mem;
341         void *r_ptr;
342         struct ndr_push *push;
343         DATA_BLOB request;
344         DATA_BLOB response;
345         struct ndr_pull *pull;
346 };
347
348 static void dcerpc_binding_handle_call_done(struct tevent_req *subreq);
349
350 struct tevent_req *dcerpc_binding_handle_call_send(TALLOC_CTX *mem_ctx,
351                                         struct tevent_context *ev,
352                                         struct dcerpc_binding_handle *h,
353                                         const struct GUID *object,
354                                         const struct ndr_interface_table *table,
355                                         uint32_t opnum,
356                                         TALLOC_CTX *r_mem,
357                                         void *r_ptr)
358 {
359         struct tevent_req *req;
360         struct dcerpc_binding_handle_call_state *state;
361         struct tevent_req *subreq;
362         enum ndr_err_code ndr_err;
363
364         req = tevent_req_create(mem_ctx, &state,
365                                 struct dcerpc_binding_handle_call_state);
366         if (req == NULL) {
367                 return NULL;
368         }
369
370 #if 0 /* TODO: activate this when the callers are fixed */
371         if (table != h->table) {
372                 tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
373                 return tevent_req_post(req, ev);
374         }
375 #endif
376
377         if (opnum >= table->num_calls) {
378                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
379                 return tevent_req_post(req, ev);
380         }
381
382         state->h = h;
383         state->call = &table->calls[opnum];
384
385         state->r_mem = r_mem;
386         state->r_ptr = r_ptr;
387
388         /* setup for a ndr_push_* call */
389         state->push = ndr_push_init_ctx(state);
390         if (tevent_req_nomem(state->push, req)) {
391                 return tevent_req_post(req, ev);
392         }
393
394         if (h->ops->ref_alloc && h->ops->ref_alloc(h)) {
395                 state->push->flags |= LIBNDR_FLAG_REF_ALLOC;
396         }
397
398         if (h->ops->push_bigendian && h->ops->push_bigendian(h)) {
399                 state->push->flags |= LIBNDR_FLAG_BIGENDIAN;
400         }
401
402         if (h->ops->use_ndr64 && h->ops->use_ndr64(h)) {
403                 state->push->flags |= LIBNDR_FLAG_NDR64;
404         }
405
406         if (h->ops->do_ndr_print) {
407                 h->ops->do_ndr_print(h, NDR_IN | NDR_SET_VALUES,
408                                      state->r_ptr, state->call);
409         }
410
411         /* push the structure into a blob */
412         ndr_err = state->call->ndr_push(state->push, NDR_IN, state->r_ptr);
413         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
414                 NTSTATUS error;
415                 error = ndr_map_error2ntstatus(ndr_err);
416                 if (h->ops->ndr_push_failed) {
417                         h->ops->ndr_push_failed(h, error,
418                                                 state->r_ptr,
419                                                 state->call);
420                 }
421                 tevent_req_nterror(req, error);
422                 return tevent_req_post(req, ev);
423         }
424
425         /* retrieve the blob */
426         state->request = ndr_push_blob(state->push);
427
428         if (h->ops->ndr_validate_in) {
429                 NTSTATUS error;
430                 error = h->ops->ndr_validate_in(h, state,
431                                                 &state->request,
432                                                 state->call);
433                 if (!NT_STATUS_IS_OK(error)) {
434                         tevent_req_nterror(req, error);
435                         return tevent_req_post(req, ev);
436                 }
437         }
438
439         subreq = dcerpc_binding_handle_raw_call_send(state, ev,
440                                                      h, object, opnum,
441                                                      state->push->flags,
442                                                      state->request.data,
443                                                      state->request.length);
444         if (tevent_req_nomem(subreq, req)) {
445                 return tevent_req_post(req, ev);
446         }
447         tevent_req_set_callback(subreq, dcerpc_binding_handle_call_done, req);
448
449         return req;
450 }
451
452 static void dcerpc_binding_handle_call_done(struct tevent_req *subreq)
453 {
454         struct tevent_req *req = tevent_req_callback_data(subreq,
455                                  struct tevent_req);
456         struct dcerpc_binding_handle_call_state *state =
457                 tevent_req_data(req,
458                 struct dcerpc_binding_handle_call_state);
459         struct dcerpc_binding_handle *h = state->h;
460         NTSTATUS error;
461         uint32_t out_flags = 0;
462         enum ndr_err_code ndr_err;
463
464         error = dcerpc_binding_handle_raw_call_recv(subreq, state,
465                                                     &state->response.data,
466                                                     &state->response.length,
467                                                     &out_flags);
468         TALLOC_FREE(subreq);
469         if (!NT_STATUS_IS_OK(error)) {
470                 tevent_req_nterror(req, error);
471                 return;
472         }
473
474         state->pull = ndr_pull_init_blob(&state->response, state);
475         if (tevent_req_nomem(state->pull, req)) {
476                 return;
477         }
478         state->pull->flags = state->push->flags;
479
480         if (out_flags & LIBNDR_FLAG_BIGENDIAN) {
481                 state->pull->flags |= LIBNDR_FLAG_BIGENDIAN;
482         } else {
483                 state->pull->flags &= ~LIBNDR_FLAG_BIGENDIAN;
484         }
485
486         state->pull->current_mem_ctx = state->r_mem;
487
488         /* pull the structure from the blob */
489         ndr_err = state->call->ndr_pull(state->pull, NDR_OUT, state->r_ptr);
490         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
491                 error = ndr_map_error2ntstatus(ndr_err);
492                 if (h->ops->ndr_pull_failed) {
493                         h->ops->ndr_pull_failed(h, error,
494                                                 &state->response,
495                                                 state->call);
496                 }
497                 tevent_req_nterror(req, error);
498                 return;
499         }
500
501         if (h->ops->do_ndr_print) {
502                 h->ops->do_ndr_print(h, NDR_OUT,
503                                      state->r_ptr, state->call);
504         }
505
506         if (h->ops->ndr_validate_out) {
507                 error = h->ops->ndr_validate_out(h,
508                                                  state->pull,
509                                                  state->r_ptr,
510                                                  state->call);
511                 if (!NT_STATUS_IS_OK(error)) {
512                         tevent_req_nterror(req, error);
513                         return;
514                 }
515         }
516
517         tevent_req_done(req);
518 }
519
520 NTSTATUS dcerpc_binding_handle_call_recv(struct tevent_req *req)
521 {
522         return tevent_req_simple_recv_ntstatus(req);
523 }
524
525 NTSTATUS dcerpc_binding_handle_call(struct dcerpc_binding_handle *h,
526                                     const struct GUID *object,
527                                     const struct ndr_interface_table *table,
528                                     uint32_t opnum,
529                                     TALLOC_CTX *r_mem,
530                                     void *r_ptr)
531 {
532         TALLOC_CTX *frame = talloc_stackframe();
533         struct tevent_context *ev;
534         struct tevent_req *subreq;
535         NTSTATUS status = NT_STATUS_NO_MEMORY;
536
537         /*
538          * TODO: allow only one sync call
539          */
540
541         if (h->sync_ev) {
542                 ev = h->sync_ev;
543         } else {
544                 ev = samba_tevent_context_init(frame);
545         }
546         if (ev == NULL) {
547                 goto fail;
548         }
549
550         subreq = dcerpc_binding_handle_call_send(frame, ev,
551                                                  h, object, table,
552                                                  opnum, r_mem, r_ptr);
553         if (subreq == NULL) {
554                 goto fail;
555         }
556
557         if (!tevent_req_poll_ntstatus(subreq, ev, &status)) {
558                 goto fail;
559         }
560
561         status = dcerpc_binding_handle_call_recv(subreq);
562 fail:
563         TALLOC_FREE(frame);
564         return status;
565 }