~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source3/lib/wb_reqtrans.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
   Unix SMB/CIFS implementation.
 
3
 
 
4
   Async transfer of winbindd_request and _response structs
 
5
 
 
6
   Copyright (C) Volker Lendecke 2008
 
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 "wbc_async.h"
 
24
 
 
25
#undef DBGC_CLASS
 
26
#define DBGC_CLASS DBGC_WINBIND
 
27
 
 
28
wbcErr map_wbc_err_from_errno(int error)
 
29
{
 
30
        switch(error) {
 
31
        case EPERM:
 
32
        case EACCES:
 
33
                return WBC_ERR_AUTH_ERROR;
 
34
        case ENOMEM:
 
35
                return WBC_ERR_NO_MEMORY;
 
36
        case EIO:
 
37
        default:
 
38
                return WBC_ERR_UNKNOWN_FAILURE;
 
39
        }
 
40
}
 
41
 
 
42
bool tevent_req_is_wbcerr(struct tevent_req *req, wbcErr *pwbc_err)
 
43
{
 
44
        enum tevent_req_state state;
 
45
        uint64_t error;
 
46
        if (!tevent_req_is_error(req, &state, &error)) {
 
47
                *pwbc_err = WBC_ERR_SUCCESS;
 
48
                return false;
 
49
        }
 
50
 
 
51
        switch (state) {
 
52
        case TEVENT_REQ_USER_ERROR:
 
53
                *pwbc_err = error;
 
54
                break;
 
55
        case TEVENT_REQ_TIMED_OUT:
 
56
                *pwbc_err = WBC_ERR_UNKNOWN_FAILURE;
 
57
                break;
 
58
        case TEVENT_REQ_NO_MEMORY:
 
59
                *pwbc_err = WBC_ERR_NO_MEMORY;
 
60
                break;
 
61
        default:
 
62
                *pwbc_err = WBC_ERR_UNKNOWN_FAILURE;
 
63
                break;
 
64
        }
 
65
        return true;
 
66
}
 
67
 
 
68
wbcErr tevent_req_simple_recv_wbcerr(struct tevent_req *req)
 
69
{
 
70
        wbcErr wbc_err;
 
71
 
 
72
        if (tevent_req_is_wbcerr(req, &wbc_err)) {
 
73
                return wbc_err;
 
74
        }
 
75
 
 
76
        return WBC_ERR_SUCCESS;
 
77
}
 
78
 
 
79
struct req_read_state {
 
80
        struct winbindd_request *wb_req;
 
81
        size_t max_extra_data;
 
82
};
 
83
 
 
84
static ssize_t wb_req_more(uint8_t *buf, size_t buflen, void *private_data);
 
85
static void wb_req_read_done(struct tevent_req *subreq);
 
86
 
 
87
struct tevent_req *wb_req_read_send(TALLOC_CTX *mem_ctx,
 
88
                                    struct tevent_context *ev,
 
89
                                    int fd, size_t max_extra_data)
 
90
{
 
91
        struct tevent_req *result, *subreq;
 
92
        struct req_read_state *state;
 
93
 
 
94
        result = tevent_req_create(mem_ctx, &state, struct req_read_state);
 
95
        if (result == NULL) {
 
96
                return NULL;
 
97
        }
 
98
        state->max_extra_data = max_extra_data;
 
99
 
 
100
        subreq = read_packet_send(state, ev, fd, 4, wb_req_more, state);
 
101
        if (subreq == NULL) {
 
102
                goto nomem;
 
103
        }
 
104
 
 
105
        tevent_req_set_callback(subreq, wb_req_read_done, result);
 
106
        return result;
 
107
 nomem:
 
108
        TALLOC_FREE(result);
 
109
        return NULL;
 
110
}
 
111
 
 
112
static ssize_t wb_req_more(uint8_t *buf, size_t buflen, void *private_data)
 
113
{
 
114
        struct req_read_state *state = talloc_get_type_abort(
 
115
                private_data, struct req_read_state);
 
116
        struct winbindd_request *req = (struct winbindd_request *)buf;
 
117
 
 
118
        if (buflen == 4) {
 
119
                if (req->length != sizeof(struct winbindd_request)) {
 
120
                        DEBUG(0, ("wb_req_read_len: Invalid request size "
 
121
                                  "received: %d (expected %d)\n",
 
122
                                  (int)req->length,
 
123
                                  (int)sizeof(struct winbindd_request)));
 
124
                        return -1;
 
125
                }
 
126
                return sizeof(struct winbindd_request) - 4;
 
127
        }
 
128
 
 
129
        if ((state->max_extra_data != 0)
 
130
            && (req->extra_len > state->max_extra_data)) {
 
131
                DEBUG(3, ("Got request with %d bytes extra data on "
 
132
                          "unprivileged socket\n", (int)req->extra_len));
 
133
                return -1;
 
134
        }
 
135
 
 
136
        return req->extra_len;
 
137
}
 
138
 
 
139
static void wb_req_read_done(struct tevent_req *subreq)
 
