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