s4-ldb_modules/acl: Get correct NTDSDSA objectGUID to check SPN for
[Samba.git] / librpc / rpc / binding_handle.c
blob93c0fd4f00eadc57fb975714a68c6875f3518867
1 /*
2 Unix SMB/CIFS implementation.
4 dcerpc binding handle functions
6 Copyright (C) Stefan Metzmacher 2010
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.
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.
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/>.
22 #include "includes.h"
23 #include <tevent.h>
24 #include "../lib/util/tevent_ntstatus.h"
25 #include "librpc/rpc/dcerpc.h"
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;
36 static int dcerpc_binding_handle_destructor(struct dcerpc_binding_handle *b)
38 return 0;
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)
50 struct dcerpc_binding_handle *h;
51 void **ppstate = (void **)pstate;
52 void *state;
54 h = talloc_zero(mem_ctx, struct dcerpc_binding_handle);
55 if (h == NULL) {
56 return NULL;
58 h->ops = ops;
59 h->location = location;
60 h->object = object;
61 h->table = table;
63 state = talloc_zero_size(h, psize);
64 if (state == NULL) {
65 talloc_free(h);
66 return NULL;
68 talloc_set_name_const(state, type);
70 h->private_data = state;
72 talloc_set_destructor(h, dcerpc_binding_handle_destructor);
74 *ppstate = state;
75 return h;
78 void *_dcerpc_binding_handle_data(struct dcerpc_binding_handle *h)
80 return h->private_data;
83 void dcerpc_binding_handle_set_sync_ev(struct dcerpc_binding_handle *h,
84 struct tevent_context *ev)
86 h->sync_ev = ev;
89 bool dcerpc_binding_handle_is_connected(struct dcerpc_binding_handle *h)
91 return h->ops->is_connected(h);
94 uint32_t dcerpc_binding_handle_set_timeout(struct dcerpc_binding_handle *h,
95 uint32_t timeout)
97 return h->ops->set_timeout(h, timeout);
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;
107 static void dcerpc_binding_handle_raw_call_done(struct tevent_req *subreq);
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)
118 struct tevent_req *req;
119 struct dcerpc_binding_handle_raw_call_state *state;
120 struct tevent_req *subreq;
122 req = tevent_req_create(mem_ctx, &state,
123 struct dcerpc_binding_handle_raw_call_state);
124 if (req == NULL) {
125 return NULL;
127 state->ops = h->ops;
128 state->out_data = NULL;
129 state->out_length = 0;
130 state->out_flags = 0;
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);
138 tevent_req_set_callback(subreq, dcerpc_binding_handle_raw_call_done, req);
140 return req;
143 static void dcerpc_binding_handle_raw_call_done(struct tevent_req *subreq)
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;
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;
162 tevent_req_done(req);
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)
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;
176 if (tevent_req_is_nterror(req, &error)) {
177 tevent_req_received(req);
178 return error;
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;
188 struct dcerpc_binding_handle_disconnect_state {
189 const struct dcerpc_binding_handle_ops *ops;
192 static void dcerpc_binding_handle_disconnect_done(struct tevent_req *subreq);
194 struct tevent_req *dcerpc_binding_handle_disconnect_send(TALLOC_CTX *mem_ctx,
195 struct tevent_context *ev,
196 struct dcerpc_binding_handle *h)
198 struct tevent_req *req;
199 struct dcerpc_binding_handle_disconnect_state *state;
200 struct tevent_req *subreq;
202 req = tevent_req_create(mem_ctx, &state,
203 struct dcerpc_binding_handle_disconnect_state);
204 if (req == NULL) {
205 return NULL;
208 state->ops = h->ops;
210 subreq = state->ops->disconnect_send(state, ev, h);
211 if (tevent_req_nomem(subreq, req)) {
212 return tevent_req_post(req, ev);
214 tevent_req_set_callback(subreq, dcerpc_binding_handle_disconnect_done, req);
216 return req;
219 static void dcerpc_binding_handle_disconnect_done(struct tevent_req *subreq)
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;
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;
235 tevent_req_done(req);
238 NTSTATUS dcerpc_binding_handle_disconnect_recv(struct tevent_req *req)
240 NTSTATUS error;
242 if (tevent_req_is_nterror(req, &error)) {
243 tevent_req_received(req);
244 return error;
247 tevent_req_received(req);
248 return NT_STATUS_OK;
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;
262 static void dcerpc_binding_handle_call_done(struct tevent_req *subreq);
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)
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;
278 req = tevent_req_create(mem_ctx, &state,
279 struct dcerpc_binding_handle_call_state);
280 if (req == NULL) {
281 return NULL;
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);
289 #endif
291 if (opnum >= table->num_calls) {
292 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
293 return tevent_req_post(req, ev);
296 state->h = h;
297 state->call = &table->calls[opnum];
299 state->r_mem = r_mem;
300 state->r_ptr = r_ptr;
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);
308 if (h->ops->ref_alloc && h->ops->ref_alloc(h)) {
309 state->push->flags |= LIBNDR_FLAG_REF_ALLOC;
312 if (h->ops->push_bigendian && h->ops->push_bigendian(h)) {
313 state->push->flags |= LIBNDR_FLAG_BIGENDIAN;
316 if (h->ops->use_ndr64 && h->ops->use_ndr64(h)) {
317 state->push->flags |= LIBNDR_FLAG_NDR64;
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);
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);
335 tevent_req_nterror(req, error);
336 return tevent_req_post(req, ev);
339 /* retrieve the blob */
340 state->request = ndr_push_blob(state->push);
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);
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);
361 tevent_req_set_callback(subreq, dcerpc_binding_handle_call_done, req);
363 return req;
366 static void dcerpc_binding_handle_call_done(struct tevent_req *subreq)
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;
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;
388 state->pull = ndr_pull_init_blob(&state->response, state);
389 if (tevent_req_nomem(state->pull, req)) {
390 return;
392 state->pull->flags = state->push->flags;
394 if (out_flags & LIBNDR_FLAG_BIGENDIAN) {
395 state->pull->flags |= LIBNDR_FLAG_BIGENDIAN;
396 } else {
397 state->pull->flags &= ~LIBNDR_FLAG_BIGENDIAN;
400 state->pull->current_mem_ctx = state->r_mem;
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);
411 tevent_req_nterror(req, error);
412 return;
415 if (h->ops->do_ndr_print) {
416 h->ops->do_ndr_print(h, NDR_OUT,
417 state->r_ptr, state->call);
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;
431 tevent_req_done(req);
434 NTSTATUS dcerpc_binding_handle_call_recv(struct tevent_req *req)
436 NTSTATUS error;
438 if (tevent_req_is_nterror(req, &error)) {
439 tevent_req_received(req);
440 return error;
443 tevent_req_received(req);
444 return NT_STATUS_OK;
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)
454 TALLOC_CTX *frame = talloc_stackframe();
455 struct tevent_context *ev;
456 struct tevent_req *subreq;
457 NTSTATUS status;
460 * TODO: allow only one sync call
463 if (h->sync_ev) {
464 ev = h->sync_ev;
465 } else {
466 ev = tevent_context_init(frame);
468 if (ev == NULL) {
469 talloc_free(frame);
470 return NT_STATUS_NO_MEMORY;
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;
481 if (!tevent_req_poll(subreq, ev)) {
482 status = map_nt_error_from_unix(errno);
483 talloc_free(frame);
484 return status;
487 status = dcerpc_binding_handle_call_recv(subreq);
488 if (!NT_STATUS_IS_OK(status)) {
489 talloc_free(frame);
490 return status;
493 TALLOC_FREE(frame);
494 return NT_STATUS_OK;