Merge branch 'master' of ssh://git.samba.org/data/git/samba
authorAndrew Tridgell <tridge@samba.org>
Thu, 19 Mar 2009 23:01:17 +0000 (10:01 +1100)
committerAndrew Tridgell <tridge@samba.org>
Thu, 19 Mar 2009 23:01:17 +0000 (10:01 +1100)
43 files changed:
docs-xml/manpages-3/idmap_hash.8.xml
lib/tevent/tevent.c
lib/tsocket/config.mk [new file with mode: 0644]
lib/tsocket/tsocket.c [new file with mode: 0644]
lib/tsocket/tsocket.h [new file with mode: 0644]
lib/tsocket/tsocket_bsd.c [new file with mode: 0644]
lib/tsocket/tsocket_connect.c [new file with mode: 0644]
lib/tsocket/tsocket_guide.txt [new file with mode: 0644]
lib/tsocket/tsocket_helpers.c [new file with mode: 0644]
lib/tsocket/tsocket_internal.h [new file with mode: 0644]
lib/tsocket/tsocket_readv.c [new file with mode: 0644]
lib/tsocket/tsocket_recvfrom.c [new file with mode: 0644]
lib/tsocket/tsocket_sendto.c [new file with mode: 0644]
lib/tsocket/tsocket_writev.c [new file with mode: 0644]
lib/util/config.mk
libcli/cldap/cldap.c [new file with mode: 0644]
libcli/cldap/cldap.h [new file with mode: 0644]
libcli/cldap/config.mk [new file with mode: 0644]
source3/Makefile.in
source3/lib/util_sock.c
source3/lib/version_test.c [new file with mode: 0644]
source3/lib/winbind_util.c
source3/libads/cldap.c
source3/libads/krb5_errs.c
source3/libsmb/clidfs.c
source3/libsmb/clitrans.c
source3/script/mkversion.sh
source3/smbd/reply.c
source3/torture/torture.c
source4/cldap_server/cldap_server.c
source4/cldap_server/netlogon.c
source4/cldap_server/rootdse.c
source4/headermap.txt
source4/libcli/cldap/cldap.c [deleted file]
source4/libcli/cldap/cldap.h [deleted file]
source4/libcli/config.mk
source4/libnet/libnet_become_dc.c
source4/libnet/libnet_site.c
source4/libnet/libnet_unbecome_dc.c
source4/main.mk
source4/torture/ldap/cldap.c
source4/torture/ldap/cldapbench.c
source4/torture/rpc/dssync.c

index fbafd71627ff3fead2cf63b243e6678235537c48..dfaece24d608354f393d3e8ae73ef60a3f635f14 100644 (file)
 
 <refsynopsisdiv>
        <title>DESCRIPTION</title>
-       <para>The idmap_hash plugin implements a hashing algorithm used
-         map SIDs for domain users and groups to a 31-bit uid and gid.
+       <para>The idmap_hash plugin implements a hashing algorithm used to map
+         SIDs for domain users and groups to 31-bit uids and gids, respectively.
          This plugin also implements the nss_info API and can be used
          to support a local name mapping files if enabled via the
-         &quot;winbind normlaize names&quot; and &quot;winbind nss info&quot;
+         &quot;winbind normalize names&quot; and &quot;winbind nss info&quot;
          parameters in smb.conf.
        </para>
 </refsynopsisdiv>
index 56fd6aec7aa54d2957f8bdcaf7e9e80a80655023..0c02e46f3ca16e6478fe820ae459d5272e4dfcbc 100644 (file)
@@ -468,6 +468,8 @@ int _tevent_loop_once(struct tevent_context *ev, const char *location)
                        errno = ELOOP;
                        return -1;
                }
