~ubuntu-branches/ubuntu/vivid/samba/vivid

« back to all changes in this revision

Viewing changes to source3/winbindd/winbindd_dual_ndr.c

  • Committer: Package Import Robot
  • Author(s): Chuck Short
  • Date: 2011-12-21 13:18:04 UTC
  • mfrom: (0.39.21 sid)
  • Revision ID: package-import@ubuntu.com-20111221131804-xtlr39wx6njehxxr
Tags: 2:3.6.1-3ubuntu1
* Merge from Debian testing.  Remaining changes:
  + debian/patches/VERSION.patch:
    - set SAMBA_VERSION_SUFFIX to Ubuntu.
  + debian/patches/error-trans.fix-276472:
    - Add the translation of Unix Error code -ENOTSUP to NT Error Code
    - NT_STATUS_NOT_SUPPORTED to prevent the Permission denied error.
  + debian/smb.conf:
    - add "(Samba, Ubuntu)" to server string.
    - comment out the default [homes] share, and add a comment about
      "valid users = %S" to show users how to restrict access to
      \\server\username to only username.
    - Set 'usershare allow guests', so that usershare admins are 
      allowed to create public shares in addition to authenticated
      ones.
    - add map to guest = Bad user, maps bad username to guest access.
  + debian/samba-common.config:
    - Do not change priority to high if dhclient3 is installed.
    - Use priority medium instead of high for the workgroup question.
  + debian/control:
    - Don't build against or suggest ctdb.
    - Add dependency on samba-common-bin to samba.
  + Add ufw integration:
    - Created debian/samba.ufw.profile
    - debian/rules, debian/samba.dirs, debian/samba.files: install
      profile
    - debian/control: have samba suggest ufw
  + Add apport hook:
    - Created debian/source_samba.py.
    - debian/rules, debian/samba.dirs, debian/samba-common-bin.files: install
  + Switch to upstart:
    - Add debian/samba.{nmbd,smbd}.upstart.
  + debian/samba.logrotate, debian/samba-common.dhcp, debian/samba.if-up:
    - Make them upstart compatible
  + debian/samba.postinst: 
    - Avoid scary pdbedit warnings on first import.
  + debian/samba-common.postinst: Add more informative error message for
    the case where smb.conf was manually deleted
  + debian/patches/fix-debuglevel-name-conflict.patch: don't use 'debug_level'
    as a global variable name in an NSS module 
  + Dropped:
    - debian/patches/error-trans.fix-276472
    - debian/patches/fix-debuglevel-name-conflict.patch

Show diffs side-by-side

added added

removed removed

Lines of Context:
29
29
#include "includes.h"
30
30
#include "winbindd/winbindd.h"
31
31
#include "winbindd/winbindd_proto.h"
 
32
#include "ntdomain.h"
32
33
#include "librpc/gen_ndr/srv_wbint.h"
33
34
 
34
 
struct wb_ndr_transport_priv {
 
35
struct wbint_bh_state {
35
36
        struct winbindd_domain *domain;
36
37
        struct winbindd_child *child;
37
38
};
38
39
 
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)
 
41
{
 
42
        struct wbint_bh_state *hs = dcerpc_binding_handle_data(h,
 
43
                                     struct wbint_bh_state);
 
44
 
 
45
        if (!hs->child) {
 
46
                return false;
 
47
        }
 
48
 
 
49
        return true;
 
50
}
 
51
 
 
52
static uint32_t wbint_bh_set_timeout(struct dcerpc_binding_handle *h,
 
53
                                     uint32_t timeout)
 
54
{
 
55
        /* TODO: implement timeouts */
 
56
        return UINT32_MAX;
 
57
}
 
58
 
 
59
struct wbint_bh_raw_call_state {
 
60
        struct winbindd_domain *domain;
41
61
        uint32_t opnum;
42
 
        const struct ndr_interface_call *call;
43
 
        void *r;
44
 
        DATA_BLOB req_blob, resp_blob;
 
62
        DATA_BLOB in_data;
45
63
        struct winbindd_request request;
46
64
        struct winbindd_response *response;
 
65
        DATA_BLOB out_data;
47
66
};
48
67
 
49
 
static void wb_ndr_dispatch_done(struct tevent_req *subreq);
 
