waf: added top level build rules
[samba.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
27 struct dcerpc_binding_handle {
28         void *private_data;
29         const struct dcerpc_binding_handle_ops *ops;
30         const char *location;
31         const struct GUID *object;
32         const struct ndr_interface_table *table;
33         struct tevent_context *sync_ev;
34 };
35
36 static int dcerpc_binding_handle_destructor(struct dcerpc_binding_handle *b)
37 {
38         return 0;
39 }
40
41 struct dcerpc_binding_handle *_dcerpc_binding_handle_create(TALLOC_CTX *mem_ctx,
42                                         const struct dcerpc_binding_handle_ops *ops,
43                                         const struct GUID *object,
44                                         const struct ndr_interface_table *table,
45                                         void *pstate,
46                                         size_t psize,
47                                         const char *type,
48                                         const char *location)
49 {
50         struct dcerpc_binding_handle *h;
51         void **ppstate = (void **)pstate;
52         void *state;
53
54         h = talloc_zero(mem_ctx, struct dcerpc_binding_handle);
55         if (h == NULL) {
56                 return NULL;
57         }
58         h->ops          = ops;
59         h->location     = location;
60         h->object       = object;
61         h->table        = table;
62
63         state = talloc_zero_size(h, psize);
64         if (state == NULL) {
65                 talloc_free(h);
66                 return NULL;
67         }
68         talloc_set_name_const(state, type);
69
70         h->private_data = state;
71
72         talloc_set_destructor(h, dcerpc_binding_handle_destructor);
73
74         *ppstate = state;
75         return h;
76 }
77
78 void *_dcerpc_binding_handle_data(struct dcerpc_binding_handle *h)
79 {
80         return h->private_data;
81 }
82
83 void dcerpc_binding_handle_set_sync_ev(struct dcerpc_binding_handle *h,
84                                        struct tevent_context *ev)
85 {
86         h->sync_ev = ev;
87 }
88
89 bool dcerpc_binding_handle_is_connected(struct dcerpc_binding_handle *h)
90 {
91         return h->ops->is_connected(h);
92 }
93
94 uint32_t dcerpc_binding_handle_set_timeout(struct dcerpc_binding_handle *h,
95                                            uint32_t timeout)
96 {
97         return h->ops->set_timeout(h, timeout);
98 }
99
100 struct dcerpc_binding_handle_raw_call_state {
101         const struct dcerpc_binding_handle_ops *ops;
102         uint8_t *out_data;
103         size_t out_length;
104         uint32_t out_flags;
105 };
106
107 static void dcerpc_binding_handle_raw_call_done(struct tevent_req *subreq);
108
109 struct tevent_req *dcerpc_binding_handle_raw_call_send(TALLOC_CTX *mem_ctx,
110                                                 struct tevent_context *ev,
111                                                 struct dcerpc_binding_handle *h,
112                                                 const struct GUID *object,
113                                                 uint32_t opnum,
114                                                 uint32_t in_flags,
115                                                 const uint8_t *in_data,
116                                                 size_t in_length)
117 {
118         struct tevent_req *req;
119         struct dcerpc_binding_handle_raw_call_state *state;
120         struct tevent_req *subreq;
121
122         req = tevent_req_create(mem_ctx, &state,
123                                 struct dcerpc_binding_handle_raw_call_state);
124         if (req == NULL) {
125                 return NULL;
126         }
127         state->ops = h->ops;
128         state->out_data = NULL;
129         state->out_length = 0;
130         state->out_flags = 0;
131
132         subreq = state->ops->raw_call_send(state, ev, h,
133                                            object, opnum,
134                                            in_flags, in_data, in_length);
135         if (tevent_req_nomem(subreq, req)) {
136                 return tevent_req_post(req, ev);
137         }
138         tevent_req_set_callback(subreq, dcerpc_binding_handle_raw_call_done, req);
139
140         return req;
141 }
142
143 static void dcerpc_binding_handle_raw_call_done(struct tevent_req *subreq)
144 {
145         struct tevent_req *req = tevent_req_callback_data(subreq,
146                                  struct tevent_req);
147         struct dcerpc_binding_handle_raw_call_state *state =
148                 tevent_req_data(req,
149                 struct dcerpc_binding_handle_raw_call_state);
150         NTSTATUS error;
151
152         error = state->ops->raw_call_recv(subreq, state,
153                                           &state->out_data,
154                                           &state->out_length,
155                                           &state->out_flags);
156         TALLOC_FREE(subreq);
157         if (!NT_STATUS_IS_OK(error)) {
158                 tevent_req_nterror(req, error);
159                 return;
160         }
161
162         tevent_req_done(req);
163 }
164
165 NTSTATUS dcerpc_binding_handle_raw_call_recv(struct tevent_req *req,
166                                              TALLOC_CTX *mem_ctx,
167                                              uint8_t **out_data,
168                                              size_t *out_length,
169                                              uint32_t *out_flags)
170 {
171         struct dcerpc_binding_handle_raw_call_state *state =
172                 tevent_req_data(req,
173                 struct dcerpc_binding_handle_raw_call_state);
174         NTSTATUS error;
175
176         if (tevent_req_is_nterror(req, &error)) {
177                 tevent_req_received(req);
178                 return error;
179         }
180
181         *out_data = talloc_move(mem_ctx, &state->out_data);
182         *out_length = state->out_length;
183         *out_flags = state->out_flags;
184         tevent_req_received(req);
185         return NT_STATUS_OK;
186 }
187
188 struct dcerpc_binding_handle_disconnect_state {
189         const struct dcerpc_binding_handle_ops *ops;
190 };
191
192 static void dcerpc_binding_handle_disconnect_done(struct tevent_req *subreq);
193
194 struct tevent_req *dcerpc_binding_handle_disconnect_send(TALLOC_CTX *mem_ctx,
195                                                 struct tevent_context *ev,
196                                                 struct dcerpc_binding_handle *h)
197 {
198         struct tevent_req *req;
199         struct dcerpc_binding_handle_disconnect_state *state;
200         struct tevent_req *subreq;
201
202         req = tevent_req_create(mem_ctx, &state,
203                                 struct dcerpc_binding_handle_disconnect_state);
204         if (req == NULL) {
205                 return NULL;
206         }
207
208         state->ops = h->ops;
209
210         subreq = state->ops->disconnect_send(state, ev, h);
211         if (tevent_req_nomem(subreq, req)) {
212                 return tevent_req_post(req, ev);
213         }
214         tevent_req_set_callback(subreq, dcerpc_binding_handle_disconnect_done, req);
215
216         return req;
217 }
218
219 static void dcerpc_binding_handle_disconnect_done(struct tevent_req *subreq)
220 {
221         struct tevent_req *req = tevent_req_callback_data(subreq,
222                                  struct tevent_req);
223         struct dcerpc_binding_handle_disconnect_state *state =
224                 tevent_req_data(req,
225                 struct dcerpc_binding_handle_disconnect_state);
226         NTSTATUS error;
227
228         error = state->ops->disconnect_recv(subreq);
229         TALLOC_FREE(subreq);
230         if (!NT_STATUS_IS_OK(error)) {
231                 tevent_req_nterror(req, error);
232                 return;
233         }
234
235         tevent_req_done(req);
236 }
237
238 NTSTATUS dcerpc_binding_handle_disconnect_recv(struct tevent_req *req)
239 {
240         NTSTATUS error;
241
242         if (tevent_req_is_nterror(req, &error)) {
243                 tevent_req_received(req);
244                 return error;
245         }
246
247         tevent_req_received(req);
248         return NT_STATUS_OK;
249 }
250
251 struct dcerpc_binding_handle_call_state {
252         struct dcerpc_binding_handle *h;
253         const struct ndr_interface_call *call;
254         TALLOC_CTX *r_mem;
255         void *r_ptr;
256         struct ndr_push *push;
257         DATA_BLOB request;
258         DATA_BLOB response;
259         struct ndr_pull *pull;
260 };
261
262 static void dcerpc_binding_handle_call_done(struct tevent_req *subreq);
263
264 struct tevent_req *dcerpc_binding_handle_call_send(TALLOC_CTX *mem_ctx,
265                                         struct tevent_context *ev,
266                                         struct dcerpc_binding_handle *h,
267                                         const struct GUID *object,
268                                         const struct ndr_interface_table *table,
269                                         uint32_t opnum,
270                                         TALLOC_CTX *r_mem,
271                                         void *r_ptr)
272 {
273         struct tevent_req *req;
274         struct dcerpc_binding_handle_call_state *state;
275         struct tevent_req *subreq;
276         enum ndr_err_code ndr_err;
277
278         req = tevent_req_create(mem_ctx, &state,
279                                 struct dcerpc_binding_handle_call_state);
280         if (req == NULL) {
281                 return NULL;
282         }
283
284 #if 0 /* TODO: activate this when the callers are fixed */
285         if (table != h->table) {
286                 tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
287                 return tevent_req_post(req, ev);
288         }
289 #endif
290
291         if (opnum >= table->num_calls) {
292                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
293                 return tevent_req_post(req, ev);
294         }
295
296         state->h = h;
297         state->call = &table->calls[opnum];
298
299         state->r_mem = r_mem;
300         state->r_ptr = r_ptr;
301
302         /* setup for a ndr_push_* call */
303         state->push = ndr_push_init_ctx(state);
304         if (tevent_req_nomem(state->push, req)) {
305                 return tevent_req_post(req, ev);
306         }
307
308         if (h->ops->ref_alloc && h->ops->ref_alloc(h)) {
309                 state->push->flags |= LIBNDR_FLAG_REF_ALLOC;
310         }
311
312         if (h->ops->push_bigendian && h->ops->push_bigendian(h)) {
313                 state->push->flags |= LIBNDR_FLAG_BIGENDIAN;
314         }
315
316         if (h->ops->use_ndr64 && h->ops->use_ndr64(h)) {
317                 state->push->flags |= LIBNDR_FLAG_NDR64;
318         }
319
320         if (h->ops->do_ndr_print) {
321                 h->ops->do_ndr_print(h, NDR_IN | NDR_SET_VALUES,
322                                      state->r_ptr, state->call);
323         }
324
325         /* push the structure into a blob */
326         ndr_err = state->call->ndr_push(state->push, NDR_IN, state->r_ptr);
327         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
328                 NTSTATUS error;
329                 error = ndr_map_error2ntstatus(ndr_err);
330                 if (h->ops->ndr_push_failed) {
331                         h->ops->ndr_push_failed(h, error,
332                                                 state->r_ptr,
333                                                 state->call);
334                 }
335                 tevent_req_nterror(req, error);
336                 return tevent_req_post(req, ev);
337         }
338
339         /* retrieve the blob */
340         state->request = ndr_push_blob(state->push);
341
342         if (h->ops->ndr_validate_in) {
343                 NTSTATUS error;
344                 error = h->ops->ndr_validate_in(h, state,
345                                                 &state->request,
346                                                 state->call);
347                 if (!NT_STATUS_IS_OK(error)) {
348                         tevent_req_nterror(req, error);
349                         return tevent_req_post(req, ev);
350                 }
351         }
352
353         subreq = dcerpc_binding_handle_raw_call_send(state, ev,
354                                                      h, object, opnum,
355                                                      state->push->flags,
356                                                      state->request.data,
357                                                      state->request.length);
358         if (tevent_req_nomem(subreq, req)) {
359                 return tevent_req_post(req, ev);
360         }
361         tevent_req_set_callback(subreq, dcerpc_binding_handle_call_done, req);
362
363         return req;
364 }
365
366 static void dcerpc_binding_handle_call_done(struct tevent_req *subreq)
367 {
368         struct tevent_req *req = tevent_req_callback_data(subreq,
369                                  struct tevent_req);
370         struct dcerpc_binding_handle_call_state *state =
371                 tevent_req_data(req,
372                 struct dcerpc_binding_handle_call_state);
373         struct dcerpc_binding_handle *h = state->h;
374         NTSTATUS error;
375         uint32_t out_flags = 0;
376         enum ndr_err_code ndr_err;
377
378         error = dcerpc_binding_handle_raw_call_recv(subreq, state,
379                                                     &state->response.data,
380                                                     &state->response.length,
381                                                     &out_flags);
382         TALLOC_FREE(subreq);
383         if (!NT_STATUS_IS_OK(error)) {
384                 tevent_req_nterror(req, error);
385                 return;
386         }
387
388         state->pull = ndr_pull_init_blob(&state->response, state);
389         if (tevent_req_nomem(state->pull, req)) {
390                 return;
391         }
392         state->pull->flags = state->push->flags;
393
394         if (out_flags & LIBNDR_FLAG_BIGENDIAN) {
395                 state->pull->flags |= LIBNDR_FLAG_BIGENDIAN;
396         } else {
397                 state->pull->flags &= ~LIBNDR_FLAG_BIGENDIAN;
398         }
399
400         state->pull->current_mem_ctx = state->r_mem;
401
402         /* pull the structure from the blob */
403         ndr_err = state->call->ndr_pull(state->pull, NDR_OUT, state->r_ptr);
404         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
405                 error = ndr_map_error2ntstatus(ndr_err);
406                 if (h->ops->ndr_pull_failed) {
407                         h->ops->ndr_pull_failed(h, error,
408                                                 &state->response,
409                                                 state->call);
410                 }
411                 tevent_req_nterror(req, error);
412                 return;
413         }
414
415         if (h->ops->do_ndr_print) {
416                 h->ops->do_ndr_print(h, NDR_OUT,
417                                      state->r_ptr, state->call);
418         }
419
420         if (h->ops->ndr_validate_out) {
421                 error = h->ops->ndr_validate_out(h,
422                                                  state->pull,
423                                                  state->r_ptr,
424                                                  state->call);
425                 if (!NT_STATUS_IS_OK(error)) {
426                         tevent_req_nterror(req, error);
427                         return;
428                 }
429         }
430
431         tevent_req_done(req);
432 }
433
434 NTSTATUS dcerpc_binding_handle_call_recv(struct tevent_req *req)
435 {
436         NTSTATUS error;
437
438         if (tevent_req_is_nterror(req, &error)) {
439                 tevent_req_received(req);
440                 return error;
441         }
442
443         tevent_req_received(req);
444         return NT_STATUS_OK;
445 }
446
447 NTSTATUS dcerpc_binding_handle_call(struct dcerpc_binding_handle *h,
448                                     const struct GUID *object,
449                                     const struct ndr_interface_table *table,
450                                     uint32_t opnum,
451                                     TALLOC_CTX *r_mem,
452                                     void *r_ptr)
453 {
454         TALLOC_CTX *frame = talloc_stackframe();
455         struct tevent_context *ev;
456         struct tevent_req *subreq;
457         NTSTATUS status;
458
459         /*
460          * TODO: allow only one sync call
461          */
462
463         if (h->sync_ev) {
464                 ev = h->sync_ev;
465         } else {
466                 ev = tevent_context_init(frame);
467         }
468         if (ev == NULL) {
469                 talloc_free(frame);
470                 return NT_STATUS_NO_MEMORY;
471         }
472
473         subreq = dcerpc_binding_handle_call_send(frame, ev,
474                                                  h, object, table,
475                                                  opnum, r_mem, r_ptr);
476         if (subreq == NULL) {
477                 talloc_free(frame);
478                 return NT_STATUS_NO_MEMORY;
479         }
480
481         if (!tevent_req_poll(subreq, ev)) {
482                 status = map_nt_error_from_unix(errno);
483                 talloc_free(frame);
484                 return status;
485         }
486
487         status = dcerpc_binding_handle_call_recv(subreq);
488         if (!NT_STATUS_IS_OK(status)) {
489                 talloc_free(frame);
490                 return status;
491         }
492
493         TALLOC_FREE(frame);
494         return NT_STATUS_OK;
495 }