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 256026 : 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 256026 : req = tevent_req_create(mem_ctx, &state, struct req_read_state);
57 256026 : if (req == NULL) {
58 0 : return NULL;
59 : }
60 256026 : state->max_extra_data = max_extra_data;
61 :
62 256026 : subreq = read_packet_send(state, ev, fd, 4, wb_req_more, state);
63 256026 : if (tevent_req_nomem(subreq, req)) {
64 0 : return tevent_req_post(req, ev);
65 : }
66 256026 : tevent_req_set_callback(subreq, wb_req_read_done, req);
67 256026 : return req;
68 : }
69 :
70 502780 : static ssize_t wb_req_more(uint8_t *buf, size_t buflen, void *private_data)
71 : {
72 502780 : struct req_read_state *state = talloc_get_type_abort(
73 : private_data, struct req_read_state);
74 502780 : struct winbindd_request *req = (struct winbindd_request *)buf;
75 :
76 502780 : if (buflen == 4) {
77 247986 : 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 247986 : return sizeof(struct winbindd_request) - 4;
85 : }
86 :
87 254794 : if (buflen > sizeof(struct winbindd_request)) {
88 : /* We've been here, we're done */
89 6808 : return 0;
90 : }
91 :
92 247986 : if ((state->max_extra_data != 0)
93 247986 : && (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 247986 : return req->extra_len;
100 : }
101 :
102 255902 : static void wb_req_read_done(struct tevent_req *subreq)
103 : {
104 255902 : struct tevent_req *req = tevent_req_callback_data(
105 : subreq, struct tevent_req);
106 255902 : 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 255902 : state->ret = read_packet_recv(subreq, state, &buf, &err);
112 255902 : TALLOC_FREE(subreq);
113 255902 : if (state->ret == -1) {
114 7916 : tevent_req_error(req, err);
115 7916 : return;
116 : }
117 :
118 247986 : state->wb_req = (struct winbindd_request *)buf;
119 :
120 247986 : if (state->wb_req->extra_len != 0) {
121 6808 : state->wb_req->extra_data.data =
122 6808 : (char *)buf + sizeof(struct winbindd_request);
123 : } else {
124 241178 : state->wb_req->extra_data.data = NULL;
125 : }
126 247986 : tevent_req_done(req);
127 : }
128 :
129 255902 : ssize_t wb_req_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
130 : struct winbindd_request **preq, int *err)
131 : {
132 255902 : struct req_read_state *state = tevent_req_data(
133 : req, struct req_read_state);
134 :
135 255902 : if (tevent_req_is_unix_error(req, err)) {
136 7916 : return -1;
137 : }
138 247986 : *preq = talloc_move(mem_ctx, &state->wb_req);
139 247986 : 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 125586 : 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 125586 : int count = 1;
157 :
158 125586 : req = tevent_req_create(mem_ctx, &state, struct req_write_state);
159 125586 : if (req == NULL) {
160 0 : return NULL;
161 : }
162 :
163 125586 : state->iov[0].iov_base = (void *)wb_req;
164 125586 : state->iov[0].iov_len = sizeof(struct winbindd_request);
165 :
166 125586 : if (wb_req->extra_len != 0) {
167 124668 : state->iov[1].iov_base = (void *)wb_req->extra_data.data;
168 124668 : state->iov[1].iov_len = wb_req->extra_len;
169 124668 : count = 2;
170 : }
171 :
172 125586 : subreq = writev_send(state, ev, queue, fd, true, state->iov, count);
173 125586 : if (tevent_req_nomem(subreq, req)) {
174 0 : return tevent_req_post(req, ev);
175 : }
176 125586 : tevent_req_set_callback(subreq, wb_req_write_done, req);
177 125586 : return req;
178 : }
179 :
180 125586 : static void wb_req_write_done(struct tevent_req *subreq)
181 : {
182 125586 : struct tevent_req *req = tevent_req_callback_data(
183 : subreq, struct tevent_req);
184 125586 : struct req_write_state *state = tevent_req_data(
185 : req, struct req_write_state);
186 0 : int err;
187 :
188 125586 : state->ret = writev_recv(subreq, &err);
189 125586 : TALLOC_FREE(subreq);
190 125586 : if (state->ret < 0) {
191 0 : tevent_req_error(req, err);
192 0 : return;
193 : }
194 125586 : tevent_req_done(req);
195 : }
196 :
197 125586 : ssize_t wb_req_write_recv(struct tevent_req *req, int *err)
198 : {
199 125586 : struct req_write_state *state = tevent_req_data(
200 : req, struct req_write_state);
201 :
202 125586 : if (tevent_req_is_unix_error(req, err)) {
203 0 : return -1;
204 : }
205 125586 : 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 125586 : 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 125586 : req = tevent_req_create(mem_ctx, &state, struct resp_read_state);
223 125586 : if (req == NULL) {
224 0 : return NULL;
225 : }
226 :
227 125586 : subreq = read_packet_send(state, ev, fd, 4, wb_resp_more, state);
228 125586 : if (tevent_req_nomem(subreq, req)) {
229 0 : return tevent_req_post(req, ev);
230 : }
231 125586 : tevent_req_set_callback(subreq, wb_resp_read_done, req);
232 125586 : return req;
233 : }
234 :
235 251172 : static ssize_t wb_resp_more(uint8_t *buf, size_t buflen, void *private_data)
236 : {
237 251172 : struct winbindd_response *resp = (struct winbindd_response *)buf;
238 :
239 251172 : if (buflen == 4) {
240 125586 : 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 251172 : return resp->length - buflen;
249 : }
250 :
251 125586 : static void wb_resp_read_done(struct tevent_req *subreq)
252 : {
253 125586 : struct tevent_req *req = tevent_req_callback_data(
254 : subreq, struct tevent_req);
255 125586 : 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 125586 : state->ret = read_packet_recv(subreq, state, &buf, &err);
261 125586 : TALLOC_FREE(subreq);
262 125586 : if (state->ret == -1) {
263 0 : tevent_req_error(req, err);
264 0 : return;
265 : }
266 :
267 125586 : state->wb_resp = (struct winbindd_response *)buf;
268 :
269 125586 : if (state->wb_resp->length > sizeof(struct winbindd_response)) {
270 125384 : state->wb_resp->extra_data.data =
271 125384 : (char *)buf + sizeof(struct winbindd_response);
272 : } else {
273 202 : state->wb_resp->extra_data.data = NULL;
274 : }
275 125586 : tevent_req_done(req);
276 : }
277 :
278 125586 : ssize_t wb_resp_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
279 : struct winbindd_response **presp, int *err)
280 : {
281 125586 : struct resp_read_state *state = tevent_req_data(
282 : req, struct resp_read_state);
283 :
284 125586 : if (tevent_req_is_unix_error(req, err)) {
285 0 : return -1;
286 : }
287 125586 : *presp = talloc_move(mem_ctx, &state->wb_resp);
288 125586 : 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 247986 : 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 247986 : int count = 1;
306 :
307 247986 : req = tevent_req_create(mem_ctx, &state, struct resp_write_state);
308 247986 : if (req == NULL) {
309 0 : return NULL;
310 : }
311 :
312 247986 : state->iov[0].iov_base = (void *)wb_resp;
313 247986 : state->iov[0].iov_len = sizeof(struct winbindd_response);
314 :
315 247986 : if (wb_resp->length > sizeof(struct winbindd_response)) {
316 8459 : state->iov[1].iov_base = (void *)wb_resp->extra_data.data;
317 8459 : state->iov[1].iov_len =
318 8459 : wb_resp->length - sizeof(struct winbindd_response);
319 8459 : count = 2;
320 : }
321 :
322 247986 : subreq = writev_send(state, ev, queue, fd, true, state->iov, count);
323 247986 : if (tevent_req_nomem(subreq, req)) {
324 0 : return tevent_req_post(req, ev);
325 : }
326 247986 : tevent_req_set_callback(subreq, wb_resp_write_done, req);
327 247986 : return req;
328 : }
329 :
330 247986 : static void wb_resp_write_done(struct tevent_req *subreq)
331 : {
332 247986 : struct tevent_req *req = tevent_req_callback_data(
333 : subreq, struct tevent_req);
334 247986 : struct resp_write_state *state = tevent_req_data(
335 : req, struct resp_write_state);
336 0 : int err;
337 :
338 247986 : state->ret = writev_recv(subreq, &err);
339 247986 : TALLOC_FREE(subreq);
340 247986 : if (state->ret < 0) {
341 0 : tevent_req_error(req, err);
342 0 : return;
343 : }
344 247986 : tevent_req_done(req);
345 : }
346 :
347 247986 : ssize_t wb_resp_write_recv(struct tevent_req *req, int *err)
348 : {
349 247986 : struct resp_write_state *state = tevent_req_data(
350 : req, struct resp_write_state);
351 :
352 247986 : if (tevent_req_is_unix_error(req, err)) {
353 0 : return -1;
354 : }
355 247986 : 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 125586 : 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 125586 : req = tevent_req_create(mem_ctx, &state, struct wb_simple_trans_state);
376 125586 : if (req == NULL) {
377 0 : return NULL;
378 : }
379 :
380 125586 : wb_req->length = sizeof(struct winbindd_request);
381 :
382 125586 : state->ev = ev;
383 125586 : state->fd = fd;
384 :
385 125586 : subreq = wb_req_write_send(state, ev, queue, fd, wb_req);
386 125586 : if (tevent_req_nomem(subreq, req)) {
387 0 : return tevent_req_post(req, ev);
388 : }
389 125586 : tevent_req_set_callback(subreq, wb_simple_trans_write_done, req);
390 :
391 125586 : return req;
392 : }
393 :
394 125586 : static void wb_simple_trans_write_done(struct tevent_req *subreq)
395 : {
396 125586 : struct tevent_req *req = tevent_req_callback_data(
397 : subreq, struct tevent_req);
398 125586 : 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 125586 : ret = wb_req_write_recv(subreq, &err);
404 125586 : TALLOC_FREE(subreq);
405 125586 : if (ret == -1) {
406 0 : tevent_req_error(req, err);
407 0 : return;
408 : }
409 125586 : subreq = wb_resp_read_send(state, state->ev, state->fd);
410 125586 : if (tevent_req_nomem(subreq, req)) {
411 0 : return;
412 : }
413 125586 : tevent_req_set_callback(subreq, wb_simple_trans_read_done, req);
414 : }
415 :
416 125586 : static void wb_simple_trans_read_done(struct tevent_req *subreq)
417 : {
418 125586 : struct tevent_req *req = tevent_req_callback_data(
419 : subreq, struct tevent_req);
420 125586 : 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 125586 : ret = wb_resp_read_recv(subreq, state, &state->wb_resp, &err);
426 125586 : TALLOC_FREE(subreq);
427 125586 : if (ret == -1) {
428 0 : tevent_req_error(req, err);
429 0 : return;
430 : }
431 :
432 125586 : tevent_req_done(req);
433 : }
434 :
435 125586 : int wb_simple_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
436 : struct winbindd_response **presponse, int *err)
437 : {
438 125586 : struct wb_simple_trans_state *state = tevent_req_data(
439 : req, struct wb_simple_trans_state);
440 :
441 125586 : if (tevent_req_is_unix_error(req, err)) {
442 0 : return -1;
443 : }
444 125586 : *presponse = talloc_move(mem_ctx, &state->wb_resp);
445 125586 : return 0;
446 : }
|