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