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