+       }
+       if (ev->nesting.level > 0) {
                if (ev->nesting.hook_fn) {
                        int ret2;
                        ret2 = ev->nesting.hook_fn(ev,
@@ -485,7 +487,7 @@ int _tevent_loop_once(struct tevent_context *ev, const char *location)
 
        ret = ev->ops->loop_once(ev, location);
 
-       if (ev->nesting.level > 1) {
+       if (ev->nesting.level > 0) {
                if (ev->nesting.hook_fn) {
                        int ret2;
                        ret2 = ev->nesting.hook_fn(ev,
@@ -525,6 +527,8 @@ int _tevent_loop_until(struct tevent_context *ev,
                        errno = ELOOP;
                        return -1;
                }
+       }
+       if (ev->nesting.level > 0) {
                if (ev->nesting.hook_fn) {
                        int ret2;
                        ret2 = ev->nesting.hook_fn(ev,
@@ -547,7 +551,7 @@ int _tevent_loop_until(struct tevent_context *ev,
                }
        }
 
-       if (ev->nesting.level > 1) {
+       if (ev->nesting.level > 0) {
                if (ev->nesting.hook_fn) {
                        int ret2;
                        ret2 = ev->nesting.hook_fn(ev,
@@ -601,9 +605,5 @@ int tevent_common_loop_wait(struct tevent_context *ev,
 */
 int _tevent_loop_wait(struct tevent_context *ev, const char *location)
 {
-       int ret;
-       ev->nesting.level++;
-       ret = ev->ops->loop_wait(ev, location);
-       ev->nesting.level--;
-       return ret;
+       return ev->ops->loop_wait(ev, location);
 }
diff --git a/lib/tsocket/config.mk b/lib/tsocket/config.mk
new file mode 100644 (file)
index 0000000..c35f0af
--- /dev/null
@@ -0,0 +1,17 @@
+[SUBSYSTEM::LIBTSOCKET]
+PRIVATE_DEPENDENCIES = LIBTALLOC LIBTEVENT LIBREPLACE_NETWORK
+
+LIBTSOCKET_OBJ_FILES = $(addprefix ../lib/tsocket/, \
+                                       tsocket.o \
+                                       tsocket_helpers.o \
+                                       tsocket_bsd.o \
+                                       tsocket_recvfrom.o \
+                                       tsocket_sendto.o \
+                                       tsocket_connect.o \
+                                       tsocket_writev.o \
+                                       tsocket_readv.o)
+
+PUBLIC_HEADERS += $(addprefix ../lib/tsocket/, \
+                                tsocket.h\
+                                tsocket_internal.h)
+
diff --git a/lib/tsocket/tsocket.c b/lib/tsocket/tsocket.c
new file mode 100644 (file)
index 0000000..1a12e69
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Copyright (C) Stefan Metzmacher 2009
+
+     ** NOTE! The following LGPL license applies to the tevent
+     ** 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/network.h"
+#include "tsocket.h"
+#include "tsocket_internal.h"
+
+static int tsocket_context_destructor(struct tsocket_context *sock)
+{
+       tsocket_disconnect(sock);
+       return 0;
+}
+
+struct tsocket_context *_tsocket_context_create(TALLOC_CTX *mem_ctx,
+                                               const struct tsocket_context_ops *ops,
+                                               void *pstate,
+                                               size_t psize,
+                                               const char *type,
+                                               const char *location)
+{
+       void **ppstate = (void **)pstate;
+       struct tsocket_context *sock;
+
+       sock = talloc_zero(mem_ctx, struct tsocket_context);
+       if (!sock) {
+               return NULL;
+       }
+       sock->ops = ops;
+       sock->location = location;
+       sock->private_data = talloc_size(sock, psize);
+       if (!sock->private_data) {
+               talloc_free(sock);
+               return NULL;
+       }
+       talloc_set_name_const(sock->private_data, type);
+
+       talloc_set_destructor(sock, tsocket_context_destructor);
+
+       *ppstate = sock->private_data;
+       return sock;
+}
+
+int tsocket_set_event_context(struct tsocket_context *sock,
+                             struct tevent_context *ev)
+{
+       return sock->ops->set_event_context(sock, ev);
+}
+
+int tsocket_set_readable_handler(struct tsocket_context *sock,
+                                tsocket_event_handler_t handler,
+                                void *private_data)
+{
+       return sock->ops->set_read_handler(sock, handler, private_data);
+}
+
+int tsocket_set_writeable_handler(struct tsocket_context *sock,
+                                 tsocket_event_handler_t handler,
+                                 void *private_data)
+{
+       return sock->ops->set_write_handler(sock, handler, private_data);
+}
+
+int tsocket_connect(struct tsocket_context *sock,
+                   const struct tsocket_address *remote_addr)
+{
+       return sock->ops->connect_to(sock, remote_addr);
+}
+
+int tsocket_listen(struct tsocket_context *sock,
+                  int queue_size)
+{
+       return sock->ops->listen_on(sock, queue_size);
+}
+
+int _tsocket_accept(struct tsocket_context *sock,
+                   TALLOC_CTX *mem_ctx,
+                   struct tsocket_context **new_sock,
+                   const char *location)
+{
+       return sock->ops->accept_new(sock, mem_ctx, new_sock, location);
+}
+
+ssize_t tsocket_pending(struct tsocket_context *sock)
+{
+       return sock->ops->pending_data(sock);
+}
+
+int tsocket_readv(struct tsocket_context *sock,
+                 const struct iovec *vector, size_t count)
+{
+       return sock->ops->readv_data(sock, vector, count);
+}
+
+int tsocket_writev(struct tsocket_context *sock,
+                  const struct iovec *vector, size_t count)
+{
+       return sock->ops->writev_data(sock, vector, count);
+}
+
+ssize_t tsocket_recvfrom(struct tsocket_context *sock,
+                        uint8_t *data, size_t len,
+                        TALLOC_CTX *addr_ctx,
+                        struct tsocket_address **src_addr)
+{
+       return sock->ops->recvfrom_data(sock, data, len, addr_ctx, src_addr);
+}
+
+ssize_t tsocket_sendto(struct tsocket_context *sock,
+                      const uint8_t *data, size_t len,
+                      const struct tsocket_address *dest_addr)
+{
+       return sock->ops->sendto_data(sock, data, len, dest_addr);
+}
+
+int tsocket_get_status(const struct tsocket_context *sock)
+{
+       return sock->ops->get_status(sock);
+}
+
+int _tsocket_get_local_address(const struct tsocket_context *sock,
+                              TALLOC_CTX *mem_ctx,
+                              struct tsocket_address **local_addr,
+                              const char *location)
+{
+       return sock->ops->get_local_address(sock, mem_ctx,
+                                           local_addr, location);
+}
+
+int _tsocket_get_remote_address(const struct tsocket_context *sock,
+                               TALLOC_CTX *mem_ctx,
+                               struct tsocket_address **remote_addr,
+                               const char *location)
+{
+       return sock->ops->get_remote_address(sock, mem_ctx,
+                                            remote_addr, location);
+}
+
+int tsocket_get_option(const struct tsocket_context *sock,
+                      const char *option,
+                      TALLOC_CTX *mem_ctx,
+                      char **value)
+{
+       return sock->ops->get_option(sock, option, mem_ctx, value);
+}
+
+int tsocket_set_option(const struct tsocket_context *sock,
+                      const char *option,
+                      bool force,
+                      const char *value)
+{
+       return sock->ops->set_option(sock, option, force, value);
+}
+
+void tsocket_disconnect(struct tsocket_context *sock)
+{
+       sock->ops->disconnect(sock);
+}
+
+struct tsocket_address *_tsocket_address_create(TALLOC_CTX *mem_ctx,
+                                               const struct tsocket_address_ops *ops,
+                                               void *pstate,
+                                               size_t psize,
+                                               const char *type,
+                                               const char *location)
+{
+       void **ppstate = (void **)pstate;
+       struct tsocket_address *addr;
+
+       addr = talloc_zero(mem_ctx, struct tsocket_address);
+       if (!addr) {
+               return NULL;
+       }
+       addr->ops = ops;
+       addr->location = location;
+       addr->private_data = talloc_size(addr, psize);
+       if (!addr->private_data) {
+               talloc_free(addr);
+               return NULL;
+       }
+       talloc_set_name_const(addr->private_data, type);
+
+       *ppstate = addr->private_data;
+       return addr;
+}
+
+char *tsocket_address_string(const struct tsocket_address *addr,
+                            TALLOC_CTX *mem_ctx)
+{
+       if (!addr) {
+               return talloc_strdup(mem_ctx, "NULL");
+       }
+       return addr->ops->string(addr, mem_ctx);
+}
+
+struct tsocket_address *_tsocket_address_copy(const struct tsocket_address *addr,
+                                             TALLOC_CTX *mem_ctx,
+                                             const char *location)
+{
+       return addr->ops->copy(addr, mem_ctx, location);
+}
+
+int _tsocket_address_create_socket(const struct tsocket_address *addr,
+                                  enum tsocket_type type,
+                                  TALLOC_CTX *mem_ctx,
+                                  struct tsocket_context **sock,
+                                  const char *location)
+{
+       return addr->ops->create_socket(addr, type, mem_ctx, sock, location);
+}
+
diff --git a/lib/tsocket/tsocket.h b/lib/tsocket/tsocket.h
new file mode 100644 (file)
index 0000000..9bcfb5c
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Copyright (C) Stefan Metzmacher 2009
+
+     ** NOTE! The following LGPL license applies to the tevent
+     ** 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _TSOCKET_H
+#define _TSOCKET_H
+
+#include <talloc.h>
+#include <tevent.h>
+
+struct tsocket_context;
+struct tsocket_address;
+struct iovec;
+
+enum tsocket_type {
+       TSOCKET_TYPE_STREAM = 1,
+       TSOCKET_TYPE_DGRAM,
+       TSOCKET_TYPE_MESSAGE
+};
+
+typedef void (*tsocket_event_handler_t)(struct tsocket_context *, void *);
+int tsocket_set_event_context(struct tsocket_context *sock,
+                             struct tevent_context *ev);
+int tsocket_set_readable_handler(struct tsocket_context *sock,
+                                tsocket_event_handler_t handler,
+                                void *private_data);
+int tsocket_set_writeable_handler(struct tsocket_context *sock,
+                                 tsocket_event_handler_t handler,
+                                 void *private_data);
+
+int tsocket_connect(struct tsocket_context *sock,
+                   const struct tsocket_address *remote_addr);
+
+int tsocket_listen(struct tsocket_context *sock,
+                  int queue_size);
+
+int _tsocket_accept(struct tsocket_context *sock,
+                   TALLOC_CTX *mem_ctx,
+                   struct tsocket_context **new_sock,
+                   const char *location);
+#define tsocket_accept(sock, mem_ctx, new_sock) \
+       _tsocket_accept(sock, mem_ctx, new_sock, __location__)
+
+ssize_t tsocket_pending(struct tsocket_context *sock);
+
+int tsocket_readv(struct tsocket_context *sock,
+                 const struct iovec *vector, size_t count);
+int tsocket_writev(struct tsocket_context *sock,
+                  const struct iovec *vector, size_t count);
+
+ssize_t tsocket_recvfrom(struct tsocket_context *sock,
+                        uint8_t *data, size_t len,
+                        TALLOC_CTX *addr_ctx,
+                        struct tsocket_address **src_addr);
+ssize_t tsocket_sendto(struct tsocket_context *sock,
+                      const uint8_t *data, size_t len,
+                      const struct tsocket_address *dest_addr);
+
+int tsocket_get_status(const struct tsocket_context *sock);
+
+int _tsocket_get_local_address(const struct tsocket_context *sock,
+                              TALLOC_CTX *mem_ctx,
+                              struct tsocket_address **local_addr,
+                              const char *location);
+#define tsocket_get_local_address(sock, mem_ctx, local_addr) \
+       _tsocket_get_local_address(sock, mem_ctx, local_addr, __location__)
+int _tsocket_get_remote_address(const struct tsocket_context *sock,
+                               TALLOC_CTX *mem_ctx,
+                               struct tsocket_address **remote_addr,
+                               const char *location);
+#define tsocket_get_remote_address(sock, mem_ctx, remote_addr) \
+       _tsocket_get_remote_address(sock, mem_ctx, remote_addr, __location__)
+
+int tsocket_get_option(const struct tsocket_context *sock,
+                      const char *option,
+                      TALLOC_CTX *mem_ctx,
+                      char **value);
+int tsocket_set_option(const struct tsocket_context *sock,
+                      const char *option,
+                      bool force,
+                      const char *value);
+
+void tsocket_disconnect(struct tsocket_context *sock);
+
+char *tsocket_address_string(const struct tsocket_address *addr,
+                            TALLOC_CTX *mem_ctx);
+
+struct tsocket_address *_tsocket_address_copy(const struct tsocket_address *addr,
+                                             TALLOC_CTX *mem_ctx,
+                                             const char *location);
+
+#define tsocket_address_copy(addr, mem_ctx) \
+       _tsocket_address_copy(addr, mem_ctx, __location__)
+
+int _tsocket_address_create_socket(const struct tsocket_address *addr,
+                                  enum tsocket_type type,
+                                  TALLOC_CTX *mem_ctx,
+                                  struct tsocket_context **sock,
+                                  const char *location);
+#define tsocket_address_create_socket(addr, type, mem_ctx, sock) \
+       _tsocket_address_create_socket(addr, type, mem_ctx, sock,\
+                                      __location__)
+
+/*
+ * BSD sockets: inet, inet6 and unix
+ */
+
+int _tsocket_address_inet_from_strings(TALLOC_CTX *mem_ctx,
+                                      const char *fam,
+                                      const char *addr,
+                                      uint16_t port,
+                                      struct tsocket_address **_addr,
+                                      const char *location);
+#define tsocket_address_inet_from_strings(mem_ctx, fam, addr, port, _addr) \
+       _tsocket_address_inet_from_strings(mem_ctx, fam, addr, port, _addr, \
+                                          __location__)
+
+char *tsocket_address_inet_addr_string(const struct tsocket_address *addr,
+                                      TALLOC_CTX *mem_ctx);
+uint16_t tsocket_address_inet_port(const struct tsocket_address *addr);
+int tsocket_address_inet_set_port(struct tsocket_address *addr,
+                                 uint16_t port);
+void tsocket_address_inet_set_broadcast(struct tsocket_address *addr,
+                                       bool broadcast);
+
+int _tsocket_address_unix_from_path(TALLOC_CTX *mem_ctx,
+                                   const char *path,
+                                   struct tsocket_address **_addr,
+                                   const char *location);
+#define tsocket_address_unix_from_path(mem_ctx, path, _addr) \
+       _tsocket_address_unix_from_path(mem_ctx, path, _addr, \
+                                       __location__)
+char *tsocket_address_unix_path(const struct tsocket_address *addr,
+                               TALLOC_CTX *mem_ctx);
+
+int _tsocket_context_bsd_wrap_existing(TALLOC_CTX *mem_ctx,
+                                      int fd, bool close_on_disconnect,
+                                      struct tsocket_context **_sock,
+                                      const char *location);
+#define tsocket_context_bsd_wrap_existing(mem_ctx, fd, cod, _sock) \
+       _tsocket_context_bsd_wrap_existing(mem_ctx, fd, cod, _sock, \
+                                          __location__)
+
+/*
+ * Async helpers
+ */
+
+struct tevent_req *tsocket_recvfrom_send(struct tsocket_context *sock,
+                                        TALLOC_CTX *mem_ctx);
+ssize_t tsocket_recvfrom_recv(struct tevent_req *req,
+                             int *perrno,
+                             TALLOC_CTX *mem_ctx,
+                             uint8_t **buf,
+                             struct tsocket_address **src);
+
+struct tevent_req *tsocket_sendto_send(struct tsocket_context *sock,
+                                      TALLOC_CTX *mem_ctx,
+                                      const uint8_t *buf,
+                                      size_t len,
+                                      const struct tsocket_address *dst);
+ssize_t tsocket_sendto_recv(struct tevent_req *req, int *perrno);
+
+struct tevent_req *tsocket_sendto_queue_send(TALLOC_CTX *mem_ctx,
+                                            struct tsocket_context *sock,
+                                            struct tevent_queue *queue,
+                                            const uint8_t *buf,
+                                            size_t len,
+                                            struct tsocket_address *dst);
+ssize_t tsocket_sendto_queue_recv(struct tevent_req *req, int *perrno);
+
+struct tevent_req *tsocket_connect_send(struct tsocket_context *sock,
+                                       TALLOC_CTX *mem_ctx,
+                                       const struct tsocket_address *dst);
+int tsocket_connect_recv(struct tevent_req *req, int *perrno);
+
+struct tevent_req *tsocket_writev_send(struct tsocket_context *sock,
+                                      TALLOC_CTX *mem_ctx,
+                                      const struct iovec *vector,
+                                      size_t count);
+int tsocket_writev_recv(struct tevent_req *req, int *perrno);
+
+struct tevent_req *tsocket_writev_queue_send(TALLOC_CTX *mem_ctx,
+                                            struct tsocket_context *sock,
+                                            struct tevent_queue *queue,
+                                            const struct iovec *vector,
+                                            size_t count);
+int tsocket_writev_queue_recv(struct tevent_req *req, int *perrno);
+
+typedef int (*tsocket_readv_next_iovec_t)(struct tsocket_context *sock,
+                                         void *private_data,
+                                         TALLOC_CTX *mem_ctx,
+                                         struct iovec **vector,
+                                         size_t *count);
+struct tevent_req *tsocket_readv_send(struct tsocket_context *sock,
+                                     TALLOC_CTX *mem_ctx,
+                                     tsocket_readv_next_iovec_t next_iovec_fn,
+                                     void *private_data);
+int tsocket_readv_recv(struct tevent_req *req, int *perrno);
+
+#endif /* _TSOCKET_H */
+
diff --git a/lib/tsocket/tsocket_bsd.c b/lib/tsocket/tsocket_bsd.c
new file mode 100644 (file)
index 0000000..2811882
--- /dev/null
@@ -0,0 +1,1126 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Copyright (C) Stefan Metzmacher 2009
+
+     ** NOTE! The following LGPL license applies to the tevent
+     ** 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/network.h"
+#include "tsocket.h"
+#include "tsocket_internal.h"
+
+static const struct tsocket_context_ops tsocket_context_bsd_ops;
+static const struct tsocket_address_ops tsocket_address_bsd_ops;
+
+static int tsocket_context_bsd_set_option(const struct tsocket_context *sock,
+                                         const char *option,
+                                         bool force,
+                                         const char *value);
+
+struct tsocket_context_bsd {
+       bool close_on_disconnect;
+       int fd;
+       struct tevent_fd *fde;
+};
+
+struct tsocket_address_bsd {
+       bool broadcast;
+       union {
+               struct sockaddr sa;
+               struct sockaddr_in sin;
+#ifdef HAVE_IPV6
+               struct sockaddr_in6 sin6;
+#endif
+               struct sockaddr_un sun;
+               struct sockaddr_storage ss;
+       } u;
+};
+
+static int _tsocket_address_bsd_from_sockaddr(TALLOC_CTX *mem_ctx,
+                                             struct sockaddr *sa,
+                                             socklen_t sa_len,
+                                             struct tsocket_address **_addr,
+                                             const char *location)
+{
+       struct tsocket_address *addr;
+       struct tsocket_address_bsd *bsda;
+
+       switch (sa->sa_family) {
+       case AF_UNIX:
+               if (sa_len < sizeof(struct sockaddr_un)) {
+                       errno = EINVAL;
+                       return -1;
+               }
+               break;
+       case AF_INET:
+               if (sa_len < sizeof(struct sockaddr_in)) {
+                       errno = EINVAL;
+                       return -1;
+               }
+               break;
+#ifdef HAVE_IPV6
+       case AF_INET6:
+               if (sa_len < sizeof(struct sockaddr_in6)) {
+                       errno = EINVAL;
+                       return -1;
+               }
+               break;
+#endif
+       default:
+               errno = EAFNOSUPPORT;
+               return -1;
+       }
+
+       if (sa_len > sizeof(struct sockaddr_storage)) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       addr = tsocket_address_create(mem_ctx,
+                                     &tsocket_address_bsd_ops,
+                                     &bsda,
+                                     struct tsocket_address_bsd,
+                                     location);
+       if (!addr) {
+               errno = ENOMEM;
+               return -1;
+       }
+
+       ZERO_STRUCTP(bsda);
+
+       memcpy(&bsda->u.ss, sa, sa_len);
+
+       *_addr = addr;
+       return 0;
+}
+
+int _tsocket_address_inet_from_strings(TALLOC_CTX *mem_ctx,
+                                      const char *fam,
+                                      const char *addr,
+                                      uint16_t port,
+                                      struct tsocket_address **_addr,
+                                      const char *location)
+{
+       struct addrinfo hints;
+       struct addrinfo *result = NULL;
+       char port_str[6];
+       int ret;
+
+       ZERO_STRUCT(hints);
+       /*
+        * we use SOCKET_STREAM here to get just one result
+        * back from getaddrinfo().
+        */
+       hints.ai_socktype = SOCK_STREAM;
+       hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
+
+       if (strcasecmp(fam, "ip") == 0) {
+               hints.ai_family = AF_UNSPEC;
+               if (!addr) {
+#ifdef HAVE_IPV6
+                       addr = "::";
+#else
+                       addr = "0.0.0.0";
+#endif
+               }
+       } else if (strcasecmp(fam, "ipv4") == 0) {
+               hints.ai_family = AF_INET;
+               if (!addr) {
+                       addr = "0.0.0.0";
+               }
+#ifdef HAVE_IPV6
+       } else if (strcasecmp(fam, "ipv6") == 0) {
+               hints.ai_family = AF_INET6;
+               if (!addr) {
+                       addr = "::";
+               }
+#endif
+       } else {
+               errno = EAFNOSUPPORT;
+               return -1;
+       }
+
+       snprintf(port_str, sizeof(port_str) - 1, "%u", port);
+
+       ret = getaddrinfo(addr, port_str, &hints, &result);
+       if (ret != 0) {
+               switch (ret) {
+               case EAI_FAIL:
+                       errno = EINVAL;
+                       break;
+               }
+               ret = -1;
+               goto done;
+       }
+
+       if (result->ai_socktype != SOCK_STREAM) {
+               errno = EINVAL;
+               ret = -1;
+               goto done;
+       }
+
+       ret = _tsocket_address_bsd_from_sockaddr(mem_ctx,
+                                                 result->ai_addr,
+                                                 result->ai_addrlen,
+                                                 _addr,
+                                                 location);
+
+done:
+       if (result) {
+               freeaddrinfo(result);
+       }
+       return ret;
+}
+
+char *tsocket_address_inet_addr_string(const struct tsocket_address *addr,
+                                      TALLOC_CTX *mem_ctx)
+{
+       struct tsocket_address_bsd *bsda = talloc_get_type(addr->private_data,
+                                          struct tsocket_address_bsd);
+       char addr_str[INET6_ADDRSTRLEN+1];
+       const char *str;
+
+       if (!bsda) {
+               errno = EINVAL;
+               return NULL;
+       }
+
+       switch (bsda->u.sa.sa_family) {
+       case AF_INET:
+               str = inet_ntop(bsda->u.sin.sin_family,
+                               &bsda->u.sin.sin_addr,
+                               addr_str, sizeof(addr_str));
+               break;
+#ifdef HAVE_IPV6
+       case AF_INET6:
+               str = inet_ntop(bsda->u.sin6.sin6_family,
+                               &bsda->u.sin6.sin6_addr,
+                               addr_str, sizeof(addr_str));
+               break;
+#endif
+       default:
+               errno = EINVAL;
+               return NULL;
+       }
+
+       if (!str) {
+               return NULL;
+       }
+
+       return talloc_strdup(mem_ctx, str);
+}
+
+uint16_t tsocket_address_inet_port(const struct tsocket_address *addr)
+{
+       struct tsocket_address_bsd *bsda = talloc_get_type(addr->private_data,
+                                          struct tsocket_address_bsd);
+       uint16_t port = 0;
+
+       if (!bsda) {
+               errno = EINVAL;
+               return 0;
+       }
+
+       switch (bsda->u.sa.sa_family) {
+       case AF_INET:
+               port = ntohs(bsda->u.sin.sin_port);
+               break;
+#ifdef HAVE_IPV6
+       case AF_INET6:
+               port = ntohs(bsda->u.sin6.sin6_port);
+               break;
+#endif
+       default:
+               errno = EINVAL;
+               return 0;
+       }
+
+       return port;
+}
+
+int tsocket_address_inet_set_port(struct tsocket_address *addr,
+                                 uint16_t port)
+{
+       struct tsocket_address_bsd *bsda = talloc_get_type(addr->private_data,
+                                          struct tsocket_address_bsd);
+
+       if (!bsda) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       switch (bsda->u.sa.sa_family) {
+       case AF_INET:
+               bsda->u.sin.sin_port = htons(port);
+               break;
+#ifdef HAVE_IPV6
+       case AF_INET6:
+               bsda->u.sin6.sin6_port = htons(port);
+               break;
+#endif
+       default:
+               errno = EINVAL;
+               return -1;
+       }
+
+       return 0;
+}
+
+void tsocket_address_inet_set_broadcast(struct tsocket_address *addr,
+                                       bool broadcast)
+{
+       struct tsocket_address_bsd *bsda = talloc_get_type(addr->private_data,
+                                          struct tsocket_address_bsd);
+
+       if (!bsda) {
+               return;
+       }
+
+       bsda->broadcast = broadcast;
+}
+
+int _tsocket_address_unix_from_path(TALLOC_CTX *mem_ctx,
+                                   const char *path,
+                                   struct tsocket_address **_addr,
+                                   const char *location)
+{
+       struct sockaddr_un sun;
+       void *p = &sun;
+       int ret;
+
+       if (!path) {
+               path = "";
+       }
+
+       ZERO_STRUCT(sun);
+       sun.sun_family = AF_UNIX;
+       strncpy(sun.sun_path, path, sizeof(sun.sun_path));
+
+       ret = _tsocket_address_bsd_from_sockaddr(mem_ctx,
+                                                (struct sockaddr *)p,
+                                                sizeof(sun),
+                                                _addr,
+                                                location);
+
+       return ret;
+}
+
+char *tsocket_address_unix_path(const struct tsocket_address *addr,
+                               TALLOC_CTX *mem_ctx)
+{
+       struct tsocket_address_bsd *bsda = talloc_get_type(addr->private_data,
+                                          struct tsocket_address_bsd);
+       const char *str;
+
+       if (!bsda) {
+               errno = EINVAL;
+               return NULL;
+       }
+
+       switch (bsda->u.sa.sa_family) {
+       case AF_UNIX:
+               str = bsda->u.sun.sun_path;
+               break;
+       default:
+               errno = EINVAL;
+               return NULL;
+       }
+
+       return talloc_strdup(mem_ctx, str);
+}
+
+static char *tsocket_address_bsd_string(const struct tsocket_address *addr,
+                                       TALLOC_CTX *mem_ctx)
+{
+       struct tsocket_address_bsd *bsda = talloc_get_type(addr->private_data,
+                                          struct tsocket_address_bsd);
+       char *str;
+       char *addr_str;
+       const char *prefix = NULL;
+       uint16_t port;
+
+       switch (bsda->u.sa.sa_family) {
+       case AF_UNIX:
+               return talloc_asprintf(mem_ctx, "unix:%s",
+                                      bsda->u.sun.sun_path);
+       case AF_INET:
+               prefix = "ipv4";
+               break;
+       case AF_INET6:
+               prefix = "ipv6";
+               break;
+       default:
+               errno = EINVAL;
+               return NULL;
+       }
+
+       addr_str = tsocket_address_inet_addr_string(addr, mem_ctx);
+       if (!addr_str) {
+               return NULL;
+       }
+
+       port = tsocket_address_inet_port(addr);
+
+       str = talloc_asprintf(mem_ctx, "%s:%s:%u",
+                             prefix, addr_str, port);
+       talloc_free(addr_str);
+
+       return str;
+}
+
+static struct tsocket_address *tsocket_address_bsd_copy(const struct tsocket_address *addr,
+                                                        TALLOC_CTX *mem_ctx,
+                                                        const char *location)
+{
+       struct tsocket_address_bsd *bsda = talloc_get_type(addr->private_data,
+                                          struct tsocket_address_bsd);
+       struct tsocket_address *copy;
+       int ret;
+
+       ret = _tsocket_address_bsd_from_sockaddr(mem_ctx,
+                                                &bsda->u.sa,
+                                                sizeof(bsda->u.ss),
+                                                &copy,
+                                                location);
+       if (ret != 0) {
+               return NULL;
+       }
+
+       tsocket_address_inet_set_broadcast(copy, bsda->broadcast);
+       return copy;
+}
+
+int _tsocket_context_bsd_wrap_existing(TALLOC_CTX *mem_ctx,
+                                      int fd, bool close_on_disconnect,
+                                      struct tsocket_context **_sock,
+                                      const char *location)
+{
+       struct tsocket_context *sock;
+       struct tsocket_context_bsd *bsds;
+
+       sock = tsocket_context_create(mem_ctx,
+                                     &tsocket_context_bsd_ops,
+                                     &bsds,
+                                     struct tsocket_context_bsd,
+                                     location);
+       if (!sock) {
+               return -1;
+       }
+
+       bsds->close_on_disconnect       = close_on_disconnect;
+       bsds->fd                        = fd;
+       bsds->fde                       = NULL;
+
+       *_sock = sock;
+       return 0;
+}
+
+static int tsocket_address_bsd_create_socket(const struct tsocket_address *addr,
+                                            enum tsocket_type type,
+                                            TALLOC_CTX *mem_ctx,
+                                            struct tsocket_context **_sock,
+                                            const char *location)
+{
+       struct tsocket_address_bsd *bsda = talloc_get_type(addr->private_data,
+                                          struct tsocket_address_bsd);
+       struct tsocket_context *sock;
+       int bsd_type;
+       int fd;
+       int ret;
+       bool do_bind = false;
+       bool do_reuseaddr = false;
+
+       switch (type) {
+       case TSOCKET_TYPE_STREAM:
+               if (bsda->broadcast) {
+                       errno = EINVAL;
+                       return -1;
+               }
+               bsd_type = SOCK_STREAM;
+               break;
+       case TSOCKET_TYPE_DGRAM:
+               bsd_type = SOCK_DGRAM;
+               break;
+       default:
+               errno = EPROTONOSUPPORT;
+               return -1;
+       }
+
+       switch (bsda->u.sa.sa_family) {
+       case AF_UNIX:
+               if (bsda->broadcast) {
+                       errno = EINVAL;
+                       return -1;
+               }
+               if (bsda->u.sun.sun_path[0] != 0) {
+                       do_bind = true;
+               }
+               break;
+       case AF_INET:
+               if (bsda->u.sin.sin_port != 0) {
+                       do_reuseaddr = true;
+                       do_bind = true;
+               }
+               if (bsda->u.sin.sin_addr.s_addr == INADDR_ANY) {
+                       do_bind = true;
+               }
+               break;
+#ifdef HAVE_IPV6
+       case AF_INET6:
+               if (bsda->u.sin6.sin6_port != 0) {
+                       do_reuseaddr = true;
+                       do_bind = true;
+               }
+               if (memcmp(&in6addr_any,
+                          &bsda->u.sin6.sin6_addr,
+                          sizeof(in6addr_any)) != 0) {
+                       do_bind = true;
+               }
+               break;
+#endif
+       default:
+               errno = EINVAL;
+               return -1;
+       }
+
+       fd = socket(bsda->u.sa.sa_family, bsd_type, 0);
+       if (fd < 0) {
+               return fd;
+       }
+
+       fd = tsocket_common_prepare_fd(fd, true);
+       if (fd < 0) {
+               return fd;
+       }
+
+       ret = _tsocket_context_bsd_wrap_existing(mem_ctx, fd, true,
+                                                &sock, location);
+       if (ret != 0) {
+               int saved_errno = errno;
+               close(fd);
+               errno = saved_errno;
+               return ret;
+       }
+
+       if (bsda->broadcast) {
+               ret = tsocket_context_bsd_set_option(sock, "SO_BROADCAST", true, "1");
+               if (ret != 0) {
+                       int saved_errno = errno;
+                       talloc_free(sock);
+                       errno = saved_errno;
+                       return ret;
+               }
+       }
+
+       if (do_reuseaddr) {
+               ret = tsocket_context_bsd_set_option(sock, "SO_REUSEADDR", true, "1");
+               if (ret != 0) {
+                       int saved_errno = errno;
+                       talloc_free(sock);
+                       errno = saved_errno;
+                       return ret;
+               }
+       }
+
+       if (do_bind) {
+               ret = bind(fd, &bsda->u.sa, sizeof(bsda->u.ss));
+               if (ret != 0) {
+                       int saved_errno = errno;
+                       talloc_free(sock);
+                       errno = saved_errno;
+                       return ret;
+               }
+       }
+
+       *_sock = sock;
+       return 0;
+}
+
+static const struct tsocket_address_ops tsocket_address_bsd_ops = {
+       .name           = "bsd",
+       .string         = tsocket_address_bsd_string,
+       .copy           = tsocket_address_bsd_copy,
+       .create_socket  = tsocket_address_bsd_create_socket
+};
+
+static void tsocket_context_bsd_fde_handler(struct tevent_context *ev,
+                                           struct tevent_fd *fde,
+                                           uint16_t flags,
+                                           void *private_data)
+{
+       struct tsocket_context *sock = talloc_get_type(private_data,
+                                      struct tsocket_context);
+
+       if (flags & TEVENT_FD_WRITE) {
+               sock->event.write_handler(sock, sock->event.write_private);
+               return;
+       }
+       if (flags & TEVENT_FD_READ) {
+               sock->event.read_handler(sock, sock->event.read_private);
+               return;
+       }
+}
+
+static int tsocket_context_bsd_set_event_context(struct tsocket_context *sock,
+                                                struct tevent_context *ev)
+{
+       struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data,
+                                          struct tsocket_context_bsd);
+
+       talloc_free(bsds->fde);
+       bsds->fde = NULL;
+       ZERO_STRUCT(sock->event);
+
+       if (!ev) {
+               return 0;
+       }
+
+       bsds->fde = tevent_add_fd(ev, bsds,
+                                 bsds->fd,
+                                 0,
+                                 tsocket_context_bsd_fde_handler,
+                                 sock);
+       if (!bsds->fde) {
+               if (errno == 0) {
+                       errno = ENOMEM;
+               }
+               return -1;
+       }
+
+       sock->event.ctx = ev;
+
+       return 0;
+}
+
+static int tsocket_context_bsd_set_read_handler(struct tsocket_context *sock,
+                                               tsocket_event_handler_t handler,
+                                               void *private_data)
+{
+       struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data,
+                                          struct tsocket_context_bsd);
+
+       if (sock->event.read_handler && !handler) {
+               TEVENT_FD_NOT_READABLE(bsds->fde);
+       } else if (!sock->event.read_handler && handler) {
+               TEVENT_FD_READABLE(bsds->fde);
+       }
+
+       sock->event.read_handler = handler;
+       sock->event.read_private = private_data;
+
+       return 0;
+}
+
+static int tsocket_context_bsd_set_write_handler(struct tsocket_context *sock,
+                                                tsocket_event_handler_t handler,
+                                                void *private_data)
+{
+       struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data,
+                                          struct tsocket_context_bsd);
+
+       if (sock->event.write_handler && !handler) {
+               TEVENT_FD_NOT_WRITEABLE(bsds->fde);
+       } else if (!sock->event.write_handler && handler) {
+               TEVENT_FD_WRITEABLE(bsds->fde);
+       }
+
+       sock->event.write_handler = handler;
+       sock->event.write_private = private_data;
+
+       return 0;
+}
+
+static int tsocket_context_bsd_connect_to(struct tsocket_context *sock,
+                                         const struct tsocket_address *remote)
+{
+       struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data,
+                                          struct tsocket_context_bsd);
+       struct tsocket_address_bsd *bsda = talloc_get_type(remote->private_data,
+                                          struct tsocket_address_bsd);
+       int ret;
+
+       ret = connect(bsds->fd, &bsda->u.sa,
+                     sizeof(bsda->u.ss));
+
+       return ret;
+}
+
+static int tsocket_context_bsd_listen_on(struct tsocket_context *sock,
+                                         int queue_size)
+{
+       struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data,
+                                          struct tsocket_context_bsd);
+       int ret;
+
+       ret = listen(bsds->fd, queue_size);
+
+       return ret;
+}
+
+static int tsocket_context_bsd_accept_new(struct tsocket_context *sock,
+                                          TALLOC_CTX *mem_ctx,
+                                          struct tsocket_context **_new_sock,
+                                          const char *location)
+{
+       struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data,
+                                          struct tsocket_context_bsd);
+       int new_fd;
+       struct tsocket_context *new_sock;
+       struct tsocket_context_bsd *new_bsds;
+       struct sockaddr_storage ss;
+       void *p = &ss;
+       socklen_t ss_len = sizeof(ss);
+
+       new_fd = accept(bsds->fd, (struct sockaddr *)p, &ss_len);
+       if (new_fd < 0) {
+               return new_fd;
+       }
+
+       new_fd = tsocket_common_prepare_fd(new_fd, true);
+       if (new_fd < 0) {
+               return new_fd;
+       }
+
+       new_sock = tsocket_context_create(mem_ctx,
+                                         &tsocket_context_bsd_ops,
+                                         &new_bsds,
+                                         struct tsocket_context_bsd,
+                                         location);
+       if (!new_sock) {
+               int saved_errno = errno;
+               close(new_fd);
+               errno = saved_errno;
+               return -1;
+       }
+
+       new_bsds->close_on_disconnect   = true;
+       new_bsds->fd                    = new_fd;
+       new_bsds->fde                   = NULL;
+
+       *_new_sock = new_sock;
+       return 0;
+}
+
+static ssize_t tsocket_context_bsd_pending_data(struct tsocket_context *sock)
+{
+       struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data,
+                                          struct tsocket_context_bsd);
+       int ret;
+       int value = 0;
+
+       ret = ioctl(bsds->fd, FIONREAD, &value);
+       if (ret == -1) {
+               return ret;
+       }
+
+       if (ret == 0) {
+               if (value == 0) {
+                       int error=0;
+                       socklen_t len = sizeof(error);
+                       /*
+                        * if no data is available check if the socket
+                        * is in error state. For dgram sockets
+                        * it's the way to return ICMP error messages
+                        * of connected sockets to the caller.
+                        */
+                       ret = getsockopt(bsds->fd, SOL_SOCKET, SO_ERROR,
+                                        &error, &len);
+                       if (ret == -1) {
+                               return ret;
+                       }
+                       if (error != 0) {
+                               errno = error;
+                               return -1;
+                       }
+               }
+               return value;
+       }
+
+       /* this should not be reached */
+       errno = EIO;
+       return -1;
+}
+
+static int tsocket_context_bsd_readv_data(struct tsocket_context *sock,
+                                         const struct iovec *vector,
+                                         size_t count)
+{
+       struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data,
+                                          struct tsocket_context_bsd);
+       int ret;
+
+       ret = readv(bsds->fd, vector, count);
+
+       return ret;
+}
+
+static int tsocket_context_bsd_writev_data(struct tsocket_context *sock,
+                                          const struct iovec *vector,
+                                          size_t count)
+{
+       struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data,
+                                          struct tsocket_context_bsd);
+       int ret;
+
+       ret = writev(bsds->fd, vector, count);
+
+       return ret;
+}
+
+static ssize_t tsocket_context_bsd_recvfrom_data(struct tsocket_context *sock,
+                                                 uint8_t *data, size_t len,
+                                                 TALLOC_CTX *addr_ctx,
+                                                 struct tsocket_address **remote)
+{
+       struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data,
+                                          struct tsocket_context_bsd);
+       struct tsocket_address *addr = NULL;
+       struct tsocket_address_bsd *bsda;
+       ssize_t ret;
+       struct sockaddr *sa = NULL;
+       socklen_t sa_len = 0;
+
+       if (remote) {
+               addr = tsocket_address_create(addr_ctx,
+                                             &tsocket_address_bsd_ops,
+                                             &bsda,
+                                             struct tsocket_address_bsd,
+                                             __location__ "recvfrom");
+               if (!addr) {
+                       return -1;
+               }
+
+               ZERO_STRUCTP(bsda);
+
+               sa = &bsda->u.sa;
+               sa_len = sizeof(bsda->u.ss);
+       }
+
+       ret = recvfrom(bsds->fd, data, len, 0, sa, &sa_len);
+       if (ret < 0) {
+               int saved_errno = errno;
+               talloc_free(addr);
+               errno = saved_errno;
+               return ret;
+       }
+
+       if (remote) {
+               *remote = addr;
+       }
+       return ret;
+}
+
+static ssize_t tsocket_context_bsd_sendto_data(struct tsocket_context *sock,
+                                               const uint8_t *data, size_t len,
+                                               const struct tsocket_address *remote)
+{
+       struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data,
+                                          struct tsocket_context_bsd);
+       struct sockaddr *sa = NULL;
+       socklen_t sa_len = 0;
+       ssize_t ret;
+
+       if (remote) {
+               struct tsocket_address_bsd *bsda =
+                       talloc_get_type(remote->private_data,
+                       struct tsocket_address_bsd);
+
+               sa = &bsda->u.sa;
+               sa_len = sizeof(bsda->u.ss);
+       }
+
+       ret = sendto(bsds->fd, data, len, 0, sa, sa_len);
+
+       return ret;
+}
+
+static int tsocket_context_bsd_get_status(const struct tsocket_context *sock)
+{
+       struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data,
+                                          struct tsocket_context_bsd);
+       int ret;
+       int error=0;
+       socklen_t len = sizeof(error);
+
+       if (bsds->fd == -1) {
+               errno = EPIPE;
+               return -1;
+       }
+
+       ret = getsockopt(bsds->fd, SOL_SOCKET, SO_ERROR, &error, &len);
+       if (ret == -1) {
+               return ret;
+       }
+       if (error != 0) {
+               errno = error;
+               return -1;
+       }
+
+       return 0;
+}
+
+static int tsocket_context_bsd_get_local_address(const struct tsocket_context *sock,
+                                                 TALLOC_CTX *mem_ctx,
+                                                 struct tsocket_address **_addr,
+                                                 const char *location)
+{
+       struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data,
+                                          struct tsocket_context_bsd);
+       struct tsocket_address *addr;
+       struct tsocket_address_bsd *bsda;
+       ssize_t ret;
+       socklen_t sa_len;
+
+       addr = tsocket_address_create(mem_ctx,
+                                     &tsocket_address_bsd_ops,
+                                     &bsda,
+                                     struct tsocket_address_bsd,
+                                     location);
+       if (!addr) {
+               return -1;
+       }
+
+       ZERO_STRUCTP(bsda);
+
+       sa_len = sizeof(bsda->u.ss);
+       ret = getsockname(bsds->fd, &bsda->u.sa, &sa_len);
+       if (ret < 0) {
+               int saved_errno = errno;
+               talloc_free(addr);
+               errno = saved_errno;
+               return ret;
+       }
+
+       *_addr = addr;
+       return 0;
+}
+
+static int tsocket_context_bsd_get_remote_address(const struct tsocket_context *sock,
+                                                  TALLOC_CTX *mem_ctx,
+                                                  struct tsocket_address **_addr,
+                                                  const char *location)
+{
+       struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data,
+                                          struct tsocket_context_bsd);
+       struct tsocket_address *addr;
+       struct tsocket_address_bsd *bsda;
+       ssize_t ret;
+       socklen_t sa_len;
+
+       addr = tsocket_address_create(mem_ctx,
+                                     &tsocket_address_bsd_ops,
+                                     &bsda,
+                                     struct tsocket_address_bsd,
+                                     location);
+       if (!addr) {
+               return -1;
+       }
+
+       ZERO_STRUCTP(bsda);
+
+       sa_len = sizeof(bsda->u.ss);
+       ret = getpeername(bsds->fd, &bsda->u.sa, &sa_len);
+       if (ret < 0) {
+               int saved_errno = errno;
+               talloc_free(addr);
+               errno = saved_errno;
+               return ret;
+       }
+
+       *_addr = addr;
+       return 0;
+}
+
+static const struct tsocket_context_bsd_option {
+       const char *name;
+       int level;
+       int optnum;
+       int optval;
+} tsocket_context_bsd_options[] = {
+#define TSOCKET_OPTION(_level, _optnum, _optval) { \
+       .name = #_optnum, \
+       .level = _level, \
+       .optnum = _optnum, \
+       .optval = _optval \
+}
+       TSOCKET_OPTION(SOL_SOCKET, SO_REUSEADDR, 0),
+       TSOCKET_OPTION(SOL_SOCKET, SO_BROADCAST, 0)
+};
+
+static int tsocket_context_bsd_get_option(const struct tsocket_context *sock,
+                                         const char *option,
+                                         TALLOC_CTX *mem_ctx,
+                                         char **_value)
+{
+       struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data,
+                                          struct tsocket_context_bsd);
+       const struct tsocket_context_bsd_option *opt = NULL;
+       uint32_t i;
+       int optval;
+       socklen_t optval_len = sizeof(optval);
+       char *value;
+       int ret;
+
+       for (i=0; i < ARRAY_SIZE(tsocket_context_bsd_options); i++) {
+               if (strcmp(option, tsocket_context_bsd_options[i].name) != 0) {
+                       continue;
+               }
+
+               opt = &tsocket_context_bsd_options[i];
+               break;
+       }
+
+       if (!opt) {
+               goto nosys;
+       }
+
+       ret = getsockopt(bsds->fd, opt->level, opt->optnum,
+                        (void *)&optval, &optval_len);
+       if (ret != 0) {
+               return ret;
+       }
+
+       if (optval_len != sizeof(optval)) {
+               value = NULL;
+       } if (opt->optval != 0) {
+               if (optval == opt->optval) {
+                       value = talloc_strdup(mem_ctx, "1");
+               } else {
+                       value = talloc_strdup(mem_ctx, "0");
+               }
+               if (!value) {
+                       goto nomem;
+               }
+       } else {
+               value = talloc_asprintf(mem_ctx, "%d", optval);
+               if (!value) {
+                       goto nomem;
+               }
+       }
+
+       *_value = value;
+       return 0;
+
+ nomem:
+       errno = ENOMEM;
+       return -1;
+ nosys:
+       errno = ENOSYS;
+       return -1;
+}
+
+static int tsocket_context_bsd_set_option(const struct tsocket_context *sock,
+                                         const char *option,
+                                         bool force,
+                                         const char *value)
+{
+       struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data,
+                                          struct tsocket_context_bsd);
+       const struct tsocket_context_bsd_option *opt = NULL;
+       uint32_t i;
+       int optval;
+       int ret;
+
+       for (i=0; i < ARRAY_SIZE(tsocket_context_bsd_options); i++) {
+               if (strcmp(option, tsocket_context_bsd_options[i].name) != 0) {
+                       continue;
+               }
+
+               opt = &tsocket_context_bsd_options[i];
+               break;
+       }
+
+       if (!opt) {
+               goto nosys;
+       }
+
+       if (value) {
+               if (opt->optval != 0) {
+                       errno = EINVAL;
+                       return -1;
+               }
+
+               optval = atoi(value);
+       } else {
+               optval = opt->optval;
+       }
+
+       ret = setsockopt(bsds->fd, opt->level, opt->optnum,
+                        (const void *)&optval, sizeof(optval));
+       if (ret != 0) {
+               if (!force) {
+                       errno = 0;
+                       return 0;
+               }
+               return ret;
+       }
+
+       return 0;
+
+ nosys:
+       if (!force) {
+               return 0;
+       }
+
+       errno = ENOSYS;
+       return -1;
+}
+
+static void tsocket_context_bsd_disconnect(struct tsocket_context *sock)
+{
+       struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data,
+                                          struct tsocket_context_bsd);
+
+       tsocket_context_bsd_set_event_context(sock, NULL);
+
+       if (bsds->fd != -1) {
+               if (bsds->close_on_disconnect) {
+                       close(bsds->fd);
+               }
+               bsds->fd = -1;
+       }
+}
+
+static const struct tsocket_context_ops tsocket_context_bsd_ops = {
+       .name                   = "bsd",
+
+       .set_event_context      = tsocket_context_bsd_set_event_context,
+       .set_read_handler       = tsocket_context_bsd_set_read_handler,
+       .set_write_handler      = tsocket_context_bsd_set_write_handler,
+
+       .connect_to             = tsocket_context_bsd_connect_to,
+       .listen_on              = tsocket_context_bsd_listen_on,
+       .accept_new             = tsocket_context_bsd_accept_new,
+
+       .pending_data           = tsocket_context_bsd_pending_data,
+       .readv_data             = tsocket_context_bsd_readv_data,
+       .writev_data            = tsocket_context_bsd_writev_data,
+       .recvfrom_data          = tsocket_context_bsd_recvfrom_data,
+       .sendto_data            = tsocket_context_bsd_sendto_data,
+
+       .get_status             = tsocket_context_bsd_get_status,
+       .get_local_address      = tsocket_context_bsd_get_local_address,
+       .get_remote_address     = tsocket_context_bsd_get_remote_address,
+
+       .get_option             = tsocket_context_bsd_get_option,
+       .set_option             = tsocket_context_bsd_set_option,
+
+       .disconnect             = tsocket_context_bsd_disconnect
+};
diff --git a/lib/tsocket/tsocket_connect.c b/lib/tsocket/tsocket_connect.c
new file mode 100644 (file)
index 0000000..7a9d4b8
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Copyright (C) Stefan Metzmacher 2009
+
+     ** NOTE! The following LGPL license applies to the tevent
+     ** 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/network.h"
+#include "tsocket.h"
+#include "tsocket_internal.h"
+
+struct tsocket_connect_state {
+       /* this structs are owned by the caller */
+       struct {
+               struct tsocket_context *sock;
+               const struct tsocket_address *dst;
+       } caller;
+};
+
+static void tsocket_connect_handler(struct tsocket_context *sock,
+                                   void *private_data);
+
+struct tevent_req *tsocket_connect_send(struct tsocket_context *sock,
+                                       TALLOC_CTX *mem_ctx,
+                                       const struct tsocket_address *dst)
+{
+       struct tevent_req *req;
+       struct tsocket_connect_state *state;
+       int ret;
+       int err;
+       bool retry;
+       bool dummy;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct tsocket_connect_state);
+       if (!req) {
+               return NULL;
+       }
+
+       state->caller.sock      = sock;
+       state->caller.dst       = dst;
+
+       ret = tsocket_connect(state->caller.sock,
+                             state->caller.dst);
+       err = tsocket_error_from_errno(ret, errno, &retry);
+       if (retry) {
+               /* retry later */
+               goto async;
+       }
+       if (tevent_req_error(req, err)) {
+               goto post;
+       }
+
+       tevent_req_done(req);
+       goto post;
+
+ async:
+       ret = tsocket_set_readable_handler(state->caller.sock,
+                                          tsocket_connect_handler,
+                                          req);
+       err = tsocket_error_from_errno(ret, errno, &dummy);
+       if (tevent_req_error(req, err)) {
+               goto post;
+       }
+
+       return req;
+
+ post:
+       return tevent_req_post(req, sock->event.ctx);
+}
+
+static void tsocket_connect_handler(struct tsocket_context *sock,
+                                   void *private_data)
+{
+       struct tevent_req *req = talloc_get_type(private_data,
+                                struct tevent_req);
+       struct tsocket_connect_state *state = tevent_req_data(req,
+                                             struct tsocket_connect_state);
+       int ret;
+       int err;
+       bool retry;
+
+       ret = tsocket_get_status(state->caller.sock);
+       err = tsocket_error_from_errno(ret, errno, &retry);
+       if (retry) {
+               /* retry later */
+               return;
+       }
+       if (tevent_req_error(req, err)) {
+               return;
+       }
+
+       tevent_req_done(req);
+}
+
+int tsocket_connect_recv(struct tevent_req *req, int *perrno)
+{
+       int ret;
+
+       ret = tsocket_simple_int_recv(req, perrno);
+
+       tevent_req_received(req);
+       return ret;
+}
+
diff --git a/lib/tsocket/tsocket_guide.txt b/lib/tsocket/tsocket_guide.txt
new file mode 100644 (file)
index 0000000..a02fa37
--- /dev/null
@@ -0,0 +1,503 @@
+
+Basic design of the tsocket abstraction
+=======================================
+
+The tsocket layer is designed to match more or less
+the bsd socket layer, but it hides the filedescriptor
+within a opaque 'tsocket_context' structure to make virtual
+sockets possible. The virtual sockets can be encrypted tunnels
+(like TLS, SASL or GSSAPI) or named pipes over smb.
+
+The tsocket layer is a bit like an abstract class, which defines
+common methods to work with sockets in a non blocking fashion.
+
+The whole library is based on the talloc(3) and 'tevent' libraries.
+
+The 'tsocket_address' structure is the 2nd abstracted class
+which represends the address of a socket endpoint.
+
+Each different type of socket has its own constructor.
+
+Typically the constructor for a tsocket_context is attached to
+the tsocket_address of the source endpoint. That means
+the tsocket_address_create_socket() function takes the
+tsocket_address of the local endpoint and creates a tsocket_context
+for the communication.
+
+For some usecases it's possible to wrap an existing socket into a
+tsocket_context, e.g. to wrap an existing pipe(2) into
+tsocket_context, so that you can use the same functions to
+communicate over the pipe.
+
+The tsocket_address abstraction
+===============================
+
+The tsocket_address represents an socket endpoint genericly.
+As it's like an abstract class it has no specific constructor.
+The specific constructors are descripted later sections.
+
+There's a function get the string representation of the
+endpoint for debugging. Callers should not try to parse
+the string! The should use additional methods of the specific
+tsocket_address implemention to get more details.
+
+   char *tsocket_address_string(const struct tsocket_address *addr,
+                                TALLOC_CTX *mem_ctx);
+
+There's a function to create a copy of the tsocket_address.
+This is useful when before doing modifications to a socket
+via additional methods of the specific tsocket_address implementation.
+
+   struct tsocket_address *tsocket_address_copy(const struct tsocket_address *addr,
+                                                TALLOC_CTX *mem_ctx);
+
+There's a function to create a tsocket_context based on the given local
+socket endpoint. The return value is 0 on success and -1 on failure
+with errno holding the specific error. Specific details are descripted in later
+sections. Note not all specific implementation have to implement all socket
+types.
+
+   enum tsocket_type {
+        TSOCKET_TYPE_STREAM = 1,
+        TSOCKET_TYPE_DGRAM,
+        TSOCKET_TYPE_MESSAGE
+   };
+
+   int tsocket_address_create_socket(const struct tsocket_address *addr,
+                                     enum tsocket_type type,
+                                     TALLOC_CTX *mem_ctx,
+                                     struct tsocket_context **sock);
+
+The tsocket_context abstraction
+===============================
+
+The tsocket_context is like an abstract class and represents
+a socket similar to bsd style sockets. The methods are more
+or less equal to the bsd socket api, while the filedescriptor
+is replaced by tsocket_context and sockaddr, socklen_t pairs
+are replaced by tsocket_address. The 'bind' operation happens
+in the specific constructor as the constructor is typically based
+on tsocket_address of local socket endpoint.
+
+All operations are by design non blocking and can return error
+values like EAGAIN, EINPROGRESS, EWOULDBLOCK or EINTR which
+indicate that the caller should retry the operation later.
+Also read the "The glue to tevent" section.
+
+The socket can of types:
+ - TSOCKET_TYPE_STREAM is the equivalent to SOCK_STREAM in the bsd socket api.
+ - TSOCKET_TYPE_DGRAM is the equivalent to SOCK_DGRAM in the bsd socket api.
+ - TSOCKET_TYPE_MESSAGE operates on a connected socket and is therefore
+   like TSOCKET_TYPE_STREAM, but the consumer needs to first read all
+   data of a message, which was generated by one message 'write' on the sender,
+   before the consumer gets data of the next message. This matches a bit
+   like message mode pipes on windows. The concept is to transfer ordered
+   messages between to endpoints.
+
+There's a function to connect to a remote endpoint. The behavior
+and error codes match the connect(2) function of the bsd socket api.
+Maybe the specific tsocket_context implementation speficied some
+further details.
+
+   int tsocket_connect(struct tsocket_context *sock,
+                       const struct tsocket_address *remote_addr);
+
+There's a function to listen for incoming connections. The behavior
+and error codes match the listen(2) function of the bsd socket api.
+Maybe the specific tsocket_context implementation speficied some
+further details.
+
+   int tsocket_listen(struct tsocket_context *sock,
+                      int queue_size);
+
+There's a function to accept incoming connections. The behavior
+and error codes match the accept(2) function of the bsd socket api.
+Maybe the specific tsocket_context implementation speficied some
+further details.
+
+   int tsocket_accept(struct tsocket_context *sock,
+                      TALLOC_CTX *mem_ctx,
+                      struct tsocket_context **new_sock);
+
+There's a function to ask how many bytes are in input buffer
+of the connection. For sockets of type TSOCKET_TYPE_DGRAM or
+TSOCKET_TYPE_MESSAGE the size of the next available dgram/message
+is returned. A return value of -1 indicates a socket error
+and errno will hold the specific error code. If no data
+is available 0 is returned, but retry error codes like
+EINTR can also be returned.
+
+   ssize_t tsocket_pending(struct tsocket_context *sock);
+
+There's a function to read data from the socket. The behavior
+and error codes match the readv(3) function, also take a look
+at the recv(2) function of the bsd socket api.
+Maybe the specific tsocket_context implementation speficied some
+further details.
+
+   int tsocket_readv(struct tsocket_context *sock,
+                     const struct iovec *vector, size_t count);
+
+There's a function to write data from the socket. The behavior
+and error codes match the writev(3) function, also take a look
+at the send(2) function of the bsd socket api.
+Maybe the specific tsocket_context implementation speficied some
+further details.
+
+   int tsocket_writev(struct tsocket_context *sock,
+                      const struct iovec *vector, size_t count);
+
+There's a function to read a datagram from a remote endpoint.
+The behavior and error codes match the recvfrom(2) function of
+the bsd socket api. As TSOCKET_TYPE_DGRAM sockets can also be
+used in connected mode src_addr can be NULL, if the caller don't
+want to get the source address. Maybe the specific tsocket_context
+implementation speficied some further details.
+
+   ssize_t tsocket_recvfrom(struct tsocket_context *sock,
+                            uint8_t *data, size_t len,
+                            TALLOC_CTX *addr_ctx,
+                            struct tsocket_address **src_addr);
+
+There's a function to send a datagram to a remote endpoint the socket.
+The behavior and error codes match the recvfrom(2) function of the
+bsd socket api. As TSOCKET_TYPE_DGRAM sockets can also be used in
+connected mode dest_addr must be NULL in connected mode and a valid
+tsocket_address otherwise. Maybe the specific tsocket_context
+implementation speficied some further details.
+
+   ssize_t tsocket_sendto(struct tsocket_context *sock,
+                          const uint8_t *data, size_t len,
+                          const struct tsocket_address *dest_addr);
+
+There's a function to get the current status of the socket.
+The behavior and error codes match the getsockopt(2) function
+of the bsd socket api, with SOL_SOCKET and SO_ERROR as arguments.
+Maybe the specific tsocket_context implementation speficied some
+further details.
+
+   int tsocket_get_status(const struct tsocket_context *sock);
+
+There's a function to get tsocket_address of the local endpoint.
+The behavior and error codes match the getsockname(2) function
+of the bsd socket api. Maybe the specific tsocket_context
+implementation speficied some further details.
+
+   int tsocket_get_local_address(const struct tsocket_context *sock,
+                                 TALLOC_CTX *mem_ctx,
+                                 struct tsocket_address **local_addr);
+
+There's a function to get tsocket_address of the remote endpoint
+of a connected socket. The behavior and error codes match the
+getpeername(2) function of the bsd socket api. Maybe the specific
+tsocket_context implementation speficied some further details.
+
+   int tsocket_get_remote_address(const struct tsocket_context *sock,
+                                  TALLOC_CTX *mem_ctx,
+                                  struct tsocket_address **remote_addr,
+                                  const char *location);
+
+There's a function to ask for specific options of the socket.
+The behavior and error codes match the getsockopt(2) function
+of the bsd socket api. The option and value are represented as string
+values, where the 'value' parameter can be NULL is the caller don't want to
+get the value. The supported options and values are up to the specific
+tsocket_context implementation.
+
+   int tsocket_get_option(const struct tsocket_context *sock,
+                          const char *option,
+                          TALLOC_CTX *mem_ctx,
+                          char **value);
+
+There's a function to set specific options of the socket.
+The behavior and error codes match the setsockopt(2) function
+of the bsd socket api. The option and value are represented as string
+values, where the 'value' parameter can be NULL. The supported options
+and values are up to the specific tsocket_context implementation.
+The 'force' parameter specifies whether an error should be returned
+for unsupported options.
+
+   int tsocket_set_option(const struct tsocket_context *sock,
+                          const char *option,
+                          bool force,
+                          const char *value);
+
+There's a function to disconnect the socket. The behavior
+and error codes match the close(2) function of the bsd socket api.
+Maybe the specific tsocket_context implementation speficied some
+further details.
+
+   void tsocket_disconnect(struct tsocket_context *sock);
+
+The glue to tevent
+==================
+
+As the tsocket library is based on the tevent library,
+there need to be functions to let the caller register
+callback functions, which are triggered when the socket
+is writeable or readable. Typically one would use
+tevent fd events, but in order to hide the filedescriptor
+the tsocket_context abstraction has their own functions.
+
+There's a function to set the currently active tevent_context
+for the socket. It's important there's only one tevent_context
+actively used with the socket. A second call will cancel
+all low level events made on the old tevent_context, it will
+also resets the send and recv handlers to NULL. If the caller
+sets attaches a new event context to the socket, the callback
+function also need to be registered again. It's important
+that the caller keeps the given tevent_context in memory
+and actively calls tsocket_set_event_context(sock, NULL)
+before calling talloc_free(event_context).
+The function returns 0 on success and -1 together with an errno
+on failure.
+
+   int tsocket_set_event_context(struct tsocket_context *sock,
+                                 struct tevent_context *ev);
+
+There's a function to register a callback function which is called
+when the socket is readable. If the caller don't want to get notified
+anymore the function should be called with NULL as handler.
+The function returns 0 on success and -1 together with an errno
+on failure.
+
+   typedef void (*tsocket_event_handler_t)(struct tsocket_context *, void *);
+   int tsocket_set_readable_handler(struct tsocket_context *sock,
+                                    tsocket_event_handler_t handler,
+                                    void *private_data);
+
+There's a function to register a callback function which is called
+when the socket is writeable. If the caller don't want to get notified
+anymore the function should be called with NULL as handler.
+The function returns 0 on success and -1 together with an errno
+on failure.
+
+   typedef void (*tsocket_event_handler_t)(struct tsocket_context *, void *);
+   int tsocket_set_writeable_handler(struct tsocket_context *sock,
+                                     tsocket_event_handler_t handler,
+                                     void *private_data);
+
+Note: if the socket is readable and writeable, only the writeable
+      handler is called, this avoids deadlocks at the application level.
+
+Async helper functions
+======================
+
+To make the life easier for the callers, there're 'tevent_req' based
+helper functions for non-blocking io-operations. For each of this functions
+to work the caller must attach the tevent_context to the tsocket_context
+with tsocket_set_event_context(). Please remember that attching a new
+tevent_context will reset the event state of the socket and should only
+be done, when there's no async request is pending on the socket!
+
+The detailed calling conventions for 'tevent_req' based programming
+will be explained in the 'tevent' documentation.
+
+To receive the next availabe datagram from socket there's a wrapper
+for tsocket_recvfrom(). The caller virtually sends its desire to receive
+the next available datagram by calling the tsocket_recvfrom_send() function
+and attaches a callback function to the returned tevent_req via tevent_req_set_callback().
+The callback function is called when a datagram is available or an error has happened.
+The callback function needs to get the result by calling
+tsocket_recvfrom_recv(). The return value of tsocket_recvfrom_recv()
+matches the return value from tsocket_recvfrom(). A possible errno is delivered
+via the perrno parameter instead of the global errno variable. The datagram
+buffer and optional the source tsocket_address of the datagram are returned as talloc
+childs of the mem_ctx passed to tsocket_recvfrom_recv().
+It's important that the caller garanties that there's only one async
+read request on the socket at a time.
+
+   struct tevent_req *tsocket_recvfrom_send(struct tsocket_context *sock,
+                                            TALLOC_CTX *mem_ctx);
+   ssize_t tsocket_recvfrom_recv(struct tevent_req *req,
+                                 int *perrno,
+                                 TALLOC_CTX *mem_ctx,
+                                 uint8_t **buf,
+                                 struct tsocket_address **src);
+
+To send a datagram there's a wrapper for tsocket_sendto().
+The caller calls tsocket_sendto_send() instead of tsocket_sendto()
+which returns a tevent_req allocated on the given TALLOC_CTX.
+The caller attaches a callback function to the returned tevent_req via
+tevent_req_set_callback(). The callback function is called when a datagram was
+deliviered into the socket or an error has happened.
+The callback function needs to get the result by calling
+tsocket_sendto_recv(). The return value of tsocket_sendto_recv()
+matches the return value from tsocket_sendto(). A possible errno is delivered
+via the perrno parameter instead of the global errno variable.
+Normal callers should not use this function directly, they should use
+tsocket_sendto_queue_send/recv() instead.
+
+   struct tevent_req *tsocket_sendto_send(struct tsocket_context *sock,
+                                          TALLOC_CTX *mem_ctx,
+                                          const uint8_t *buf,
+                                          size_t len,
+                                          const struct tsocket_address *dst);
+   ssize_t tsocket_sendto_recv(struct tevent_req *req, int *perrno);
+
+As only one async tsocket_sendto() call should happen at a time,
+there's a 'tevent_queue' is used to serialize the sendto requests.
+
+   struct tevent_req *tsocket_sendto_queue_send(TALLOC_CTX *mem_ctx,
+                                                struct tsocket_context *sock,
+                                                struct tevent_queue *queue,
+                                                const uint8_t *buf,
+                                                size_t len,
+                                                struct tsocket_address *dst);
+   ssize_t tsocket_sendto_queue_recv(struct tevent_req *req, int *perrno);
+
+Ther's an async helper for tsocket_connect(), which should be used
+to connect TSOCKET_TYPE_STREAM based sockets.
+The caller virtually sends its desire to connect to the destination
+tsocket_address by calling tsocket_connect_send() and gets back a tevent_req.
+The caller sets a callback function via tevent_req_set_callback().
+The callback function is called if the tsocket is connected or an error has happened.
+The callback function needs to get the result by calling
+tsocket_connect_recv(). The return value of tsocket_connect_recv()
+matches the return value from tsocket_connect()/tsocket_get_status().
+A possible errno is delivered via the perrno parameter instead of the global
+errno variable.
+
+   struct tevent_req *tsocket_connect_send(struct tsocket_context *sock,
+                                           TALLOC_CTX *mem_ctx,
+                                           const struct tsocket_address *dst);
+   int tsocket_connect_recv(struct tevent_req *req, int *perrno);
+
+To send an 'iovec' there's a wrapper for tsocket_writev().
+The caller calls tsocket_writev_send() instead of tsocket_writev()
+which returns a tevent_req allocated on the given TALLOC_CTX.
+The caller attaches a callback function to the returned tevent_req via
+tevent_req_set_callback(). The callback function is called when the whole iovec
+was deliviered into the socket or an error has happened.
+The callback function needs to get the result by calling
+tsocket_writev_recv(). The return value of tsocket_writev_recv()
+matches the return value from tsocket_writev(). A possible errno is delivered
+via the perrno parameter instead of the global errno variable.
+Normal callers should not use this function directly, they should use
+tsocket_writev_queue_send/recv() instead.
+
+   struct tevent_req *tsocket_writev_send(struct tsocket_context *sock,
+                                          TALLOC_CTX *mem_ctx,
+                                          const struct iovec *vector,
+                                          size_t count);
+   int tsocket_writev_recv(struct tevent_req *req, int *perrno);
+
+As only one async tsocket_writev() call should happen at a time,
+there's a 'tevent_queue' is used to serialize the writev requests.
+
+   struct tevent_req *tsocket_writev_queue_send(TALLOC_CTX *mem_ctx,
+                                                struct tsocket_context *sock,
+                                                struct tevent_queue *queue,
+                                                const struct iovec *vector,
+                                                size_t count);
+   int tsocket_writev_queue_recv(struct tevent_req *req, int *perrno);
+
+For TSOCKET_TYPE_STREAM sockets, it's typically desired to split the stream
+into PDUs. That's why the helper function for tsocket_readv() is a bit
+different compared to the other helper functions. The general rule
+is still to get a tevent_req, set a callback which gets called when the
+operation is done. The callback function needs to get the result by
+calling tsocket_readv_recv(). The 'next_iovec' callback function
+makes the difference to the other helper function.
+The tsocket_writev_send/recv() logic asks the caller via the
+next_iovec_fn for an iovec array, which will be filled completely
+with bytes from the socket, then the next_iovec_fn is called for
+the next iovec array to fill, untill the next_iovec_fn returns an empty
+iovec array. That next_iovec_fn should allocate the array as child of the
+passed mem_ctx, while the buffers the array referr to belong to the caller.
+The tsocket_writev_send/recv() engine will modify and free the given array!
+The basic idea is that the caller allocates and maintains the real buffers.
+The next_iovec_fn should report error by returning -1 and setting errno to
+the specific error code. The engine will pass the error to the caller
+via tsocket_readv_recv().
+
+typedef int (*tsocket_readv_next_iovec_t)(struct tsocket_context *sock,
+                                         void *private_data,
+                                         TALLOC_CTX *mem_ctx,
+                                         struct iovec **vector,
+                                         size_t *count);
+struct tevent_req *tsocket_readv_send(struct tsocket_context *sock,
+                                     TALLOC_CTX *mem_ctx,
+                                     tsocket_readv_next_iovec_t next_iovec_fn,
+                                     void *private_data);
+int tsocket_readv_recv(struct tevent_req *req, int *perrno);
+
+Wrapper for BSD style sockets
+=============================
+
+Support for BSD style sockets of AF_INET, AF_INET6 and AF_UNIX
+are part of the main tsocket library.
+
+To wrap an existing fd into a tsocket_context the function
+tsocket_context_bsd_wrap_existing() can be used.
+The caller needs to make sure the fd is marked as non-blocking!
+Normaly the tsocket_disconnect() function would close the fd,
+but the caller can influence this behavior based on the close_on_disconnect
+parameter. The caller should also make sure that the socket is only
+accessed via the tsocket_context wrapper after the call to
+tsocket_context_bsd_wrap_existing().
+
+   int tsocket_context_bsd_wrap_existing(TALLOC_CTX *mem_ctx,
+                                         int fd, bool close_on_disconnect,
+                                         struct tsocket_context **_sock);
+
+To create a tsocket_address for an inet address you need to use
+the tsocket_address_inet_from_strings() function. It takes the family
+as parameter which can be "ipv4", "ipv6" or "ip", where "ip" autodetects
+"ipv4" or "ipv6", based on the given address string. Depending on the
+operating system, "ipv6" may not be supported. Note: NULL as address
+is mapped to "0.0.0.0" or "::" based on the given family.
+The address parameter only accepts valid ipv4 or ipv6 address strings
+and no names! The caller need to resolve names before using this function.
+
+   int tsocket_address_inet_from_strings(TALLOC_CTX *mem_ctx,
+                                         const char *family,
+                                         const char *address,
+                                         uint16_t port,
+                                         struct tsocket_address **addr);
+
+To get the address of the inet tsocket_address as string the
+tsocket_address_inet_addr_string() function should be used.
+The caller should not try to parse the tsocket_address_string() output!
+
+   char *tsocket_address_inet_addr_string(const struct tsocket_address *addr,
+                                          TALLOC_CTX *mem_ctx);
+
+To get the port number of the inet tsocket_address the
+tsocket_address_inet_port() function should be used.
+The caller should not try to parse the tsocket_address_string() output!
+
+   uint16_t tsocket_address_inet_port(const struct tsocket_address *addr);
+
+To alter the port number of an inet tsocket_address the
+tsocket_address_inet_set_port() function can be used.
+This is usefull if the caller gets the address from
+tsocket_address_copy(), tsocket_context_remote_address() or
+tsocket_context_remote_address() instead of tsocket_address_inet_from_strings().
+
+   int tsocket_address_inet_set_port(struct tsocket_address *addr,
+                                     uint16_t port);
+
+If the caller wants to create a broadcast socket, with the SO_BROADCAST
+socket option, the broadcast option needs to be set with the
+tsocket_address_inet_set_broadcast() function before calling
+tsocket_address_create_socket().
+
+   void tsocket_address_inet_set_broadcast(struct tsocket_address *addr,
+                                           bool broadcast);
+
+To create a tsocket_address for AF_UNIX style sockets the
+tsocket_address_unix_from_path() should be used.
+NULL as path is handled like "".
+
+   int tsocket_address_unix_from_path(TALLOC_CTX *mem_ctx,
+                                      const char *path,
+                                      struct tsocket_address **addr);
+
+To get the unix path of an existing unix tsocket_address
+the tsocket_address_unix_path() should be used.
+The caller should not try to parse the tsocket_address_string() output!
+
+   char *tsocket_address_unix_path(const struct tsocket_address *addr,
+                                   TALLOC_CTX *mem_ctx);
+
diff --git a/lib/tsocket/tsocket_helpers.c b/lib/tsocket/tsocket_helpers.c
new file mode 100644 (file)
index 0000000..b2edf43
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Copyright (C) Stefan Metzmacher 2009
+
+     ** NOTE! The following LGPL license applies to the tevent
+     ** 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/network.h"
+#include "system/filesys.h"
+#include "tsocket.h"
+#include "tsocket_internal.h"
+
+int tsocket_error_from_errno(int ret,
+                            int sys_errno,
+                            bool *retry)
+{
+       *retry = false;
+
+       if (ret >= 0) {
+               return 0;
+       }
+
+       if (ret != -1) {
+               return EIO;
+       }
+
+       if (sys_errno == 0) {
+               return EIO;
+       }
+
+       if (sys_errno == EINTR) {
+               *retry = true;
+               return sys_errno;
+       }
+
+       if (sys_errno == EINPROGRESS) {
+               *retry = true;
+               return sys_errno;
+       }
+
+       if (sys_errno == EAGAIN) {
+               *retry = true;
+               return sys_errno;
+       }
+
+#ifdef EWOULDBLOCK
+       if (sys_errno == EWOULDBLOCK) {
+               *retry = true;
+               return sys_errno;
+       }
+#endif
+
+       return sys_errno;
+}
+
+int tsocket_simple_int_recv(struct tevent_req *req, int *perrno)
+{
+       enum tevent_req_state state;
+       uint64_t error;
+
+       if (!tevent_req_is_error(req, &state, &error)) {
+               return 0;
+       }
+
+       switch (state) {
+       case TEVENT_REQ_NO_MEMORY:
+               *perrno = ENOMEM;
+               return -1;
+       case TEVENT_REQ_TIMED_OUT:
+               *perrno = ETIMEDOUT;
+               return -1;
+       case TEVENT_REQ_USER_ERROR:
+               *perrno = (int)error;
+               return -1;
+       default:
+               *perrno = EIO;
+               return -1;
+       }
+
+       *perrno = EIO;
+       return -1;
+}
+
+int tsocket_common_prepare_fd(int fd, bool high_fd)
+{
+       int i;
+       int sys_errno = 0;
+       int fds[3];
+       int num_fds = 0;
+
+       int result, flags;
+
+       if (fd == -1) {
+               return -1;
+       }
+
+       /* first make a fd >= 3 */
+       if (high_fd) {
+               while (fd < 3) {
+                       fds[num_fds++] = fd;
+                       fd = dup(fd);
+                       if (fd == -1) {
+                               sys_errno = errno;
+                               break;
+                       }
+               }
+               for (i=0; i<num_fds; i++) {
+                       close(fds[i]);
+               }
+               if (fd == -1) {
+                       errno = sys_errno;
+                       return fd;
+               }
+       }
+
+       /* fd should be nonblocking. */
+
+#ifdef O_NONBLOCK
+#define FLAG_TO_SET O_NONBLOCK
+#else
+#ifdef SYSV
+#define FLAG_TO_SET O_NDELAY
+#else /* BSD */
+#define FLAG_TO_SET FNDELAY
+#endif
+#endif
+
+       if ((flags = fcntl(fd, F_GETFL)) == -1) {
+               goto fail;
+       }
+
+       flags |= FLAG_TO_SET;
+       if (fcntl(fd, F_SETFL, flags) == -1) {
+               goto fail;
+       }
+
+#undef FLAG_TO_SET
+
+       /* fd should be closed on exec() */
+#ifdef FD_CLOEXEC
+       result = flags = fcntl(fd, F_GETFD, 0);
+       if (flags >= 0) {
+               flags |= FD_CLOEXEC;
+               result = fcntl(fd, F_SETFD, flags);
+       }
+       if (result < 0) {
+               goto fail;
+       }
+#endif
+       return fd;
+
+ fail:
+       if (fd != -1) {
+               sys_errno = errno;
+               close(fd);
+               errno = sys_errno;
+       }
+       return -1;
+}
+
diff --git a/lib/tsocket/tsocket_internal.h b/lib/tsocket/tsocket_internal.h
new file mode 100644 (file)
index 0000000..e4a4908
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Copyright (C) Stefan Metzmacher 2009
+
+     ** NOTE! The following LGPL license applies to the tevent
+     ** 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _TSOCKET_INTERNAL_H
+#define _TSOCKET_INTERNAL_H
+
+struct tsocket_context_ops {
+       const char *name;
+
+       /* event handling */
+       int (*set_event_context)(struct tsocket_context *sock,
+                                struct tevent_context *ev);
+       int (*set_read_handler)(struct tsocket_context *sock,
+                               tsocket_event_handler_t handler,
+                               void *private_data);
+       int (*set_write_handler)(struct tsocket_context *sock,
+                                tsocket_event_handler_t handler,
+                                void *private_data);
+
+       /* client ops */
+       int (*connect_to)(struct tsocket_context *sock,
+                         const struct tsocket_address *remote_addr);
+
+       /* server ops */
+       int (*listen_on)(struct tsocket_context *sock,
+                        int queue_size);
+       int (*accept_new)(struct tsocket_context *sock,
+                         TALLOC_CTX *mem_ctx,
+                         struct tsocket_context **new_sock,
+                         const char *location);
+
+       /* general ops */
+       ssize_t (*pending_data)(struct tsocket_context *sock);
+
+       int (*readv_data)(struct tsocket_context *sock,
+                         const struct iovec *vector, size_t count);
+       int (*writev_data)(struct tsocket_context *sock,
+                          const struct iovec *vector, size_t count);
+
+       ssize_t (*recvfrom_data)(struct tsocket_context *sock,
+                                uint8_t *data, size_t len,
+                                TALLOC_CTX *addr_ctx,
+                                struct tsocket_address **remote_addr);
+       ssize_t (*sendto_data)(struct tsocket_context *sock,
+                              const uint8_t *data, size_t len,
+                              const struct tsocket_address *remote_addr);
+
+       /* info */
+       int (*get_status)(const struct tsocket_context *sock);
+       int (*get_local_address)(const struct tsocket_context *sock,
+                               TALLOC_CTX *mem_ctx,
+                               struct tsocket_address **local_addr,
+                               const char *location);
+       int (*get_remote_address)(const struct tsocket_context *sock,
+                                 TALLOC_CTX *mem_ctx,
+                                 struct tsocket_address **remote_addr,
+                                 const char *location);
+
+       /* options */
+       int (*get_option)(const struct tsocket_context *sock,
+                         const char *option,
+                         TALLOC_CTX *mem_ctx,
+                         char **value);
+       int (*set_option)(const struct tsocket_context *sock,
+                         const char *option,
+                         bool force,
+                         const char *value);
+
+       /* close/disconnect */
+       void (*disconnect)(struct tsocket_context *sock);
+};
+
+struct tsocket_context {
+       const char *location;
+       const struct tsocket_context_ops *ops;
+
+       void *private_data;
+
+       struct {
+               struct tevent_context *ctx;
+               void *read_private;
+               tsocket_event_handler_t read_handler;
+               void *write_private;
+               tsocket_event_handler_t write_handler;
+       } event;
+};
+
+struct tsocket_context *_tsocket_context_create(TALLOC_CTX *mem_ctx,
+                                       const struct tsocket_context_ops *ops,
+                                       void *pstate,
+                                       size_t psize,
+                                       const char *type,
+                                       const char *location);
+#define tsocket_context_create(mem_ctx, ops, state, type, location) \
+       _tsocket_context_create(mem_ctx, ops, state, sizeof(type), \
+                               #type, location)
+
+struct tsocket_address_ops {
+       const char *name;
+
+       char *(*string)(const struct tsocket_address *addr,
+                       TALLOC_CTX *mem_ctx);
+
+       struct tsocket_address *(*copy)(const struct tsocket_address *addr,
+                                       TALLOC_CTX *mem_ctx,
+                                       const char *location);
+
+       int (*create_socket)(const struct tsocket_address *addr,
+                            enum tsocket_type,
+                            TALLOC_CTX *mem_ctx,
+                            struct tsocket_context **sock,
+                            const char *location);
+};
+
+struct tsocket_address {
+       const char *location;
+       const struct tsocket_address_ops *ops;
+
+       void *private_data;
+};
+
+struct tsocket_address *_tsocket_address_create(TALLOC_CTX *mem_ctx,
+                                       const struct tsocket_address_ops *ops,
+                                       void *pstate,
+                                       size_t psize,
+                                       const char *type,
+                                       const char *location);
+#define tsocket_address_create(mem_ctx, ops, state, type, location) \
+       _tsocket_address_create(mem_ctx, ops, state, sizeof(type), \
+                               #type, location)
+
+int tsocket_error_from_errno(int ret, int sys_errno, bool *retry);
+int tsocket_simple_int_recv(struct tevent_req *req, int *perrno);
+int tsocket_common_prepare_fd(int fd, bool high_fd);
+
+#endif /* _TSOCKET_H */
+
diff --git a/lib/tsocket/tsocket_readv.c b/lib/tsocket/tsocket_readv.c
new file mode 100644 (file)
index 0000000..2c8483e
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Copyright (C) Stefan Metzmacher 2009
+
+     ** NOTE! The following LGPL license applies to the tevent
+     ** 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/network.h"
+#include "tsocket.h"
+#include "tsocket_internal.h"
+
+struct tsocket_readv_state {
+       /* this structs are owned by the caller */
+       struct {
+               struct tsocket_context *sock;
+               tsocket_readv_next_iovec_t next_iovec_fn;
+               void *private_data;
+       } caller;
+
+       /*
+        * Each call to the callback resets iov and count
+        * the callback allocated the iov as child of our state,
+        * that means we are allowed to modify and free it.
+        *
+        * we should call the callback every time we filled the given
+        * vector and ask for a new vector. We return if the callback
+        * ask for 0 bytes.
+        */
+       struct iovec *iov;
+       size_t count;
+
+       /*
+        * the total number of bytes we read,
+        * the return value of the _recv function
+        */
+       int total_read;
+};
+
+static int tsocket_readv_state_destructor(struct tsocket_readv_state *state)
+{
+       if (state->caller.sock) {
+               tsocket_set_readable_handler(state->caller.sock, NULL, NULL);
+       }
+       ZERO_STRUCT(state->caller);
+
+       return 0;
+}
+
+static bool tsocket_readv_ask_for_next_vector(struct tevent_req *req,
+                                             struct tsocket_readv_state *state)
+{
+       int ret;
+       int err;
+       bool dummy;
+       size_t to_read = 0;
+       size_t i;
+
+       talloc_free(state->iov);
+       state->iov = NULL;
+       state->count = 0;
+
+       ret = state->caller.next_iovec_fn(state->caller.sock,
+                                         state->caller.private_data,
+                                         state, &state->iov, &state->count);
+       err = tsocket_error_from_errno(ret, errno, &dummy);
+       if (tevent_req_error(req, err)) {
+               return false;
+       }
+
+       for (i=0; i < state->count; i++) {
+               size_t tmp = to_read;
+               tmp += state->iov[i].iov_len;
+
+               if (tmp < to_read) {
+                       tevent_req_error(req, EMSGSIZE);
+                       return false;
+               }
+
+               to_read = tmp;
+       }
+
+       if (to_read == 0) {
+               tevent_req_done(req);
+               return false;
+       }
+
+       if (state->total_read + to_read < state->total_read) {
+               tevent_req_error(req, EMSGSIZE);
+               return false;
+       }
+
+       return true;
+}
+
+static void tsocket_readv_handler(struct tsocket_context *sock,
+                                 void *private_data);
+
+struct tevent_req *tsocket_readv_send(struct tsocket_context *sock,
+                                     TALLOC_CTX *mem_ctx,
+                                     tsocket_readv_next_iovec_t next_iovec_fn,
+                                     void *private_data)
+{
+       struct tevent_req *req;
+       struct tsocket_readv_state *state;
+       int ret;
+       int err;
+       bool dummy;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct tsocket_readv_state);
+       if (!req) {
+               return NULL;
+       }
+
+       state->caller.sock              = sock;
+       state->caller.next_iovec_fn     = next_iovec_fn;
+       state->caller.private_data      = private_data;
+
+       state->iov              = NULL;
+       state->count            = 0;
+       state->total_read       = 0;
+
+       if (!tsocket_readv_ask_for_next_vector(req, state)) {
+               goto post;
+       }
+
+       talloc_set_destructor(state, tsocket_readv_state_destructor);
+
+       ret = tsocket_set_readable_handler(sock,
+                                          tsocket_readv_handler,
+                                          req);
+       err = tsocket_error_from_errno(ret, errno, &dummy);
+       if (tevent_req_error(req, err)) {
+               goto post;
+       }
+
+       return req;
+
+ post:
+       return tevent_req_post(req, sock->event.ctx);
+}
+
+static void tsocket_readv_handler(struct tsocket_context *sock,
+                                 void *private_data)
+{
+       struct tevent_req *req = talloc_get_type(private_data,
+                                struct tevent_req);
+       struct tsocket_readv_state *state = tevent_req_data(req,
+                                           struct tsocket_readv_state);
+       ssize_t ret;
+       int err;
+       bool retry;
+
+       ret = tsocket_readv(state->caller.sock,
+                           state->iov,
+                           state->count);
+       err = tsocket_error_from_errno(ret, errno, &retry);
+       if (retry) {
+               /* retry later */
+               return;
+       }
+       if (tevent_req_error(req, err)) {
+               return;
+       }
+
+       state->total_read += ret;
+
+       while (ret > 0) {
+               if (ret < state->iov[0].iov_len) {
+                       uint8_t *base;
+                       base = (uint8_t *)state->iov[0].iov_base;
+                       base += ret;
+                       state->iov[0].iov_base = base;
+                       state->iov[0].iov_len -= ret;
+                       break;
+               }
+               ret -= state->iov[0].iov_len;
+               state->iov += 1;
+               state->count -= 1;
+       }
+
+       if (state->count) {
+               /* we have more to read */
+               return;
+       }
+
+       /* ask the callback for a new vector we should fill */
+       tsocket_readv_ask_for_next_vector(req, state);
+}
+
+int tsocket_readv_recv(struct tevent_req *req, int *perrno)
+{
+       struct tsocket_readv_state *state = tevent_req_data(req,
+                                           struct tsocket_readv_state);
+       int ret;
+
+       ret = tsocket_simple_int_recv(req, perrno);
+       if (ret == 0) {
+               ret = state->total_read;
+       }
+
+       tevent_req_received(req);
+       return ret;
+}
+
diff --git a/lib/tsocket/tsocket_recvfrom.c b/lib/tsocket/tsocket_recvfrom.c
new file mode 100644 (file)
index 0000000..467738c
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Copyright (C) Stefan Metzmacher 2009
+
+     ** NOTE! The following LGPL license applies to the tevent
+     ** 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/network.h"
+#include "tsocket.h"
+#include "tsocket_internal.h"
+
+struct tsocket_recvfrom_state {
+       /* this structs are owned by the caller */
+       struct {
+               struct tsocket_context *sock;
+       } caller;
+
+       uint8_t *buf;
+       size_t len;
+       struct tsocket_address *src;
+};
+
+static int tsocket_recvfrom_state_destructor(struct tsocket_recvfrom_state *state)
+{
+       if (state->caller.sock) {
+               tsocket_set_readable_handler(state->caller.sock, NULL, NULL);
+       }
+       ZERO_STRUCT(state->caller);
+
+       return 0;
+}
+
+static void tsocket_recvfrom_handler(struct tsocket_context *sock,
+                                    void *private_data);
+
+struct tevent_req *tsocket_recvfrom_send(struct tsocket_context *sock,
+                                        TALLOC_CTX *mem_ctx)
+{
+       struct tevent_req *req;
+       struct tsocket_recvfrom_state *state;
+       int ret;
+       int err;
+       bool dummy;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct tsocket_recvfrom_state);
+       if (!req) {
+               return NULL;
+       }
+
+       state->caller.sock      = sock;
+       state->buf              = NULL;
+       state->len              = 0;
+       state->src              = NULL;
+
+       talloc_set_destructor(state, tsocket_recvfrom_state_destructor);
+
+       ret = tsocket_set_readable_handler(sock,
+                                          tsocket_recvfrom_handler,
+                                          req);
+       err = tsocket_error_from_errno(ret, errno, &dummy);
+       if (tevent_req_error(req, err)) {
+               goto post;
+       }
+
+       return req;
+
+ post:
+       return tevent_req_post(req, sock->event.ctx);
+}
+
+static void tsocket_recvfrom_handler(struct tsocket_context *sock,
+                                    void *private_data)
+{
+       struct tevent_req *req = talloc_get_type(private_data,
+                                struct tevent_req);
+       struct tsocket_recvfrom_state *state = tevent_req_data(req,
+                                              struct tsocket_recvfrom_state);
+       ssize_t ret;
+       int err;
+       bool retry;
+
+       ret = tsocket_pending(state->caller.sock);
+       if (ret == 0) {
+               /* retry later */
+               return;
+       }
+       err = tsocket_error_from_errno(ret, errno, &retry);
+       if (retry) {
+               /* retry later */
+               return;
+       }
+       if (tevent_req_error(req, err)) {
+               return;
+       }
+
+       state->buf = talloc_array(state, uint8_t, ret);
+       if (tevent_req_nomem(state->buf, req)) {
+               return;
+       }
+       state->len = ret;
+
+       ret = tsocket_recvfrom(state->caller.sock,
+                              state->buf,
+                              state->len,
+                              state,
+                              &state->src);
+       err = tsocket_error_from_errno(ret, errno, &retry);
+       if (retry) {
+               /* retry later */
+               return;
+       }
+       if (tevent_req_error(req, err)) {
+               return;
+       }
+
+       if (ret != state->len) {
+               tevent_req_error(req, EIO);
+               return;
+       }
+
+       tevent_req_done(req);
+}
+
+ssize_t tsocket_recvfrom_recv(struct tevent_req *req,
+                             int *perrno,
+                             TALLOC_CTX *mem_ctx,
+                             uint8_t **buf,
+                             struct tsocket_address **src)
+{
+       struct tsocket_recvfrom_state *state = tevent_req_data(req,
+                                              struct tsocket_recvfrom_state);
+       ssize_t ret;
+
+       ret = tsocket_simple_int_recv(req, perrno);
+       if (ret == 0) {
+               *buf = talloc_move(mem_ctx, &state->buf);
+               ret = state->len;
+               if (src) {
+                       *src = talloc_move(mem_ctx, &state->src);
+               }
+       }
+
+       tevent_req_received(req);
+       return ret;
+}
+
diff --git a/lib/tsocket/tsocket_sendto.c b/lib/tsocket/tsocket_sendto.c
new file mode 100644 (file)
index 0000000..9c0a76b
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Copyright (C) Stefan Metzmacher 2009
+
+     ** NOTE! The following LGPL license applies to the tevent
+     ** 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/network.h"
+#include "tsocket.h"
+#include "tsocket_internal.h"
+
+struct tsocket_sendto_state {
+       /* this structs are owned by the caller */
+       struct {
+               struct tsocket_context *sock;
+               const uint8_t *buf;
+               size_t len;
+               const struct tsocket_address *dst;
+       } caller;
+
+       ssize_t ret;
+};
+
+static int tsocket_sendto_state_destructor(struct tsocket_sendto_state *state)
+{
+       if (state->caller.sock) {
+               tsocket_set_writeable_handler(state->caller.sock, NULL, NULL);
+       }
+       ZERO_STRUCT(state->caller);
+
+       return 0;
+}
+
+static void tsocket_sendto_handler(struct tsocket_context *sock,
+                                  void *private_data);
+
+struct tevent_req *tsocket_sendto_send(struct tsocket_context *sock,
+                                      TALLOC_CTX *mem_ctx,
+                                      const uint8_t *buf,
+                                      size_t len,
+                                      const struct tsocket_address *dst)
+{
+       struct tevent_req *req;
+       struct tsocket_sendto_state *state;
+       int ret;
+       int err;
+       bool dummy;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct tsocket_sendto_state);
+       if (!req) {
+               return NULL;
+       }
+
+       state->caller.sock      = sock;
+       state->caller.buf       = buf;
+       state->caller.len       = len;
+       state->caller.dst       = dst;
+       state->ret              = -1;
+
+       /*
+        * this is a fast path, not waiting for the
+        * socket to become explicit writeable gains
+        * about 10%-20% performance in benchmark tests.
+        */
+       tsocket_sendto_handler(sock, req);
+       if (!tevent_req_is_in_progress(req)) {
+               goto post;
+       }
+
+       talloc_set_destructor(state, tsocket_sendto_state_destructor);
+
+       ret = tsocket_set_writeable_handler(sock,
+                                           tsocket_sendto_handler,
+                                           req);
+       err = tsocket_error_from_errno(ret, errno, &dummy);
+       if (tevent_req_error(req, err)) {
+               goto post;
+       }
+
+       return req;
+
+ post:
+       return tevent_req_post(req, sock->event.ctx);
+}
+
+static void tsocket_sendto_handler(struct tsocket_context *sock,
+                                  void *private_data)
+{
+       struct tevent_req *req = talloc_get_type(private_data,
+                                struct tevent_req);
+       struct tsocket_sendto_state *state = tevent_req_data(req,
+                                            struct tsocket_sendto_state);
+       ssize_t ret;
+       int err;
+       bool retry;
+
+       ret = tsocket_sendto(state->caller.sock,
+                            state->caller.buf,
+                            state->caller.len,
+                            state->caller.dst);
+       err = tsocket_error_from_errno(ret, errno, &retry);
+       if (retry) {
+               /* retry later */
+               return;
+       }
+       if (tevent_req_error(req, err)) {
+               return;
+       }
+
+       state->ret = ret;
+
+       tevent_req_done(req);
+}
+
+ssize_t tsocket_sendto_recv(struct tevent_req *req, int *perrno)
+{
+       struct tsocket_sendto_state *state = tevent_req_data(req,
+                                            struct tsocket_sendto_state);
+       ssize_t ret;
+
+       ret = tsocket_simple_int_recv(req, perrno);
+       if (ret == 0) {
+               ret = state->ret;
+       }
+
+       tevent_req_received(req);
+       return ret;
+}
+
+struct tsocket_sendto_queue_state {
+       /* this structs are owned by the caller */
+       struct {
+               struct tsocket_context *sock;
+               const uint8_t *buf;
+               size_t len;
+               const struct tsocket_address *dst;
+       } caller;
+       ssize_t ret;
+};
+
+static void tsocket_sendto_queue_trigger(struct tevent_req *req,
+                                        void *private_data);
+static void tsocket_sendto_queue_done(struct tevent_req *subreq);
+
+/**
+ * @brief Queue a dgram blob for sending through the socket
+ * @param[in] mem_ctx  The memory context for the result
+ * @param[in] sock     The socket to send the message buffer
+ * @param[in] queue    The existing dgram queue
+ * @param[in] buf      The message buffer
+ * @param[in] len      The message length
+ * @param[in] dst      The destination socket address
+ * @retval             The async request handle
+ *
+ * This function queues a blob for sending to destination through an existing
+ * dgram socket. The async callback is triggered when the whole blob is
+ * delivered to the underlying system socket.
+ *
+ * The caller needs to make sure that all non-scalar input parameters hang
+ * arround for the whole lifetime of the request.
+ */
+struct tevent_req *tsocket_sendto_queue_send(TALLOC_CTX *mem_ctx,
+                                            struct tsocket_context *sock,
+                                            struct tevent_queue *queue,
+                                            const uint8_t *buf,
+                                            size_t len,
+                                            struct tsocket_address *dst)
+{
+       struct tevent_req *req;
+       struct tsocket_sendto_queue_state *state;
+       bool ok;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct tsocket_sendto_queue_state);
+       if (!req) {
+               return NULL;
+       }
+
+       state->caller.sock      = sock;
+       state->caller.buf       = buf;
+       state->caller.len       = len;
+       state->caller.dst       = dst;
+       state->ret              = -1;
+
+       ok = tevent_queue_add(queue,
+                             sock->event.ctx,
+                             req,
+                             tsocket_sendto_queue_trigger,
+                             NULL);
+       if (!ok) {
+               tevent_req_nomem(NULL, req);
+               goto post;
+       }
+
+       return req;
+
+ post:
+       return tevent_req_post(req, sock->event.ctx);
+}
+
+static void tsocket_sendto_queue_trigger(struct tevent_req *req,
+                                        void *private_data)
+{
+       struct tsocket_sendto_queue_state *state = tevent_req_data(req,
+                                       struct tsocket_sendto_queue_state);
+       struct tevent_req *subreq;
+
+       subreq = tsocket_sendto_send(state->caller.sock,
+                                    state,
+                                    state->caller.buf,
+                                    state->caller.len,
+                                    state->caller.dst);
+       if (tevent_req_nomem(subreq, req)) {
+               return;
+       }
+       tevent_req_set_callback(subreq, tsocket_sendto_queue_done ,req);
+}
+
+static void tsocket_sendto_queue_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(subreq,
+                                struct tevent_req);
+       struct tsocket_sendto_queue_state *state = tevent_req_data(req,
+                                       struct tsocket_sendto_queue_state);
+       ssize_t ret;
+       int sys_errno;
+
+       ret = tsocket_sendto_recv(subreq, &sys_errno);
+       talloc_free(subreq);
+       if (ret == -1) {
+               tevent_req_error(req, sys_errno);
+               return;
+       }
+       state->ret = ret;
+
+       tevent_req_done(req);
+}
+
+ssize_t tsocket_sendto_queue_recv(struct tevent_req *req, int *perrno)
+{
+       struct tsocket_sendto_queue_state *state = tevent_req_data(req,
+                                       struct tsocket_sendto_queue_state);
+       ssize_t ret;
+
+       ret = tsocket_simple_int_recv(req, perrno);
+       if (ret == 0) {
+               ret = state->ret;
+       }
+
+       tevent_req_received(req);
+       return ret;
+}
+
diff --git a/lib/tsocket/tsocket_writev.c b/lib/tsocket/tsocket_writev.c
new file mode 100644 (file)
index 0000000..8c5cd40
--- /dev/null
@@ -0,0 +1,316 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Copyright (C) Stefan Metzmacher 2009
+
+     ** NOTE! The following LGPL license applies to the tevent
+     ** 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/network.h"
+#include "tsocket.h"
+#include "tsocket_internal.h"
+
+struct tsocket_writev_state {
+       /* this structs are owned by the caller */
+       struct {
+               struct tsocket_context *sock;
+               const struct iovec *vector;
+               size_t count;
+       } caller;
+
+       struct iovec *iov;
+       size_t count;
+       int total_written;
+};
+
+static int tsocket_writev_state_destructor(struct tsocket_writev_state *state)
+{
+       if (state->caller.sock) {
+               tsocket_set_writeable_handler(state->caller.sock, NULL, NULL);
+       }
+       ZERO_STRUCT(state->caller);
+
+       return 0;
+}
+
+static void tsocket_writev_handler(struct tsocket_context *sock,
+                                  void *private_data);
+
+struct tevent_req *tsocket_writev_send(struct tsocket_context *sock,
+                                      TALLOC_CTX *mem_ctx,
+                                      const struct iovec *vector,
+                                      size_t count)
+{
+       struct tevent_req *req;
+       struct tsocket_writev_state *state;
+       int ret;
+       int err;
+       bool dummy;
+       int to_write = 0;
+       size_t i;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct tsocket_writev_state);
+       if (!req) {
+               return NULL;
+       }
+
+       state->caller.sock      = sock;
+       state->caller.vector    = vector;
+       state->caller.count     = count;
+
+       state->iov              = NULL;
+       state->count            = count;
+       state->total_written    = 0;
+
+       state->iov = talloc_array(state, struct iovec, count);
+       if (tevent_req_nomem(state->iov, req)) {
+               goto post;
+       }
+       memcpy(state->iov, vector, sizeof(struct iovec) * count);
+
+       for (i=0; i < count; i++) {
+               int tmp = to_write;
+
+               tmp += state->iov[i].iov_len;
+
+               if (tmp < to_write) {
+                       tevent_req_error(req, EMSGSIZE);
+                       goto post;
+               }
+
+               to_write = tmp;
+       }
+
+       if (to_write == 0) {
+               tevent_req_done(req);
+               goto post;
+       }
+
+       /*
+        * this is a fast path, not waiting for the
+        * socket to become explicit writeable gains
+        * about 10%-20% performance in benchmark tests.
+        */
+       tsocket_writev_handler(sock, req);
+       if (!tevent_req_is_in_progress(req)) {
+               goto post;
+       }
+
+       talloc_set_destructor(state, tsocket_writev_state_destructor);
+
+       ret = tsocket_set_writeable_handler(sock,
+                                           tsocket_writev_handler,
+                                           req);
+       err = tsocket_error_from_errno(ret, errno, &dummy);
+       if (tevent_req_error(req, err)) {
+               goto post;
+       }
+
+       return req;
+
+ post:
+       return tevent_req_post(req, sock->event.ctx);
+}
+
+static void tsocket_writev_handler(struct tsocket_context *sock,
+                                  void *private_data)
+{
+       struct tevent_req *req = talloc_get_type(private_data,
+                                struct tevent_req);
+       struct tsocket_writev_state *state = tevent_req_data(req,
+                                            struct tsocket_writev_state);
+       int ret;
+       int err;
+       bool retry;
+
+       ret = tsocket_writev(state->caller.sock,
+                            state->iov,
+                            state->count);
+       err = tsocket_error_from_errno(ret, errno, &retry);
+       if (retry) {
+               /* retry later */
+               return;
+       }
+       if (tevent_req_error(req, err)) {
+               return;
+       }
+
+       state->total_written += ret;
+
+       /*
+        * we have not written everything yet, so we need to truncate
+        * the already written bytes from our iov copy
+        */
+       while (ret > 0) {
+               if (ret < state->iov[0].iov_len) {
+                       uint8_t *base;
+                       base = (uint8_t *)state->iov[0].iov_base;
+                       base += ret;
+                       state->iov[0].iov_base = base;
+                       state->iov[0].iov_len -= ret;
+                       break;
+               }
+               ret -= state->iov[0].iov_len;
+               state->iov += 1;
+               state->count -= 1;
+       }
+
+       if (state->count > 0) {
+               /* more to write */
+               return;
+       }
+
+       tevent_req_done(req);
+}
+
+int tsocket_writev_recv(struct tevent_req *req, int *perrno)
+{
+       struct tsocket_writev_state *state = tevent_req_data(req,
+                                            struct tsocket_writev_state);
+       int ret;
+
+       ret = tsocket_simple_int_recv(req, perrno);
+       if (ret == 0) {
+               ret = state->total_written;
+       }
+
+       tevent_req_received(req);
+       return ret;
+}
+
+struct tsocket_writev_queue_state {
+       /* this structs are owned by the caller */
+       struct {
+               struct tsocket_context *sock;
+               const struct iovec *vector;
+               size_t count;
+       } caller;
+       int ret;
+};
+
+static void tsocket_writev_queue_trigger(struct tevent_req *req,
+                                        void *private_data);
+static void tsocket_writev_queue_done(struct tevent_req *subreq);
+
+/**
+ * @brief Queue a dgram blob for sending through the socket
+ * @param[in] mem_ctx  The memory context for the result
+ * @param[in] sock     The socket to send data through
+ * @param[in] queue    The existing send queue
+ * @param[in] vector   The iovec vector so write
+ * @param[in] count    The size of the vector
+ * @retval             The async request handle
+ *
+ * This function queues a blob for sending to destination through an existing
+ * dgram socket. The async callback is triggered when the whole blob is
+ * delivered to the underlying system socket.
+ *
+ * The caller needs to make sure that all non-scalar input parameters hang
+ * arround for the whole lifetime of the request.
+ */
+struct tevent_req *tsocket_writev_queue_send(TALLOC_CTX *mem_ctx,
+                                            struct tsocket_context *sock,
+                                            struct tevent_queue *queue,
+                                            const struct iovec *vector,
+                                            size_t count)
+{
+       struct tevent_req *req;
+       struct tsocket_writev_queue_state *state;
+       bool ok;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct tsocket_writev_queue_state);
+       if (!req) {
+               return NULL;
+       }
+
+       state->caller.sock      = sock;
+       state->caller.vector    = vector;
+       state->caller.count     = count;
+       state->ret              = -1;
+
+       ok = tevent_queue_add(queue,
+                             sock->event.ctx,
+                             req,
+                             tsocket_writev_queue_trigger,
+                             NULL);
+       if (!ok) {
+               tevent_req_nomem(NULL, req);
+               goto post;
+       }
+
+       return req;
+
+ post:
+       return tevent_req_post(req, sock->event.ctx);
+}
+
+static void tsocket_writev_queue_trigger(struct tevent_req *req,
+                                        void *private_data)
+{
+       struct tsocket_writev_queue_state *state = tevent_req_data(req,
+                                       struct tsocket_writev_queue_state);
+       struct tevent_req *subreq;
+
+       subreq = tsocket_writev_send(state->caller.sock,
+                                    state,
+                                    state->caller.vector,
+                                    state->caller.count);
+       if (tevent_req_nomem(subreq, req)) {
+               return;
+       }
+       tevent_req_set_callback(subreq, tsocket_writev_queue_done ,req);
+}
+
+static void tsocket_writev_queue_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(subreq,
+                                struct tevent_req);
+       struct tsocket_writev_queue_state *state = tevent_req_data(req,
+                                       struct tsocket_writev_queue_state);
+       int ret;
+       int sys_errno;
+
+       ret = tsocket_writev_recv(subreq, &sys_errno);
+       talloc_free(subreq);
+       if (ret == -1) {
+               tevent_req_error(req, sys_errno);
+               return;
+       }
+       state->ret = ret;
+
+       tevent_req_done(req);
+}
+
+int tsocket_writev_queue_recv(struct tevent_req *req, int *perrno)
+{
+       struct tsocket_writev_queue_state *state = tevent_req_data(req,
+                                       struct tsocket_writev_queue_state);
+       int ret;
+
+       ret = tsocket_simple_int_recv(req, perrno);
+       if (ret == 0) {
+               ret = state->ret;
+       }
+
+       tevent_req_received(req);
+       return ret;
+}
+
index 14bdb2a2776d91756307497ad27236ed182f5ea4..7835fed911869a5aced8c922e4e0ccf25ad3da87 100644 (file)
@@ -5,7 +5,7 @@ PUBLIC_DEPENDENCIES = \
                CHARSET EXECINFO
 
 LIBSAMBA-UTIL_OBJ_FILES = $(addprefix $(libutilsrcdir)/, \
-       xfile.o \
+               xfile.o \
                debug.o \
                fault.o \
                signal.o \
@@ -68,6 +68,13 @@ PUBLIC_DEPENDENCIES = LIBTDB
 
 UTIL_TDB_OBJ_FILES = $(libutilsrcdir)/util_tdb.o
 
+[SUBSYSTEM::UTIL_TEVENT]
+PUBLIC_DEPENDENCIES = LIBTEVENT
+
+UTIL_TEVENT_OBJ_FILES = $(addprefix $(libutilsrcdir)/, \
+                       tevent_unix.o \
+                       tevent_ntstatus.o)
+
 [SUBSYSTEM::UTIL_LDB]
 PUBLIC_DEPENDENCIES = LIBLDB
 
diff --git a/libcli/cldap/cldap.c b/libcli/cldap/cldap.c
new file mode 100644 (file)
index 0000000..561ae80
--- /dev/null
@@ -0,0 +1,1125 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   cldap client library
+
+   Copyright (C) Andrew Tridgell 2005
+   Copyright (C) Stefan Metzmacher 2009
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program 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 General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+  see RFC1798 for details of CLDAP
+
+  basic properties
+    - carried over UDP on port 389
+    - request and response matched by message ID
+    - request consists of only a single searchRequest element
+    - response can be in one of two forms
+       - a single searchResponse, followed by a searchResult
+       - a single searchResult
+*/
+
+#include "includes.h"
+#include <tevent.h>
+#include "../lib/util/dlinklist.h"
+#include "../libcli/ldap/ldap_message.h"
+#include "../libcli/ldap/ldap_ndr.h"
+#include "../libcli/cldap/cldap.h"
+#include "../lib/tsocket/tsocket.h"
+#include "../libcli/security/dom_sid.h"
+#include "../librpc/gen_ndr/ndr_nbt.h"
+#include "../lib/util/asn1.h"
+#include "../lib/util/tevent_ntstatus.h"
+
+#undef strcasecmp
+
+/*
+  context structure for operations on cldap packets
+*/
+struct cldap_socket {
+       /* the low level socket */
+       struct tsocket_context *sock;
+
+       /*
+        * Are we in connected mode, which means
+        * we get ICMP errors back instead of timing
+        * out requests. And we can only send requests
+        * to the connected peer.
+        */
+       bool connected;
+
+       /*
+        * we allow sync requests only, if the caller
+        * did not pass an event context to cldap_socket_init()
+        */
+       struct {
+               bool allow_poll;
+               struct tevent_context *ctx;
+       } event;
+
+       /* the queue for outgoing dgrams */
+       struct tevent_queue *send_queue;
+
+       /* do we have an async tsocket_recvfrom request pending */
+       struct tevent_req *recv_subreq;
+
+       struct {
+               /* a queue of pending search requests */
+               struct cldap_search_state *list;
+
+               /* mapping from message_id to pending request */
+               struct idr_context *idr;
+       } searches;
+
+       /* what to do with incoming request packets */
+       struct {
+               void (*handler)(struct cldap_socket *,
+                               void *private_data,
+                               struct cldap_incoming *);
+               void *private_data;
+       } incoming;
+};
+
+struct cldap_search_state {
+       struct cldap_search_state *prev, *next;
+
+       struct {
+               struct cldap_socket *cldap;
+       } caller;
+
+       int message_id;
+
+       struct {
+               uint32_t idx;
+               uint32_t delay;
+               uint32_t count;
+               struct tsocket_address *dest;
+               DATA_BLOB blob;
+       } request;
+
+       struct {
+               struct cldap_incoming *in;
+               struct asn1_data *asn1;
+       } response;
+
+       struct tevent_req *req;
+};
+
+static int cldap_socket_destructor(struct cldap_socket *c)
+{
+       tsocket_disconnect(c->sock);
+
+       while (c->searches.list) {
+               struct cldap_search_state *s = c->searches.list;
+               DLIST_REMOVE(c->searches.list, s);
+               ZERO_STRUCT(s->caller);
+       }
+
+       talloc_free(c->recv_subreq);
+       talloc_free(c->send_queue);
+       talloc_free(c->sock);
+       return 0;
+}
+
+static void cldap_recvfrom_done(struct tevent_req *subreq);
+
+static bool cldap_recvfrom_setup(struct cldap_socket *c)
+{
+       if (c->recv_subreq) {
+               return true;
+       }
+
+       if (!c->searches.list && !c->incoming.handler) {
+               return true;
+       }
+
+       c->recv_subreq = tsocket_recvfrom_send(c->sock, c);
+       if (!c->recv_subreq) {
+               return false;
+       }
+       tevent_req_set_callback(c->recv_subreq, cldap_recvfrom_done, c);
+
+       return true;
+}
+
+static void cldap_recvfrom_stop(struct cldap_socket *c)
+{
+       if (!c->recv_subreq) {
+               return;
+       }
+
+       if (c->searches.list || c->incoming.handler) {
+               return;
+       }
+
+       talloc_free(c->recv_subreq);
+       c->recv_subreq = NULL;
+}
+
+static void cldap_socket_recv_dgram(struct cldap_socket *c,
+                                   struct cldap_incoming *in);
+
+static void cldap_recvfrom_done(struct tevent_req *subreq)
+{
+       struct cldap_socket *c = tevent_req_callback_data(subreq,
+                                struct cldap_socket);
+       struct cldap_incoming *in = NULL;
+       ssize_t ret;
+
+       c->recv_subreq = NULL;
+
+       in = talloc_zero(c, struct cldap_incoming);
+       if (!in) {
+               goto nomem;
+       }
+
+       ret = tsocket_recvfrom_recv(subreq,
+                                   &in->recv_errno,
+                                   in,
+                                   &in->buf,
+                                   &in->src);
+       talloc_free(subreq);
+       subreq = NULL;
+       if (ret >= 0) {
+               in->len = ret;
+       }
+       if (ret == -1 && in->recv_errno == 0) {
+               in->recv_errno = EIO;
+       }
+
+       /* this function should free or steal 'in' */
+       cldap_socket_recv_dgram(c, in);
+       in = NULL;
+
+       if (!cldap_recvfrom_setup(c)) {
+               goto nomem;
+       }
+
+       return;
+
+nomem:
+       talloc_free(subreq);
+       talloc_free(in);
+       /*TODO: call a dead socket handler */
+       return;
+}
+
+/*
+  handle recv events on a cldap socket
+*/
+static void cldap_socket_recv_dgram(struct cldap_socket *c,
+                                   struct cldap_incoming *in)
+{
+       DATA_BLOB blob;
+       struct asn1_data *asn1;
+       void *p;
+       struct cldap_search_state *search;
+       NTSTATUS status;
+
+       if (in->recv_errno != 0) {
+               goto error;
+       }
+
+       blob = data_blob_const(in->buf, in->len);
+
+       asn1 = asn1_init(in);
+       if (!asn1) {
+               goto nomem;
+       }
+
+       if (!asn1_load(asn1, blob)) {
+               goto nomem;
+       }
+
+       in->ldap_msg = talloc(in, struct ldap_message);
+       if (in->ldap_msg == NULL) {
+               goto nomem;
+       }
+
+       /* this initial decode is used to find the message id */
+       status = ldap_decode(asn1, NULL, in->ldap_msg);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto nterror;
+       }
+
+       /* find the pending request */
+       p = idr_find(c->searches.idr, in->ldap_msg->messageid);
+       if (p == NULL) {
+               if (!c->incoming.handler) {
+                       goto done;
+               }
+
+               /* this function should free or steal 'in' */
+               c->incoming.handler(c, c->incoming.private_data, in);
+               return;
+       }
+
+       search = talloc_get_type(p, struct cldap_search_state);
+       search->response.in = talloc_move(search, &in);
+       search->response.asn1 = asn1;
+       search->response.asn1->ofs = 0;
+
+       tevent_req_done(search->req);
+       goto done;
+
+nomem:
+       in->recv_errno = ENOMEM;
+error:
+       status = map_nt_error_from_unix(in->recv_errno);
+nterror:
+       /* in connected mode the first pending search gets the error */
+       if (!c->connected) {
+               /* otherwise we just ignore the error */
+               goto done;
+       }
+       if (!c->searches.list) {
+               goto done;
+       }
+       tevent_req_nterror(c->searches.list->req, status);
+done:
+       talloc_free(in);
+}
+
+/*
+  initialise a cldap_sock
+*/
+NTSTATUS cldap_socket_init(TALLOC_CTX *mem_ctx,
+                          struct tevent_context *ev,
+                          const struct tsocket_address *local_addr,
+                          const struct tsocket_address *remote_addr,
+                          struct cldap_socket **_cldap)
+{
+       struct cldap_socket *c = NULL;
+       struct tsocket_address *any = NULL;
+       NTSTATUS status;
+       int ret;
+
+       c = talloc_zero(mem_ctx, struct cldap_socket);
+       if (!c) {
+               goto nomem;
+       }
+
+       if (!ev) {
+               ev = tevent_context_init(c);
+               if (!ev) {
+                       goto nomem;
+               }
+               c->event.allow_poll = true;
+       }
+       c->event.ctx = ev;
+
+       if (!local_addr) {
+               ret = tsocket_address_inet_from_strings(c, "ipv4",
+                                                       NULL, 0,
+                                                       &any);
+               if (ret != 0) {
+                       status = map_nt_error_from_unix(errno);
+                       goto nterror;
+               }
+               local_addr = any;
+       }
+
+       c->searches.idr = idr_init(c);
+       if (!c->searches.idr) {
+               goto nomem;
+       }
+
+       ret = tsocket_address_create_socket(local_addr,
+                                           TSOCKET_TYPE_DGRAM,
+                                           c, &c->sock);
+       if (ret != 0) {
+               status = map_nt_error_from_unix(errno);
+               goto nterror;
+       }
+       talloc_free(any);
+
+       tsocket_set_event_context(c->sock, c->event.ctx);
+
+       if (remote_addr) {
+               ret = tsocket_connect(c->sock, remote_addr);
+               if (ret != 0) {
+                       status = map_nt_error_from_unix(errno);
+                       goto nterror;
+               }
+               c->connected = true;
+       }
+
+       c->send_queue = tevent_queue_create(c, "cldap_send_queue");
+       if (!c->send_queue) {
+               goto nomem;
+       }
+
+       talloc_set_destructor(c, cldap_socket_destructor);
+
+       *_cldap = c;
+       return NT_STATUS_OK;
+
+nomem:
+       status = NT_STATUS_NO_MEMORY;
+nterror:
+       talloc_free(c);
+       return status;
+}
+
+/*
+  setup a handler for incoming requests
+*/
+NTSTATUS cldap_set_incoming_handler(struct cldap_socket *c,
+                                   void (*handler)(struct cldap_socket *,
+                                                   void *private_data,
+                                                   struct cldap_incoming *),
+                                   void *private_data)
+{
+       if (c->connected) {
+               return NT_STATUS_PIPE_CONNECTED;
+       }
+
+       /* if sync requests are allowed, we don't allow an incoming handler */
+       if (c->event.allow_poll) {
+               return NT_STATUS_INVALID_PIPE_STATE;
+       }
+
+       c->incoming.handler = handler;
+       c->incoming.private_data = private_data;
+
+       if (!cldap_recvfrom_setup(c)) {
+               ZERO_STRUCT(c->incoming);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       return NT_STATUS_OK;
+}
+
+struct cldap_reply_state {
+       struct tsocket_address *dest;
+       DATA_BLOB blob;
+};
+
+static void cldap_reply_state_destroy(struct tevent_req *req);
+
+/*
+  queue a cldap reply for send
+*/
+NTSTATUS cldap_reply_send(struct cldap_socket *cldap, struct cldap_reply *io)
+{
+       struct cldap_reply_state *state = NULL;
+       struct ldap_message *msg;
+       DATA_BLOB blob1, blob2;
+       NTSTATUS status;
+       struct tevent_req *req;
+
+       if (cldap->connected) {
+               return NT_STATUS_PIPE_CONNECTED;
+       }
+
+       if (!io->dest) {
+               return NT_STATUS_INVALID_ADDRESS;
+       }
+
+       state = talloc(cldap, struct cldap_reply_state);
+       NT_STATUS_HAVE_NO_MEMORY(state);
+
+       state->dest = tsocket_address_copy(io->dest, state);
+       if (!state->dest) {
+               goto nomem;
+       }
+
+       msg = talloc(state, struct ldap_message);
+       if (!msg) {
+               goto nomem;
+       }
+
+       msg->messageid       = io->messageid;
+       msg->controls        = NULL;
+
+       if (io->response) {
+               msg->type = LDAP_TAG_SearchResultEntry;
+               msg->r.SearchResultEntry = *io->response;
+
+               if (!ldap_encode(msg, NULL, &blob1, state)) {
+                       status = NT_STATUS_INVALID_PARAMETER;
+                       goto failed;
+               }
+       } else {
+               blob1 = data_blob(NULL, 0);
+       }
+
+       msg->type = LDAP_TAG_SearchResultDone;
+       msg->r.SearchResultDone = *io->result;
+
+       if (!ldap_encode(msg, NULL, &blob2, state)) {
+               status = NT_STATUS_INVALID_PARAMETER;
+               goto failed;
+       }
+       talloc_free(msg);
+
+       state->blob = data_blob_talloc(state, NULL, blob1.length + blob2.length);
+       if (!state->blob.data) {
+               goto nomem;
+       }
+
+       memcpy(state->blob.data, blob1.data, blob1.length);
+       memcpy(state->blob.data+blob1.length, blob2.data, blob2.length);
+       data_blob_free(&blob1);
+       data_blob_free(&blob2);
+
+       req = tsocket_sendto_queue_send(state,
+                                       cldap->sock,
+                                       cldap->send_queue,
+                                       state->blob.data,
+                                       state->blob.length,
+                                       state->dest);
+       if (!req) {
+               goto nomem;
+       }
+       /* the callback will just free the state, as we don't need a result */
+       tevent_req_set_callback(req, cldap_reply_state_destroy, state);
+
+       return NT_STATUS_OK;
+
+nomem:
+       status = NT_STATUS_NO_MEMORY;
+failed:
+       talloc_free(state);
+       return status;
+}
+
+static void cldap_reply_state_destroy(struct tevent_req *req)
+{
+       struct cldap_reply_state *state = tevent_req_callback_data(req,
+                                         struct cldap_reply_state);
+
+       /* we don't want to know the result here, we just free the state */
+       talloc_free(req);
+       talloc_free(state);
+}
+
+static int cldap_search_state_destructor(struct cldap_search_state *s)
+{
+       if (s->caller.cldap) {
+               DLIST_REMOVE(s->caller.cldap->searches.list, s);
+               cldap_recvfrom_stop(s->caller.cldap);
+               ZERO_STRUCT(s->caller);
+       }
+
+       return 0;
+}
+
+static void cldap_search_state_queue_done(struct tevent_req *subreq);
+static void cldap_search_state_wakeup_done(struct tevent_req *subreq);
+
+/*
+  queue a cldap reply for send
+*/
+struct tevent_req *cldap_search_send(TALLOC_CTX *mem_ctx,
+                                   struct cldap_socket *cldap,
+                                   const struct cldap_search *io)
+{
+       struct tevent_req *req, *subreq;
+       struct cldap_search_state *state = NULL;
+       struct ldap_message *msg;
+       struct ldap_SearchRequest *search;
+       struct timeval now;
+       struct timeval end;
+       uint32_t i;
+       int ret;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct cldap_search_state);
+       if (!req) {
+               return NULL;
+       }
+       state->req = req;
+       state->caller.cldap = cldap;
+
+       if (io->in.dest_address) {
+               if (cldap->connected) {
+                       tevent_req_nterror(req, NT_STATUS_PIPE_CONNECTED);
+                       goto post;
+               }
+               ret = tsocket_address_inet_from_strings(state,
+                                                       "ipv4",
+                                                       io->in.dest_address,
+                                                       io->in.dest_port,
+                                                       &state->request.dest);
+               if (ret != 0) {
+                       tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+                       goto post;
+               }
+       } else {
+               if (!cldap->connected) {
+                       tevent_req_nterror(req, NT_STATUS_INVALID_ADDRESS);
+                       goto post;
+               }
+               state->request.dest = NULL;
+       }
+
+       state->message_id = idr_get_new_random(cldap->searches.idr,
+                                              state, UINT16_MAX);
+       if (state->message_id == -1) {
+               tevent_req_nterror(req, NT_STATUS_INSUFFICIENT_RESOURCES);
+               goto post;
+       }
+
+       msg = talloc(state, struct ldap_message);
+       if (tevent_req_nomem(msg, req)) {
+               goto post;
+       }
+
+       msg->messageid  = state->message_id;
+       msg->type       = LDAP_TAG_SearchRequest;
+       msg->controls   = NULL;
+       search = &msg->r.SearchRequest;
+
+       search->basedn          = "";
+       search->scope           = LDAP_SEARCH_SCOPE_BASE;
+       search->deref           = LDAP_DEREFERENCE_NEVER;
+       search->timelimit       = 0;
+       search->sizelimit       = 0;
+       search->attributesonly  = false;
+       search->num_attributes  = str_list_length(io->in.attributes);
+       search->attributes      = io->in.attributes;
+       search->tree            = ldb_parse_tree(msg, io->in.filter);
+       if (tevent_req_nomem(search->tree, req)) {
+               goto post;
+       }
+
+       if (!ldap_encode(msg, NULL, &state->request.blob, state)) {
+               tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+               goto post;
+       }
+       talloc_free(msg);
+
+       state->request.idx = 0;
+       state->request.delay = 10*1000*1000;
+       state->request.count = 3;
+       if (io->in.timeout > 0) {
+               state->request.delay = io->in.timeout * 1000 * 1000;
+               state->request.count = io->in.retries + 1;
+       }
+
+       now = tevent_timeval_current();
+       end = now;
+       for (i = 0; i < state->request.count; i++) {
+               end = tevent_timeval_add(&end, 0, state->request.delay);
+       }
+
+       if (!tevent_req_set_endtime(req, state->caller.cldap->event.ctx, end)) {
+               tevent_req_nomem(NULL, req);
+               goto post;
+       }
+
+       subreq = tsocket_sendto_queue_send(state,
+                                          state->caller.cldap->sock,
+                                          state->caller.cldap->send_queue,
+                                          state->request.blob.data,
+                                          state->request.blob.length,
+                                          state->request.dest);
+       if (tevent_req_nomem(subreq, req)) {
+               goto post;
+       }
+       tevent_req_set_callback(subreq, cldap_search_state_queue_done, req);
+
+       DLIST_ADD_END(cldap->searches.list, state, struct cldap_search_state *);
+       talloc_set_destructor(state, cldap_search_state_destructor);
+
+       return req;
+
+ post:
+       return tevent_req_post(req, cldap->event.ctx);
+}
+
+static void cldap_search_state_queue_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(subreq,
+                                struct tevent_req);
+       struct cldap_search_state *state = tevent_req_data(req,
+                                          struct cldap_search_state);
+       ssize_t ret;
+       int sys_errno = 0;
+       struct timeval next;
+
+       ret = tsocket_sendto_queue_recv(subreq, &sys_errno);
+       talloc_free(subreq);
+       if (ret == -1) {
+               NTSTATUS status;
+               status = map_nt_error_from_unix(sys_errno);
+               DLIST_REMOVE(state->caller.cldap->searches.list, state);
+               ZERO_STRUCT(state->caller.cldap);
+               tevent_req_nterror(req, status);
+               return;
+       }
+
+       state->request.idx++;
+
+       /* wait for incoming traffic */
+       if (!cldap_recvfrom_setup(state->caller.cldap)) {
+               tevent_req_nomem(NULL, req);
+               return;
+       }
+
+       if (state->request.idx > state->request.count) {
+               /* we just wait for the response or a timeout */
+               return;
+       }
+
+       next = tevent_timeval_current_ofs(0, state->request.delay);
+       subreq = tevent_wakeup_send(state,
+                                   state->caller.cldap->event.ctx,
+                                   next);
+       if (tevent_req_nomem(subreq, req)) {
+               return;
+       }
+       tevent_req_set_callback(subreq, cldap_search_state_wakeup_done, req);
+}
+
+static void cldap_search_state_wakeup_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(subreq,
+                                struct tevent_req);
+       struct cldap_search_state *state = tevent_req_data(req,
+                                          struct cldap_search_state);
+       bool ok;
+
+       ok = tevent_wakeup_recv(subreq);
+       talloc_free(subreq);
+       if (!ok) {
+               tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+               return;
+       }
+
+       subreq = tsocket_sendto_queue_send(state,
+                                          state->caller.cldap->sock,
+                                          state->caller.cldap->send_queue,
+                                          state->request.blob.data,
+                                          state->request.blob.length,
+                                          state->request.dest);
+       if (tevent_req_nomem(subreq, req)) {
+               return;
+       }
+       tevent_req_set_callback(subreq, cldap_search_state_queue_done, req);
+}
+
+/*
+  receive a cldap reply
+*/
+NTSTATUS cldap_search_recv(struct tevent_req *req,
+                          TALLOC_CTX *mem_ctx,
+                          struct cldap_search *io)
+{
+       struct cldap_search_state *state = tevent_req_data(req,
+                                          struct cldap_search_state);
+       struct ldap_message *ldap_msg;
+       NTSTATUS status;
+
+       if (tevent_req_is_nterror(req, &status)) {
+               goto failed;
+       }
+
+       ldap_msg = talloc(mem_ctx, struct ldap_message);
+       if (!ldap_msg) {
+               goto nomem;
+       }
+
+       status = ldap_decode(state->response.asn1, NULL, ldap_msg);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto failed;
+       }
+
+       ZERO_STRUCT(io->out);
+
+       /* the first possible form has a search result in first place */
+       if (ldap_msg->type == LDAP_TAG_SearchResultEntry) {
+               io->out.response = talloc(mem_ctx, struct ldap_SearchResEntry);
+               if (!io->out.response) {
+                       goto nomem;
+               }
+               *io->out.response = ldap_msg->r.SearchResultEntry;
+
+               /* decode the 2nd part */
+               status = ldap_decode(state->response.asn1, NULL, ldap_msg);
+               if (!NT_STATUS_IS_OK(status)) {
+                       goto failed;
+               }
+       }
+
+       if (ldap_msg->type != LDAP_TAG_SearchResultDone) {
+               status = NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
+               goto failed;
+       }
+
+       io->out.result = talloc(mem_ctx, struct ldap_Result);
+       if (!io->out.result) {
+               goto nomem;
+       }
+       *io->out.result = ldap_msg->r.SearchResultDone;
+
+       if (io->out.result->resultcode != LDAP_SUCCESS) {
+               status = NT_STATUS_LDAP(io->out.result->resultcode);
+               goto failed;
+       }
+
+       tevent_req_received(req);
+       return NT_STATUS_OK;
+
+nomem:
+       status = NT_STATUS_NO_MEMORY;
+failed:
+       tevent_req_received(req);
+       return status;
+}
+
+
+/*
+  synchronous cldap search
+*/
+NTSTATUS cldap_search(struct cldap_socket *cldap,
+                     TALLOC_CTX *mem_ctx,
+                     struct cldap_search *io)
+{
+       struct tevent_req *req;
+       NTSTATUS status;
+
+       if (!cldap->event.allow_poll) {
+               return NT_STATUS_INVALID_PIPE_STATE;
+       }
+
+       if (cldap->searches.list) {
+               return NT_STATUS_PIPE_BUSY;
+       }
+
+       req = cldap_search_send(mem_ctx, cldap, io);
+       NT_STATUS_HAVE_NO_MEMORY(req);
+
+       if (!tevent_req_poll(req, cldap->event.ctx)) {
+               talloc_free(req);
+               return NT_STATUS_INTERNAL_ERROR;
+       }
+
+       status = cldap_search_recv(req, mem_ctx, io);
+       talloc_free(req);
+
+       return status;
+}
+
+struct cldap_netlogon_state {
+       struct cldap_search search;
+};
+
+static void cldap_netlogon_state_done(struct tevent_req *subreq);
+/*
+  queue a cldap netlogon for send
+*/
+struct tevent_req *cldap_netlogon_send(TALLOC_CTX *mem_ctx,
+                                     struct cldap_socket *cldap,
+                                     const struct cldap_netlogon *io)
+{
+       struct tevent_req *req, *subreq;
+       struct cldap_netlogon_state *state;
+       char *filter;
+       static const char * const attr[] = { "NetLogon", NULL };
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct cldap_netlogon_state);
+       if (!req) {
+               return NULL;
+       }
+
+       filter = talloc_asprintf(state, "(&(NtVer=%s)", 
+                                ldap_encode_ndr_uint32(state, io->in.version));
+       if (tevent_req_nomem(filter, req)) {
+               goto post;
+       }
+       if (io->in.user) {
+               filter = talloc_asprintf_append_buffer(filter, "(User=%s)", io->in.user);
+               if (tevent_req_nomem(filter, req)) {
+                       goto post;
+               }
+       }
+       if (io->in.host) {
+               filter = talloc_asprintf_append_buffer(filter, "(Host=%s)", io->in.host);
+               if (tevent_req_nomem(filter, req)) {
+                       goto post;
+               }
+       }
+       if (io->in.realm) {
+               filter = talloc_asprintf_append_buffer(filter, "(DnsDomain=%s)", io->in.realm);
+               if (tevent_req_nomem(filter, req)) {
+                       goto post;
+               }
+       }
+       if (io->in.acct_control != -1) {
+               filter = talloc_asprintf_append_buffer(filter, "(AAC=%s)", 
+                                               ldap_encode_ndr_uint32(state, io->in.acct_control));
+               if (tevent_req_nomem(filter, req)) {
+                       goto post;
+               }
+       }
+       if (io->in.domain_sid) {
+               struct dom_sid *sid = dom_sid_parse_talloc(state, io->in.domain_sid);
+               if (tevent_req_nomem(sid, req)) {
+                       goto post;
+               }
+               filter = talloc_asprintf_append_buffer(filter, "(domainSid=%s)",
+                                               ldap_encode_ndr_dom_sid(state, sid));
+               if (tevent_req_nomem(filter, req)) {
+                       goto post;
+               }
+       }
+       if (io->in.domain_guid) {
+               struct GUID guid;
+               NTSTATUS status;
+               status = GUID_from_string(io->in.domain_guid, &guid);
+               if (tevent_req_nterror(req, status)) {
+                       goto post;
+               }
+               filter = talloc_asprintf_append_buffer(filter, "(DomainGuid=%s)",
+                                               ldap_encode_ndr_GUID(state, &guid));
+               if (tevent_req_nomem(filter, req)) {
+                       goto post;
+               }
+       }
+       filter = talloc_asprintf_append_buffer(filter, ")");
+       if (tevent_req_nomem(filter, req)) {
+               goto post;
+       }
+
+       if (io->in.dest_address) {
+               state->search.in.dest_address = talloc_strdup(state,
+                                               io->in.dest_address);
+               if (tevent_req_nomem(state->search.in.dest_address, req)) {
+                       goto post;
+               }
+               state->search.in.dest_port = io->in.dest_port;
+       } else {
+               state->search.in.dest_address   = NULL;
+               state->search.in.dest_port      = 0;
+       }
+       state->search.in.filter         = filter;
+       state->search.in.attributes     = attr;
+       state->search.in.timeout        = 2;
+       state->search.in.retries        = 2;
+
+       subreq = cldap_search_send(state, cldap, &state->search);
+       if (tevent_req_nomem(subreq, req)) {
+               goto post;
+       }
+       tevent_req_set_callback(subreq, cldap_netlogon_state_done, req);
+
+       return req;
+post:
+       return tevent_req_post(req, cldap->event.ctx);
+}
+
+static void cldap_netlogon_state_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(subreq,
+                                struct tevent_req);
+       struct cldap_netlogon_state *state = tevent_req_data(req,
+                                            struct cldap_netlogon_state);
+       NTSTATUS status;
+
+       status = cldap_search_recv(subreq, state, &state->search);
+       talloc_free(subreq);
+
+       if (tevent_req_nterror(req, status)) {
+               return;
+       }
+
+       tevent_req_done(req);
+}
+
+/*
+  receive a cldap netlogon reply
+*/
+NTSTATUS cldap_netlogon_recv(struct tevent_req *req,
+                            struct smb_iconv_convenience *iconv_convenience,
+                            TALLOC_CTX *mem_ctx,
+                            struct cldap_netlogon *io)
+{
+       struct cldap_netlogon_state *state = tevent_req_data(req,
+                                            struct cldap_netlogon_state);
+       NTSTATUS status;
+       DATA_BLOB *data;
+
+       if (tevent_req_is_nterror(req, &status)) {
+               goto failed;
+       }
+
+       if (state->search.out.response == NULL) {
+               status = NT_STATUS_NOT_FOUND;
+               goto failed;
+       }
+
+       if (state->search.out.response->num_attributes != 1 ||
+           strcasecmp(state->search.out.response->attributes[0].name, "netlogon") != 0 ||
+           state->search.out.response->attributes[0].num_values != 1 ||
+           state->search.out.response->attributes[0].values->length < 2) {
+               status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
+               goto failed;
+       }
+       data = state->search.out.response->attributes[0].values;
+
+       status = pull_netlogon_samlogon_response(data, mem_ctx,
+                                                iconv_convenience,
+                                                &io->out.netlogon);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto failed;
+       }
+
+       if (io->in.map_response) {
+               map_netlogon_samlogon_response(&io->out.netlogon);
+       }
+
+       status =  NT_STATUS_OK;
+failed:
+       tevent_req_received(req);
+       return status;
+}
+
+/*
+  sync cldap netlogon search
+*/
+NTSTATUS cldap_netlogon(struct cldap_socket *cldap,
+                       struct smb_iconv_convenience *iconv_convenience,
+                       TALLOC_CTX *mem_ctx,
+                       struct cldap_netlogon *io)
+{
+       struct tevent_req *req;
+       NTSTATUS status;
+
+       if (!cldap->event.allow_poll) {
+               return NT_STATUS_INVALID_PIPE_STATE;
+       }
+
+       if (cldap->searches.list) {
+               return NT_STATUS_PIPE_BUSY;
+       }
+
+       req = cldap_netlogon_send(mem_ctx, cldap, io);
+       NT_STATUS_HAVE_NO_MEMORY(req);
+
+       if (!tevent_req_poll(req, cldap->event.ctx)) {
+               talloc_free(req);
+               return NT_STATUS_INTERNAL_ERROR;
+       }
+
+       status = cldap_netlogon_recv(req, iconv_convenience, mem_ctx, io);
+       talloc_free(req);
+
+       return status;
+}
+
+
+/*
+  send an empty reply (used on any error, so the client doesn't keep waiting
+  or send the bad request again)
+*/
+NTSTATUS cldap_empty_reply(struct cldap_socket *cldap,
+                          uint32_t message_id,
+                          struct tsocket_address *dest)
+{
+       NTSTATUS status;
+       struct cldap_reply reply;
+       struct ldap_Result result;
+
+       reply.messageid    = message_id;
+       reply.dest         = dest;
+       reply.response     = NULL;
+       reply.result       = &result;
+
+       ZERO_STRUCT(result);
+
+       status = cldap_reply_send(cldap, &reply);
+
+       return status;
+}
+
+/*
+  send an error reply (used on any error, so the client doesn't keep waiting
+  or send the bad request again)
+*/
+NTSTATUS cldap_error_reply(struct cldap_socket *cldap,
+                          uint32_t message_id,
+                          struct tsocket_address *dest,
+                          int resultcode,
+                          const char *errormessage)
+{
+       NTSTATUS status;
+       struct cldap_reply reply;
+       struct ldap_Result result;
+
+       reply.messageid    = message_id;
+       reply.dest         = dest;
+       reply.response     = NULL;
+       reply.result       = &result;
+
+       ZERO_STRUCT(result);
+       result.resultcode       = resultcode;
+       result.errormessage     = errormessage;
+
+       status = cldap_reply_send(cldap, &reply);
+
+       return status;
+}
+
+
+/*
+  send a netlogon reply 
+*/
+NTSTATUS cldap_netlogon_reply(struct cldap_socket *cldap,
+                             struct smb_iconv_convenience *iconv_convenience,
+                             uint32_t message_id,
+                             struct tsocket_address *dest,
+                             uint32_t version,
+                             struct netlogon_samlogon_response *netlogon)
+{
+       NTSTATUS status;
+       struct cldap_reply reply;
+       struct ldap_SearchResEntry response;
+       struct ldap_Result result;
+       TALLOC_CTX *tmp_ctx = talloc_new(cldap);
+       DATA_BLOB blob;
+
+       status = push_netlogon_samlogon_response(&blob, tmp_ctx,
+                                                iconv_convenience,
+                                                netlogon);
+       if (!NT_STATUS_IS_OK(status)) {
+               talloc_free(tmp_ctx);
+               return status;
+       }
+       reply.messageid    = message_id;
+       reply.dest         = dest;
+       reply.response     = &response;
+       reply.result       = &result;
+
+       ZERO_STRUCT(result);
+
+       response.dn = "";
+       response.num_attributes = 1;
+       response.attributes = talloc(tmp_ctx, struct ldb_message_element);
+       NT_STATUS_HAVE_NO_MEMORY(response.attributes);
+       response.attributes->name = "netlogon";
+       response.attributes->num_values = 1;
+       response.attributes->values = &blob;
+
+       status = cldap_reply_send(cldap, &reply);
+
+       talloc_free(tmp_ctx);
+
+       return status;
+}
+
diff --git a/libcli/cldap/cldap.h b/libcli/cldap/cldap.h
new file mode 100644 (file)
index 0000000..111fa2c
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   a async CLDAP library
+
+   Copyright (C) Andrew Tridgell 2005
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "../libcli/netlogon.h"
+
+struct ldap_message;
+struct tsocket_address;
+struct cldap_socket;
+
+struct cldap_incoming {
+       int recv_errno;
+       uint8_t *buf;
+       size_t len;
+       struct tsocket_address *src;
+       struct ldap_message *ldap_msg;
+};
+
+/*
+ a general cldap search request
+*/
+struct cldap_search {
+       struct {
+               const char *dest_address;
+               uint16_t dest_port;
+               const char *filter;
+               const char * const *attributes;
+               int timeout;
+               int retries;
+       } in;
+       struct {
+               struct ldap_SearchResEntry *response;
+               struct ldap_Result         *result;
+       } out;
+};
+
+NTSTATUS cldap_socket_init(TALLOC_CTX *mem_ctx,
+                          struct tevent_context *ev,
+                          const struct tsocket_address *local_addr,
+                          const struct tsocket_address *remote_addr,
+                          struct cldap_socket **_cldap);
+
+NTSTATUS cldap_set_incoming_handler(struct cldap_socket *cldap,
+                                   void (*handler)(struct cldap_socket *,
+                                                   void *private_data,
+                                                   struct cldap_incoming *),
+                                   void *private_data);
+struct tevent_req *cldap_search_send(TALLOC_CTX *mem_ctx,
+                                    struct cldap_socket *cldap,
+                                    const struct cldap_search *io);
+NTSTATUS cldap_search_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+                          struct cldap_search *io);
+NTSTATUS cldap_search(struct cldap_socket *cldap, TALLOC_CTX *mem_ctx,
+                     struct cldap_search *io);
+
+/*
+  a general cldap reply
+*/
+struct cldap_reply {
+       uint32_t messageid;
+       struct tsocket_address *dest;
+       struct ldap_SearchResEntry *response;
+       struct ldap_Result         *result;
+};
+
+NTSTATUS cldap_reply_send(struct cldap_socket *cldap, struct cldap_reply *io);
+
+NTSTATUS cldap_empty_reply(struct cldap_socket *cldap,
+                          uint32_t message_id,
+                          struct tsocket_address *dst);
+NTSTATUS cldap_error_reply(struct cldap_socket *cldap,
+                          uint32_t message_id,
+                          struct tsocket_address *dst,
+                          int resultcode,
+                          const char *errormessage);
+
+/*
+  a netlogon cldap request  
+*/
+struct cldap_netlogon {
+       struct {
+               const char *dest_address;
+               uint16_t dest_port;
+               const char *realm;
+               const char *host;
+               const char *user;
+               const char *domain_guid;
+               const char *domain_sid;
+               int acct_control;
+               uint32_t version;
+               bool map_response;
+       } in;
+       struct {
+               struct netlogon_samlogon_response netlogon;
+       } out;
+};
+
+struct tevent_req *cldap_netlogon_send(TALLOC_CTX *mem_ctx,
+                                      struct cldap_socket *cldap,
+                                      const struct cldap_netlogon *io);
+NTSTATUS cldap_netlogon_recv(struct tevent_req *req,
+                            struct smb_iconv_convenience *iconv_convenience,
+                            TALLOC_CTX *mem_ctx,
+                            struct cldap_netlogon *io);
+NTSTATUS cldap_netlogon(struct cldap_socket *cldap,
+                       struct smb_iconv_convenience *iconv_convenience,
+                       TALLOC_CTX *mem_ctx,
+                       struct cldap_netlogon *io);
+
+NTSTATUS cldap_netlogon_reply(struct cldap_socket *cldap,
+                             struct smb_iconv_convenience *iconv_convenience,
+                             uint32_t message_id,
+                             struct tsocket_address *dst,
+                             uint32_t version,
+                             struct netlogon_samlogon_response *netlogon);
+
diff --git a/libcli/cldap/config.mk b/libcli/cldap/config.mk
new file mode 100644 (file)
index 0000000..a4a75b4
--- /dev/null
@@ -0,0 +1,7 @@
+[SUBSYSTEM::LIBCLI_CLDAP]
+PUBLIC_DEPENDENCIES = LIBCLI_LDAP
+PRIVATE_DEPENDENCIES = LIBTSOCKET LIBSAMBA-UTIL UTIL_TEVENT LIBLDB LIBCLI_NETLOGON
+
+LIBCLI_CLDAP_OBJ_FILES = ../libcli/cldap/cldap.o
+# PUBLIC_HEADERS += ../libcli/cldap/cldap.h
+
index e3b46ada4d6db124d6974d273c9fc5c09684d3f9..cf74182f27886cbabb3d584dffbbb5be66d6de0f 100644 (file)
@@ -448,7 +448,19 @@ LIBSAMBA_OBJ = $(LIBSMB_OBJ0) \
 LIBCLI_LDAP_MESSAGE_OBJ = ../libcli/ldap/ldap_message.o
 LIBCLI_LDAP_NDR_OBJ = ../libcli/ldap/ldap_ndr.o
 