68
static void wbint_bh_raw_call_done(struct tevent_req *subreq);
50
69
 
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,
55
 
                                               uint32_t opnum,
56
 
                                               void *r)
 
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,
 
74
                                                  uint32_t opnum,
 
75
                                                  uint32_t in_flags,
 
76
                                                  const uint8_t *in_data,
 
77
                                                  size_t in_length)
57
78
{
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;
 
84
        bool ok;
 
85
        struct tevent_req *subreq;
64
86
 
65
87
        req = tevent_req_create(mem_ctx, &state,
66
 
                                struct wb_ndr_dispatch_state);
 
88
                                struct wbint_bh_raw_call_state);
67
89
        if (req == NULL) {
68
90
                return NULL;
69
91
        }
70
 
 
71
 
        state->r = r;
72
 
        state->call = &table->calls[opnum];
73
 
        state->transport = transport;
 
92
        state->domain = hs->domain;
74
93
        state->opnum = opnum;
75
 
 
76
 
        push = ndr_push_init_ctx(state, NULL);
77
 
        if (tevent_req_nomem(push, req)) {
78
 
                return tevent_req_post(req, ev);
79
 
        }
80
 
 
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));
84
 
                TALLOC_FREE(push);
85
 
                return tevent_req_post(req, ev);
86
 
        }
87
 
 
88
 
        state->req_blob = ndr_push_blob(push);
89
 
 
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;
 
96
 
 
97
        ok = wbint_bh_is_connected(h);
 
98
        if (!ok) {
 
99
                tevent_req_nterror(req, NT_STATUS_INVALID_CONNECTION);
 
100
                return tevent_req_post(req, ev);
 
101
        }
 
102
 
 
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);
95
108
        }
96
109
 
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;
101
114
 
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);
106
119
        }
107
 
        tevent_req_set_callback(subreq, wb_ndr_dispatch_done, req);
 
120
        tevent_req_set_callback(subreq, wbint_bh_raw_call_done, req);
 
121
 
108
122
        return req;
109
123
}
110
124
 
111
 
static void wb_ndr_dispatch_done(struct tevent_req *subreq)
 
125
static void wbint_bh_raw_call_done(struct tevent_req *subreq)
112
126
{
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,
 
129
                struct tevent_req);
 
130
        struct wbint_bh_raw_call_state *state =
 
131
                tevent_req_data(req,
 
132
                struct wbint_bh_raw_call_state);
117
133
        int ret, err;
118
134
 
119
135
        ret = wb_child_request_recv(subreq, state, &state->response, &err);
120
136
        TALLOC_FREE(subreq);
121
137
        if (ret == -1) {
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);
123
140
                return;
124
141
        }
125
142
 
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);
 
148
                return;
 
149
        }
129
150
 
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);
133
154
        }
134
155
 
135
156
        tevent_req_done(req);
136
157
}
137
158
 
138
 
static NTSTATUS wb_ndr_dispatch_recv(struct tevent_req *req,
139
 
                                     TALLOC_CTX *mem_ctx)
 
159
static NTSTATUS wbint_bh_raw_call_recv(struct tevent_req *req,
 
160
                                        TALLOC_CTX *mem_ctx,
 
161
                                        uint8_t **out_data,
 
162
                                        size_t *out_length,
 
163
                                        uint32_t *out_flags)
140
164
{
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 =
 
166
                tevent_req_data(req,
 
167
                struct wbint_bh_raw_call_state);
143
168
        NTSTATUS status;
144
 
        struct ndr_pull *pull;
145
 
        enum ndr_err_code ndr_err;
146
169
 
147
170
        if (tevent_req_is_nterror(req, &status)) {
 
171
                tevent_req_received(req);
148
172
                return status;
149
173
        }
150
174
 
151
 
        pull = ndr_pull_init_blob(&state->resp_blob, mem_ctx, NULL);
152
 
        if (pull == NULL) {
153
 
                return NT_STATUS_NO_MEMORY;
154
 
        }
155
 
 
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);
159
 
        TALLOC_FREE(pull);
160
 
 
161
 
        if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
162
 
                return ndr_map_error2ntstatus(ndr_err);
163
 
        }
164
 
 
 
