29
29
#include "includes.h"
30
30
#include "winbindd/winbindd.h"
31
31
#include "winbindd/winbindd_proto.h"
32
33
#include "librpc/gen_ndr/srv_wbint.h"
34
struct wb_ndr_transport_priv {
35
struct wbint_bh_state {
35
36
struct winbindd_domain *domain;
36
37
struct winbindd_child *child;
39
struct wb_ndr_dispatch_state {
40
struct wb_ndr_transport_priv *transport;
40
static bool wbint_bh_is_connected(struct dcerpc_binding_handle *h)
42
struct wbint_bh_state *hs = dcerpc_binding_handle_data(h,
43
struct wbint_bh_state);
52
static uint32_t wbint_bh_set_timeout(struct dcerpc_binding_handle *h,
55
/* TODO: implement timeouts */
59
struct wbint_bh_raw_call_state {
60
struct winbindd_domain *domain;
42
const struct ndr_interface_call *call;
44
DATA_BLOB req_blob, resp_blob;
45
63
struct winbindd_request request;
46
64
struct winbindd_response *response;
49
static void wb_ndr_dispatch_done(struct tevent_req *subreq);
68
static void wbint_bh_raw_call_done(struct tevent_req *subreq);
51
static struct tevent_req *wb_ndr_dispatch_send(TALLOC_CTX *mem_ctx,
52
struct tevent_context *ev,
53
struct rpc_pipe_client *cli,
54
const struct ndr_interface_table *table,
70
static struct tevent_req *wbint_bh_raw_call_send(TALLOC_CTX *mem_ctx,
71
struct tevent_context *ev,
72
struct dcerpc_binding_handle *h,
73
const struct GUID *object,
76
const uint8_t *in_data,
58
struct tevent_req *req, *subreq;
59
struct wb_ndr_dispatch_state *state;
60
struct wb_ndr_transport_priv *transport = talloc_get_type_abort(
61
cli->transport->priv, struct wb_ndr_transport_priv);
62
struct ndr_push *push;
63
enum ndr_err_code ndr_err;
79
struct wbint_bh_state *hs =
80
dcerpc_binding_handle_data(h,
81
struct wbint_bh_state);
82
struct tevent_req *req;
83
struct wbint_bh_raw_call_state *state;
85
struct tevent_req *subreq;
65
87
req = tevent_req_create(mem_ctx, &state,
66
struct wb_ndr_dispatch_state);
88
struct wbint_bh_raw_call_state);
72
state->call = &table->calls[opnum];
73
state->transport = transport;
92
state->domain = hs->domain;
74
93
state->opnum = opnum;
76
push = ndr_push_init_ctx(state, NULL);
77
if (tevent_req_nomem(push, req)) {
78
return tevent_req_post(req, ev);
81
ndr_err = state->call->ndr_push(push, NDR_IN, r);
82
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
83
tevent_req_nterror(req, ndr_map_error2ntstatus(ndr_err));
85
return tevent_req_post(req, ev);
88
state->req_blob = ndr_push_blob(push);
90
if ((transport->domain != NULL)
91
&& wcache_fetch_ndr(state, transport->domain, opnum,
92
&state->req_blob, &state->resp_blob)) {
94
state->in_data.data = discard_const_p(uint8_t, in_data);
95
state->in_data.length = in_length;
97
ok = wbint_bh_is_connected(h);
99
tevent_req_nterror(req, NT_STATUS_INVALID_CONNECTION);
100
return tevent_req_post(req, ev);
103
if ((state->domain != NULL)
104
&& wcache_fetch_ndr(state, state->domain, state->opnum,
105
&state->in_data, &state->out_data)) {
93
106
tevent_req_done(req);
94
107
return tevent_req_post(req, ev);
97
110
state->request.cmd = WINBINDD_DUAL_NDRCMD;
98
state->request.data.ndrcmd = opnum;
99
state->request.extra_data.data = (char *)state->req_blob.data;
100
state->request.extra_len = state->req_blob.length;
111
state->request.data.ndrcmd = state->opnum;
112
state->request.extra_data.data = (char *)state->in_data.data;
113
state->request.extra_len = state->in_data.length;
102
subreq = wb_child_request_send(state, ev, transport->child,
115
subreq = wb_child_request_send(state, ev, hs->child,
103
116
&state->request);
104
117
if (tevent_req_nomem(subreq, req)) {
105
118
return tevent_req_post(req, ev);
107
tevent_req_set_callback(subreq, wb_ndr_dispatch_done, req);
120
tevent_req_set_callback(subreq, wbint_bh_raw_call_done, req);
111
static void wb_ndr_dispatch_done(struct tevent_req *subreq)
125
static void wbint_bh_raw_call_done(struct tevent_req *subreq)
113
struct tevent_req *req = tevent_req_callback_data(
114
subreq, struct tevent_req);
115
struct wb_ndr_dispatch_state *state = tevent_req_data(
116
req, struct wb_ndr_dispatch_state);
127
struct tevent_req *req =
128
tevent_req_callback_data(subreq,
130
struct wbint_bh_raw_call_state *state =
132
struct wbint_bh_raw_call_state);
119
135
ret = wb_child_request_recv(subreq, state, &state->response, &err);
120
136
TALLOC_FREE(subreq);
122
tevent_req_nterror(req, map_nt_error_from_unix(err));
138
NTSTATUS status = map_nt_error_from_unix(err);
139
tevent_req_nterror(req, status);
126
state->resp_blob = data_blob_const(
143
state->out_data = data_blob_talloc(state,
127
144
state->response->extra_data.data,
128
state->response->length - sizeof(struct winbindd_response));
145
state->response->length - sizeof(struct winbindd_response));
146
if (state->response->extra_data.data && !state->out_data.data) {
147
tevent_req_nomem(NULL, req);
130
if (state->transport->domain != NULL) {
131
wcache_store_ndr(state->transport->domain, state->opnum,
132
&state->req_blob, &state->resp_blob);
151
if (state->domain != NULL) {
152
wcache_store_ndr(state->domain, state->opnum,
153
&state->in_data, &state->out_data);
135
156
tevent_req_done(req);
138
static NTSTATUS wb_ndr_dispatch_recv(struct tevent_req *req,
159
static NTSTATUS wbint_bh_raw_call_recv(struct tevent_req *req,
141
struct wb_ndr_dispatch_state *state = tevent_req_data(
142
req, struct wb_ndr_dispatch_state);
165
struct wbint_bh_raw_call_state *state =
167
struct wbint_bh_raw_call_state);
144
struct ndr_pull *pull;
145
enum ndr_err_code ndr_err;
147
170
if (tevent_req_is_nterror(req, &status)) {
171
tevent_req_received(req);
151
pull = ndr_pull_init_blob(&state->resp_blob, mem_ctx, NULL);
153
return NT_STATUS_NO_MEMORY;
156
/* have the ndr parser alloc memory for us */
157
pull->flags |= LIBNDR_FLAG_REF_ALLOC;
158
ndr_err = state->call->ndr_pull(pull, NDR_OUT, state->r);
161
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
162
return ndr_map_error2ntstatus(ndr_err);
175
*out_data = talloc_move(mem_ctx, &state->out_data.data);
176
*out_length = state->out_data.length;
178
tevent_req_received(req);
165
179
return NT_STATUS_OK;
168
static NTSTATUS wb_ndr_dispatch(struct rpc_pipe_client *cli,
170
const struct ndr_interface_table *table,
171
uint32_t opnum, void *r)
182
struct wbint_bh_disconnect_state {
186
static struct tevent_req *wbint_bh_disconnect_send(TALLOC_CTX *mem_ctx,
187
struct tevent_context *ev,
188
struct dcerpc_binding_handle *h)
173
TALLOC_CTX *frame = talloc_stackframe();
174
struct event_context *ev;
190
struct wbint_bh_state *hs = dcerpc_binding_handle_data(h,
191
struct wbint_bh_state);
175
192
struct tevent_req *req;
176
NTSTATUS status = NT_STATUS_OK;
178
ev = event_context_init(frame);
180
status = NT_STATUS_NO_MEMORY;
184
req = wb_ndr_dispatch_send(frame, ev, cli, table, opnum, r);
193
struct wbint_bh_disconnect_state *state;
196
req = tevent_req_create(mem_ctx, &state,
197
struct wbint_bh_disconnect_state);
185
198
if (req == NULL) {
186
status = NT_STATUS_NO_MEMORY;
190
if (!tevent_req_poll(req, ev)) {
191
status = map_nt_error_from_unix(errno);
195
status = wb_ndr_dispatch_recv(req, mem_ctx);
201
struct rpc_pipe_client *wbint_rpccli_create(TALLOC_CTX *mem_ctx,
202
struct winbindd_domain *domain,
203
struct winbindd_child *child)
205
struct rpc_pipe_client *result;
206
struct wb_ndr_transport_priv *transp;
208
result = talloc(mem_ctx, struct rpc_pipe_client);
209
if (result == NULL) {
212
result->abstract_syntax = ndr_table_wbint.syntax_id;
213
result->transfer_syntax = ndr_transfer_syntax;
214
result->dispatch = wb_ndr_dispatch;
215
result->dispatch_send = wb_ndr_dispatch_send;
216
result->dispatch_recv = wb_ndr_dispatch_recv;
217
result->max_xmit_frag = RPC_MAX_PDU_FRAG_LEN;
218
result->max_recv_frag = RPC_MAX_PDU_FRAG_LEN;
219
result->desthost = NULL;
220
result->srv_name_slash = NULL;
202
ok = wbint_bh_is_connected(h);
204
tevent_req_nterror(req, NT_STATUS_INVALID_CONNECTION);
205
return tevent_req_post(req, ev);
223
* Initialize a fake transport. Due to our own wb_ndr_dispatch
224
* function we don't use all the fragmentation engine in
225
* cli_pipe, which would use all the _read and _write
226
* functions in rpc_cli_transport. But we need a place to
227
* store the child struct in, and we're re-using
228
* result->transport->priv for that.
209
* TODO: do a real async disconnect ...
211
* For now the caller needs to free rpc_cli
231
result->transport = talloc_zero(result, struct rpc_cli_transport);
232
if (result->transport == NULL) {
236
transp = talloc(result->transport, struct wb_ndr_transport_priv);
237
if (transp == NULL) {
241
transp->domain = domain;
242
transp->child = child;
243
result->transport->priv = transp;
215
tevent_req_done(req);
216
return tevent_req_post(req, ev);
219
static NTSTATUS wbint_bh_disconnect_recv(struct tevent_req *req)
223
if (tevent_req_is_nterror(req, &status)) {
224
tevent_req_received(req);
228
tevent_req_received(req);
232
static bool wbint_bh_ref_alloc(struct dcerpc_binding_handle *h)
237
static void wbint_bh_do_ndr_print(struct dcerpc_binding_handle *h,
239
const void *_struct_ptr,
240
const struct ndr_interface_call *call)
242
void *struct_ptr = discard_const(_struct_ptr);
244
if (DEBUGLEVEL < 10) {
248
if (ndr_flags & NDR_IN) {
249
ndr_print_function_debug(call->ndr_print,
254
if (ndr_flags & NDR_OUT) {
255
ndr_print_function_debug(call->ndr_print,
262
static const struct dcerpc_binding_handle_ops wbint_bh_ops = {
264
.is_connected = wbint_bh_is_connected,
265
.set_timeout = wbint_bh_set_timeout,
266
.raw_call_send = wbint_bh_raw_call_send,
267
.raw_call_recv = wbint_bh_raw_call_recv,
268
.disconnect_send = wbint_bh_disconnect_send,
269
.disconnect_recv = wbint_bh_disconnect_recv,
271
.ref_alloc = wbint_bh_ref_alloc,
272
.do_ndr_print = wbint_bh_do_ndr_print,
275
/* initialise a wbint binding handle */
276
struct dcerpc_binding_handle *wbint_binding_handle(TALLOC_CTX *mem_ctx,
277
struct winbindd_domain *domain,
278
struct winbindd_child *child)
280
struct dcerpc_binding_handle *h;
281
struct wbint_bh_state *hs;
283
h = dcerpc_binding_handle_create(mem_ctx,
288
struct wbint_bh_state,
247
299
enum winbindd_result winbindd_dual_ndrcmd(struct winbindd_domain *domain,
248
300
struct winbindd_cli_state *state)
302
struct pipes_struct p;
251
303
struct api_struct *fns;