Do queueing in wbclient.c
[ira/wip.git] / source3 / lib / wbclient.c
index ae9a034cc8db3d74b17703846a2118b0ad89489f..979aa94d40fc6a701b517d3961c1738f9117149e 100644 (file)
 */
 
 #include "includes.h"
-#include "winbindd/winbindd.h"
-#include "winbindd/winbindd_proto.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)
 {
@@ -110,33 +166,6 @@ static int make_safe_fd(int fd)
        return -1;
 }
 
-static bool winbind_closed_fd(int fd)
-{
-       struct timeval tv;
-       fd_set r_fds;
-
-       if (fd == -1) {
-               return true;
-       }
-
-       FD_ZERO(&r_fds);
-       FD_SET(fd, &r_fds);
-       ZERO_STRUCT(tv);
-
-       if ((select(fd+1, &r_fds, NULL, NULL, &tv) == -1)
-           || FD_ISSET(fd, &r_fds)) {
-               return true;
-       }
-
-       return false;
-}
-
-struct wb_context {
-       struct async_req_queue *queue;
-       int fd;
-       bool is_priv;
-};
-
 struct wb_context *wb_context_init(TALLOC_CTX *mem_ctx)
 {
        struct wb_context *result;
@@ -145,25 +174,38 @@ struct wb_context *wb_context_init(TALLOC_CTX *mem_ctx)
        if (result == NULL) {
                return NULL;
        }
-       result->queue = async_req_queue_init(result);
+       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;
 }
 
-static struct async_req *wb_connect_send(TALLOC_CTX *mem_ctx,
-                                        struct tevent_context *ev,
-                                        struct wb_context *wb_ctx,
-                                        const char *dir)
+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 async_req *req;
+       struct tevent_req *result, *subreq;
+       struct wb_connect_state *state;
        struct sockaddr_un sunaddr;
        struct stat st;
        char *path = NULL;