175
        *out_data = talloc_move(mem_ctx, &state->out_data.data);
 
176
        *out_length = state->out_data.length;
 
177
        *out_flags = 0;
 
178
        tevent_req_received(req);
165
179
        return NT_STATUS_OK;
166
180
}
167
181
 
168
 
static NTSTATUS wb_ndr_dispatch(struct rpc_pipe_client *cli,
169
 
                                TALLOC_CTX *mem_ctx,
170
 
                                const struct ndr_interface_table *table,
171
 
                                uint32_t opnum, void *r)
 
182
struct wbint_bh_disconnect_state {
 
183
        uint8_t _dummy;
 
184
};
 
185
 
 
186
static struct tevent_req *wbint_bh_disconnect_send(TALLOC_CTX *mem_ctx,
 
187
                                                struct tevent_context *ev,
 
188
                                                struct dcerpc_binding_handle *h)
172
189
{
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;
177
 
 
178
 
        ev = event_context_init(frame);
179
 
        if (ev == NULL) {
180
 
                status = NT_STATUS_NO_MEMORY;
181
 
                goto fail;
182
 
        }
183
 
 
184
 
        req = wb_ndr_dispatch_send(frame, ev, cli, table, opnum, r);
 
193
        struct wbint_bh_disconnect_state *state;
 
194
        bool ok;
 
195
 
 
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;
187
 
                goto fail;
188
 
        }
189
 
 
190
 
        if (!tevent_req_poll(req, ev)) {
191
 
                status = map_nt_error_from_unix(errno);
192
 
                goto fail;
193
 
        }
194
 
 
195
 
        status = wb_ndr_dispatch_recv(req, mem_ctx);
196
 
 fail:
197
 
        TALLOC_FREE(frame);
198
 
        return status;
199
 
}
200
 
 
201
 
struct rpc_pipe_client *wbint_rpccli_create(TALLOC_CTX *mem_ctx,
202
 
                                            struct winbindd_domain *domain,
203
 
                                            struct winbindd_child *child)
204
 
{
205
 
        struct rpc_pipe_client *result;
206
 
        struct wb_ndr_transport_priv *transp;
207
 
 
208
 
        result = talloc(mem_ctx, struct rpc_pipe_client);
209
 
        if (result == NULL) {
210
199
                return NULL;
211
200
        }
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;
 
201
 
 
202
        ok = wbint_bh_is_connected(h);
 
203
        if (!ok) {
 
204
                tevent_req_nterror(req, NT_STATUS_INVALID_CONNECTION);
 
205
                return tevent_req_post(req, ev);
 
206
        }
221
207
 
222
208
        /*
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 ...
 
210
         *
 
211
         * For now the caller needs to free rpc_cli
229
212
         */
230
 
 
231
 
        result->transport = talloc_zero(result, struct rpc_cli_transport);
232
 
        if (result->transport == NULL) {
233
 
                TALLOC_FREE(result);
234
 
                return NULL;
235
 
        }
236
 
        transp = talloc(result->transport, struct wb_ndr_transport_priv);
237
 
        if (transp == NULL) {
238
 
                TALLOC_FREE(result);
239
 
                return NULL;
240
 
        }
241
 
        transp->domain = domain;
242
 
        transp->child = child;
243
 
        result->transport->priv = transp;
244
 
        return result;
 
213
        hs->child = NULL;
 
214
 
 
215
        tevent_req_done(req);
 
216
        return tevent_req_post(req, ev);
 
217
}
 
218
 
 
219
static NTSTATUS wbint_bh_disconnect_recv(struct tevent_req *req)
 
220
{
 
221
        NTSTATUS status;
 
222
 
 
223
        if (tevent_req_is_nterror(req, &status)) {
 
224
                tevent_req_received(req);
 
225
                return status;
 
226
        }
 
227
 
 
228
        tevent_req_received(req);
 
229
        return NT_STATUS_OK;
 
230
}
 
231
 
 
232
static bool wbint_bh_ref_alloc(struct dcerpc_binding_handle *h)
 
233
{
 
234
        return true;
 
235
}
 
236
 
 
237
static void wbint_bh_do_ndr_print(struct dcerpc_binding_handle *h,
 
238
                                  int ndr_flags,
 
239
                                  const void *_struct_ptr,
 
240
                                  const struct ndr_interface_call *call)
 
