30e5f75062fda373244aef6905df967b680015b9
[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 tevent_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 tevent_req *result, *subreq;
129         struct req_read_state *state;
130
131         result = tevent_req_create(mem_ctx, &state, struct req_read_state);
132         if (result == NULL) {
133                 return NULL;
134         }
135         state->max_extra_data = max_extra_data;
136
137         subreq = read_packet_send(state, ev, fd, 4, wb_req_more, state);
138         if (subreq == NULL) {
139                 goto nomem;
140         }
141
142         tevent_req_set_callback(subreq, wb_req_read_done, result);
143         return result;
144  nomem:
145         TALLOC_FREE(result);
146         return NULL;
147 }
148
149 static ssize_t wb_req_more(uint8_t *buf, size_t buflen, void *private_data)
150 {
151         struct req_read_state *state = talloc_get_type_abort(
152                 private_data, struct req_read_state);
153         struct winbindd_request *req = (struct winbindd_request *)buf;
154
155         if (buflen == 4) {
156                 if (req->length != sizeof(struct winbindd_request)) {
157                         DEBUG(0, ("wb_req_read_len: Invalid request size "
158                                   "received: %d (expected %d)\n",
159                                   (int)req->length,
160                                   (int)sizeof(struct winbindd_request)));
161                         return -1;
162                 }
163                 return sizeof(struct winbindd_request) - 4;
164         }
165
166         if ((state->max_extra_data != 0)
167             && (req->extra_len > state->max_extra_data)) {
168                 DEBUG(3, ("Got request with %d bytes extra data on "
169                           "unprivileged socket\n", (int)req->extra_len));
170                 return -1;
171         }
172
173         return req->extra_len;
174 }
175
176 static void wb_req_read_done(struct tevent_req *subreq)
177 {
178         struct tevent_req *req = tevent_req_callback_data(
179                 subreq, struct tevent_req);
180         struct req_read_state *state = tevent_req_data(
181                 req, struct req_read_state);
182         int err;
183         ssize_t ret;
184         uint8_t *buf;
185
186         ret = read_packet_recv(subreq, state, &buf, &err);
187         TALLOC_FREE(subreq);
188         if (ret == -1) {
189                 tevent_req_error(req, map_wbc_err_from_errno(err));
190                 return;
191         }
192
193         state->wb_req = (struct winbindd_request *)buf;
194
195         if (state->wb_req->extra_len != 0) {
196                 state->wb_req->extra_data.data =
197                         (char *)buf + sizeof(struct winbindd_request);
198         } else {
199                 state->wb_req->extra_data.data = NULL;
200         }
201         tevent_req_done(req);
202 }
203
204 wbcErr wb_req_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
205                         struct winbindd_request **preq)
206 {
207         struct req_read_state *state = tevent_req_data(
208                 req, struct req_read_state);
209         wbcErr wbc_err;
210
211         if (tevent_req_is_wbcerr(req, &wbc_err)) {
212                 return wbc_err;
213         }
214         *preq = talloc_move(mem_ctx, &state->wb_req);
215         return WBC_ERR_SUCCESS;
216 }
217
218 struct req_write_state {
219         struct iovec iov[2];
220 };
221
222 static void wb_req_write_done(struct tevent_req *subreq);
223
224 struct tevent_req *wb_req_write_send(TALLOC_CTX *mem_ctx,
225                                      struct tevent_context *ev,
226                                      struct tevent_queue *queue, int fd,
227                                      struct winbindd_request *wb_req)
228 {
229         struct tevent_req *result, *subreq;
230         struct req_write_state *state;
231         int count = 1;
232
233         result = tevent_req_create(mem_ctx, &state, struct req_write_state);
234         if (result == NULL) {
235                 return NULL;
236         }
237
238         state->iov[0].iov_base = wb_req;
239         state->iov[0].iov_len = sizeof(struct winbindd_request);
240
241         if (wb_req->extra_len != 0) {
242                 state->iov[1].iov_base = wb_req->extra_data.data;
243                 state->iov[1].iov_len = wb_req->extra_len;
244                 count = 2;
245         }
246
247         subreq = writev_send(state, ev, queue, fd, state->iov, count);
248         if (subreq == NULL) {
249                 goto fail;
250         }
251         tevent_req_set_callback(subreq, wb_req_write_done, result);
252         return result;
253
254  fail:
255         TALLOC_FREE(result);
256         return NULL;
257 }
258
259 static void wb_req_write_done(struct tevent_req *subreq)
260 {
261         struct tevent_req *req = tevent_req_callback_data(
262                 subreq, struct tevent_req);
263         int err;
264         ssize_t ret;
265
266         ret = writev_recv(subreq, &err);
267         TALLOC_FREE(subreq);
268         if (ret < 0) {
269                 tevent_req_error(req, map_wbc_err_from_errno(err));
270                 return;
271         }
272         tevent_req_done(req);
273 }
274
275 wbcErr wb_req_write_recv(struct tevent_req *req)
276 {
277         return tevent_req_simple_recv_wbcerr(req);
278 }
279
280 struct resp_read_state {
281         struct winbindd_response *wb_resp;
282 };
283
284 static ssize_t wb_resp_more(uint8_t *buf, size_t buflen, void *private_data);
285 static void wb_resp_read_done(struct tevent_req *subreq);
286
287 struct async_req *wb_resp_read_send(TALLOC_CTX *mem_ctx,
288                                     struct tevent_context *ev, int fd)
289 {
290         struct async_req *result;
291         struct tevent_req *subreq;
292         struct resp_read_state *state;
293
294         if (!async_req_setup(mem_ctx, &result, &state,
295                              struct resp_read_state)) {
296                 return NULL;
297         }
298
299         subreq = read_packet_send(state, ev, fd, 4, wb_resp_more, state);
300         if (subreq == NULL) {
301                 goto nomem;
302         }
303         tevent_req_set_callback(subreq, wb_resp_read_done, result);
304         return result;
305
306  nomem:
307         TALLOC_FREE(result);
308         return NULL;
309 }
310
311 static ssize_t wb_resp_more(uint8_t *buf, size_t buflen, void *private_data)
312 {
313         struct winbindd_response *resp = (struct winbindd_response *)buf;
314
315         if (buflen == 4) {
316                 if (resp->length < sizeof(struct winbindd_response)) {
317                         DEBUG(0, ("wb_resp_read_len: Invalid response size "
318                                   "received: %d (expected at least%d)\n",
319                                   (int)resp->length,
320                                   (int)sizeof(struct winbindd_response)));
321                         return -1;
322                 }
323         }
324         return resp->length - buflen;
325 }
326
327 static void wb_resp_read_done(struct tevent_req *subreq)
328 {
329         struct async_req *req =
330                 tevent_req_callback_data(subreq, struct async_req);
331         struct resp_read_state *state = talloc_get_type_abort(
332                 req->private_data, struct resp_read_state);
333         uint8_t *buf;
334         int err;
335         ssize_t ret;
336
337         ret = read_packet_recv(subreq, state, &buf, &err);
338         TALLOC_FREE(subreq);
339         if (ret == -1) {
340                 async_req_error(req, map_wbc_err_from_errno(err));
341                 return;
342         }
343
344         state->wb_resp = (struct winbindd_response *)buf;
345
346         if (state->wb_resp->length > sizeof(struct winbindd_response)) {
347                 state->wb_resp->extra_data.data =
348                         (char *)buf + sizeof(struct winbindd_response);
349         } else {
350                 state->wb_resp->extra_data.data = NULL;
351         }
352         async_req_done(req);
353 }
354
355 wbcErr wb_resp_read_recv(struct async_req *req, TALLOC_CTX *mem_ctx,
356                          struct winbindd_response **presp)
357 {
358         struct resp_read_state *state = talloc_get_type_abort(
359                 req->private_data, struct resp_read_state);
360         wbcErr wbc_err;
361
362         if (async_req_is_wbcerr(req, &wbc_err)) {
363                 return wbc_err;
364         }
365         *presp = talloc_move(mem_ctx, &state->wb_resp);
366         return WBC_ERR_SUCCESS;
367 }
368
369 struct resp_write_state {
370         struct iovec iov[2];
371 };
372
373 static void wb_resp_write_done(struct tevent_req *subreq);
374
375 struct async_req *wb_resp_write_send(TALLOC_CTX *mem_ctx,
376                                     struct tevent_context *ev, int fd,
377                                     struct winbindd_response *wb_resp)
378 {
379         struct async_req *result;
380         struct tevent_req *subreq;
381         struct resp_write_state *state;
382         int count = 1;
383
384         if (!async_req_setup(mem_ctx, &result, &state,
385                              struct resp_write_state)) {
386                 return NULL;
387         }
388
389         state->iov[0].iov_base = wb_resp;
390         state->iov[0].iov_len = sizeof(struct winbindd_response);
391
392         if (wb_resp->length > sizeof(struct winbindd_response)) {
393                 state->iov[1].iov_base = wb_resp->extra_data.data;
394                 state->iov[1].iov_len =
395                         wb_resp->length - sizeof(struct winbindd_response);
396                 count = 2;
397         }
398
399         subreq = writev_send(state, ev, NULL, fd, state->iov, count);
400         if (subreq == NULL) {
401                 goto fail;
402         }
403         tevent_req_set_callback(subreq, wb_resp_write_done, result);
404         return result;
405
406  fail:
407         TALLOC_FREE(result);
408         return NULL;
409 }
410
411 static void wb_resp_write_done(struct tevent_req *subreq)
412 {
413         struct async_req *req =
414                 tevent_req_callback_data(subreq, struct async_req);
415         int err;
416         ssize_t ret;
417
418         ret = writev_recv(subreq, &err);
419         TALLOC_FREE(subreq);
420         if (ret < 0) {
421                 async_req_error(req, map_wbc_err_from_errno(err));
422                 return;
423         }
424         async_req_done(req);
425 }
426
427 wbcErr wb_resp_write_recv(struct async_req *req)
428 {
429         return async_req_simple_recv_wbcerr(req);
430 }