From 57ea909b327812479e9c61f0398f257023a504b4 Mon Sep 17 00:00:00 2001 From: Kai Blin Date: Thu, 16 Apr 2009 14:53:36 +0200 Subject: libwbclient: Add async call framework. --- lib/async_req/async_sock.c | 4 +- lib/async_req/config.mk | 1 + nsswitch/config.mk | 6 +- nsswitch/libwbclient/config.mk | 15 + nsswitch/libwbclient/libwbclient.h | 1 + nsswitch/libwbclient/wb_reqtrans.c | 445 ++++++++++++++++++++ nsswitch/libwbclient/wbc_async.c | 687 +++++++++++++++++++++++++++++++ nsswitch/libwbclient/wbc_async.h | 79 ++++ nsswitch/libwbclient/wbclient.c | 2 + nsswitch/libwbclient/wbclient_internal.h | 1 - nsswitch/winbind_struct_protocol.h | 5 + source3/Makefile.in | 10 +- source3/include/wbc_async.h | 75 ---- source3/lib/wb_reqtrans.c | 433 ------------------- source3/lib/wbclient.c | 678 ------------------------------ source3/samba4.mk | 1 + source3/torture/torture.c | 2 +- source4/Makefile | 1 + source4/libcli/wbclient/config.mk | 4 +- source4/main.mk | 1 + source4/ntvfs/posix/config.mk | 2 +- source4/rpc_server/config.mk | 2 +- 22 files changed, 1257 insertions(+), 1198 deletions(-) create mode 100644 nsswitch/libwbclient/config.mk create mode 100644 nsswitch/libwbclient/wb_reqtrans.c create mode 100644 nsswitch/libwbclient/wbc_async.c create mode 100644 nsswitch/libwbclient/wbc_async.h delete mode 100644 source3/include/wbc_async.h delete mode 100644 source3/lib/wb_reqtrans.c delete mode 100644 source3/lib/wbclient.c diff --git a/lib/async_req/async_sock.c b/lib/async_req/async_sock.c index 598a126467..09eec10fc5 100644 --- a/lib/async_req/async_sock.c +++ b/lib/async_req/async_sock.c @@ -426,7 +426,7 @@ static void writev_handler(struct tevent_context *ev, struct tevent_fd *fde, to_write += state->iov[i].iov_len; } - written = sys_writev(state->fd, state->iov, state->count); + written = writev(state->fd, state->iov, state->count); if (written == -1) { tevent_req_error(req, errno); return; @@ -570,7 +570,7 @@ static void read_packet_handler(struct tevent_context *ev, return; } - tmp = TALLOC_REALLOC_ARRAY(state, state->buf, uint8_t, total+more); + tmp = talloc_realloc(state, state->buf, uint8_t, total+more); if (tevent_req_nomem(tmp, req)) { return; } diff --git a/lib/async_req/config.mk b/lib/async_req/config.mk index bf0fd6a2db..1f4b557ce4 100644 --- a/lib/async_req/config.mk +++ b/lib/async_req/config.mk @@ -1,3 +1,4 @@ [SUBSYSTEM::LIBASYNC_REQ] +PUBLIC_DEPENDENCIES = LIBREPLACE_NETWORK LIBASYNC_REQ_OBJ_FILES = $(addprefix ../lib/async_req/, async_sock.o) diff --git a/nsswitch/config.mk b/nsswitch/config.mk index 3a4f054d1f..264032e530 100644 --- a/nsswitch/config.mk +++ b/nsswitch/config.mk @@ -26,7 +26,11 @@ PRIVATE_DEPENDENCIES = \ LIBCLI_AUTH \ LIBPOPT \ POPT_SAMBA \ - LIBWINBIND-CLIENT + LIBWINBIND-CLIENT \ + LIBWBCLIENT \ + LIBTEVENT \ + UTIL_TEVENT \ + LIBASYNC_REQ # End BINARY nsstest ################################# diff --git a/nsswitch/libwbclient/config.mk b/nsswitch/libwbclient/config.mk new file mode 100644 index 0000000000..ffdab159f8 --- /dev/null +++ b/nsswitch/libwbclient/config.mk @@ -0,0 +1,15 @@ +[SUBSYSTEM::LIBWBCLIENT] +PUBLIC_DEPENDENCIES = LIBASYNC_REQ \ + LIBTEVENT \ + LIBTALLOC \ + UTIL_TEVENT + +LIBWBCLIENT_OBJ_FILES = $(addprefix $(libwbclientsrcdir)/, wbc_async.o \ + wbc_guid.o \ + wbc_idmap.o \ + wbclient.o \ + wbc_pam.o \ + wbc_pwd.o \ + wbc_sid.o \ + wbc_util.o \ + wb_reqtrans.o ) diff --git a/nsswitch/libwbclient/libwbclient.h b/nsswitch/libwbclient/libwbclient.h index 74cba7e796..5a25cf462c 100644 --- a/nsswitch/libwbclient/libwbclient.h +++ b/nsswitch/libwbclient/libwbclient.h @@ -36,6 +36,7 @@ /* Public headers */ #include "wbclient.h" +#include "wbc_async.h" /* Private headers */ diff --git a/nsswitch/libwbclient/wb_reqtrans.c b/nsswitch/libwbclient/wb_reqtrans.c new file mode 100644 index 0000000000..84ed7198f2 --- /dev/null +++ b/nsswitch/libwbclient/wb_reqtrans.c @@ -0,0 +1,445 @@ +/* + Unix SMB/CIFS implementation. + + Async transfer of winbindd_request and _response structs + + Copyright (C) Volker Lendecke 2008 + + ** NOTE! The following LGPL license applies to the wbclient + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ + +#include "replace.h" +#include "system/filesys.h" +#include "system/network.h" +#include +#include +struct fd_event; +struct event_context; +#include "lib/async_req/async_sock.h" +#include "lib/util/tevent_unix.h" +#include "nsswitch/winbind_struct_protocol.h" +#include "nsswitch/libwbclient/wbclient.h" +#include "nsswitch/libwbclient/wbc_async.h" + +#ifdef DBGC_CLASS +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_WINBIND +#endif + +struct req_read_state { + struct winbindd_request *wb_req; + size_t max_extra_data; + ssize_t ret; +}; + +static ssize_t wb_req_more(uint8_t *buf, size_t buflen, void *private_data); +static void wb_req_read_done(struct tevent_req *subreq); + +struct tevent_req *wb_req_read_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + int fd, size_t max_extra_data) +{ + struct tevent_req *req, *subreq; + struct req_read_state *state; + + req = tevent_req_create(mem_ctx, &state, struct req_read_state); + if (req == NULL) { + return NULL; + } + state->max_extra_data = max_extra_data; + + subreq = read_packet_send(state, ev, fd, 4, wb_req_more, state); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, wb_req_read_done, req); + return req; +} + +static ssize_t wb_req_more(uint8_t *buf, size_t buflen, void *private_data) +{ + struct req_read_state *state = talloc_get_type_abort( + private_data, struct req_read_state); + struct winbindd_request *req = (struct winbindd_request *)buf; + + if (buflen == 4) { + if (req->length != sizeof(struct winbindd_request)) { + DEBUG(0, ("wb_req_read_len: Invalid request size " + "received: %d (expected %d)\n", + (int)req->length, + (int)sizeof(struct winbindd_request))); + return -1; + } + return sizeof(struct winbindd_request) - 4; + } + + if ((state->max_extra_data != 0) + && (req->extra_len > state->max_extra_data)) { + DEBUG(3, ("Got request with %d bytes extra data on " + "unprivileged socket\n", (int)req->extra_len)); + return -1; + } + + return req->extra_len; +} + +static void wb_req_read_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct req_read_state *state = tevent_req_data( + req, struct req_read_state); + int err; + uint8_t *buf; + + state->ret = read_packet_recv(subreq, state, &buf, &err); + TALLOC_FREE(subreq); + if (state->ret == -1) { + tevent_req_error(req, err); + return; + } + + state->wb_req = (struct winbindd_request *)buf; + + if (state->wb_req->extra_len != 0) { + state->wb_req->extra_data.data = + (char *)buf + sizeof(struct winbindd_request); + } else { + state->wb_req->extra_data.data = NULL; + } + tevent_req_done(req); +} + +ssize_t wb_req_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + struct winbindd_request **preq, int *err) +{ + struct req_read_state *state = tevent_req_data( + req, struct req_read_state); + + if (tevent_req_is_unix_error(req, err)) { + return -1; + } + *preq = talloc_move(mem_ctx, &state->wb_req); + return state->ret; +} + +struct req_write_state { + struct iovec iov[2]; + ssize_t ret; +}; + +static void wb_req_write_done(struct tevent_req *subreq); + +struct tevent_req *wb_req_write_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct tevent_queue *queue, int fd, + struct winbindd_request *wb_req) +{ + struct tevent_req *req, *subreq; + struct req_write_state *state; + int count = 1; + + req = tevent_req_create(mem_ctx, &state, struct req_write_state); + if (req == NULL) { + return NULL; + } + + state->iov[0].iov_base = (void *)wb_req; + state->iov[0].iov_len = sizeof(struct winbindd_request); + + if (wb_req->extra_len != 0) { + state->iov[1].iov_base = (void *)wb_req->extra_data.data; + state->iov[1].iov_len = wb_req->extra_len; + count = 2; + } + + subreq = writev_send(state, ev, queue, fd, true, state->iov, count); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, wb_req_write_done, req); + return req; +} + +static void wb_req_write_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct req_write_state *state = tevent_req_data( + req, struct req_write_state); + int err; + + state->ret = writev_recv(subreq, &err); + TALLOC_FREE(subreq); + if (state->ret < 0) { + tevent_req_error(req, err); + return; + } + tevent_req_done(req); +} + +ssize_t wb_req_write_recv(struct tevent_req *req, int *err) +{ + struct req_write_state *state = tevent_req_data( + req, struct req_write_state); + + if (tevent_req_is_unix_error(req, err)) { + return -1; + } + return state->ret; +} + +struct resp_read_state { + struct winbindd_response *wb_resp; + ssize_t ret; +}; + +static ssize_t wb_resp_more(uint8_t *buf, size_t buflen, void *private_data); +static void wb_resp_read_done(struct tevent_req *subreq); + +struct tevent_req *wb_resp_read_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, int fd) +{ + struct tevent_req *req, *subreq; + struct resp_read_state *state; + + req = tevent_req_create(mem_ctx, &state, struct resp_read_state); + if (req == NULL) { + return NULL; + } + + subreq = read_packet_send(state, ev, fd, 4, wb_resp_more, state); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, wb_resp_read_done, req); + return req; +} + +static ssize_t wb_resp_more(uint8_t *buf, size_t buflen, void *private_data) +{ + struct winbindd_response *resp = (struct winbindd_response *)buf; + + if (buflen == 4) { + if (resp->length < sizeof(struct winbindd_response)) { + DEBUG(0, ("wb_resp_read_len: Invalid response size " + "received: %d (expected at least%d)\n", + (int)resp->length, + (int)sizeof(struct winbindd_response))); + return -1; + } + } + return resp->length - buflen; +} + +static void wb_resp_read_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct resp_read_state *state = tevent_req_data( + req, struct resp_read_state); + uint8_t *buf; + int err; + + state->ret = read_packet_recv(subreq, state, &buf, &err); + TALLOC_FREE(subreq); + if (state->ret == -1) { + tevent_req_error(req, err); + return; + } + + state->wb_resp = (struct winbindd_response *)buf; + + if (state->wb_resp->length > sizeof(struct winbindd_response)) { + state->wb_resp->extra_data.data = + (char *)buf + sizeof(struct winbindd_response); + } else { + state->wb_resp->extra_data.data = NULL; + } + tevent_req_done(req); +} + +ssize_t wb_resp_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + struct winbindd_response **presp, int *err) +{ + struct resp_read_state *state = tevent_req_data( + req, struct resp_read_state); + + if (tevent_req_is_unix_error(req, err)) { + return -1; + } + *presp = talloc_move(mem_ctx, &state->wb_resp); + return state->ret; +} + +struct resp_write_state { + struct iovec iov[2]; + ssize_t ret; +}; + +static void wb_resp_write_done(struct tevent_req *subreq); + +struct tevent_req *wb_resp_write_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct tevent_queue *queue, int fd, + struct winbindd_response *wb_resp) +{ + struct tevent_req *req, *subreq; + struct resp_write_state *state; + int count = 1; + + req = tevent_req_create(mem_ctx, &state, struct resp_write_state); + if (req == NULL) { + return NULL; + } + + state->iov[0].iov_base = (void *)wb_resp; + state->iov[0].iov_len = sizeof(struct winbindd_response); + + if (wb_resp->length > sizeof(struct winbindd_response)) { + state->iov[1].iov_base = (void *)wb_resp->extra_data.data; + state->iov[1].iov_len = + wb_resp->length - sizeof(struct winbindd_response); + count = 2; + } + + subreq = writev_send(state, ev, queue, fd, true, state->iov, count); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, wb_resp_write_done, req); + return req; +} + +static void wb_resp_write_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct resp_write_state *state = tevent_req_data( + req, struct resp_write_state); + int err; + + state->ret = writev_recv(subreq, &err); + TALLOC_FREE(subreq); + if (state->ret < 0) { + tevent_req_error(req, err); + return; + } + tevent_req_done(req); +} + +ssize_t wb_resp_write_recv(struct tevent_req *req, int *err) +{ + struct resp_write_state *state = tevent_req_data( + req, struct resp_write_state); + + if (tevent_req_is_unix_error(req, err)) { + return -1; + } + return state->ret; +} + +struct wb_simple_trans_state { + struct tevent_context *ev; + int fd; + struct winbindd_response *wb_resp; +}; + +static void wb_simple_trans_write_done(struct tevent_req *subreq); +static void wb_simple_trans_read_done(struct tevent_req *subreq); + +struct tevent_req *wb_simple_trans_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct tevent_queue *queue, int fd, + struct winbindd_request *wb_req) +{ + struct tevent_req *req, *subreq; + struct wb_simple_trans_state *state; + + req = tevent_req_create(mem_ctx, &state, struct wb_simple_trans_state); + if (req == NULL) { + return NULL; + } + + wb_req->length = sizeof(struct winbindd_request); + + state->ev = ev; + state->fd = fd; + + subreq = wb_req_write_send(state, ev, queue, fd, wb_req); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, wb_simple_trans_write_done, req); + + return req; +} + +static void wb_simple_trans_write_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct wb_simple_trans_state *state = tevent_req_data( + req, struct wb_simple_trans_state); + ssize_t ret; + int err; + + ret = wb_req_write_recv(subreq, &err); + TALLOC_FREE(subreq); + if (ret == -1) { + tevent_req_error(req, err); + return; + } + subreq = wb_resp_read_send(state, state->ev, state->fd); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, wb_simple_trans_read_done, req); +} + +static void wb_simple_trans_read_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct wb_simple_trans_state *state = tevent_req_data( + req, struct wb_simple_trans_state); + ssize_t ret; + int err; + + ret = wb_resp_read_recv(subreq, state, &state->wb_resp, &err); + TALLOC_FREE(subreq); + if (ret == -1) { + tevent_req_error(req, err); + return; + } + + tevent_req_done(req); +} + +int wb_simple_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + struct winbindd_response **presponse, int *err) +{ + struct wb_simple_trans_state *state = tevent_req_data( + req, struct wb_simple_trans_state); + + if (tevent_req_is_unix_error(req, err)) { + return -1; + } + *presponse = talloc_move(mem_ctx, &state->wb_resp); + return 0; +} diff --git a/nsswitch/libwbclient/wbc_async.c b/nsswitch/libwbclient/wbc_async.c new file mode 100644 index 0000000000..141c9816aa --- /dev/null +++ b/nsswitch/libwbclient/wbc_async.c @@ -0,0 +1,687 @@ +/* + Unix SMB/CIFS implementation. + Infrastructure for async winbind requests + Copyright (C) Volker Lendecke 2008 + + ** NOTE! The following LGPL license applies to the wbclient + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ + +#include "replace.h" +#include "system/filesys.h" +#include "system/network.h" +#include +#include +struct fd_event; +struct event_context; +#include "lib/async_req/async_sock.h" +#include "nsswitch/winbind_struct_protocol.h" +#include "nsswitch/libwbclient/wbclient.h" +#include "nsswitch/libwbclient/wbc_async.h" + +wbcErr map_wbc_err_from_errno(int error) +{ + switch(error) { + case EPERM: + case EACCES: + return WBC_ERR_AUTH_ERROR; + case ENOMEM: + return WBC_ERR_NO_MEMORY; + case EIO: + default: + return WBC_ERR_UNKNOWN_FAILURE; + } +} + +bool tevent_req_is_wbcerr(struct tevent_req *req, wbcErr *pwbc_err) +{ + enum tevent_req_state state; + uint64_t error; + if (!tevent_req_is_error(req, &state, &error)) { + *pwbc_err = WBC_ERR_SUCCESS; + return false; + } + + switch (state) { + case TEVENT_REQ_USER_ERROR: + *pwbc_err = error; + break; + case TEVENT_REQ_TIMED_OUT: + *pwbc_err = WBC_ERR_UNKNOWN_FAILURE; + break; + case TEVENT_REQ_NO_MEMORY: + *pwbc_err = WBC_ERR_NO_MEMORY; + break; + default: + *pwbc_err = WBC_ERR_UNKNOWN_FAILURE; + break; + } + return true; +} + +wbcErr tevent_req_simple_recv_wbcerr(struct tevent_req *req) +{ + wbcErr wbc_err; + + if (tevent_req_is_wbcerr(req, &wbc_err)) { + return wbc_err; + } + + return WBC_ERR_SUCCESS; +} + +struct wb_context { + struct tevent_queue *queue; + int fd; + bool is_priv; +}; + +static int make_nonstd_fd(int fd) +{ + int i; + int sys_errno = 0; + int fds[3]; + int num_fds = 0; + + if (fd == -1) { + return -1; + } + while (fd < 3) { + fds[num_fds++] = fd; + fd = dup(fd); + if (fd == -1) { + sys_errno = errno; + break; + } + } + for (i=0; i= 0) { + flags |= FD_CLOEXEC; + result = fcntl( new_fd, F_SETFD, flags ); + } + if (result < 0) { + goto fail; + } +#endif + return new_fd; + + fail: + if (new_fd != -1) { + int sys_errno = errno; + close(new_fd); + errno = sys_errno; + } + return -1; +} + +struct wb_context *wb_context_init(TALLOC_CTX *mem_ctx) +{ + struct wb_context *result; + + result = talloc(mem_ctx, struct wb_context); + if (result == NULL) { + return NULL; + } + result->queue = tevent_queue_create(result, "wb_trans"); + if (result->queue == NULL) { + TALLOC_FREE(result); + return NULL; + } + result->fd = -1; + result->is_priv = false; + return result; +} + +struct wb_connect_state { + int dummy; +}; + +static void wbc_connect_connected(struct tevent_req *subreq); + +static struct tevent_req *wb_connect_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct wb_context *wb_ctx, + const char *dir) +{ + struct tevent_req *result, *subreq; + struct wb_connect_state *state; + struct sockaddr_un sunaddr; + struct stat st; + char *path = NULL; + wbcErr wbc_err; + + result = tevent_req_create(mem_ctx, &state, struct wb_connect_state); + if (result == NULL) { + return NULL; + } + + if (wb_ctx->fd != -1) { + close(wb_ctx->fd); + wb_ctx->fd = -1; + } + + /* Check permissions on unix socket directory */ + + if (lstat(dir, &st) == -1) { + wbc_err = WBC_ERR_WINBIND_NOT_AVAILABLE; + goto post_status; + } + + if (!S_ISDIR(st.st_mode) || + (st.st_uid != 0 && st.st_uid != geteuid())) { + wbc_err = WBC_ERR_WINBIND_NOT_AVAILABLE; + goto post_status; + } + + /* Connect to socket */ + + path = talloc_asprintf(talloc_tos(), "%s/%s", dir, + WINBINDD_SOCKET_NAME); + if (path == NULL) { + goto nomem; + } + + sunaddr.sun_family = AF_UNIX; + strlcpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path)); + TALLOC_FREE(path); + + /* If socket file doesn't exist, don't bother trying to connect + with retry. This is an attempt to make the system usable when + the winbindd daemon is not running. */ + + if ((lstat(sunaddr.sun_path, &st) == -1) + || !S_ISSOCK(st.st_mode) + || (st.st_uid != 0 && st.st_uid != geteuid())) { + wbc_err = WBC_ERR_WINBIND_NOT_AVAILABLE; + goto post_status; + } + + wb_ctx->fd = make_safe_fd(socket(AF_UNIX, SOCK_STREAM, 0)); + if (wb_ctx->fd == -1) { + wbc_err = map_wbc_err_from_errno(errno); + goto post_status; + } + + subreq = async_connect_send(mem_ctx, ev, wb_ctx->fd, + (struct sockaddr *)(void *)&sunaddr, + sizeof(sunaddr)); + if (subreq == NULL) { + goto nomem; + } + tevent_req_set_callback(subreq, wbc_connect_connected, result); + return result; + + post_status: + tevent_req_error(result, wbc_err); + return tevent_req_post(result, ev); + nomem: + TALLOC_FREE(result); + return NULL; +} + +static void wbc_connect_connected(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + int res, err; + + res = async_connect_recv(subreq, &err); + TALLOC_FREE(subreq); + if (res == -1) { + tevent_req_error(req, map_wbc_err_from_errno(err)); + return; + } + tevent_req_done(req); +} + +static wbcErr wb_connect_recv(struct tevent_req *req) +{ + return tevent_req_simple_recv_wbcerr(req); +} + +static const char *winbindd_socket_dir(void) +{ +#ifdef SOCKET_WRAPPER + const char *env_dir; + + env_dir = getenv(WINBINDD_SOCKET_DIR_ENVVAR); + if (env_dir) { + return env_dir; + } +#endif + + return WINBINDD_SOCKET_DIR; +} + +struct wb_open_pipe_state { + struct wb_context *wb_ctx; + struct tevent_context *ev; + bool need_priv; + struct winbindd_request wb_req; +}; + +static void wb_open_pipe_connect_nonpriv_done(struct tevent_req *subreq); +static void wb_open_pipe_ping_done(struct tevent_req *subreq); +static void wb_open_pipe_getpriv_done(struct tevent_req *subreq); +static void wb_open_pipe_connect_priv_done(struct tevent_req *subreq); + +static struct tevent_req *wb_open_pipe_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct wb_context *wb_ctx, + bool need_priv) +{ + struct tevent_req *result, *subreq; + struct wb_open_pipe_state *state; + + result = tevent_req_create(mem_ctx, &state, struct wb_open_pipe_state); + if (result == NULL) { + return NULL; + } + state->wb_ctx = wb_ctx; + state->ev = ev; + state->need_priv = need_priv; + + if (wb_ctx->fd != -1) { + close(wb_ctx->fd); + wb_ctx->fd = -1; + } + + subreq = wb_connect_send(state, ev, wb_ctx, winbindd_socket_dir()); + if (subreq == NULL) { + goto fail; + } + tevent_req_set_callback(subreq, wb_open_pipe_connect_nonpriv_done, + result); + return result; + + fail: + TALLOC_FREE(result); + return NULL; +} + +static void wb_open_pipe_connect_nonpriv_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct wb_open_pipe_state *state = tevent_req_data( + req, struct wb_open_pipe_state); + wbcErr wbc_err; + + wbc_err = wb_connect_recv(subreq); + TALLOC_FREE(subreq); + if (!WBC_ERROR_IS_OK(wbc_err)) { + state->wb_ctx->is_priv = true; + tevent_req_error(req, wbc_err); + return; + } + + ZERO_STRUCT(state->wb_req); + state->wb_req.cmd = WINBINDD_INTERFACE_VERSION; + state->wb_req.pid = getpid(); + + subreq = wb_simple_trans_send(state, state->ev, NULL, + state->wb_ctx->fd, &state->wb_req); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, wb_open_pipe_ping_done, req); +} + +static void wb_open_pipe_ping_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct wb_open_pipe_state *state = tevent_req_data( + req, struct wb_open_pipe_state); + struct winbindd_response *wb_resp; + int ret, err; + + ret = wb_simple_trans_recv(subreq, state, &wb_resp, &err); + TALLOC_FREE(subreq); + if (ret == -1) { + tevent_req_error(req, map_wbc_err_from_errno(err)); + return; + } + + if (!state->need_priv) { + tevent_req_done(req); + return; + } + + state->wb_req.cmd = WINBINDD_PRIV_PIPE_DIR; + state->wb_req.pid = getpid(); + + subreq = wb_simple_trans_send(state, state->ev, NULL, + state->wb_ctx->fd, &state->wb_req); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, wb_open_pipe_getpriv_done, req); +} + +static void wb_open_pipe_getpriv_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct wb_open_pipe_state *state = tevent_req_data( + req, struct wb_open_pipe_state); + struct winbindd_response *wb_resp = NULL; + int ret, err; + + ret = wb_simple_trans_recv(subreq, state, &wb_resp, &err); + TALLOC_FREE(subreq); + if (ret == -1) { + tevent_req_error(req, map_wbc_err_from_errno(err)); + return; + } + + close(state->wb_ctx->fd); + state->wb_ctx->fd = -1; + + subreq = wb_connect_send(state, state->ev, state->wb_ctx, + (char *)wb_resp->extra_data.data); + TALLOC_FREE(wb_resp); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, wb_open_pipe_connect_priv_done, req); +} + +static void wb_open_pipe_connect_priv_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct wb_open_pipe_state *state = tevent_req_data( + req, struct wb_open_pipe_state); + wbcErr wbc_err; + + wbc_err = wb_connect_recv(subreq); + TALLOC_FREE(subreq); + if (!WBC_ERROR_IS_OK(wbc_err)) { + tevent_req_error(req, wbc_err); + return; + } + state->wb_ctx->is_priv = true; + tevent_req_done(req); +} + +static wbcErr wb_open_pipe_recv(struct tevent_req *req) +{ + return tevent_req_simple_recv_wbcerr(req); +} + +struct wb_trans_state { + struct wb_trans_state *prev, *next; + struct wb_context *wb_ctx; + struct tevent_context *ev; + struct winbindd_request *wb_req; + struct winbindd_response *wb_resp; + bool need_priv; +}; + +static bool closed_fd(int fd) +{ + struct timeval tv; + fd_set r_fds; + int selret; + + if (fd == -1) { + return true; + } + + FD_ZERO(&r_fds); + FD_SET(fd, &r_fds); + ZERO_STRUCT(tv); + + selret = select(fd+1, &r_fds, NULL, NULL, &tv); + if (selret == -1) { + return true; + } + if (selret == 0) { + return false; + } + return (FD_ISSET(fd, &r_fds)); +} + +static void wb_trans_trigger(struct tevent_req *req, void *private_data); +static void wb_trans_connect_done(struct tevent_req *subreq); +static void wb_trans_done(struct tevent_req *subreq); +static void wb_trans_retry_wait_done(struct tevent_req *subreq); + +struct tevent_req *wb_trans_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct wb_context *wb_ctx, bool need_priv, + struct winbindd_request *wb_req) +{ + struct tevent_req *req; + struct wb_trans_state *state; + + req = tevent_req_create(mem_ctx, &state, struct wb_trans_state); + if (req == NULL) { + return NULL; + } + state->wb_ctx = wb_ctx; + state->ev = ev; + state->wb_req = wb_req; + state->need_priv = need_priv; + + if (!tevent_queue_add(wb_ctx->queue, ev, req, wb_trans_trigger, + NULL)) { + tevent_req_nomem(NULL, req); + return tevent_req_post(req, ev); + } + return req; +} + +static void wb_trans_trigger(struct tevent_req *req, void *private_data) +{ + struct wb_trans_state *state = tevent_req_data( + req, struct wb_trans_state); + struct tevent_req *subreq; + + if ((state->wb_ctx->fd != -1) && closed_fd(state->wb_ctx->fd)) { + close(state->wb_ctx->fd); + state->wb_ctx->fd = -1; + } + + if ((state->wb_ctx->fd == -1) + || (state->need_priv && !state->wb_ctx->is_priv)) { + subreq = wb_open_pipe_send(state, state->ev, state->wb_ctx, + state->need_priv); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, wb_trans_connect_done, req); + return; + } + + state->wb_req->pid = getpid(); + + subreq = wb_simple_trans_send(state, state->ev, NULL, + state->wb_ctx->fd, state->wb_req); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, wb_trans_done, req); +} + +static bool wb_trans_retry(struct tevent_req *req, + struct wb_trans_state *state, + wbcErr wbc_err) +{ + struct tevent_req *subreq; + + if (WBC_ERROR_IS_OK(wbc_err)) { + return false; + } + + if (wbc_err == WBC_ERR_WINBIND_NOT_AVAILABLE) { + /* + * Winbind not around or we can't connect to the pipe. Fail + * immediately. + */ + tevent_req_error(req, wbc_err); + return true; + } + + /* + * The transfer as such failed, retry after one second + */ + + if (state->wb_ctx->fd != -1) { + close(state->wb_ctx->fd); + state->wb_ctx->fd = -1; + } + + subreq = tevent_wakeup_send(state, state->ev, + timeval_current_ofs(1, 0)); + if (tevent_req_nomem(subreq, req)) { + return true; + } + tevent_req_set_callback(subreq, wb_trans_retry_wait_done, req); + return true; +} + +static void wb_trans_retry_wait_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct wb_trans_state *state = tevent_req_data( + req, struct wb_trans_state); + bool ret; + + ret = tevent_wakeup_recv(subreq); + TALLOC_FREE(subreq); + if (!ret) { + tevent_req_error(req, WBC_ERR_UNKNOWN_FAILURE); + return; + } + + subreq = wb_open_pipe_send(state, state->ev, state->wb_ctx, + state->need_priv); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, wb_trans_connect_done, req); +} + +static void wb_trans_connect_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct wb_trans_state *state = tevent_req_data( + req, struct wb_trans_state); + wbcErr wbc_err; + + wbc_err = wb_open_pipe_recv(subreq); + TALLOC_FREE(subreq); + + if (wb_trans_retry(req, state, wbc_err)) { + return; + } + + subreq = wb_simple_trans_send(state, state->ev, NULL, + state->wb_ctx->fd, state->wb_req); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, wb_trans_done, req); +} + +static void wb_trans_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct wb_trans_state *state = tevent_req_data( + req, struct wb_trans_state); + int ret, err; + + ret = wb_simple_trans_recv(subreq, state, &state->wb_resp, &err); + TALLOC_FREE(subreq); + if ((ret == -1) + && wb_trans_retry(req, state, map_wbc_err_from_errno(err))) { + return; + } + + tevent_req_done(req); +} + +wbcErr wb_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + struct winbindd_response **presponse) +{ + struct wb_trans_state *state = tevent_req_data( + req, struct wb_trans_state); + wbcErr wbc_err; + + if (tevent_req_is_wbcerr(req, &wbc_err)) { + return wbc_err; + } + + *presponse = talloc_move(mem_ctx, &state->wb_resp); + return WBC_ERR_SUCCESS; +} diff --git a/nsswitch/libwbclient/wbc_async.h b/nsswitch/libwbclient/wbc_async.h new file mode 100644 index 0000000000..a2e0eed448 --- /dev/null +++ b/nsswitch/libwbclient/wbc_async.h @@ -0,0 +1,79 @@ +/* + Unix SMB/CIFS implementation. + Headers for the async winbind client library + Copyright (C) Volker Lendecke 2008 + + ** NOTE! The following LGPL license applies to the wbclient + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ + +#ifndef _WBC_ASYNC_H_ +#define _WBC_ASYNC_H_ + +#include +#include +#include "nsswitch/libwbclient/wbclient.h" + +struct wb_context; +struct winbindd_request; +struct winbindd_response; + +struct tevent_req *wb_trans_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct wb_context *wb_ctx, bool need_priv, + struct winbindd_request *wb_req); +wbcErr wb_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + struct winbindd_response **presponse); +struct wb_context *wb_context_init(TALLOC_CTX *mem_ctx); + +/* Definitions from wb_reqtrans.c */ +wbcErr map_wbc_err_from_errno(int error); + +bool tevent_req_is_wbcerr(struct tevent_req *req, wbcErr *pwbc_err); +wbcErr tevent_req_simple_recv_wbcerr(struct tevent_req *req); + +struct tevent_req *wb_req_read_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + int fd, size_t max_extra_data); +ssize_t wb_req_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + struct winbindd_request **preq, int *err); + +struct tevent_req *wb_req_write_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct tevent_queue *queue, int fd, + struct winbindd_request *wb_req); +ssize_t wb_req_write_recv(struct tevent_req *req, int *err); + +struct tevent_req *wb_resp_read_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, int fd); +ssize_t wb_resp_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + struct winbindd_response **presp, int *err); + +struct tevent_req *wb_resp_write_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct tevent_queue *queue, int fd, + struct winbindd_response *wb_resp); +ssize_t wb_resp_write_recv(struct tevent_req *req, int *err); + +struct tevent_req *wb_simple_trans_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct tevent_queue *queue, int fd, + struct winbindd_request *wb_req); +int wb_simple_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + struct winbindd_response **presponse, int *err); + +#endif /*_WBC_ASYNC_H_*/ diff --git a/nsswitch/libwbclient/wbclient.c b/nsswitch/libwbclient/wbclient.c index f5c72315f2..77b7e12d04 100644 --- a/nsswitch/libwbclient/wbclient.c +++ b/nsswitch/libwbclient/wbclient.c @@ -22,6 +22,8 @@ /* Required Headers */ +#include "lib/talloc/talloc.h" +#include "lib/tevent/tevent.h" #include "libwbclient.h" /* From wb_common.c */ diff --git a/nsswitch/libwbclient/wbclient_internal.h b/nsswitch/libwbclient/wbclient_internal.h index fc03c5409b..2d103ab3df 100644 --- a/nsswitch/libwbclient/wbclient_internal.h +++ b/nsswitch/libwbclient/wbclient_internal.h @@ -28,5 +28,4 @@ wbcErr wbcRequestResponse(int cmd, struct winbindd_request *request, struct winbindd_response *response); - #endif /* _WBCLIENT_INTERNAL_H */ diff --git a/nsswitch/winbind_struct_protocol.h b/nsswitch/winbind_struct_protocol.h index 11b2069c3a..1785c30906 100644 --- a/nsswitch/winbind_struct_protocol.h +++ b/nsswitch/winbind_struct_protocol.h @@ -15,6 +15,11 @@ #define SAFE_FREE(x) do { if(x) {free(x); x=NULL;} } while(0) #endif +#ifndef FSTRING_LEN +#define FSTRING_LEN 256 +typedef char fstring[FSTRING_LEN]; +#endif + #ifndef _WINBINDD_NTDOM_H #define _WINBINDD_NTDOM_H diff --git a/source3/Makefile.in b/source3/Makefile.in index 72fce60faa..613e127770 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -992,7 +992,7 @@ SMBTORTURE_OBJ1 = torture/torture.o torture/nbio.o torture/scanner.o torture/uta SMBTORTURE_OBJ = $(SMBTORTURE_OBJ1) $(PARAM_OBJ) \ $(LIBSMB_OBJ) $(LDB_OBJ) $(KRBCLIENT_OBJ) $(LIB_NONSMBD_OBJ) \ - lib/wb_reqtrans.o lib/wbclient.o \ + @LIBWBCLIENT_STATIC@ \ $(LIBNDR_GEN_OBJ0) MASKTEST_OBJ = torture/masktest.o $(PARAM_OBJ) $(LIBSMB_OBJ) $(LDB_OBJ) $(KRBCLIENT_OBJ) \ @@ -1876,7 +1876,10 @@ LIBWBCLIENT_OBJ0 = ../nsswitch/libwbclient/wbclient.o \ ../nsswitch/libwbclient/wbc_idmap.o \ ../nsswitch/libwbclient/wbc_sid.o \ ../nsswitch/libwbclient/wbc_guid.o \ - ../nsswitch/libwbclient/wbc_pam.o + ../nsswitch/libwbclient/wbc_pam.o \ + ../nsswitch/libwbclient/wb_reqtrans.o \ + ../nsswitch/libwbclient/wbc_async.o + LIBWBCLIENT_OBJ = $(LIBWBCLIENT_OBJ0) \ $(WBCOMMON_OBJ) \ $(LIBREPLACE_OBJ) @@ -1887,7 +1890,8 @@ LIBWBCLIENT_SHARED_TARGET_SONAME=$(LIBWBCLIENT_SHARED_TARGET).$(LIBWBCLIENT_SOVE LIBWBCLIENT_STATIC_TARGET=@LIBWBCLIENT_STATIC_TARGET@ LIBWBCLIENT=@LIBWBCLIENT_STATIC@ @LIBWBCLIENT_SHARED@ LIBWBCLIENT_SYMS=$(srcdir)/exports/libwbclient.@SYMSEXT@ -LIBWBCLIENT_HEADERS=$(srcdir)/../nsswitch/libwbclient/wbclient.h +LIBWBCLIENT_HEADERS=$(srcdir)/../nsswitch/libwbclient/wbclient.h \ + $(srcdir)/../nsswitch/libwbclient/wbc_async.h $(LIBWBCLIENT_SYMS): $(LIBWBCLIENT_HEADERS) @$(MKSYMS_SH) $(AWK) $@ $(LIBWBCLIENT_HEADERS) diff --git a/source3/include/wbc_async.h b/source3/include/wbc_async.h deleted file mode 100644 index 96c5f8c348..0000000000 --- a/source3/include/wbc_async.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Headers for the async winbind client library - Copyright (C) Volker Lendecke 2008 - - ** NOTE! The following LGPL license applies to the wbclient - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see . -*/ - -#ifndef _WBC_ASYNC_H_ -#define _WBC_ASYNC_H_ - -#include "nsswitch/libwbclient/wbclient.h" - -struct wb_context; - -struct tevent_req *wb_trans_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct wb_context *wb_ctx, bool need_priv, - struct winbindd_request *wb_req); -wbcErr wb_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, - struct winbindd_response **presponse); -struct wb_context *wb_context_init(TALLOC_CTX *mem_ctx); - -/* Definitions from wb_reqtrans.c */ -wbcErr map_wbc_err_from_errno(int error); - -bool tevent_req_is_wbcerr(struct tevent_req *req, wbcErr *pwbc_err); -wbcErr tevent_req_simple_recv_wbcerr(struct tevent_req *req); - -struct tevent_req *wb_req_read_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - int fd, size_t max_extra_data); -ssize_t wb_req_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, - struct winbindd_request **preq, int *err); - -struct tevent_req *wb_req_write_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct tevent_queue *queue, int fd, - struct winbindd_request *wb_req); -ssize_t wb_req_write_recv(struct tevent_req *req, int *err); - -struct tevent_req *wb_resp_read_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, int fd); -ssize_t wb_resp_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, - struct winbindd_response **presp, int *err); - -struct tevent_req *wb_resp_write_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct tevent_queue *queue, int fd, - struct winbindd_response *wb_resp); -ssize_t wb_resp_write_recv(struct tevent_req *req, int *err); - -struct tevent_req *wb_simple_trans_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct tevent_queue *queue, int fd, - struct winbindd_request *wb_req); -int wb_simple_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, - struct winbindd_response **presponse, int *err); - -#endif /*_WBC_ASYNC_H_*/ diff --git a/source3/lib/wb_reqtrans.c b/source3/lib/wb_reqtrans.c deleted file mode 100644 index 7088925927..0000000000 --- a/source3/lib/wb_reqtrans.c +++ /dev/null @@ -1,433 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - Async transfer of winbindd_request and _response structs - - Copyright (C) Volker Lendecke 2008 - - ** NOTE! The following LGPL license applies to the wbclient - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see . -*/ - -#include "includes.h" -#include "wbc_async.h" - -#undef DBGC_CLASS -#define DBGC_CLASS DBGC_WINBIND - -struct req_read_state { - struct winbindd_request *wb_req; - size_t max_extra_data; - ssize_t ret; -}; - -static ssize_t wb_req_more(uint8_t *buf, size_t buflen, void *private_data); -static void wb_req_read_done(struct tevent_req *subreq); - -struct tevent_req *wb_req_read_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - int fd, size_t max_extra_data) -{ - struct tevent_req *req, *subreq; - struct req_read_state *state; - - req = tevent_req_create(mem_ctx, &state, struct req_read_state); - if (req == NULL) { - return NULL; - } - state->max_extra_data = max_extra_data; - - subreq = read_packet_send(state, ev, fd, 4, wb_req_more, state); - if (tevent_req_nomem(subreq, req)) { - return tevent_req_post(req, ev); - } - tevent_req_set_callback(subreq, wb_req_read_done, req); - return req; -} - -static ssize_t wb_req_more(uint8_t *buf, size_t buflen, void *private_data) -{ - struct req_read_state *state = talloc_get_type_abort( - private_data, struct req_read_state); - struct winbindd_request *req = (struct winbindd_request *)buf; - - if (buflen == 4) { - if (req->length != sizeof(struct winbindd_request)) { - DEBUG(0, ("wb_req_read_len: Invalid request size " - "received: %d (expected %d)\n", - (int)req->length, - (int)sizeof(struct winbindd_request))); - return -1; - } - return sizeof(struct winbindd_request) - 4; - } - - if ((state->max_extra_data != 0) - && (req->extra_len > state->max_extra_data)) { - DEBUG(3, ("Got request with %d bytes extra data on " - "unprivileged socket\n", (int)req->extra_len)); - return -1; - } - - return req->extra_len; -} - -static void wb_req_read_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - struct req_read_state *state = tevent_req_data( - req, struct req_read_state); - int err; - uint8_t *buf; - - state->ret = read_packet_recv(subreq, state, &buf, &err); - TALLOC_FREE(subreq); - if (state->ret == -1) { - tevent_req_error(req, err); - return; - } - - state->wb_req = (struct winbindd_request *)buf; - - if (state->wb_req->extra_len != 0) { - state->wb_req->extra_data.data = - (char *)buf + sizeof(struct winbindd_request); - } else { - state->wb_req->extra_data.data = NULL; - } - tevent_req_done(req); -} - -ssize_t wb_req_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, - struct winbindd_request **preq, int *err) -{ - struct req_read_state *state = tevent_req_data( - req, struct req_read_state); - - if (tevent_req_is_unix_error(req, err)) { - return -1; - } - *preq = talloc_move(mem_ctx, &state->wb_req); - return state->ret; -} - -struct req_write_state { - struct iovec iov[2]; - ssize_t ret; -}; - -static void wb_req_write_done(struct tevent_req *subreq); - -struct tevent_req *wb_req_write_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct tevent_queue *queue, int fd, - struct winbindd_request *wb_req) -{ - struct tevent_req *req, *subreq; - struct req_write_state *state; - int count = 1; - - req = tevent_req_create(mem_ctx, &state, struct req_write_state); - if (req == NULL) { - return NULL; - } - - state->iov[0].iov_base = (void *)wb_req; - state->iov[0].iov_len = sizeof(struct winbindd_request); - - if (wb_req->extra_len != 0) { - state->iov[1].iov_base = (void *)wb_req->extra_data.data; - state->iov[1].iov_len = wb_req->extra_len; - count = 2; - } - - subreq = writev_send(state, ev, queue, fd, true, state->iov, count); - if (tevent_req_nomem(subreq, req)) { - return tevent_req_post(req, ev); - } - tevent_req_set_callback(subreq, wb_req_write_done, req); - return req; -} - -static void wb_req_write_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - struct req_write_state *state = tevent_req_data( - req, struct req_write_state); - int err; - - state->ret = writev_recv(subreq, &err); - TALLOC_FREE(subreq); - if (state->ret < 0) { - tevent_req_error(req, err); - return; - } - tevent_req_done(req); -} - -ssize_t wb_req_write_recv(struct tevent_req *req, int *err) -{ - struct req_write_state *state = tevent_req_data( - req, struct req_write_state); - - if (tevent_req_is_unix_error(req, err)) { - return -1; - } - return state->ret; -} - -struct resp_read_state { - struct winbindd_response *wb_resp; - ssize_t ret; -}; - -static ssize_t wb_resp_more(uint8_t *buf, size_t buflen, void *private_data); -static void wb_resp_read_done(struct tevent_req *subreq); - -struct tevent_req *wb_resp_read_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, int fd) -{ - struct tevent_req *req, *subreq; - struct resp_read_state *state; - - req = tevent_req_create(mem_ctx, &state, struct resp_read_state); - if (req == NULL) { - return NULL; - } - - subreq = read_packet_send(state, ev, fd, 4, wb_resp_more, state); - if (tevent_req_nomem(subreq, req)) { - return tevent_req_post(req, ev); - } - tevent_req_set_callback(subreq, wb_resp_read_done, req); - return req; -} - -static ssize_t wb_resp_more(uint8_t *buf, size_t buflen, void *private_data) -{ - struct winbindd_response *resp = (struct winbindd_response *)buf; - - if (buflen == 4) { - if (resp->length < sizeof(struct winbindd_response)) { - DEBUG(0, ("wb_resp_read_len: Invalid response size " - "received: %d (expected at least%d)\n", - (int)resp->length, - (int)sizeof(struct winbindd_response))); - return -1; - } - } - return resp->length - buflen; -} - -static void wb_resp_read_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - struct resp_read_state *state = tevent_req_data( - req, struct resp_read_state); - uint8_t *buf; - int err; - - state->ret = read_packet_recv(subreq, state, &buf, &err); - TALLOC_FREE(subreq); - if (state->ret == -1) { - tevent_req_error(req, err); - return; - } - - state->wb_resp = (struct winbindd_response *)buf; - - if (state->wb_resp->length > sizeof(struct winbindd_response)) { - state->wb_resp->extra_data.data = - (char *)buf + sizeof(struct winbindd_response); - } else { - state->wb_resp->extra_data.data = NULL; - } - tevent_req_done(req); -} - -ssize_t wb_resp_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, - struct winbindd_response **presp, int *err) -{ - struct resp_read_state *state = tevent_req_data( - req, struct resp_read_state); - - if (tevent_req_is_unix_error(req, err)) { - return -1; - } - *presp = talloc_move(mem_ctx, &state->wb_resp); - return state->ret; -} - -struct resp_write_state { - struct iovec iov[2]; - ssize_t ret; -}; - -static void wb_resp_write_done(struct tevent_req *subreq); - -struct tevent_req *wb_resp_write_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct tevent_queue *queue, int fd, - struct winbindd_response *wb_resp) -{ - struct tevent_req *req, *subreq; - struct resp_write_state *state; - int count = 1; - - req = tevent_req_create(mem_ctx, &state, struct resp_write_state); - if (req == NULL) { - return NULL; - } - - state->iov[0].iov_base = (void *)wb_resp; - state->iov[0].iov_len = sizeof(struct winbindd_response); - - if (wb_resp->length > sizeof(struct winbindd_response)) { - state->iov[1].iov_base = (void *)wb_resp->extra_data.data; - state->iov[1].iov_len = - wb_resp->length - sizeof(struct winbindd_response); - count = 2; - } - - subreq = writev_send(state, ev, queue, fd, true, state->iov, count); - if (tevent_req_nomem(subreq, req)) { - return tevent_req_post(req, ev); - } - tevent_req_set_callback(subreq, wb_resp_write_done, req); - return req; -} - -static void wb_resp_write_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - struct resp_write_state *state = tevent_req_data( - req, struct resp_write_state); - int err; - - state->ret = writev_recv(subreq, &err); - TALLOC_FREE(subreq); - if (state->ret < 0) { - tevent_req_error(req, err); - return; - } - tevent_req_done(req); -} - -ssize_t wb_resp_write_recv(struct tevent_req *req, int *err) -{ - struct resp_write_state *state = tevent_req_data( - req, struct resp_write_state); - - if (tevent_req_is_unix_error(req, err)) { - return -1; - } - return state->ret; -} - -struct wb_simple_trans_state { - struct tevent_context *ev; - int fd; - struct winbindd_response *wb_resp; -}; - -static void wb_simple_trans_write_done(struct tevent_req *subreq); -static void wb_simple_trans_read_done(struct tevent_req *subreq); - -struct tevent_req *wb_simple_trans_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct tevent_queue *queue, int fd, - struct winbindd_request *wb_req) -{ - struct tevent_req *req, *subreq; - struct wb_simple_trans_state *state; - - req = tevent_req_create(mem_ctx, &state, struct wb_simple_trans_state); - if (req == NULL) { - return NULL; - } - - wb_req->length = sizeof(struct winbindd_request); - - state->ev = ev; - state->fd = fd; - - subreq = wb_req_write_send(state, ev, queue, fd, wb_req); - if (tevent_req_nomem(subreq, req)) { - return tevent_req_post(req, ev); - } - tevent_req_set_callback(subreq, wb_simple_trans_write_done, req); - - return req; -} - -static void wb_simple_trans_write_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - struct wb_simple_trans_state *state = tevent_req_data( - req, struct wb_simple_trans_state); - ssize_t ret; - int err; - - ret = wb_req_write_recv(subreq, &err); - TALLOC_FREE(subreq); - if (ret == -1) { - tevent_req_error(req, err); - return; - } - subreq = wb_resp_read_send(state, state->ev, state->fd); - if (tevent_req_nomem(subreq, req)) { - return; - } - tevent_req_set_callback(subreq, wb_simple_trans_read_done, req); -} - -static void wb_simple_trans_read_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - struct wb_simple_trans_state *state = tevent_req_data( - req, struct wb_simple_trans_state); - ssize_t ret; - int err; - - ret = wb_resp_read_recv(subreq, state, &state->wb_resp, &err); - TALLOC_FREE(subreq); - if (ret == -1) { - tevent_req_error(req, err); - return; - } - - tevent_req_done(req); -} - -int wb_simple_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, - struct winbindd_response **presponse, int *err) -{ - struct wb_simple_trans_state *state = tevent_req_data( - req, struct wb_simple_trans_state); - - if (tevent_req_is_unix_error(req, err)) { - return -1; - } - *presponse = talloc_move(mem_ctx, &state->wb_resp); - return 0; -} diff --git a/source3/lib/wbclient.c b/source3/lib/wbclient.c deleted file mode 100644 index d0070ea349..0000000000 --- a/source3/lib/wbclient.c +++ /dev/null @@ -1,678 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Infrastructure for async winbind requests - Copyright (C) Volker Lendecke 2008 - - ** NOTE! The following LGPL license applies to the wbclient - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see . -*/ - -#include "includes.h" -#include "wbc_async.h" - -wbcErr map_wbc_err_from_errno(int error) -{ - switch(error) { - case EPERM: - case EACCES: - return WBC_ERR_AUTH_ERROR; - case ENOMEM: - return WBC_ERR_NO_MEMORY; - case EIO: - default: - return WBC_ERR_UNKNOWN_FAILURE; - } -} - -bool tevent_req_is_wbcerr(struct tevent_req *req, wbcErr *pwbc_err) -{ - enum tevent_req_state state; - uint64_t error; - if (!tevent_req_is_error(req, &state, &error)) { - *pwbc_err = WBC_ERR_SUCCESS; - return false; - } - - switch (state) { - case TEVENT_REQ_USER_ERROR: - *pwbc_err = error; - break; - case TEVENT_REQ_TIMED_OUT: - *pwbc_err = WBC_ERR_UNKNOWN_FAILURE; - break; - case TEVENT_REQ_NO_MEMORY: - *pwbc_err = WBC_ERR_NO_MEMORY; - break; - default: - *pwbc_err = WBC_ERR_UNKNOWN_FAILURE; - break; - } - return true; -} - -wbcErr tevent_req_simple_recv_wbcerr(struct tevent_req *req) -{ - wbcErr wbc_err; - - if (tevent_req_is_wbcerr(req, &wbc_err)) { - return wbc_err; - } - - return WBC_ERR_SUCCESS; -} - -struct wb_context { - struct tevent_queue *queue; - int fd; - bool is_priv; -}; - -static int make_nonstd_fd(int fd) -{ - int i; - int sys_errno = 0; - int fds[3]; - int num_fds = 0; - - if (fd == -1) { - return -1; - } - while (fd < 3) { - fds[num_fds++] = fd; - fd = dup(fd); - if (fd == -1) { - sys_errno = errno; - break; - } - } - for (i=0; i= 0) { - flags |= FD_CLOEXEC; - result = fcntl( new_fd, F_SETFD, flags ); - } - if (result < 0) { - goto fail; - } -#endif - return new_fd; - - fail: - if (new_fd != -1) { - int sys_errno = errno; - close(new_fd); - errno = sys_errno; - } - return -1; -} - -struct wb_context *wb_context_init(TALLOC_CTX *mem_ctx) -{ - struct wb_context *result; - - result = talloc(mem_ctx, struct wb_context); - if (result == NULL) { - return NULL; - } - result->queue = tevent_queue_create(result, "wb_trans"); - if (result->queue == NULL) { - TALLOC_FREE(result); - return NULL; - } - result->fd = -1; - result->is_priv = false; - return result; -} - -struct wb_connect_state { - int dummy; -}; - -static void wbc_connect_connected(struct tevent_req *subreq); - -static struct tevent_req *wb_connect_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct wb_context *wb_ctx, - const char *dir) -{ - struct tevent_req *result, *subreq; - struct wb_connect_state *state; - struct sockaddr_un sunaddr; - struct stat st; - char *path = NULL; - wbcErr wbc_err; - - result = tevent_req_create(mem_ctx, &state, struct wb_connect_state); - if (result == NULL) { - return NULL; - } - - if (wb_ctx->fd != -1) { - close(wb_ctx->fd); - wb_ctx->fd = -1; - } - - /* Check permissions on unix socket directory */ - - if (lstat(dir, &st) == -1) { - wbc_err = WBC_ERR_WINBIND_NOT_AVAILABLE; - goto post_status; - } - - if (!S_ISDIR(st.st_mode) || - (st.st_uid != 0 && st.st_uid != geteuid())) { - wbc_err = WBC_ERR_WINBIND_NOT_AVAILABLE; - goto post_status; - } - - /* Connect to socket */ - - path = talloc_asprintf(talloc_tos(), "%s/%s", dir, - WINBINDD_SOCKET_NAME); - if (path == NULL) { - goto nomem; - } - - sunaddr.sun_family = AF_UNIX; - strlcpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path)); - TALLOC_FREE(path); - - /* If socket file doesn't exist, don't bother trying to connect - with retry. This is an attempt to make the system usable when - the winbindd daemon is not running. */ - - if ((lstat(sunaddr.sun_path, &st) == -1) - || !S_ISSOCK(st.st_mode) - || (st.st_uid != 0 && st.st_uid != geteuid())) { - wbc_err = WBC_ERR_WINBIND_NOT_AVAILABLE; - goto post_status; - } - - wb_ctx->fd = make_safe_fd(socket(AF_UNIX, SOCK_STREAM, 0)); - if (wb_ctx->fd == -1) { - wbc_err = map_wbc_err_from_errno(errno); - goto post_status; - } - - subreq = async_connect_send(mem_ctx, ev, wb_ctx->fd, - (struct sockaddr *)(void *)&sunaddr, - sizeof(sunaddr)); - if (subreq == NULL) { - goto nomem; - } - tevent_req_set_callback(subreq, wbc_connect_connected, result); - return result; - - post_status: - tevent_req_error(result, wbc_err); - return tevent_req_post(result, ev); - nomem: - TALLOC_FREE(result); - return NULL; -} - -static void wbc_connect_connected(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - int res, err; - - res = async_connect_recv(subreq, &err); - TALLOC_FREE(subreq); - if (res == -1) { - tevent_req_error(req, map_wbc_err_from_errno(err)); - return; - } - tevent_req_done(req); -} - -static wbcErr wb_connect_recv(struct tevent_req *req) -{ - return tevent_req_simple_recv_wbcerr(req); -} - -static const char *winbindd_socket_dir(void) -{ -#ifdef SOCKET_WRAPPER - const char *env_dir; - - env_dir = getenv(WINBINDD_SOCKET_DIR_ENVVAR); - if (env_dir) { - return env_dir; - } -#endif - - return WINBINDD_SOCKET_DIR; -} - -struct wb_open_pipe_state { - struct wb_context *wb_ctx; - struct tevent_context *ev; - bool need_priv; - struct winbindd_request wb_req; -}; - -static void wb_open_pipe_connect_nonpriv_done(struct tevent_req *subreq); -static void wb_open_pipe_ping_done(struct tevent_req *subreq); -static void wb_open_pipe_getpriv_done(struct tevent_req *subreq); -static void wb_open_pipe_connect_priv_done(struct tevent_req *subreq); - -static struct tevent_req *wb_open_pipe_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct wb_context *wb_ctx, - bool need_priv) -{ - struct tevent_req *result, *subreq; - struct wb_open_pipe_state *state; - - result = tevent_req_create(mem_ctx, &state, struct wb_open_pipe_state); - if (result == NULL) { - return NULL; - } - state->wb_ctx = wb_ctx; - state->ev = ev; - state->need_priv = need_priv; - - if (wb_ctx->fd != -1) { - close(wb_ctx->fd); - wb_ctx->fd = -1; - } - - subreq = wb_connect_send(state, ev, wb_ctx, winbindd_socket_dir()); - if (subreq == NULL) { - goto fail; - } - tevent_req_set_callback(subreq, wb_open_pipe_connect_nonpriv_done, - result); - return result; - - fail: - TALLOC_FREE(result); - return NULL; -} - -static void wb_open_pipe_connect_nonpriv_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - struct wb_open_pipe_state *state = tevent_req_data( - req, struct wb_open_pipe_state); - wbcErr wbc_err; - - wbc_err = wb_connect_recv(subreq); - TALLOC_FREE(subreq); - if (!WBC_ERROR_IS_OK(wbc_err)) { - state->wb_ctx->is_priv = true; - tevent_req_error(req, wbc_err); - return; - } - - ZERO_STRUCT(state->wb_req); - state->wb_req.cmd = WINBINDD_INTERFACE_VERSION; - state->wb_req.pid = getpid(); - - subreq = wb_simple_trans_send(state, state->ev, NULL, - state->wb_ctx->fd, &state->wb_req); - if (tevent_req_nomem(subreq, req)) { - return; - } - tevent_req_set_callback(subreq, wb_open_pipe_ping_done, req); -} - -static void wb_open_pipe_ping_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - struct wb_open_pipe_state *state = tevent_req_data( - req, struct wb_open_pipe_state); - struct winbindd_response *wb_resp; - int ret, err; - - ret = wb_simple_trans_recv(subreq, state, &wb_resp, &err); - TALLOC_FREE(subreq); - if (ret == -1) { - tevent_req_error(req, map_wbc_err_from_errno(err)); - return; - } - - if (!state->need_priv) { - tevent_req_done(req); - return; - } - - state->wb_req.cmd = WINBINDD_PRIV_PIPE_DIR; - state->wb_req.pid = getpid(); - - subreq = wb_simple_trans_send(state, state->ev, NULL, - state->wb_ctx->fd, &state->wb_req); - if (tevent_req_nomem(subreq, req)) { - return; - } - tevent_req_set_callback(subreq, wb_open_pipe_getpriv_done, req); -} - -static void wb_open_pipe_getpriv_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - struct wb_open_pipe_state *state = tevent_req_data( - req, struct wb_open_pipe_state); - struct winbindd_response *wb_resp = NULL; - int ret, err; - - ret = wb_simple_trans_recv(subreq, state, &wb_resp, &err); - TALLOC_FREE(subreq); - if (ret == -1) { - tevent_req_error(req, map_wbc_err_from_errno(err)); - return; - } - - close(state->wb_ctx->fd); - state->wb_ctx->fd = -1; - - subreq = wb_connect_send(state, state->ev, state->wb_ctx, - (char *)wb_resp->extra_data.data); - TALLOC_FREE(wb_resp); - if (tevent_req_nomem(subreq, req)) { - return; - } - tevent_req_set_callback(subreq, wb_open_pipe_connect_priv_done, req); -} - -static void wb_open_pipe_connect_priv_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - struct wb_open_pipe_state *state = tevent_req_data( - req, struct wb_open_pipe_state); - wbcErr wbc_err; - - wbc_err = wb_connect_recv(subreq); - TALLOC_FREE(subreq); - if (!WBC_ERROR_IS_OK(wbc_err)) { - tevent_req_error(req, wbc_err); - return; - } - state->wb_ctx->is_priv = true; - tevent_req_done(req); -} - -static wbcErr wb_open_pipe_recv(struct tevent_req *req) -{ - return tevent_req_simple_recv_wbcerr(req); -} - -struct wb_trans_state { - struct wb_trans_state *prev, *next; - struct wb_context *wb_ctx; - struct tevent_context *ev; - struct winbindd_request *wb_req; - struct winbindd_response *wb_resp; - bool need_priv; -}; - -static bool closed_fd(int fd) -{ - struct timeval tv; - fd_set r_fds; - int selret; - - if (fd == -1) { - return true; - } - - FD_ZERO(&r_fds); - FD_SET(fd, &r_fds); - ZERO_STRUCT(tv); - - selret = select(fd+1, &r_fds, NULL, NULL, &tv); - if (selret == -1) { - return true; - } - if (selret == 0) { - return false; - } - return (FD_ISSET(fd, &r_fds)); -} - -static void wb_trans_trigger(struct tevent_req *req, void *private_data); -static void wb_trans_connect_done(struct tevent_req *subreq); -static void wb_trans_done(struct tevent_req *subreq); -static void wb_trans_retry_wait_done(struct tevent_req *subreq); - -struct tevent_req *wb_trans_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct wb_context *wb_ctx, bool need_priv, - struct winbindd_request *wb_req) -{ - struct tevent_req *req; - struct wb_trans_state *state; - - req = tevent_req_create(mem_ctx, &state, struct wb_trans_state); - if (req == NULL) { - return NULL; - } - state->wb_ctx = wb_ctx; - state->ev = ev; - state->wb_req = wb_req; - state->need_priv = need_priv; - - if (!tevent_queue_add(wb_ctx->queue, ev, req, wb_trans_trigger, - NULL)) { - tevent_req_nomem(NULL, req); - return tevent_req_post(req, ev); - } - return req; -} - -static void wb_trans_trigger(struct tevent_req *req, void *private_data) -{ - struct wb_trans_state *state = tevent_req_data( - req, struct wb_trans_state); - struct tevent_req *subreq; - - if ((state->wb_ctx->fd != -1) && closed_fd(state->wb_ctx->fd)) { - close(state->wb_ctx->fd); - state->wb_ctx->fd = -1; - } - - if ((state->wb_ctx->fd == -1) - || (state->need_priv && !state->wb_ctx->is_priv)) { - subreq = wb_open_pipe_send(state, state->ev, state->wb_ctx, - state->need_priv); - if (tevent_req_nomem(subreq, req)) { - return; - } - tevent_req_set_callback(subreq, wb_trans_connect_done, req); - return; - } - - state->wb_req->pid = getpid(); - - subreq = wb_simple_trans_send(state, state->ev, NULL, - state->wb_ctx->fd, state->wb_req); - if (tevent_req_nomem(subreq, req)) { - return; - } - tevent_req_set_callback(subreq, wb_trans_done, req); -} - -static bool wb_trans_retry(struct tevent_req *req, - struct wb_trans_state *state, - wbcErr wbc_err) -{ - struct tevent_req *subreq; - - if (WBC_ERROR_IS_OK(wbc_err)) { - return false; - } - - if (wbc_err == WBC_ERR_WINBIND_NOT_AVAILABLE) { - /* - * Winbind not around or we can't connect to the pipe. Fail - * immediately. - */ - tevent_req_error(req, wbc_err); - return true; - } - - /* - * The transfer as such failed, retry after one second - */ - - if (state->wb_ctx->fd != -1) { - close(state->wb_ctx->fd); - state->wb_ctx->fd = -1; - } - - subreq = tevent_wakeup_send(state, state->ev, - timeval_current_ofs(1, 0)); - if (tevent_req_nomem(subreq, req)) { - return true; - } - tevent_req_set_callback(subreq, wb_trans_retry_wait_done, req); - return true; -} - -static void wb_trans_retry_wait_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - struct wb_trans_state *state = tevent_req_data( - req, struct wb_trans_state); - bool ret; - - ret = tevent_wakeup_recv(subreq); - TALLOC_FREE(subreq); - if (!ret) { - tevent_req_error(req, WBC_ERR_UNKNOWN_FAILURE); - return; - } - - subreq = wb_open_pipe_send(state, state->ev, state->wb_ctx, - state->need_priv); - if (tevent_req_nomem(subreq, req)) { - return; - } - tevent_req_set_callback(subreq, wb_trans_connect_done, req); -} - -static void wb_trans_connect_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - struct wb_trans_state *state = tevent_req_data( - req, struct wb_trans_state); - wbcErr wbc_err; - - wbc_err = wb_open_pipe_recv(subreq); - TALLOC_FREE(subreq); - - if (wb_trans_retry(req, state, wbc_err)) { - return; - } - - subreq = wb_simple_trans_send(state, state->ev, NULL, - state->wb_ctx->fd, state->wb_req); - if (tevent_req_nomem(subreq, req)) { - return; - } - tevent_req_set_callback(subreq, wb_trans_done, req); -} - -static void wb_trans_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - struct wb_trans_state *state = tevent_req_data( - req, struct wb_trans_state); - int ret, err; - - ret = wb_simple_trans_recv(subreq, state, &state->wb_resp, &err); - TALLOC_FREE(subreq); - if ((ret == -1) - && wb_trans_retry(req, state, map_wbc_err_from_errno(err))) { - return; - } - - tevent_req_done(req); -} - -wbcErr wb_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, - struct winbindd_response **presponse) -{ - struct wb_trans_state *state = tevent_req_data( - req, struct wb_trans_state); - wbcErr wbc_err; - - if (tevent_req_is_wbcerr(req, &wbc_err)) { - return wbc_err; - } - - *presponse = talloc_move(mem_ctx, &state->wb_resp); - return WBC_ERR_SUCCESS; -} diff --git a/source3/samba4.mk b/source3/samba4.mk index 3f661bdd14..e63a8453c0 100644 --- a/source3/samba4.mk +++ b/source3/samba4.mk @@ -74,6 +74,7 @@ clustersrcdir := $(samba4srcdir)/cluster libnetsrcdir := $(samba4srcdir)/libnet authsrcdir := $(samba4srcdir)/auth nsswitchsrcdir := $(samba4srcdir)/../nsswitch +libwbclientsrcdir := $(nsswitchsrcdir)/libwbclient libsrcdir := $(samba4srcdir)/lib libsocketsrcdir := $(samba4srcdir)/lib/socket libcharsetsrcdir := $(samba4srcdir)/../lib/util/charset diff --git a/source3/torture/torture.c b/source3/torture/torture.c index cfd3d640f9..30e7e8cbc5 100644 --- a/source3/torture/torture.c +++ b/source3/torture/torture.c @@ -18,7 +18,7 @@ */ #include "includes.h" -#include "wbc_async.h" +#include "nsswitch/libwbclient/wbc_async.h" extern char *optarg; extern int optind; diff --git a/source4/Makefile b/source4/Makefile index 7bc48b9fe4..2a3ad2def1 100644 --- a/source4/Makefile +++ b/source4/Makefile @@ -58,6 +58,7 @@ clustersrcdir := cluster libnetsrcdir := libnet authsrcdir := auth nsswitchsrcdir := ../nsswitch +libwbclientsrcdir := ../nsswitch/libwbclient libsrcdir := lib libsocketsrcdir := lib/socket libcharsetsrcdir := ../lib/util/charset diff --git a/source4/libcli/wbclient/config.mk b/source4/libcli/wbclient/config.mk index 00df5dbb22..af4d3eff82 100644 --- a/source4/libcli/wbclient/config.mk +++ b/source4/libcli/wbclient/config.mk @@ -1,5 +1,5 @@ -[SUBSYSTEM::LIBWBCLIENT] +[SUBSYSTEM::LIBWBCLIENT_OLD] PUBLIC_DEPENDENCIES = LIBSAMBA-ERRORS LIBEVENTS PRIVATE_DEPENDENCIES = NDR_WINBIND MESSAGING -LIBWBCLIENT_OBJ_FILES = $(libclisrcdir)/wbclient/wbclient.o +LIBWBCLIENT_OLD_OBJ_FILES = $(libclisrcdir)/wbclient/wbclient.o diff --git a/source4/main.mk b/source4/main.mk index 2e74ba9a5b..b4a82017c8 100644 --- a/source4/main.mk +++ b/source4/main.mk @@ -7,6 +7,7 @@ mkinclude smbd/process_model.mk mkinclude libnet/config.mk mkinclude auth/config.mk mkinclude ../nsswitch/config.mk +mkinclude ../nsswitch/libwbclient/config.mk mkinclude lib/samba3/config.mk mkinclude lib/socket/config.mk mkinclude ../lib/util/charset/config.mk diff --git a/source4/ntvfs/posix/config.mk b/source4/ntvfs/posix/config.mk index 1d7949214a..1aaef3f1d4 100644 --- a/source4/ntvfs/posix/config.mk +++ b/source4/ntvfs/posix/config.mk @@ -42,7 +42,7 @@ OUTPUT_TYPE = MERGED_OBJ INIT_FUNCTION = ntvfs_posix_init #PRIVATE_DEPENDENCIES = pvfs_acl_xattr pvfs_acl_nfs4 PRIVATE_DEPENDENCIES = NDR_XATTR WRAP_XATTR BLKID ntvfs_common MESSAGING \ - LIBWBCLIENT pvfs_acl pvfs_aio + LIBWBCLIENT_OLD pvfs_acl pvfs_aio # End MODULE ntvfs_posix ################################################ diff --git a/source4/rpc_server/config.mk b/source4/rpc_server/config.mk index dfc3d17bed..f3dc074125 100644 --- a/source4/rpc_server/config.mk +++ b/source4/rpc_server/config.mk @@ -85,7 +85,7 @@ PRIVATE_DEPENDENCIES = \ SAMDB \ NDR_UNIXINFO \ NSS_WRAPPER \ - LIBWBCLIENT + LIBWBCLIENT_OLD # End MODULE dcerpc_unixinfo ################################################ -- cgit