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 struct tevent_context
*ev
;
31 size_t max_extra_data
;
35 bool async_req_is_wbcerr(struct async_req
*req
, wbcErr
*pwbc_err
)
37 enum async_req_state state
;
39 if (!async_req_is_error(req
, &state
, &error
)) {
40 *pwbc_err
= WBC_ERR_SUCCESS
;
45 case ASYNC_REQ_USER_ERROR
:
48 case ASYNC_REQ_TIMED_OUT
:
49 *pwbc_err
= WBC_ERR_UNKNOWN_FAILURE
;
51 case ASYNC_REQ_NO_MEMORY
:
52 *pwbc_err
= WBC_ERR_NO_MEMORY
;
55 *pwbc_err
= WBC_ERR_UNKNOWN_FAILURE
;
61 wbcErr
map_wbc_err_from_errno(int error
)
66 return WBC_ERR_AUTH_ERROR
;
68 return WBC_ERR_NO_MEMORY
;
71 return WBC_ERR_UNKNOWN_FAILURE
;
75 wbcErr
async_req_simple_recv_wbcerr(struct async_req
*req
)
79 if (async_req_is_wbcerr(req
, &wbc_err
)) {
83 return WBC_ERR_SUCCESS
;
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
);
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
)
94 struct async_req
*result
, *subreq
;
95 struct req_read_state
*state
;
97 if (!async_req_setup(mem_ctx
, &result
, &state
,
98 struct req_read_state
)) {
103 state
->max_extra_data
= max_extra_data
;
104 state
->wb_req
= talloc(state
, struct winbindd_request
);
105 if (state
->wb_req
== NULL
) {
109 subreq
= recvall_send(state
, ev
, state
->fd
, &(state
->wb_req
->length
),
110 sizeof(state
->wb_req
->length
), 0);
111 if (subreq
== NULL
) {
115 subreq
->async
.fn
= wb_req_read_len
;
116 subreq
->async
.priv
= result
;
124 static void wb_req_read_len(struct async_req
*subreq
)
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
);
133 ret
= recvall_recv(subreq
, &err
);
136 async_req_error(req
, map_wbc_err_from_errno(err
));
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
);
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
)) {
155 subreq
->async
.fn
= wb_req_read_main
;
156 subreq
->async
.priv
= req
;
159 static void wb_req_read_main(struct async_req
*subreq
)
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
);
168 ret
= recvall_recv(subreq
, &err
);
171 async_req_error(req
, map_wbc_err_from_errno(err
));
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
);
184 if (state
->wb_req
->extra_len
== 0) {
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
)) {
195 state
->wb_req
->extra_data
.data
[state
->wb_req
->extra_len
] = 0;
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
)) {
204 subreq
->async
.fn
= wb_req_read_extra
;
205 subreq
->async
.priv
= req
;
208 static void wb_req_read_extra(struct async_req
*subreq
)
210 struct async_req
*req
= talloc_get_type_abort(
211 subreq
->async
.priv
, struct async_req
);
215 ret
= recvall_recv(subreq
, &err
);
218 async_req_error(req
, map_wbc_err_from_errno(err
));
225 wbcErr
wb_req_read_recv(struct async_req
*req
, TALLOC_CTX
*mem_ctx
,
226 struct winbindd_request
**preq
)
228 struct req_read_state
*state
= talloc_get_type_abort(
229 req
->private_data
, struct req_read_state
);
232 if (async_req_is_wbcerr(req
, &wbc_err
)) {
235 *preq
= talloc_move(mem_ctx
, &state
->wb_req
);
236 return WBC_ERR_SUCCESS
;
239 struct req_write_state
{
240 struct winbindd_request
*wb_req
;
241 struct tevent_context
*ev
;
245 static void wb_req_write_main(struct async_req
*subreq
);
246 static void wb_req_write_extra(struct async_req
*subreq
);
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
)
252 struct async_req
*result
, *subreq
;
253 struct req_write_state
*state
;
255 if (!async_req_setup(mem_ctx
, &result
, &state
,
256 struct req_write_state
)) {
261 state
->wb_req
= wb_req
;
263 subreq
= sendall_send(state
, state
->ev
, state
->fd
, state
->wb_req
,
264 sizeof(struct winbindd_request
), 0);
265 if (subreq
== NULL
) {
269 subreq
->async
.fn
= wb_req_write_main
;
270 subreq
->async
.priv
= result
;
278 static void wb_req_write_main(struct async_req
*subreq
)
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
);
287 ret
= sendall_recv(subreq
, &err
);
290 async_req_error(req
, map_wbc_err_from_errno(err
));
294 if (state
->wb_req
->extra_len
== 0) {
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
)) {
306 subreq
->async
.fn
= wb_req_write_extra
;
307 subreq
->async
.priv
= req
;
310 static void wb_req_write_extra(struct async_req
*subreq
)
312 struct async_req
*req
= talloc_get_type_abort(
313 subreq
->async
.priv
, struct async_req
);
317 ret
= sendall_recv(subreq
, &err
);
320 async_req_error(req
, map_wbc_err_from_errno(err
));
327 wbcErr
wb_req_write_recv(struct async_req
*req
)
329 return async_req_simple_recv_wbcerr(req
);
332 struct resp_read_state
{
333 struct winbindd_response
*wb_resp
;
334 struct tevent_context
*ev
;
335 size_t max_extra_data
;
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
);
343 struct async_req
*wb_resp_read_send(TALLOC_CTX
*mem_ctx
,
344 struct tevent_context
*ev
, int fd
)
346 struct async_req
*result
, *subreq
;
347 struct resp_read_state
*state
;
349 if (!async_req_setup(mem_ctx
, &result
, &state
,
350 struct resp_read_state
)) {
355 state
->wb_resp
= talloc(state
, struct winbindd_response
);
356 if (state
->wb_resp
== NULL
) {
360 subreq
= recvall_send(state
, ev
, state
->fd
, &(state
->wb_resp
->length
),
361 sizeof(state
->wb_resp
->length
), 0);
362 if (subreq
== NULL
) {
366 subreq
->async
.fn
= wb_resp_read_len
;
367 subreq
->async
.priv
= result
;
375 static void wb_resp_read_len(struct async_req
*subreq
)
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
);
384 ret
= recvall_recv(subreq
, &err
);
387 async_req_error(req
, map_wbc_err_from_errno(err
));
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
);
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
)) {
407 subreq
->async
.fn
= wb_resp_read_main
;
408 subreq
->async
.priv
= req
;
411 static void wb_resp_read_main(struct async_req
*subreq
)
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
);
421 ret
= recvall_recv(subreq
, &err
);
424 async_req_error(req
, map_wbc_err_from_errno(err
));
428 extra_len
= state
->wb_resp
->length
- sizeof(struct winbindd_response
);
429 if (extra_len
== 0) {
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
)) {
439 ((char *)state
->wb_resp
->extra_data
.data
)[extra_len
] = 0;
441 subreq
= recvall_send(
442 req
, state
->ev
, state
->fd
, state
->wb_resp
->extra_data
.data
,
444 if (async_req_nomem(subreq
, req
)) {
448 subreq
->async
.fn
= wb_resp_read_extra
;
449 subreq
->async
.priv
= req
;
452 static void wb_resp_read_extra(struct async_req
*subreq
)
454 struct async_req
*req
= talloc_get_type_abort(
455 subreq
->async
.priv
, struct async_req
);
459 ret
= recvall_recv(subreq
, &err
);
462 async_req_error(req
, map_wbc_err_from_errno(err
));
469 wbcErr
wb_resp_read_recv(struct async_req
*req
, TALLOC_CTX
*mem_ctx
,
470 struct winbindd_response
**presp
)
472 struct resp_read_state
*state
= talloc_get_type_abort(
473 req
->private_data
, struct resp_read_state
);
476 if (async_req_is_wbcerr(req
, &wbc_err
)) {
479 *presp
= talloc_move(mem_ctx
, &state
->wb_resp
);
480 return WBC_ERR_SUCCESS
;
483 struct resp_write_state
{
484 struct winbindd_response
*wb_resp
;
485 struct tevent_context
*ev
;
489 static void wb_resp_write_main(struct async_req
*subreq
);
490 static void wb_resp_write_extra(struct async_req
*subreq
);
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
)
496 struct async_req
*result
, *subreq
;
497 struct resp_write_state
*state
;
499 if (!async_req_setup(mem_ctx
, &result
, &state
,
500 struct resp_write_state
)) {
505 state
->wb_resp
= wb_resp
;
507 subreq
= sendall_send(state
, state
->ev
, state
->fd
, state
->wb_resp
,
508 sizeof(struct winbindd_response
), 0);
509 if (subreq
== NULL
) {
513 subreq
->async
.fn
= wb_resp_write_main
;
514 subreq
->async
.priv
= result
;
522 static void wb_resp_write_main(struct async_req
*subreq
)
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
);
531 ret
= sendall_recv(subreq
, &err
);
534 async_req_error(req
, map_wbc_err_from_errno(err
));
538 if (state
->wb_resp
->length
== sizeof(struct winbindd_response
)) {
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
)) {
551 subreq
->async
.fn
= wb_resp_write_extra
;
552 subreq
->async
.priv
= req
;
555 static void wb_resp_write_extra(struct async_req
*subreq
)
557 struct async_req
*req
= talloc_get_type_abort(
558 subreq
->async
.priv
, struct async_req
);
562 ret
= sendall_recv(subreq
, &err
);
565 async_req_error(req
, map_wbc_err_from_errno(err
));
572 wbcErr
wb_resp_write_recv(struct async_req
*req
)
574 return async_req_simple_recv_wbcerr(req
);