Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : Infrastructure for async winbind requests
4 : Copyright (C) Volker Lendecke 2008
5 :
6 : ** NOTE! The following LGPL license applies to the wbclient
7 : ** library. This does NOT imply that all of Samba is released
8 : ** under the LGPL
9 :
10 : This library is free software; you can redistribute it and/or
11 : modify it under the terms of the GNU Lesser General Public
12 : License as published by the Free Software Foundation; either
13 : version 3 of the License, or (at your option) any later version.
14 :
15 : This library is distributed in the hope that it will be useful,
16 : but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 : Library General Public License for more details.
19 :
20 : You should have received a copy of the GNU Lesser General Public License
21 : along with this program. If not, see <http://www.gnu.org/licenses/>.
22 : */
23 :
24 : #include "replace.h"
25 : #include "system/filesys.h"
26 : #include "system/network.h"
27 : #include <talloc.h>
28 : #include <tevent.h>
29 : #include "lib/async_req/async_sock.h"
30 : #include "nsswitch/winbind_struct_protocol.h"
31 : #include "nsswitch/libwbclient/wbclient.h"
32 : #include "wbc_async.h"
33 : #include "lib/util/blocking.h"
34 :
35 0 : wbcErr map_wbc_err_from_errno(int error)
36 : {
37 0 : switch(error) {
38 0 : case EPERM:
39 : case EACCES:
40 0 : return WBC_ERR_AUTH_ERROR;
41 0 : case ENOMEM:
42 0 : return WBC_ERR_NO_MEMORY;
43 0 : case EIO:
44 : default:
45 0 : return WBC_ERR_UNKNOWN_FAILURE;
46 : }
47 : }
48 :
49 206 : bool tevent_req_is_wbcerr(struct tevent_req *req, wbcErr *pwbc_err)
50 : {
51 0 : enum tevent_req_state state;
52 0 : uint64_t error;
53 206 : if (!tevent_req_is_error(req, &state, &error)) {
54 206 : *pwbc_err = WBC_ERR_SUCCESS;
55 206 : return false;
56 : }
57 :
58 0 : switch (state) {
59 0 : case TEVENT_REQ_USER_ERROR:
60 0 : *pwbc_err = error;
61 0 : break;
62 0 : case TEVENT_REQ_TIMED_OUT:
63 0 : *pwbc_err = WBC_ERR_UNKNOWN_FAILURE;
64 0 : break;
65 0 : case TEVENT_REQ_NO_MEMORY:
66 0 : *pwbc_err = WBC_ERR_NO_MEMORY;
67 0 : break;
68 0 : default:
69 0 : *pwbc_err = WBC_ERR_UNKNOWN_FAILURE;
70 0 : break;
71 : }
72 0 : return true;
73 : }
74 :
75 6 : wbcErr tevent_req_simple_recv_wbcerr(struct tevent_req *req)
76 : {
77 0 : wbcErr wbc_err;
78 :
79 6 : if (tevent_req_is_wbcerr(req, &wbc_err)) {
80 0 : return wbc_err;
81 : }
82 :
83 6 : return WBC_ERR_SUCCESS;
84 : }
85 :
86 : struct wbc_debug_ops {
87 : void (*debug)(void *context, enum wbcDebugLevel level,
88 : const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0);
89 : void *context;
90 : };
91 :
92 : struct wb_context {
93 : struct tevent_queue *queue;
94 : int fd;
95 : bool is_priv;
96 : const char *dir;
97 : struct wbc_debug_ops debug_ops;
98 : };
99 :
100 4 : static int make_nonstd_fd(int fd)
101 : {
102 0 : size_t i;
103 4 : int sys_errno = 0;
104 0 : int fds[3];
105 4 : size_t num_fds = 0;
106 :
107 4 : if (fd == -1) {
108 0 : return -1;
109 : }
110 4 : while (fd < 3) {
111 0 : fds[num_fds++] = fd;
112 0 : fd = dup(fd);
113 0 : if (fd == -1) {
114 0 : sys_errno = errno;
115 0 : break;
116 : }
117 : }
118 4 : for (i=0; i<num_fds; i++) {
119 0 : close(fds[i]);
120 : }
121 4 : if (fd == -1) {
122 0 : errno = sys_errno;
123 : }
124 4 : return fd;
125 : }
126 :
127 : /****************************************************************************
128 : Set a fd into blocking/nonblocking mode.
129 : Set close on exec also.
130 : ****************************************************************************/
131 :
132 4 : static int make_safe_fd(int fd)
133 : {
134 0 : int result, flags;
135 4 : int new_fd = make_nonstd_fd(fd);
136 :
137 4 : if (new_fd == -1) {
138 0 : goto fail;
139 : }
140 :
141 4 : result = set_blocking(new_fd, false);
142 4 : if (result == -1) {
143 0 : goto fail;
144 : }
145 :
146 : /* Socket should be closed on exec() */
147 : #ifdef FD_CLOEXEC
148 4 : result = flags = fcntl(new_fd, F_GETFD, 0);
149 4 : if (flags >= 0) {
150 4 : flags |= FD_CLOEXEC;
151 4 : result = fcntl( new_fd, F_SETFD, flags );
152 : }
153 4 : if (result < 0) {
154 0 : goto fail;
155 : }
156 : #endif
157 4 : return new_fd;
158 :
159 0 : fail:
160 0 : if (new_fd != -1) {
161 0 : int sys_errno = errno;
162 0 : close(new_fd);
163 0 : errno = sys_errno;
164 : }
165 0 : return -1;
166 : }
167 :
168 : /* Just put a prototype to avoid moving the whole function around */
169 : static const char *winbindd_socket_dir(void);
170 :
171 2 : struct wb_context *wb_context_init(TALLOC_CTX *mem_ctx, const char* dir)
172 : {
173 0 : struct wb_context *result;
174 :
175 2 : result = talloc_zero(mem_ctx, struct wb_context);
176 2 : if (result == NULL) {
177 0 : return NULL;
178 : }
179 2 : result->queue = tevent_queue_create(result, "wb_trans");
180 2 : if (result->queue == NULL) {
181 0 : TALLOC_FREE(result);
182 0 : return NULL;
183 : }
184 2 : result->fd = -1;
185 2 : result->is_priv = false;
186 :
187 2 : if (dir != NULL) {
188 0 : result->dir = talloc_strdup(result, dir);
189 : } else {
190 2 : result->dir = winbindd_socket_dir();
191 : }
192 2 : if (result->dir == NULL) {
193 0 : TALLOC_FREE(result);
194 0 : return NULL;
195 : }
196 2 : return result;
197 : }
198 :
199 : struct wb_connect_state {
200 : int dummy;
201 : };
202 :
203 : static void wbc_connect_connected(struct tevent_req *subreq);
204 :
205 4 : static struct tevent_req *wb_connect_send(TALLOC_CTX *mem_ctx,
206 : struct tevent_context *ev,
207 : struct wb_context *wb_ctx,
208 : const char *dir)
209 : {
210 0 : struct tevent_req *result, *subreq;
211 0 : struct wb_connect_state *state;
212 0 : struct sockaddr_un sunaddr;
213 0 : struct stat st;
214 4 : char *path = NULL;
215 0 : wbcErr wbc_err;
216 :
217 4 : result = tevent_req_create(mem_ctx, &state, struct wb_connect_state);
218 4 : if (result == NULL) {
219 0 : return NULL;
220 : }
221 :
222 4 : if (wb_ctx->fd != -1) {
223 0 : close(wb_ctx->fd);
224 0 : wb_ctx->fd = -1;
225 : }
226 :
227 : /* Check permissions on unix socket directory */
228 :
229 4 : if (lstat(dir, &st) == -1) {
230 0 : wbc_err = WBC_ERR_WINBIND_NOT_AVAILABLE;
231 0 : goto post_status;
232 : }
233 :
234 4 : if (!S_ISDIR(st.st_mode) ||
235 4 : (st.st_uid != 0 && st.st_uid != geteuid())) {
236 0 : wbc_err = WBC_ERR_WINBIND_NOT_AVAILABLE;
237 0 : goto post_status;
238 : }
239 :
240 : /* Connect to socket */
241 :
242 4 : path = talloc_asprintf(mem_ctx, "%s/%s", dir,
243 : WINBINDD_SOCKET_NAME);
244 4 : if (path == NULL) {
245 0 : goto nomem;
246 : }
247 :
248 4 : sunaddr.sun_family = AF_UNIX;
249 4 : strlcpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path));
250 4 : TALLOC_FREE(path);
251 :
252 : /* If socket file doesn't exist, don't bother trying to connect
253 : with retry. This is an attempt to make the system usable when
254 : the winbindd daemon is not running. */
255 :
256 4 : if ((lstat(sunaddr.sun_path, &st) == -1)
257 4 : || !S_ISSOCK(st.st_mode)
258 4 : || (st.st_uid != 0 && st.st_uid != geteuid())) {
259 0 : wbc_err = WBC_ERR_WINBIND_NOT_AVAILABLE;
260 0 : goto post_status;
261 : }
262 :
263 4 : wb_ctx->fd = make_safe_fd(socket(AF_UNIX, SOCK_STREAM, 0));
264 4 : if (wb_ctx->fd == -1) {
265 0 : wbc_err = map_wbc_err_from_errno(errno);
266 0 : goto post_status;
267 : }
268 :
269 4 : subreq = async_connect_send(mem_ctx, ev, wb_ctx->fd,
270 : (struct sockaddr *)(void *)&sunaddr,
271 : sizeof(sunaddr), NULL, NULL, NULL);
272 4 : if (subreq == NULL) {
273 0 : goto nomem;
274 : }
275 4 : tevent_req_set_callback(subreq, wbc_connect_connected, result);
276 4 : return result;
277 :
278 0 : post_status:
279 0 : tevent_req_error(result, wbc_err);
280 0 : return tevent_req_post(result, ev);
281 0 : nomem:
282 0 : TALLOC_FREE(result);
283 0 : return NULL;
284 : }
285 :
286 4 : static void wbc_connect_connected(struct tevent_req *subreq)
287 : {
288 4 : struct tevent_req *req = tevent_req_callback_data(
289 : subreq, struct tevent_req);
290 0 : int res, err;
291 :
292 4 : res = async_connect_recv(subreq, &err);
293 4 : TALLOC_FREE(subreq);
294 4 : if (res == -1) {
295 0 : tevent_req_error(req, map_wbc_err_from_errno(err));
296 0 : return;
297 : }
298 4 : tevent_req_done(req);
299 : }
300 :
301 4 : static wbcErr wb_connect_recv(struct tevent_req *req)
302 : {
303 4 : return tevent_req_simple_recv_wbcerr(req);
304 : }
305 :
306 2 : static const char *winbindd_socket_dir(void)
307 : {
308 2 : if (nss_wrapper_enabled()) {
309 0 : const char *env_dir;
310 :
311 2 : env_dir = getenv("SELFTEST_WINBINDD_SOCKET_DIR");
312 2 : if (env_dir != NULL) {
313 2 : return env_dir;
314 : }
315 : }
316 :
317 0 : return WINBINDD_SOCKET_DIR;
318 : }
319 :
320 : struct wb_open_pipe_state {
321 : struct wb_context *wb_ctx;
322 : struct tevent_context *ev;
323 : bool need_priv;
324 : struct winbindd_request wb_req;
325 : };
326 :
327 : static void wb_open_pipe_connect_nonpriv_done(struct tevent_req *subreq);
328 : static void wb_open_pipe_ping_done(struct tevent_req *subreq);
329 : static void wb_open_pipe_getpriv_done(struct tevent_req *subreq);
330 : static void wb_open_pipe_connect_priv_done(struct tevent_req *subreq);
331 :
332 2 : static struct tevent_req *wb_open_pipe_send(TALLOC_CTX *mem_ctx,
333 : struct tevent_context *ev,
334 : struct wb_context *wb_ctx,
335 : bool need_priv)
336 : {
337 0 : struct tevent_req *result, *subreq;
338 0 : struct wb_open_pipe_state *state;
339 :
340 2 : result = tevent_req_create(mem_ctx, &state, struct wb_open_pipe_state);
341 2 : if (result == NULL) {
342 0 : return NULL;
343 : }
344 2 : state->wb_ctx = wb_ctx;
345 2 : state->ev = ev;
346 2 : state->need_priv = need_priv;
347 :
348 2 : if (wb_ctx->fd != -1) {
349 0 : close(wb_ctx->fd);
350 0 : wb_ctx->fd = -1;
351 : }
352 :
353 2 : subreq = wb_connect_send(state, ev, wb_ctx, wb_ctx->dir);
354 2 : if (subreq == NULL) {
355 0 : goto fail;
356 : }
357 2 : tevent_req_set_callback(subreq, wb_open_pipe_connect_nonpriv_done,
358 : result);
359 2 : return result;
360 :
361 0 : fail:
362 0 : TALLOC_FREE(result);
363 0 : return NULL;
364 : }
365 :
366 2 : static void wb_open_pipe_connect_nonpriv_done(struct tevent_req *subreq)
367 : {
368 2 : struct tevent_req *req = tevent_req_callback_data(
369 : subreq, struct tevent_req);
370 2 : struct wb_open_pipe_state *state = tevent_req_data(
371 : req, struct wb_open_pipe_state);
372 0 : wbcErr wbc_err;
373 :
374 2 : wbc_err = wb_connect_recv(subreq);
375 2 : TALLOC_FREE(subreq);
376 2 : if (!WBC_ERROR_IS_OK(wbc_err)) {
377 0 : state->wb_ctx->is_priv = true;
378 0 : tevent_req_error(req, wbc_err);
379 0 : return;
380 : }
381 :
382 2 : ZERO_STRUCT(state->wb_req);
383 2 : state->wb_req.cmd = WINBINDD_INTERFACE_VERSION;
384 2 : state->wb_req.pid = getpid();
385 2 : (void)snprintf(state->wb_req.client_name,
386 : sizeof(state->wb_req.client_name),
387 : "%s",
388 : "TORTURE");
389 :
390 2 : subreq = wb_simple_trans_send(state, state->ev, NULL,
391 2 : state->wb_ctx->fd, &state->wb_req);
392 2 : if (tevent_req_nomem(subreq, req)) {
393 0 : return;
394 : }
395 2 : tevent_req_set_callback(subreq, wb_open_pipe_ping_done, req);
396 : }
397 :
398 2 : static void wb_open_pipe_ping_done(struct tevent_req *subreq)
399 : {
400 2 : struct tevent_req *req = tevent_req_callback_data(
401 : subreq, struct tevent_req);
402 2 : struct wb_open_pipe_state *state = tevent_req_data(
403 : req, struct wb_open_pipe_state);
404 0 : struct winbindd_response *wb_resp;
405 0 : int ret, err;
406 :
407 2 : ret = wb_simple_trans_recv(subreq, state, &wb_resp, &err);
408 2 : TALLOC_FREE(subreq);
409 2 : if (ret == -1) {
410 0 : tevent_req_error(req, map_wbc_err_from_errno(err));
411 0 : return;
412 : }
413 :
414 2 : if (!state->need_priv) {
415 0 : tevent_req_done(req);
416 0 : return;
417 : }
418 :
419 2 : state->wb_req.cmd = WINBINDD_PRIV_PIPE_DIR;
420 2 : state->wb_req.pid = getpid();
421 :
422 2 : subreq = wb_simple_trans_send(state, state->ev, NULL,
423 2 : state->wb_ctx->fd, &state->wb_req);
424 2 : if (tevent_req_nomem(subreq, req)) {
425 0 : return;
426 : }
427 2 : tevent_req_set_callback(subreq, wb_open_pipe_getpriv_done, req);
428 : }
429 :
430 2 : static void wb_open_pipe_getpriv_done(struct tevent_req *subreq)
431 : {
432 2 : struct tevent_req *req = tevent_req_callback_data(
433 : subreq, struct tevent_req);
434 2 : struct wb_open_pipe_state *state = tevent_req_data(
435 : req, struct wb_open_pipe_state);
436 2 : struct winbindd_response *wb_resp = NULL;
437 0 : int ret, err;
438 :
439 2 : ret = wb_simple_trans_recv(subreq, state, &wb_resp, &err);
440 2 : TALLOC_FREE(subreq);
441 2 : if (ret == -1) {
442 0 : tevent_req_error(req, map_wbc_err_from_errno(err));
443 0 : return;
444 : }
445 :
446 2 : close(state->wb_ctx->fd);
447 2 : state->wb_ctx->fd = -1;
448 :
449 2 : subreq = wb_connect_send(state, state->ev, state->wb_ctx,
450 2 : (char *)wb_resp->extra_data.data);
451 2 : TALLOC_FREE(wb_resp);
452 2 : if (tevent_req_nomem(subreq, req)) {
453 0 : return;
454 : }
455 2 : tevent_req_set_callback(subreq, wb_open_pipe_connect_priv_done, req);
456 : }
457 :
458 2 : static void wb_open_pipe_connect_priv_done(struct tevent_req *subreq)
459 : {
460 2 : struct tevent_req *req = tevent_req_callback_data(
461 : subreq, struct tevent_req);
462 2 : struct wb_open_pipe_state *state = tevent_req_data(
463 : req, struct wb_open_pipe_state);
464 0 : wbcErr wbc_err;
465 :
466 2 : wbc_err = wb_connect_recv(subreq);
467 2 : TALLOC_FREE(subreq);
468 2 : if (!WBC_ERROR_IS_OK(wbc_err)) {
469 0 : tevent_req_error(req, wbc_err);
470 0 : return;
471 : }
472 2 : state->wb_ctx->is_priv = true;
473 2 : tevent_req_done(req);
474 : }
475 :
476 2 : static wbcErr wb_open_pipe_recv(struct tevent_req *req)
477 : {
478 2 : return tevent_req_simple_recv_wbcerr(req);
479 : }
480 :
481 : struct wb_trans_state {
482 : struct wb_trans_state *prev, *next;
483 : struct wb_context *wb_ctx;
484 : struct tevent_context *ev;
485 : struct winbindd_request *wb_req;
486 : struct winbindd_response *wb_resp;
487 : bool need_priv;
488 : };
489 :
490 198 : static bool closed_fd(int fd)
491 : {
492 0 : struct timeval tv;
493 0 : fd_set r_fds;
494 0 : int selret;
495 :
496 198 : if (fd == -1) {
497 0 : return true;
498 : }
499 :
500 3366 : FD_ZERO(&r_fds);
501 198 : FD_SET(fd, &r_fds);
502 198 : ZERO_STRUCT(tv);
503 :
504 198 : selret = select(fd+1, &r_fds, NULL, NULL, &tv);
505 198 : if (selret == -1) {
506 0 : return true;
507 : }
508 198 : if (selret == 0) {
509 198 : return false;
510 : }
511 0 : return (FD_ISSET(fd, &r_fds));
512 : }
513 :
514 : static void wb_trans_trigger(struct tevent_req *req, void *private_data);
515 : static void wb_trans_connect_done(struct tevent_req *subreq);
516 : static void wb_trans_done(struct tevent_req *subreq);
517 : static void wb_trans_retry_wait_done(struct tevent_req *subreq);
518 :
519 200 : struct tevent_req *wb_trans_send(TALLOC_CTX *mem_ctx,
520 : struct tevent_context *ev,
521 : struct wb_context *wb_ctx, bool need_priv,
522 : struct winbindd_request *wb_req)
523 : {
524 0 : struct tevent_req *req;
525 0 : struct wb_trans_state *state;
526 :
527 200 : req = tevent_req_create(mem_ctx, &state, struct wb_trans_state);
528 200 : if (req == NULL) {
529 0 : return NULL;
530 : }
531 200 : state->wb_ctx = wb_ctx;
532 200 : state->ev = ev;
533 200 : state->wb_req = wb_req;
534 200 : state->need_priv = need_priv;
535 :
536 200 : if (!tevent_queue_add(wb_ctx->queue, ev, req, wb_trans_trigger,
537 : NULL)) {
538 0 : tevent_req_oom(req);
539 0 : return tevent_req_post(req, ev);
540 : }
541 200 : return req;
542 : }
543 :
544 200 : static void wb_trans_trigger(struct tevent_req *req, void *private_data)
545 : {
546 200 : struct wb_trans_state *state = tevent_req_data(
547 : req, struct wb_trans_state);
548 0 : struct tevent_req *subreq;
549 :
550 200 : if ((state->wb_ctx->fd != -1) && closed_fd(state->wb_ctx->fd)) {
551 0 : close(state->wb_ctx->fd);
552 0 : state->wb_ctx->fd = -1;
553 : }
554 :
555 200 : if ((state->wb_ctx->fd == -1)
556 198 : || (state->need_priv && !state->wb_ctx->is_priv)) {
557 2 : subreq = wb_open_pipe_send(state, state->ev, state->wb_ctx,
558 2 : state->need_priv);
559 2 : if (tevent_req_nomem(subreq, req)) {
560 0 : return;
561 : }
562 2 : tevent_req_set_callback(subreq, wb_trans_connect_done, req);
563 2 : return;
564 : }
565 :
566 198 : state->wb_req->pid = getpid();
567 :
568 198 : subreq = wb_simple_trans_send(state, state->ev, NULL,
569 198 : state->wb_ctx->fd, state->wb_req);
570 198 : if (tevent_req_nomem(subreq, req)) {
571 0 : return;
572 : }
573 198 : tevent_req_set_callback(subreq, wb_trans_done, req);
574 : }
575 :
576 2 : static bool wb_trans_retry(struct tevent_req *req,
577 : struct wb_trans_state *state,
578 : wbcErr wbc_err)
579 : {
580 0 : struct tevent_req *subreq;
581 :
582 2 : if (WBC_ERROR_IS_OK(wbc_err)) {
583 2 : return false;
584 : }
585 :
586 0 : if (wbc_err == WBC_ERR_WINBIND_NOT_AVAILABLE) {
587 : /*
588 : * Winbind not around or we can't connect to the pipe. Fail
589 : * immediately.
590 : */
591 0 : tevent_req_error(req, wbc_err);
592 0 : return true;
593 : }
594 :
595 : /*
596 : * The transfer as such failed, retry after one second
597 : */
598 :
599 0 : if (state->wb_ctx->fd != -1) {
600 0 : close(state->wb_ctx->fd);
601 0 : state->wb_ctx->fd = -1;
602 : }
603 :
604 0 : subreq = tevent_wakeup_send(state, state->ev,
605 : tevent_timeval_current_ofs(1, 0));
606 0 : if (tevent_req_nomem(subreq, req)) {
607 0 : return true;
608 : }
609 0 : tevent_req_set_callback(subreq, wb_trans_retry_wait_done, req);
610 0 : return true;
611 : }
612 :
613 0 : static void wb_trans_retry_wait_done(struct tevent_req *subreq)
614 : {
615 0 : struct tevent_req *req = tevent_req_callback_data(
616 : subreq, struct tevent_req);
617 0 : struct wb_trans_state *state = tevent_req_data(
618 : req, struct wb_trans_state);
619 0 : bool ret;
620 :
621 0 : ret = tevent_wakeup_recv(subreq);
622 0 : TALLOC_FREE(subreq);
623 0 : if (!ret) {
624 0 : tevent_req_error(req, WBC_ERR_UNKNOWN_FAILURE);
625 0 : return;
626 : }
627 :
628 0 : subreq = wb_open_pipe_send(state, state->ev, state->wb_ctx,
629 0 : state->need_priv);
630 0 : if (tevent_req_nomem(subreq, req)) {
631 0 : return;
632 : }
633 0 : tevent_req_set_callback(subreq, wb_trans_connect_done, req);
634 : }
635 :
636 2 : static void wb_trans_connect_done(struct tevent_req *subreq)
637 : {
638 2 : struct tevent_req *req = tevent_req_callback_data(
639 : subreq, struct tevent_req);
640 2 : struct wb_trans_state *state = tevent_req_data(
641 : req, struct wb_trans_state);
642 0 : wbcErr wbc_err;
643 :
644 2 : wbc_err = wb_open_pipe_recv(subreq);
645 2 : TALLOC_FREE(subreq);
646 :
647 2 : if (wb_trans_retry(req, state, wbc_err)) {
648 0 : return;
649 : }
650 :
651 2 : subreq = wb_simple_trans_send(state, state->ev, NULL,
652 2 : state->wb_ctx->fd, state->wb_req);
653 2 : if (tevent_req_nomem(subreq, req)) {
654 0 : return;
655 : }
656 2 : tevent_req_set_callback(subreq, wb_trans_done, req);
657 : }
658 :
659 200 : static void wb_trans_done(struct tevent_req *subreq)
660 : {
661 200 : struct tevent_req *req = tevent_req_callback_data(
662 : subreq, struct tevent_req);
663 200 : struct wb_trans_state *state = tevent_req_data(
664 : req, struct wb_trans_state);
665 0 : int ret, err;
666 :
667 200 : ret = wb_simple_trans_recv(subreq, state, &state->wb_resp, &err);
668 200 : TALLOC_FREE(subreq);
669 200 : if ((ret == -1)
670 0 : && wb_trans_retry(req, state, map_wbc_err_from_errno(err))) {
671 0 : return;
672 : }
673 :
674 200 : tevent_req_done(req);
675 : }
676 :
677 200 : wbcErr wb_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
678 : struct winbindd_response **presponse)
679 : {
680 200 : struct wb_trans_state *state = tevent_req_data(
681 : req, struct wb_trans_state);
682 0 : wbcErr wbc_err;
683 :
684 200 : if (tevent_req_is_wbcerr(req, &wbc_err)) {
685 0 : return wbc_err;
686 : }
687 :
688 200 : *presponse = talloc_move(mem_ctx, &state->wb_resp);
689 200 : return WBC_ERR_SUCCESS;
690 : }
691 :
692 : /********************************************************************
693 : * Debug wrapper functions, modeled (with lot's of code copied as is)
694 : * after the tevent debug wrapper functions
695 : ********************************************************************/
696 :
697 : /*
698 : this allows the user to choose their own debug function
699 : */
700 0 : int wbcSetDebug(struct wb_context *wb_ctx,
701 : void (*debug)(void *context,
702 : enum wbcDebugLevel level,
703 : const char *fmt,
704 : va_list ap) PRINTF_ATTRIBUTE(3,0),
705 : void *context)
706 : {
707 0 : wb_ctx->debug_ops.debug = debug;
708 0 : wb_ctx->debug_ops.context = context;
709 0 : return 0;
710 : }
711 :
712 : /*
713 : debug function for wbcSetDebugStderr
714 : */
715 : static void wbcDebugStderr(void *private_data,
716 : enum wbcDebugLevel level,
717 : const char *fmt,
718 : va_list ap) PRINTF_ATTRIBUTE(3,0);
719 0 : static void wbcDebugStderr(void *private_data,
720 : enum wbcDebugLevel level,
721 : const char *fmt, va_list ap)
722 : {
723 0 : if (level <= WBC_DEBUG_WARNING) {
724 0 : vfprintf(stderr, fmt, ap);
725 : }
726 0 : }
727 :
728 : /*
729 : convenience function to setup debug messages on stderr
730 : messages of level WBC_DEBUG_WARNING and higher are printed
731 : */
732 0 : int wbcSetDebugStderr(struct wb_context *wb_ctx)
733 : {
734 0 : return wbcSetDebug(wb_ctx, wbcDebugStderr, wb_ctx);
735 : }
736 :
737 : /*
738 : * log a message
739 : *
740 : * The default debug action is to ignore debugging messages.
741 : * This is the most appropriate action for a library.
742 : * Applications using the library must decide where to
743 : * redirect debugging messages
744 : */
745 0 : void wbcDebug(struct wb_context *wb_ctx, enum wbcDebugLevel level,
746 : const char *fmt, ...)
747 : {
748 0 : va_list ap;
749 0 : if (!wb_ctx) {
750 0 : return;
751 : }
752 0 : if (wb_ctx->debug_ops.debug == NULL) {
753 0 : return;
754 : }
755 0 : va_start(ap, fmt);
756 0 : wb_ctx->debug_ops.debug(wb_ctx->debug_ops.context, level, fmt, ap);
757 0 : va_end(ap);
758 : }
|