2 Unix SMB/CIFS implementation.
3 Infrastructure for async winbind requests
4 Copyright (C) Volker Lendecke 2008
6 ** NOTE! The following LGPL license applies to the wbclient
7 ** library. This does NOT imply that all of Samba is released
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.
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.
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/>.
25 #include "system/filesys.h"
26 #include "system/network.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"
35 wbcErr
map_wbc_err_from_errno(int error
)
40 return WBC_ERR_AUTH_ERROR
;
42 return WBC_ERR_NO_MEMORY
;
45 return WBC_ERR_UNKNOWN_FAILURE
;
49 bool tevent_req_is_wbcerr(struct tevent_req
*req
, wbcErr
*pwbc_err
)
51 enum tevent_req_state state
;
53 if (!tevent_req_is_error(req
, &state
, &error
)) {
54 *pwbc_err
= WBC_ERR_SUCCESS
;
59 case TEVENT_REQ_USER_ERROR
:
62 case TEVENT_REQ_TIMED_OUT
:
63 *pwbc_err
= WBC_ERR_UNKNOWN_FAILURE
;
65 case TEVENT_REQ_NO_MEMORY
:
66 *pwbc_err
= WBC_ERR_NO_MEMORY
;
69 *pwbc_err
= WBC_ERR_UNKNOWN_FAILURE
;
75 wbcErr
tevent_req_simple_recv_wbcerr(struct tevent_req
*req
)
79 if (tevent_req_is_wbcerr(req
, &wbc_err
)) {
83 return WBC_ERR_SUCCESS
;
86 struct wbc_debug_ops
{
87 void (*debug
)(void *context
, enum wbcDebugLevel level
,
88 const char *fmt
, va_list ap
) PRINTF_ATTRIBUTE(3,0);
93 struct tevent_queue
*queue
;
97 struct wbc_debug_ops debug_ops
;
100 static int make_nonstd_fd(int fd
)
118 for (i
=0; i
<num_fds
; i
++) {
127 /****************************************************************************
128 Set a fd into blocking/nonblocking mode.
129 Set close on exec also.
130 ****************************************************************************/
132 static int make_safe_fd(int fd
)
135 int new_fd
= make_nonstd_fd(fd
);
141 result
= set_blocking(new_fd
, false);
146 /* Socket should be closed on exec() */
148 result
= flags
= fcntl(new_fd
, F_GETFD
, 0);
151 result
= fcntl( new_fd
, F_SETFD
, flags
);
161 int sys_errno
= errno
;
168 /* Just put a prototype to avoid moving the whole function around */
169 static const char *winbindd_socket_dir(void);
171 struct wb_context
*wb_context_init(TALLOC_CTX
*mem_ctx
, const char* dir
)
173 struct wb_context
*result
;
175 result
= talloc_zero(mem_ctx
, struct wb_context
);
176 if (result
== NULL
) {
179 result
->queue
= tevent_queue_create(result
, "wb_trans");
180 if (result
->queue
== NULL
) {
185 result
->is_priv
= false;
188 result
->dir
= talloc_strdup(result
, dir
);
190 result
->dir
= winbindd_socket_dir();
192 if (result
->dir
== NULL
) {
199 struct wb_connect_state
{
203 static void wbc_connect_connected(struct tevent_req
*subreq
);
205 static struct tevent_req
*wb_connect_send(TALLOC_CTX
*mem_ctx
,
206 struct tevent_context
*ev
,
207 struct wb_context
*wb_ctx
,
210 struct tevent_req
*result
, *subreq
;
211 struct wb_connect_state
*state
;
212 struct sockaddr_un sunaddr
;
217 result
= tevent_req_create(mem_ctx
, &state
, struct wb_connect_state
);
218 if (result
== NULL
) {
222 if (wb_ctx
->fd
!= -1) {
227 /* Check permissions on unix socket directory */
229 if (lstat(dir
, &st
) == -1) {
230 wbc_err
= WBC_ERR_WINBIND_NOT_AVAILABLE
;
234 if (!S_ISDIR(st
.st_mode
) ||
235 (st
.st_uid
!= 0 && st
.st_uid
!= geteuid())) {
236 wbc_err
= WBC_ERR_WINBIND_NOT_AVAILABLE
;
240 /* Connect to socket */
242 path
= talloc_asprintf(mem_ctx
, "%s/%s", dir
,
243 WINBINDD_SOCKET_NAME
);
248 sunaddr
.sun_family
= AF_UNIX
;
249 strlcpy(sunaddr
.sun_path
, path
, sizeof(sunaddr
.sun_path
));
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. */
256 if ((lstat(sunaddr
.sun_path
, &st
) == -1)
257 || !S_ISSOCK(st
.st_mode
)
258 || (st
.st_uid
!= 0 && st
.st_uid
!= geteuid())) {
259 wbc_err
= WBC_ERR_WINBIND_NOT_AVAILABLE
;
263 wb_ctx
->fd
= make_safe_fd(socket(AF_UNIX
, SOCK_STREAM
, 0));
264 if (wb_ctx
->fd
== -1) {
265 wbc_err
= map_wbc_err_from_errno(errno
);
269 subreq
= async_connect_send(mem_ctx
, ev
, wb_ctx
->fd
,
270 (struct sockaddr
*)(void *)&sunaddr
,
271 sizeof(sunaddr
), NULL
, NULL
, NULL
);
272 if (subreq
== NULL
) {
275 tevent_req_set_callback(subreq
, wbc_connect_connected
, result
);
279 tevent_req_error(result
, wbc_err
);
280 return tevent_req_post(result
, ev
);
286 static void wbc_connect_connected(struct tevent_req
*subreq
)
288 struct tevent_req
*req
= tevent_req_callback_data(
289 subreq
, struct tevent_req
);
292 res
= async_connect_recv(subreq
, &err
);
295 tevent_req_error(req
, map_wbc_err_from_errno(err
));
298 tevent_req_done(req
);
301 static wbcErr
wb_connect_recv(struct tevent_req
*req
)
303 return tevent_req_simple_recv_wbcerr(req
);
306 static const char *winbindd_socket_dir(void)
308 if (nss_wrapper_enabled()) {
311 env_dir
= getenv("SELFTEST_WINBINDD_SOCKET_DIR");
312 if (env_dir
!= NULL
) {
317 return WINBINDD_SOCKET_DIR
;
320 struct wb_open_pipe_state
{
321 struct wb_context
*wb_ctx
;
322 struct tevent_context
*ev
;
324 struct winbindd_request wb_req
;
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
);
332 static struct tevent_req
*wb_open_pipe_send(TALLOC_CTX
*mem_ctx
,
333 struct tevent_context
*ev
,
334 struct wb_context
*wb_ctx
,
337 struct tevent_req
*result
, *subreq
;
338 struct wb_open_pipe_state
*state
;
340 result
= tevent_req_create(mem_ctx
, &state
, struct wb_open_pipe_state
);
341 if (result
== NULL
) {
344 state
->wb_ctx
= wb_ctx
;
346 state
->need_priv
= need_priv
;
348 if (wb_ctx
->fd
!= -1) {
353 subreq
= wb_connect_send(state
, ev
, wb_ctx
, wb_ctx
->dir
);
354 if (subreq
== NULL
) {
357 tevent_req_set_callback(subreq
, wb_open_pipe_connect_nonpriv_done
,
366 static void wb_open_pipe_connect_nonpriv_done(struct tevent_req
*subreq
)
368 struct tevent_req
*req
= tevent_req_callback_data(
369 subreq
, struct tevent_req
);
370 struct wb_open_pipe_state
*state
= tevent_req_data(
371 req
, struct wb_open_pipe_state
);
374 wbc_err
= wb_connect_recv(subreq
);
376 if (!WBC_ERROR_IS_OK(wbc_err
)) {
377 state
->wb_ctx
->is_priv
= true;
378 tevent_req_error(req
, wbc_err
);
382 ZERO_STRUCT(state
->wb_req
);
383 state
->wb_req
.cmd
= WINBINDD_INTERFACE_VERSION
;
384 state
->wb_req
.pid
= getpid();
385 (void)snprintf(state
->wb_req
.client_name
,
386 sizeof(state
->wb_req
.client_name
),
390 subreq
= wb_simple_trans_send(state
, state
->ev
, NULL
,
391 state
->wb_ctx
->fd
, &state
->wb_req
);
392 if (tevent_req_nomem(subreq
, req
)) {
395 tevent_req_set_callback(subreq
, wb_open_pipe_ping_done
, req
);
398 static void wb_open_pipe_ping_done(struct tevent_req
*subreq
)
400 struct tevent_req
*req
= tevent_req_callback_data(
401 subreq
, struct tevent_req
);
402 struct wb_open_pipe_state
*state
= tevent_req_data(
403 req
, struct wb_open_pipe_state
);
404 struct winbindd_response
*wb_resp
;
407 ret
= wb_simple_trans_recv(subreq
, state
, &wb_resp
, &err
);
410 tevent_req_error(req
, map_wbc_err_from_errno(err
));
414 if (!state
->need_priv
) {
415 tevent_req_done(req
);
419 state
->wb_req
.cmd
= WINBINDD_PRIV_PIPE_DIR
;
420 state
->wb_req
.pid
= getpid();
422 subreq
= wb_simple_trans_send(state
, state
->ev
, NULL
,
423 state
->wb_ctx
->fd
, &state
->wb_req
);
424 if (tevent_req_nomem(subreq
, req
)) {
427 tevent_req_set_callback(subreq
, wb_open_pipe_getpriv_done
, req
);
430 static void wb_open_pipe_getpriv_done(struct tevent_req
*subreq
)
432 struct tevent_req
*req
= tevent_req_callback_data(
433 subreq
, struct tevent_req
);
434 struct wb_open_pipe_state
*state
= tevent_req_data(
435 req
, struct wb_open_pipe_state
);
436 struct winbindd_response
*wb_resp
= NULL
;
439 ret
= wb_simple_trans_recv(subreq
, state
, &wb_resp
, &err
);
442 tevent_req_error(req
, map_wbc_err_from_errno(err
));
446 close(state
->wb_ctx
->fd
);
447 state
->wb_ctx
->fd
= -1;
449 subreq
= wb_connect_send(state
, state
->ev
, state
->wb_ctx
,
450 (char *)wb_resp
->extra_data
.data
);
451 TALLOC_FREE(wb_resp
);
452 if (tevent_req_nomem(subreq
, req
)) {
455 tevent_req_set_callback(subreq
, wb_open_pipe_connect_priv_done
, req
);
458 static void wb_open_pipe_connect_priv_done(struct tevent_req
*subreq
)
460 struct tevent_req
*req
= tevent_req_callback_data(
461 subreq
, struct tevent_req
);
462 struct wb_open_pipe_state
*state
= tevent_req_data(
463 req
, struct wb_open_pipe_state
);
466 wbc_err
= wb_connect_recv(subreq
);
468 if (!WBC_ERROR_IS_OK(wbc_err
)) {
469 tevent_req_error(req
, wbc_err
);
472 state
->wb_ctx
->is_priv
= true;
473 tevent_req_done(req
);
476 static wbcErr
wb_open_pipe_recv(struct tevent_req
*req
)
478 return tevent_req_simple_recv_wbcerr(req
);
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
;
490 static bool closed_fd(int fd
)
504 selret
= select(fd
+1, &r_fds
, NULL
, NULL
, &tv
);
511 return (FD_ISSET(fd
, &r_fds
));
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
);
519 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
)
524 struct tevent_req
*req
;
525 struct wb_trans_state
*state
;
527 req
= tevent_req_create(mem_ctx
, &state
, struct wb_trans_state
);
531 state
->wb_ctx
= wb_ctx
;
533 state
->wb_req
= wb_req
;
534 state
->need_priv
= need_priv
;
536 if (!tevent_queue_add(wb_ctx
->queue
, ev
, req
, wb_trans_trigger
,
539 return tevent_req_post(req
, ev
);
544 static void wb_trans_trigger(struct tevent_req
*req
, void *private_data
)
546 struct wb_trans_state
*state
= tevent_req_data(
547 req
, struct wb_trans_state
);
548 struct tevent_req
*subreq
;
550 if ((state
->wb_ctx
->fd
!= -1) && closed_fd(state
->wb_ctx
->fd
)) {
551 close(state
->wb_ctx
->fd
);
552 state
->wb_ctx
->fd
= -1;
555 if ((state
->wb_ctx
->fd
== -1)
556 || (state
->need_priv
&& !state
->wb_ctx
->is_priv
)) {
557 subreq
= wb_open_pipe_send(state
, state
->ev
, state
->wb_ctx
,
559 if (tevent_req_nomem(subreq
, req
)) {
562 tevent_req_set_callback(subreq
, wb_trans_connect_done
, req
);
566 state
->wb_req
->pid
= getpid();
568 subreq
= wb_simple_trans_send(state
, state
->ev
, NULL
,
569 state
->wb_ctx
->fd
, state
->wb_req
);
570 if (tevent_req_nomem(subreq
, req
)) {
573 tevent_req_set_callback(subreq
, wb_trans_done
, req
);
576 static bool wb_trans_retry(struct tevent_req
*req
,
577 struct wb_trans_state
*state
,
580 struct tevent_req
*subreq
;
582 if (WBC_ERROR_IS_OK(wbc_err
)) {
586 if (wbc_err
== WBC_ERR_WINBIND_NOT_AVAILABLE
) {
588 * Winbind not around or we can't connect to the pipe. Fail
591 tevent_req_error(req
, wbc_err
);
596 * The transfer as such failed, retry after one second
599 if (state
->wb_ctx
->fd
!= -1) {
600 close(state
->wb_ctx
->fd
);
601 state
->wb_ctx
->fd
= -1;
604 subreq
= tevent_wakeup_send(state
, state
->ev
,
605 tevent_timeval_current_ofs(1, 0));
606 if (tevent_req_nomem(subreq
, req
)) {
609 tevent_req_set_callback(subreq
, wb_trans_retry_wait_done
, req
);
613 static void wb_trans_retry_wait_done(struct tevent_req
*subreq
)
615 struct tevent_req
*req
= tevent_req_callback_data(
616 subreq
, struct tevent_req
);
617 struct wb_trans_state
*state
= tevent_req_data(
618 req
, struct wb_trans_state
);
621 ret
= tevent_wakeup_recv(subreq
);
624 tevent_req_error(req
, WBC_ERR_UNKNOWN_FAILURE
);
628 subreq
= wb_open_pipe_send(state
, state
->ev
, state
->wb_ctx
,
630 if (tevent_req_nomem(subreq
, req
)) {
633 tevent_req_set_callback(subreq
, wb_trans_connect_done
, req
);
636 static void wb_trans_connect_done(struct tevent_req
*subreq
)
638 struct tevent_req
*req
= tevent_req_callback_data(
639 subreq
, struct tevent_req
);
640 struct wb_trans_state
*state
= tevent_req_data(
641 req
, struct wb_trans_state
);
644 wbc_err
= wb_open_pipe_recv(subreq
);
647 if (wb_trans_retry(req
, state
, wbc_err
)) {
651 subreq
= wb_simple_trans_send(state
, state
->ev
, NULL
,
652 state
->wb_ctx
->fd
, state
->wb_req
);
653 if (tevent_req_nomem(subreq
, req
)) {
656 tevent_req_set_callback(subreq
, wb_trans_done
, req
);
659 static void wb_trans_done(struct tevent_req
*subreq
)
661 struct tevent_req
*req
= tevent_req_callback_data(
662 subreq
, struct tevent_req
);
663 struct wb_trans_state
*state
= tevent_req_data(
664 req
, struct wb_trans_state
);
667 ret
= wb_simple_trans_recv(subreq
, state
, &state
->wb_resp
, &err
);
670 && wb_trans_retry(req
, state
, map_wbc_err_from_errno(err
))) {
674 tevent_req_done(req
);
677 wbcErr
wb_trans_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
678 struct winbindd_response
**presponse
)
680 struct wb_trans_state
*state
= tevent_req_data(
681 req
, struct wb_trans_state
);
684 if (tevent_req_is_wbcerr(req
, &wbc_err
)) {
688 *presponse
= talloc_move(mem_ctx
, &state
->wb_resp
);
689 return WBC_ERR_SUCCESS
;
692 /********************************************************************
693 * Debug wrapper functions, modeled (with lot's of code copied as is)
694 * after the tevent debug wrapper functions
695 ********************************************************************/
698 this allows the user to choose their own debug function
700 int wbcSetDebug(struct wb_context
*wb_ctx
,
701 void (*debug
)(void *context
,
702 enum wbcDebugLevel level
,
704 va_list ap
) PRINTF_ATTRIBUTE(3,0),
707 wb_ctx
->debug_ops
.debug
= debug
;
708 wb_ctx
->debug_ops
.context
= context
;
713 debug function for wbcSetDebugStderr
715 static void wbcDebugStderr(void *private_data
,
716 enum wbcDebugLevel level
,
718 va_list ap
) PRINTF_ATTRIBUTE(3,0);
719 static void wbcDebugStderr(void *private_data
,
720 enum wbcDebugLevel level
,
721 const char *fmt
, va_list ap
)
723 if (level
<= WBC_DEBUG_WARNING
) {
724 vfprintf(stderr
, fmt
, ap
);
729 convenience function to setup debug messages on stderr
730 messages of level WBC_DEBUG_WARNING and higher are printed
732 int wbcSetDebugStderr(struct wb_context
*wb_ctx
)
734 return wbcSetDebug(wb_ctx
, wbcDebugStderr
, wb_ctx
);
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
745 void wbcDebug(struct wb_context
*wb_ctx
, enum wbcDebugLevel level
,
746 const char *fmt
, ...)
752 if (wb_ctx
->debug_ops
.debug
== NULL
) {
756 wb_ctx
->debug_ops
.debug(wb_ctx
->debug_ops
.context
, level
, fmt
, ap
);