--8GpibOaaTibBMecb
Content-Type: multipart/mixed; boundary="nFreZHaLTZJo0R7j"
Content-Disposition: inline


--nFreZHaLTZJo0R7j
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Hi!

As at least Kai and Jerry showed interest, attached find a
very early patch on the way to make libwbclient async.

I tried to abstract away the concrete event library using
the function pointers in wbcEventShim. In the wbinfo part of
the patch you see how it would integrate with lib/events.c.
I looked at libev (libev.schmorp.de), this also looks
doable. The EventShim functions are (I think) abstract
enough to match pretty any event lib out there.

The main disadvantage is that the fact that we're talking to
file descriptors shows through. This means that it would not
match the IRPC API of Samba4 as easily. But maybe even that
is doable.

Current status: It does survive the wbcPingSend in wbinfo
under valgrind, nothing more. But the API should be in a
state where I'm ready to take comments. :-)

Volker

--nFreZHaLTZJo0R7j
Content-Type: text/x-patch; charset=us-ascii
Content-Disposition: attachment; filename="0001-Start-async-libwbclient.patch"
Content-Transfer-Encoding: quoted-printable

=46rom 9e0f52768acfed7c8d6912426bc18f18258f7393 Mon Sep 17 00:00:00 2001
=46rom: Volker Lendecke
Date: Sun, 6 Apr 2008 14:53:02 +0200
Subject: [PATCH] Start async libwbclient

---
source/nsswitch/libwbclient/wbc_util.c | 16 +
source/nsswitch/libwbclient/wbclient.c | 593 +++++++++++++++++++=
++++
source/nsswitch/libwbclient/wbclient.h | 54 ++
source/nsswitch/libwbclient/wbclient_internal.h | 44 ++
source/nsswitch/wbinfo.c | 201 ++++++++
source/nsswitch/winbind_struct_protocol.h | 3 +
6 files changed, 911 insertions(+), 0 deletions(-)