-CLDAP_OBJ = libads/cldap.o $(LIBCLI_LDAP_MESSAGE_OBJ) $(LIBCLI_LDAP_NDR_OBJ)
+LIBTSOCKET_OBJ = ../lib/tsocket/tsocket.o \
+               ../lib/tsocket/tsocket_helpers.o \
+               ../lib/tsocket/tsocket_bsd.o \
+               ../lib/tsocket/tsocket_recvfrom.o \
+               ../lib/tsocket/tsocket_sendto.o \
+               ../lib/tsocket/tsocket_connect.o \
+               ../lib/tsocket/tsocket_writev.o \
+               ../lib/tsocket/tsocket_readv.o
+
+CLDAP_OBJ = libads/cldap.o \
+       ../libcli/cldap/cldap.o \
+       ../lib/util/idtree.o \
+       $(LIBCLI_LDAP_MESSAGE_OBJ) $(LIBCLI_LDAP_NDR_OBJ) $(LIBTSOCKET_OBJ)
 
 LIBSMB_OBJ = libsmb/clientgen.o libsmb/cliconnect.o libsmb/clifile.o \
             libsmb/clikrb5.o libsmb/clispnego.o ../lib/util/asn1.o \
@@ -1629,6 +1641,10 @@ bin/ldbrename: $(BINARY_PREREQS) $(LDBRENAME_OBJ) @BUILD_POPT@ @LIBTALLOC_SHARED
                $(LIBS) $(POPT_LIBS) $(LDAP_LIBS) \
                $(LIBTALLOC_LIBS) $(LIBTDB_LIBS) $(WINBIND_LIBS)
 
