On Fri, 2011-11-18 at 16:07 +0100, Sumit Bose wrote:
> On Thu, Nov 17, 2011 at 05:00:51PM -0500, Simo Sorce wrote:
> > Attached find a series of patches that implement a CLDAP server as a
> > dirsrv plugin.
> > 
> > The server right now responds only to a very limited class of requests,
> > as observed on the wire. But it can be easily expanded to respond to
> > additional requests as needed.
> > 
> > Tested against windows 2008 with which I had create a trust.
> > To test you need Sumit's uncommitted adtrust code to successfully create
> > the trust and provision the IPA tree with the right data.
> 
> The patch prevents dirsrv from shutting down cleanly, so NACK. But
> otherwise it is working great. I will rebase my patches on top of yours,
> fix some missing bits and send them here as well.

Ok here is a rebase/modified patchset.
I reworked it to have even less churn between patches (you should see
only additions and no deletions.

I also added a pipe() to deal with the worker thread shutdown.
This allows us to interrupt the poll() at any time and at the same time
tell the worker thread it is time to end.

I tested a dirsrv shutdown in gdb and it works as expected.

Simo.

-- 
Simo Sorce * Red Hat, Inc * New York
>From 9ffe37efbd18b5da084a8328766bacd6e3c31e0b Mon Sep 17 00:00:00 2001
From: Simo Sorce <sso...@redhat.com>
Date: Wed, 16 Nov 2011 09:59:46 -0500
Subject: [PATCH 1/6] Add NT domain GUID attribute.

We need this to be able to re-set it, as ipaUniqueID cannot be arbitraily set
to a value. Only needed for the domain object.
---
 install/share/60basev3.ldif |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/install/share/60basev3.ldif b/install/share/60basev3.ldif
index d118de2f04a81c0b858d20b5aeb997e6e313fd9a..f518541586b2df9ed08718098a7f170563aa4e1d 100644
--- a/install/share/60basev3.ldif
+++ b/install/share/60basev3.ldif
@@ -13,7 +13,8 @@ attributeTypes: (2.16.840.1.113730.3.8.11.6 NAME 'ipaNTLogonScript' DESC 'User L
 attributeTypes: (2.16.840.1.113730.3.8.11.7 NAME 'ipaNTProfilePath' DESC 'User Profile Path' EQUALITY caseIgnoreMatch OREDRING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA v3' )
 attributeTypes: (2.16.840.1.113730.3.8.11.8 NAME 'ipaNTHomeDirectory' DESC 'User Home Directory Path' EQUALITY caseIgnoreMatch OREDRING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA v3' )
 attributeTypes: (2.16.840.1.113730.3.8.11.9 NAME 'ipaNTHomeDirectoryDrive' DESC 'User Home Drive Letter' EQUALITY caseIgnoreMatch OREDRING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA v3' )
+attributeTypes: (2.16.840.1.113730.3.8.11.10 NAME 'ipaNTDomainGUID' DESC 'NT Domain GUID' EQUALITY caseIgnoreIA5Match OREDRING caseIgnoreIA5OrderingMatch SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'IPA v3' )
 objectClasses: (2.16.840.1.113730.3.8.12.1 NAME 'ipaExternalGroup' SUP top STRUCTURAL MUST ( cn ) MAY ( ipaExternalMember $ memberOf $ description $ owner) X-ORIGIN 'IPA v3' )
 objectClasses: (2.16.840.1.113730.3.8.12.2 NAME 'ipaNTUserAttrs' SUP top AUXILIARY MUST ( ipaNTSecurityIdentifier ) MAY ( ipaNTHash $ ipaNTLogonScript $ ipaNTProfilePath $ ipaNTHomeDirectory $ ipaNTHomeDirectoryDrive ) X-ORIGIN 'IPA v3' )
 objectClasses: (2.16.840.1.113730.3.8.12.3 NAME 'ipaNTGroupAttrs' SUP top AUXILIARY MUST ( ipaNTSecurityIdentifier ) X-ORIGIN 'IPA v3' )
-objectClasses: (2.16.840.1.113730.3.8.12.4 NAME 'ipaNTDomainAttrs' SUP top AUXILIARY MUST ( ipaNTSecurityIdentifier $ ipaNTFlatName ) MAY ( ipaNTFallbackPrimaryGroup ) X-ORIGIN 'IPA v3' )
+objectClasses: (2.16.840.1.113730.3.8.12.4 NAME 'ipaNTDomainAttrs' SUP top AUXILIARY MUST ( ipaNTSecurityIdentifier $ ipaNTFlatName $ ipaNTDomainGUID ) MAY ( ipaNTFallbackPrimaryGroup ) X-ORIGIN 'IPA v3' )
-- 
1.7.7.1

>From 2724eb2999af2af74d71a9c63af0a46099bca0ec Mon Sep 17 00:00:00 2001
From: Simo Sorce <sso...@redhat.com>
Date: Wed, 9 Nov 2011 19:03:48 -0500
Subject: [PATCH 2/6] Create skeleton CLDAP server as a DS plugin

---
 daemons/configure.ac                               |    2 +
 daemons/ipa-slapi-plugins/Makefile.am              |    1 +
 daemons/ipa-slapi-plugins/ipa-cldap/Makefile.am    |   49 ++++
 .../ipa-cldap/ipa-cldap-conf.ldif                  |   16 ++
 daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.c    |  238 ++++++++++++++++++++
 daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.h    |   72 ++++++
 .../ipa-slapi-plugins/ipa-cldap/ipa_cldap_worker.c |   49 ++++
 freeipa.spec.in                                    |   15 +-
 8 files changed, 436 insertions(+), 6 deletions(-)
 create mode 100644 daemons/ipa-slapi-plugins/ipa-cldap/Makefile.am
 create mode 100644 daemons/ipa-slapi-plugins/ipa-cldap/ipa-cldap-conf.ldif
 create mode 100644 daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.c
 create mode 100644 daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.h
 create mode 100644 daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_worker.c

diff --git a/daemons/configure.ac b/daemons/configure.ac
index f89c50d62a3d59c3dddd3439f285fe6e5d9b89ee..46f476574cee0d48910748496cfb1faa2df974bf 100644
--- a/daemons/configure.ac
+++ b/daemons/configure.ac
@@ -234,6 +234,7 @@ PKG_PROG_PKG_CONFIG()
 PKG_CHECK_MODULES([TALLOC], [talloc])
 PKG_CHECK_MODULES([TEVENT], [tevent])
 PKG_CHECK_MODULES([NDRPAC], [ndr_krb5pac])
+PKG_CHECK_MODULES([NDRNBT], [ndr_nbt])
 
 
 dnl ---------------------------------------------------------------------------
@@ -300,6 +301,7 @@ AC_CONFIG_FILES([
     Makefile
     ipa-kdb/Makefile
     ipa-slapi-plugins/Makefile
+    ipa-slapi-plugins/ipa-cldap/Makefile
     ipa-slapi-plugins/ipa-enrollment/Makefile
     ipa-slapi-plugins/ipa-lockout/Makefile
     ipa-slapi-plugins/ipa-pwd-extop/Makefile
diff --git a/daemons/ipa-slapi-plugins/Makefile.am b/daemons/ipa-slapi-plugins/Makefile.am
index 25f50d5f7c64f4daa88e71c6e9d600009a8c46fe..29b985e69424c9f2ce453ea3607cdb0e936bcce2 100644
--- a/daemons/ipa-slapi-plugins/Makefile.am
+++ b/daemons/ipa-slapi-plugins/Makefile.am
@@ -1,6 +1,7 @@
 NULL =
 
 SUBDIRS =			\
+	ipa-cldap		\
 	ipa-enrollment		\
 	ipa-lockout		\
 	ipa-modrdn		\
diff --git a/daemons/ipa-slapi-plugins/ipa-cldap/Makefile.am b/daemons/ipa-slapi-plugins/ipa-cldap/Makefile.am
new file mode 100644
index 0000000000000000000000000000000000000000..b563e98763d78298b64de92c59716bacd8c822a4
--- /dev/null
+++ b/daemons/ipa-slapi-plugins/ipa-cldap/Makefile.am
@@ -0,0 +1,49 @@
+NULL =
+
+PLUGIN_COMMON_DIR=../common
+
+INCLUDES =							\
+	-I.							\
+	-I$(srcdir)						\
+	-I$(PLUGIN_COMMON_DIR)					\
+	-I$(COMMON_BER_DIR)					\
+	-DPREFIX=\""$(prefix)"\" 				\
+	-DBINDIR=\""$(bindir)"\"				\
+	-DLIBDIR=\""$(libdir)"\" 				\
+	-DLIBEXECDIR=\""$(libexecdir)"\"			\
+	-DDATADIR=\""$(datadir)"\"				\
+	$(AM_CFLAGS)						\
+	$(LDAP_CFLAGS)						\
+	$(WARN_CFLAGS)						\
+	$(NDRNBT_CFLAGS)					\
+	$(NULL)
+
+plugindir = $(libdir)/dirsrv/plugins
+plugin_LTLIBRARIES = 			\
+	libipa_cldap.la			\
+	$(NULL)
+
+libipa_cldap_la_SOURCES = 		\
+	ipa_cldap_worker.c		\
+	ipa_cldap.c			\
+	$(NULL)
+
+libipa_cldap_la_LDFLAGS = -avoid-version
+
+libipa_cldap_la_LIBADD = 		\
+	$(LDAP_LIBS)			\
+	$(NDRNBT_LIBS)			\
+	$(NULL)
+
+appdir = $(IPA_DATA_DIR)
+app_DATA =			\
+	ipa-cldap-conf.ldif	\
+	$(NULL)
+
+EXTRA_DIST =			\
+	$(app_DATA)		\
+	$(NULL)
+
+MAINTAINERCLEANFILES =		\
+	*~			\
+	Makefile.in
diff --git a/daemons/ipa-slapi-plugins/ipa-cldap/ipa-cldap-conf.ldif b/daemons/ipa-slapi-plugins/ipa-cldap/ipa-cldap-conf.ldif
new file mode 100644
index 0000000000000000000000000000000000000000..2d70b9acfde7dabdb23c0db8dad49d84204b32b1
--- /dev/null
+++ b/daemons/ipa-slapi-plugins/ipa-cldap/ipa-cldap-conf.ldif
@@ -0,0 +1,16 @@
+dn: cn=ipa_cldap,cn=plugins,cn=config
+changetype: add
+objectclass: top
+objectclass: nsSlapdPlugin
+objectclass: extensibleObject
+cn: ipa_cldap
+nsslapd-pluginpath: libipa_cldap
+nsslapd-plugininitfunc: ipa_cldap_init
+nsslapd-plugintype: postoperation
+nsslapd-pluginenabled: on
+nsslapd-pluginid: ipa_cldap_init
+nsslapd-pluginversion: @PACKAGE_VERSION@
+nsslapd-pluginvendor: RedHat
+nsslapd-plugindescription: CLDAP Server to interoperate with AD
+nsslapd-plugin-depends-on-type: database
+nsslapd-basedn: $SUFFIX
diff --git a/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.c b/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.c
new file mode 100644
index 0000000000000000000000000000000000000000..d7a59d51229ca9fbf754a2600e42339dcc235698
--- /dev/null
+++ b/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.c
@@ -0,0 +1,238 @@
+/** BEGIN COPYRIGHT BLOCK
+ * 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/>.
+ *
+ * Additional permission under GPLv3 section 7:
+ *
+ * In the following paragraph, "GPL" means the GNU General Public
+ * License, version 3 or any later version, and "Non-GPL Code" means
+ * code that is governed neither by the GPL nor a license
+ * compatible with the GPL.
+ *
+ * You may link the code of this Program with Non-GPL Code and convey
+ * linked combinations including the two, provided that such Non-GPL
+ * Code only links to the code of this Program through those well
+ * defined interfaces identified in the file named EXCEPTION found in
+ * the source code files (the "Approved Interfaces"). The files of
+ * Non-GPL Code may instantiate templates or use macros or inline
+ * functions from the Approved Interfaces without causing the resulting
+ * work to be covered by the GPL. Only the copyright holders of this
+ * Program may make changes or additions to the list of Approved
+ * Interfaces.
+ *
+ * Authors:
+ * Simo Sorce <sso...@redhat.com>
+ *
+ * Copyright (C) 2011 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include "ipa_cldap.h"
+#include "util.h"
+
+Slapi_PluginDesc ipa_cldap_desc = {
+    IPA_CLDAP_PLUGIN_NAME,
+    "FreeIPA project",
+    "FreeIPA/3.0",
+    IPA_CLDAP_PLUGIN_DESC
+};
+
+static int ipa_cldap_start(Slapi_PBlock *pb)
+{
+    struct ipa_cldap_ctx *ctx;
+    int ret;
+
+    ret = slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &ctx);
+    if (ret) {
+        LOG_FATAL("No plugin context ?!\n");
+        return -1;
+    }
+
+    ret = pthread_create(&ctx->tid, NULL, ipa_cldap_worker, ctx);
+    if (ret) {
+        LOG_FATAL("Failed to create worker thread\n");
+        return -1;
+    }
+
+    LOG("Plugin statrup completed.\n");
+
+    return 0;
+}
+
+static int ipa_cldap_stop(Slapi_PBlock *pb)
+{
+    struct ipa_cldap_ctx *ctx;
+    void *retval;
+    int ret;
+
+    ret = slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &ctx);
+    if (ret) {
+        LOG_FATAL("No plugin context ?!\n");
+        return -1;
+    }
+
+    /* send stop signal to terminate worker thread */
+    write(ctx->stopfd[1], "", 1);
+    close(ctx->stopfd[1]);
+
+    ret = pthread_join(ctx->tid, &retval);
+    if (ret) {
+        LOG_FATAL("Failed to stop worker thread\n");
+        return -1;
+    }
+
+    LOG("Plugin shutdown completed.\n");
+
+    return 0;
+}
+
+static int ipa_cldap_init_service(Slapi_PBlock *pb,
+                                  struct ipa_cldap_ctx **cldap_ctx)
+{
+    struct ipa_cldap_ctx *ctx;
+    struct sockaddr_in6 addr;
+    Slapi_Entry *e;
+    int flags;
+    int val;
+    int ret;
+
+    ctx = calloc(1, sizeof(struct ipa_cldap_ctx));
+    if (!ctx) {
+        return ENOMEM;
+    }
+    ctx->sd = -1;
+
+    ret = slapi_pblock_get(pb, SLAPI_PLUGIN_IDENTITY, &ctx->plugin_id);
+    if ((ret != 0) || (NULL == ctx->plugin_id)) {
+        LOG_FATAL("Could not get identity or identity was NULL\n");
+        if (ret == 0) {
+            ret = -1;
+        }
+        goto done;
+    }
+
+    slapi_pblock_get(pb, SLAPI_PLUGIN_CONFIG_ENTRY, &e);
+    if (!e) {
+        LOG_FATAL("Plugin configuration not found!\n");
+        return -1;
+    }
+
+    ctx->base_dn = slapi_entry_attr_get_charptr(e, "nsslapd-basedn");
+    if (!ctx->base_dn) {
+        LOG_FATAL("Plugin configuration not found!\n");
+        return -1;
+    }
+
+    /* create a stop pipe so the main DS thread can interrupt the poll()
+     * of the worker thread at any time and cause the worker thread to
+     * immediately exit without waiting for timeouts or such */
+    ret = pipe(ctx->stopfd);
+    if (ret != 0) {
+        LOG_FATAL("Failed to stop pipe\n");
+        ret = EIO;
+        goto done;
+    }
+
+    ctx->sd = socket(PF_INET6, SOCK_DGRAM, 0);
+    if (ctx->sd == -1) {
+        LOG_FATAL("Failed to create socket\n");
+        ret = EIO;
+        goto done;
+    }
+
+    val = 1;
+    ret = setsockopt(ctx->sd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
+    if (ret == -1) {
+        ret = errno;
+        LOG("Failed to make socket immediately reusable (%d, %s)\n",
+            ret, strerror(ret));
+    }
+
+    memset(&addr, 0, sizeof(addr));
+    addr.sin6_family = AF_INET6;
+    addr.sin6_port = htons(CLDAP_PORT);
+
+    ret = bind(ctx->sd, (struct sockaddr *)&addr, sizeof(addr));
+    if (ret == -1) {
+        ret = errno;
+        LOG_FATAL("Failed to bind socket (%d, %s)\n", ret, strerror(ret));
+        goto done;
+    }
+
+    flags = fcntl(ctx->sd, F_GETFL);
+    if ((flags & O_NONBLOCK) == 0) {
+        ret = fcntl(ctx->sd, F_SETFL, flags | O_NONBLOCK);
+        if (ret == -1) {
+            ret = errno;
+            LOG_FATAL("Failed to set socket to non-blocking\n");
+            goto done;
+        }
+    }
+
+done:
+    if (ret) {
+        if (ctx->sd != -1) {
+            close(ctx->sd);
+        }
+        free(ctx);
+    } else {
+        *cldap_ctx = ctx;
+    }
+    return ret;
+}
+
+static int ipa_cldap_post_init(Slapi_PBlock *pb)
+{
+    return 0;
+}
+
+/* Initialization function */
+int ipa_cldap_init(Slapi_PBlock *pb)
+{
+    struct ipa_cldap_ctx *cldap_ctx = NULL;
+    int ret;
+
+    ret = ipa_cldap_init_service(pb, &cldap_ctx);
+    if (ret) {
+        LOG_FATAL("Failed to initialize CLDAP Plugin\n");
+        /* do not cause DS to stop, simply do nothing */
+        return 0;
+    }
+
+    /* Register the plug-in */
+    ret = slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_03);
+    if (!ret) {
+        ret = slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, &ipa_cldap_desc);
+    }
+    if (!ret) {
+        ret = slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN, &ipa_cldap_start);
+    }
+    if (!ret) {
+        ret = slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN, &ipa_cldap_stop);
+    }
+    if (!ret) {
+        ret = slapi_pblock_set(pb, SLAPI_PLUGIN_PRIVATE, cldap_ctx);
+    }
+    if (ret) {
+        LOG_FATAL("Failed to initialize plug-in\n" );
+        return -1;
+    }
+
+    slapi_register_plugin("postoperation", 1,
+                          "ipa_cldap_post_init",
+                          ipa_cldap_post_init,
+                          "CLDAP post ops", NULL,
+                          cldap_ctx->plugin_id);
+
+    return 0;
+}
diff --git a/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.h b/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.h
new file mode 100644
index 0000000000000000000000000000000000000000..013dad2fd8143c2e60f1760e76e516ef183b26d2
--- /dev/null
+++ b/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.h
@@ -0,0 +1,72 @@
+/** BEGIN COPYRIGHT BLOCK
+ * 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/>.
+ *
+ * Additional permission under GPLv3 section 7:
+ *
+ * In the following paragraph, "GPL" means the GNU General Public
+ * License, version 3 or any later version, and "Non-GPL Code" means
+ * code that is governed neither by the GPL nor a license
+ * compatible with the GPL.
+ *
+ * You may link the code of this Program with Non-GPL Code and convey
+ * linked combinations including the two, provided that such Non-GPL
+ * Code only links to the code of this Program through those well
+ * defined interfaces identified in the file named EXCEPTION found in
+ * the source code files (the "Approved Interfaces"). The files of
+ * Non-GPL Code may instantiate templates or use macros or inline
+ * functions from the Approved Interfaces without causing the resulting
+ * work to be covered by the GPL. Only the copyright holders of this
+ * Program may make changes or additions to the list of Approved
+ * Interfaces.
+ *
+ * Authors:
+ * Simo Sorce <sso...@redhat.com>
+ *
+ * Copyright (C) 2011 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifndef _IPA_CLDAP_H_
+#define _IPA_CLDAP_H_
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <dirsrv/slapi-plugin.h>
+#include "util.h"
+
+#define IPA_CLDAP_PLUGIN_NAME "CLDAP Server"
+#define IPA_CLDAP_PLUGIN_DESC "MS/AD introperable CLDAP server"
+
+#define IPA_PLUGIN_NAME IPA_CLDAP_PLUGIN_NAME
+#define CLDAP_PORT 389
+
+struct ipa_cldap_ctx {
+    Slapi_ComponentId *plugin_id;
+    pthread_t tid;
+    char *base_dn;
+    int stopfd[2];
+    int sd;
+};
+
+void *ipa_cldap_worker(struct ipa_cldap_ctx *ctx);
+
+#endif /* _IPA_CLDAP_H_ */
diff --git a/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_worker.c b/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_worker.c
new file mode 100644
index 0000000000000000000000000000000000000000..4bbba5359624e92a1c43ef30325fbac165840d06
--- /dev/null
+++ b/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_worker.c
@@ -0,0 +1,49 @@
+/** BEGIN COPYRIGHT BLOCK
+ * 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/>.
+ *
+ * Additional permission under GPLv3 section 7:
+ *
+ * In the following paragraph, "GPL" means the GNU General Public
+ * License, version 3 or any later version, and "Non-GPL Code" means
+ * code that is governed neither by the GPL nor a license
+ * compatible with the GPL.
+ *
+ * You may link the code of this Program with Non-GPL Code and convey
+ * linked combinations including the two, provided that such Non-GPL
+ * Code only links to the code of this Program through those well
+ * defined interfaces identified in the file named EXCEPTION found in
+ * the source code files (the "Approved Interfaces"). The files of
+ * Non-GPL Code may instantiate templates or use macros or inline
+ * functions from the Approved Interfaces without causing the resulting
+ * work to be covered by the GPL. Only the copyright holders of this
+ * Program may make changes or additions to the list of Approved
+ * Interfaces.
+ *
+ * Authors:
+ * Simo Sorce <sso...@redhat.com>
+ *
+ * Copyright (C) 2011 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include "ipa_cldap.h"
+
+void *ipa_cldap_worker(struct ipa_cldap_ctx *ctx)
+{
+    bool stop = false;
+
+    while (!stop) {
+        sleep(1);
+    }
+}
diff --git a/freeipa.spec.in b/freeipa.spec.in
index 6531cf5dde55bcbf8f57125dfdc8b1e53c7d6e3d..2da5d41768f3e04555c0807819aaa9b28c1f2d8f 100644
--- a/freeipa.spec.in
+++ b/freeipa.spec.in
@@ -24,11 +24,7 @@ Source0:        freeipa-%{version}.tar.gz
 BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 
 %if ! %{ONLY_CLIENT}
-%if 0%{?fedora} >= 16
-BuildRequires: 389-ds-base-devel >= 1.2.10
-%else
-BuildRequires:  389-ds-base-devel >= 1.2.9
-%endif
+BuildRequires: 389-ds-base-devel >= 1.2.10-0.5.a5
 BuildRequires:  svrcore-devel
 BuildRequires:  /usr/share/selinux/devel/Makefile
 BuildRequires:  policycoreutils >= %{POLICYCOREUTILSVER}
@@ -93,7 +89,7 @@ Requires: %{name}-python = %{version}-%{release}
 Requires: %{name}-client = %{version}-%{release}
 Requires: %{name}-admintools = %{version}-%{release}
 Requires: %{name}-server-selinux = %{version}-%{release}
-Requires(pre): 389-ds-base >= 1.2.10-0.4.a4
+Requires(pre): 389-ds-base >= 1.2.10-0.5.a5
 Requires: openldap-clients
 Requires: nss
 Requires: nss-tools
@@ -330,6 +326,7 @@ rm %{buildroot}/%{plugin_dir}/libipa_repl_version.la
 rm %{buildroot}/%{plugin_dir}/libipa_uuid.la
 rm %{buildroot}/%{plugin_dir}/libipa_modrdn.la
 rm %{buildroot}/%{plugin_dir}/libipa_lockout.la
+rm %{buildroot}/%{plugin_dir}/libipa_cldap.la
 rm %{buildroot}/%{_libdir}/krb5/plugins/kdb/ipadb.la
 
 # Some user-modifiable HTML files are provided. Move these to /etc
@@ -541,6 +538,7 @@ fi
 %attr(755,root,root) %{plugin_dir}/libipa_uuid.so
 %attr(755,root,root) %{plugin_dir}/libipa_modrdn.so
 %attr(755,root,root) %{plugin_dir}/libipa_lockout.so
+%attr(755,root,root) %{plugin_dir}/libipa_cldap.so
 %dir %{_localstatedir}/lib/ipa
 %attr(700,root,root) %dir %{_localstatedir}/lib/ipa/sysrestore
 %dir %{_localstatedir}/cache/ipa
@@ -618,6 +616,11 @@ fi
 %ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/ipa/default.conf
 
 %changelog
+* Wed Nov 17 2011 Simo Sorce <s...@redhat.com> - 2.99.0-12
+- Add CLDAP plugin
+- Set min nvr of 389-ds-base to 1.2.10-0.5.a5 for SLAPI_PLUGIN_CONFIG_ENTRY
+  support
+
 * Wed Nov 14 2011 Endi S. Dewata <edew...@redhat.com> - 2.99.0-11
 - Make sure changes to extension.js are not removed.
 
-- 
1.7.7.1

>From 2f0987170788d98b5b4e13be1b1cfbee6ae3c61f Mon Sep 17 00:00:00 2001
From: Simo Sorce <sso...@redhat.com>
Date: Mon, 14 Nov 2011 17:38:53 -0500
Subject: [PATCH 3/6] ipa-cldap: Implement worker thread.

---
 daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.h    |   11 +++
 .../ipa-slapi-plugins/ipa-cldap/ipa_cldap_worker.c |   71 +++++++++++++++++++-
 2 files changed, 81 insertions(+), 1 deletions(-)

diff --git a/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.h b/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.h
index 013dad2fd8143c2e60f1760e76e516ef183b26d2..ff9818a64b186f7d20cb289b8ee829698459fb4d 100644
--- a/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.h
+++ b/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.h
@@ -58,6 +58,7 @@
 
 #define IPA_PLUGIN_NAME IPA_CLDAP_PLUGIN_NAME
 #define CLDAP_PORT 389
+#define MAX_DG_SIZE 4096
 
 struct ipa_cldap_ctx {
     Slapi_ComponentId *plugin_id;
@@ -67,6 +68,16 @@ struct ipa_cldap_ctx {
     int sd;
 };
 
+struct ipa_cldap_req {
+    int fd;
+
+    struct sockaddr_storage ss;
+    socklen_t ss_len;
+
+    char dgram[MAX_DG_SIZE];
+    size_t dgsize;
+};
+
 void *ipa_cldap_worker(struct ipa_cldap_ctx *ctx);
 
 #endif /* _IPA_CLDAP_H_ */
diff --git a/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_worker.c b/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_worker.c
index 4bbba5359624e92a1c43ef30325fbac165840d06..474c5327c7b9229f9a24a81c68268f0e41ec79e8 100644
--- a/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_worker.c
+++ b/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_worker.c
@@ -38,12 +38,81 @@
  * END COPYRIGHT BLOCK **/
 
 #include "ipa_cldap.h"
+#include <poll.h>
+
+static void ipa_cldap_process(struct ipa_cldap_ctx *ctx,
+                              struct ipa_cldap_req *req)
+{
+    free(req);
+    return;
+}
+
+static struct ipa_cldap_req *ipa_cldap_recv_dgram(struct ipa_cldap_ctx *ctx)
+{
+    struct ipa_cldap_req *req;
+
+    req = calloc(1, sizeof(struct ipa_cldap_req));
+    if (!req) {
+        LOG("Failed to allocate memory for req");
+        return NULL;
+    }
+
+    req->fd = ctx->sd;
+    req->ss_len = sizeof(struct sockaddr_storage);
+
+    req->dgsize = recvfrom(req->fd, req->dgram, MAX_DG_SIZE, 0,
+                           (struct sockaddr *)&req->ss, &req->ss_len);
+    if (req->dgsize == -1) {
+        LOG_TRACE("Failed to get datagram\n");
+        free(req);
+        return NULL;
+    }
+
+    return req;
+}
 
 void *ipa_cldap_worker(struct ipa_cldap_ctx *ctx)
 {
+    struct ipa_cldap_req *req;
+    struct pollfd fds[2];
     bool stop = false;
+    int ret;
 
     while (!stop) {
-        sleep(1);
+
+        fds[0].fd = ctx->stopfd[0];
+        fds[0].events = POLLIN;
+        fds[0].revents = 0;
+        fds[1].fd = ctx->sd;
+        fds[1].events = POLLIN;
+        fds[1].revents = 0;
+
+        /* wait until a request comes in */
+        ret = poll(fds, 2, -1);
+        if (ret == -1) {
+            if (errno != EINTR) {
+                LOG_FATAL("poll() failed with [%d, %s]. Can't continue.\n",
+                          errno, strerror(errno));
+                stop = true;
+            }
+        }
+        if (ret <= 0) {
+            continue;
+        }
+
+        /* got a stop signal, exit the loop */
+        if (fds[0].revents & POLLIN) {
+            stop = true;
+            continue;
+        }
+
+        /* got a CLDAP packet, handle it */
+        if (fds[1].revents & POLLIN) {
+            req = ipa_cldap_recv_dgram(ctx);
+            if (req) {
+                ipa_cldap_process(ctx, req);
+            }
+        }
     }
+    return NULL;
 }
-- 
1.7.7.1

>From c6f89d6544ffcc9fdddbbadb74a2ddfa00ce3030 Mon Sep 17 00:00:00 2001
From: Simo Sorce <sso...@redhat.com>
Date: Mon, 14 Nov 2011 23:09:50 -0500
Subject: [PATCH 4/6] ipa-cldap: Decode CLDAP request.

---
 daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.h    |   16 ++
 .../ipa-slapi-plugins/ipa-cldap/ipa_cldap_worker.c |  175 ++++++++++++++++++++
 2 files changed, 191 insertions(+), 0 deletions(-)

diff --git a/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.h b/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.h
index ff9818a64b186f7d20cb289b8ee829698459fb4d..8484749f51e8bbf3e6857901b2a525adf86c1623 100644
--- a/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.h
+++ b/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.h
@@ -68,6 +68,17 @@ struct ipa_cldap_ctx {
     int sd;
 };
 
+struct kvp {
+    struct berval attr;
+    struct berval value;
+};
+
+struct kvp_list {
+    struct kvp *pairs;
+    int allocated;
+    int top;
+};
+
 struct ipa_cldap_req {
     int fd;
 
@@ -76,6 +87,11 @@ struct ipa_cldap_req {
 
     char dgram[MAX_DG_SIZE];
     size_t dgsize;
+
+    ber_int_t id;
+
+    /* filter members */
+    struct kvp_list kvps;
 };
 
 void *ipa_cldap_worker(struct ipa_cldap_ctx *ctx);
diff --git a/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_worker.c b/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_worker.c
index 474c5327c7b9229f9a24a81c68268f0e41ec79e8..57c3ffce796ea3df36c17c418e4f1231ac649070 100644
--- a/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_worker.c
+++ b/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_worker.c
@@ -39,10 +39,185 @@
 
 #include "ipa_cldap.h"
 #include <poll.h>
+#include <lber.h>
+
+/* pre allocate some space for answers, default to increment 3 at a time */
+static int ipa_cldap_more_kvps(struct kvp_list *kvps)
+{
+    struct kvp *pairs;
+
+    if (kvps->allocated - kvps->top > 0) {
+        return 0;
+    }
+
+    pairs = realloc(kvps->pairs, (kvps->allocated + 3) * sizeof(struct kvp));
+    if (!pairs) {
+        return ENOMEM;
+    }
+    kvps->pairs = pairs;
+    kvps->allocated += 3;
+
+    return 0;
+}
+
+static void ipa_cldap_free_kvps(struct kvp_list *kvps)
+{
+    free(kvps->pairs);
+    kvps->pairs = NULL;
+    kvps->allocated = 0;
+    kvps->top = 0;
+}
+
+static int ipa_cldap_get_kvp(BerElement *be, struct kvp_list *kvps)
+{
+    ber_tag_t tag;
+    int ret;
+
+    ret = ipa_cldap_more_kvps(kvps);
+    if (ret) {
+        return ret;
+    }
+
+    tag = ber_scanf(be, "{mm}",
+                    &(kvps->pairs[kvps->top].attr),
+                    &(kvps->pairs[kvps->top].value));
+    if (tag == LBER_ERROR) {
+        LOG_TRACE("Invalid filter\n");
+        ret = EINVAL;
+    } else {
+        kvps->top++;
+    }
+
+    return ret;
+}
+
+static int ipa_cldap_get_tree(BerElement *be, struct kvp_list *kvps)
+{
+    ber_tag_t tag;
+    ber_tag_t len;
+    char *cookie;
+    int ret;
+
+    tag = ber_first_element(be, &len, &cookie);
+    while (tag != LBER_DEFAULT) {
+        tag = ber_peek_tag(be, &len);
+        switch (tag) {
+        case LDAP_FILTER_EQUALITY:
+            ret = ipa_cldap_get_kvp(be, kvps);
+            break;
+        case LDAP_FILTER_AND:
+            ret = ipa_cldap_get_tree(be, kvps);
+            break;
+        default:
+            LOG_TRACE("Unsupported filter\n");
+            ret = EINVAL;
+            break;
+        }
+
+        if (ret) {
+            return ret;
+        }
+
+        tag = ber_next_element(be, &len, cookie);
+    }
+
+    return 0;
+}
+
+static int ipa_cldap_decode(struct ipa_cldap_req *req)
+{
+    struct berval bv;
+    BerElement *be;
+    ber_tag_t tag;
+    ber_len_t len;
+    ber_int_t scope;
+    ber_int_t deref;
+    ber_int_t sizelimit;
+    ber_int_t timelimit;
+    ber_int_t typesonly;
+    struct berval base;
+    struct berval attr;
+    int ret = EINVAL;
+
+    bv.bv_val = req->dgram;
+    bv.bv_len = req->dgsize;
+
+    be = ber_alloc_t(0);
+    if (!be) {
+        LOG_FATAL("Out of memory!\n");
+        goto done;
+    }
+
+    ber_init2(be, &bv, 0);
+
+    tag = ber_skip_tag(be, &len);
+    if (tag != LDAP_TAG_MESSAGE) {
+        LOG_TRACE("Invalid message (%d)\n", (int)tag);
+        goto done;
+    }
+
+    tag = ber_get_int(be, &req->id);
+    if (tag != LDAP_TAG_MSGID) {
+        LOG_TRACE("Failed to get id\n");
+        goto done;
+    }
+
+    tag = ber_peek_tag(be, &len);
+    if (tag != LDAP_REQ_SEARCH) {
+        LOG_TRACE("Unexpected message type (%d)\n", (int)tag);
+        goto done;
+    }
+
+    tag = ber_scanf(be, "{meeiib",
+                    &base, &scope, &deref, &sizelimit, &timelimit, &typesonly);
+    if (tag == LBER_ERROR) {
+        LOG_TRACE("Failed to parse message\n");
+        goto done;
+    }
+
+    if ((base.bv_len != 0) ||
+        (scope != 0) ||
+        (typesonly != 0)){
+        LOG_TRACE("Unexpected request\n");
+        goto done;
+    }
+
+    ret = ipa_cldap_get_tree(be, &req->kvps);
+    if (ret) {
+        LOG_TRACE("Failed to parse filter\n");
+        goto done;
+    }
+
+    tag = ber_scanf(be, "{m}}", &attr);
+    if (tag == LBER_ERROR) {
+        LOG_TRACE("Failed to parse message\n");
+        goto done;
+    }
+
+    if (strncasecmp(attr.bv_val, "netlogon", attr.bv_len) != 0) {
+        LOG_TRACE("Unexpected request\n");
+        goto done;
+    }
+
+done:
+    ber_free(be, 0);
+    return ret;
+}
 
 static void ipa_cldap_process(struct ipa_cldap_ctx *ctx,
                               struct ipa_cldap_req *req)
 {
+    int ret;
+
+    ret = ipa_cldap_decode(req);
+    if (ret) {
+        goto done;
+    }
+
+    LOG_TRACE("CLDAP Request received");
+
+done:
+    ipa_cldap_free_kvps(&req->kvps);
     free(req);
     return;
 }
-- 
1.7.7.1

>From 9ed34ba1449297c60c90b06ad9ba851b75bedba4 Mon Sep 17 00:00:00 2001
From: Simo Sorce <sso...@redhat.com>
Date: Tue, 15 Nov 2011 18:33:26 -0500
Subject: [PATCH 5/6] ipa-cldap: Create netlogon blob

---
 daemons/ipa-slapi-plugins/ipa-cldap/Makefile.am    |    1 +
 daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.h    |    8 +
 .../ipa-cldap/ipa_cldap_netlogon.c                 |  329 ++++++++++++++++++++
 .../ipa-slapi-plugins/ipa-cldap/ipa_cldap_worker.c |    6 +
 4 files changed, 344 insertions(+), 0 deletions(-)
 create mode 100644 daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_netlogon.c

diff --git a/daemons/ipa-slapi-plugins/ipa-cldap/Makefile.am b/daemons/ipa-slapi-plugins/ipa-cldap/Makefile.am
index b563e98763d78298b64de92c59716bacd8c822a4..27f53e9aa129ff2ef31c909f2b55069fae7b64da 100644
--- a/daemons/ipa-slapi-plugins/ipa-cldap/Makefile.am
+++ b/daemons/ipa-slapi-plugins/ipa-cldap/Makefile.am
@@ -24,6 +24,7 @@ plugin_LTLIBRARIES = 			\
 	$(NULL)
 
 libipa_cldap_la_SOURCES = 		\
+	ipa_cldap_netlogon.c		\
 	ipa_cldap_worker.c		\
 	ipa_cldap.c			\
 	$(NULL)
diff --git a/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.h b/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.h
index 8484749f51e8bbf3e6857901b2a525adf86c1623..ae0b06fe677276a932c832e82b1578896ddafd51 100644
--- a/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.h
+++ b/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.h
@@ -60,6 +60,10 @@
 #define CLDAP_PORT 389
 #define MAX_DG_SIZE 4096
 
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 64
+#endif
+
 struct ipa_cldap_ctx {
     Slapi_ComponentId *plugin_id;
     pthread_t tid;
@@ -96,4 +100,8 @@ struct ipa_cldap_req {
 
 void *ipa_cldap_worker(struct ipa_cldap_ctx *ctx);
 
+int ipa_cldap_netlogon(struct ipa_cldap_ctx *ctx,
+                       struct ipa_cldap_req *req,
+                       struct berval *reply);
+
 #endif /* _IPA_CLDAP_H_ */
diff --git a/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_netlogon.c b/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_netlogon.c
new file mode 100644
index 0000000000000000000000000000000000000000..6eb7eb9b1b88bb190a75feeab39a2fe5ff2719bf
--- /dev/null
+++ b/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_netlogon.c
@@ -0,0 +1,329 @@
+/** BEGIN COPYRIGHT BLOCK
+ * 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/>.
+ *
+ * Additional permission under GPLv3 section 7:
+ *
+ * In the following paragraph, "GPL" means the GNU General Public
+ * License, version 3 or any later version, and "Non-GPL Code" means
+ * code that is governed neither by the GPL nor a license
+ * compatible with the GPL.
+ *
+ * You may link the code of this Program with Non-GPL Code and convey
+ * linked combinations including the two, provided that such Non-GPL
+ * Code only links to the code of this Program through those well
+ * defined interfaces identified in the file named EXCEPTION found in
+ * the source code files (the "Approved Interfaces"). The files of
+ * Non-GPL Code may instantiate templates or use macros or inline
+ * functions from the Approved Interfaces without causing the resulting
+ * work to be covered by the GPL. Only the copyright holders of this
+ * Program may make changes or additions to the list of Approved
+ * Interfaces.
+ *
+ * Authors:
+ * Simo Sorce <sso...@redhat.com>
+ *
+ * Copyright (C) 2011 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include "ipa_cldap.h"
+#include <endian.h>
+#include <talloc.h>
+#include <ctype.h>
+#include "gen_ndr/ndr_nbt.h"
+#include "gen_ndr/netlogon.h"
+
+static int string_to_guid(char *str, struct GUID *guid)
+{
+    unsigned int time_low;
+    unsigned int time_mid;
+    unsigned int time_hi;
+    unsigned int seq[2];
+    unsigned int node[6];
+    int ret;
+
+    ret = sscanf(str, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+                 &time_low, &time_mid, &time_hi, &seq[0], &seq[1],
+                 &node[0], &node[1], &node[2], &node[3], &node[4], &node[5]);
+    if (ret != 11) {
+        return EINVAL;
+    }
+
+    guid->time_low = time_low;
+    guid->time_mid = time_mid;
+    guid->time_hi_and_version = time_hi;
+    guid->clock_seq[0] = seq[0];
+    guid->clock_seq[1] = seq[1];
+    guid->node[0] = node[0];
+    guid->node[1] = node[1];
+    guid->node[2] = node[2];
+    guid->node[3] = node[3];
+    guid->node[4] = node[4];
+    guid->node[5] = node[5];
+
+    return 0;
+}
+
+static int ipa_cldap_get_domain_entry(struct ipa_cldap_ctx *ctx,
+                                      char *domain,
+                                      char **guid, char **sid, char **name)
+{
+    Slapi_PBlock *pb;
+    Slapi_Entry **e = NULL;
+    char *filter;
+    int ret;
+
+    pb = slapi_pblock_new();
+    if (!pb) {
+        return ENOMEM;
+    }
+
+    ret = asprintf(&filter, "(&(cn=%s)(objectclass=ipaNTDomainAttrs))", domain);
+    if (ret == -1) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    slapi_search_internal_set_pb(pb, ctx->base_dn,
+                                 LDAP_SCOPE_SUBTREE, filter,
+                                 NULL, 0, NULL, NULL, ctx->plugin_id, 0);
+
+    slapi_search_internal_pb(pb);
+    slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &ret);
+
+    if (ret) {
+        ret = ENOENT;
+        goto done;
+    }
+
+    slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &e);
+    if (!e || !e[0] || e[1]) {
+        /* no matches or too many matches */
+        ret = ENOENT;
+        goto done;
+    }
+
+    *guid = slapi_entry_attr_get_charptr(e[0], "ipaNTDomainGUID");
+    *sid = slapi_entry_attr_get_charptr(e[0], "ipaNTSecurityIdentifier");
+    *name = slapi_entry_attr_get_charptr(e[0], "ipaNTFlatName");
+
+    ret = 0;
+
+done:
+    slapi_free_search_results_internal(pb);
+    slapi_pblock_destroy(pb);
+    free(filter);
+    return ret;
+}
+
+#define NETLOGON_SAM_LOGON_RESPONSE_EX_pusher \
+            (ndr_push_flags_fn_t)ndr_push_NETLOGON_SAM_LOGON_RESPONSE_EX
+
+static int ipa_cldap_encode_netlogon(char *hostname, char *domain,
+                                     char *guid, char *sid, char *name,
+                                     uint32_t ntver, struct berval *reply)
+{
+    struct NETLOGON_SAM_LOGON_RESPONSE_EX *nlr;
+    enum ndr_err_code ndr_err;
+    DATA_BLOB blob;
+    char *pdc_name;
+    char *p;
+    int ret;
+
+    nlr = talloc_zero(NULL, struct NETLOGON_SAM_LOGON_RESPONSE_EX);
+    if (!nlr) {
+        return ENOMEM;
+    }
+
+    if (!(ntver & NETLOGON_NT_VERSION_5EX)) {
+        ret = EINVAL;
+        goto done;
+    }
+
+    nlr->command = LOGON_SAM_LOGON_RESPONSE_EX;
+    /* nlr->sbz */
+    nlr->server_type = DS_SERVER_PDC |
+                        DS_SERVER_GC |
+                        DS_SERVER_LDAP |
+                        DS_SERVER_DS |
+                        DS_SERVER_KDC |
+                        DS_SERVER_TIMESERV |
+                        DS_SERVER_CLOSEST |
+                        DS_SERVER_WRITABLE |
+                        DS_SERVER_GOOD_TIMESERV;
+    string_to_guid(guid, &nlr->domain_uuid);
+    nlr->forest = domain;
+    nlr->dns_domain = domain;
+    nlr->pdc_dns_name = talloc_asprintf(nlr, "%s.%s", hostname, domain);
+    if (!nlr->pdc_dns_name) {
+        ret = ENOMEM;
+        goto done;
+    }
+    nlr->domain_name = name;
+    pdc_name = talloc_asprintf(nlr, "\\\\%s", hostname);
+    for (p = pdc_name; *p; p++) {
+        *p = toupper(*p);
+    }
+    nlr->pdc_name = pdc_name;
+    nlr->user_name = "";
+    nlr->server_site = "Default-First-Site-Name";
+    nlr->client_site = "Default-First-Site-Name";
+    /* nlr->sockaddr_size (filled in by ndr_push) */
+    nlr->sockaddr.sockaddr_family = 2;
+    nlr->sockaddr.pdc_ip = "127.0.0.1";
+    nlr->sockaddr.remaining.length = 8;
+    nlr->sockaddr.remaining.data = talloc_zero_size(nlr, 8);
+    /* nlr->next_closest_site */
+    nlr->nt_version = NETLOGON_NT_VERSION_5EX|NETLOGON_NT_VERSION_1;
+    nlr->lmnt_token = 0xFFFF;
+    nlr->lm20_token = 0xFFFF;
+
+    ndr_err = ndr_push_struct_blob(&blob, nlr, nlr,
+                                   NETLOGON_SAM_LOGON_RESPONSE_EX_pusher);
+    if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+        ret = EFAULT;
+        goto done;
+    }
+
+    reply->bv_val = malloc(blob.length);
+    if (!reply->bv_val) {
+        ret = ENOMEM;
+        goto done;
+    }
+    memcpy(reply->bv_val, blob.data, blob.length);
+    reply->bv_len = blob.length;
+    ret = 0;
+
+done:
+    talloc_free(nlr);
+    return ret;
+}
+
+int ipa_cldap_netlogon(struct ipa_cldap_ctx *ctx,
+                       struct ipa_cldap_req *req,
+                       struct berval *reply)
+{
+    char hostname[MAXHOSTNAMELEN + 1]; /* NOTE: lenght hardcoded in kernel */
+    char *domain = NULL;
+    char *guid = NULL;
+    char *sid = NULL;
+    char *name = NULL;
+    uint32_t ntver = 0;
+    uint32_t t;
+    char *p;
+    int ret;
+    int len;
+    int i;
+
+    /* determine request type */
+
+    for (i = 0; i < req->kvps.top; i++) {
+        if (strncasecmp("DnsDomain",
+                        req->kvps.pairs[i].attr.bv_val,
+                        req->kvps.pairs[i].attr.bv_len) == 0) {
+            /* remove trailing dot if any */
+            len = req->kvps.pairs[i].value.bv_len;
+            if (req->kvps.pairs[i].value.bv_val[len-1] == '.') {
+                len--;
+            }
+            domain = strndup(req->kvps.pairs[i].value.bv_val, len);
+            if (!domain) {
+                ret = ENOMEM;
+                goto done;
+            }
+            continue;
+        }
+        if (strncasecmp("Host",
+                        req->kvps.pairs[i].attr.bv_val,
+                        req->kvps.pairs[i].attr.bv_len) == 0) {
+            /* we ignore Host for now */
+            continue;
+        }
+        if (strncasecmp("DomainGUID",
+                        req->kvps.pairs[i].attr.bv_val,
+                        req->kvps.pairs[i].attr.bv_len) == 0) {
+            /* we ignore DomainGUID for now */
+            continue;
+        }
+        if (strncasecmp("DomainSID",
+                        req->kvps.pairs[i].attr.bv_val,
+                        req->kvps.pairs[i].attr.bv_len) == 0) {
+            /* we ignore DomainSID for now */
+            continue;
+        }
+        if (strncasecmp("User",
+                        req->kvps.pairs[i].attr.bv_val,
+                        req->kvps.pairs[i].attr.bv_len) == 0) {
+            /* we ignore User for now */
+            continue;
+        }
+        if (strncasecmp("AAC",
+                        req->kvps.pairs[i].attr.bv_val,
+                        req->kvps.pairs[i].attr.bv_len) == 0) {
+            /* we ignore AAC for now */
+            continue;
+        }
+        if (strncasecmp("NTver",
+                        req->kvps.pairs[i].attr.bv_val,
+                        req->kvps.pairs[i].attr.bv_len) == 0) {
+            if (req->kvps.pairs[i].value.bv_len != 4) {
+                ret = EINVAL;
+                goto done;
+            }
+            memcpy(&t, req->kvps.pairs[i].value.bv_val, 4);
+            ntver = le32toh(t);
+            continue;
+        }
+        LOG_TRACE("Unknown filter attribute: %s\n",
+                  req->kvps.pairs[i].attr.bv_val);
+    }
+
+    if (!domain || !ntver) {
+        ret = EINVAL;
+        goto done;
+    }
+
+    /* FIXME: we support only NETLOGON_NT_VERSION_5EX for now */
+    if (!(ntver & NETLOGON_NT_VERSION_5EX)) {
+        ret = EINVAL;
+        goto done;
+    }
+
+    ret = ipa_cldap_get_domain_entry(ctx, domain, &guid, &sid, &name);
+    if (ret) {
+        goto done;
+    }
+
+    ret = gethostname(hostname, MAXHOSTNAMELEN);
+    if (ret == -1) {
+        ret = errno;
+        goto done;
+    }
+    hostname[MAXHOSTNAMELEN] = '\0';
+    p = strchr(hostname, '.');
+    if (p) {
+        *p = '\0';
+    }
+
+    ret = ipa_cldap_encode_netlogon(hostname, domain,
+                                    guid, sid, name,
+                                    ntver, reply);
+
+done:
+    free(domain);
+    free(guid);
+    free(sid);
+    free(name);
+    return ret;
+}
diff --git a/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_worker.c b/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_worker.c
index 57c3ffce796ea3df36c17c418e4f1231ac649070..90ea32e0326d04c59f8eba56be707bbcecab2956 100644
--- a/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_worker.c
+++ b/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_worker.c
@@ -207,6 +207,7 @@ done:
 static void ipa_cldap_process(struct ipa_cldap_ctx *ctx,
                               struct ipa_cldap_req *req)
 {
+    struct berval reply;
     int ret;
 
     ret = ipa_cldap_decode(req);
@@ -216,6 +217,11 @@ static void ipa_cldap_process(struct ipa_cldap_ctx *ctx,
 
     LOG_TRACE("CLDAP Request received");
 
+    ret = ipa_cldap_netlogon(ctx, req, &reply);
+    if (ret) {
+        goto done;
+    }
+
 done:
     ipa_cldap_free_kvps(&req->kvps);
     free(req);
-- 
1.7.7.1

>From a87664798dc91a4685679a8f58f777bebfb896b5 Mon Sep 17 00:00:00 2001
From: Simo Sorce <sso...@redhat.com>
Date: Thu, 17 Nov 2011 11:51:05 -0500
Subject: [PATCH 6/6] ipa-cldap: send cldap reply

---
 .../ipa-slapi-plugins/ipa-cldap/ipa_cldap_worker.c |   48 ++++++++++++++++++++
 1 files changed, 48 insertions(+), 0 deletions(-)

diff --git a/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_worker.c b/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_worker.c
index 90ea32e0326d04c59f8eba56be707bbcecab2956..307110c123c2d898c910371da9ebeb2edfa0f1b5 100644
--- a/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_worker.c
+++ b/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_worker.c
@@ -204,6 +204,52 @@ done:
     return ret;
 }
 
+static void ipa_cldap_respond(struct ipa_cldap_ctx *ctx,
+                              struct ipa_cldap_req *req,
+                              struct berval *nbtblob)
+{
+    struct berval *bv = NULL;
+    BerElement *be;
+    int ret;
+
+    be = ber_alloc_t(0);
+    if (!be) {
+        LOG_OOM();
+        return;
+    }
+
+    /* result */
+    ret = ber_printf(be, "{it{s{{s[O]}}}}", req->id,
+                         LDAP_RES_SEARCH_ENTRY, "", "netlogon", nbtblob);
+    if (ret == LBER_ERROR) {
+        LOG("Failed to encode CLDAP reply\n");
+        goto done;
+    }
+    /* done */
+    ret = ber_printf(be, "{it{ess}}", req->id,
+                         LDAP_RES_SEARCH_RESULT, 0, "", "");
+    if (ret == LBER_ERROR) {
+        LOG("Failed to encode CLDAP reply\n");
+        goto done;
+    }
+    /* get data blob */
+    ret = ber_flatten(be, &bv);
+    if (ret == LBER_ERROR) {
+        LOG("Failed to encode CLDAP reply\n");
+        goto done;
+    }
+
+    ret = sendto(ctx->sd, bv->bv_val, bv->bv_len, 0,
+                 (struct sockaddr *)&req->ss, req->ss_len);
+    if (ret == -1) {
+        LOG("Failed to send CLDAP reply (%d, %s)\n", errno, strerror(errno));
+    }
+
+done:
+    ber_bvfree(bv);
+    ber_free(be, 1);
+}
+
 static void ipa_cldap_process(struct ipa_cldap_ctx *ctx,
                               struct ipa_cldap_req *req)
 {
@@ -222,6 +268,8 @@ static void ipa_cldap_process(struct ipa_cldap_ctx *ctx,
         goto done;
     }
 
+    ipa_cldap_respond(ctx, req, &reply);
+
 done:
     ipa_cldap_free_kvps(&req->kvps);
     free(req);
-- 
1.7.7.1

_______________________________________________
Freeipa-devel mailing list
Freeipa-devel@redhat.com
https://www.redhat.com/mailman/listinfo/freeipa-devel

Reply via email to