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