+bin/versiontest: $(BINARY_PREREQS) lib/version_test.o $(VERSION_OBJ)
+       @echo Linking $@
+       @$(CC) $(FLAGS) -o $@ $(VERSION_OBJ) lib/version_test.o
+
 
 #####################################################################
 #
index de5b232aac7eba495a31d4d285061c176c41dc91..a0dbca1a001ed01046b287bb91c2d7f5107d6fa7 100644 (file)
@@ -519,7 +519,7 @@ NTSTATUS read_socket_with_timeout(int fd, char *buf,
                }
 
                while (nread < mincnt) {
-                       readret = sys_read(fd, buf + nread, maxcnt - nread);
+                       readret = sys_recv(fd, buf + nread, maxcnt - nread, 0);
 
                        if (readret == 0) {
                                DEBUG(5,("read_socket_with_timeout: "
@@ -588,7 +588,7 @@ NTSTATUS read_socket_with_timeout(int fd, char *buf,
                        return NT_STATUS_IO_TIMEOUT;
                }
 
-               readret = sys_read(fd, buf+nread, maxcnt-nread);
+               readret = sys_recv(fd, buf+nread, maxcnt-nread, 0);
 
                if (readret == 0) {
                        /* we got EOF on the file descriptor */
diff --git a/source3/lib/version_test.c b/source3/lib/version_test.c
new file mode 100644 (file)
index 0000000..880cfeb
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ *  Unix SMB/CIFS implementation.
+ *  version_test - test program for samba_version_strion()
+ *  Copyright (C) Michael Adam 2009
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+int main(void)
+{
+       printf("%s\n", samba_version_string());
+       return 0;
+}
index 64f5fb421a9a6df59b3799455b4c5cf479f12dd5..df095b9e91c1b84c81953f95255c446110f29f38 100644 (file)
@@ -322,7 +322,6 @@ bool winbind_get_sid_aliases(TALLOC_CTX *mem_ctx,
                               &rids,
                               &num_rids);
        if (ret != WBC_ERR_SUCCESS) {
-               wbcFreeMemory(rids);
                return false;
        }
 
index d66e35cacb89a4eca68430a8ee6677b2ce14f7e3..d941ba60cd628d702790c8ef4989879802189df5 100644 (file)
@@ -4,6 +4,7 @@
    Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
    Copyright (C) 2003 Jim McDonough (jmcd@us.ibm.com)
    Copyright (C) 2008 Guenther Deschner (gd@samba.org)
+   Copyright (C) 2009 Stefan Metzmacher (metze@samba.org)
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 */
 
 #include "includes.h"
-
-/*
-  do a cldap netlogon query
-*/
-static int send_cldap_netlogon(TALLOC_CTX *mem_ctx, int sock, const char *domain,
-                              const char *hostname, unsigned ntversion)
-{
-       ASN1_DATA *data;
-       char ntver[4];
-#ifdef CLDAP_USER_QUERY
-       char aac[4];
-
-       SIVAL(aac, 0, 0x00000180);
-#endif
-       SIVAL(ntver, 0, ntversion);
-
-       data = asn1_init(mem_ctx);
-       if (data == NULL) {
-               return -1;
-       }
-
-       asn1_push_tag(data,ASN1_SEQUENCE(0));
-       asn1_write_Integer(data, 4);
-       asn1_push_tag(data, ASN1_APPLICATION(3));
-       asn1_write_OctetString(data, NULL, 0);
-       asn1_write_enumerated(data, 0);
-       asn1_write_enumerated(data, 0);
-       asn1_write_Integer(data, 0);
-       asn1_write_Integer(data, 0);
-       asn1_write_BOOLEAN(data, False);
-       asn1_push_tag(data, ASN1_CONTEXT(0));
-
-       if (domain) {
-               asn1_push_tag(data, ASN1_CONTEXT(3));
-               asn1_write_OctetString(data, "DnsDomain", 9);
-               asn1_write_OctetString(data, domain, strlen(domain));
-               asn1_pop_tag(data);
-       }
-
-       asn1_push_tag(data, ASN1_CONTEXT(3));
-       asn1_write_OctetString(data, "Host", 4);
-       asn1_write_OctetString(data, hostname, strlen(hostname));
-       asn1_pop_tag(data);
-
-#ifdef CLDAP_USER_QUERY
-       asn1_push_tag(data, ASN1_CONTEXT(3));
-       asn1_write_OctetString(data, "User", 4);
-       asn1_write_OctetString(data, "SAMBA$", 6);
-       asn1_pop_tag(data);
-
-       asn1_push_tag(data, ASN1_CONTEXT(3));
-       asn1_write_OctetString(data, "AAC", 4);
-       asn1_write_OctetString(data, aac, 4);
-       asn1_pop_tag(data);
-#endif
-
-       asn1_push_tag(data, ASN1_CONTEXT(3));
-       asn1_write_OctetString(data, "NtVer", 5);
-       asn1_write_OctetString(data, ntver, 4);
-       asn1_pop_tag(data);
-
-       asn1_pop_tag(data);
-
-       asn1_push_tag(data,ASN1_SEQUENCE(0));
-       asn1_write_OctetString(data, "NetLogon", 8);
-       asn1_pop_tag(data);
-       asn1_pop_tag(data);
-       asn1_pop_tag(data);
-
-       if (data->has_error) {
-               DEBUG(2,("Failed to build cldap netlogon at offset %d\n", (int)data->ofs));
-               asn1_free(data);
-               return -1;
-       }
-
-       if (write(sock, data->data, data->length) != (ssize_t)data->length) {
-               DEBUG(2,("failed to send cldap query (%s)\n", strerror(errno)));
-               asn1_free(data);
-               return -1;
-       }
-
-       asn1_free(data);
-
-       return 0;
-}
-
-/*
-  receive a cldap netlogon reply
-*/
-static int recv_cldap_netlogon(TALLOC_CTX *mem_ctx,
-                              int sock,
-                              uint32_t nt_version,
-                              struct netlogon_samlogon_response **reply)
-{
-       int ret;
-       ASN1_DATA *data;
-       DATA_BLOB blob = data_blob_null;
-       DATA_BLOB os1 = data_blob_null;
-       DATA_BLOB os2 = data_blob_null;
-       DATA_BLOB os3 = data_blob_null;
-       int i1;
-       struct netlogon_samlogon_response *r = NULL;
-       NTSTATUS status;
-
-       fd_set r_fds;
-       struct timeval timeout;
-
-       blob = data_blob(NULL, 8192);
-       if (blob.data == NULL) {
-               DEBUG(1, ("data_blob failed\n"));
-               errno = ENOMEM;
-               return -1;
-       }
-
-       FD_ZERO(&r_fds);
-       FD_SET(sock, &r_fds);
-
-       /*
-        * half the time of a regular ldap timeout, not less than 3 seconds.
-        */
-       timeout.tv_sec = MAX(3,lp_ldap_timeout()/2);
-       timeout.tv_usec = 0;
-
-       ret = sys_select(sock+1, &r_fds, NULL, NULL, &timeout);
-       if (ret == -1) {
-               DEBUG(10, ("select failed: %s\n", strerror(errno)));
-               data_blob_free(&blob);
-               return -1;
-       }
-
-       if (ret == 0) {
-               DEBUG(1,("no reply received to cldap netlogon\n"));
-               data_blob_free(&blob);
-               return -1;
-       }
-
-       ret = read(sock, blob.data, blob.length);
-       if (ret <= 0) {
-               DEBUG(1,("no reply received to cldap netlogon\n"));
-               data_blob_free(&blob);
-               return -1;
-       }
-       blob.length = ret;
-
-       data = asn1_init(mem_ctx);
-       if (data == NULL) {
-               data_blob_free(&blob);
-               return -1;
-       }
-
-       asn1_load(data, blob);
-       asn1_start_tag(data, ASN1_SEQUENCE(0));
-       asn1_read_Integer(data, &i1);
-       asn1_start_tag(data, ASN1_APPLICATION(4));
-       asn1_read_OctetString(data, NULL, &os1);
-       asn1_start_tag(data, ASN1_SEQUENCE(0));
-       asn1_start_tag(data, ASN1_SEQUENCE(0));
-       asn1_read_OctetString(data, NULL, &os2);
-       asn1_start_tag(data, ASN1_SET);
-       asn1_read_OctetString(data, NULL, &os3);
-       asn1_end_tag(data);
-       asn1_end_tag(data);
-       asn1_end_tag(data);
-       asn1_end_tag(data);
-       asn1_end_tag(data);
-
-       if (data->has_error) {
-               data_blob_free(&blob);
-               data_blob_free(&os1);
-               data_blob_free(&os2);
-               data_blob_free(&os3);
-               asn1_free(data);
-               DEBUG(1,("Failed to parse cldap reply\n"));
-               return -1;
-       }
-
-       r = TALLOC_ZERO_P(mem_ctx, struct netlogon_samlogon_response);
-       if (!r) {
-               errno = ENOMEM;
-               data_blob_free(&os1);
-               data_blob_free(&os2);
-               data_blob_free(&os3);
-               data_blob_free(&blob);
-               asn1_free(data);
-               return -1;
-       }
-
-       status = pull_netlogon_samlogon_response(&os3, mem_ctx, NULL, r);
-       if (!NT_STATUS_IS_OK(status)) {
-               data_blob_free(&os1);
-               data_blob_free(&os2);
-               data_blob_free(&os3);
-               data_blob_free(&blob);
-               asn1_free(data);
-               TALLOC_FREE(r);
-               return -1;
-       }
-
-       map_netlogon_samlogon_response(r);
-
-       data_blob_free(&os1);
-       data_blob_free(&os2);
-       data_blob_free(&os3);
-       data_blob_free(&blob);
-
-       asn1_free(data);
-
-       if (reply) {
-               *reply = r;
-       } else {
-               TALLOC_FREE(r);
-       }
-
-       return 0;
-}
+#include "../libcli/cldap/cldap.h"
+#include "../lib/tsocket/tsocket.h"
 
 /*******************************************************************
   do a cldap netlogon query.  Always 389/udp
@@ -244,31 +32,81 @@ bool ads_cldap_netlogon(TALLOC_CTX *mem_ctx,
                        const char *server,
                        const char *realm,
                        uint32_t nt_version,
-                       struct netlogon_samlogon_response **reply)
+                       struct netlogon_samlogon_response **_reply)
 {
-       int sock;
+       struct cldap_socket *cldap;
+       struct cldap_netlogon io;
+       struct netlogon_samlogon_response *reply;
+       NTSTATUS status;
+       struct in_addr addr;
+       char addrstr[INET_ADDRSTRLEN];
+       const char *dest_str;
        int ret;
+       struct tsocket_address *dest_addr;
 
-       sock = open_udp_socket(server, LDAP_PORT );
-       if (sock == -1) {
-               DEBUG(2,("ads_cldap_netlogon: Failed to open udp socket to %s\n", 
+       addr = interpret_addr2(server);
+       dest_str = inet_ntop(AF_INET, &addr,
+                            addrstr, sizeof(addrstr));
+       if (!dest_str) {
+               DEBUG(2,("Failed to resolve[%s] into an address for cldap\n",
                         server));
-               return False;
+               return false;
        }
 
-       ret = send_cldap_netlogon(mem_ctx, sock, realm, global_myname(), nt_version);
+       ret = tsocket_address_inet_from_strings(mem_ctx, "ipv4",
+                                               dest_str, LDAP_PORT,
+                                               &dest_addr);
        if (ret != 0) {
-               close(sock);
-               return False;
+               status = map_nt_error_from_unix(errno);
+               DEBUG(2,("Failed to create cldap tsocket_address for %s - %s\n",
+                        dest_str, nt_errstr(status)));
+               return false;
+       }
+
+       /*
+        * as we use a connected udp socket
+        */
+       status = cldap_socket_init(mem_ctx, NULL, NULL, dest_addr, &cldap);
+       TALLOC_FREE(dest_addr);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(2,("Failed to create cldap socket to %s: %s\n",
+                        dest_str, nt_errstr(status)));
+               return false;
        }
-       ret = recv_cldap_netlogon(mem_ctx, sock, nt_version, reply);
-       close(sock);
 
-       if (ret == -1) {
-               return False;
+       reply = talloc(cldap, struct netlogon_samlogon_response);
+       if (!reply) {
+               goto failed;
        }
 
-       return True;
+       /*
+        * as we use a connected socket, so we don't need to specify the
+        * destination
+        */
+       io.in.dest_address      = NULL;
+       io.in.dest_port         = 0;
+       io.in.realm             = realm;
+       io.in.host              = NULL;
+       io.in.user              = NULL;
+       io.in.domain_guid       = NULL;
+       io.in.domain_sid        = NULL;
+       io.in.acct_control      = 0;
+       io.in.version           = nt_version;
+       io.in.map_response      = false;
+
+       status = cldap_netlogon(cldap, NULL, reply, &io);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(2,("cldap_netlogon() failed: %s\n", nt_errstr(status)));
+               goto failed;
+       }
+
+       *reply = io.out.netlogon;
+       *_reply = talloc_move(mem_ctx, &reply);
+       TALLOC_FREE(cldap);
+       return true;
+failed:
+       TALLOC_FREE(cldap);
+       return false;
 }
 
 /*******************************************************************
index 53023cc75a5c7b6553937c420963402bfc18fce2..0e03ebb90ddff83ee4847dd45e8888b8d610c81c 100644 (file)
@@ -30,12 +30,10 @@ static const struct {
        {KRB5KDC_ERR_CLIENT_REVOKED, NT_STATUS_ACCESS_DENIED},
        {KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN, NT_STATUS_INVALID_ACCOUNT_NAME},
        {KRB5KDC_ERR_ETYPE_NOSUPP, NT_STATUS_LOGON_FAILURE},
-#if defined(KRB5KDC_ERR_KEY_EXPIRED) /* Heimdal */
-       {KRB5KDC_ERR_KEY_EXPIRED, NT_STATUS_PASSWORD_EXPIRED},
-#elif defined(KRB5KDC_ERR_KEY_EXP) /* MIT */
+#if defined(KRB5KDC_ERR_KEY_EXP) /* MIT */
        {KRB5KDC_ERR_KEY_EXP, NT_STATUS_PASSWORD_EXPIRED},
-#else 
-#error Neither KRB5KDC_ERR_KEY_EXPIRED nor KRB5KDC_ERR_KEY_EXP available
+#else /* old Heimdal releases have it with different name only in an enum: */
+       {KRB5KDC_ERR_KEY_EXPIRED, NT_STATUS_PASSWORD_EXPIRED},
 #endif
        {25, NT_STATUS_PASSWORD_EXPIRED}, /* FIXME: bug in heimdal 0.7 krb5_get_init_creds_password (Inappropriate ioctl for device (25)) */
        {KRB5KDC_ERR_NULL_KEY, NT_STATUS_LOGON_FAILURE},
index 18e7ab1dec732084dc105c15041a1dc119038316..430807eb7f319db765cc2449aec568e355b697de 100644 (file)
@@ -551,13 +551,23 @@ static char *cli_dfs_make_full_path(TALLOC_CTX *ctx,
                                        struct cli_state *cli,
                                        const char *dir)
 {
+       char path_sep = '\\';
+
        /* Ensure the extrapath doesn't start with a separator. */
        while (IS_DIRECTORY_SEP(*dir)) {
                dir++;
        }
 
-       return talloc_asprintf(ctx, "\\%s\\%s\\%s",
-                       cli->desthost, cli->share, dir);
+       if (cli->posix_capabilities & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
+               path_sep = '/';
+       }
+       return talloc_asprintf(ctx, "%c%s%c%s%c%s",
+                       path_sep,
+                       cli->desthost,
+                       path_sep,
+                       cli->share,
+                       path_sep,
+                       dir);
 }
 
 /********************************************************************
index 69e2be3af7f3f74884a2e890fc79da4abd1229e8..0266c0307e5a296139cd58b5fcb1f7007a11f0b0 100644 (file)
@@ -112,9 +112,6 @@ bool cli_send_trans(struct cli_state *cli, int trans,
                        this_lparam = MIN(lparam-tot_param,cli->max_xmit - 500); /* hack */
                        this_ldata = MIN(ldata-tot_data,cli->max_xmit - (500+this_lparam));
 
-                       client_set_trans_sign_state_off(cli, mid);
-                       client_set_trans_sign_state_on(cli, mid);
-
                        cli_set_message(cli->outbuf,trans==SMBtrans?8:9,0,True);
                        SCVAL(cli->outbuf,smb_com,(trans==SMBtrans ? SMBtranss : SMBtranss2));
 
@@ -138,20 +135,14 @@ bool cli_send_trans(struct cli_state *cli, int trans,
                                memcpy(outdata,data+tot_data,this_ldata);
                        cli_setup_bcc(cli, outdata+this_ldata);
 
-                       /*
-                        * Save the mid we're using. We need this for finding
-                        * signing replies.
-                        */
-                       mid = cli->mid;
-
                        show_msg(cli->outbuf);
+
+                       client_set_trans_sign_state_off(cli, mid);
+                       cli->mid = mid;
                        if (!cli_send_smb(cli)) {
-                               client_set_trans_sign_state_off(cli, mid);
                                return False;
                        }
-
-                       /* Ensure we use the same mid for the secondaries. */
-                       cli->mid = mid;
+                       client_set_trans_sign_state_on(cli, mid);
 
                        tot_data += this_ldata;
                        tot_param += this_lparam;
@@ -461,21 +452,14 @@ bool cli_send_nt_trans(struct cli_state *cli,
                                memcpy(outdata,data+tot_data,this_ldata);
                        cli_setup_bcc(cli, outdata+this_ldata);
 
-                       /*
-                        * Save the mid we're using. We need this for finding
-                        * signing replies.
-                        */
-                       mid = cli->mid;
-
                        show_msg(cli->outbuf);
 
+                       client_set_trans_sign_state_off(cli, mid);
+                       cli->mid = mid;
                        if (!cli_send_smb(cli)) {
-                               client_set_trans_sign_state_off(cli, mid);
                                return False;
                        }
-
-                       /* Ensure we use the same mid for the secondaries. */
-                       cli->mid = mid;
+                       client_set_trans_sign_state_on(cli, mid);
 
                        tot_data += this_ldata;
                        tot_param += this_lparam;
@@ -747,6 +731,7 @@ static struct async_req *cli_ship_trans(TALLOC_CTX *mem_ctx,
        uint16_t this_data = 0;
        uint32_t useable_space;
        uint8_t cmd;
+       uint8_t pad[3];
 
        frame = talloc_stackframe();
 
@@ -759,9 +744,16 @@ static struct async_req *cli_ship_trans(TALLOC_CTX *mem_ctx,
 
        param_offset = smb_size - 4;
 
+       bytes = TALLOC_ARRAY(talloc_tos(), uint8_t, 0); /* padding */
+       if (bytes == NULL) {
+               goto fail;
+       }
+
        switch (cmd) {
        case SMBtrans:
-               bytes = TALLOC_ZERO_P(talloc_tos(), uint8_t); /* padding */
+               pad[0] = 0;
+               bytes = (uint8_t *)talloc_append_blob(talloc_tos(), bytes,
+                                               data_blob_const(pad, 1));
                if (bytes == NULL) {
                        goto fail;
                }
@@ -775,13 +767,14 @@ static struct async_req *cli_ship_trans(TALLOC_CTX *mem_ctx,
                param_offset += talloc_get_size(bytes);
                break;
        case SMBtrans2:
-               bytes = TALLOC_ARRAY(talloc_tos(), uint8_t, 3); /* padding */
+               pad[0] = 0;
+               pad[1] = 'D'; /* Copy this from "old" 3.0 behaviour */
+               pad[2] = ' ';
+               bytes = (uint8_t *)talloc_append_blob(talloc_tos(), bytes,
+                                               data_blob_const(pad, 3));
                if (bytes == NULL) {
                        goto fail;
                }
-               bytes[0] = 0;
-               bytes[1] = 'D'; /* Copy this from "old" 3.0 behaviour */
-               bytes[2] = ' ';
                wct = 14 + state->num_setup;
                param_offset += talloc_get_size(bytes);
                break;
index a55aafcd0c2c444b7354dfbb339dc09fd4c3df62..ce9d2af4c0d17d1cd1143649a91cc7cf61d5ea24 100755 (executable)
@@ -112,6 +112,7 @@ if test -n "${SAMBA_VERSION_VENDOR_SUFFIX}";then
     SAMBA_VERSION_STRING="${SAMBA_VERSION_STRING}-${SAMBA_VERSION_VENDOR_SUFFIX}"
     if test -n "${SAMBA_VERSION_VENDOR_PATCH}";then
         echo "#define SAMBA_VERSION_VENDOR_PATCH ${SAMBA_VERSION_VENDOR_PATCH}" >> $OUTPUT_FILE
+        echo "#define SAMBA_VERSION_VENDOR_PATCH_STRING \"${SAMBA_VERSION_VENDOR_PATCH}\"" >> $OUTPUT_FILE
         SAMBA_VERSION_STRING="${SAMBA_VERSION_STRING}-${SAMBA_VERSION_VENDOR_PATCH}"
     fi
 fi
@@ -130,7 +131,7 @@ cat >>$OUTPUT_FILE<<CEOF
 #else /* SAMBA_VERSION_VENDOR_FUNCTION */
 #  ifdef SAMBA_VERSION_VENDOR_SUFFIX
 #    ifdef SAMBA_VERSION_VENDOR_PATCH
-#      define SAMBA_VERSION_STRING SAMBA_VERSION_OFFICIAL_STRING "-" SAMBA_VERSION_VENDOR_SUFFIX "-" SAMBA_VERSION_VENDOR_PATCH
+#      define SAMBA_VERSION_STRING SAMBA_VERSION_OFFICIAL_STRING "-" SAMBA_VERSION_VENDOR_SUFFIX "-" SAMBA_VERSION_VENDOR_PATCH_STRING
 #    else /* SAMBA_VERSION_VENDOR_PATCH */
 #      define SAMBA_VERSION_STRING SAMBA_VERSION_OFFICIAL_STRING "-" SAMBA_VERSION_VENDOR_SUFFIX
 #    endif /* SAMBA_VERSION_VENDOR_SUFFIX */
index a743385f7f51fa7c454f66875ba4fd7a19ba1104..8b560bd8ca64b87dd098e3bc1b274cfd19859fb6 100644 (file)
@@ -72,11 +72,16 @@ static NTSTATUS check_path_syntax_internal(char *path,
                        }
                }
 
-               if (!stream_started && *s == ':') {
+               if (!posix_path && !stream_started && *s == ':') {
                        if (*p_last_component_contains_wcard) {
                                return NT_STATUS_OBJECT_NAME_INVALID;
                        }
-                       /* stream names allow more characters than file names */
+                       /* Stream names allow more characters than file names.
+                          We're overloading posix_path here to allow a wider
+                          range of characters. If stream_started is true this
+                          is still a Windows path even if posix_path is true.
+                          JRA.
+                       */
                        stream_started = true;
                        start_of_name_component = false;
                        posix_path = true;
index 19849a84a89a3833fa1a2b965d4e1b2973d3e0f4..6029eb072781d8cc1670385009b2ad0f1d3644ae 100644 (file)
@@ -4160,8 +4160,8 @@ static bool run_opentest(int dummy)
 static bool run_simple_posix_open_test(int dummy)
 {
        static struct cli_state *cli1;
-       const char *fname = "\\posix.file";
-       const char *dname = "\\posix.dir";
+       const char *fname = "\\posix:file";
+       const char *dname = "\\posix:dir";
        uint16 major, minor;
        uint32 caplow, caphigh;
        int fnum1 = -1;
index 240f2b1dc23d3cb5ba9ea5d94e2ed8d9ac3bf2db..1a08cd21f90d2b871d02a329710b419e0228075a 100644 (file)
@@ -20,8 +20,8 @@
 */
 
 #include "includes.h"
+#include <talloc.h>
 #include "libcli/ldap/ldap.h"
-#include "lib/socket/socket.h"
 #include "lib/messaging/irpc.h"
 #include "smbd/service_task.h"
 #include "smbd/service.h"
 #include "ldb_wrap.h"
 #include "auth/auth.h"
 #include "param/param.h"
+#include "../lib/tsocket/tsocket.h"
 
 /*
   handle incoming cldap requests
 */
-static void cldapd_request_handler(struct cldap_socket *cldap, 
-                                  struct ldap_message *ldap_msg, 
-                                  struct socket_address *src)
+static void cldapd_request_handler(struct cldap_socket *cldap,
+                                  void *private_data,
+                                  struct cldap_incoming *in)
 {
+       struct cldapd_server *cldapd = talloc_get_type(private_data,
+                                      struct cldapd_server);
        struct ldap_SearchRequest *search;
-       if (ldap_msg->type != LDAP_TAG_SearchRequest) {
-               DEBUG(0,("Invalid CLDAP request type %d from %s:%d\n", 
-                        ldap_msg->type, src->addr, src->port));
-               cldap_error_reply(cldap, ldap_msg->messageid, src,
+
+       if (in->ldap_msg->type != LDAP_TAG_SearchRequest) {
+               DEBUG(0,("Invalid CLDAP request type %d from %s\n",
+                        in->ldap_msg->type,
+                        tsocket_address_string(in->src, in)));
+               cldap_error_reply(cldap, in->ldap_msg->messageid, in->src,
                                  LDAP_OPERATIONS_ERROR, "Invalid CLDAP request");
+               talloc_free(in);
                return;
        }
 
-       search = &ldap_msg->r.SearchRequest;
+       search = &in->ldap_msg->r.SearchRequest;
 
        if (strcmp("", search->basedn) != 0) {
-               DEBUG(0,("Invalid CLDAP basedn '%s' from %s:%d\n", 
-                        search->basedn, src->addr, src->port));
-               cldap_error_reply(cldap, ldap_msg->messageid, src,
+               DEBUG(0,("Invalid CLDAP basedn '%s' from %s\n",
+                        search->basedn,
+                        tsocket_address_string(in->src, in)));
+               cldap_error_reply(cldap, in->ldap_msg->messageid, in->src,
                                  LDAP_OPERATIONS_ERROR, "Invalid CLDAP basedn");
+               talloc_free(in);
                return;
        }
 
        if (search->scope != LDAP_SEARCH_SCOPE_BASE) {
-               DEBUG(0,("Invalid CLDAP scope %d from %s:%d\n", 
-                        search->scope, src->addr, src->port));
-               cldap_error_reply(cldap, ldap_msg->messageid, src,
+               DEBUG(0,("Invalid CLDAP scope %d from %s\n",
+                        search->scope,
+                        tsocket_address_string(in->src, in)));
+               cldap_error_reply(cldap, in->ldap_msg->messageid, in->src,
                                  LDAP_OPERATIONS_ERROR, "Invalid CLDAP scope");
+               talloc_free(in);
                return;
        }
 
        if (search->num_attributes == 1 &&
            strcasecmp(search->attributes[0], "netlogon") == 0) {
-               cldapd_netlogon_request(cldap, ldap_msg->messageid,
-                                       search->tree, src);
+               cldapd_netlogon_request(cldap,
+                                       cldapd,
+                                       in,
+                                       in->ldap_msg->messageid,
+                                       search->tree,
+                                       in->src);
+               talloc_free(in);
                return;
        }
 
-       cldapd_rootdse_request(cldap, ldap_msg->messageid,
-                              search, src);
+       cldapd_rootdse_request(cldap, cldapd, in,
+                              in->ldap_msg->messageid,
+                              search, in->src);
+       talloc_free(in);
 }
 
 
@@ -88,28 +105,36 @@ static NTSTATUS cldapd_add_socket(struct cldapd_server *cldapd, struct loadparm_
                                  const char *address)
 {
        struct cldap_socket *cldapsock;
-       struct socket_address *socket_address;
+       struct tsocket_address *socket_address;
        NTSTATUS status;
-
-       /* listen for unicasts on the CLDAP port (389) */
-       cldapsock = cldap_socket_init(cldapd, cldapd->task->event_ctx, lp_iconv_convenience(cldapd->task->lp_ctx));
-       NT_STATUS_HAVE_NO_MEMORY(cldapsock);
-
-       socket_address = socket_address_from_strings(cldapsock, cldapsock->sock->backend_name, 
-                                                    address, lp_cldap_port(lp_ctx));
-       if (!socket_address) {
-               talloc_free(cldapsock);
-               return NT_STATUS_NO_MEMORY;
+       int ret;
+
+       ret = tsocket_address_inet_from_strings(cldapd,
+                                               "ip",
+                                               address,
+                                               lp_cldap_port(lp_ctx),
+                                               &socket_address);
+       if (ret != 0) {
+               status = map_nt_error_from_unix(errno);
+               DEBUG(0,("invalid address %s:%d - %s:%s\n",
+                        address, lp_cldap_port(lp_ctx),
+                        gai_strerror(ret), nt_errstr(status)));
+               return status;
        }
 
-       status = socket_listen(cldapsock->sock, socket_address, 0, 0);
+       /* listen for unicasts on the CLDAP port (389) */
+       status = cldap_socket_init(cldapd,
+                                  cldapd->task->event_ctx,
+                                  socket_address,
+                                  NULL,
+                                  &cldapsock);
        if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(0,("Failed to bind to %s:%d - %s\n", 
-                        address, lp_cldap_port(lp_ctx), nt_errstr(status)));
-               talloc_free(cldapsock);
+               DEBUG(0,("Failed to bind to %s - %s\n", 
+                        tsocket_address_string(socket_address, socket_address),
+                        nt_errstr(status)));
+               talloc_free(socket_address);
                return status;
        }
-
        talloc_free(socket_address);
 
        cldap_set_incoming_handler(cldapsock, cldapd_request_handler, cldapd);
@@ -117,7 +142,6 @@ static NTSTATUS cldapd_add_socket(struct cldapd_server *cldapd, struct loadparm_
        return NT_STATUS_OK;
 }
 
-
 /*
   setup our listening sockets on the configured network interfaces
 */
index 0df35be6fdd59da03084217c7ca52949e027f6cc..33c0adc3b18b6d34a2f8abfe968d91124282cefb 100644 (file)
@@ -24,7 +24,6 @@
 #include "lib/ldb/include/ldb.h"
 #include "lib/ldb/include/ldb_errors.h"
 #include "lib/events/events.h"
-#include "lib/socket/socket.h"
 #include "smbd/service_task.h"
 #include "cldap_server/cldap_server.h"
 #include "librpc/gen_ndr/ndr_misc.h"
@@ -36,6 +35,8 @@
 #include "system/network.h"
 #include "lib/socket/netif.h"
 #include "param/param.h"
+#include "../lib/tsocket/tsocket.h"
+
 /*
   fill in the cldap netlogon union for a given version
 */
@@ -402,12 +403,13 @@ NTSTATUS fill_netlogon_samlogon_response(struct ldb_context *sam_ctx,
 /*
   handle incoming cldap requests
 */
-void cldapd_netlogon_request(struct cldap_socket *cldap, 
+void cldapd_netlogon_request(struct cldap_socket *cldap,
+                            struct cldapd_server *cldapd,
+                            TALLOC_CTX *tmp_ctx,
                             uint32_t message_id,
                             struct ldb_parse_tree *tree,
-                            struct socket_address *src)
+                            struct tsocket_address *src)
 {
-       struct cldapd_server *cldapd = talloc_get_type(cldap->incoming.private_data, struct cldapd_server);
        int i;
        const char *domain = NULL;
        const char *host = NULL;
@@ -419,8 +421,6 @@ void cldapd_netlogon_request(struct cldap_socket *cldap,
        struct netlogon_samlogon_response netlogon;
        NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
 
-       TALLOC_CTX *tmp_ctx = talloc_new(cldap);
-
        if (tree->operation != LDB_OP_AND) goto failed;
 
        /* extract the query elements */
@@ -478,24 +478,25 @@ void cldapd_netlogon_request(struct cldap_socket *cldap,
                 domain, host, user, version, domain_guid));
 
        status = fill_netlogon_samlogon_response(cldapd->samctx, tmp_ctx, domain, NULL, NULL, domain_guid,
-                                                user, acct_control, src->addr, 
+                                                user, acct_control,
+                                                tsocket_address_inet_addr_string(src, tmp_ctx),
                                                 version, cldapd->task->lp_ctx, &netlogon);
        if (!NT_STATUS_IS_OK(status)) {
                goto failed;
        }
 
-       status = cldap_netlogon_reply(cldap, message_id, src, version,
+       status = cldap_netlogon_reply(cldap,
+                                     lp_iconv_convenience(cldapd->task->lp_ctx),
+                                     message_id, src, version,
                                      &netlogon);
        if (!NT_STATUS_IS_OK(status)) {
                goto failed;
        }
 
-       talloc_free(tmp_ctx);
        return;
        
 failed:
        DEBUG(2,("cldap netlogon query failed domain=%s host=%s version=%d - %s\n",
                 domain, host, version, nt_errstr(status)));
-       talloc_free(tmp_ctx);
-       cldap_empty_reply(cldap, message_id, src);      
+       cldap_empty_reply(cldap, message_id, src);
 }
index daa5060d07cf7ae1580f410711bec33c9a02488d..7e867deff29f2d244c6d82558d55dc4eb8310b16 100644 (file)
 */
 
 #include "includes.h"
+#include <tevent.h>
 #include "libcli/ldap/ldap.h"
 #include "lib/ldb/include/ldb.h"
 #include "lib/ldb/include/ldb_errors.h"
-#include "lib/events/events.h"
-#include "lib/socket/socket.h"
 #include "smbd/service_task.h"
 #include "cldap_server/cldap_server.h"
 #include "librpc/gen_ndr/ndr_misc.h"
 #include "dsdb/samdb/samdb.h"
-#include "auth/auth.h"
 #include "ldb_wrap.h"
-#include "system/network.h"
-#include "lib/socket/netif.h"
 
 static void cldapd_rootdse_fill(struct cldapd_server *cldapd,
                                TALLOC_CTX *mem_ctx,
@@ -151,15 +147,15 @@ done:
   handle incoming cldap requests
 */
 void cldapd_rootdse_request(struct cldap_socket *cldap, 
+                           struct cldapd_server *cldapd,
+                           TALLOC_CTX *tmp_ctx,
                            uint32_t message_id,
                            struct ldap_SearchRequest *search,
-                           struct socket_address *src)
+                           struct tsocket_address *src)
 {
-       struct cldapd_server *cldapd = talloc_get_type(cldap->incoming.private_data, struct cldapd_server);
        NTSTATUS status;
        struct cldap_reply reply;
        struct ldap_Result result;
-       TALLOC_CTX *tmp_ctx = talloc_new(cldap);
 
        ZERO_STRUCT(result);
 
@@ -176,6 +172,5 @@ void cldapd_rootdse_request(struct cldap_socket *cldap,
                         ldb_filter_from_tree(tmp_ctx, search->tree), nt_errstr(status)));
        }
 
-       talloc_free(tmp_ctx);
        return;
 }
index 9de5b1cc0cc4dd7dde55d0916ddd3beca07158d0..280d60beb2fb1f58f4a7ba9e71700340ff6391bc 100644 (file)
@@ -10,6 +10,8 @@
 ../lib/util/talloc_stack.h: util/talloc_stack.h
 ../lib/util/xfile.h: util/xfile.h
 ../lib/tdr/tdr.h: tdr.h
+../lib/tsocket/tsocket.h: tsocket.h
+../lib/tsocket/tsocket_internal.h: tsocket_internal.h
 librpc/rpc/dcerpc.h: dcerpc.h
 lib/ldb/include/ldb.h: ldb.h
 lib/ldb/include/ldb_errors.h: ldb_errors.h
@@ -23,7 +25,7 @@ lib/registry/registry.h: registry.h
 libcli/util/werror.h: core/werror.h
 libcli/util/doserr.h: core/doserr.h
 libcli/util/ntstatus.h: core/ntstatus.h
-libcli/cldap/cldap.h: cldap.h
+../libcli/cldap/cldap.h: cldap.h
 auth/credentials/credentials.h: credentials.h
 auth/credentials/credentials_krb5.h: credentials/krb5.h
 rpc_server/dcerpc_server.h: dcerpc_server.h
diff --git a/source4/libcli/cldap/cldap.c b/source4/libcli/cldap/cldap.c
deleted file mode 100644 (file)
index b18ba12..0000000
+++ /dev/null
@@ -1,738 +0,0 @@
-/* 
-   Unix SMB/CIFS implementation.
-
-   cldap client library
-
-   Copyright (C) Andrew Tridgell 2005
-   
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
-   
-   This program 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 General Public License for more details.
-   
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/*
-  see RFC1798 for details of CLDAP
-
-  basic properties
-    - carried over UDP on port 389
-    - request and response matched by message ID
-    - request consists of only a single searchRequest element
-    - response can be in one of two forms
-       - a single searchResponse, followed by a searchResult
-       - a single searchResult
-*/
-
-#include "includes.h"
-#include "lib/events/events.h"
-#include "../lib/util/dlinklist.h"
-#include "libcli/ldap/ldap.h"
-#include "libcli/ldap/ldap_ndr.h"
-#include "libcli/cldap/cldap.h"
-#include "lib/socket/socket.h"
-#include "libcli/security/security.h"
-#include "librpc/gen_ndr/ndr_nbt.h"
-
-/*
-  destroy a pending request
-*/
-static int cldap_request_destructor(struct cldap_request *req)
-{
-       if (req->state == CLDAP_REQUEST_SEND) {
-               DLIST_REMOVE(req->cldap->send_queue, req);
-       }
-       if (!req->is_reply && req->message_id != 0) {
-               idr_remove(req->cldap->idr, req->message_id);
-               req->message_id = 0;
-       }
-       return 0;
-}
-
-/*
-  handle recv events on a cldap socket
-*/
-static void cldap_socket_recv(struct cldap_socket *cldap)
-{
-       TALLOC_CTX *tmp_ctx = talloc_new(cldap);
-       NTSTATUS status;
-       struct socket_address *src;
-       DATA_BLOB blob;
-       size_t nread, dsize;
-       struct asn1_data *asn1 = asn1_init(tmp_ctx);
-       struct ldap_message *ldap_msg;
-       struct cldap_request *req;
-
-       if (!asn1) return;
-
-       status = socket_pending(cldap->sock, &dsize);
-       if (!NT_STATUS_IS_OK(status)) {
-               talloc_free(tmp_ctx);
-               return;
-       }
-
-       blob = data_blob_talloc(tmp_ctx, NULL, dsize);
-       if (blob.data == NULL) {
-               talloc_free(tmp_ctx);
-               return;
-       }
-
-       status = socket_recvfrom(cldap->sock, blob.data, blob.length, &nread,
-                                tmp_ctx, &src);
-       if (!NT_STATUS_IS_OK(status)) {
-               talloc_free(tmp_ctx);
-               return;
-       }
-       blob.length = nread;
-
-       DEBUG(2,("Received cldap packet of length %d from %s:%d\n", 
-                (int)blob.length, src->addr, src->port));
-
-       if (!asn1_load(asn1, blob)) {
-               DEBUG(2,("Failed to setup for asn.1 decode\n"));
-               talloc_free(tmp_ctx);
-               return;
-       }
-
-       ldap_msg = talloc(tmp_ctx, struct ldap_message);
-       if (ldap_msg == NULL) {
-               talloc_free(tmp_ctx);
-               return;
-       }
-
-       /* this initial decode is used to find the message id */
-       status = ldap_decode(asn1, NULL, ldap_msg);
-       if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(2,("Failed to decode ldap message: %s\n", nt_errstr(status)));
-               talloc_free(tmp_ctx);
-               return;
-       }
-
-       /* find the pending request */
-       req = idr_find(cldap->idr, ldap_msg->messageid);
-       if (req == NULL) {
-               if (cldap->incoming.handler) {
-                       cldap->incoming.handler(cldap, ldap_msg, src);
-               } else {
-                       DEBUG(2,("Mismatched cldap reply %u from %s:%d\n",
-                                ldap_msg->messageid, src->addr, src->port));
-               }
-               talloc_free(tmp_ctx);
-               return;
-       }
-
-       req->asn1 = talloc_steal(req, asn1);
-       req->asn1->ofs = 0;
-
-       req->state = CLDAP_REQUEST_DONE;
-       talloc_free(req->te);
-
-       talloc_free(tmp_ctx);
-
-       if (req->async.fn) {
-               req->async.fn(req);
-       }
-}
-
-/*
-  handle request timeouts
-*/
-static void cldap_request_timeout(struct tevent_context *event_ctx, 
-                                 struct tevent_timer *te, struct timeval t,
-                                 void *private_data)
-{
-       struct cldap_request *req = talloc_get_type(private_data, struct cldap_request);
-
-       /* possibly try again */
-       if (req->num_retries != 0) {
-               size_t len = req->encoded.length;
-
-               req->num_retries--;
-
-               socket_sendto(req->cldap->sock, &req->encoded, &len, 
-                             req->dest);
-
-               req->te = event_add_timed(req->cldap->event_ctx, req, 
-                                         timeval_current_ofs(req->timeout, 0),
-                                         cldap_request_timeout, req);
-               return;
-       }
-
-       req->state = CLDAP_REQUEST_ERROR;
-       req->status = NT_STATUS_IO_TIMEOUT;
-       if (req->async.fn) {
-               req->async.fn(req);
-       }
-}
-
-/*
-  handle send events on a cldap socket
-*/
-static void cldap_socket_send(struct cldap_socket *cldap)
-{
-       struct cldap_request *req;
-       NTSTATUS status;
-
-       while ((req = cldap->send_queue)) {
-               size_t len;
-               
-               len = req->encoded.length;
-               status = socket_sendto(cldap->sock, &req->encoded, &len,
-                                      req->dest);
-               if (NT_STATUS_IS_ERR(status)) {
-                       DEBUG(0,("Failed to send cldap request of length %u to %s:%d\n",
-                                (unsigned)req->encoded.length, req->dest->addr, req->dest->port));
-                       DLIST_REMOVE(cldap->send_queue, req);
-                       req->state = CLDAP_REQUEST_ERROR;
-                       req->status = status;
-                       if (req->async.fn) {
-                               req->async.fn(req);
-                       }
-                       continue;
-               }
-
-               if (!NT_STATUS_IS_OK(status)) return;
-
-               DLIST_REMOVE(cldap->send_queue, req);
-
-               if (req->is_reply) {
-                       talloc_free(req);
-               } else {
-                       req->state = CLDAP_REQUEST_WAIT;
-
-                       req->te = event_add_timed(cldap->event_ctx, req, 
-                                                 timeval_current_ofs(req->timeout, 0),
-                                                 cldap_request_timeout, req);
-
-                       EVENT_FD_READABLE(cldap->fde);
-               }
-       }
-
-       EVENT_FD_NOT_WRITEABLE(cldap->fde);
-       return;
-}
-
-
-/*
-  handle fd events on a cldap_socket
-*/
-static void cldap_socket_handler(struct tevent_context *ev, struct tevent_fd *fde,
-                                uint16_t flags, void *private_data)
-{
-       struct cldap_socket *cldap = talloc_get_type(private_data, struct cldap_socket);
-       if (flags & EVENT_FD_WRITE) {
-               cldap_socket_send(cldap);
-       } 
-       if (flags & EVENT_FD_READ) {
-               cldap_socket_recv(cldap);
-       }
-}
-
-/*
-  initialise a cldap_socket. The event_ctx is optional, if provided
-  then operations will use that event context
-*/
-struct cldap_socket *cldap_socket_init(TALLOC_CTX *mem_ctx, 
-                                      struct tevent_context *event_ctx,
-                                      struct smb_iconv_convenience *iconv_convenience)
-{
-       struct cldap_socket *cldap;
-       NTSTATUS status;
-
-       cldap = talloc(mem_ctx, struct cldap_socket);
-       if (cldap == NULL) goto failed;
-
-       cldap->event_ctx = talloc_reference(cldap, event_ctx);
-       if (cldap->event_ctx == NULL) goto failed;
-
-       cldap->idr = idr_init(cldap);
-       if (cldap->idr == NULL) goto failed;
-
-       status = socket_create("ip", SOCKET_TYPE_DGRAM, &cldap->sock, 0);
-       if (!NT_STATUS_IS_OK(status)) goto failed;
-
-       talloc_steal(cldap, cldap->sock);
-
-       cldap->fde = event_add_fd(cldap->event_ctx, cldap, 
-                                     socket_get_fd(cldap->sock), 0,
-                                     cldap_socket_handler, cldap);
-
-       cldap->send_queue = NULL;
-       cldap->incoming.handler = NULL;
-       cldap->iconv_convenience = iconv_convenience;
-       
-       return cldap;
-
-failed:
-       talloc_free(cldap);
-       return NULL;
-}
-
-
-/*
-  setup a handler for incoming requests
-*/
-NTSTATUS cldap_set_incoming_handler(struct cldap_socket *cldap,
-                                 void (*handler)(struct cldap_socket *, struct ldap_message *, 
-                                                 struct socket_address *),
-                                 void *private_data)
-{
-       cldap->incoming.handler = handler;
-       cldap->incoming.private_data = private_data;
-       EVENT_FD_READABLE(cldap->fde);
-       return NT_STATUS_OK;
-}
-
-/*
-  queue a cldap request for send
-*/
-struct cldap_request *cldap_search_send(struct cldap_socket *cldap, 
-                                       struct cldap_search *io)
-{
-       struct ldap_message *msg;
-       struct cldap_request *req;
-       struct ldap_SearchRequest *search;
-
-       req = talloc_zero(cldap, struct cldap_request);
-       if (req == NULL) goto failed;
-
-       req->cldap       = cldap;
-       req->state       = CLDAP_REQUEST_SEND;
-       req->timeout     = io->in.timeout;
-       req->num_retries = io->in.retries;
-       req->is_reply    = false;
-       req->asn1        = asn1_init(req);
-       if (!req->asn1) {
-               goto failed;
-       }
-
-       req->dest = socket_address_from_strings(req, cldap->sock->backend_name,
-                                               io->in.dest_address, 
-                                               io->in.dest_port);
-       if (!req->dest) goto failed;
-
-       req->message_id = idr_get_new_random(cldap->idr, req, UINT16_MAX);
-       if (req->message_id == -1) goto failed;
-
-       talloc_set_destructor(req, cldap_request_destructor);
-
-       msg = talloc(req, struct ldap_message);
-       if (msg == NULL) goto failed;
-       msg->messageid       = req->message_id;
-       msg->type            = LDAP_TAG_SearchRequest;
-       msg->controls        = NULL;
-       search = &msg->r.SearchRequest;
-
-       search->basedn         = "";
-       search->scope          = LDAP_SEARCH_SCOPE_BASE;
-       search->deref          = LDAP_DEREFERENCE_NEVER;
-       search->timelimit      = 0;
-       search->sizelimit      = 0;
-       search->attributesonly = false;
-       search->num_attributes = str_list_length(io->in.attributes);
-       search->attributes     = io->in.attributes;
-       search->tree           = ldb_parse_tree(req, io->in.filter);
-       if (search->tree == NULL) {
-               goto failed;
-       }
-
-       if (!ldap_encode(msg, NULL, &req->encoded, req)) {
-               DEBUG(0,("Failed to encode cldap message to %s:%d\n",
-                        req->dest->addr, req->dest->port));
-               goto failed;
-       }
-
-       DLIST_ADD_END(cldap->send_queue, req, struct cldap_request *);
-
-       EVENT_FD_WRITEABLE(cldap->fde);
-
-       return req;
-
-failed:
-       talloc_free(req);
-       return NULL;
-}
-
-
-/*
-  queue a cldap reply for send
-*/
-NTSTATUS cldap_reply_send(struct cldap_socket *cldap, struct cldap_reply *io)
-{
-       struct ldap_message *msg;
-       struct cldap_request *req;
-       DATA_BLOB blob1, blob2;
-       NTSTATUS status = NT_STATUS_NO_MEMORY;
-
-       req = talloc_zero(cldap, struct cldap_request);
-       if (req == NULL) goto failed;
-
-       req->cldap       = cldap;
-       req->state       = CLDAP_REQUEST_SEND;
-       req->is_reply    = true;
-       req->asn1        = asn1_init(req);
-       if (!req->asn1) {
-               goto failed;
-       }
-
-       req->dest        = io->dest;
-       if (talloc_reference(req, io->dest) == NULL) goto failed;
-
-       talloc_set_destructor(req, cldap_request_destructor);
-
-       msg = talloc(req, struct ldap_message);
-       if (msg == NULL) goto failed;
-       msg->messageid       = io->messageid;
-       msg->controls        = NULL;
-       
-       if (io->response) {
-               msg->type = LDAP_TAG_SearchResultEntry;
-               msg->r.SearchResultEntry = *io->response;
-
-               if (!ldap_encode(msg, NULL, &blob1, req)) {
-                       DEBUG(0,("Failed to encode cldap message to %s:%d\n",
-                                req->dest->addr, req->dest->port));
-                       status = NT_STATUS_INVALID_PARAMETER;
-                       goto failed;
-               }
-       } else {
-               blob1 = data_blob(NULL, 0);
-       }
-
-       msg->type = LDAP_TAG_SearchResultDone;
-       msg->r.SearchResultDone = *io->result;
-
-       if (!ldap_encode(msg, NULL, &blob2, req)) {
-               DEBUG(0,("Failed to encode cldap message to %s:%d\n",
-                        req->dest->addr, req->dest->port));
-               status = NT_STATUS_INVALID_PARAMETER;
-               goto failed;
-       }
-
-       req->encoded = data_blob_talloc(req, NULL, blob1.length + blob2.length);
-       if (req->encoded.data == NULL) goto failed;
-
-       memcpy(req->encoded.data, blob1.data, blob1.length);
-       memcpy(req->encoded.data+blob1.length, blob2.data, blob2.length);
-
-       DLIST_ADD_END(cldap->send_queue, req, struct cldap_request *);
-
-       EVENT_FD_WRITEABLE(cldap->fde);
-
-       return NT_STATUS_OK;
-
-failed:
-       talloc_free(req);
-       return status;
-}
-
-/*
-  receive a cldap reply
-*/
-NTSTATUS cldap_search_recv(struct cldap_request *req, 
-                          TALLOC_CTX *mem_ctx, 
-                          struct cldap_search *io)
-{
-       struct ldap_message *ldap_msg;
-       NTSTATUS status;
-
-       if (req == NULL) {
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       while (req->state < CLDAP_REQUEST_DONE) {
-               if (event_loop_once(req->cldap->event_ctx) != 0) {
-                       talloc_free(req);
-                       return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
-               }
-       }
-
-       if (req->state == CLDAP_REQUEST_ERROR) {
-               status = req->status;
-               talloc_free(req);
-               return status;
-       }
-
-       ldap_msg = talloc(mem_ctx, struct ldap_message);
-       NT_STATUS_HAVE_NO_MEMORY(ldap_msg);
-
-       status = ldap_decode(req->asn1, NULL, ldap_msg);
-       if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(2,("Failed to decode cldap search reply: %s\n", nt_errstr(status)));
-               talloc_free(req);
-               return status;
-       }
-
-       ZERO_STRUCT(io->out);
-
-       /* the first possible form has a search result in first place */
-       if (ldap_msg->type == LDAP_TAG_SearchResultEntry) {
-               io->out.response = talloc(mem_ctx, struct ldap_SearchResEntry);
-               NT_STATUS_HAVE_NO_MEMORY(io->out.response);
-               *io->out.response = ldap_msg->r.SearchResultEntry;
-
-               /* decode the 2nd part */
-               status = ldap_decode(req->asn1, NULL, ldap_msg);
-               if (!NT_STATUS_IS_OK(status)) {
-                       DEBUG(2,("Failed to decode cldap search result entry: %s\n", nt_errstr(status)));
-                       talloc_free(req);
-                       return status;
-               }
-       }
-
-       if (ldap_msg->type != LDAP_TAG_SearchResultDone) {
-               talloc_free(req);
-               return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
-       }
-
-       io->out.result = talloc(mem_ctx, struct ldap_Result);
-       NT_STATUS_HAVE_NO_MEMORY(io->out.result);
-       *io->out.result = ldap_msg->r.SearchResultDone;
-
-       talloc_free(req);
-
-       if (io->out.result->resultcode != LDAP_SUCCESS) {
-               return NT_STATUS_LDAP(io->out.result->resultcode);
-       }
-       return NT_STATUS_OK;
-}
-
-
-/*
-  synchronous cldap search
-*/
-NTSTATUS cldap_search(struct cldap_socket *cldap, 
-                     TALLOC_CTX *mem_ctx, 
-                     struct cldap_search *io)
-{
-       struct cldap_request *req = cldap_search_send(cldap, io);
-       return cldap_search_recv(req, mem_ctx, io);
-}
-
-
-
-/*
-  queue a cldap netlogon for send
-*/
-struct cldap_request *cldap_netlogon_send(struct cldap_socket *cldap, 
-                                         struct cldap_netlogon *io)
-{
-       struct cldap_search search;
-       char *filter;
-       struct cldap_request *req;
-       const char *attr[] = { "NetLogon", NULL };
-       TALLOC_CTX *tmp_ctx = talloc_new(cldap);
-
-       filter = talloc_asprintf(tmp_ctx, "(&(NtVer=%s)", 
-                                ldap_encode_ndr_uint32(tmp_ctx, io->in.version));
-       if (filter == NULL) goto failed;
-       if (io->in.user) {
-               filter = talloc_asprintf_append_buffer(filter, "(User=%s)", io->in.user);
-               if (filter == NULL) goto failed;
-       }
-       if (io->in.host) {
-               filter = talloc_asprintf_append_buffer(filter, "(Host=%s)", io->in.host);
-               if (filter == NULL) goto failed;
-       }
-       if (io->in.realm) {
-               filter = talloc_asprintf_append_buffer(filter, "(DnsDomain=%s)", io->in.realm);
-               if (filter == NULL) goto failed;
-       }
-       if (io->in.acct_control != -1) {
-               filter = talloc_asprintf_append_buffer(filter, "(AAC=%s)", 
-                                               ldap_encode_ndr_uint32(tmp_ctx, io->in.acct_control));
-               if (filter == NULL) goto failed;
-       }
-       if (io->in.domain_sid) {
-               struct dom_sid *sid = dom_sid_parse_talloc(tmp_ctx, io->in.domain_sid);
-               if (sid == NULL) goto failed;
-               filter = talloc_asprintf_append_buffer(filter, "(domainSid=%s)",
-                                               ldap_encode_ndr_dom_sid(tmp_ctx, sid));
-               if (filter == NULL) goto failed;
-       }
-       if (io->in.domain_guid) {
-               struct GUID guid;
-               NTSTATUS status;
-               status = GUID_from_string(io->in.domain_guid, &guid);
-               if (!NT_STATUS_IS_OK(status)) goto failed;
-               filter = talloc_asprintf_append_buffer(filter, "(DomainGuid=%s)",
-                                               ldap_encode_ndr_GUID(tmp_ctx, &guid));
-               if (filter == NULL) goto failed;
-       }
-       filter = talloc_asprintf_append_buffer(filter, ")");
-       if (filter == NULL) goto failed;
-
-       search.in.dest_address = io->in.dest_address;
-       search.in.dest_port    = io->in.dest_port;
-       search.in.filter       = filter;
-       search.in.attributes   = attr;
-       search.in.timeout      = 2;
-       search.in.retries      = 2;
-
-       req = cldap_search_send(cldap, &search);
-
-       talloc_free(tmp_ctx);
-       return req;
-failed:
-       talloc_free(tmp_ctx);
-       return NULL;
-}
-
-
-/*
-  receive a cldap netlogon reply
-*/
-NTSTATUS cldap_netlogon_recv(struct cldap_request *req, 
-                            TALLOC_CTX *mem_ctx, 
-                            struct cldap_netlogon *io)
-{
-       NTSTATUS status;
-       struct cldap_search search;
-       struct cldap_socket *cldap;
-       DATA_BLOB *data;
-
-       cldap = req->cldap;
-
-       status = cldap_search_recv(req, mem_ctx, &search);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
-       if (search.out.response == NULL) {
-               return NT_STATUS_NOT_FOUND;
-       }
-
-       if (search.out.response->num_attributes != 1 ||
-           strcasecmp(search.out.response->attributes[0].name, "netlogon") != 0 ||
-           search.out.response->attributes[0].num_values != 1 ||
-           search.out.response->attributes[0].values->length < 2) {
-               return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
-       }
-       data = search.out.response->attributes[0].values;
-
-       status = pull_netlogon_samlogon_response(data, mem_ctx, req->cldap->iconv_convenience,
-                                                &io->out.netlogon);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
-       
-       if (io->in.map_response) {
-               map_netlogon_samlogon_response(&io->out.netlogon);
-       }
-       return NT_STATUS_OK;
-}
-
-/*
-  sync cldap netlogon search
-*/
-NTSTATUS cldap_netlogon(struct cldap_socket *cldap, 
-                       TALLOC_CTX *mem_ctx, struct cldap_netlogon *io)
-{
-       struct cldap_request *req = cldap_netlogon_send(cldap, io);
-       return cldap_netlogon_recv(req, mem_ctx, io);
-}
-
-
-/*
-  send an empty reply (used on any error, so the client doesn't keep waiting
-  or send the bad request again)
-*/
-NTSTATUS cldap_empty_reply(struct cldap_socket *cldap, 
-                          uint32_t message_id,
-                          struct socket_address *src)
-{
-       NTSTATUS status;
-       struct cldap_reply reply;
-       struct ldap_Result result;
-
-       reply.messageid    = message_id;
-       reply.dest         = src;
-       reply.response     = NULL;
-       reply.result       = &result;
-
-       ZERO_STRUCT(result);
-
-       status = cldap_reply_send(cldap, &reply);
-
-       return status;
-}
-
-/*
-  send an error reply (used on any error, so the client doesn't keep waiting
-  or send the bad request again)
-*/
-NTSTATUS cldap_error_reply(struct cldap_socket *cldap, 
-                          uint32_t message_id,
-                          struct socket_address *src,
-                          int resultcode,
-                          const char *errormessage)
-{
-       NTSTATUS status;
-       struct cldap_reply reply;
-       struct ldap_Result result;
-
-       reply.messageid    = message_id;
-       reply.dest         = src;
-       reply.response     = NULL;
-       reply.result       = &result;
-
-       ZERO_STRUCT(result);
-       result.resultcode       = resultcode;
-       result.errormessage     = errormessage;
-
-       status = cldap_reply_send(cldap, &reply);
-
-       return status;
-}
-
-
-/*
-  send a netlogon reply 
-*/
-NTSTATUS cldap_netlogon_reply(struct cldap_socket *cldap, 
-                             uint32_t message_id,
-                             struct socket_address *src,
-                             uint32_t version,
-                             struct netlogon_samlogon_response *netlogon)
-{
-       NTSTATUS status;
-       struct cldap_reply reply;
-       struct ldap_SearchResEntry response;
-       struct ldap_Result result;
-       TALLOC_CTX *tmp_ctx = talloc_new(cldap);
-       DATA_BLOB blob;
-
-       status = push_netlogon_samlogon_response(&blob, tmp_ctx, cldap->iconv_convenience,
-                                                netlogon);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
-       reply.messageid    = message_id;
-       reply.dest         = src;
-       reply.response     = &response;
-       reply.result       = &result;
-
-       ZERO_STRUCT(result);
-
-       response.dn = "";
-       response.num_attributes = 1;
-       response.attributes = talloc(tmp_ctx, struct ldb_message_element);
-       NT_STATUS_HAVE_NO_MEMORY(response.attributes);
-       response.attributes->name = "netlogon";
-       response.attributes->num_values = 1;
-       response.attributes->values = &blob;
-
-       status = cldap_reply_send(cldap, &reply);
-
-       talloc_free(tmp_ctx);
-
-       return status;
-}
-
-
diff --git a/source4/libcli/cldap/cldap.h b/source4/libcli/cldap/cldap.h
deleted file mode 100644 (file)
index 8951daa..0000000
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
-   Unix SMB/CIFS implementation.
-
-   a async CLDAP library
-
-   Copyright (C) Andrew Tridgell 2005
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
-
-   This program 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 General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "../lib/util/asn1.h"
-#include "../libcli/netlogon.h"
-
-struct ldap_message;
-
-enum cldap_request_state {CLDAP_REQUEST_SEND, 
-                         CLDAP_REQUEST_WAIT, 
-                         CLDAP_REQUEST_DONE,
-                         CLDAP_REQUEST_ERROR};
-
-/*
-  a cldap request packet
-*/
-struct cldap_request {
-       struct cldap_request *next, *prev;
-
-       struct cldap_socket *cldap;
-
-       enum cldap_request_state state;
-       NTSTATUS status;
-
-       /* where to send the request */
-       struct socket_address *dest;
-
-       /* timeout between retries (seconds) */
-       int timeout;
-       int num_retries;
-
-       bool is_reply;
-
-       /* the ldap message_id */
-       int message_id;
-
-       struct tevent_timer *te;
-
-       /* the encoded request */
-       DATA_BLOB encoded;
-
-       /* the reply data */
-       struct asn1_data *asn1;
-
-       /* information on what to do on completion */
-       struct {
-               void (*fn)(struct cldap_request *);
-               void *private_data;
-       } async;
-};
-
-/*
-  context structure for operations on cldap packets
-*/
-struct cldap_socket {
-       struct socket_context *sock;
-       struct tevent_context *event_ctx;
-       struct smb_iconv_convenience *iconv_convenience;
-
-       /* the fd event */
-       struct tevent_fd *fde;
-
-       /* a queue of outgoing requests */
-       struct cldap_request *send_queue;
-
-       /* mapping from message_id to pending request */
-       struct idr_context *idr;
-
-       /* what to do with incoming request packets */
-       struct {
-               void (*handler)(struct cldap_socket *, struct ldap_message *, 
-                               struct socket_address *);
-               void *private_data;
-       } incoming;
-};
-
-
-/*
- a general cldap search request  
-*/
-struct cldap_search {
-       struct {
-               const char *dest_address;
-               uint16_t dest_port;
-               const char *filter;
-               const char **attributes;
-               int timeout;
-               int retries;
-       } in;
-       struct {
-               struct ldap_SearchResEntry *response;
-               struct ldap_Result         *result;
-       } out;
-};
-
-struct cldap_socket *cldap_socket_init(TALLOC_CTX *mem_ctx, 
-                                      struct tevent_context *event_ctx, 
-                                      struct smb_iconv_convenience *iconv_convenience);
-NTSTATUS cldap_set_incoming_handler(struct cldap_socket *cldap,
-                                   void (*handler)(struct cldap_socket *, struct ldap_message *, 
-                                                   struct socket_address *),
-                                   void *private_data);
-struct cldap_request *cldap_search_send(struct cldap_socket *cldap, 
-                                       struct cldap_search *io);
-NTSTATUS cldap_search_recv(struct cldap_request *req, TALLOC_CTX *mem_ctx, 
-                          struct cldap_search *io);
-NTSTATUS cldap_search(struct cldap_socket *cldap, TALLOC_CTX *mem_ctx, 
-                     struct cldap_search *io);
-
-
-/*
-  a general cldap reply
-*/
-struct cldap_reply {
-       uint32_t messageid;
-       struct socket_address *dest;
-       struct ldap_SearchResEntry *response;
-       struct ldap_Result         *result;
-};
-
-NTSTATUS cldap_reply_send(struct cldap_socket *cldap, struct cldap_reply *io);
-
-NTSTATUS cldap_empty_reply(struct cldap_socket *cldap, 
-                          uint32_t message_id,
-                          struct socket_address *src);
-NTSTATUS cldap_error_reply(struct cldap_socket *cldap, 
-                          uint32_t message_id,
-                          struct socket_address *src,
-                          int resultcode,
-                          const char *errormessage);
-
-/*
-  a netlogon cldap request  
-*/
-struct cldap_netlogon {
-       struct {
-               const char *dest_address;
-               uint16_t dest_port;
-               const char *realm;
-               const char *host;
-               const char *user;
-               const char *domain_guid;
-               const char *domain_sid;
-               int acct_control;
-               uint32_t version;
-               bool map_response;
-       } in;
-       struct {
-               struct netlogon_samlogon_response netlogon;
-       } out;
-};
-
-struct cldap_request *cldap_netlogon_send(struct cldap_socket *cldap, 
-                                         struct cldap_netlogon *io);
-NTSTATUS cldap_netlogon_recv(struct cldap_request *req, 
-                            TALLOC_CTX *mem_ctx, 
-                            struct cldap_netlogon *io);
-NTSTATUS cldap_netlogon(struct cldap_socket *cldap, 
-                       TALLOC_CTX *mem_ctx, struct cldap_netlogon *io);
-NTSTATUS cldap_netlogon_reply(struct cldap_socket *cldap, 
-                             uint32_t message_id,
-                             struct socket_address *src,
-                             uint32_t version,
-                             struct netlogon_samlogon_response *netlogon);
index dc3431ab9fc6d1121a48f5a5976b64ed7811b8f0..5b50bdfcbec2a8b793a5b652305bf6f714de25eb 100644 (file)
@@ -96,13 +96,6 @@ LIBCLI_DGRAM_OBJ_FILES = $(addprefix $(libclisrcdir)/dgram/, \
        netlogon.o \
        browse.o)
 
-[SUBSYSTEM::LIBCLI_CLDAP]
-PUBLIC_DEPENDENCIES = LIBCLI_LDAP
-PRIVATE_DEPENDENCIES = LIBSAMBA-UTIL LIBLDB LIBCLI_NETLOGON
-
-LIBCLI_CLDAP_OBJ_FILES = $(libclisrcdir)/cldap/cldap.o
-# PUBLIC_HEADERS += $(libclisrcdir)/cldap/cldap.h
-
 [SUBSYSTEM::LIBCLI_WREPL]
 PUBLIC_DEPENDENCIES = NDR_WINSREPL samba_socket LIBEVENTS LIBPACKET
 
index bf046745e6a3aacc48be95fbbc3dc56cb195e782..dbbabd6a6da636f8b9e97bf17d6d101aec5c4f34 100644 (file)
@@ -731,12 +731,12 @@ struct libnet_BecomeDC_state {
        struct libnet_BecomeDC_Callbacks callbacks;
 };
 
-static void becomeDC_recv_cldap(struct cldap_request *req);
+static void becomeDC_recv_cldap(struct tevent_req *req);
 
 static void becomeDC_send_cldap(struct libnet_BecomeDC_state *s)
 {
        struct composite_context *c = s->creq;
-       struct cldap_request *req;
+       struct tevent_req *req;
 
        s->cldap.io.in.dest_address     = s->source_dsa.address;
        s->cldap.io.in.dest_port        = lp_cldap_port(s->libnet->lp_ctx);
@@ -749,25 +749,27 @@ static void becomeDC_send_cldap(struct libnet_BecomeDC_state *s)
        s->cldap.io.in.version          = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX;
        s->cldap.io.in.map_response     = true;
 
-       s->cldap.sock = cldap_socket_init(s, s->libnet->event_ctx, 
-                                         lp_iconv_convenience(s->libnet->lp_ctx));
-       if (composite_nomem(s->cldap.sock, c)) return;
+       c->status = cldap_socket_init(s, s->libnet->event_ctx,
+                                     NULL, NULL, &s->cldap.sock);//TODO
+       if (!composite_is_ok(c)) return;
 
-       req = cldap_netlogon_send(s->cldap.sock, &s->cldap.io);
+       req = cldap_netlogon_send(s, s->cldap.sock, &s->cldap.io);
        if (composite_nomem(req, c)) return;
-       req->async.fn           = becomeDC_recv_cldap;
-       req->async.private_data = s;
+       tevent_req_set_callback(req, becomeDC_recv_cldap, s);
 }
 
 static void becomeDC_connect_ldap1(struct libnet_BecomeDC_state *s);
 
-static void becomeDC_recv_cldap(struct cldap_request *req)
+static void becomeDC_recv_cldap(struct tevent_req *req)
 {
-       struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data,
+       struct libnet_BecomeDC_state *s = tevent_req_callback_data(req,
                                          struct libnet_BecomeDC_state);
        struct composite_context *c = s->creq;
 
-       c->status = cldap_netlogon_recv(req, s, &s->cldap.io);
+       c->status = cldap_netlogon_recv(req,
+                                       lp_iconv_convenience(s->libnet->lp_ctx),
+                                       s, &s->cldap.io);
+       talloc_free(req);
        if (!composite_is_ok(c)) return;
 
        s->cldap.netlogon = s->cldap.io.out.netlogon.data.nt5_ex;
index 4a32ab92ed58b4a1e6559ecfac473f254e29eac1..8a002b24a4b1e03346f8964743e65cdd8b196fa4 100644 (file)
@@ -56,8 +56,14 @@ NTSTATUS libnet_FindSite(TALLOC_CTX *ctx, struct libnet_context *lctx, struct li
        search.in.version = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX;
        search.in.map_response = true;
 
-       cldap = cldap_socket_init(tmp_ctx, lctx->event_ctx, lp_iconv_convenience(lctx->lp_ctx));
-       status = cldap_netlogon(cldap, tmp_ctx, &search);
+       /* we want to use non async calls, so we're not passing an event context */
+       status = cldap_socket_init(tmp_ctx, NULL, NULL, NULL, &cldap);//TODO
+       if (!NT_STATUS_IS_OK(status)) {
+               talloc_free(tmp_ctx);
+               r->out.error_string = NULL;
+               return status;
+       }
+       status = cldap_netlogon(cldap, lp_iconv_convenience(lctx->lp_ctx), tmp_ctx, &search);
        if (!NT_STATUS_IS_OK(status)
            || !search.out.netlogon.data.nt5_ex.client_site) {
                /*
index 3f92daab2817aa088b00f424ae7cf717e8aba4f1..e0e5e421151a87b56f8506403b9af47703fdd022 100644 (file)
@@ -250,12 +250,12 @@ struct libnet_UnbecomeDC_state {
        } dest_dsa;
 };
 
-static void unbecomeDC_recv_cldap(struct cldap_request *req);
+static void unbecomeDC_recv_cldap(struct tevent_req *req);
 
 static void unbecomeDC_send_cldap(struct libnet_UnbecomeDC_state *s)
 {
        struct composite_context *c = s->creq;
-       struct cldap_request *req;
+       struct tevent_req *req;
 
        s->cldap.io.in.dest_address     = s->source_dsa.address;
        s->cldap.io.in.dest_port        = lp_cldap_port(s->libnet->lp_ctx);
@@ -268,25 +268,27 @@ static void unbecomeDC_send_cldap(struct libnet_UnbecomeDC_state *s)
        s->cldap.io.in.version          = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX;
        s->cldap.io.in.map_response     = true;
 
-       s->cldap.sock = cldap_socket_init(s, s->libnet->event_ctx,
-                                         lp_iconv_convenience(s->libnet->lp_ctx));
-       if (composite_nomem(s->cldap.sock, c)) return;
+       c->status = cldap_socket_init(s, s->libnet->event_ctx,
+                                     NULL, NULL, &s->cldap.sock);//TODO
+       if (!composite_is_ok(c)) return;
 
-       req = cldap_netlogon_send(s->cldap.sock, &s->cldap.io);
+       req = cldap_netlogon_send(s, s->cldap.sock, &s->cldap.io);
        if (composite_nomem(req, c)) return;
-       req->async.fn           = unbecomeDC_recv_cldap;
-       req->async.private_data = s;
+       tevent_req_set_callback(req, unbecomeDC_recv_cldap, s);
 }
 
 static void unbecomeDC_connect_ldap(struct libnet_UnbecomeDC_state *s);
 
-static void unbecomeDC_recv_cldap(struct cldap_request *req)
+static void unbecomeDC_recv_cldap(struct tevent_req *req)
 {
-       struct libnet_UnbecomeDC_state *s = talloc_get_type(req->async.private_data,
+       struct libnet_UnbecomeDC_state *s = tevent_req_callback_data(req,
                                            struct libnet_UnbecomeDC_state);
        struct composite_context *c = s->creq;
 
-       c->status = cldap_netlogon_recv(req, s, &s->cldap.io);
+       c->status = cldap_netlogon_recv(req,
+                                       lp_iconv_convenience(s->libnet->lp_ctx),
+                                       s, &s->cldap.io);
+       talloc_free(req);
        if (!composite_is_ok(c)) return;
 
        s->cldap.netlogon = s->cldap.io.out.netlogon.data.nt5_ex;
index 8ea9727ed3bc2a92a3c92339ce642f4b65b0073a..a143604f33c818df66c418d8e82e79dadaa410c1 100644 (file)
@@ -21,6 +21,7 @@ mkinclude ../lib/nss_wrapper/config.mk
 mkinclude lib/stream/config.mk
 mkinclude ../lib/util/config.mk
 mkinclude ../lib/tdr/config.mk
+mkinclude ../lib/tsocket/config.mk
 mkinclude ../lib/crypto/config.mk
 mkinclude ../lib/torture/config.mk
 mkinclude lib/basic.mk
index 1ddc628a5c643e6f1de23832fe7808a15a9dc7dd..98669288a8f392bf62bbe3659a2d6ef851417e21 100644 (file)
@@ -28,6 +28,7 @@
 #include "torture/torture.h"
 #include "lib/ldb/include/ldb.h"
 #include "param/param.h"
+#include "../lib/tsocket/tsocket.h"
 
 #define CHECK_STATUS(status, correct) torture_assert_ntstatus_equal(tctx, status, correct, "incorrect status")
 
@@ -45,12 +46,21 @@ static bool test_cldap_netlogon(struct torture_context *tctx, const char *dest)
        struct netlogon_samlogon_response n1;
        struct GUID guid;
        int i;
+       struct smb_iconv_convenience *iconv_convenience = lp_iconv_convenience(tctx->lp_ctx);
+       struct tsocket_address *dest_addr;
+       int ret;
 
-       cldap = cldap_socket_init(tctx, tctx->ev, lp_iconv_convenience(tctx->lp_ctx));
+       ret = tsocket_address_inet_from_strings(tctx, "ip",
+                                               dest,
+                                               lp_cldap_port(tctx->lp_ctx),
+                                               &dest_addr);
+
+       status = cldap_socket_init(tctx, NULL, NULL, dest_addr, &cldap);
+       CHECK_STATUS(status, NT_STATUS_OK);
 
        ZERO_STRUCT(search);
-       search.in.dest_address = dest;
-       search.in.dest_port = lp_cldap_port(tctx->lp_ctx);
+       search.in.dest_address = NULL;//dest;
+       search.in.dest_port = 0;//lp_cldap_port(tctx->lp_ctx);
        search.in.acct_control = -1;
        search.in.version = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX;
        search.in.map_response = true;
@@ -59,7 +69,7 @@ static bool test_cldap_netlogon(struct torture_context *tctx, const char *dest)
 
        printf("Trying without any attributes\n");
        search = empty_search;
-       status = cldap_netlogon(cldap, tctx, &search);
+       status = cldap_netlogon(cldap, iconv_convenience, tctx, &search);
        CHECK_STATUS(status, NT_STATUS_OK);
 
        n1 = search.out.netlogon;
@@ -72,7 +82,7 @@ static bool test_cldap_netlogon(struct torture_context *tctx, const char *dest)
        for (i=0;i<256;i++) {
                search.in.version = i;
                printf("Trying netlogon level %d\n", i);
-               status = cldap_netlogon(cldap, tctx, &search);
+               status = cldap_netlogon(cldap, iconv_convenience, tctx, &search);
                CHECK_STATUS(status, NT_STATUS_OK);
        }
 
@@ -80,19 +90,19 @@ static bool test_cldap_netlogon(struct torture_context *tctx, const char *dest)
        for (i=0;i<31;i++) {
                search.in.version = (1<<i);
                printf("Trying netlogon level 0x%x\n", i);
-               status = cldap_netlogon(cldap, tctx, &search);
+               status = cldap_netlogon(cldap, iconv_convenience, tctx, &search);
                CHECK_STATUS(status, NT_STATUS_OK);
        }
 
        search.in.version = NETLOGON_NT_VERSION_5|NETLOGON_NT_VERSION_5EX|NETLOGON_NT_VERSION_IP;
 
-       status = cldap_netlogon(cldap, tctx, &search);
+       status = cldap_netlogon(cldap, iconv_convenience, tctx, &search);
        CHECK_STATUS(status, NT_STATUS_OK);
 
        printf("Trying with User=NULL\n");
 
        search.in.user = NULL;
-       status = cldap_netlogon(cldap, tctx, &search);
+       status = cldap_netlogon(cldap, iconv_convenience, tctx, &search);
        CHECK_STATUS(status, NT_STATUS_OK);
        CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, "");
        CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_RESPONSE_EX);
@@ -100,20 +110,20 @@ static bool test_cldap_netlogon(struct torture_context *tctx, const char *dest)
        printf("Trying with User=Administrator\n");
 
        search.in.user = "Administrator";
-       status = cldap_netlogon(cldap, tctx, &search);
+       status = cldap_netlogon(cldap, iconv_convenience, tctx, &search);
        CHECK_STATUS(status, NT_STATUS_OK);
 
        CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, search.in.user);
        CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_USER_UNKNOWN_EX);
 
        search.in.version = NETLOGON_NT_VERSION_5;
-       status = cldap_netlogon(cldap, tctx, &search);
+       status = cldap_netlogon(cldap, iconv_convenience, tctx, &search);
        CHECK_STATUS(status, NT_STATUS_OK);
 
        printf("Trying with User=NULL\n");
 
        search.in.user = NULL;
-       status = cldap_netlogon(cldap, tctx, &search);
+       status = cldap_netlogon(cldap, iconv_convenience, tctx, &search);
        CHECK_STATUS(status, NT_STATUS_OK);
        CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, "");
        CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_RESPONSE);
@@ -121,7 +131,7 @@ static bool test_cldap_netlogon(struct torture_context *tctx, const char *dest)
        printf("Trying with User=Administrator\n");
 
        search.in.user = "Administrator";
-       status = cldap_netlogon(cldap, tctx, &search);
+       status = cldap_netlogon(cldap, iconv_convenience, tctx, &search);
        CHECK_STATUS(status, NT_STATUS_OK);
 
        CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, search.in.user);
@@ -132,7 +142,7 @@ static bool test_cldap_netlogon(struct torture_context *tctx, const char *dest)
        printf("Trying with a GUID\n");
        search.in.realm       = NULL;
        search.in.domain_guid = GUID_string(tctx, &n1.data.nt5_ex.domain_uuid);
-       status = cldap_netlogon(cldap, tctx, &search);
+       status = cldap_netlogon(cldap, iconv_convenience, tctx, &search);
        CHECK_STATUS(status, NT_STATUS_OK);
        CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_USER_UNKNOWN_EX);
        CHECK_STRING(GUID_string(tctx, &search.out.netlogon.data.nt5_ex.domain_uuid), search.in.domain_guid);
@@ -141,13 +151,13 @@ static bool test_cldap_netlogon(struct torture_context *tctx, const char *dest)
        guid = GUID_random();
        search.in.user        = NULL;
        search.in.domain_guid = GUID_string(tctx, &guid);
-       status = cldap_netlogon(cldap, tctx, &search);
+       status = cldap_netlogon(cldap, iconv_convenience, tctx, &search);
        CHECK_STATUS(status, NT_STATUS_NOT_FOUND);
 
        printf("Trying with a AAC\n");
        search.in.acct_control = ACB_WSTRUST|ACB_SVRTRUST;
        search.in.realm = n1.data.nt5_ex.dns_domain;
-       status = cldap_netlogon(cldap, tctx, &search);
+       status = cldap_netlogon(cldap, iconv_convenience, tctx, &search);
        CHECK_STATUS(status, NT_STATUS_OK);
        CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_RESPONSE_EX);
        CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, "");
@@ -155,7 +165,7 @@ static bool test_cldap_netlogon(struct torture_context *tctx, const char *dest)
        printf("Trying with a zero AAC\n");
        search.in.acct_control = 0x0;
        search.in.realm = n1.data.nt5_ex.dns_domain;
-       status = cldap_netlogon(cldap, tctx, &search);
+       status = cldap_netlogon(cldap, iconv_convenience, tctx, &search);
        CHECK_STATUS(status, NT_STATUS_OK);
        CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_RESPONSE_EX);
        CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, "");
@@ -164,7 +174,7 @@ static bool test_cldap_netlogon(struct torture_context *tctx, const char *dest)
        search.in.acct_control = 0x0;
        search.in.user = "Administrator";
        search.in.realm = n1.data.nt5_ex.dns_domain;
-       status = cldap_netlogon(cldap, tctx, &search);
+       status = cldap_netlogon(cldap, iconv_convenience, tctx, &search);
        CHECK_STATUS(status, NT_STATUS_OK);
        CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_USER_UNKNOWN_EX);
        CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, "Administrator");
@@ -173,7 +183,7 @@ static bool test_cldap_netlogon(struct torture_context *tctx, const char *dest)
        search.in.user = NULL;
        search.in.acct_control = 0xFF00FF00;
        search.in.realm = n1.data.nt5_ex.dns_domain;
-       status = cldap_netlogon(cldap, tctx, &search);
+       status = cldap_netlogon(cldap, iconv_convenience, tctx, &search);
        CHECK_STATUS(status, NT_STATUS_OK);
        CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_RESPONSE_EX);
        CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, "");
@@ -181,14 +191,14 @@ static bool test_cldap_netlogon(struct torture_context *tctx, const char *dest)
        printf("Trying with a user only\n");
        search = empty_search;
        search.in.user = "Administrator";
-       status = cldap_netlogon(cldap, tctx, &search);
+       status = cldap_netlogon(cldap, iconv_convenience, tctx, &search);
        CHECK_STATUS(status, NT_STATUS_OK);
        CHECK_STRING(search.out.netlogon.data.nt5_ex.dns_domain, n1.data.nt5_ex.dns_domain);
        CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, search.in.user);
 
        printf("Trying with just a bad username\n");
        search.in.user = "___no_such_user___";
-       status = cldap_netlogon(cldap, tctx, &search);
+       status = cldap_netlogon(cldap, iconv_convenience, tctx, &search);
        CHECK_STATUS(status, NT_STATUS_OK);
        CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, search.in.user);
        CHECK_STRING(search.out.netlogon.data.nt5_ex.dns_domain, n1.data.nt5_ex.dns_domain);
@@ -197,12 +207,12 @@ static bool test_cldap_netlogon(struct torture_context *tctx, const char *dest)
        printf("Trying with just a bad domain\n");
        search = empty_search;
        search.in.realm = "___no_such_domain___";
-       status = cldap_netlogon(cldap, tctx, &search);
+       status = cldap_netlogon(cldap, iconv_convenience, tctx, &search);
        CHECK_STATUS(status, NT_STATUS_NOT_FOUND);
 
        printf("Trying with a incorrect domain and correct guid\n");
        search.in.domain_guid = GUID_string(tctx, &n1.data.nt5_ex.domain_uuid);
-       status = cldap_netlogon(cldap, tctx, &search);
+       status = cldap_netlogon(cldap, iconv_convenience, tctx, &search);
        CHECK_STATUS(status, NT_STATUS_OK);
        CHECK_STRING(search.out.netlogon.data.nt5_ex.dns_domain, n1.data.nt5_ex.dns_domain);
        CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, "");
@@ -210,7 +220,7 @@ static bool test_cldap_netlogon(struct torture_context *tctx, const char *dest)
 
        printf("Trying with a incorrect domain and incorrect guid\n");
        search.in.domain_guid = GUID_string(tctx, &guid);
-       status = cldap_netlogon(cldap, tctx, &search);
+       status = cldap_netlogon(cldap, iconv_convenience, tctx, &search);
        CHECK_STATUS(status, NT_STATUS_NOT_FOUND);
        CHECK_STRING(search.out.netlogon.data.nt5_ex.dns_domain, n1.data.nt5_ex.dns_domain);
        CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, "");
@@ -219,7 +229,7 @@ static bool test_cldap_netlogon(struct torture_context *tctx, const char *dest)
        printf("Trying with a incorrect GUID and correct domain\n");
        search.in.domain_guid = GUID_string(tctx, &guid);
        search.in.realm = n1.data.nt5_ex.dns_domain;
-       status = cldap_netlogon(cldap, tctx, &search);
+       status = cldap_netlogon(cldap, iconv_convenience, tctx, &search);
        CHECK_STATUS(status, NT_STATUS_OK);
        CHECK_STRING(search.out.netlogon.data.nt5_ex.dns_domain, n1.data.nt5_ex.dns_domain);
        CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, "");
@@ -239,10 +249,12 @@ static bool test_cldap_netlogon_flags(struct torture_context *tctx,
        struct cldap_netlogon search;
        struct netlogon_samlogon_response n1;
        uint32_t server_type;
+       struct smb_iconv_convenience *iconv_convenience = lp_iconv_convenience(tctx->lp_ctx);
 
-       cldap = cldap_socket_init(tctx, tctx->ev, lp_iconv_convenience(tctx->lp_ctx));
+       status = cldap_socket_init(tctx, NULL, NULL, NULL, &cldap);
+       CHECK_STATUS(status, NT_STATUS_OK);
 
-       printf("Printing out netlogon server type flags:\n");
+       printf("Printing out netlogon server type flags: %s\n", dest);
 
        ZERO_STRUCT(search);
        search.in.dest_address = dest;
@@ -251,7 +263,7 @@ static bool test_cldap_netlogon_flags(struct torture_context *tctx,
        search.in.version = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX;
        search.in.map_response = true;
 
-       status = cldap_netlogon(cldap, tctx, &search);
+       status = cldap_netlogon(cldap, iconv_convenience, tctx, &search);
        CHECK_STATUS(status, NT_STATUS_OK);
 
        n1 = search.out.netlogon;
@@ -348,10 +360,12 @@ static bool test_cldap_netlogon_flag_ds_dns_forest(struct torture_context *tctx,
        struct cldap_netlogon search;
        uint32_t server_type;
        struct netlogon_samlogon_response n1;
+       struct smb_iconv_convenience *iconv_convenience = lp_iconv_convenience(tctx->lp_ctx);
 
        bool result = true;
 
-       cldap = cldap_socket_init(tctx, tctx->ev, lp_iconv_convenience(tctx->lp_ctx));
+       status = cldap_socket_init(tctx, NULL, NULL, NULL, &cldap);
+       CHECK_STATUS(status, NT_STATUS_OK);
 
        printf("Testing netlogon server type flag NBT_SERVER_DS_DNS_FOREST: ");
 
@@ -362,7 +376,7 @@ static bool test_cldap_netlogon_flag_ds_dns_forest(struct torture_context *tctx,
        search.in.version = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX;
        search.in.map_response = true;
 
-       status = cldap_netlogon(cldap, tctx, &search);
+       status = cldap_netlogon(cldap, iconv_convenience, tctx, &search);
        CHECK_STATUS(status, NT_STATUS_OK);
 
        n1 = search.out.netlogon;
@@ -423,7 +437,8 @@ static bool test_cldap_generic(struct torture_context *tctx, const char *dest)
        const char *attrs2[] = { "currentTime", "highestCommittedUSN", "netlogon", NULL };
        const char *attrs3[] = { "netlogon", NULL };
 
-       cldap = cldap_socket_init(tctx, tctx->ev, lp_iconv_convenience(tctx->lp_ctx));
+       status = cldap_socket_init(tctx, NULL, NULL, NULL, &cldap);
+       CHECK_STATUS(status, NT_STATUS_OK);
 
        ZERO_STRUCT(search);
        search.in.dest_address = dest;
index ae2cb808360d93f3ee065496a524805ce4400eda..a422732b039100dc62975f6badd4b3b29eb10abb 100644 (file)
 */
 
 #include "includes.h"
-#include "lib/events/events.h"
+#include <tevent.h>
 #include "libcli/cldap/cldap.h"
 #include "libcli/resolve/resolve.h"
 #include "torture/torture.h"
 #include "param/param.h"
 
 struct bench_state {
+       struct torture_context *tctx;
        int pass_count, fail_count;
 };
 
-static void request_netlogon_handler(struct cldap_request *req)
+static void request_netlogon_handler(struct tevent_req *req)
 {
        struct cldap_netlogon io;
-       struct bench_state *state = talloc_get_type(req->async.private_data, struct bench_state);
+       struct bench_state *state = tevent_req_callback_data(req, struct bench_state);
        NTSTATUS status;
        TALLOC_CTX *tmp_ctx = talloc_new(NULL);
        io.in.version = 6;
-       status = cldap_netlogon_recv(req, tmp_ctx, &io);
+       status = cldap_netlogon_recv(req,
+                                    lp_iconv_convenience(state->tctx->lp_ctx),
+                                    tmp_ctx, &io);
+       talloc_free(req);
        if (NT_STATUS_IS_OK(status)) {
                state->pass_count++;
        } else {
@@ -58,10 +62,13 @@ static bool bench_cldap_netlogon(struct torture_context *tctx, const char *addre
        int timelimit = torture_setting_int(tctx, "timelimit", 10);
        struct cldap_netlogon search;
        struct bench_state *state;
+       NTSTATUS status;
 
-       cldap = cldap_socket_init(tctx, tctx->ev, lp_iconv_convenience(tctx->lp_ctx));
+       status = cldap_socket_init(tctx, tctx->ev, NULL, NULL, &cldap);
+       torture_assert_ntstatus_ok(tctx, status, "cldap_socket_init");
 
        state = talloc_zero(tctx, struct bench_state);
+       state->tctx = tctx;
 
        ZERO_STRUCT(search);
        search.in.dest_address = address;
@@ -72,11 +79,11 @@ static bool bench_cldap_netlogon(struct torture_context *tctx, const char *addre
        printf("Running CLDAP/netlogon for %d seconds\n", timelimit);
        while (timeval_elapsed(&tv) < timelimit) {
                while (num_sent - (state->pass_count+state->fail_count) < 10) {
-                       struct cldap_request *req;
-                       req = cldap_netlogon_send(cldap, &search);
+                       struct tevent_req *req;
+                       req = cldap_netlogon_send(state, cldap, &search);
+
+                       tevent_req_set_callback(req, request_netlogon_handler, state);
 
-                       req->async.private_data = state;
-                       req->async.fn = request_netlogon_handler;
                        num_sent++;
                        if (num_sent % 50 == 0) {
                                if (torture_setting_bool(tctx, "progress", true)) {
@@ -88,11 +95,11 @@ static bool bench_cldap_netlogon(struct torture_context *tctx, const char *addre
                        }
                }
 
-               event_loop_once(cldap->event_ctx);
+               tevent_loop_once(tctx->ev);
        }
 
        while (num_sent != (state->pass_count + state->fail_count)) {
-               event_loop_once(cldap->event_ctx);
+               tevent_loop_once(tctx->ev);
        }
 
        printf("%.1f queries per second (%d failures)  \n", 
@@ -103,13 +110,14 @@ static bool bench_cldap_netlogon(struct torture_context *tctx, const char *addre
        return ret;
 }
 
-static void request_rootdse_handler(struct cldap_request *req)
+static void request_rootdse_handler(struct tevent_req *req)
 {
        struct cldap_search io;
-       struct bench_state *state = talloc_get_type(req->async.private_data, struct bench_state);
+       struct bench_state *state = tevent_req_callback_data(req, struct bench_state);
        NTSTATUS status;
        TALLOC_CTX *tmp_ctx = talloc_new(NULL);
        status = cldap_search_recv(req, tmp_ctx, &io);
+       talloc_free(req);
        if (NT_STATUS_IS_OK(status)) {
                state->pass_count++;
        } else {
@@ -130,8 +138,10 @@ static bool bench_cldap_rootdse(struct torture_context *tctx, const char *addres
        int timelimit = torture_setting_int(tctx, "timelimit", 10);
        struct cldap_search search;
        struct bench_state *state;
+       NTSTATUS status;
 
-       cldap = cldap_socket_init(tctx, tctx->ev, lp_iconv_convenience(tctx->lp_ctx));
+       status = cldap_socket_init(tctx, tctx->ev, NULL, NULL, &cldap);
+       torture_assert_ntstatus_ok(tctx, status, "cldap_socket_init");
 
        state = talloc_zero(tctx, struct bench_state);
 
@@ -145,11 +155,11 @@ static bool bench_cldap_rootdse(struct torture_context *tctx, const char *addres
        printf("Running CLDAP/rootdse for %d seconds\n", timelimit);
        while (timeval_elapsed(&tv) < timelimit) {
                while (num_sent - (state->pass_count+state->fail_count) < 10) {
-                       struct cldap_request *req;
-                       req = cldap_search_send(cldap, &search);
+                       struct tevent_req *req;
+                       req = cldap_search_send(state, cldap, &search);
+
+                       tevent_req_set_callback(req, request_rootdse_handler, state);
 
-                       req->async.private_data = state;
-                       req->async.fn = request_rootdse_handler;
                        num_sent++;
                        if (num_sent % 50 == 0) {
                                if (torture_setting_bool(tctx, "progress", true)) {
index 847b32827b8dd2739eb5d285e65f51f2132540ad..1aaf914ceb8af7e7e790eb10717e5e410be81682 100644 (file)
@@ -273,7 +273,12 @@ static bool test_GetInfo(struct torture_context *tctx, struct DsSyncTest *ctx)
        struct cldap_socket *cldap;
        struct cldap_netlogon search;
 
-       cldap = cldap_socket_init(ctx, tctx->ev, lp_iconv_convenience(tctx->lp_ctx));
+       status = cldap_socket_init(ctx, NULL, NULL, NULL, &cldap);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("failed to setup cldap socket - %s\n",
+                       nt_errstr(status));
+               return false;
+       }
 
        r.in.bind_handle                = &ctx->admin.drsuapi.bind_handle;
        r.in.level                      = 1;
@@ -311,7 +316,7 @@ static bool test_GetInfo(struct torture_context *tctx, struct DsSyncTest *ctx)
        search.in.acct_control = -1;
        search.in.version               = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX;
        search.in.map_response = true;
-       status = cldap_netlogon(cldap, ctx, &search);
+       status = cldap_netlogon(cldap, lp_iconv_convenience(tctx->lp_ctx), ctx, &search);
        if (!NT_STATUS_IS_OK(status)) {
                const char *errstr = nt_errstr(status);
                ctx->site_name = talloc_asprintf(ctx, "%s", "Default-First-Site-Name");