140
{
 
141
        struct tevent_req *req = tevent_req_callback_data(
 
142
                subreq, struct tevent_req);
 
143
        struct req_read_state *state = tevent_req_data(
 
144
                req, struct req_read_state);
 
145
        int err;
 
146
        ssize_t ret;
 
147
        uint8_t *buf;
 
148
 
 
149
        ret = read_packet_recv(subreq, state, &buf, &err);
 
150
        TALLOC_FREE(subreq);
 
151
        if (ret == -1) {
 
152
                tevent_req_error(req, map_wbc_err_from_errno(err));
 
153
                return;
 
154
        }
 
155
 
 
156
        state->wb_req = (struct winbindd_request *)buf;
 
157
 
 
158
        if (state->wb_req->extra_len != 0) {
 
159
                state->wb_req->extra_data.data =
 
160
                        (char *)buf + sizeof(struct winbindd_request);
 
161
        } else {
 
162
                state->wb_req->extra_data.data = NULL;
 
163
        }
 
164
        tevent_req_done(req);
 
165
}
 
166
 
 
167
wbcErr wb_req_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
 
168
                        struct winbindd_request **preq)
 
169
{
 
170
        struct req_read_state *state = tevent_req_data(
 
171
                req, struct req_read_state);
 
172
        wbcErr wbc_err;
 
173
 
 
174
        if (tevent_req_is_wbcerr(req, &wbc_err)) {
 
175
                return wbc_err;
 
176
        }
 
177
        *preq = talloc_move(mem_ctx, &state->wb_req);
 
178
        return WBC_ERR_SUCCESS;
 
179
}
 
180
 
 
181
struct req_write_state {
 
182
        struct iovec iov[2];
 
183
};
 
184
 
 
185
static void wb_req_write_done(struct tevent_req *subreq);
 
186
 
 
187
struct tevent_req *wb_req_write_send(TALLOC_CTX *mem_ctx,
 
188
                                     struct tevent_context *ev,
 
189
                                     struct tevent_queue *queue, int fd,
 
190
                                     struct winbindd_request *wb_req)
 
191
{
 
192
        struct tevent_req *result, *subreq;
 
193
        struct req_write_state *state;
 
194
        int count = 1;
 
195
 
 
196
        result = tevent_req_create(mem_ctx, &state, struct req_write_state);
 
197
        if (result == NULL) {
 
198
                return NULL;
 
199
        }
 
200
 
 
201
        state->iov[0].iov_base = wb_req;
 
202
        state->iov[0].iov_len = sizeof(struct winbindd_request);
 
203
 
 
204
        if (wb_req->extra_len != 0) {
 
205
                state->iov[1].iov_base = wb_req->extra_data.data;
 
206
                state->iov[1].iov_len = wb_req->extra_len;
 
207
                count = 2;
 
208
        }
 
209
 
 
210
        subreq = writev_send(state, ev, queue, fd, state->iov, count);
 
211
        if (subreq == NULL) {
 
212
                goto fail;
 
213
        }
 
214
        tevent_req_set_callback(subreq, wb_req_write_done, result);
 
215
        return result;
 
216
 
 
217
 fail:
 
218
        TALLOC_FREE(result);
 
219
        return NULL;
 
220
}
 
221
 
 
222
static void wb_req_write_done(struct tevent_req *subreq)
 
223
{
 
224
        struct tevent_req *req = tevent_req_callback_data(
 
225
                subreq, struct tevent_req);
 
226
        int err;
 
227
        ssize_t ret;
 
228
 
 
229
        ret = writev_recv(subreq, &err);
 
230
        TALLOC_FREE(subreq);
 
231
        if (ret < 0) {
 
232
                tevent_req_error(req, map_wbc_err_from_errno(err));
 
233
                return;
 
234
        }
 
235
        tevent_req_done(req);
 
236
}
 
237
 
 
238
wbcErr wb_req_write_recv(struct tevent_req *req)
 
239
{
 
240
        return tevent_req_simple_recv_wbcerr(req);
 
241
}
 
242
 
 
243
struct resp_read_state {
 
244
        struct winbindd_response *wb_resp;
 
245
};
 
246
 
 
247
static ssize_t wb_resp_more(uint8_t *buf, size_t buflen, void *private_data);
 
248
static void wb_resp_read_done(struct tevent_req *subreq);
 
249
 
 
250
struct tevent_req *wb_resp_read_send(TALLOC_CTX *mem_ctx,
 
251
                                     struct tevent_context *ev, int fd)
 
252
{
 
253
        struct tevent_req *result, *subreq;
 
254
        struct resp_read_state *state;
 
255
 
 
256
        result = tevent_req_create(mem_ctx, &state, struct resp_read_state);
 
257
        if (result == NULL) {
 
258
                return NULL;
 
259
        }
 
260
 
 
261
        subreq = read_packet_send(state, ev, fd, 4, wb_resp_more, state);
 
262
        if (subreq == NULL) {
 
263
                goto nomem;
 
264
        }
 
265
        tevent_req_set_callback(subreq, wb_resp_read_done, result);
 
266
        return result;
 
267
 
 
268
 nomem:
 
269
        TALLOC_FREE(result);
 
270
        return NULL;
 
271
}
 
