Line data Source code
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 : ** NOTE! The following LGPL license applies to the wbclient
9 : ** library. This does NOT imply that all of Samba is released
10 : ** under the LGPL
11 :
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.
16 :
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.
21 :
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/>.
24 : */
25 :
26 : #include "replace.h"
27 : #include "system/filesys.h"
28 : #include "system/network.h"
29 : #include <talloc.h>
30 : #include <tevent.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/wb_reqtrans.h"
36 :
37 : /* can't use DEBUG here... */
38 : #define DEBUG(a,b)
39 :
40 : struct req_read_state {
41 : struct winbindd_request *wb_req;
42 : size_t max_extra_data;
43 : ssize_t ret;
44 : };
45 :
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);
48 :
49 262744 : struct tevent_req *wb_req_read_send(TALLOC_CTX *mem_ctx,
50 : struct tevent_context *ev,
51 : int fd, size_t max_extra_data)
52 : {
53 0 : struct tevent_req *req, *subreq;
54 0 : struct req_read_state *state;
55 :
56 262744 : req = tevent_req_create(mem_ctx, &state, struct req_read_state);
57 262744 : if (req == NULL) {
58 0 : return NULL;
59 : }
60 262744 : state->max_extra_data = max_extra_data;
61 :
62 262744 : subreq = read_packet_send(state, ev, fd, 4, wb_req_more, state);
63 262744 : if (tevent_req_nomem(subreq, req)) {
64 0 : return tevent_req_post(req, ev);
65 : }
66 262744 : tevent_req_set_callback(subreq, wb_req_read_done, req);
67 262744 : return req;
68 : }
69 :
70 517741 : static ssize_t wb_req_more(uint8_t *buf, size_t buflen, void *private_data)
71 : {
72 517741 : struct req_read_state *state = talloc_get_type_abort(
73 : private_data, struct req_read_state);
74 517741 : struct winbindd_request *req = (struct winbindd_request *)buf;
75 :
76 517741 : if (buflen == 4) {
77 254707 : if (req->length != sizeof(struct winbindd_request)) {
78 : DEBUG(0, ("wb_req_read_len: Invalid request size "
79 : "received: %d (expected %d)\n",
80 : (int)req->length,
81 : (int)sizeof(struct winbindd_request)));
82 0 : return -1;
83 : }
84 254707 : return sizeof(struct winbindd_request) - 4;
85 : }
86 :
87 263034 : if (buflen > sizeof(struct winbindd_request)) {
88 : /* We've been here, we're done */
89 8327 : return 0;
90 : }
91 :
92 254707 : if ((state->max_extra_data != 0)
93 254707 : && (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));
96 0 : return -1;
97 : }
98 :
99 254707 : return req->extra_len;
100 : }
101 :
102 262625 : static void wb_req_read_done(struct tevent_req *subreq)
103 : {
104 262625 : struct tevent_req *req = tevent_req_callback_data(
105 : subreq, struct tevent_req);
106 262625 : struct req_read_state *state = tevent_req_data(
107 : req, struct req_read_state);
108 0 : int err;
109 0 : uint8_t *buf;
110 :
111 262625 : state->ret = read_packet_recv(subreq, state, &buf, &err);
112 262625 : TALLOC_FREE(subreq);
113 262625 : if (state->ret == -1) {
114 7918 : tevent_req_error(req, err);
115 7918 : return;
116 : }
117 :
118 254707 : state->wb_req = (struct winbindd_request *)buf;
119 :
120 254707 : if (state->wb_req->extra_len != 0) {
121 8327 : state->wb_req->extra_data.data =
122 8327 : (char *)buf + sizeof(struct winbindd_request);
123 : } else {
124 246380 : state->wb_req->extra_data.data = NULL;
125 : }
126 254707 : tevent_req_done(req);
127 : }
128 :
129 262625 : ssize_t wb_req_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
130 : struct winbindd_request **preq, int *err)
131 : {
132 262625 : struct req_read_state *state = tevent_req_data(
133 : req, struct req_read_state);
134 :
135 262625 : if (tevent_req_is_unix_error(req, err)) {
136 7918 : return -1;
137 : }
138 254707 : *preq = talloc_move(mem_ctx, &state->wb_req);
139 254707 : return state->ret;
140 : }
141 :
142 : struct req_write_state {
143 : struct iovec iov[2];
144 : ssize_t ret;
145 : };
146 :
147 : static void wb_req_write_done(struct tevent_req *subreq);
148 :
149 132729 : 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)
153 : {
154 0 : struct tevent_req *req, *subreq;
155 0 : struct req_write_state *state;
156 132729 : int count = 1;
157 :
158 132729 : req = tevent_req_create(mem_ctx, &state, struct req_write_state);
159 132729 : if (req == NULL) {
160 0 : return NULL;
161 : }
162 :
163 132729 : state->iov[0].iov_base = (void *)wb_req;
164 132729 : state->iov[0].iov_len = sizeof(struct winbindd_request);
165 :
166 132729 : if (wb_req->extra_len != 0) {
167 131814 : state->iov[1].iov_base = (void *)wb_req->extra_data.data;
168 131814 : state->iov[1].iov_len = wb_req->extra_len;
169 131814 : count = 2;
170 : }
171 :
172 132729 : subreq = writev_send(state, ev, queue, fd, true, state->iov, count);
173 132729 : if (tevent_req_nomem(subreq, req)) {
174 0 : return tevent_req_post(req, ev);
175 : }
176 132729 : tevent_req_set_callback(subreq, wb_req_write_done, req);
177 132729 : return req;
178 : }
179 :
180 132729 : static void wb_req_write_done(struct tevent_req *subreq)
181 : {
182 132729 : struct tevent_req *req = tevent_req_callback_data(
183 : subreq, struct tevent_req);
184 132729 : struct req_write_state *state = tevent_req_data(
185 : req, struct req_write_state);
186 0 : int err;
187 :
188 132729 : state->ret = writev_recv(subreq, &err);
189 132729 : TALLOC_FREE(subreq);
190 132729 : if (state->ret < 0) {
191 0 : tevent_req_error(req, err);
192 0 : return;
193 : }
194 132729 : tevent_req_done(req);
195 : }
196 :
197 132729 : ssize_t wb_req_write_recv(struct tevent_req *req, int *err)
198 : {
199 132729 : struct req_write_state *state = tevent_req_data(
200 : req, struct req_write_state);
201 :
202 132729 : if (tevent_req_is_unix_error(req, err)) {
203 0 : return -1;
204 : }
205 132729 : return state->ret;
206 : }
207 :
208 : struct resp_read_state {
209 : struct winbindd_response *wb_resp;
210 : ssize_t ret;
211 : };
212 :
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);
215 :
216 132729 : struct tevent_req *wb_resp_read_send(TALLOC_CTX *mem_ctx,
217 : struct tevent_context *ev, int fd)
218 : {
219 0 : struct tevent_req *req, *subreq;
220 0 : struct resp_read_state *state;
221 :
222 132729 : req = tevent_req_create(mem_ctx, &state, struct resp_read_state);
223 132729 : if (req == NULL) {
224 0 : return NULL;
225 : }
226 :
227 132729 : subreq = read_packet_send(state, ev, fd, 4, wb_resp_more, state);
228 132729 : if (tevent_req_nomem(subreq, req)) {
229 0 : return tevent_req_post(req, ev);
230 : }
231 132729 : tevent_req_set_callback(subreq, wb_resp_read_done, req);
232 132729 : return req;
233 : }
234 :
235 265458 : static ssize_t wb_resp_more(uint8_t *buf, size_t buflen, void *private_data)
236 : {
237 265458 : struct winbindd_response *resp = (struct winbindd_response *)buf;
238 :
239 265458 : if (buflen == 4) {
240 132729 : 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",
243 : (int)resp->length,
244 : (int)sizeof(struct winbindd_response)));
245 0 : return -1;
246 : }
247 : }
248 265458 : return resp->length - buflen;
249 : }
250 :
251 132729 : static void wb_resp_read_done(struct tevent_req *subreq)
252 : {
253 132729 : struct tevent_req *req = tevent_req_callback_data(
254 : subreq, struct tevent_req);
255 132729 : struct resp_read_state *state = tevent_req_data(
256 : req, struct resp_read_state);
257 0 : uint8_t *buf;
258 0 : int err;
259 :
260 132729 : state->ret = read_packet_recv(subreq, state, &buf, &err);
261 132729 : TALLOC_FREE(subreq);
262 132729 : if (state->ret == -1) {
263 0 : tevent_req_error(req, err);
264 0 : return;
265 : }
266 :
267 132729 : state->wb_resp = (struct winbindd_response *)buf;
268 :
269 132729 : if (state->wb_resp->length > sizeof(struct winbindd_response)) {
270 132527 : state->wb_resp->extra_data.data =
271 132527 : (char *)buf + sizeof(struct winbindd_response);
272 : } else {
273 202 : state->wb_resp->extra_data.data = NULL;
274 : }
275 132729 : tevent_req_done(req);
276 : }
277 :
278 132729 : ssize_t wb_resp_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
279 : struct winbindd_response **presp, int *err)
280 : {
281 132729 : struct resp_read_state *state = tevent_req_data(
282 : req, struct resp_read_state);
283 :
284 132729 : if (tevent_req_is_unix_error(req, err)) {
285 0 : return -1;
286 : }
287 132729 : *presp = talloc_move(mem_ctx, &state->wb_resp);
288 132729 : return state->ret;
289 : }
290 :
291 : struct resp_write_state {
292 : struct iovec iov[2];
293 : ssize_t ret;
294 : };
295 :
296 : static void wb_resp_write_done(struct tevent_req *subreq);
297 :
298 254707 : 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)
302 : {
303 0 : struct tevent_req *req, *subreq;
304 0 : struct resp_write_state *state;
305 254707 : int count = 1;
306 :
307 254707 : req = tevent_req_create(mem_ctx, &state, struct resp_write_state);
308 254707 : if (req == NULL) {
309 0 : return NULL;
310 : }
311 :
312 254707 : state->iov[0].iov_base = (void *)wb_resp;
313 254707 : state->iov[0].iov_len = sizeof(struct winbindd_response);
314 :
315 254707 : if (wb_resp->length > sizeof(struct winbindd_response)) {
316 9275 : state->iov[1].iov_base = (void *)wb_resp->extra_data.data;
317 9275 : state->iov[1].iov_len =
318 9275 : wb_resp->length - sizeof(struct winbindd_response);
319 9275 : count = 2;
320 : }
321 :
322 254707 : subreq = writev_send(state, ev, queue, fd, true, state->iov, count);
323 254707 : if (tevent_req_nomem(subreq, req)) {
324 0 : return tevent_req_post(req, ev);
325 : }
326 254707 : tevent_req_set_callback(subreq, wb_resp_write_done, req);
327 254707 : return req;
328 : }
329 :
330 254707 : static void wb_resp_write_done(struct tevent_req *subreq)
331 : {
332 254707 : struct tevent_req *req = tevent_req_callback_data(
333 : subreq, struct tevent_req);
334 254707 : struct resp_write_state *state = tevent_req_data(
335 : req, struct resp_write_state);
336 0 : int err;
337 :
338 254707 : state->ret = writev_recv(subreq, &err);
339 254707 : TALLOC_FREE(subreq);
340 254707 : if (state->ret < 0) {
341 0 : tevent_req_error(req, err);
342 0 : return;
343 : }
344 254707 : tevent_req_done(req);
345 : }
346 :
347 254707 : ssize_t wb_resp_write_recv(struct tevent_req *req, int *err)
348 : {
349 254707 : struct resp_write_state *state = tevent_req_data(
350 : req, struct resp_write_state);
351 :
352 254707 : if (tevent_req_is_unix_error(req, err)) {
353 0 : return -1;
354 : }
355 254707 : return state->ret;
356 : }
357 :
358 : struct wb_simple_trans_state {
359 : struct tevent_context *ev;
360 : int fd;
361 : struct winbindd_response *wb_resp;
362 : };
363 :
364 : static void wb_simple_trans_write_done(struct tevent_req *subreq);
365 : static void wb_simple_trans_read_done(struct tevent_req *subreq);
366 :
367 132729 : 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)
371 : {
372 0 : struct tevent_req *req, *subreq;
373 0 : struct wb_simple_trans_state *state;
374 :
375 132729 : req = tevent_req_create(mem_ctx, &state, struct wb_simple_trans_state);
376 132729 : if (req == NULL) {
377 0 : return NULL;
378 : }
379 :
380 132729 : wb_req->length = sizeof(struct winbindd_request);
381 :
382 132729 : state->ev = ev;
383 132729 : state->fd = fd;
384 :
385 132729 : subreq = wb_req_write_send(state, ev, queue, fd, wb_req);
386 132729 : if (tevent_req_nomem(subreq, req)) {
387 0 : return tevent_req_post(req, ev);
388 : }
389 132729 : tevent_req_set_callback(subreq, wb_simple_trans_write_done, req);
390 :
391 132729 : return req;
392 : }
393 :
394 132729 : static void wb_simple_trans_write_done(struct tevent_req *subreq)
395 : {
396 132729 : struct tevent_req *req = tevent_req_callback_data(
397 : subreq, struct tevent_req);
398 132729 : struct wb_simple_trans_state *state = tevent_req_data(
399 : req, struct wb_simple_trans_state);
400 0 : ssize_t ret;
401 0 : int err;
402 :
403 132729 : ret = wb_req_write_recv(subreq, &err);
404 132729 : TALLOC_FREE(subreq);
405 132729 : if (ret == -1) {
406 0 : tevent_req_error(req, err);
407 0 : return;
408 : }
409 132729 : subreq = wb_resp_read_send(state, state->ev, state->fd);
410 132729 : if (tevent_req_nomem(subreq, req)) {
411 0 : return;
412 : }
413 132729 : tevent_req_set_callback(subreq, wb_simple_trans_read_done, req);
414 : }
415 :
416 132729 : static void wb_simple_trans_read_done(struct tevent_req *subreq)
417 : {
418 132729 : struct tevent_req *req = tevent_req_callback_data(
419 : subreq, struct tevent_req);
420 132729 : struct wb_simple_trans_state *state = tevent_req_data(
421 : req, struct wb_simple_trans_state);
422 0 : ssize_t ret;
423 0 : int err;
424 :
425 132729 : ret = wb_resp_read_recv(subreq, state, &state->wb_resp, &err);
426 132729 : TALLOC_FREE(subreq);
427 132729 : if (ret == -1) {
428 0 : tevent_req_error(req, err);
429 0 : return;
430 : }
431 :
432 132729 : tevent_req_done(req);
433 : }
434 :
435 132729 : int wb_simple_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
436 : struct winbindd_response **presponse, int *err)
437 : {
438 132729 : struct wb_simple_trans_state *state = tevent_req_data(
439 : req, struct wb_simple_trans_state);
440 :
441 132729 : if (tevent_req_is_unix_error(req, err)) {
442 0 : return -1;
443 : }
444 132729 : *presponse = talloc_move(mem_ctx, &state->wb_resp);
445 132729 : return 0;
446 : }
|