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