272
 
 
273
static ssize_t wb_resp_more(uint8_t *buf, size_t buflen, void *private_data)
 
274
{
 
275
        struct winbindd_response *resp = (struct winbindd_response *)buf;
 
276
 
 
277
        if (buflen == 4) {
 
278
                if (resp->length < sizeof(struct winbindd_response)) {
 
279
                        DEBUG(0, ("wb_resp_read_len: Invalid response size "
 
280
                                  "received: %d (expected at least%d)\n",
 
281
                                  (int)resp->length,
 
282
                                  (int)sizeof(struct winbindd_response)));
 
283
                        return -1;
 
284
                }
 
285
        }
 
286
        return resp->length - buflen;
 
287
}
 
288
 
 
289
static void wb_resp_read_done(struct tevent_req *subreq)
 
290
{
 
291
        struct tevent_req *req = tevent_req_callback_data(
 
292
                subreq, struct tevent_req);
 
293
        struct resp_read_state *state = tevent_req_data(
 
294
                req, struct resp_read_state);
 
295
        uint8_t *buf;
 
296
        int err;
 
297
        ssize_t ret;
 
298
 
 
299
        ret = read_packet_recv(subreq, state, &buf, &err);
 
300
        TALLOC_FREE(subreq);
 
301
        if (ret == -1) {
 
302
                tevent_req_error(req, map_wbc_err_from_errno(err));
 
303
                return;
 
304
        }
 
305
 
 
306
        state->wb_resp = (struct winbindd_response *)buf;
 
307
 
 
308
        if (state->wb_resp->length > sizeof(struct winbindd_response)) {
 
309
                state->wb_resp->extra_data.data =
 
310
                        (char *)buf + sizeof(struct winbindd_response);
 
311
        } else {
 
312
                state->wb_resp->extra_data.data = NULL;
 
313
        }
 
314
        tevent_req_done(req);
 
315
}
 
316
 
 
317
wbcErr wb_resp_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
 
318
                         struct winbindd_response **presp)
 
319
{
 
320
        struct resp_read_state *state = tevent_req_data(
 
321
                req, struct resp_read_state);
 
322
        wbcErr wbc_err;
 
323
 
 
324
        if (tevent_req_is_wbcerr(req, &wbc_err)) {
 
325
                return wbc_err;
 
326
        }
 
327
        *presp = talloc_move(mem_ctx, &state->wb_resp);
 
328
        return WBC_ERR_SUCCESS;
 
329
}
 
330
 
 
331
struct resp_write_state {
 
332
        struct iovec iov[2];
 
333
};
 
334
 
 
335
static void wb_resp_write_done(struct tevent_req *subreq);
 
336
 
 
337
struct tevent_req *wb_resp_write_send(TALLOC_CTX *mem_ctx,
 
338
                                      struct tevent_context *ev,
 
339
                                      struct tevent_queue *queue, int fd,
 
340
                                      struct winbindd_response *wb_resp)
 
341
{
 
342
        struct tevent_req *result, *subreq;
 
343
        struct resp_write_state *state;
 
344
        int count = 1;
 
345
 
 
346
        result = tevent_req_create(mem_ctx, &state, struct resp_write_state);
 
347
        if (result == NULL) {
 
348
                return NULL;
 
349
        }
 
350
 
 
351
        state->iov[0].iov_base = wb_resp;
 
352
        state->iov[0].iov_len = sizeof(struct winbindd_response);
 
353
 
 
354
        if (wb_resp->length > sizeof(struct winbindd_response)) {
 
355
                state->iov[1].iov_base = wb_resp->extra_data.data;
 
356
                state->iov[1].iov_len =
 
357
                        wb_resp->length - sizeof(struct winbindd_response);
 
358
                count = 2;
 
359
        }
 
360
 
 
361
        subreq = writev_send(state, ev, queue, fd, state->iov, count);
 
362
        if (subreq == NULL) {
 
363
                goto fail;
 
364
        }
 
365
        tevent_req_set_callback(subreq, wb_resp_write_done, result);
 
366
        return result;
 
367
 
 
368
 fail:
 
369
        TALLOC_FREE(result);
 
370
        return NULL;
 
371
}
 
372
 
 
373
static void wb_resp_write_done(struct tevent_req *subreq)
 
374
{
 
375
        struct tevent_req *req = tevent_req_callback_data(
 
376
                subreq, struct tevent_req);
 
377
        int err;
 
378
        ssize_t ret;
 
379
 
 
380
        ret = writev_recv(subreq, &err);
 
381
        TALLOC_FREE(subreq);
 
382
        if (ret < 0) {
 
383
                tevent_req_error(req, map_wbc_err_from_errno(err));
 
384
                return;
 
385
        }
 
386
        tevent_req_done(req);
 
387
}
 
388
 
 
389
wbcErr wb_resp_write_recv(struct tevent_req *req)
 
390
{
 
391
        return tevent_req_simple_recv_wbcerr(req);
 
392
}