-       NTSTATUS status;
+       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);
@@ -173,13 +215,13 @@ static struct async_req *wb_connect_send(TALLOC_CTX *mem_ctx,
        /* Check permissions on unix socket directory */
 
        if (lstat(dir, &st) == -1) {
-               status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+               wbc_err = WBC_ERR_WINBIND_NOT_AVAILABLE;
                goto post_status;
        }
 
        if (!S_ISDIR(st.st_mode) ||
            (st.st_uid != 0 && st.st_uid != geteuid())) {
-               status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+               wbc_err = WBC_ERR_WINBIND_NOT_AVAILABLE;
                goto post_status;
        }
 
@@ -202,182 +244,56 @@ static struct async_req *wb_connect_send(TALLOC_CTX *mem_ctx,
        if ((lstat(sunaddr.sun_path, &st) == -1)
            || !S_ISSOCK(st.st_mode)
            || (st.st_uid != 0 && st.st_uid != geteuid())) {
-               status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+               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) {
-               status = map_nt_error_from_unix(errno);
+               wbc_err = map_wbc_err_from_errno(errno);
                goto post_status;
        }
 
-       req = async_connect_send(mem_ctx, ev, wb_ctx->fd,
-                                (struct sockaddr *)&sunaddr,
-                                sizeof(sunaddr));
-       if (req == NULL) {
-               goto nomem;
-       }
-       if (!async_req_set_timeout(req, ev, timeval_set(30, 0))) {
-               TALLOC_FREE(req);
+       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 req;
-
- nomem:
-       status = NT_STATUS_NO_MEMORY;
- post_status:
-       req = async_req_new(mem_ctx);
-       if (req == NULL) {
-               return NULL;
-       }
-       if (async_post_ntstatus(req, ev, status)) {
-               return req;
-       }
-       TALLOC_FREE(req);
-       return NULL;
-}
-
-static NTSTATUS wb_connect_recv(struct async_req *req)
-{
-       int dummy;
-
-       return async_connect_recv(req, &dummy);
-}
-
-static struct winbindd_request *winbindd_request_copy(
-       TALLOC_CTX *mem_ctx,
-       const struct winbindd_request *req)
-{
-       struct winbindd_request *result;
-
-       result = (struct winbindd_request *)TALLOC_MEMDUP(
-               mem_ctx, req, sizeof(struct winbindd_request));
-       if (result == NULL) {
-               return NULL;
-       }
-
-       if (result->extra_len == 0) {
-               return result;
-       }
-
-       result->extra_data.data = (char *)TALLOC_MEMDUP(
-               result, result->extra_data.data, result->extra_len);
-       if (result->extra_data.data == NULL) {
-               TALLOC_FREE(result);
-               return NULL;
-       }
-       return result;
-}
-
-struct wb_int_trans_state {
-       struct tevent_context *ev;
-       int fd;
-       struct winbindd_request *wb_req;
-       struct winbindd_response *wb_resp;
-};
-
-static void wb_int_trans_write_done(struct async_req *subreq);
-static void wb_int_trans_read_done(struct async_req *subreq);
-
-static struct async_req *wb_int_trans_send(TALLOC_CTX *mem_ctx,
-                                          struct tevent_context *ev, int fd,
-                                          struct winbindd_request *wb_req)
-{
-       struct async_req *result;
-       struct async_req *subreq;
-       struct wb_int_trans_state *state;
-
-       if (!async_req_setup(mem_ctx, &result, &state,
-                            struct wb_int_trans_state)) {
-               return NULL;
-       }
-
-       if (winbind_closed_fd(fd)) {
-               if (!async_post_ntstatus(result, ev,
-                                        NT_STATUS_PIPE_DISCONNECTED)) {
-                       goto fail;
-               }
-               return result;
-       }
-
-       state->ev = ev;
-       state->fd = fd;
-       state->wb_req = wb_req;
-
-       state->wb_req->length = sizeof(struct winbindd_request);
-       state->wb_req->pid = getpid();
-
-       subreq = wb_req_write_send(state, state->ev, state->fd, state->wb_req);
-       if (subreq == NULL) {
-               goto fail;
+       if (!tevent_req_set_endtime(subreq, ev, timeval_current_ofs(30, 0))) {
+               goto nomem;
        }
-       subreq->async.fn = wb_int_trans_write_done;
-       subreq->async.priv = result;
 
        return result;
 
- fail:
+ post_status:
+       tevent_req_error(result, wbc_err);
+       return tevent_req_post(result, ev);
+ nomem:
        TALLOC_FREE(result);
        return NULL;
 }
 
-static void wb_int_trans_write_done(struct async_req *subreq)
+static void wbc_connect_connected(struct tevent_req *subreq)
 {
-       struct async_req *req = talloc_get_type_abort(
-               subreq->async.priv, struct async_req);
-       struct wb_int_trans_state *state = talloc_get_type_abort(
-               req->private_data, struct wb_int_trans_state);
-       NTSTATUS status;
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       int res, err;
 
-       status = wb_req_write_recv(subreq);
+       res = async_connect_recv(subreq, &err);
        TALLOC_FREE(subreq);
-       if (!NT_STATUS_IS_OK(status)) {
-               async_req_nterror(req, status);
+       if (res == -1) {
+               tevent_req_error(req, map_wbc_err_from_errno(err));
                return;
        }
-
-       subreq = wb_resp_read_send(state, state->ev, state->fd);
-       if (subreq == NULL) {
-               async_req_nterror(req, NT_STATUS_NO_MEMORY);
-       }
-       subreq->async.fn = wb_int_trans_read_done;
-       subreq->async.priv = req;
+       tevent_req_done(req);
 }
 
-static void wb_int_trans_read_done(struct async_req *subreq)
+static wbcErr wb_connect_recv(struct tevent_req *req)
 {
-       struct async_req *req = talloc_get_type_abort(
-               subreq->async.priv, struct async_req);
-       struct wb_int_trans_state *state = talloc_get_type_abort(
-               req->private_data, struct wb_int_trans_state);
-       NTSTATUS status;
-
-       status = wb_resp_read_recv(subreq, state, &state->wb_resp);
-       TALLOC_FREE(subreq);
-       if (!NT_STATUS_IS_OK(status)) {
-               async_req_nterror(req, status);
-               return;
-       }
-
-       async_req_done(req);
-}
-
-static NTSTATUS wb_int_trans_recv(struct async_req *req,
-                                 TALLOC_CTX *mem_ctx,
-                                 struct winbindd_response **presponse)
-{
-       struct wb_int_trans_state *state = talloc_get_type_abort(
-               req->private_data, struct wb_int_trans_state);
-       NTSTATUS status;
-
-       if (async_req_is_nterror(req, &status)) {
-               return status;
-       }
-
-       *presponse = talloc_move(mem_ctx, &state->wb_resp);
-       return NT_STATUS_OK;
+       return tevent_req_simple_recv_wbcerr(req);
 }
 
 static const char *winbindd_socket_dir(void)
@@ -401,22 +317,21 @@ struct wb_open_pipe_state {
        struct winbindd_request wb_req;
 };
 
-static void wb_open_pipe_connect_nonpriv_done(struct async_req *subreq);
-static void wb_open_pipe_ping_done(struct async_req *subreq);
-static void wb_open_pipe_getpriv_done(struct async_req *subreq);
-static void wb_open_pipe_connect_priv_done(struct async_req *subreq);
+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 async_req *wb_open_pipe_send(TALLOC_CTX *mem_ctx,
-                                          struct tevent_context *ev,
-                                          struct wb_context *wb_ctx,
-                                          bool need_priv)
+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 async_req *result;
-       struct async_req *subreq;
+       struct tevent_req *result, *subreq;
        struct wb_open_pipe_state *state;
 
-       if (!async_req_setup(mem_ctx, &result, &state,
-                            struct wb_open_pipe_state)) {
+       result = tevent_req_create(mem_ctx, &state, struct wb_open_pipe_state);
+       if (result == NULL) {
                return NULL;
        }
        state->wb_ctx = wb_ctx;
@@ -432,9 +347,8 @@ static struct async_req *wb_open_pipe_send(TALLOC_CTX *mem_ctx,
        if (subreq == NULL) {
                goto fail;
        }
-
-       subreq->async.fn = wb_open_pipe_connect_nonpriv_done;
-       subreq->async.priv = result;
+       tevent_req_set_callback(subreq, wb_open_pipe_connect_nonpriv_done,
+                               result);
        return result;
 
  fail:
@@ -442,81 +356,79 @@ static struct async_req *wb_open_pipe_send(TALLOC_CTX *mem_ctx,
        return NULL;
 }
 
-static void wb_open_pipe_connect_nonpriv_done(struct async_req *subreq)
+static void wb_open_pipe_connect_nonpriv_done(struct tevent_req *subreq)
 {
-       struct async_req *req = talloc_get_type_abort(
-               subreq->async.priv, struct async_req);
-       struct wb_open_pipe_state *state = talloc_get_type_abort(
-               req->private_data, struct wb_open_pipe_state);
-       NTSTATUS status;
+       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;
 
-       status = wb_connect_recv(subreq);
+       wbc_err = wb_connect_recv(subreq);
        TALLOC_FREE(subreq);
-       if (!NT_STATUS_IS_OK(status)) {
+       if (!WBC_ERROR_IS_OK(wbc_err)) {
                state->wb_ctx->is_priv = true;
-               async_req_nterror(req, status);
+               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_int_trans_send(state, state->ev, state->wb_ctx->fd,
-                                  &state->wb_req);
-       if (async_req_nomem(subreq, req)) {
+       subreq = wb_simple_trans_send(state, state->ev, NULL,
+                                     state->wb_ctx->fd, &state->wb_req);
+       if (tevent_req_nomem(subreq, req)) {
                return;
        }
-
-       subreq->async.fn = wb_open_pipe_ping_done;
-       subreq->async.priv = req;
+       tevent_req_set_callback(subreq, wb_open_pipe_ping_done, req);
 }
 
-static void wb_open_pipe_ping_done(struct async_req *subreq)
+static void wb_open_pipe_ping_done(struct tevent_req *subreq)
 {
-       struct async_req *req = talloc_get_type_abort(
-               subreq->async.priv, struct async_req);
-       struct wb_open_pipe_state *state = talloc_get_type_abort(
-               req->private_data, struct wb_open_pipe_state);
+       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;
-       NTSTATUS status;
+       int ret, err;
 
-       status = wb_int_trans_recv(subreq, state, &wb_resp);
+       ret = wb_simple_trans_recv(subreq, state, &wb_resp, &err);
        TALLOC_FREE(subreq);
-       if (!NT_STATUS_IS_OK(status)) {
-               async_req_nterror(req, status);
+       if (ret == -1) {
+               tevent_req_error(req, map_wbc_err_from_errno(err));
                return;
        }
 
        if (!state->need_priv) {
-               async_req_done(req);
+               tevent_req_done(req);
                return;
        }
 
        state->wb_req.cmd = WINBINDD_PRIV_PIPE_DIR;
+       state->wb_req.pid = getpid();
 
-       subreq = wb_int_trans_send(state, state->ev, state->wb_ctx->fd,
-                                  &state->wb_req);
-       if (async_req_nomem(subreq, req)) {
+       subreq = wb_simple_trans_send(state, state->ev, NULL,
+                                     state->wb_ctx->fd, &state->wb_req);
+       if (tevent_req_nomem(subreq, req)) {
                return;
        }
-
-       subreq->async.fn = wb_open_pipe_getpriv_done;
-       subreq->async.priv = req;
+       tevent_req_set_callback(subreq, wb_open_pipe_getpriv_done, req);
 }
 
-static void wb_open_pipe_getpriv_done(struct async_req *subreq)
+static void wb_open_pipe_getpriv_done(struct tevent_req *subreq)
 {
-       struct async_req *req = talloc_get_type_abort(
-               subreq->async.priv, struct async_req);
-       struct wb_open_pipe_state *state = talloc_get_type_abort(
-               req->private_data, struct wb_open_pipe_state);
+       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;
-       NTSTATUS status;
+       int ret, err;
 
-       status = wb_int_trans_recv(subreq, state, &wb_resp);
+       ret = wb_simple_trans_recv(subreq, state, &wb_resp, &err);
        TALLOC_FREE(subreq);
-       if (!NT_STATUS_IS_OK(status)) {
-               async_req_nterror(req, status);
+       if (ret == -1) {
+               tevent_req_error(req, map_wbc_err_from_errno(err));
                return;
        }
 
@@ -524,37 +436,35 @@ static void wb_open_pipe_getpriv_done(struct async_req *subreq)
        state->wb_ctx->fd = -1;
 
        subreq = wb_connect_send(state, state->ev, state->wb_ctx,
-                                (char *)wb_resp->extra_data.data);
+                                 (char *)wb_resp->extra_data.data);
        TALLOC_FREE(wb_resp);
-       if (async_req_nomem(subreq, req)) {
+       if (tevent_req_nomem(subreq, req)) {
                return;
        }
-
-       subreq->async.fn = wb_open_pipe_connect_priv_done;
-       subreq->async.priv = req;
+       tevent_req_set_callback(subreq, wb_open_pipe_connect_priv_done, req);
 }
 
-static void wb_open_pipe_connect_priv_done(struct async_req *subreq)
+static void wb_open_pipe_connect_priv_done(struct tevent_req *subreq)
 {
-       struct async_req *req = talloc_get_type_abort(
-               subreq->async.priv, struct async_req);
-       struct wb_open_pipe_state *state = talloc_get_type_abort(
-               req->private_data, struct wb_open_pipe_state);
-       NTSTATUS status;
+       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;
 
-       status = wb_connect_recv(subreq);
+       wbc_err = wb_connect_recv(subreq);
        TALLOC_FREE(subreq);
-       if (!NT_STATUS_IS_OK(status)) {
-               async_req_nterror(req, status);
+       if (!WBC_ERROR_IS_OK(wbc_err)) {
+               tevent_req_error(req, wbc_err);
                return;
        }
        state->wb_ctx->is_priv = true;
-       async_req_done(req);
+       tevent_req_done(req);
 }
 
-static NTSTATUS wb_open_pipe_recv(struct async_req *req)
+static wbcErr wb_open_pipe_recv(struct tevent_req *req)
 {
-       return async_req_simple_recv_ntstatus(req);
+       return tevent_req_simple_recv_wbcerr(req);
 }
 
 struct wb_trans_state {
@@ -567,91 +477,115 @@ struct wb_trans_state {
        bool need_priv;
 };
 
-static void wb_trans_connect_done(struct async_req *subreq);
-static void wb_trans_done(struct async_req *subreq);
-static void wb_trans_retry_wait_done(struct async_req *subreq);
-
-static void wb_trigger_trans(struct async_req *req)
+static bool closed_fd(int fd)
 {
-       struct wb_trans_state *state = talloc_get_type_abort(
-               req->private_data, struct wb_trans_state);
-       struct async_req *subreq;
-
-       if ((state->wb_ctx->fd == -1)
-           || (state->need_priv && !state->wb_ctx->is_priv)) {
+       struct timeval tv;
+       fd_set r_fds;
+       int selret;
 
-               subreq = wb_open_pipe_send(state, state->ev, state->wb_ctx,
-                                          state->need_priv);
-               if (async_req_nomem(subreq, req)) {
-                       return;
-               }
-               subreq->async.fn = wb_trans_connect_done;
-               subreq->async.priv = req;
-               return;
+       if (fd == -1) {
+               return true;
        }
 
-       subreq = wb_int_trans_send(state, state->ev, state->wb_ctx->fd,
-                                  state->wb_req);
-       if (async_req_nomem(subreq, req)) {
-               return;
+       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;
        }
-       subreq->async.fn = wb_trans_done;
-       subreq->async.priv = req;
+       return (FD_ISSET(fd, &r_fds));
 }
 
-struct async_req *wb_trans_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
-                               struct wb_context *wb_ctx, bool need_priv,
-                               const struct winbindd_request *wb_req)
+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 async_req *result;
+       struct tevent_req *req;
        struct wb_trans_state *state;
 
-       if (!async_req_setup(mem_ctx, &result, &state,
-                            struct wb_trans_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 = winbindd_request_copy(state, wb_req);
-       if (state->wb_req == NULL) {
-               goto fail;
-       }
+       state->wb_req = wb_req;
        state->num_retries = 10;
        state->need_priv = need_priv;
 
-       if (!async_req_enqueue(wb_ctx->queue, ev, result, wb_trigger_trans)) {
-               goto fail;
+       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 result;
+       return req;
+}
 
- fail:
-       TALLOC_FREE(result);
-       return NULL;
+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 async_req *req,
+static bool wb_trans_retry(struct tevent_req *req,
                           struct wb_trans_state *state,
-                          NTSTATUS status)
+                          wbcErr wbc_err)
 {
-       struct async_req *subreq;
+       struct tevent_req *subreq;
 
-       if (NT_STATUS_IS_OK(status)) {
+       if (WBC_ERROR_IS_OK(wbc_err)) {
                return false;
        }
 
-       if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)
-           || NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+       if (wbc_err == WBC_ERR_WINBIND_NOT_AVAILABLE) {
                /*
                 * Winbind not around or we can't connect to the pipe. Fail
                 * immediately.
                 */
-               async_req_nterror(req, status);
+               tevent_req_error(req, wbc_err);
                return true;
        }
 
        state->num_retries -= 1;
        if (state->num_retries == 0) {
-               async_req_nterror(req, status);
+               tevent_req_error(req, wbc_err);
                return true;
        }
 
@@ -664,94 +598,90 @@ static bool wb_trans_retry(struct async_req *req,
                state->wb_ctx->fd = -1;
        }
 
-       subreq = async_wait_send(state, state->ev, timeval_set(1, 0));
-       if (async_req_nomem(subreq, req)) {
+       subreq = tevent_wakeup_send(state, state->ev,
+                                   timeval_current_ofs(1, 0));
+       if (tevent_req_nomem(subreq, req)) {
                return true;
        }
-
-       subreq->async.fn = wb_trans_retry_wait_done;
-       subreq->async.priv = req;
+       tevent_req_set_callback(subreq, wb_trans_retry_wait_done, req);
        return true;
 }
 
-static void wb_trans_retry_wait_done(struct async_req *subreq)
+static void wb_trans_retry_wait_done(struct tevent_req *subreq)
 {
-       struct async_req *req = talloc_get_type_abort(
-               subreq->async.priv, struct async_req);
-       struct wb_trans_state *state = talloc_get_type_abort(
-               req->private_data, struct wb_trans_state);
+       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 = async_wait_recv(subreq);
+       ret = tevent_wakeup_recv(subreq);
        TALLOC_FREE(subreq);
-       if (ret) {
-               async_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+       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 (async_req_nomem(subreq, req)) {
+       if (tevent_req_nomem(subreq, req)) {
                return;
        }
-       subreq->async.fn = wb_trans_connect_done;
-       subreq->async.priv = req;
+       tevent_req_set_callback(subreq, wb_trans_connect_done, req);
 }
 
-static void wb_trans_connect_done(struct async_req *subreq)
+static void wb_trans_connect_done(struct tevent_req *subreq)
 {
-       struct async_req *req = talloc_get_type_abort(
-               subreq->async.priv, struct async_req);
-       struct wb_trans_state *state = talloc_get_type_abort(
-               req->private_data, struct wb_trans_state);
-       NTSTATUS status;
+       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;
 
-       status = wb_open_pipe_recv(subreq);
+       wbc_err = wb_open_pipe_recv(subreq);
        TALLOC_FREE(subreq);
 
-       if (wb_trans_retry(req, state, status)) {
+       if (wb_trans_retry(req, state, wbc_err)) {
                return;
        }
 
-       subreq = wb_int_trans_send(state, state->ev, state->wb_ctx->fd,
-                                  state->wb_req);
-       if (async_req_nomem(subreq, req)) {
+       subreq = wb_simple_trans_send(state, state->ev, NULL,
+                                     state->wb_ctx->fd, state->wb_req);
+       if (tevent_req_nomem(subreq, req)) {
                return;
        }
-
-       subreq->async.fn = wb_trans_done;
-       subreq->async.priv = req;
+       tevent_req_set_callback(subreq, wb_trans_done, req);
 }
 
-static void wb_trans_done(struct async_req *subreq)
+static void wb_trans_done(struct tevent_req *subreq)
 {
-       struct async_req *req = talloc_get_type_abort(
-               subreq->async.priv, struct async_req);
-       struct wb_trans_state *state = talloc_get_type_abort(
-               req->private_data, struct wb_trans_state);
-       NTSTATUS status;
+       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;
 
-       status = wb_int_trans_recv(subreq, state, &state->wb_resp);
+       ret = wb_simple_trans_recv(subreq, state, &state->wb_resp, &err);
        TALLOC_FREE(subreq);
-
-       if (wb_trans_retry(req, state, status)) {
+       if ((ret == -1)
+           && wb_trans_retry(req, state, map_wbc_err_from_errno(err))) {
                return;
        }
 
-       async_req_done(req);
+       tevent_req_done(req);
 }
 
-NTSTATUS wb_trans_recv(struct async_req *req, TALLOC_CTX *mem_ctx,
-                      struct winbindd_response **presponse)
+wbcErr wb_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+                    struct winbindd_response **presponse)
 {
-       struct wb_trans_state *state = talloc_get_type_abort(
-               req->private_data, struct wb_trans_state);
-       NTSTATUS status;
+       struct wb_trans_state *state = tevent_req_data(
+               req, struct wb_trans_state);
+       wbcErr wbc_err;
 
-       if (async_req_is_nterror(req, &status)) {
-               return status;
+       if (tevent_req_is_wbcerr(req, &wbc_err)) {
+               return wbc_err;
        }
 
        *presponse = talloc_move(mem_ctx, &state->wb_resp);
-       return NT_STATUS_OK;
+       return WBC_ERR_SUCCESS;
 }