diff --git a/source/nsswitch/libwbclient/wbc_util.c b/source/nsswitch/libwb=
client/wbc_util.c
index 7bdae91..95b7d17 100644
--- a/source/nsswitch/libwbclient/wbc_util.c
+++ b/source/nsswitch/libwbclient/wbc_util.c
@@ -24,7 +24,23 @@
=20
#include "libwbclient.h"
=20
+wbcErr wbcPingSend(struct wbcConnection *conn,
+ void (*completion)(struct wbcRequest *req, void *priv),
+ void *priv, struct wbcRequest **preq)
+{
+ struct winbindd_request request;
=20
+ ZERO_STRUCT(request);
+ return wbcRequestSend(conn, WINBINDD_PING, &request,
+ completion, priv, preq);
+}
+
+wbcErr wbcPingRecv(struct wbcRequest *req)
+{
+ wbcErr result =3D req->err;
+ wbcFreeMemory(req);
+ return result;
+}
=20
/** @brief Ping winbindd to see if the daemon is running
*
diff --git a/source/nsswitch/libwbclient/wbclient.c b/source/nsswitch/libwb=
client/wbclient.c
index e172962..f7013d7 100644
--- a/source/nsswitch/libwbclient/wbclient.c
+++ b/source/nsswitch/libwbclient/wbclient.c
@@ -23,6 +23,58 @@
/* Required Headers */
=20
#include "libwbclient.h"
+#include "dlinklist.h"
+
+/** @brief Close the socket in a wbcConnection
+ *
+ * @param conn The wbcConnection to be destroyed
+ *
+ * @return Always succeed...
+ **/
+
+static int wbcConnectionDestructor(struct wbcConnection *conn)
+{
+ if (conn->fd_event !=3D NULL) {
+ conn->ev.del_fd(conn->ev.lib_private, conn->fd_event);
+ conn->fd_event =3D NULL;
+ }
+ if (conn->fd !=3D -1) {
+ close(conn->fd);
+ }
+ return 0;
+}
+
+/** @brief Initialize a wbc_connection
+ *
+ * @param set_fd_status Callback to indicate interest in read/writability
+ * of a file descriptor
+ * @param priv Private pointer passed to set_fd_status
+ * @param connection The connection. To close, free with wbcFreeMemory
+ *
+ * @return #wbcErr
+ **/
+
+wbcErr wbcInitConnection(const struct wbcEventShim *shim,
+ struct wbcConnection **presult)
+{
+ struct wbcConnection *result;
+
+ result =3D talloc(NULL, struct wbcConnection);
+ if (result =3D=3D NULL) {
+ return WBC_ERR_NO_MEMORY;
+ }
+
+ result->ev =3D *shim;
+ result->fd =3D -1;
+ result->fd_event =3D NULL;
+ result->requests =3D NULL;
+
+ talloc_set_destructor(result, wbcConnectionDestructor);
+
+ *presult =3D result;
+
+ return WBC_ERR_SUCCESS;
+}
=20
/* From wb_common.c */
=20
@@ -81,6 +133,547 @@ wbcErr wbcRequestResponse(int cmd,
return wbc_status;
}
=20
+/** @brief Make sure fd is not 0, 1 or 2, and set NONBLOCK and CLOEXEC
+ *
+ * @param fd The fd to dup;
+ **/
+
+static int wbcMakeSafeFd(int fd)
+{
+ int flags;
+
+ if ((fd >=3D 0) && (fd <=3D 2)) {
+ int i, fds[3];
+
+ for (i=3D0; i<3; i++) {
+ fds[i] =3D dup(fd);
+ if ((fds[i] =3D=3D -1) || (fds[i] > 2)) {
+ break;
+ }
+ }
+
+ if (i>0) close(fds[0]);
+ if (i>1) close(fds[1]);
+
+ if (fds[i] =3D=3D -1) {
+ return -1;
+ }
+
+ /*
+ * fd is moved away now
+ */
+
+ close(fd);
+ fd =3D fds[i];
+ }
+
+ flags =3D fcntl(fd, F_GETFL);
+ if (flags =3D=3D -1) {
+ goto fail;
+ }
+
+#if 0
+
+#ifdef O_NONBLOCK
+ flags |=3D O_NONBLOCK;
+#else
+#ifdef SYSV
+ flags |=3D O_NDELAY;
+#else /* BSD */
+ flags |=3D FNDELAY;
+#endif
+#endif
+
+#endif
+
+#ifdef FD_CLOEXEC
+ flags |=3D FD_CLOEXEC;
+#endif
+
+ if (fcntl(fd, F_SETFD, flags) =3D=3D -1) {
+ goto fail;
+ }
+
+ return fd;
+
+ fail:
+ close(fd);
+ return -1;
+}
+
+static void wbcConnectionError(struct wbcConnection *conn)
+{
+ while (conn->requests !=3D NULL) {
+ struct wbcRequest *req =3D conn->requests;
+ req->err =3D WBC_ERR_WINBIND_NOT_AVAILABLE;
+ req->completion(req, req->priv);
+ DLIST_REMOVE(conn->requests, req);
+ wbcFreeMemory(req);
+ }
+
+ conn->ev.del_fd(conn->ev.lib_private, conn->fd_event);
+ conn->fd_event =3D NULL;
+ close(conn->fd);
+}
+
+static void wbcSockWriteable(struct wbcConnection *conn,
+ struct wbcRequest *req)
+{
+ ssize_t nwritten;
+
+ nwritten =3D write(conn->fd, (char *)(&req->request) + req->nwritten,
+ sizeof(req->request) - req->nwritten);
+
+ if (nwritten =3D=3D -1) {
+ wbcConnectionError(conn);
+ return;
+ }
+
+ req->nwritten +=3D nwritten;
+ if (req->nwritten =3D=3D sizeof(req->request)) {
+ conn->ev.set_fd(conn->ev.lib_private, conn->fd_event, 1, 0);
+ }
+}
+
+static void wbcSockReadable(struct wbcConnection *conn,
+ struct wbcRequest *req)
+{
+ size_t to_read;
+ void *data;
+ ssize_t nread;
+
+ /*
+ * Look where to read
+ */
+
+ if (req->nread < sizeof(struct winbindd_response)) {
+ /*
+ * Read the main response
+ */
+ data =3D (void *)((char *)req->response + req->nread);
+ to_read =3D sizeof(struct winbindd_response) - req->nread;
+ }
+ else {
+ /*
+ * Read extra data;
+ */
+ size_t off =3D req->nread - sizeof(struct winbindd_response);
+
+ data =3D (void *)((char *)req->response->extra_data.data + off);
+ to_read =3D req->response->length
+ - sizeof(struct winbindd_response);
+ }
+
+ nread =3D read(conn->fd, data, to_read);
+ if (nread <=3D 0) {
+ wbcConnectionError(conn);
+ return;
+ }
+ req->nread +=3D nread;
+
+ if (req->nread < sizeof(struct winbindd_response)) {
+ /*
+ * Still within the main response.
+ */
+ return;
+ }
+
+ if (req->nread =3D=3D sizeof(struct winbindd_response)) {
+ int extra_data_len =3D req->response->length
+ - sizeof(struct winbindd_response);
+
+ if (extra_data_len =3D=3D 0) {
+ goto finished;
+ }
+
+ req->response->extra_data.data =3D talloc_size(
+ req->response, extra_data_len);
+ if (req->response->extra_data.data =3D=3D NULL) {
+ wbcConnectionError(conn);
+ return;
+ }
+
+ return;
+ }
+
+ if (req->nread < req->response->length) {
+ return;
+ }
+
+ finished:
+ conn->ev.set_fd(conn->ev.lib_private, conn->fd_event, 0, 1);
+ req->err =3D WBC_ERR_SUCCESS;
+ req->completion(req, req->priv);
+}
+
+static void wbcFdCallback(void *event, int readable, int writeable,
+ void *event_private)
+{
+ struct wbcConnection *conn =3D talloc_get_type(
+ event_private, struct wbcConnection);
+ struct wbcRequest *req =3D conn->requests;
+
+ if (conn->fd =3D=3D -1) {
+ /*
+ * We're in connect() state
+ */
+ }
+
+ if (req =3D=3D NULL) {
+ conn->ev.set_fd(conn->ev.lib_private, conn->fd_event, 0, 0);
+ return;
+ }
+
+ if (writeable) {
+ wbcSockWriteable(conn, req);
+ }
+ if (readable) {
+ wbcSockReadable(conn, req);
+ }
+}
+
+static void wbcSockConnectDone(const struct timeval *now, void *event_priv=
ate)
+{
+ struct wbcConnection *conn =3D talloc_get_type(
+ event_private, struct wbcConnection);
+ conn->requests->completion(conn->requests, conn->requests->priv);
+}
+
+static wbcErr wbcSockConnectSend(struct wbcConnection *conn, const char *d=
ir,
+ int timeout,
+ void (*completion)(struct wbcRequest *req,
+ void *priv),
+ void *priv, struct wbcRequest **preq)
+{
+ struct wbcRequest *result;
+ struct stat st;
+ struct sockaddr_un sunaddr;
+ int res;
+ char *path =3D NULL;
+
+ if ((conn->fd !=3D -1) || (conn->fd_event !=3D NULL)) {
+ return WBC_ERR_INVALID_PARAM;
+ }
+
+ result =3D talloc(conn, struct wbcRequest);
+ if (result =3D=3D NULL) {
+ return WBC_ERR_NO_MEMORY;
+ }
+
+ result->conn =3D conn;
+ result->completion =3D completion;
+ result->priv =3D priv;
+ result->data.fd =3D -1;
+
+ DLIST_ADD(conn->requests, result);
+
+ result->data.fd =3D socket(AF_UNIX, SOCK_STREAM, 0);
+ if (result->data.fd =3D=3D -1) {
+ goto fail;
+ }
+
+ result->data.fd =3D wbcMakeSafeFd(result->data.fd);
+ if (result->data.fd =3D=3D -1) {
+ goto fail;
+ }
+
+ conn->fd_event =3D conn->ev.add_fd(
+ conn->ev.lib_private, result->data.fd, wbcFdCallback, conn);
+ if (conn->fd_event =3D=3D NULL) {
+ goto fail;
+ }
+
+ if (asprintf(&path, "%s/%s", dir, WINBINDD_SOCKET_NAME) < 0) {
+ goto fail;
+ }
+
+ /* 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(path, &st) =3D=3D -1) {
+ free(path);
+ goto fail;
+ }
+
+ memset(&sunaddr, 0, sizeof(sunaddr));
+ sunaddr.sun_family =3D AF_UNIX;
+ strncpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path) - 1);
+
+ free(path);
+
+ /* Check permissions on unix socket file */
+
+ if (!S_ISSOCK(st.st_mode) ||
+ (st.st_uid !=3D 0 && st.st_uid !=3D geteuid())) {
+ goto fail;
+ }
+
+ res =3D connect(result->data.fd, (struct sockaddr *)&sunaddr,
+ sizeof(sunaddr));
+
+ if (res =3D=3D 0) {
+ struct timeval null;
+
+ /*
+ * Fire an immediate timed event, we're done
+ */
+
+ memset(&null, 0, sizeof(null));
+ if (conn->ev.add_timed(conn->ev.lib_private, &null,
+ wbcSockConnectDone, conn) =3D=3D NULL) {
+ goto fail;
+ }
+ result->err =3D WBC_ERR_SUCCESS;
+ *preq =3D result;
+ return WBC_ERR_SUCCESS;
+ }
+
+ fail:
+ if (path !=3D NULL) {
+ free(path);
+ }
+ DLIST_REMOVE(conn->requests, result);
+ if (result->data.fd !=3D -1) {
+ close(result->data.fd);
+ result->data.fd =3D -1;
+ }
+ if (conn->fd_event !=3D NULL) {
+ conn->ev.del_fd(conn->ev.lib_private, conn->fd_event);
+ conn->fd_event =3D NULL;
+ }
+ wbcFreeMemory(result);
+ return WBC_ERR_UNKNOWN_FAILURE;
+}
+
+static wbcErr wbcSockConnectRecv(struct wbcRequest *req, int *fd)
+{
+ wbcErr result =3D req->err;
+ if (result =3D=3D WBC_ERR_SUCCESS) {
+ *fd =3D req->data.fd;
+ }
+ DLIST_REMOVE(req->conn->requests, req);
+ wbcFreeMemory(req);
+ return result;
+}
+
+static const char *winbindd_socket_dir(void)
+{
+#ifdef SOCKET_WRAPPER
+ const char *env_dir;
+
+ env_dir =3D getenv(WINBINDD_SOCKET_DIR_ENVVAR);
+ if (env_dir) {
+ return env_dir;
+ }
+#endif
+
+ return WINBINDD_SOCKET_DIR;
+}
+
+struct wbcConnectState {
+ struct wbcConnection *conn;
+ struct wbcRequest *user_request;
+};
+
+static void wbcConnectRequestConnected(struct wbcRequest *req, void *priv);
+static void wbcConnectRequestGotVersion(struct wbcRequest *req, void *priv=
);
+static void wbcConnectRequestGotPrivDir(struct wbcRequest *req, void *priv=
);
+
+static wbcErr wbcConnectRequestSend(struct wbcConnection *conn,
+ struct wbcRequest *user_request,
+ struct wbcRequest **preq)
+{
+ struct wbcConnectState *state;
+
+ state =3D talloc(conn, struct wbcConnectState);
+ if (state =3D=3D NULL) {
+ return WBC_ERR_NO_MEMORY;
+ }
+
+ state->conn =3D conn;
+ state->user_request =3D talloc_move(state, &user_request);
+
+ return wbcSockConnectSend(conn, winbindd_socket_dir(), 30,
+ wbcConnectRequestConnected,
+ state, preq);
+}
+
+static void wbcConnectRequestConnected(struct wbcRequest *req, void *priv)
+{
+ struct wbcConnectState *state =3D talloc_get_type(
+ priv, struct wbcConnectState);
+ struct winbindd_request request;
+ int fd;
+
+ state->user_request->err =3D wbcSockConnectRecv(req, &fd);
+ if (!WBC_ERROR_IS_OK(state->user_request->err)) {
+ state->user_request->completion(state->user_request,
+ state->user_request->priv);
+ return;
+ }
+
+ state->conn->fd =3D fd;
+
+ memset(&request, 0, sizeof(request));
+ request.flags =3D WBFLAG_CONNECTING;
+
+ state->user_request->err =3D wbcRequestSend(
+ state->conn, WINBINDD_INTERFACE_VERSION, &request,
+ wbcConnectRequestGotVersion, state, &req);
+
+ if (!WBC_ERROR_IS_OK(state->user_request->err)) {
+ state->user_request->completion(state->user_request,
+ state->user_request->priv);
+ return;
+ }
+}
+
+static void wbcConnectRequestGotVersion(struct wbcRequest *req, void *priv)
+{
+ struct wbcConnectState *state =3D talloc_get_type(
+ priv, struct wbcConnectState);
+ struct winbindd_request request;
+ struct winbindd_response *response;
+
+ state->user_request->err =3D wbcRequestRecv(req, &response);
+
+ if (!WBC_ERROR_IS_OK(state->user_request->err)) {
+ state->user_request->completion(state->user_request,
+ state->user_request->priv);
+ return;
+ }
+
+ if (response->data.interface_version !=3D WINBIND_INTERFACE_VERSION) {
+ state->user_request->err =3D WBC_ERR_WINBIND_NOT_AVAILABLE;
+ state->user_request->completion(state->user_request,
+ state->user_request->priv);
+ return;
+ }
+
+ wbcFreeMemory(response);
+
+ memset(&request, 0, sizeof(request));
+ request.flags =3D WBFLAG_CONNECTING;
+
+ state->user_request->err =3D wbcRequestSend(
+ state->conn, WINBINDD_PRIV_PIPE_DIR, &request,
+ wbcConnectRequestGotPrivDir, state, &req);
+
+ if (!WBC_ERROR_IS_OK(state->user_request->err)) {
+ state->user_request->completion(state->user_request,
+ state->user_request->priv);
+ return;
+ }
+}
+
+static void wbcConnectRequestGotPrivDir(struct wbcRequest *req, void *priv)
+{
+ struct wbcConnectState *state =3D talloc_get_type(
+ priv, struct wbcConnectState);
+ struct wbcConnection *conn =3D state->conn;
+ struct winbindd_response *response;
+ struct wbcRequest *userRequest;
+
+ state->user_request->err =3D wbcRequestRecv(req, &response);
+
+ if (!WBC_ERROR_IS_OK(state->user_request->err)) {
+ state->user_request->completion(state->user_request,
+ state->user_request->priv);
+ return;
+ }
+
+ conn->private_dir =3D talloc_strdup(state->conn,
+ (char *)response->extra_data.data);
+
+ /*
+ * TODO: Connect to the private dir here
+ */
+
+ /*
+ * Ship the originial request triggering this connect now
+ */
+
+ userRequest =3D talloc_move(NULL, &state->user_request);
+ DLIST_ADD(conn->requests, userRequest);
+ conn->ev.set_fd(conn->ev.lib_private, conn->fd_event, 0, 1);
+ wbcFreeMemory(state);
+}
+
+static wbcErr wbcConnectRecv(struct wbcRequest *req)
+{
+ wbcErr result =3D req->err;
+ wbcFreeMemory(req);
+ return result;
+}
+
+static int wbcRequestDestructor(struct wbcRequest *req)
+{
+ DLIST_REMOVE(req->conn->requests, req);
+ return 0;
+}
+
+wbcErr wbcRequestSend(struct wbcConnection *conn, int cmd,
+ struct winbindd_request *request,
+ void (*completion)(struct wbcRequest *req, void *priv),
+ void *priv, struct wbcRequest **preq)
+{
+ struct wbcRequest *result;
+
+ if ((conn->fd =3D=3D -1) && (request->flags & WBFLAG_CONNECTING)) {
+ return WBC_ERR_WINBIND_NOT_AVAILABLE;
+ }
+
+ result =3D talloc(conn, struct wbcRequest);
+ if (result =3D=3D NULL) {
+ return WBC_ERR_NO_MEMORY;
+ }
+ memset(result, 0, sizeof(result));
+
+ result->response =3D talloc(result, struct winbindd_response);
+ if (result =3D=3D NULL) {
+ talloc_free(result);
+ return WBC_ERR_NO_MEMORY;
+ }
+
+ result->conn =3D conn;
+
+ result->request =3D *request;
+ result->request.length =3D sizeof(result->request);
+ result->request.cmd =3D cmd;
+ result->request.pid =3D getpid();
+
+ result->nwritten =3D 0;
+ result->nread =3D 0;
+
+ result->completion =3D completion;
+ result->priv =3D priv;
+
+ if (conn->fd =3D=3D -1) {
+ return wbcConnectRequestSend(conn, result, preq);
+ }
+
+ DLIST_ADD(conn->requests, result);
+ talloc_set_destructor(result, wbcRequestDestructor);
+
+ conn->ev.set_fd(conn->ev.lib_private, conn->fd_event, -1, 1);
+
+ *preq =3D result;
+ return WBC_ERR_SUCCESS;
+}
+
+wbcErr wbcRequestRecv(struct wbcRequest *req,
+ struct winbindd_response **response)
+{
+ wbcErr result =3D req->err;
+
+ if (WBC_ERROR_IS_OK(req->err)) {
+ *response =3D talloc_move(NULL, &req->response);
+ }
+ talloc_free(req);
+ return result;
+}
+
/** @brief Translate an error value into a string
*
* @param error
diff --git a/source/nsswitch/libwbclient/wbclient.h b/source/nsswitch/libwb=
client/wbclient.h
index 16b68c0..671fafb 100644
--- a/source/nsswitch/libwbclient/wbclient.h
+++ b/source/nsswitch/libwbclient/wbclient.h
@@ -271,6 +271,44 @@ struct wbcAuthErrorInfo {
char *display_string;
};
=20
+struct wbcRequest;
+
+/*
+ * Connection management
+ */
+
+struct wbcEventShim {
+
+ /*
+ * Callbacks from libwbclient into the central event loop, to be
+ * filled in by the caller of libwbclient prior to calling
+ * wbcInitConnection. These will be called from within the wbc
+ * routines, informing the event loop about interest in events.
+ */
+
+ void *(*add_fd)(void *lib_private, int fd,
+ void (*completion)(void *event,
+ int readable, int writeable,
+ void *event_private),
+ void *event_private);
+ void (*set_fd)(void *lib_private, void *event,
+ int want_read, int want_write);
+ void (*del_fd)(void *lib_private, void *event);
+
+ void *(*add_timed)(void *lib_private, const struct timeval *tv,
+ void (*completion)(const struct timeval *now,
+ void *event_private),
+ void *event_private);
+ void (*del_timed)(void *lib_private, void *event);
+
+ void *lib_private;
+};
+
+struct wbcConnection;
+
+wbcErr wbcInitConnection(const struct wbcEventShim *shim,
+ struct wbcConnection **presult);
+
/*
* Memory Management
*/
@@ -288,6 +326,12 @@ wbcErr wbcSidToString(const struct wbcDomainSid *sid,
wbcErr wbcStringToSid(const char *sid_string,
struct wbcDomainSid *sid);
=20
+wbcErr wbcPingSend(struct wbcConnection *conn,
+ void (*completion)(struct wbcRequest *req, void *priv),
+ void *priv, struct wbcRequest **preq);
+
+wbcErr wbcPingRecv(struct wbcRequest *req);
+
wbcErr wbcPing(void);
=20
wbcErr wbcInterfaceDetails(struct wbcInterfaceDetails **details);
@@ -389,6 +433,16 @@ wbcErr wbcDomainInfo(const char *domain,
wbcErr wbcAuthenticateUser(const char *username,
const char *password);
=20
+wbcErr wbcAuthenticateUserExSend(struct wbcConnection *conn,
+ const struct wbcAuthUserParams *params,
+ void (*completion)(struct wbcRequest *req,
+ void *priv),
+ void *priv, struct wbcRequest **preq);
+
+wbcErr wbcAuthenticateUserExRecv(struct wbcRequest *req,
+ struct wbcAuthUserInfo **info,
+ struct wbcAuthErrorInfo **error);
+
wbcErr wbcAuthenticateUserEx(const struct wbcAuthUserParams *params,
struct wbcAuthUserInfo **info,
struct wbcAuthErrorInfo **error);
diff --git a/source/nsswitch/libwbclient/wbclient_internal.h b/source/nsswi=
tch/libwbclient/wbclient_internal.h
index fc03c54..6718430 100644
--- a/source/nsswitch/libwbclient/wbclient_internal.h
+++ b/source/nsswitch/libwbclient/wbclient_internal.h
@@ -22,8 +22,52 @@
#ifndef _WBCLIENT_INTERNAL_H
#define _WBCLIENT_INTERNAL_H
=20
+struct wbcConnection {
+ int fd;
+ pid_t pid; /** After a fork we need to reconnect */
+ char *private_dir;
+
+ struct wbcEventShim ev;
+ void *fd_event;
+
+ struct wbcRequest *requests;
+};
+
+struct wbcRequest {
+ struct wbcRequest *prev, *next;
+
+ struct wbcConnection *conn;
+ void *timed_event;
+
+ size_t nwritten;
+ struct winbindd_request request;
+
+ size_t nread;
+ struct winbindd_response *response;
+
+
+ /** To be called when this request finishes */
+ void (*completion)(struct wbcRequest *req, void *priv);
+ void *priv;
+
+ wbcErr err;
+
+ union {
+ /** Result from wbcSockConnectSend */
+ int fd;
+ } data;
+};
+
/* Private functions */
=20
+wbcErr wbcRequestSend(struct wbcConnection *conn, int cmd,
+ struct winbindd_request *request,
+ void (*completion)(struct wbcRequest *req, void *priv),
+ void *priv, struct wbcRequest **preq);
+
+wbcErr wbcRequestRecv(struct wbcRequest *req,
+ struct winbindd_response **response);
+
wbcErr wbcRequestResponse(int cmd,
struct winbindd_request *request,
struct winbindd_response *response);
diff --git a/source/nsswitch/wbinfo.c b/source/nsswitch/wbinfo.c
index ba358bd..353a63a 100644
--- a/source/nsswitch/wbinfo.c
+++ b/source/nsswitch/wbinfo.c
@@ -1341,6 +1341,198 @@ static bool wbinfo_ping(void)
return WBC_ERROR_IS_OK(wbc_status);
}
=20
+struct wbc_fd_event_state {
+ void (*completion)(void *event, int readable, int writeable,
+ void *event_private);
+ void *event_private;
+};
+
+static void wbc_fd_handler(struct event_context *ev, struct fd_event *fde,
+ uint16_t flags, void *private_data)
+{
+ struct wbc_fd_event_state *state =3D talloc_get_type_abort(
+ private_data, struct wbc_fd_event_state);
+
+ state->completion(fde, (flags & EVENT_FD_READ) ? 1 : 0,
+ (flags & EVENT_FD_WRITE) ? 1 : 0,
+ state->event_private);
+}
+
+static void *wbc_add_fd(void *lib_private, int fd,
+ void (*completion)(void *event, int readable,
+ int writeable, void *event_private),
+ void *event_private)
+{
+ struct event_context *ev =3D talloc_get_type_abort(
+ lib_private, struct event_context);
+ struct fd_event *result;
+ struct wbc_fd_event_state *state;
+
+ DEBUG(10, ("wbc_add_fd called on fd %d\n", fd));
+
+ state =3D talloc(ev, struct wbc_fd_event_state);
+ if (state =3D=3D NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ return NULL;
+ }
+
+ state->completion =3D completion;
+ state->event_private =3D event_private;
+
+ result =3D event_add_fd(ev, ev, fd, 0, wbc_fd_handler, state);
+ if (result =3D=3D NULL) {
+ DEBUG(0, ("event_add_fd failed\n"));
+ TALLOC_FREE(state);
+ return NULL;
+ }
+
+ state =3D talloc_move(ev, &state);
+ return result;
+}
+
+static void wbc_set_fd(void *lib_private, void *event, int want_read,
+ int want_write)
+{
+ struct fd_event *fde =3D talloc_get_type_abort(
+ event, struct fd_event);
+
+ if (want_read =3D=3D 0) {
+ event_fd_set_not_readable(fde);
+ }
+ if (want_read =3D=3D 1) {
+ event_fd_set_readable(fde);
+ }
+ if (want_write =3D=3D 0) {
+ event_fd_set_not_writeable(fde);
+ }
+ if (want_write =3D=3D 1) {
+ event_fd_set_writeable(fde);
+ }
+}
+
+static void wbc_del_fd(void *lib_private, void *event)
+{
+ struct fd_event *fde =3D talloc_get_type_abort(
+ event, struct fd_event);
+
+ TALLOC_FREE(fde);
+}
+
+struct wbc_timed_event_state {
+ void (*completion)(const struct timeval *now, void *event_private);
+ void *event_private;
+};
+
+static void wbc_timed_handler(struct event_context *event_ctx,
+ struct timed_event *te,
+ const struct timeval *now,
+ void *private_data)
+{
+ struct wbc_timed_event_state *state =3D talloc_get_type_abort(
+ private_data, struct wbc_timed_event_state);
+
+ TALLOC_FREE(te);
+ state->completion(now, state->event_private);
+}
+
+static void *wbc_add_timed(void *lib_private, const struct timeval *when,
+ void (*completion)(const struct timeval *now,
+ void *event_private),
+ void *event_private)
+{
+ struct event_context *ev =3D talloc_get_type_abort(
+ lib_private, struct event_context);
+ struct timed_event *result;
+ struct wbc_timed_event_state *state;
+
+ DEBUG(10, ("wbc_add_timed called\n"));
+
+ state =3D talloc(ev, struct wbc_timed_event_state);
+ if (state =3D=3D NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ return NULL;
+ }
+ state->completion =3D completion;
+ state->event_private =3D event_private;
+
+ result =3D event_add_timed(ev, ev, *when, "event_shim",
+ wbc_timed_handler, state);
+ if (result =3D=3D NULL) {
+ DEBUG(0, ("event_add_timed failed\n"));
+ TALLOC_FREE(state);
+ return NULL;
+ }
+
+ state =3D talloc_move(ev, &state);
+ return result;
+}
+
+static void wbc_del_timed(void *lib_private, void *event)
+{
+ struct timed_event *te =3D talloc_get_type_abort(
+ event, struct timed_event);
+
+ TALLOC_FREE(te);
+}
+
+static void ping_done(struct wbcRequest *req, void *priv)
+{
+ bool *done =3D (bool *)priv;
+ *done =3D true;
+ return;
+}
+
+static bool wbinfo_async(void)
+{
+ struct event_context *ev;
+ struct wbcEventShim shim;
+ struct wbcConnection *conn =3D NULL;
+ struct wbcRequest *req;
+ wbcErr wbc_status;
+ bool ping_is_done =3D false;
+
+ ev =3D event_context_init(NULL);
+ if (ev =3D=3D NULL) {
+ d_printf("event_context_init failed\n");
+ return false;
+ }
+
+ shim.add_fd =3D wbc_add_fd;
+ shim.set_fd =3D wbc_set_fd;
+ shim.del_fd =3D wbc_del_fd;
+ shim.add_timed =3D wbc_add_timed;
+ shim.del_timed =3D wbc_del_timed;
+ shim.lib_private =3D ev;
+
+ wbc_status =3D wbcInitConnection(&shim, &conn);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ d_printf("wbcInitConnection failed\n");
+ goto fail;
+ }
+
+ wbc_status =3D wbcPingSend(conn, ping_done, &ping_is_done, &req);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ d_printf("wbcPingSend failed\n");
+ goto fail;
+ }
+
+ while (!ping_is_done) {
+ event_loop_once(ev);
+ }
+
+ wbcFreeMemory(conn);
+ TALLOC_FREE(ev);
+
+ return true;
+
+ fail:
+ if (conn !=3D NULL) {
+ wbcFreeMemory(conn);
+ }
+ TALLOC_FREE(ev);
+ return false;
+}
+
/* Main program */
=20
enum {
@@ -1359,6 +1551,7 @@ enum {
OPT_LIST_OWN_DOMAIN,
OPT_UID_INFO,
OPT_GROUP_INFO,
+ OPT_ASYNC,
OPT_VERBOSE
};
=20
@@ -1394,6 +1587,8 @@ int main(int argc, char **argv, char **envp)
"Get a new UID out of idmap" },
{ "allocate-gid", 0, POPT_ARG_NONE, 0, OPT_ALLOCATE_GID,
"Get a new GID out of idmap" },
+ { "async", 0, POPT_ARG_NONE, 0, OPT_ASYNC,
+ "async fake test" },
{ "check-secret", 't', POPT_ARG_NONE, 0, 't', "Check shared secret" },
{ "trusted-domains", 'm', POPT_ARG_NONE, 0, 'm', "List trusted domains" =
},
{ "all-domains", 0, POPT_ARG_NONE, 0, OPT_LIST_ALL_DOMAINS, "List all do=
mains (trusted and own domain)" },
@@ -1553,6 +1748,12 @@ int main(int argc, char **argv, char **envp)
goto done;
}
break;
+ case OPT_ASYNC:
+ if (!wbinfo_async()) {
+ d_fprintf(stderr, "wbinfo_async failed\n");
+ goto done;
+ }
+ break;
case 't':
if (!wbinfo_check_secret()) {
d_fprintf(stderr, "Could not check secret\n");
diff --git a/source/nsswitch/winbind_struct_protocol.h b/source/nsswitch/wi=
nbind_struct_protocol.h
index e81813c..567b780 100644
--- a/source/nsswitch/winbind_struct_protocol.h
+++ b/source/nsswitch/winbind_struct_protocol.h
@@ -203,6 +203,9 @@ typedef struct winbindd_gr {
/* Flag to say this is a winbindd internal send - don't recurse. */
#define WBFLAG_RECURSE 0x00000800
=20
+/* Same meaning as _RECURSE with a (IMO) slightly better name */
+#define WBFLAG_CONNECTING 0x00000800
+
=20
#define WINBINDD_MAX_EXTRA_DATA (128*1024)
=20
--=20
1.5.3.7


--nFreZHaLTZJo0R7j--

--8GpibOaaTibBMecb
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.5 (GNU/Linux)

iD8DBQFH+oz7UzqjrWwMRl0RAkjfAJ9+EjHXKuVlTM1quxJQrj Pnn8J7HQCghxOn
2HkGLbpLIeY4RN6DFjTR44Y=
=zcsd
-----END PGP SIGNATURE-----

--8GpibOaaTibBMecb--