16d71fe03e36aadc715380e3810ca6bfed1e96bd
[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    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 struct req_read_state {
29         struct winbindd_request *wb_req;
30         size_t max_extra_data;
31         ssize_t ret;
32 };
33
34 static ssize_t wb_req_more(uint8_t *buf, size_t buflen, void *private_data);
35 static void wb_req_read_done(struct tevent_req *subreq);
36
37 struct tevent_req *wb_req_read_send(TALLOC_CTX *mem_ctx,
38                                     struct tevent_context *ev,
39                                     int fd, size_t max_extra_data)
40 {
41         struct tevent_req *req, *subreq;
42         struct req_read_state *state;
43
44         req = tevent_req_create(mem_ctx, &state, struct req_read_state);
45         if (req == NULL) {
46                 return NULL;
47         }
48         state->max_extra_data = max_extra_data;
49
50         subreq = read_packet_send(state, ev, fd, 4, wb_req_more, state);
51         if (tevent_req_nomem(subreq, req)) {
52                 return tevent_req_post(req, ev);
53         }
54         tevent_req_set_callback(subreq, wb_req_read_done, req);
55         return req;
56 }
57
58 static ssize_t wb_req_more(uint8_t *buf, size_t buflen, void *private_data)
59 {
60         struct req_read_state *state = talloc_get_type_abort(
61                 private_data, struct req_read_state);
62         struct winbindd_request *req = (struct winbindd_request *)buf;
63
64         if (buflen == 4) {
65                 if (req->length != sizeof(struct winbindd_request)) {
66                         DEBUG(0, ("wb_req_read_len: Invalid request size "
67                                   "received: %d (expected %d)\n",
68                                   (int)req->length,
69                                   (int)sizeof(struct winbindd_request)));
70                         return -1;
71                 }
72                 return sizeof(struct winbindd_request) - 4;
73         }
74
75         if ((state->max_extra_data != 0)
76             && (req->extra_len > state->max_extra_data)) {
77                 DEBUG(3, ("Got request with %d bytes extra data on "
78                           "unprivileged socket\n", (int)req->extra_len));
79                 return -1;
80         }
81
82         return req->extra_len;
83 }
84
85 static void wb_req_read_done(struct tevent_req *subreq)
86 {
87         struct tevent_req *req = tevent_req_callback_data(
88                 subreq, struct tevent_req);
89         struct req_read_state *state = tevent_req_data(
90                 req, struct req_read_state);
91         int err;
92         uint8_t *buf;
93
94         state->ret = read_packet_recv(subreq, state, &buf, &err);
95         TALLOC_FREE(subreq);
96         if (state->ret == -1) {
97                 tevent_req_error(req, err);
98                 return;
99         }
100
101         state->wb_req = (struct winbindd_request *)buf;
102
103         if (state->wb_req->extra_len != 0) {
104                 state->wb_req->extra_data.data =
105                         (char *)buf + sizeof(struct winbindd_request);
106         } else {
107                 state->wb_req->extra_data.data = NULL;
108         }
109         tevent_req_done(req);
110 }
111
112 ssize_t wb_req_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
113                          struct winbindd_request **preq, int *err)
114 {
115         struct req_read_state *state = tevent_req_data(
116                 req, struct req_read_state);
117
118         if (tevent_req_is_unix_error(req, err)) {
119                 return -1;
120         }
121         *preq = talloc_move(mem_ctx, &state->wb_req);
122         return state->ret;
123 }
124
125 struct req_write_state {
126         struct iovec iov[2];
127         ssize_t ret;
128 };
129
130 static void wb_req_write_done(struct tevent_req *subreq);
131
132 struct tevent_req *wb_req_write_send(TALLOC_CTX *mem_ctx,
133                                      struct tevent_context *ev,
134                                      struct tevent_queue *queue, int fd,
135                                      struct winbindd_request *wb_req)
136 {
137         struct tevent_req *req, *subreq;
138         struct req_write_state *state;
139         int count = 1;
140
141         req = tevent_req_create(mem_ctx, &state, struct req_write_state);
142         if (req == NULL) {
143                 return NULL;
144         }
145
146         state->iov[0].iov_base = (void *)wb_req;
147         state->iov[0].iov_len = sizeof(struct winbindd_request);
148
149         if (wb_req->extra_len != 0) {
150                 state->iov[1].iov_base = (void *)wb_req->extra_data.data;
151                 state->iov[1].iov_len = wb_req->extra_len;
152                 count = 2;
153         }
154
155         subreq = writev_send(state, ev, queue, fd, true, state->iov, count);
156         if (tevent_req_nomem(subreq, req)) {
157                 return tevent_req_post(req, ev);
158         }
159         tevent_req_set_callback(subreq, wb_req_write_done, req);
160         return req;
161 }
162
163 static void wb_req_write_done(struct tevent_req *subreq)
164 {
165         struct tevent_req *req = tevent_req_callback_data(
166                 subreq, struct tevent_req);
167         struct req_write_state *state = tevent_req_data(
168                 req, struct req_write_state);
169         int err;
170
171         state->ret = writev_recv(subreq, &err);
172         TALLOC_FREE(subreq);
173         if (state->ret < 0) {
174                 tevent_req_error(req, err);
175                 return;
176         }
177         tevent_req_done(req);
178 }
179
180 ssize_t wb_req_write_recv(struct tevent_req *req, int *err)
181 {
182         struct req_write_state *state = tevent_req_data(
183                 req, struct req_write_state);
184
185         if (tevent_req_is_unix_error(req, err)) {
186                 return -1;
187         }
188         return state->ret;
189 }
190
191 struct resp_read_state {
192         struct winbindd_response *wb_resp;
193         ssize_t ret;
194 };
195
196 static ssize_t wb_resp_more(uint8_t *buf, size_t buflen, void *private_data);
197 static void wb_resp_read_done(struct tevent_req *subreq);
198
199 struct tevent_req *wb_resp_read_send(TALLOC_CTX *mem_ctx,
200                                      struct tevent_context *ev, int fd)
201 {
202         struct tevent_req *req, *subreq;
203         struct resp_read_state *state;
204
205         req = tevent_req_create(mem_ctx, &state, struct resp_read_state);
206         if (req == NULL) {
207                 return NULL;
208         }
209
210         subreq = read_packet_send(state, ev, fd, 4, wb_resp_more, state);
211         if (tevent_req_nomem(subreq, req)) {
212                 return tevent_req_post(req, ev);
213         }
214         tevent_req_set_callback(subreq, wb_resp_read_done, req);
215         return req;
216 }
217
218 static ssize_t wb_resp_more(uint8_t *buf, size_t buflen, void *private_data)
219 {
220         struct winbindd_response *resp = (struct winbindd_response *)buf;
221
222         if (buflen == 4) {
223                 if (resp->length < sizeof(struct winbindd_response)) {
224                         DEBUG(0, ("wb_resp_read_len: Invalid response size "
225                                   "received: %d (expected at least%d)\n",
226                                   (int)resp->length,
227                                   (int)sizeof(struct winbindd_response)));
228                         return -1;
229                 }
230         }
231         return resp->length - buflen;
232 }
233
234 static void wb_resp_read_done(struct tevent_req *subreq)
235 {
236         struct tevent_req *req = tevent_req_callback_data(
237                 subreq, struct tevent_req);
238         struct resp_read_state *state = tevent_req_data(
239                 req, struct resp_read_state);
240         uint8_t *buf;
241         int err;
242
243         state->ret = read_packet_recv(subreq, state, &buf, &err);
244         TALLOC_FREE(subreq);
245         if (state->ret == -1) {
246                 tevent_req_error(req, err);
247                 return;
248         }
249
250         state->wb_resp = (struct winbindd_response *)buf;
251
252         if (state->wb_resp->length > sizeof(struct winbindd_response)) {
253                 state->wb_resp->extra_data.data =
254                         (char *)buf + sizeof(struct winbindd_response);
255         } else {
256                 state->wb_resp->extra_data.data = NULL;
257         }
258         tevent_req_done(req);
259 }
260
261 ssize_t wb_resp_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
262                           struct winbindd_response **presp, int *err)
263 {
264         struct resp_read_state *state = tevent_req_data(
265                 req, struct resp_read_state);
266
267         if (tevent_req_is_unix_error(req, err)) {
268                 return -1;
269         }
270         *presp = talloc_move(mem_ctx, &state->wb_resp);
271         return state->ret;
272 }
273
274 struct resp_write_state {
275         struct iovec iov[2];
276         ssize_t ret;
277 };
278
279 static void wb_resp_write_done(struct tevent_req *subreq);
280
281 struct tevent_req *wb_resp_write_send(TALLOC_CTX *mem_ctx,
282                                       struct tevent_context *ev,
283                                       struct tevent_queue *queue, int fd,
284                                       struct winbindd_response *wb_resp)
285 {
286         struct tevent_req *req, *subreq;
287         struct resp_write_state *state;
288         int count = 1;
289
290         req = tevent_req_create(mem_ctx, &state, struct resp_write_state);
291         if (req == NULL) {
292                 return NULL;
293         }
294
295         state->iov[0].iov_base = (void *)wb_resp;
296         state->iov[0].iov_len = sizeof(struct winbindd_response);
297
298         if (wb_resp->length > sizeof(struct winbindd_response)) {
299                 state->iov[1].iov_base = (void *)wb_resp->extra_data.data;
300                 state->iov[1].iov_len =
301                         wb_resp->length - sizeof(struct winbindd_response);
302                 count = 2;
303         }
304
305         subreq = writev_send(state, ev, queue, fd, true, state->iov, count);
306         if (tevent_req_nomem(subreq, req)) {
307                 return tevent_req_post(req, ev);
308         }
309         tevent_req_set_callback(subreq, wb_resp_write_done, req);
310         return req;
311 }
312
313 static void wb_resp_write_done(struct tevent_req *subreq)
314 {
315         struct tevent_req *req = tevent_req_callback_data(
316                 subreq, struct tevent_req);
317         struct resp_write_state *state = tevent_req_data(
318                 req, struct resp_write_state);
319         int err;
320
321         state->ret = writev_recv(subreq, &err);
322         TALLOC_FREE(subreq);
323         if (state->ret < 0) {
324                 tevent_req_error(req, err);
325                 return;
326         }
327         tevent_req_done(req);
328 }
329
330 ssize_t wb_resp_write_recv(struct tevent_req *req, int *err)
331 {
332         struct resp_write_state *state = tevent_req_data(
333                 req, struct resp_write_state);
334
335         if (tevent_req_is_unix_error(req, err)) {
336                 return -1;
337         }
338         return state->ret;
339 }
340
341 static bool closed_fd(int fd)
342 {
343         struct timeval tv;
344         fd_set r_fds;
345
346         if (fd == -1) {
347                 return true;
348         }
349
350         FD_ZERO(&r_fds);
351         FD_SET(fd, &r_fds);
352         ZERO_STRUCT(tv);
353
354         if ((select(fd+1, &r_fds, NULL, NULL, &tv) == -1)
355             || FD_ISSET(fd, &r_fds)) {
356                 return true;
357         }
358
359         return false;
360 }
361
362 struct wb_simple_trans_state {
363         struct tevent_context *ev;
364         int fd;
365         struct winbindd_response *wb_resp;
366 };
367
368 static void wb_simple_trans_write_done(struct tevent_req *subreq);
369 static void wb_simple_trans_read_done(struct tevent_req *subreq);
370
371 struct tevent_req *wb_simple_trans_send(TALLOC_CTX *mem_ctx,
372                                         struct tevent_context *ev,
373                                         struct tevent_queue *queue, int fd,
374                                         struct winbindd_request *wb_req)
375 {
376         struct tevent_req *req, *subreq;
377         struct wb_simple_trans_state *state;
378
379         req = tevent_req_create(mem_ctx, &state, struct wb_simple_trans_state);
380         if (req == NULL) {
381                 return NULL;
382         }
383
384         if (closed_fd(fd)) {
385                 tevent_req_error(req, EPIPE);
386                 return tevent_req_post(req, ev);
387         }
388
389         wb_req->length = sizeof(struct winbindd_request);
390
391         state->ev = ev;
392         state->fd = fd;
393
394         subreq = wb_req_write_send(state, ev, queue, fd, wb_req);
395         if (tevent_req_nomem(subreq, req)) {
396                 return tevent_req_post(req, ev);
397         }
398         tevent_req_set_callback(subreq, wb_simple_trans_write_done, req);
399
400         return req;
401 }
402
403 static void wb_simple_trans_write_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_req_write_recv(subreq, &err);
413         TALLOC_FREE(subreq);
414         if (ret == -1) {
415                 tevent_req_error(req, err);
416                 return;
417         }
418         subreq = wb_resp_read_send(state, state->ev, state->fd);
419         if (tevent_req_nomem(subreq, req)) {
420                 return;
421         }
422         tevent_req_set_callback(subreq, wb_simple_trans_read_done, req);
423 }
424
425 static void wb_simple_trans_read_done(struct tevent_req *subreq)
426 {
427         struct tevent_req *req = tevent_req_callback_data(
428                 subreq, struct tevent_req);
429         struct wb_simple_trans_state *state = tevent_req_data(
430                 req, struct wb_simple_trans_state);
431         ssize_t ret;
432         int err;
433
434         ret = wb_resp_read_recv(subreq, state, &state->wb_resp, &err);
435         TALLOC_FREE(subreq);
436         if (ret == -1) {
437                 tevent_req_error(req, err);
438                 return;
439         }
440
441         tevent_req_done(req);
442 }
443
444 int wb_simple_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
445                          struct winbindd_response **presponse, int *err)
446 {
447         struct wb_simple_trans_state *state = tevent_req_data(
448                 req, struct wb_simple_trans_state);
449
450         if (tevent_req_is_unix_error(req, err)) {
451                 return -1;
452         }
453         *presponse = talloc_move(mem_ctx, &state->wb_resp);
454         return 0;
455 }