wbinfo: Free memory when we leave wbinfo_dsgetdcname()
[gd/samba-autobuild/.git] / nsswitch / wb_reqtrans.c
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 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         req = tevent_req_create(mem_ctx, &state, struct req_read_state);
57         if (req == NULL) {
58                 return NULL;
59         }
60         state->max_extra_data = max_extra_data;
61
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);
65         }
66         tevent_req_set_callback(subreq, wb_req_read_done, req);
67         return req;
68 }
69
70 static ssize_t wb_req_more(uint8_t *buf, size_t buflen, void *private_data)
71 {
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;
75
76         if (buflen == 4) {
77                 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                         return -1;
83                 }
84                 return sizeof(struct winbindd_request) - 4;
85         }
86
87         if (buflen > sizeof(struct winbindd_request)) {
88                 /* We've been here, we're done */
89                 return 0;
90         }
91
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));
96                 return -1;
97         }
98
99         return req->extra_len;
100 }
101
102 static void wb_req_read_done(struct tevent_req *subreq)
103 {
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);
108         int err;
109         uint8_t *buf;
110
111         state->ret = read_packet_recv(subreq, state, &buf, &err);
112         TALLOC_FREE(subreq);
113         if (state->ret == -1) {
114                 tevent_req_error(req, err);
115                 return;
116         }
117
118         state->wb_req = (struct winbindd_request *)buf;
119
120         if (state->wb_req->extra_len != 0) {
121                 state->wb_req->extra_data.data =
122                         (char *)buf + sizeof(struct winbindd_request);
123         } else {
124                 state->wb_req->extra_data.data = NULL;
125         }
126         tevent_req_done(req);
127 }
128
129 ssize_t wb_req_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
130                          struct winbindd_request **preq, int *err)
131 {
132         struct req_read_state *state = tevent_req_data(
133                 req, struct req_read_state);
134
135         if (tevent_req_is_unix_error(req, err)) {
136                 return -1;
137         }
138         *preq = talloc_move(mem_ctx, &state->wb_req);
139         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 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         int count = 1;
157
158         req = tevent_req_create(mem_ctx, &state, struct req_write_state);
159         if (req == NULL) {
160                 return NULL;
161         }
162
163         state->iov[0].iov_base = (void *)wb_req;
164         state->iov[0].iov_len = sizeof(struct winbindd_request);
165
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;
169                 count = 2;
170         }
171
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);
175         }
176         tevent_req_set_callback(subreq, wb_req_write_done, req);
177         return req;
178 }
179
180 static void wb_req_write_done(struct tevent_req *subreq)
181 {
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);
186         int err;
187
188         state->ret = writev_recv(subreq, &err);
189         TALLOC_FREE(subreq);
190         if (state->ret < 0) {
191                 tevent_req_error(req, err);
192                 return;
193         }
194         tevent_req_done(req);
195 }
196
197 ssize_t wb_req_write_recv(struct tevent_req *req, int *err)
198 {
199         struct req_write_state *state = tevent_req_data(
200                 req, struct req_write_state);
201
202         if (tevent_req_is_unix_error(req, err)) {
203                 return -1;
204         }
205         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 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         req = tevent_req_create(mem_ctx, &state, struct resp_read_state);
223         if (req == NULL) {
224                 return NULL;
225         }
226
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);
230         }
231         tevent_req_set_callback(subreq, wb_resp_read_done, req);
232         return req;
233 }
234
235 static ssize_t wb_resp_more(uint8_t *buf, size_t buflen, void *private_data)
236 {
237         struct winbindd_response *resp = (struct winbindd_response *)buf;
238
239         if (buflen == 4) {
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",
243                                   (int)resp->length,
244                                   (int)sizeof(struct winbindd_response)));
245                         return -1;
246                 }
247         }
248         return resp->length - buflen;
249 }
250
251 static void wb_resp_read_done(struct tevent_req *subreq)
252 {
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);
257         uint8_t *buf;
258         int err;
259
260         state->ret = read_packet_recv(subreq, state, &buf, &err);
261         TALLOC_FREE(subreq);
262         if (state->ret == -1) {
263                 tevent_req_error(req, err);
264                 return;
265         }
266
267         state->wb_resp = (struct winbindd_response *)buf;
268
269         if (state->wb_resp->length > sizeof(struct winbindd_response)) {
270                 state->wb_resp->extra_data.data =
271                         (char *)buf + sizeof(struct winbindd_response);
272         } else {
273                 state->wb_resp->extra_data.data = NULL;
274         }
275         tevent_req_done(req);
276 }
277
278 ssize_t wb_resp_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
279                           struct winbindd_response **presp, int *err)
280 {
281         struct resp_read_state *state = tevent_req_data(
282                 req, struct resp_read_state);
283
284         if (tevent_req_is_unix_error(req, err)) {
285                 return -1;
286         }
287         *presp = talloc_move(mem_ctx, &state->wb_resp);
288         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 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         int count = 1;
306
307         req = tevent_req_create(mem_ctx, &state, struct resp_write_state);
308         if (req == NULL) {
309                 return NULL;
310         }
311
312         state->iov[0].iov_base = (void *)wb_resp;
313         state->iov[0].iov_len = sizeof(struct winbindd_response);
314
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);
319                 count = 2;
320         }
321
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);
325         }
326         tevent_req_set_callback(subreq, wb_resp_write_done, req);
327         return req;
328 }
329
330 static void wb_resp_write_done(struct tevent_req *subreq)
331 {
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);
336         int err;
337
338         state->ret = writev_recv(subreq, &err);
339         TALLOC_FREE(subreq);
340         if (state->ret < 0) {
341                 tevent_req_error(req, err);
342                 return;
343         }
344         tevent_req_done(req);
345 }
346
347 ssize_t wb_resp_write_recv(struct tevent_req *req, int *err)
348 {
349         struct resp_write_state *state = tevent_req_data(
350                 req, struct resp_write_state);
351
352         if (tevent_req_is_unix_error(req, err)) {
353                 return -1;
354         }
355         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 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         req = tevent_req_create(mem_ctx, &state, struct wb_simple_trans_state);
376         if (req == NULL) {
377                 return NULL;
378         }
379
380         wb_req->length = sizeof(struct winbindd_request);
381
382         state->ev = ev;
383         state->fd = fd;
384
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);
388         }
389         tevent_req_set_callback(subreq, wb_simple_trans_write_done, req);
390
391         return req;
392 }
393
394 static void wb_simple_trans_write_done(struct tevent_req *subreq)
395 {
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);
400         ssize_t ret;
401         int err;
402
403         ret = wb_req_write_recv(subreq, &err);
404         TALLOC_FREE(subreq);
405         if (ret == -1) {
406                 tevent_req_error(req, err);
407                 return;
408         }
409         subreq = wb_resp_read_send(state, state->ev, state->fd);
410         if (tevent_req_nomem(subreq, req)) {
411                 return;
412         }
413         tevent_req_set_callback(subreq, wb_simple_trans_read_done, req);
414 }
415
416 static void wb_simple_trans_read_done(struct tevent_req *subreq)
417 {
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);
422         ssize_t ret;
423         int err;
424
425         ret = wb_resp_read_recv(subreq, state, &state->wb_resp, &err);
426         TALLOC_FREE(subreq);
427         if (ret == -1) {
428                 tevent_req_error(req, err);
429                 return;
430         }
431
432         tevent_req_done(req);
433 }
434
435 int wb_simple_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
436                          struct winbindd_response **presponse, int *err)
437 {
438         struct wb_simple_trans_state *state = tevent_req_data(
439                 req, struct wb_simple_trans_state);
440
441         if (tevent_req_is_unix_error(req, err)) {
442                 return -1;
443         }
444         *presponse = talloc_move(mem_ctx, &state->wb_resp);
445         return 0;
446 }