2 Unix SMB/CIFS implementation.
4 Async transfer of winbindd_request and _response structs
6 Copyright (C) Volker Lendecke 2008
8 ** NOTE! The following LGPL license applies to the wbclient
9 ** library. This does NOT imply that all of Samba is released
12 This library is free software; you can redistribute it and/or
13 modify it under the terms of the GNU Lesser General Public
14 License as published by the Free Software Foundation; either
15 version 3 of the License, or (at your option) any later version.
17 This library is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 Library General Public License for more details.
22 You should have received a copy of the GNU Lesser General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 #include "system/filesys.h"
28 #include "system/network.h"
31 #include "lib/async_req/async_sock.h"
32 #include "lib/util/tevent_unix.h"
33 #include "nsswitch/winbind_struct_protocol.h"
34 #include "nsswitch/libwbclient/wbclient.h"
35 #include "nsswitch/libwbclient/wbc_async.h"
37 /* can't use DEBUG here... */
40 struct req_read_state
{
41 struct winbindd_request
*wb_req
;
42 size_t max_extra_data
;
46 static ssize_t
wb_req_more(uint8_t *buf
, size_t buflen
, void *private_data
);
47 static void wb_req_read_done(struct tevent_req
*subreq
);
49 struct tevent_req
*wb_req_read_send(TALLOC_CTX
*mem_ctx
,
50 struct tevent_context
*ev
,
51 int fd
, size_t max_extra_data
)
53 struct tevent_req
*req
, *subreq
;
54 struct req_read_state
*state
;
56 req
= tevent_req_create(mem_ctx
, &state
, struct req_read_state
);
60 state
->max_extra_data
= max_extra_data
;
62 subreq
= read_packet_send(state
, ev
, fd
, 4, wb_req_more
, state
);
63 if (tevent_req_nomem(subreq
, req
)) {
64 return tevent_req_post(req
, ev
);
66 tevent_req_set_callback(subreq
, wb_req_read_done
, req
);
70 static ssize_t
wb_req_more(uint8_t *buf
, size_t buflen
, void *private_data
)
72 struct req_read_state
*state
= talloc_get_type_abort(
73 private_data
, struct req_read_state
);
74 struct winbindd_request
*req
= (struct winbindd_request
*)buf
;
77 if (req
->length
!= sizeof(struct winbindd_request
)) {
78 DEBUG(0, ("wb_req_read_len: Invalid request size "
79 "received: %d (expected %d)\n",
81 (int)sizeof(struct winbindd_request
)));
84 return sizeof(struct winbindd_request
) - 4;
87 if (buflen
> sizeof(struct winbindd_request
)) {
88 /* We've been here, we're done */
92 if ((state
->max_extra_data
!= 0)
93 && (req
->extra_len
> state
->max_extra_data
)) {
94 DEBUG(3, ("Got request with %d bytes extra data on "
95 "unprivileged socket\n", (int)req
->extra_len
));
99 return req
->extra_len
;
102 static void wb_req_read_done(struct tevent_req
*subreq
)
104 struct tevent_req
*req
= tevent_req_callback_data(
105 subreq
, struct tevent_req
);
106 struct req_read_state
*state
= tevent_req_data(
107 req
, struct req_read_state
);
111 state
->ret
= read_packet_recv(subreq
, state
, &buf
, &err
);
113 if (state
->ret
== -1) {
114 tevent_req_error(req
, err
);
118 state
->wb_req
= (struct winbindd_request
*)buf
;
120 if (state
->wb_req
->extra_len
!= 0) {
121 state
->wb_req
->extra_data
.data
=
122 (char *)buf
+ sizeof(struct winbindd_request
);
124 state
->wb_req
->extra_data
.data
= NULL
;
126 tevent_req_done(req
);
129 ssize_t
wb_req_read_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
130 struct winbindd_request
**preq
, int *err
)
132 struct req_read_state
*state
= tevent_req_data(
133 req
, struct req_read_state
);
135 if (tevent_req_is_unix_error(req
, err
)) {
138 *preq
= talloc_move(mem_ctx
, &state
->wb_req
);
142 struct req_write_state
{
147 static void wb_req_write_done(struct tevent_req
*subreq
);
149 struct tevent_req
*wb_req_write_send(TALLOC_CTX
*mem_ctx
,
150 struct tevent_context
*ev
,
151 struct tevent_queue
*queue
, int fd
,
152 struct winbindd_request
*wb_req
)
154 struct tevent_req
*req
, *subreq
;
155 struct req_write_state
*state
;
158 req
= tevent_req_create(mem_ctx
, &state
, struct req_write_state
);
163 state
->iov
[0].iov_base
= (void *)wb_req
;
164 state
->iov
[0].iov_len
= sizeof(struct winbindd_request
);
166 if (wb_req
->extra_len
!= 0) {
167 state
->iov
[1].iov_base
= (void *)wb_req
->extra_data
.data
;
168 state
->iov
[1].iov_len
= wb_req
->extra_len
;
172 subreq
= writev_send(state
, ev
, queue
, fd
, true, state
->iov
, count
);
173 if (tevent_req_nomem(subreq
, req
)) {
174 return tevent_req_post(req
, ev
);
176 tevent_req_set_callback(subreq
, wb_req_write_done
, req
);
180 static void wb_req_write_done(struct tevent_req
*subreq
)
182 struct tevent_req
*req
= tevent_req_callback_data(
183 subreq
, struct tevent_req
);
184 struct req_write_state
*state
= tevent_req_data(
185 req
, struct req_write_state
);
188 state
->ret
= writev_recv(subreq
, &err
);
190 if (state
->ret
< 0) {
191 tevent_req_error(req
, err
);
194 tevent_req_done(req
);
197 ssize_t
wb_req_write_recv(struct tevent_req
*req
, int *err
)
199 struct req_write_state
*state
= tevent_req_data(
200 req
, struct req_write_state
);
202 if (tevent_req_is_unix_error(req
, err
)) {
208 struct resp_read_state
{
209 struct winbindd_response
*wb_resp
;
213 static ssize_t
wb_resp_more(uint8_t *buf
, size_t buflen
, void *private_data
);
214 static void wb_resp_read_done(struct tevent_req
*subreq
);
216 struct tevent_req
*wb_resp_read_send(TALLOC_CTX
*mem_ctx
,
217 struct tevent_context
*ev
, int fd
)
219 struct tevent_req
*req
, *subreq
;
220 struct resp_read_state
*state
;
222 req
= tevent_req_create(mem_ctx
, &state
, struct resp_read_state
);
227 subreq
= read_packet_send(state
, ev
, fd
, 4, wb_resp_more
, state
);
228 if (tevent_req_nomem(subreq
, req
)) {
229 return tevent_req_post(req
, ev
);
231 tevent_req_set_callback(subreq
, wb_resp_read_done
, req
);
235 static ssize_t
wb_resp_more(uint8_t *buf
, size_t buflen
, void *private_data
)
237 struct winbindd_response
*resp
= (struct winbindd_response
*)buf
;
240 if (resp
->length
< sizeof(struct winbindd_response
)) {
241 DEBUG(0, ("wb_resp_read_len: Invalid response size "
242 "received: %d (expected at least%d)\n",
244 (int)sizeof(struct winbindd_response
)));
248 return resp
->length
- buflen
;
251 static void wb_resp_read_done(struct tevent_req
*subreq
)
253 struct tevent_req
*req
= tevent_req_callback_data(
254 subreq
, struct tevent_req
);
255 struct resp_read_state
*state
= tevent_req_data(
256 req
, struct resp_read_state
);
260 state
->ret
= read_packet_recv(subreq
, state
, &buf
, &err
);
262 if (state
->ret
== -1) {
263 tevent_req_error(req
, err
);
267 state
->wb_resp
= (struct winbindd_response
*)buf
;
269 if (state
->wb_resp
->length
> sizeof(struct winbindd_response
)) {
270 state
->wb_resp
->extra_data
.data
=
271 (char *)buf
+ sizeof(struct winbindd_response
);
273 state
->wb_resp
->extra_data
.data
= NULL
;
275 tevent_req_done(req
);
278 ssize_t
wb_resp_read_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
279 struct winbindd_response
**presp
, int *err
)
281 struct resp_read_state
*state
= tevent_req_data(
282 req
, struct resp_read_state
);
284 if (tevent_req_is_unix_error(req
, err
)) {
287 *presp
= talloc_move(mem_ctx
, &state
->wb_resp
);
291 struct resp_write_state
{
296 static void wb_resp_write_done(struct tevent_req
*subreq
);
298 struct tevent_req
*wb_resp_write_send(TALLOC_CTX
*mem_ctx
,
299 struct tevent_context
*ev
,
300 struct tevent_queue
*queue
, int fd
,
301 struct winbindd_response
*wb_resp
)
303 struct tevent_req
*req
, *subreq
;
304 struct resp_write_state
*state
;
307 req
= tevent_req_create(mem_ctx
, &state
, struct resp_write_state
);
312 state
->iov
[0].iov_base
= (void *)wb_resp
;
313 state
->iov
[0].iov_len
= sizeof(struct winbindd_response
);
315 if (wb_resp
->length
> sizeof(struct winbindd_response
)) {
316 state
->iov
[1].iov_base
= (void *)wb_resp
->extra_data
.data
;
317 state
->iov
[1].iov_len
=
318 wb_resp
->length
- sizeof(struct winbindd_response
);
322 subreq
= writev_send(state
, ev
, queue
, fd
, true, state
->iov
, count
);
323 if (tevent_req_nomem(subreq
, req
)) {
324 return tevent_req_post(req
, ev
);
326 tevent_req_set_callback(subreq
, wb_resp_write_done
, req
);
330 static void wb_resp_write_done(struct tevent_req
*subreq
)
332 struct tevent_req
*req
= tevent_req_callback_data(
333 subreq
, struct tevent_req
);
334 struct resp_write_state
*state
= tevent_req_data(
335 req
, struct resp_write_state
);
338 state
->ret
= writev_recv(subreq
, &err
);
340 if (state
->ret
< 0) {
341 tevent_req_error(req
, err
);
344 tevent_req_done(req
);
347 ssize_t
wb_resp_write_recv(struct tevent_req
*req
, int *err
)
349 struct resp_write_state
*state
= tevent_req_data(
350 req
, struct resp_write_state
);
352 if (tevent_req_is_unix_error(req
, err
)) {
358 struct wb_simple_trans_state
{
359 struct tevent_context
*ev
;
361 struct winbindd_response
*wb_resp
;
364 static void wb_simple_trans_write_done(struct tevent_req
*subreq
);
365 static void wb_simple_trans_read_done(struct tevent_req
*subreq
);
367 struct tevent_req
*wb_simple_trans_send(TALLOC_CTX
*mem_ctx
,
368 struct tevent_context
*ev
,
369 struct tevent_queue
*queue
, int fd
,
370 struct winbindd_request
*wb_req
)
372 struct tevent_req
*req
, *subreq
;
373 struct wb_simple_trans_state
*state
;
375 req
= tevent_req_create(mem_ctx
, &state
, struct wb_simple_trans_state
);
380 wb_req
->length
= sizeof(struct winbindd_request
);
385 subreq
= wb_req_write_send(state
, ev
, queue
, fd
, wb_req
);
386 if (tevent_req_nomem(subreq
, req
)) {
387 return tevent_req_post(req
, ev
);
389 tevent_req_set_callback(subreq
, wb_simple_trans_write_done
, req
);
394 static void wb_simple_trans_write_done(struct tevent_req
*subreq
)
396 struct tevent_req
*req
= tevent_req_callback_data(
397 subreq
, struct tevent_req
);
398 struct wb_simple_trans_state
*state
= tevent_req_data(
399 req
, struct wb_simple_trans_state
);
403 ret
= wb_req_write_recv(subreq
, &err
);
406 tevent_req_error(req
, err
);
409 subreq
= wb_resp_read_send(state
, state
->ev
, state
->fd
);
410 if (tevent_req_nomem(subreq
, req
)) {
413 tevent_req_set_callback(subreq
, wb_simple_trans_read_done
, req
);
416 static void wb_simple_trans_read_done(struct tevent_req
*subreq
)
418 struct tevent_req
*req
= tevent_req_callback_data(
419 subreq
, struct tevent_req
);
420 struct wb_simple_trans_state
*state
= tevent_req_data(
421 req
, struct wb_simple_trans_state
);
425 ret
= wb_resp_read_recv(subreq
, state
, &state
->wb_resp
, &err
);
428 tevent_req_error(req
, err
);
432 tevent_req_done(req
);
435 int wb_simple_trans_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
436 struct winbindd_response
**presponse
, int *err
)
438 struct wb_simple_trans_state
*state
= tevent_req_data(
439 req
, struct wb_simple_trans_state
);
441 if (tevent_req_is_unix_error(req
, err
)) {
444 *presponse
= talloc_move(mem_ctx
, &state
->wb_resp
);