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