7088925927451ad60fae2b4f34ec22064d6b7425
[ira/wip.git] / source3 / lib / wb_reqtrans.c
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      ** NOTE! The following LGPL license applies to the wbclient
9      ** library. This does NOT imply that all of Samba is released
10      ** under the LGPL
11
12    This library is free software; you can redistribute it and/or
13    modify it under the terms of the GNU Lesser General Public
14    License as published by the Free Software Foundation; either
15    version 3 of the License, or (at your option) any later version.
16
17    This library is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20    Library General Public License for more details.
21
22    You should have received a copy of the GNU Lesser General Public License
23    along with this program.  If not, see <http://www.gnu.org/licenses/>.
24 */
25
26 #include "includes.h"
27 #include "wbc_async.h"
28
29 #undef DBGC_CLASS
30 #define DBGC_CLASS DBGC_WINBIND
31
32 struct req_read_state {
33         struct winbindd_request *wb_req;
34         size_t max_extra_data;
35         ssize_t ret;
36 };
37
38 static ssize_t wb_req_more(uint8_t *buf, size_t buflen, void *private_data);
39 static void wb_req_read_done(struct tevent_req *subreq);
40
41 struct tevent_req *wb_req_read_send(TALLOC_CTX *mem_ctx,
42                                     struct tevent_context *ev,
43                                     int fd, size_t max_extra_data)
44 {
45         struct tevent_req *req, *subreq;
46         struct req_read_state *state;
47
48         req = tevent_req_create(mem_ctx, &state, struct req_read_state);
49         if (req == NULL) {
50                 return NULL;
51         }
52         state->max_extra_data = max_extra_data;
53
54         subreq = read_packet_send(state, ev, fd, 4, wb_req_more, state);
55         if (tevent_req_nomem(subreq, req)) {
56                 return tevent_req_post(req, ev);
57         }
58         tevent_req_set_callback(subreq, wb_req_read_done, req);
59         return req;
60 }
61
62 static ssize_t wb_req_more(uint8_t *buf, size_t buflen, void *private_data)
63 {
64         struct req_read_state *state = talloc_get_type_abort(
65                 private_data, struct req_read_state);
66         struct winbindd_request *req = (struct winbindd_request *)buf;
67
68         if (buflen == 4) {
69                 if (req->length != sizeof(struct winbindd_request)) {
70                         DEBUG(0, ("wb_req_read_len: Invalid request size "
71                                   "received: %d (expected %d)\n",
72                                   (int)req->length,
73                                   (int)sizeof(struct winbindd_request)));
74                         return -1;
75                 }
76                 return sizeof(struct winbindd_request) - 4;
77         }
78
79         if ((state->max_extra_data != 0)
80             && (req->extra_len > state->max_extra_data)) {
81                 DEBUG(3, ("Got request with %d bytes extra data on "
82                           "unprivileged socket\n", (int)req->extra_len));
83                 return -1;
84         }
85
86         return req->extra_len;
87 }
88
89 static void wb_req_read_done(struct tevent_req *subreq)
90 {
91         struct tevent_req *req = tevent_req_callback_data(
92                 subreq, struct tevent_req);
93         struct req_read_state *state = tevent_req_data(
94                 req, struct req_read_state);
95         int err;
96         uint8_t *buf;
97
98         state->ret = read_packet_recv(subreq, state, &buf, &err);
99         TALLOC_FREE(subreq);
100         if (state->ret == -1) {
101                 tevent_req_error(req, err);
102                 return;
103         }
104
105         state->wb_req = (struct winbindd_request *)buf;
106
107         if (state->wb_req->extra_len != 0) {
108                 state->wb_req->extra_data.data =
109                         (char *)buf + sizeof(struct winbindd_request);
110         } else {
111                 state->wb_req->extra_data.data = NULL;
112         }
113         tevent_req_done(req);
114 }
115
116 ssize_t wb_req_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
117                          struct winbindd_request **preq, int *err)
118 {
119         struct req_read_state *state = tevent_req_data(
120                 req, struct req_read_state);
121
122         if (tevent_req_is_unix_error(req, err)) {
123                 return -1;
124         }
125         *preq = talloc_move(mem_ctx, &state->wb_req);
126         return state->ret;
127 }
128
129 struct req_write_state {
130         struct iovec iov[2];
131         ssize_t ret;
132 };
133
134 static void wb_req_write_done(struct tevent_req *subreq);
135
136 struct tevent_req *wb_req_write_send(TALLOC_CTX *mem_ctx,
137                                      struct tevent_context *ev,
138                                      struct tevent_queue *queue, int fd,
139                                      struct winbindd_request *wb_req)
140 {
141         struct tevent_req *req, *subreq;
142         struct req_write_state *state;
143         int count = 1;
144
145         req = tevent_req_create(mem_ctx, &state, struct req_write_state);
146         if (req == NULL) {
147                 return NULL;
148         }
149
150         state->iov[0].iov_base = (void *)wb_req;
151         state->iov[0].iov_len = sizeof(struct winbindd_request);
152
153         if (wb_req->extra_len != 0) {
154                 state->iov[1].iov_base = (void *)wb_req->extra_data.data;
155                 state->iov[1].iov_len = wb_req->extra_len;
156                 count = 2;
157         }
158
159         subreq = writev_send(state, ev, queue, fd, true, state->iov, count);
160         if (tevent_req_nomem(subreq, req)) {
161                 return tevent_req_post(req, ev);
162         }
163         tevent_req_set_callback(subreq, wb_req_write_done, req);
164         return req;
165 }
166
167 static void wb_req_write_done(struct tevent_req *subreq)
168 {
169         struct tevent_req *req = tevent_req_callback_data(
170                 subreq, struct tevent_req);
171         struct req_write_state *state = tevent_req_data(
172                 req, struct req_write_state);
173         int err;
174
175         state->ret = writev_recv(subreq, &err);
176         TALLOC_FREE(subreq);
177         if (state->ret < 0) {
178                 tevent_req_error(req, err);
179                 return;
180         }
181         tevent_req_done(req);
182 }
183
184 ssize_t wb_req_write_recv(struct tevent_req *req, int *err)
185 {
186         struct req_write_state *state = tevent_req_data(
187                 req, struct req_write_state);
188
189         if (tevent_req_is_unix_error(req, err)) {
190                 return -1;
191         }
192         return state->ret;
193 }
194
195 struct resp_read_state {
196         struct winbindd_response *wb_resp;
197         ssize_t ret;
198 };
199
200 static ssize_t wb_resp_more(uint8_t *buf, size_t buflen, void *private_data);
201 static void wb_resp_read_done(struct tevent_req *subreq);
202
203 struct tevent_req *wb_resp_read_send(TALLOC_CTX *mem_ctx,
204                                      struct tevent_context *ev, int fd)
205 {
206         struct tevent_req *req, *subreq;
207         struct resp_read_state *state;
208
209         req = tevent_req_create(mem_ctx, &state, struct resp_read_state);
210         if (req == NULL) {
211                 return NULL;
212         }
213
214         subreq = read_packet_send(state, ev, fd, 4, wb_resp_more, state);
215         if (tevent_req_nomem(subreq, req)) {
216                 return tevent_req_post(req, ev);
217         }
218         tevent_req_set_callback(subreq, wb_resp_read_done, req);
219         return req;
220 }
221
222 static ssize_t wb_resp_more(uint8_t *buf, size_t buflen, void *private_data)
223 {
224         struct winbindd_response *resp = (struct winbindd_response *)buf;
225
226         if (buflen == 4) {
227                 if (resp->length < sizeof(struct winbindd_response)) {
228                         DEBUG(0, ("wb_resp_read_len: Invalid response size "
229                                   "received: %d (expected at least%d)\n",
230                                   (int)resp->length,
231                                   (int)sizeof(struct winbindd_response)));
232                         return -1;
233                 }
234         }
235         return resp->length - buflen;
236 }
237
238 static void wb_resp_read_done(struct tevent_req *subreq)
239 {
240         struct tevent_req *req = tevent_req_callback_data(
241                 subreq, struct tevent_req);
242         struct resp_read_state *state = tevent_req_data(
243                 req, struct resp_read_state);
244         uint8_t *buf;
245         int err;
246
247         state->ret = read_packet_recv(subreq, state, &buf, &err);
248         TALLOC_FREE(subreq);
249         if (state->ret == -1) {
250                 tevent_req_error(req, err);
251                 return;
252         }
253
254         state->wb_resp = (struct winbindd_response *)buf;
255
256         if (state->wb_resp->length > sizeof(struct winbindd_response)) {
257                 state->wb_resp->extra_data.data =
258                         (char *)buf + sizeof(struct winbindd_response);
259         } else {
260                 state->wb_resp->extra_data.data = NULL;
261         }
262         tevent_req_done(req);
263 }
264
265 ssize_t wb_resp_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
266                           struct winbindd_response **presp, int *err)
267 {
268         struct resp_read_state *state = tevent_req_data(
269                 req, struct resp_read_state);
270
271         if (tevent_req_is_unix_error(req, err)) {
272                 return -1;
273         }
274         *presp = talloc_move(mem_ctx, &state->wb_resp);
275         return state->ret;
276 }
277
278 struct resp_write_state {
279         struct iovec iov[2];
280         ssize_t ret;
281 };
282
283 static void wb_resp_write_done(struct tevent_req *subreq);
284
285 struct tevent_req *wb_resp_write_send(TALLOC_CTX *mem_ctx,
286                                       struct tevent_context *ev,
287                                       struct tevent_queue *queue, int fd,
288                                       struct winbindd_response *wb_resp)
289 {
290         struct tevent_req *req, *subreq;
291         struct resp_write_state *state;
292         int count = 1;
293
294         req = tevent_req_create(mem_ctx, &state, struct resp_write_state);
295         if (req == NULL) {
296                 return NULL;
297         }
298
299         state->iov[0].iov_base = (void *)wb_resp;
300         state->iov[0].iov_len = sizeof(struct winbindd_response);
301
302         if (wb_resp->length > sizeof(struct winbindd_response)) {
303                 state->iov[1].iov_base = (void *)wb_resp->extra_data.data;
304                 state->iov[1].iov_len =
305                         wb_resp->length - sizeof(struct winbindd_response);
306                 count = 2;
307         }
308
309         subreq = writev_send(state, ev, queue, fd, true, state->iov, count);
310         if (tevent_req_nomem(subreq, req)) {
311                 return tevent_req_post(req, ev);
312         }
313         tevent_req_set_callback(subreq, wb_resp_write_done, req);
314         return req;
315 }
316
317 static void wb_resp_write_done(struct tevent_req *subreq)
318 {
319         struct tevent_req *req = tevent_req_callback_data(
320                 subreq, struct tevent_req);
321         struct resp_write_state *state = tevent_req_data(
322                 req, struct resp_write_state);
323         int err;
324
325         state->ret = writev_recv(subreq, &err);
326         TALLOC_FREE(subreq);
327         if (state->ret < 0) {
328                 tevent_req_error(req, err);
329                 return;
330         }
331         tevent_req_done(req);
332 }
333
334 ssize_t wb_resp_write_recv(struct tevent_req *req, int *err)
335 {
336         struct resp_write_state *state = tevent_req_data(
337                 req, struct resp_write_state);
338
339         if (tevent_req_is_unix_error(req, err)) {
340                 return -1;
341         }
342         return state->ret;
343 }
344
345 struct wb_simple_trans_state {
346         struct tevent_context *ev;
347         int fd;
348         struct winbindd_response *wb_resp;
349 };
350
351 static void wb_simple_trans_write_done(struct tevent_req *subreq);
352 static void wb_simple_trans_read_done(struct tevent_req *subreq);
353
354 struct tevent_req *wb_simple_trans_send(TALLOC_CTX *mem_ctx,
355                                         struct tevent_context *ev,
356                                         struct tevent_queue *queue, int fd,
357                                         struct winbindd_request *wb_req)
358 {
359         struct tevent_req *req, *subreq;
360         struct wb_simple_trans_state *state;
361
362         req = tevent_req_create(mem_ctx, &state, struct wb_simple_trans_state);
363         if (req == NULL) {
364                 return NULL;
365         }
366
367         wb_req->length = sizeof(struct winbindd_request);
368
369         state->ev = ev;
370         state->fd = fd;
371
372         subreq = wb_req_write_send(state, ev, queue, fd, wb_req);
373         if (tevent_req_nomem(subreq, req)) {
374                 return tevent_req_post(req, ev);
375         }
376         tevent_req_set_callback(subreq, wb_simple_trans_write_done, req);
377
378         return req;
379 }
380
381 static void wb_simple_trans_write_done(struct tevent_req *subreq)
382 {
383         struct tevent_req *req = tevent_req_callback_data(
384                 subreq, struct tevent_req);
385         struct wb_simple_trans_state *state = tevent_req_data(
386                 req, struct wb_simple_trans_state);
387         ssize_t ret;
388         int err;
389
390         ret = wb_req_write_recv(subreq, &err);
391         TALLOC_FREE(subreq);
392         if (ret == -1) {
393                 tevent_req_error(req, err);
394                 return;
395         }
396         subreq = wb_resp_read_send(state, state->ev, state->fd);
397         if (tevent_req_nomem(subreq, req)) {
398                 return;
399         }
400         tevent_req_set_callback(subreq, wb_simple_trans_read_done, req);
401 }
402
403 static void wb_simple_trans_read_done(struct tevent_req *subreq)
404 {
405         struct tevent_req *req = tevent_req_callback_data(
406                 subreq, struct tevent_req);
407         struct wb_simple_trans_state *state = tevent_req_data(
408                 req, struct wb_simple_trans_state);
409         ssize_t ret;
410         int err;
411
412         ret = wb_resp_read_recv(subreq, state, &state->wb_resp, &err);
413         TALLOC_FREE(subreq);
414         if (ret == -1) {
415                 tevent_req_error(req, err);
416                 return;
417         }
418
419         tevent_req_done(req);
420 }
421
422 int wb_simple_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
423                          struct winbindd_response **presponse, int *err)
424 {
425         struct wb_simple_trans_state *state = tevent_req_data(
426                 req, struct wb_simple_trans_state);
427
428         if (tevent_req_is_unix_error(req, err)) {
429                 return -1;
430         }
431         *presponse = talloc_move(mem_ctx, &state->wb_resp);
432         return 0;
433 }