2 Unix SMB/CIFS implementation.
4 Async transfer of winbindd_request and _response structs
6 Copyright (C) Volker Lendecke 2008
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.
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.
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/>.
23 #include "wbc_async.h"
26 #define DBGC_CLASS DBGC_WINBIND
28 struct req_read_state
{
29 struct winbindd_request
*wb_req
;
30 size_t max_extra_data
;
34 static ssize_t
wb_req_more(uint8_t *buf
, size_t buflen
, void *private_data
);
35 static void wb_req_read_done(struct tevent_req
*subreq
);
37 struct tevent_req
*wb_req_read_send(TALLOC_CTX
*mem_ctx
,
38 struct tevent_context
*ev
,
39 int fd
, size_t max_extra_data
)
41 struct tevent_req
*req
, *subreq
;
42 struct req_read_state
*state
;
44 req
= tevent_req_create(mem_ctx
, &state
, struct req_read_state
);
48 state
->max_extra_data
= max_extra_data
;
50 subreq
= read_packet_send(state
, ev
, fd
, 4, wb_req_more
, state
);
51 if (tevent_req_nomem(subreq
, req
)) {
52 return tevent_req_post(req
, ev
);
54 tevent_req_set_callback(subreq
, wb_req_read_done
, req
);
58 static ssize_t
wb_req_more(uint8_t *buf
, size_t buflen
, void *private_data
)
60 struct req_read_state
*state
= talloc_get_type_abort(
61 private_data
, struct req_read_state
);
62 struct winbindd_request
*req
= (struct winbindd_request
*)buf
;
65 if (req
->length
!= sizeof(struct winbindd_request
)) {
66 DEBUG(0, ("wb_req_read_len: Invalid request size "
67 "received: %d (expected %d)\n",
69 (int)sizeof(struct winbindd_request
)));
72 return sizeof(struct winbindd_request
) - 4;
75 if ((state
->max_extra_data
!= 0)
76 && (req
->extra_len
> state
->max_extra_data
)) {
77 DEBUG(3, ("Got request with %d bytes extra data on "
78 "unprivileged socket\n", (int)req
->extra_len
));
82 return req
->extra_len
;
85 static void wb_req_read_done(struct tevent_req
*subreq
)
87 struct tevent_req
*req
= tevent_req_callback_data(
88 subreq
, struct tevent_req
);
89 struct req_read_state
*state
= tevent_req_data(
90 req
, struct req_read_state
);
94 state
->ret
= read_packet_recv(subreq
, state
, &buf
, &err
);
96 if (state
->ret
== -1) {
97 tevent_req_error(req
, err
);
101 state
->wb_req
= (struct winbindd_request
*)buf
;
103 if (state
->wb_req
->extra_len
!= 0) {
104 state
->wb_req
->extra_data
.data
=
105 (char *)buf
+ sizeof(struct winbindd_request
);
107 state
->wb_req
->extra_data
.data
= NULL
;
109 tevent_req_done(req
);
112 ssize_t
wb_req_read_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
113 struct winbindd_request
**preq
, int *err
)
115 struct req_read_state
*state
= tevent_req_data(
116 req
, struct req_read_state
);
118 if (tevent_req_is_unix_error(req
, err
)) {
121 *preq
= talloc_move(mem_ctx
, &state
->wb_req
);
125 struct req_write_state
{
130 static void wb_req_write_done(struct tevent_req
*subreq
);
132 struct tevent_req
*wb_req_write_send(TALLOC_CTX
*mem_ctx
,
133 struct tevent_context
*ev
,
134 struct tevent_queue
*queue
, int fd
,
135 struct winbindd_request
*wb_req
)
137 struct tevent_req
*req
, *subreq
;
138 struct req_write_state
*state
;
141 req
= tevent_req_create(mem_ctx
, &state
, struct req_write_state
);
146 state
->iov
[0].iov_base
= wb_req
;
147 state
->iov
[0].iov_len
= sizeof(struct winbindd_request
);
149 if (wb_req
->extra_len
!= 0) {
150 state
->iov
[1].iov_base
= wb_req
->extra_data
.data
;
151 state
->iov
[1].iov_len
= wb_req
->extra_len
;
155 subreq
= writev_send(state
, ev
, queue
, fd
, state
->iov
, count
);
156 if (tevent_req_nomem(subreq
, req
)) {
157 return tevent_req_post(req
, ev
);
159 tevent_req_set_callback(subreq
, wb_req_write_done
, req
);
163 static void wb_req_write_done(struct tevent_req
*subreq
)
165 struct tevent_req
*req
= tevent_req_callback_data(
166 subreq
, struct tevent_req
);
167 struct req_write_state
*state
= tevent_req_data(
168 req
, struct req_write_state
);
171 state
->ret
= writev_recv(subreq
, &err
);
173 * We do not TALLOC_FREE(subreq) here, as this would trigger the next
174 * write of a client. The winbind protocol is purely request/response
175 * without multiplex ID's, so having multiple requeusts on the fly
176 * would confuse sequencing.
178 * Eventually the writev_req will be freed, "subreq" a child of "req"
180 if (state
->ret
< 0) {
181 tevent_req_error(req
, err
);
184 tevent_req_done(req
);
187 ssize_t
wb_req_write_recv(struct tevent_req
*req
, int *err
)
189 struct req_write_state
*state
= tevent_req_data(
190 req
, struct req_write_state
);
192 if (tevent_req_is_unix_error(req
, err
)) {
198 struct resp_read_state
{
199 struct winbindd_response
*wb_resp
;
203 static ssize_t
wb_resp_more(uint8_t *buf
, size_t buflen
, void *private_data
);
204 static void wb_resp_read_done(struct tevent_req
*subreq
);
206 struct tevent_req
*wb_resp_read_send(TALLOC_CTX
*mem_ctx
,
207 struct tevent_context
*ev
, int fd
)
209 struct tevent_req
*req
, *subreq
;
210 struct resp_read_state
*state
;
212 req
= tevent_req_create(mem_ctx
, &state
, struct resp_read_state
);
217 subreq
= read_packet_send(state
, ev
, fd
, 4, wb_resp_more
, state
);
218 if (tevent_req_nomem(subreq
, req
)) {
219 return tevent_req_post(req
, ev
);
221 tevent_req_set_callback(subreq
, wb_resp_read_done
, req
);
225 static ssize_t
wb_resp_more(uint8_t *buf
, size_t buflen
, void *private_data
)
227 struct winbindd_response
*resp
= (struct winbindd_response
*)buf
;
230 if (resp
->length
< sizeof(struct winbindd_response
)) {
231 DEBUG(0, ("wb_resp_read_len: Invalid response size "
232 "received: %d (expected at least%d)\n",
234 (int)sizeof(struct winbindd_response
)));
238 return resp
->length
- buflen
;
241 static void wb_resp_read_done(struct tevent_req
*subreq
)
243 struct tevent_req
*req
= tevent_req_callback_data(
244 subreq
, struct tevent_req
);
245 struct resp_read_state
*state
= tevent_req_data(
246 req
, struct resp_read_state
);
250 state
->ret
= read_packet_recv(subreq
, state
, &buf
, &err
);
252 if (state
->ret
== -1) {
253 tevent_req_error(req
, err
);
257 state
->wb_resp
= (struct winbindd_response
*)buf
;
259 if (state
->wb_resp
->length
> sizeof(struct winbindd_response
)) {
260 state
->wb_resp
->extra_data
.data
=
261 (char *)buf
+ sizeof(struct winbindd_response
);
263 state
->wb_resp
->extra_data
.data
= NULL
;
265 tevent_req_done(req
);
268 ssize_t
wb_resp_read_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
269 struct winbindd_response
**presp
, int *err
)
271 struct resp_read_state
*state
= tevent_req_data(
272 req
, struct resp_read_state
);
274 if (tevent_req_is_unix_error(req
, err
)) {
277 *presp
= talloc_move(mem_ctx
, &state
->wb_resp
);
281 struct resp_write_state
{
286 static void wb_resp_write_done(struct tevent_req
*subreq
);
288 struct tevent_req
*wb_resp_write_send(TALLOC_CTX
*mem_ctx
,
289 struct tevent_context
*ev
,
290 struct tevent_queue
*queue
, int fd
,
291 struct winbindd_response
*wb_resp
)
293 struct tevent_req
*req
, *subreq
;
294 struct resp_write_state
*state
;
297 req
= tevent_req_create(mem_ctx
, &state
, struct resp_write_state
);
302 state
->iov
[0].iov_base
= wb_resp
;
303 state
->iov
[0].iov_len
= sizeof(struct winbindd_response
);
305 if (wb_resp
->length
> sizeof(struct winbindd_response
)) {
306 state
->iov
[1].iov_base
= wb_resp
->extra_data
.data
;
307 state
->iov
[1].iov_len
=
308 wb_resp
->length
- sizeof(struct winbindd_response
);
312 subreq
= writev_send(state
, ev
, queue
, fd
, state
->iov
, count
);
313 if (tevent_req_nomem(subreq
, req
)) {
314 return tevent_req_post(req
, ev
);
316 tevent_req_set_callback(subreq
, wb_resp_write_done
, req
);
320 static void wb_resp_write_done(struct tevent_req
*subreq
)
322 struct tevent_req
*req
= tevent_req_callback_data(
323 subreq
, struct tevent_req
);
324 struct resp_write_state
*state
= tevent_req_data(
325 req
, struct resp_write_state
);
328 state
->ret
= writev_recv(subreq
, &err
);
330 if (state
->ret
< 0) {
331 tevent_req_error(req
, err
);
334 tevent_req_done(req
);
337 ssize_t
wb_resp_write_recv(struct tevent_req
*req
, int *err
)
339 struct resp_write_state
*state
= tevent_req_data(
340 req
, struct resp_write_state
);
342 if (tevent_req_is_unix_error(req
, err
)) {
348 static bool closed_fd(int fd
)
361 if ((select(fd
+1, &r_fds
, NULL
, NULL
, &tv
) == -1)
362 || FD_ISSET(fd
, &r_fds
)) {
369 struct wb_simple_trans_state
{
370 struct tevent_context
*ev
;
372 struct winbindd_response
*wb_resp
;
375 static void wb_simple_trans_write_done(struct tevent_req
*subreq
);
376 static void wb_simple_trans_read_done(struct tevent_req
*subreq
);
378 struct tevent_req
*wb_simple_trans_send(TALLOC_CTX
*mem_ctx
,
379 struct tevent_context
*ev
,
380 struct tevent_queue
*queue
, int fd
,
381 struct winbindd_request
*wb_req
)
383 struct tevent_req
*req
, *subreq
;
384 struct wb_simple_trans_state
*state
;
386 req
= tevent_req_create(mem_ctx
, &state
, struct wb_simple_trans_state
);
392 tevent_req_error(req
, EPIPE
);
393 return tevent_req_post(req
, ev
);
396 wb_req
->length
= sizeof(struct winbindd_request
);
401 subreq
= wb_req_write_send(state
, ev
, queue
, fd
, wb_req
);
402 if (tevent_req_nomem(subreq
, req
)) {
403 return tevent_req_post(req
, ev
);
405 tevent_req_set_callback(subreq
, wb_simple_trans_write_done
, req
);
410 static void wb_simple_trans_write_done(struct tevent_req
*subreq
)
412 struct tevent_req
*req
= tevent_req_callback_data(
413 subreq
, struct tevent_req
);
414 struct wb_simple_trans_state
*state
= tevent_req_data(
415 req
, struct wb_simple_trans_state
);
419 ret
= wb_req_write_recv(subreq
, &err
);
421 * We do not TALLOC_FREE(subreq) here, as this would trigger the next
422 * write of a client. The winbind protocol is purely request/response
423 * without multiplex ID's, so having multiple requeusts on the fly
424 * would confuse sequencing.
426 * Eventually the "subreq" will be freed, it is a child of "req"
429 tevent_req_error(req
, err
);
432 subreq
= wb_resp_read_send(state
, state
->ev
, state
->fd
);
433 if (tevent_req_nomem(subreq
, req
)) {
436 tevent_req_set_callback(subreq
, wb_simple_trans_read_done
, req
);
439 static void wb_simple_trans_read_done(struct tevent_req
*subreq
)
441 struct tevent_req
*req
= tevent_req_callback_data(
442 subreq
, struct tevent_req
);
443 struct wb_simple_trans_state
*state
= tevent_req_data(
444 req
, struct wb_simple_trans_state
);
448 ret
= wb_resp_read_recv(subreq
, state
, &state
->wb_resp
, &err
);
450 tevent_req_error(req
, err
);
454 tevent_req_done(req
);
457 int wb_simple_trans_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
458 struct winbindd_response
**presponse
, int *err
)
460 struct wb_simple_trans_state
*state
= tevent_req_data(
461 req
, struct wb_simple_trans_state
);
463 if (tevent_req_is_unix_error(req
, err
)) {
466 *presponse
= talloc_move(mem_ctx
, &state
->wb_resp
);