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