async_sock: Use unix errnos instead of NTSTATUS
[gd/samba-autobuild/.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         struct tevent_context *ev;
31         size_t max_extra_data;
32         int fd;
33 };
34
35 bool async_req_is_wbcerr(struct async_req *req, wbcErr *pwbc_err)
36 {
37         enum async_req_state state;
38         uint64_t error;
39         if (!async_req_is_error(req, &state, &error)) {
40                 *pwbc_err = WBC_ERR_SUCCESS;
41                 return false;
42         }
43
44         switch (state) {
45         case ASYNC_REQ_USER_ERROR:
46                 *pwbc_err = error;
47                 break;
48         case ASYNC_REQ_TIMED_OUT:
49                 *pwbc_err = WBC_ERR_UNKNOWN_FAILURE;
50                 break;
51         case ASYNC_REQ_NO_MEMORY:
52                 *pwbc_err = WBC_ERR_NO_MEMORY;
53                 break;
54         default:
55                 *pwbc_err = WBC_ERR_UNKNOWN_FAILURE;
56                 break;
57         }
58         return true;
59 }
60
61 wbcErr map_wbc_err_from_errno(int error)
62 {
63         switch(error) {
64         case EPERM:
65         case EACCES:
66                 return WBC_ERR_AUTH_ERROR;
67         case ENOMEM:
68                 return WBC_ERR_NO_MEMORY;
69         case EIO:
70         default:
71                 return WBC_ERR_UNKNOWN_FAILURE;
72         }
73 }
74
75 wbcErr async_req_simple_recv_wbcerr(struct async_req *req)
76 {
77         wbcErr wbc_err;
78
79         if (async_req_is_wbcerr(req, &wbc_err)) {
80                 return wbc_err;
81         }
82
83         return WBC_ERR_SUCCESS;
84 }
85
86 static void wb_req_read_len(struct async_req *subreq);
87 static void wb_req_read_main(struct async_req *subreq);
88 static void wb_req_read_extra(struct async_req *subreq);
89
90 struct async_req *wb_req_read_send(TALLOC_CTX *mem_ctx,
91                                    struct tevent_context *ev,
92                                    int fd, size_t max_extra_data)
93 {
94         struct async_req *result, *subreq;
95         struct req_read_state *state;
96
97         if (!async_req_setup(mem_ctx, &result, &state,
98                              struct req_read_state)) {
99                 return NULL;
100         }
101         state->fd = fd;
102         state->ev = ev;
103         state->max_extra_data = max_extra_data;
104         state->wb_req = talloc(state, struct winbindd_request);
105         if (state->wb_req == NULL) {
106                 goto nomem;
107         }
108
109         subreq = recvall_send(state, ev, state->fd, &(state->wb_req->length),
110                               sizeof(state->wb_req->length), 0);
111         if (subreq == NULL) {
112                 goto nomem;
113         }
114
115         subreq->async.fn = wb_req_read_len;
116         subreq->async.priv = result;
117         return result;
118
119  nomem:
120         TALLOC_FREE(result);
121         return NULL;
122 }
123
124 static void wb_req_read_len(struct async_req *subreq)
125 {
126         struct async_req *req = talloc_get_type_abort(
127                 subreq->async.priv, struct async_req);
128         struct req_read_state *state = talloc_get_type_abort(
129                 req->private_data, struct req_read_state);
130         int err;
131         ssize_t ret;
132
133         ret = recvall_recv(subreq, &err);
134         TALLOC_FREE(subreq);
135         if (ret < 0) {
136                 async_req_error(req, map_wbc_err_from_errno(err));
137                 return;
138         }
139
140         if (state->wb_req->length != sizeof(struct winbindd_request)) {
141                 DEBUG(0, ("wb_req_read_len: Invalid request size received: "
142                           "%d (expected %d)\n", (int)state->wb_req->length,
143                           (int)sizeof(struct winbindd_request)));
144                 async_req_error(req, WBC_ERR_INVALID_RESPONSE);
145                 return;
146         }
147
148         subreq = recvall_send(
149                 req, state->ev, state->fd, (uint32 *)(state->wb_req)+1,
150                 sizeof(struct winbindd_request) - sizeof(uint32), 0);
151         if (async_req_nomem(subreq, req)) {
152                 return;
153         }
154
155         subreq->async.fn = wb_req_read_main;
156         subreq->async.priv = req;
157 }
158
159 static void wb_req_read_main(struct async_req *subreq)
160 {
161         struct async_req *req = talloc_get_type_abort(
162                 subreq->async.priv, struct async_req);
163         struct req_read_state *state = talloc_get_type_abort(
164                 req->private_data, struct req_read_state);
165         int err;
166         ssize_t ret;
167
168         ret = recvall_recv(subreq, &err);
169         TALLOC_FREE(subreq);
170         if (ret < 0) {
171                 async_req_error(req, map_wbc_err_from_errno(err));
172                 return;
173         }
174
175         if ((state->max_extra_data != 0)
176             && (state->wb_req->extra_len > state->max_extra_data)) {
177                 DEBUG(3, ("Got request with %d bytes extra data on "
178                           "unprivileged socket\n",
179                           (int)state->wb_req->extra_len));
180                 async_req_error(req, WBC_ERR_INVALID_RESPONSE);
181                 return;
182         }
183
184         if (state->wb_req->extra_len == 0) {
185                 async_req_done(req);
186                 return;
187         }
188
189         state->wb_req->extra_data.data = TALLOC_ARRAY(
190                 state->wb_req, char, state->wb_req->extra_len + 1);
191         if (async_req_nomem(state->wb_req->extra_data.data, req)) {
192                 return;
193         }
194
195         state->wb_req->extra_data.data[state->wb_req->extra_len] = 0;
196
197         subreq = recvall_send(
198                 req, state->ev, state->fd, state->wb_req->extra_data.data,
199                 state->wb_req->extra_len, 0);
200         if (async_req_nomem(subreq, req)) {
201                 return;
202         }
203
204         subreq->async.fn = wb_req_read_extra;
205         subreq->async.priv = req;
206 }
207
208 static void wb_req_read_extra(struct async_req *subreq)
209 {
210         struct async_req *req = talloc_get_type_abort(
211                 subreq->async.priv, struct async_req);
212         int err;
213         ssize_t ret;
214
215         ret = recvall_recv(subreq, &err);
216         TALLOC_FREE(subreq);
217         if (ret < 0) {
218                 async_req_error(req, map_wbc_err_from_errno(err));
219                 return;
220         }
221         async_req_done(req);
222 }
223
224
225 wbcErr wb_req_read_recv(struct async_req *req, TALLOC_CTX *mem_ctx,
226                         struct winbindd_request **preq)
227 {
228         struct req_read_state *state = talloc_get_type_abort(
229                 req->private_data, struct req_read_state);
230         wbcErr wbc_err;
231
232         if (async_req_is_wbcerr(req, &wbc_err)) {
233                 return wbc_err;
234         }
235         *preq = talloc_move(mem_ctx, &state->wb_req);
236         return WBC_ERR_SUCCESS;
237 }
238
239 struct req_write_state {
240         struct winbindd_request *wb_req;
241         struct tevent_context *ev;
242         int fd;
243 };
244
245 static void wb_req_write_main(struct async_req *subreq);
246 static void wb_req_write_extra(struct async_req *subreq);
247
248 struct async_req *wb_req_write_send(TALLOC_CTX *mem_ctx,
249                                     struct tevent_context *ev, int fd,
250                                     struct winbindd_request *wb_req)
251 {
252         struct async_req *result, *subreq;
253         struct req_write_state *state;
254
255         if (!async_req_setup(mem_ctx, &result, &state,
256                              struct req_write_state)) {
257                 return NULL;
258         }
259         state->fd = fd;
260         state->ev = ev;
261         state->wb_req = wb_req;
262
263         subreq = sendall_send(state, state->ev, state->fd, state->wb_req,
264                               sizeof(struct winbindd_request), 0);
265         if (subreq == NULL) {
266                 goto nomem;
267         }
268
269         subreq->async.fn = wb_req_write_main;
270         subreq->async.priv = result;
271         return result;
272
273  nomem:
274         TALLOC_FREE(result);
275         return NULL;
276 }
277
278 static void wb_req_write_main(struct async_req *subreq)
279 {
280         struct async_req *req = talloc_get_type_abort(
281                 subreq->async.priv, struct async_req);
282         struct req_write_state *state = talloc_get_type_abort(
283                 req->private_data, struct req_write_state);
284         int err;
285         ssize_t ret;
286
287         ret = sendall_recv(subreq, &err);
288         TALLOC_FREE(subreq);
289         if (ret < 0) {
290                 async_req_error(req, map_wbc_err_from_errno(err));
291                 return;
292         }
293
294         if (state->wb_req->extra_len == 0) {
295                 async_req_done(req);
296                 return;
297         }
298
299         subreq = sendall_send(state, state->ev, state->fd,
300                               state->wb_req->extra_data.data,
301                               state->wb_req->extra_len, 0);
302         if (async_req_nomem(subreq, req)) {
303                 return;
304         }
305
306         subreq->async.fn = wb_req_write_extra;
307         subreq->async.priv = req;
308 }
309
310 static void wb_req_write_extra(struct async_req *subreq)
311 {
312         struct async_req *req = talloc_get_type_abort(
313                 subreq->async.priv, struct async_req);
314         int err;
315         ssize_t ret;
316
317         ret = sendall_recv(subreq, &err);
318         TALLOC_FREE(subreq);
319         if (ret < 0) {
320                 async_req_error(req, map_wbc_err_from_errno(err));
321                 return;
322         }
323
324         async_req_done(req);
325 }
326
327 wbcErr wb_req_write_recv(struct async_req *req)
328 {
329         return async_req_simple_recv_wbcerr(req);
330 }
331
332 struct resp_read_state {
333         struct winbindd_response *wb_resp;
334         struct tevent_context *ev;
335         size_t max_extra_data;
336         int fd;
337 };
338
339 static void wb_resp_read_len(struct async_req *subreq);
340 static void wb_resp_read_main(struct async_req *subreq);
341 static void wb_resp_read_extra(struct async_req *subreq);
342
343 struct async_req *wb_resp_read_send(TALLOC_CTX *mem_ctx,
344                                     struct tevent_context *ev, int fd)
345 {
346         struct async_req *result, *subreq;
347         struct resp_read_state *state;
348
349         if (!async_req_setup(mem_ctx, &result, &state,
350                              struct resp_read_state)) {
351                 return NULL;
352         }
353         state->fd = fd;
354         state->ev = ev;
355         state->wb_resp = talloc(state, struct winbindd_response);
356         if (state->wb_resp == NULL) {
357                 goto nomem;
358         }
359
360         subreq = recvall_send(state, ev, state->fd, &(state->wb_resp->length),
361                               sizeof(state->wb_resp->length), 0);
362         if (subreq == NULL) {
363                 goto nomem;
364         }
365
366         subreq->async.fn = wb_resp_read_len;
367         subreq->async.priv = result;
368         return result;
369
370  nomem:
371         TALLOC_FREE(result);
372         return NULL;
373 }
374
375 static void wb_resp_read_len(struct async_req *subreq)
376 {
377         struct async_req *req = talloc_get_type_abort(
378                 subreq->async.priv, struct async_req);
379         struct resp_read_state *state = talloc_get_type_abort(
380                 req->private_data, struct resp_read_state);
381         int err;
382         ssize_t ret;
383
384         ret = recvall_recv(subreq, &err);
385         TALLOC_FREE(subreq);
386         if (ret < 0) {
387                 async_req_error(req, map_wbc_err_from_errno(err));
388                 return;
389         }
390
391         if (state->wb_resp->length < sizeof(struct winbindd_response)) {
392                 DEBUG(0, ("wb_resp_read_len: Invalid response size received: "
393                           "%d (expected at least%d)\n",
394                           (int)state->wb_resp->length,
395                           (int)sizeof(struct winbindd_response)));
396                 async_req_error(req, WBC_ERR_INVALID_RESPONSE);
397                 return;
398         }
399
400         subreq = recvall_send(
401                 req, state->ev, state->fd, (uint32 *)(state->wb_resp)+1,
402                 sizeof(struct winbindd_response) - sizeof(uint32), 0);
403         if (async_req_nomem(subreq, req)) {
404                 return;
405         }
406
407         subreq->async.fn = wb_resp_read_main;
408         subreq->async.priv = req;
409 }
410
411 static void wb_resp_read_main(struct async_req *subreq)
412 {
413         struct async_req *req = talloc_get_type_abort(
414                 subreq->async.priv, struct async_req);
415         struct resp_read_state *state = talloc_get_type_abort(
416                 req->private_data, struct resp_read_state);
417         int err;
418         ssize_t ret;
419         size_t extra_len;
420
421         ret = recvall_recv(subreq, &err);
422         TALLOC_FREE(subreq);
423         if (ret < 0) {
424                 async_req_error(req, map_wbc_err_from_errno(err));
425                 return;
426         }
427
428         extra_len = state->wb_resp->length - sizeof(struct winbindd_response);
429         if (extra_len == 0) {
430                 async_req_done(req);
431                 return;
432         }
433
434         state->wb_resp->extra_data.data = TALLOC_ARRAY(
435                 state->wb_resp, char, extra_len+1);
436         if (async_req_nomem(state->wb_resp->extra_data.data, req)) {
437                 return;
438         }
439         ((char *)state->wb_resp->extra_data.data)[extra_len] = 0;
440
441         subreq = recvall_send(
442                 req, state->ev, state->fd, state->wb_resp->extra_data.data,
443                 extra_len, 0);
444         if (async_req_nomem(subreq, req)) {
445                 return;
446         }
447
448         subreq->async.fn = wb_resp_read_extra;
449         subreq->async.priv = req;
450 }
451
452 static void wb_resp_read_extra(struct async_req *subreq)
453 {
454         struct async_req *req = talloc_get_type_abort(
455                 subreq->async.priv, struct async_req);
456         int err;
457         ssize_t ret;
458
459         ret = recvall_recv(subreq, &err);
460         TALLOC_FREE(subreq);
461         if (ret < 0) {
462                 async_req_error(req, map_wbc_err_from_errno(err));
463                 return;
464         }
465         async_req_done(req);
466 }
467
468
469 wbcErr wb_resp_read_recv(struct async_req *req, TALLOC_CTX *mem_ctx,
470                          struct winbindd_response **presp)
471 {
472         struct resp_read_state *state = talloc_get_type_abort(
473                 req->private_data, struct resp_read_state);
474         wbcErr wbc_err;
475
476         if (async_req_is_wbcerr(req, &wbc_err)) {
477                 return wbc_err;
478         }
479         *presp = talloc_move(mem_ctx, &state->wb_resp);
480         return WBC_ERR_SUCCESS;
481 }
482
483 struct resp_write_state {
484         struct winbindd_response *wb_resp;
485         struct tevent_context *ev;
486         int fd;
487 };
488
489 static void wb_resp_write_main(struct async_req *subreq);
490 static void wb_resp_write_extra(struct async_req *subreq);
491
492 struct async_req *wb_resp_write_send(TALLOC_CTX *mem_ctx,
493                                     struct tevent_context *ev, int fd,
494                                     struct winbindd_response *wb_resp)
495 {
496         struct async_req *result, *subreq;
497         struct resp_write_state *state;
498
499         if (!async_req_setup(mem_ctx, &result, &state,
500                              struct resp_write_state)) {
501                 return NULL;
502         }
503         state->fd = fd;
504         state->ev = ev;
505         state->wb_resp = wb_resp;
506
507         subreq = sendall_send(state, state->ev, state->fd, state->wb_resp,
508                               sizeof(struct winbindd_response), 0);
509         if (subreq == NULL) {
510                 goto nomem;
511         }
512
513         subreq->async.fn = wb_resp_write_main;
514         subreq->async.priv = result;
515         return result;
516
517  nomem:
518         TALLOC_FREE(result);
519         return NULL;
520 }
521
522 static void wb_resp_write_main(struct async_req *subreq)
523 {
524         struct async_req *req = talloc_get_type_abort(
525                 subreq->async.priv, struct async_req);
526         struct resp_write_state *state = talloc_get_type_abort(
527                 req->private_data, struct resp_write_state);
528         int err;
529         ssize_t ret;
530
531         ret = sendall_recv(subreq, &err);
532         TALLOC_FREE(subreq);
533         if (ret < 0) {
534                 async_req_error(req, map_wbc_err_from_errno(err));
535                 return;
536         }
537
538         if (state->wb_resp->length == sizeof(struct winbindd_response)) {
539                 async_req_done(req);
540                 return;
541         }
542
543         subreq = sendall_send(
544                 state, state->ev, state->fd,
545                 state->wb_resp->extra_data.data,
546                 state->wb_resp->length - sizeof(struct winbindd_response), 0);
547         if (async_req_nomem(subreq, req)) {
548                 return;
549         }
550
551         subreq->async.fn = wb_resp_write_extra;
552         subreq->async.priv = req;
553 }
554
555 static void wb_resp_write_extra(struct async_req *subreq)
556 {
557         struct async_req *req = talloc_get_type_abort(
558                 subreq->async.priv, struct async_req);
559         int err;
560         ssize_t ret;
561
562         ret = sendall_recv(subreq, &err);
563         TALLOC_FREE(subreq);
564         if (err < 0) {
565                 async_req_error(req, map_wbc_err_from_errno(err));
566                 return;
567         }
568
569         async_req_done(req);
570 }
571
572 wbcErr wb_resp_write_recv(struct async_req *req)
573 {
574         return async_req_simple_recv_wbcerr(req);
575 }