s4:lib/events: remove unused events_internal.h
[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 (async_req_nomem(subreq, req)) {
107                 return;
108         }
109
110         subreq->async.fn = wb_req_read_main;
111         subreq->async.priv = req;
112 }
113
114 static void wb_req_read_main(struct async_req *subreq)
115 {
116         struct async_req *req = talloc_get_type_abort(
117                 subreq->async.priv, struct async_req);
118         struct req_read_state *state = talloc_get_type_abort(
119                 req->private_data, struct req_read_state);
120         NTSTATUS status;
121
122         status = recvall_recv(subreq);
123         TALLOC_FREE(subreq);
124         if (!NT_STATUS_IS_OK(status)) {
125                 async_req_error(req, status);
126                 return;
127         }
128
129         if ((state->max_extra_data != 0)
130             && (state->wb_req->extra_len > state->max_extra_data)) {
131                 DEBUG(3, ("Got request with %d bytes extra data on "
132                           "unprivileged socket\n",
133                           (int)state->wb_req->extra_len));
134                 async_req_error(req, NT_STATUS_INVALID_BUFFER_SIZE);
135                 return;
136         }
137
138         if (state->wb_req->extra_len == 0) {
139                 async_req_done(req);
140                 return;
141         }
142
143         state->wb_req->extra_data.data = TALLOC_ARRAY(
144                 state->wb_req, char, state->wb_req->extra_len + 1);
145         if (async_req_nomem(state->wb_req->extra_data.data, req)) {
146                 return;
147         }
148
149         state->wb_req->extra_data.data[state->wb_req->extra_len] = 0;
150
151         subreq = recvall_send(
152                 req, state->ev, state->fd, state->wb_req->extra_data.data,
153                 state->wb_req->extra_len, 0);
154         if (async_req_nomem(subreq, req)) {
155                 return;
156         }
157
158         subreq->async.fn = wb_req_read_extra;
159         subreq->async.priv = req;
160 }
161
162 static void wb_req_read_extra(struct async_req *subreq)
163 {
164         struct async_req *req = talloc_get_type_abort(
165                 subreq->async.priv, struct async_req);
166         NTSTATUS status;
167
168         status = recvall_recv(subreq);
169         TALLOC_FREE(subreq);
170         if (!NT_STATUS_IS_OK(status)) {
171                 async_req_error(req, status);
172                 return;
173         }
174         async_req_done(req);
175 }
176
177
178 NTSTATUS wb_req_read_recv(struct async_req *req, TALLOC_CTX *mem_ctx,
179                           struct winbindd_request **preq)
180 {
181         struct req_read_state *state = talloc_get_type_abort(
182                 req->private_data, struct req_read_state);
183         NTSTATUS status;
184
185         if (async_req_is_error(req, &status)) {
186                 return status;
187         }
188         *preq = talloc_move(mem_ctx, &state->wb_req);
189         return NT_STATUS_OK;
190 }
191
192 struct req_write_state {
193         struct winbindd_request *wb_req;
194         struct event_context *ev;
195         int fd;
196 };
197
198 static void wb_req_write_main(struct async_req *subreq);
199 static void wb_req_write_extra(struct async_req *subreq);
200
201 struct async_req *wb_req_write_send(TALLOC_CTX *mem_ctx,
202                                     struct event_context *ev, int fd,
203                                     struct winbindd_request *wb_req)
204 {
205         struct async_req *result, *subreq;
206         struct req_write_state *state;
207
208         result = async_req_new(mem_ctx, ev);
209         if (result == NULL) {
210                 return NULL;
211         }
212
213         state = talloc(result, struct req_write_state);
214         if (state == NULL) {
215                 goto nomem;
216         }
217         result->private_data = state;
218
219         state->fd = fd;
220         state->ev = ev;
221         state->wb_req = wb_req;
222
223         subreq = sendall_send(state, state->ev, state->fd, state->wb_req,
224                               sizeof(struct winbindd_request), 0);
225         if (subreq == NULL) {
226                 goto nomem;
227         }
228
229         subreq->async.fn = wb_req_write_main;
230         subreq->async.priv = result;
231         return result;
232
233  nomem:
234         TALLOC_FREE(result);
235         return NULL;
236 }
237
238 static void wb_req_write_main(struct async_req *subreq)
239 {
240         struct async_req *req = talloc_get_type_abort(
241                 subreq->async.priv, struct async_req);
242         struct req_write_state *state = talloc_get_type_abort(
243                 req->private_data, struct req_write_state);
244         NTSTATUS status;
245
246         status = sendall_recv(subreq);
247         TALLOC_FREE(subreq);
248         if (!NT_STATUS_IS_OK(status)) {
249                 async_req_error(req, status);
250                 return;
251         }
252
253         if (state->wb_req->extra_len == 0) {
254                 async_req_done(req);
255                 return;
256         }
257
258         subreq = sendall_send(state, state->ev, state->fd,
259                               state->wb_req->extra_data.data,
260                               state->wb_req->extra_len, 0);
261         if (async_req_nomem(subreq, req)) {
262                 return;
263         }
264
265         subreq->async.fn = wb_req_write_extra;
266         subreq->async.priv = req;
267 }
268
269 static void wb_req_write_extra(struct async_req *subreq)
270 {
271         struct async_req *req = talloc_get_type_abort(
272                 subreq->async.priv, struct async_req);
273         NTSTATUS status;
274
275         status = sendall_recv(subreq);
276         TALLOC_FREE(subreq);
277         if (!NT_STATUS_IS_OK(status)) {
278                 async_req_error(req, status);
279                 return;
280         }
281
282         async_req_done(req);
283 }
284
285 NTSTATUS wb_req_write_recv(struct async_req *req)
286 {
287         return async_req_simple_recv(req);
288 }
289
290 struct resp_read_state {
291         struct winbindd_response *wb_resp;
292         struct event_context *ev;
293         size_t max_extra_data;
294         int fd;
295 };
296
297 static void wb_resp_read_len(struct async_req *subreq);
298 static void wb_resp_read_main(struct async_req *subreq);
299 static void wb_resp_read_extra(struct async_req *subreq);
300
301 struct async_req *wb_resp_read_send(TALLOC_CTX *mem_ctx,
302                                     struct event_context *ev, int fd)
303 {
304         struct async_req *result, *subreq;
305         struct resp_read_state *state;
306
307         result = async_req_new(mem_ctx, ev);
308         if (result == NULL) {
309                 return NULL;
310         }
311
312         state = talloc(result, struct resp_read_state);
313         if (state == NULL) {
314                 goto nomem;
315         }
316         result->private_data = state;
317
318         state->fd = fd;
319         state->ev = ev;
320         state->wb_resp = talloc(state, struct winbindd_response);
321         if (state->wb_resp == NULL) {
322                 goto nomem;
323         }
324
325         subreq = recvall_send(state, ev, state->fd, &(state->wb_resp->length),
326                               sizeof(state->wb_resp->length), 0);
327         if (subreq == NULL) {
328                 goto nomem;
329         }
330
331         subreq->async.fn = wb_resp_read_len;
332         subreq->async.priv = result;
333         return result;
334
335  nomem:
336         TALLOC_FREE(result);
337         return NULL;
338 }
339
340 static void wb_resp_read_len(struct async_req *subreq)
341 {
342         struct async_req *req = talloc_get_type_abort(
343                 subreq->async.priv, struct async_req);
344         struct resp_read_state *state = talloc_get_type_abort(
345                 req->private_data, struct resp_read_state);
346         NTSTATUS status;
347
348         status = recvall_recv(subreq);
349         TALLOC_FREE(subreq);
350         if (!NT_STATUS_IS_OK(status)) {
351                 async_req_error(req, status);
352                 return;
353         }
354
355         if (state->wb_resp->length < sizeof(struct winbindd_response)) {
356                 DEBUG(0, ("wb_resp_read_len: Invalid response size received: "
357                           "%d (expected at least%d)\n",
358                           (int)state->wb_resp->length,
359                           (int)sizeof(struct winbindd_response)));
360                 async_req_error(req, NT_STATUS_INVALID_BUFFER_SIZE);
361                 return;
362         }
363
364         subreq = recvall_send(
365                 req, state->ev, state->fd, (uint32 *)(state->wb_resp)+1,
366                 sizeof(struct winbindd_response) - sizeof(uint32), 0);
367         if (async_req_nomem(subreq, req)) {
368                 return;
369         }
370
371         subreq->async.fn = wb_resp_read_main;
372         subreq->async.priv = req;
373 }
374
375 static void wb_resp_read_main(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         NTSTATUS status;
382         size_t extra_len;
383
384         status = recvall_recv(subreq);
385         TALLOC_FREE(subreq);
386         if (!NT_STATUS_IS_OK(status)) {
387                 async_req_error(req, status);
388                 return;
389         }
390
391         extra_len = state->wb_resp->length - sizeof(struct winbindd_response);
392         if (extra_len == 0) {
393                 async_req_done(req);
394                 return;
395         }
396
397         state->wb_resp->extra_data.data = TALLOC_ARRAY(
398                 state->wb_resp, char, extra_len+1);
399         if (async_req_nomem(state->wb_resp->extra_data.data, req)) {
400                 return;
401         }
402         ((char *)state->wb_resp->extra_data.data)[extra_len] = 0;
403
404         subreq = recvall_send(
405                 req, state->ev, state->fd, state->wb_resp->extra_data.data,
406                 extra_len, 0);
407         if (async_req_nomem(subreq, req)) {
408                 return;
409         }
410
411         subreq->async.fn = wb_resp_read_extra;
412         subreq->async.priv = req;
413 }
414
415 static void wb_resp_read_extra(struct async_req *subreq)
416 {
417         struct async_req *req = talloc_get_type_abort(
418                 subreq->async.priv, struct async_req);
419         NTSTATUS status;
420
421         status = recvall_recv(subreq);
422         TALLOC_FREE(subreq);
423         if (!NT_STATUS_IS_OK(status)) {
424                 async_req_error(req, status);
425                 return;
426         }
427         async_req_done(req);
428 }
429
430
431 NTSTATUS wb_resp_read_recv(struct async_req *req, TALLOC_CTX *mem_ctx,
432                            struct winbindd_response **presp)
433 {
434         struct resp_read_state *state = talloc_get_type_abort(
435                 req->private_data, struct resp_read_state);
436         NTSTATUS status;
437
438         if (async_req_is_error(req, &status)) {
439                 return status;
440         }
441         *presp = talloc_move(mem_ctx, &state->wb_resp);
442         return NT_STATUS_OK;
443 }
444
445 struct resp_write_state {
446         struct winbindd_response *wb_resp;
447         struct event_context *ev;
448         int fd;
449 };
450
451 static void wb_resp_write_main(struct async_req *subreq);
452 static void wb_resp_write_extra(struct async_req *subreq);
453
454 struct async_req *wb_resp_write_send(TALLOC_CTX *mem_ctx,
455                                     struct event_context *ev, int fd,
456                                     struct winbindd_response *wb_resp)
457 {
458         struct async_req *result, *subreq;
459         struct resp_write_state *state;
460
461         result = async_req_new(mem_ctx, ev);
462         if (result == NULL) {
463                 return NULL;
464         }
465
466         state = talloc(result, struct resp_write_state);
467         if (state == NULL) {
468                 goto nomem;
469         }
470         result->private_data = state;
471
472         state->fd = fd;
473         state->ev = ev;
474         state->wb_resp = wb_resp;
475
476         subreq = sendall_send(state, state->ev, state->fd, state->wb_resp,
477                               sizeof(struct winbindd_response), 0);
478         if (subreq == NULL) {
479                 goto nomem;
480         }
481
482         subreq->async.fn = wb_resp_write_main;
483         subreq->async.priv = result;
484         return result;
485
486  nomem:
487         TALLOC_FREE(result);
488         return NULL;
489 }
490
491 static void wb_resp_write_main(struct async_req *subreq)
492 {
493         struct async_req *req = talloc_get_type_abort(
494                 subreq->async.priv, struct async_req);
495         struct resp_write_state *state = talloc_get_type_abort(
496                 req->private_data, struct resp_write_state);
497         NTSTATUS status;
498
499         status = sendall_recv(subreq);
500         TALLOC_FREE(subreq);
501         if (!NT_STATUS_IS_OK(status)) {
502                 async_req_error(req, status);
503                 return;
504         }
505
506         if (state->wb_resp->length == sizeof(struct winbindd_response)) {
507                 async_req_done(req);
508                 return;
509         }
510
511         subreq = sendall_send(
512                 state, state->ev, state->fd,
513                 state->wb_resp->extra_data.data,
514                 state->wb_resp->length - sizeof(struct winbindd_response), 0);
515         if (async_req_nomem(subreq, req)) {
516                 return;
517         }
518
519         subreq->async.fn = wb_resp_write_extra;
520         subreq->async.priv = req;
521 }
522
523 static void wb_resp_write_extra(struct async_req *subreq)
524 {
525         struct async_req *req = talloc_get_type_abort(
526                 subreq->async.priv, struct async_req);
527         NTSTATUS status;
528
529         status = sendall_recv(subreq);
530         TALLOC_FREE(subreq);
531         if (!NT_STATUS_IS_OK(status)) {
532                 async_req_error(req, status);
533                 return;
534         }
535
536         async_req_done(req);
537 }
538
539 NTSTATUS wb_resp_write_recv(struct async_req *req)
540 {
541         return async_req_simple_recv(req);
542 }
543
544 struct wb_trans_state {
545         struct event_context *ev;
546         struct timed_event *te;
547         int fd;
548         struct winbindd_response *wb_resp;
549         size_t reply_max_extra_data;
550 };
551
552 static void wb_trans_timeout(struct event_context *ev, struct timed_event *te,
553                              const struct timeval *now, void *priv);
554 static void wb_trans_sent(struct async_req *req);
555 static void wb_trans_received(struct async_req *req);
556
557 struct async_req *wb_trans_send(TALLOC_CTX *mem_ctx,
558                                 struct event_context *ev,
559                                 int fd,
560                                 struct winbindd_request *wb_req,
561                                 struct timeval timeout,
562                                 size_t reply_max_extra_data)
563 {
564         struct async_req *result, *subreq;
565         struct wb_trans_state *state;
566
567         result = async_req_new(mem_ctx, ev);
568         if (result == NULL) {
569                 return NULL;
570         }
571
572         state = talloc(result, struct wb_trans_state);
573         if (state == NULL) {
574                 goto nomem;
575         }
576         result->private_data = state;
577
578         state->ev = ev;
579         state->fd = fd;
580         state->reply_max_extra_data = reply_max_extra_data;
581
582         state->te = event_add_timed(
583                 ev, state,
584                 timeval_current_ofs(timeout.tv_sec, timeout.tv_usec),
585                 "wb_trans_timeout", wb_trans_timeout, result);
586         if (state->te == NULL) {
587                 goto nomem;
588         }
589
590         subreq = wb_req_write_send(state, state->ev, state->fd, wb_req);
591         if (subreq == NULL) {
592                 goto nomem;
593         }
594         subreq->async.fn = wb_trans_sent;
595         subreq->async.priv = result;
596
597         return result;
598
599  nomem:
600         TALLOC_FREE(result);
601         return NULL;
602 }
603
604 static void wb_trans_timeout(struct event_context *ev, struct timed_event *te,
605                              const struct timeval *now, void *priv)
606 {
607         struct async_req *req = talloc_get_type_abort(
608                 priv, struct async_req);
609         struct wb_trans_state *state = talloc_get_type_abort(
610                 req->private_data, struct wb_trans_state);
611
612         TALLOC_FREE(state->te);
613         async_req_error(req, NT_STATUS_IO_TIMEOUT);
614 }
615
616 static void wb_trans_sent(struct async_req *subreq)
617 {
618         struct async_req *req = talloc_get_type_abort(
619                 subreq->async.priv, struct async_req);
620         struct wb_trans_state *state = talloc_get_type_abort(
621                 req->private_data, struct wb_trans_state);
622         NTSTATUS status;
623
624         status = wb_req_write_recv(subreq);
625         TALLOC_FREE(subreq);
626         if (!NT_STATUS_IS_OK(status)) {
627                 async_req_error(req, status);
628                 return;
629         }
630
631         subreq = wb_resp_read_send(state, state->ev, state->fd);
632         if (async_req_nomem(subreq, req)) {
633                 return;
634         }
635
636         subreq->async.fn = wb_trans_received;
637         subreq->async.priv = req;
638 };
639
640 static void wb_trans_received(struct async_req *subreq)
641 {
642         struct async_req *req = talloc_get_type_abort(
643                 subreq->async.priv, struct async_req);
644         struct wb_trans_state *state = talloc_get_type_abort(
645                 req->private_data, struct wb_trans_state);
646         NTSTATUS status;
647
648         TALLOC_FREE(state->te);
649
650         status = wb_resp_read_recv(subreq, state, &state->wb_resp);
651         TALLOC_FREE(subreq);
652         if (!NT_STATUS_IS_OK(status)) {
653                 async_req_error(req, status);
654                 return;
655         }
656
657         async_req_done(req);
658 }
659
660 NTSTATUS wb_trans_recv(struct async_req *req, TALLOC_CTX *mem_ctx,
661                        struct winbindd_response **presp)
662 {
663         struct wb_trans_state *state = talloc_get_type_abort(
664                 req->private_data, struct wb_trans_state);
665         NTSTATUS status;
666
667         if (async_req_is_error(req, &status)) {
668                 return status;
669         }
670         *presp = talloc_move(mem_ctx, &state->wb_resp);
671         return NT_STATUS_OK;
672 }
673
674 struct wb_trans_queue_state {
675         struct wb_trans_queue_state *prev, *next;
676         struct wb_trans_queue *queue;
677         struct winbindd_request *req;
678 };
679
680 struct wb_trans_queue {
681         int fd;
682         struct timeval timeout;
683         size_t max_resp_extra_data;
684         struct wb_trans_queue_state *queued_requests;
685 };