241
{
 
242
        void *struct_ptr = discard_const(_struct_ptr);
 
243
 
 
244
        if (DEBUGLEVEL < 10) {
 
245
                return;
 
246
        }
 
247
 
 
248
        if (ndr_flags & NDR_IN) {
 
249
                ndr_print_function_debug(call->ndr_print,
 
250
                                         call->name,
 
251
                                         ndr_flags,
 
252
                                         struct_ptr);
 
253
        }
 
254
        if (ndr_flags & NDR_OUT) {
 
255
                ndr_print_function_debug(call->ndr_print,
 
256
                                         call->name,
 
257
                                         ndr_flags,
 
258
                                         struct_ptr);
 
259
        }
 
260
}
 
261
 
 
262
static const struct dcerpc_binding_handle_ops wbint_bh_ops = {
 
263
        .name                   = "wbint",
 
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,
 
270
 
 
271
        .ref_alloc              = wbint_bh_ref_alloc,
 
272
        .do_ndr_print           = wbint_bh_do_ndr_print,
 
273
};
 
274
 
 
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)
 
279
{
 
280
        struct dcerpc_binding_handle *h;
 
281
        struct wbint_bh_state *hs;
 
282
 
 
283
        h = dcerpc_binding_handle_create(mem_ctx,
 
284
                                         &wbint_bh_ops,
 
285
                                         NULL,
 
286
                                         &ndr_table_wbint,
 
287
                                         &hs,
 
288
                                         struct wbint_bh_state,
 
289
                                         __location__);
 
290
        if (h == NULL) {
 
291
                return NULL;
 
292
        }
 
293
        hs->domain = domain;
 
294
        hs->child = child;
 
295
 
 
296
        return h;
245
297
}
246
298
 
247
299
enum winbindd_result winbindd_dual_ndrcmd(struct winbindd_domain *domain,
248
300
                                          struct winbindd_cli_state *state)
249
301
{
250
 
        pipes_struct p;
 
302
        struct pipes_struct p;
251
303
        struct api_struct *fns;
252
304
        int num_fns;
253
305
        bool ret;
264
316
 
265
317
        ZERO_STRUCT(p);
266
318
        p.mem_ctx = talloc_stackframe();
267
 
        p.in_data.data.buffer_size = state->request->extra_len;
268
 
        p.in_data.data.data_p = state->request->extra_data.data;
269
 
        prs_init(&p.out_data.rdata, 0, state->mem_ctx, false);
 
319
        p.in_data.data = data_blob_const(state->request->extra_data.data,
 
320
                                         state->request->extra_len);
270
321
 
271
322
        ret = fns[state->request->data.ndrcmd].fn(&p);
272
 
        TALLOC_FREE(p.mem_ctx);
273
323
        if (!ret) {
 
324
                TALLOC_FREE(p.mem_ctx);
274
325
                return WINBINDD_ERROR;
275
326
        }
276
327
 
277
328
        state->response->extra_data.data =
278
 
                talloc_memdup(state->mem_ctx, p.out_data.rdata.data_p,
279
 
                              p.out_data.rdata.data_offset);
280
 
        state->response->length += p.out_data.rdata.data_offset;
281
 
        prs_mem_free(&p.out_data.rdata);
 
329
                talloc_move(state->mem_ctx, &p.out_data.rdata.data);
 
330
        state->response->length += p.out_data.rdata.length;
 
331
        p.out_data.rdata.length = 0;
 
332
 
 
333
        TALLOC_FREE(p.mem_ctx);
 
334
 
282
335
        if (state->response->extra_data.data == NULL) {
283
336
                return WINBINDD_ERROR;
284
337
        }
285
338
        return WINBINDD_OK;
286
339
}
287
 
 
288
 
/*
289
 
 * Just a dummy to make srv_wbint.c happy
290
 
 */
291
 
NTSTATUS rpc_srv_register(int version, const char *clnt, const char *srv,
292
 
                          const struct ndr_interface_table *iface,
293
 
                          const struct api_struct *cmds, int size)
294
 
{
295
 
        return NT_STATUS_OK;
296
 
}