[Freeipa-devel] [PATCH] Add sidgen postop and task

Sumit Bose sbose at redhat.com
Mon Jun 25 09:53:10 UTC 2012


Hi,

this patch added support to automatically create SIDs for local objects
as described in ticket https://fedorahosted.org/freeipa/ticket/2825.

The post-operation plugin adds the SID and if necessary the needed
objectclass for a newly created object.

The directory server task can you used to set SID to existing objects in
one run. Since there were concerns about the amount of replication
traffic this task accepts a parameter 'delay' to let the task pause for
the given number of micro-seconds after an object was changed. I also do
not start the task during ipa-adtrust-install to allow to run the task
at a more appropriate time. I wonder if it is ok to just have an ldif
file as example and explain in the docs how to start the task with
ldapmodify or if a tighter integration is needed. Typically this task
should be called only once after ipa-adtrust-install.

bye,
Sumit
-------------- next part --------------
From 82e6725c5e00839b85da29b6232f176aa4266191 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Thu, 21 Jun 2012 12:54:34 +0200
Subject: [PATCH] Add sidgen postop and task

A postop plugin is added to create the SID for new created users and
groups. A directory server task allows to set the SID for existing
users and groups.

Fixes https://fedorahosted.org/freeipa/ticket/2825
---
 daemons/configure.ac                               |    1 +
 daemons/ipa-slapi-plugins/Makefile.am              |    1 +
 daemons/ipa-slapi-plugins/ipa-sidgen/Makefile.am   |   60 +++
 .../ipa-sidgen/ipa-sidgen-conf.ldif                |   16 +
 .../ipa-sidgen/ipa-sidgen-task-conf.ldif           |   20 +
 .../ipa-sidgen/ipa-sidgen-task-example.ldif        |   10 +
 daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.c  |  244 +++++++++
 daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.h  |  110 ++++
 .../ipa-sidgen/ipa_sidgen_common.c                 |  568 ++++++++++++++++++++
 .../ipa-slapi-plugins/ipa-sidgen/ipa_sidgen_task.c |  348 ++++++++++++
 freeipa.spec.in                                    |    4 +
 ipaserver/install/adtrustinstance.py               |    8 +
 12 Dateien ge?ndert, 1390 Zeilen hinzugef?gt(+)
 create mode 100644 daemons/ipa-slapi-plugins/ipa-sidgen/Makefile.am
 create mode 100644 daemons/ipa-slapi-plugins/ipa-sidgen/ipa-sidgen-conf.ldif
 create mode 100644 daemons/ipa-slapi-plugins/ipa-sidgen/ipa-sidgen-task-conf.ldif
 create mode 100644 daemons/ipa-slapi-plugins/ipa-sidgen/ipa-sidgen-task-example.ldif
 create mode 100644 daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.c
 create mode 100644 daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.h
 create mode 100644 daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen_common.c
 create mode 100644 daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen_task.c

diff --git a/daemons/configure.ac b/daemons/configure.ac
index deaa47358445fa552f5a9b53c9b65a9550b71d9e..5dbdca20a6574945ca333d0ce58aaceb34639bc8 100644
--- a/daemons/configure.ac
+++ b/daemons/configure.ac
@@ -314,6 +314,7 @@ AC_CONFIG_FILES([
     ipa-slapi-plugins/ipa-version/Makefile
     ipa-slapi-plugins/ipa-uuid/Makefile
     ipa-slapi-plugins/ipa-modrdn/Makefile
+    ipa-slapi-plugins/ipa-sidgen/Makefile
 ])
 
 AC_OUTPUT
diff --git a/daemons/ipa-slapi-plugins/Makefile.am b/daemons/ipa-slapi-plugins/Makefile.am
index 29b985e69424c9f2ce453ea3607cdb0e936bcce2..58df1a0981ff4f0f12aec84b4706ae3879bdec07 100644
--- a/daemons/ipa-slapi-plugins/Makefile.am
+++ b/daemons/ipa-slapi-plugins/Makefile.am
@@ -9,6 +9,7 @@ SUBDIRS =			\
 	ipa-uuid		\
 	ipa-version		\
 	ipa-winsync		\
+	ipa-sidgen		\
 	$(NULL)
 
 EXTRA_DIST =			\
diff --git a/daemons/ipa-slapi-plugins/ipa-sidgen/Makefile.am b/daemons/ipa-slapi-plugins/ipa-sidgen/Makefile.am
new file mode 100644
index 0000000000000000000000000000000000000000..0d8b74e86369ae9c972e090ff0e6feddc840cfde
--- /dev/null
+++ b/daemons/ipa-slapi-plugins/ipa-sidgen/Makefile.am
@@ -0,0 +1,60 @@
+NULL =
+
+PLUGIN_COMMON_DIR=../common
+
+INCLUDES =							\
+	-I.							\
+	-I$(srcdir)						\
+	-I$(PLUGIN_COMMON_DIR)					\
+	-I/usr/include/dirsrv					\
+	-DPREFIX=\""$(prefix)"\" 				\
+	-DBINDIR=\""$(bindir)"\"				\
+	-DLIBDIR=\""$(libdir)"\" 				\
+	-DLIBEXECDIR=\""$(libexecdir)"\"			\
+	-DDATADIR=\""$(datadir)"\"				\
+	$(AM_CFLAGS)						\
+	$(LDAP_CFLAGS)					\
+	$(WARN_CFLAGS)						\
+	$(NULL)
+
+plugindir = $(libdir)/dirsrv/plugins
+plugin_LTLIBRARIES = 		\
+	libipa_sidgen.la	\
+	libipa_sidgen_task.la	\
+	$(NULL)
+
+libipa_sidgen_la_SOURCES = 	\
+	ipa_sidgen.c		\
+	ipa_sidgen_common.c	\
+	$(NULL)
+
+libipa_sidgen_la_LDFLAGS = -avoid-version
+
+libipa_sidgen_la_LIBADD = 	\
+	$(LDAP_LIBS)		\
+	$(NULL)
+
+libipa_sidgen_task_la_SOURCES = 	\
+	ipa_sidgen_task.c		\
+	ipa_sidgen_common.c		\
+	$(NULL)
+
+libipa_sidgen_task_la_LDFLAGS = -avoid-version
+
+libipa_sidgen_task_la_LIBADD = 	\
+	$(LDAP_LIBS)		\
+	$(NULL)
+
+appdir = $(IPA_DATA_DIR)
+app_DATA =				\
+	ipa-sidgen-conf.ldif		\
+	ipa-sidgen-task-conf.ldif	\
+	$(NULL)
+
+EXTRA_DIST =			\
+	$(app_DATA)		\
+	$(NULL)
+
+MAINTAINERCLEANFILES =		\
+	*~			\
+	Makefile.in
diff --git a/daemons/ipa-slapi-plugins/ipa-sidgen/ipa-sidgen-conf.ldif b/daemons/ipa-slapi-plugins/ipa-sidgen/ipa-sidgen-conf.ldif
new file mode 100644
index 0000000000000000000000000000000000000000..6a8ed5f9ef73a01f5c29015b16283e90a61fc7d1
--- /dev/null
+++ b/daemons/ipa-slapi-plugins/ipa-sidgen/ipa-sidgen-conf.ldif
@@ -0,0 +1,16 @@
+dn: cn=IPA SIDGEN,cn=plugins,cn=config
+changetype: add
+objectclass: top
+objectclass: nsSlapdPlugin
+objectclass: extensibleObject
+cn: IPA SIDGEN
+nsslapd-pluginpath: libipa_sidgen
+nsslapd-plugininitfunc: ipa_sidgen_init
+nsslapd-plugintype: postoperation
+nsslapd-pluginenabled: on
+nsslapd-pluginid: ipa_sidgen_postop
+nsslapd-pluginversion: 1.0
+nsslapd-pluginvendor: Red Hat, Inc.
+nsslapd-plugindescription: IPA SIDGEN post operation
+nsslapd-plugin-depends-on-type: database
+nsslapd-basedn: $SUFFIX
diff --git a/daemons/ipa-slapi-plugins/ipa-sidgen/ipa-sidgen-task-conf.ldif b/daemons/ipa-slapi-plugins/ipa-sidgen/ipa-sidgen-task-conf.ldif
new file mode 100644
index 0000000000000000000000000000000000000000..c54989e144330e3e806724ebfb09c635845b6bc5
--- /dev/null
+++ b/daemons/ipa-slapi-plugins/ipa-sidgen/ipa-sidgen-task-conf.ldif
@@ -0,0 +1,20 @@
+dn: cn=ipa-sidgen-task,cn=plugins,cn=config
+changetype: add
+objectClass: top
+objectClass: nsSlapdPlugin
+objectClass: extensibleObject
+cn: ipa-sidgen-task
+nsslapd-pluginPath: libipa_sidgen_task
+nsslapd-pluginInitfunc: sidgen_task_init
+nsslapd-pluginType: object
+nsslapd-pluginEnabled: on
+nsslapd-pluginId: ipa_sidgen_task
+nsslapd-pluginVersion: 1.0
+nsslapd-pluginVendor: RedHat
+nsslapd-pluginDescription: Generate SIDs for existing user and group entries
+
+dn: cn=ipa-sidgen-task,cn=tasks,cn=config
+changetype: add
+objectClass: top
+objectClass: extensibleObject
+cn: ipa-sidgen-task
diff --git a/daemons/ipa-slapi-plugins/ipa-sidgen/ipa-sidgen-task-example.ldif b/daemons/ipa-slapi-plugins/ipa-sidgen/ipa-sidgen-task-example.ldif
new file mode 100644
index 0000000000000000000000000000000000000000..9cfded73b1b53461c0c0aa4f563452f51d258aae
--- /dev/null
+++ b/daemons/ipa-slapi-plugins/ipa-sidgen/ipa-sidgen-task-example.ldif
@@ -0,0 +1,10 @@
+dn: cn=sidgen,cn=ipa-sidgen-task,cn=plugins,cn=config
+changetype: add
+objectClass: top
+objectClass: nsSlapdPlugin
+objectClass: extensibleObject
+cn: ipa-sidgen-task
+nsslapd-pluginPath: libipa_sidgen_task
+nsslapd-pluginInitfunc: sidgen_task_init
+nsslapd-basedn: $SUFFIX
+delay: 0
diff --git a/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.c b/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.c
new file mode 100644
index 0000000000000000000000000000000000000000..135c47a392853e482e5470e7f40cb79b7be86b76
--- /dev/null
+++ b/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.c
@@ -0,0 +1,244 @@
+/** 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:
+ * Sumit Bose <sbose at redhat.com>
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include <stdlib.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <dirsrv/slapi-plugin.h>
+
+#include "util.h"
+#include "ipa_sidgen.h"
+
+Slapi_PluginDesc ipa_sidgen_plugin_desc = {
+    IPA_SIDGEN_FEATURE_DESC,
+    "FreeIPA project",
+    "FreeIPA/1.0",
+    IPA_SIDGEN_PLUGIN_DESC
+};
+
+static int ipa_sidgen_start(Slapi_PBlock *pb)
+{
+    return 0;
+}
+
+static int ipa_sidgen_close(Slapi_PBlock *pb)
+{
+    int ret;
+    struct ipa_sidgen_ctx *ctx;
+
+    ret = slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &ctx);
+    if (ret == 0) {
+        free_ranges(&ctx->ranges);
+        slapi_ch_free_string(&ctx->dom_sid);
+    } else {
+        LOG_FATAL("Missing private plugin context.\n");
+    }
+
+    return 0;
+}
+
+static int ipa_sidgen_add_post_op(Slapi_PBlock *pb)
+{
+    int ret;
+    int is_repl_op;
+    struct slapi_entry *entry = NULL;
+    const char *dn_str;
+    Slapi_DN *dn = NULL;
+    struct ipa_sidgen_ctx *ctx;
+    Slapi_PBlock *search_pb = NULL;
+    char *errmsg = NULL;
+
+    ret = slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &is_repl_op);
+    if (ret != 0) {
+        LOG_FATAL("slapi_pblock_get failed!?\n");
+        return LDAP_OPERATIONS_ERROR;
+    }
+
+    if (is_repl_op) {
+        LOG("Is replicated operation, nothing to do.\n");
+        return LDAP_SUCCESS;
+    }
+
+    ret = slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &ctx);
+    if (ret != 0) {
+        LOG_FATAL("Missing private plugin context.\n");
+        goto done;
+    }
+
+    if (ctx->dom_sid == NULL) {
+        ret = get_dom_sid(ctx->plugin_id, ctx->base_dn, &ctx->dom_sid);
+        if (ret != 0) {
+            LOG_FATAL("Domain SID not available, nothing to do.\n");
+            ret = 0;
+            goto done;
+        }
+    }
+
+    ret = slapi_pblock_get(pb, SLAPI_TARGET_DN, &dn_str);
+    if (ret != 0) {
+        LOG_FATAL("Missing target DN.\n");
+        goto done;
+    }
+
+    dn = slapi_sdn_new_dn_byref(dn_str);
+    if (dn == NULL) {
+        LOG_FATAL("Failed to convert target DN.\n");
+        ret = LDAP_OPERATIONS_ERROR;
+        goto done;
+    }
+
+    ret = slapi_search_internal_get_entry(dn, NULL, &entry, ctx->plugin_id);
+    if (ret != 0 || entry == NULL) {
+        LOG_FATAL("Missing target entry.\n");
+        ret = LDAP_NO_SUCH_OBJECT;
+        goto done;
+    }
+
+    if (ctx->ranges == NULL) {
+        ret = get_ranges(ctx->plugin_id, ctx->base_dn, &ctx->ranges);
+        if (ret != 0) {
+            if (ret == LDAP_NO_SUCH_OBJECT) {
+                ret = 0;
+                LOG("No ID ranges found, nothing to do.\n");
+            } else {
+                LOG_FATAL("Failed to get ID ranges.\n");
+            }
+            goto done;
+        }
+    }
+
+    ret = find_sid_for_ldap_entry(entry, ctx->plugin_id, ctx->base_dn,
+                                  ctx->dom_sid, ctx->ranges);
+    if (ret != 0) {
+        LOG_FATAL("Cannot add SID to new entry.\n");
+        goto done;
+    }
+
+    ret = 0;
+done:
+    slapi_free_search_results_internal(search_pb);
+    slapi_pblock_destroy(search_pb);
+    slapi_sdn_free(&dn);
+
+    if (ret != 0) {
+        if (errmsg == NULL) {
+            errmsg = "SIDGEN error";
+        }
+        slapi_send_ldap_result(pb, ret, NULL, errmsg, 0, NULL);
+    }
+
+    return ret;
+}
+
+static int ipa_sidgen_init_ctx(Slapi_PBlock *pb, struct ipa_sidgen_ctx **_ctx)
+{
+    struct ipa_sidgen_ctx *ctx;
+    Slapi_Entry *entry;
+    int ret;
+
+    ctx = calloc(1, sizeof(struct ipa_sidgen_ctx));
+    if (ctx == NULL) {
+        return LDAP_OPERATIONS_ERROR;
+    }
+
+    ret = slapi_pblock_get(pb, SLAPI_PLUGIN_IDENTITY, &ctx->plugin_id);
+    if ((ret != 0) || (ctx->plugin_id == NULL)) {
+        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, &entry);
+    if (entry == NULL) {
+        LOG_FATAL("Plugin configuration not found!\n");
+        ret = EINVAL;
+        goto done;
+    }
+
+    ctx->base_dn = slapi_entry_attr_get_charptr(entry, "nsslapd-basedn");
+    if (ctx->base_dn == NULL) {
+        LOG_FATAL("Base DN not found in plugin configuration!\n");
+        ret = EINVAL;
+        goto done;
+    }
+
+    ret = 0;
+
+done:
+    if (ret != 0) {
+        free(ctx);
+    } else {
+        *_ctx = ctx;
+    }
+
+    return ret;
+}
+
+int ipa_sidgen_init(Slapi_PBlock *pb)
+{
+    int ret;
+    struct ipa_sidgen_ctx *ctx;
+
+    ret = ipa_sidgen_init_ctx(pb, &ctx);
+    if (ret != 0) {
+        LOG_FATAL("Failed ot initialize sidgen postop plugin.\n");
+        /* do not cause DS to stop, simply do nothing */
+        return 0;
+    }
+
+    ret = 0;
+    if (slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION,
+                         SLAPI_PLUGIN_VERSION_03) != 0 ||
+        slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN,
+                         (void *) ipa_sidgen_start) != 0 ||
+        slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN,
+                         (void *) ipa_sidgen_close) != 0 ||
+        slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION,
+                         (void *) &ipa_sidgen_plugin_desc) != 0 ||
+        slapi_pblock_set(pb, SLAPI_PLUGIN_POST_ADD_FN,
+                         (void *) ipa_sidgen_add_post_op) != 0 ||
+        slapi_pblock_set(pb, SLAPI_PLUGIN_PRIVATE, ctx) != 0) {
+        LOG_FATAL("failed to register plugin\n");
+        ret = EFAIL;
+    }
+
+    return ret;
+}
diff --git a/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.h b/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.h
new file mode 100644
index 0000000000000000000000000000000000000000..2c488435a03fe8bfc36ce7e4396e87d5b488e1c1
--- /dev/null
+++ b/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.h
@@ -0,0 +1,110 @@
+/** 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:
+ * Sumit Bose <sbose at redhat.com>
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifndef _IPA_SIDGEN_H_
+#define _IPA_SIDGEN_H_
+
+#define OBJECTCLASS "objectclass"
+#define IPA_OBJECT "ipaobject"
+#define MEP_MANAGED_ENTRY "mepManagedEntry"
+#define UID_NUMBER "uidNumber"
+#define GID_NUMBER "gidNumber"
+#define IPA_SID "ipaNTSecurityIdentifier"
+#define DOM_ATTRS_FILTER OBJECTCLASS"=ipaNTDomainAttrs"
+#define DOMAIN_ID_RANGE_FILTER OBJECTCLASS"=ipaDomainIDRange"
+#define POSIX_ACCOUNT "posixAccount"
+#define POSIX_GROUP "posixGroup"
+#define IPA_ID_OBJECT "ipaIDObject"
+#define IPANT_USER_ATTRS "ipaNTUserAttrs"
+#define IPANT_GROUP_ATTRS "ipaNTGroupAttrs"
+
+#define IPA_DNA_MAGIC 999
+
+#define IPA_PLUGIN_NAME "ipa-sidgen-postop"
+#define IPA_SIDGEN_FEATURE_DESC "IPA SIDGEN postop plugin"
+#define IPA_SIDGEN_PLUGIN_DESC "Add a SID to newly added or modified " \
+                               "objects with uid pr gid numbers"
+
+#define IPA_BASE_ID "ipaBaseID"
+#define IPA_ID_RANGE_SIZE "ipaIDRangeSize"
+#define IPA_BASE_RID "ipaBaseRID"
+#define IPA_SECONDARY_BASE_RID "ipaSecondaryBaseRID"
+
+struct range_info {
+    uint32_t base_id;
+    uint32_t id_range_size;
+    uint32_t base_rid;
+    uint32_t secondary_base_rid;
+};
+
+struct ipa_sidgen_ctx {
+    Slapi_ComponentId *plugin_id;
+    const char *base_dn;
+    char *dom_sid;
+    struct range_info **ranges;
+};
+
+void set_plugin_id_for_sidgen_task(Slapi_ComponentId *plugin_id);
+
+int sidgen_task_add(Slapi_PBlock *pb, Slapi_Entry *e,
+                    Slapi_Entry *eAfter, int *returncode,
+                    char *returntext, void *arg);
+
+int get_dom_sid(Slapi_ComponentId *plugin_id, const char *base_dn, char **_sid);
+
+int get_objectclass_flags(char **objectclasses,
+                          bool *has_posix_account,
+                          bool *has_posix_group,
+                          bool *has_ipa_id_object);
+
+void free_ranges(struct range_info ***_ranges);
+
+int get_ranges(Slapi_ComponentId *plugin_id, const char *base_dn,
+               struct range_info ***_ranges);
+
+int find_sid_for_id(uint32_t id, Slapi_ComponentId *plugin_id,
+                    const char *base_dn, const char *dom_sid,
+                    struct range_info **ranges, char **_sid);
+
+int find_sid_for_ldap_entry(struct slapi_entry *entry,
+                            Slapi_ComponentId *plugin_id,
+                            const char *base_dn,
+                            const char *dom_sid,
+                            struct range_info **ranges);
+#endif /* _IPA_SIDGEN_H_ */
diff --git a/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen_common.c b/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen_common.c
new file mode 100644
index 0000000000000000000000000000000000000000..cbbb2ef183f2d94826a9ead20ca1fc39daa09599
--- /dev/null
+++ b/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen_common.c
@@ -0,0 +1,568 @@
+/** 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:
+ * Sumit Bose <sbose at redhat.com>
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include <stdlib.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <dirsrv/slapi-plugin.h>
+
+#include "util.h"
+#include "ipa_sidgen.h"
+
+int get_dom_sid(Slapi_ComponentId *plugin_id, const char *base_dn, char **_sid)
+{
+    Slapi_PBlock *search_pb = NULL;
+    int search_result;
+    Slapi_Entry **search_entries = NULL;
+    int ret;
+    const char *sid;
+
+    search_pb = slapi_pblock_new();
+    if (search_pb == NULL) {
+        LOG_FATAL("Failed to create new pblock.\n");
+        ret = LDAP_OPERATIONS_ERROR;
+        goto done;
+    }
+
+    slapi_search_internal_set_pb(search_pb, base_dn,
+                                 LDAP_SCOPE_SUBTREE, DOM_ATTRS_FILTER,
+                                 NULL, 0, NULL, NULL, plugin_id, 0);
+
+    ret = slapi_search_internal_pb(search_pb);
+    if (ret != 0) {
+        LOG_FATAL("Starting internal search failed.\n");
+        goto done;
+    }
+
+    ret = slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &search_result);
+    if (ret != 0 || search_result != LDAP_SUCCESS) {
+        LOG_FATAL("Internal search failed.\n");
+        ret = LDAP_OPERATIONS_ERROR;
+        goto done;
+    }
+
+    ret = slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES,
+                           &search_entries);
+    if (ret != 0) {
+        LOG_FATAL("Failed to read searched entries.\n");
+        goto done;
+    }
+
+    if (search_entries == NULL || search_entries[0] == NULL) {
+        LOG("No existing entries.\n");
+        ret = LDAP_NO_SUCH_OBJECT;
+        goto done;
+    }
+
+    if (search_entries[1] != NULL) {
+        LOG("Too many results found.\n");
+        ret = LDAP_OPERATIONS_ERROR;
+        goto done;
+    }
+
+    sid = slapi_entry_attr_get_charptr(search_entries[0], IPA_SID);
+    if (sid == NULL) {
+        LOG("Domain object does not have a SID.\n");
+        ret = LDAP_NO_SUCH_ATTRIBUTE;
+        goto done;
+    }
+
+    *_sid = slapi_ch_strdup(sid);
+    if (*_sid == NULL) {
+        LOG("slapi_ch_strdup failed.\n");
+        ret = LDAP_OPERATIONS_ERROR;
+        goto done;
+    }
+
+    LOG("Found domain SID [%s].\n", *_sid);
+    ret = 0;
+
+done:
+    slapi_free_search_results_internal(search_pb);
+    slapi_pblock_destroy(search_pb);
+
+    return ret;
+}
+
+static int slapi_entry_to_range_info(struct slapi_entry *entry,
+                                     struct range_info **_range)
+{
+    int ret;
+    unsigned long ul_val;
+    struct range_info *range = NULL;
+
+    range = ( struct range_info *) slapi_ch_calloc(1, sizeof(struct range_info));
+    if (range == NULL) {
+        return LDAP_OPERATIONS_ERROR;
+    }
+
+    ul_val = slapi_entry_attr_get_ulong(entry, IPA_BASE_ID);
+    if (ul_val == 0 || ul_val >= UINT32_MAX) {
+        ret = LDAP_OPERATIONS_ERROR;
+        goto done;
+    }
+    range->base_id = ul_val;
+
+    ul_val = slapi_entry_attr_get_ulong(entry, IPA_ID_RANGE_SIZE);
+    if (ul_val == 0 || ul_val >= UINT32_MAX) {
+        ret = LDAP_OPERATIONS_ERROR;
+        goto done;
+    }
+    range->id_range_size = ul_val;
+
+    ul_val = slapi_entry_attr_get_ulong(entry, IPA_BASE_RID);
+    if (ul_val == 0 || ul_val >= UINT32_MAX) {
+        ret = LDAP_OPERATIONS_ERROR;
+        goto done;
+    }
+    range->base_rid = ul_val;
+
+    ul_val = slapi_entry_attr_get_ulong(entry, IPA_SECONDARY_BASE_RID);
+    if (ul_val == 0 || ul_val >= UINT32_MAX) {
+        ret = ERANGE;
+        goto done;
+    }
+    range->secondary_base_rid = ul_val;
+
+    *_range = range;
+    ret = 0;
+
+done:
+    if (ret != 0) {
+        slapi_ch_free((void **) &range);
+    }
+
+    return ret;
+}
+
+int get_objectclass_flags(char **objectclasses,
+                          bool *has_posix_account,
+                          bool *has_posix_group,
+                          bool *has_ipa_id_object)
+{
+    size_t c;
+
+    if (objectclasses == NULL) {
+        return LDAP_OPERATIONS_ERROR;
+    }
+
+    *has_posix_account = false;
+    *has_posix_group = false;
+    *has_ipa_id_object = false;
+
+    for (c = 0; objectclasses[c] != NULL; c++) {
+        if (strcasecmp(objectclasses[c], POSIX_ACCOUNT) == 0) {
+            *has_posix_account = true;
+        } else if (strcasecmp(objectclasses[c], POSIX_GROUP) == 0) {
+            *has_posix_group = true;
+        } else if (strcasecmp(objectclasses[c], IPA_ID_OBJECT) == 0) {
+            *has_ipa_id_object = true;
+        }
+    }
+
+    return 0;
+}
+
+void free_ranges(struct range_info ***_ranges)
+{
+    size_t c;
+    struct range_info **ranges = *_ranges;
+
+    if (ranges != NULL) {
+        for (c = 0; ranges[c] != NULL; c++) {
+            slapi_ch_free((void **) &ranges[c]);
+        }
+
+        slapi_ch_free((void **) _ranges);
+    }
+}
+
+int get_ranges(Slapi_ComponentId *plugin_id, const char *base_dn,
+               struct range_info ***_ranges)
+{
+    Slapi_PBlock *search_pb = NULL;
+    Slapi_Entry **search_entries = NULL;
+    int search_result;
+    size_t c;
+    int ret;
+    struct range_info **ranges = NULL;
+
+    search_pb = slapi_pblock_new();
+    if (search_pb == NULL) {
+        LOG_FATAL("Failed to create new pblock.\n");
+        ret = LDAP_OPERATIONS_ERROR;
+        goto done;
+    }
+
+    slapi_search_internal_set_pb(search_pb, base_dn,
+                                 LDAP_SCOPE_SUBTREE, DOMAIN_ID_RANGE_FILTER,
+                                 NULL, 0, NULL, NULL, plugin_id, 0);
+
+    ret = slapi_search_internal_pb(search_pb);
+    if (ret != 0) {
+        LOG_FATAL("Starting internal search failed.\n");
+        goto done;
+    }
+
+    ret = slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &search_result);
+    if (ret != 0 || search_result != LDAP_SUCCESS) {
+        LOG_FATAL("Internal search failed.\n");
+        ret = (search_result != LDAP_SUCCESS) ? search_result:
+                                                LDAP_OPERATIONS_ERROR;
+        goto done;
+    }
+
+    ret = slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES,
+                           &search_entries);
+    if (ret != 0) {
+        LOG_FATAL("Failed to read searched entries.\n");
+        goto done;
+    }
+
+    if (search_entries == NULL || search_entries[0] == NULL) {
+        LOG("No ranges found.\n");
+        ret = LDAP_NO_SUCH_OBJECT;
+        goto done;
+    }
+
+    for (c = 0; search_entries[c] != NULL; c++);
+    ranges = (struct range_info **) slapi_ch_calloc(c + 1,
+                                                    sizeof(struct range_info *));
+    if (ranges == NULL) {
+        LOG("calloc failed.\n");
+        ret = LDAP_OPERATIONS_ERROR;
+        goto done;
+    }
+
+    for (c = 0; search_entries[c] != NULL; c++) {
+        ret = slapi_entry_to_range_info(search_entries[c], &ranges[c]);
+        if (ret != 0) {
+            LOG_FATAL("Failed to convert LDAP entry to range struct.\n");
+            goto done;
+        }
+    }
+
+    *_ranges = ranges;
+    ret = 0;
+
+done:
+    slapi_free_search_results_internal(search_pb);
+    slapi_pblock_destroy(search_pb);
+    if (ret != 0) {
+        free_ranges(&ranges);
+    }
+
+    return ret;
+}
+
+static int find_sid(const char *sid, Slapi_ComponentId *plugin_id,
+                    const char *base_dn)
+{
+    Slapi_PBlock *search_pb = NULL;
+    Slapi_Entry **search_entries = NULL;
+    int search_result;
+    int ret;
+    char *filter = NULL;
+
+    search_pb = slapi_pblock_new();
+    if (search_pb == NULL) {
+        LOG_FATAL("Failed to create new pblock.\n");
+        ret = LDAP_OPERATIONS_ERROR;
+        goto done;
+    }
+
+    filter = slapi_ch_smprintf("%s=%s", IPA_SID, sid);
+    if (filter == NULL) {
+        LOG_FATAL("Cannot create search filter to check if SID is used.\n");
+        ret = LDAP_OPERATIONS_ERROR;
+        goto done;
+    }
+
+    slapi_search_internal_set_pb(search_pb, base_dn,
+                                 LDAP_SCOPE_SUBTREE, filter,
+                                 NULL, 0, NULL, NULL, plugin_id, 0);
+
+    ret = slapi_search_internal_pb(search_pb);
+    if (ret != 0) {
+        LOG_FATAL("Starting internal search failed.\n");
+        goto done;
+    }
+
+    ret = slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &search_result);
+    if (ret != 0 || search_result != LDAP_SUCCESS) {
+        LOG_FATAL("Internal search failed.\n");
+        ret = (search_result != LDAP_SUCCESS) ? search_result:
+                                                LDAP_OPERATIONS_ERROR;
+        goto done;
+    }
+
+    ret = slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES,
+                           &search_entries);
+    if (ret != 0) {
+        LOG_FATAL("Failed to read searched entries.\n");
+        goto done;
+    }
+
+    if (search_entries == NULL || search_entries[0] == NULL) {
+        LOG("No SID found.\n");
+        ret = LDAP_NO_SUCH_OBJECT;
+        goto done;
+    }
+
+    ret = 0;
+
+done:
+    slapi_ch_free_string(&filter);
+    slapi_free_search_results_internal(search_pb);
+    slapi_pblock_destroy(search_pb);
+
+    return ret;
+}
+
+static int rid_to_sid_with_check(uint32_t rid, Slapi_ComponentId *plugin_id,
+                                 const char *base_dn, const char *dom_sid,
+                                 char **_sid)
+{
+    char *sid = NULL;
+    int ret;
+
+    sid = slapi_ch_smprintf("%s-%lu", dom_sid, (unsigned long) rid);
+    if (sid == NULL) {
+        LOG("Failed to create SID string.\n");
+        ret = LDAP_OPERATIONS_ERROR;
+        goto done;
+    }
+
+    LOG("SID is [%s].\n", sid);
+
+    ret = find_sid(sid, plugin_id, base_dn);
+    if (ret == LDAP_NO_SUCH_OBJECT) {
+        *_sid = sid;
+        ret = 0;
+        goto done;
+    } else if (ret != 0) {
+        LOG_FATAL("Cannot check if SID is already used.\n");
+        goto done;
+    }
+
+    LOG_FATAL("SID [%s] is already used.\n", sid);
+    ret = LDAP_CONSTRAINT_VIOLATION;
+
+done:
+    if (ret != 0) {
+        slapi_ch_free_string(&sid);
+    }
+
+    return ret;
+}
+
+int find_sid_for_id(uint32_t id, Slapi_ComponentId *plugin_id,
+                    const char *base_dn, const char *dom_sid,
+                    struct range_info **ranges, char **_sid)
+{
+    uint32_t rid;
+    size_t c;
+    char *sid = NULL;
+    int ret;
+
+    rid = 0;
+    for (c = 0; ranges[c] != NULL; c++) {
+        if (id >= ranges[c]->base_id &&
+            id < (ranges[c]->base_id + ranges[c]->id_range_size)) {
+            rid = ranges[c]->base_rid + (id - ranges[c]->base_id);
+            break;
+        }
+    }
+
+    if (rid == 0) {
+        LOG("No matching range found. Cannot add SID.\n");
+        ret = LDAP_NO_SUCH_OBJECT;
+        goto done;
+    }
+
+    ret = rid_to_sid_with_check(rid, plugin_id, base_dn, dom_sid, &sid);
+    if (ret != LDAP_CONSTRAINT_VIOLATION) {
+        goto done;
+    }
+
+    /* SID is already used, try secondary range.*/
+    rid = ranges[c]->secondary_base_rid + (id - ranges[c]->base_id);
+
+    ret = rid_to_sid_with_check(rid, plugin_id, base_dn, dom_sid, &sid);
+    if (ret != LDAP_CONSTRAINT_VIOLATION) {
+        goto done;
+    }
+
+    LOG_FATAL("Secondary SID is used as well.\n");
+
+done:
+    if (ret != 0) {
+        slapi_ch_free_string(&sid);
+    } else {
+        *_sid = sid;
+    }
+
+    return ret;
+}
+
+int find_sid_for_ldap_entry(struct slapi_entry *entry,
+                            Slapi_ComponentId *plugin_id,
+                            const char *base_dn,
+                            const char *dom_sid,
+                            struct range_info **ranges)
+{
+    int ret;
+    const char *dn_str;
+    uint32_t uid_number;
+    uint32_t gid_number;
+    uint32_t id;
+    char *sid = NULL;
+    char **objectclasses = NULL;
+    Slapi_PBlock *mod_pb = NULL;
+    Slapi_Mods *smods = NULL;
+    int result;
+    bool has_posix_account = false;
+    bool has_posix_group = false;
+    bool has_ipa_id_object = false;
+    const char *objectclass_to_add = NULL;
+
+    dn_str = slapi_entry_get_dn_const(entry);
+    if (dn_str == NULL) {
+        LOG_FATAL("Cannot find DN of an LDAP entry.\n");
+        ret = LDAP_NO_SUCH_ATTRIBUTE;
+        goto done;
+    }
+    LOG("Trying to add SID for [%s].\n", dn_str);
+
+    uid_number = slapi_entry_attr_get_ulong(entry, UID_NUMBER);
+    gid_number = slapi_entry_attr_get_ulong(entry, GID_NUMBER);
+
+    if (uid_number == 0 && gid_number == 0) {
+        LOG("[%s] does not have Posix IDs, nothing to do.\n", dn_str);
+        ret = 0;
+        goto done;
+    }
+
+    if (uid_number == IPA_DNA_MAGIC || gid_number == IPA_DNA_MAGIC) {
+        LOG_FATAL("Looks that DNA plugin was not run before.\n");
+        ret = LDAP_OPERATIONS_ERROR;
+        goto done;
+    }
+
+    if (uid_number >= UINT32_MAX || gid_number >= UINT32_MAX) {
+        LOG_FATAL("ID value too large.\n");
+        ret = LDAP_CONSTRAINT_VIOLATION;
+        goto done;
+    }
+
+    sid = slapi_entry_attr_get_charptr(entry, IPA_SID);
+    if (sid != NULL) {
+        LOG("Object already has a SID, nothing to do.\n");
+        ret = 0;
+        goto done;
+    }
+
+    objectclasses = slapi_entry_attr_get_charray(entry, OBJECTCLASS);
+    ret = get_objectclass_flags(objectclasses, &has_posix_account,
+                                               &has_posix_group,
+                                               &has_ipa_id_object);
+    if (ret != 0) {
+        LOG_FATAL("Cannot determine objectclasses.\n");
+        goto done;
+    }
+
+    if (has_posix_account && uid_number != 0 && gid_number != 0) {
+        id = uid_number;
+        objectclass_to_add = IPANT_USER_ATTRS;
+    } else if (has_posix_group && gid_number != 0) {
+        id = gid_number;
+        objectclass_to_add = IPANT_GROUP_ATTRS;
+    } else if (has_ipa_id_object) {
+        id = (uid_number != 0) ? uid_number : gid_number;
+        objectclass_to_add = NULL;
+    } else {
+        LOG_FATAL("Inconsistent objectclasses and attributes, nothing to do.\n");
+        ret = 0;
+        goto done;
+    }
+
+    ret = find_sid_for_id(id, plugin_id, base_dn, dom_sid, ranges, &sid);
+    if (ret != 0) {
+        LOG_FATAL("Cannot convert Posix ID [%ul] into an unused SID.\n", id);
+        goto done;
+    }
+
+    smods = slapi_mods_new();
+    if (smods == NULL) {
+        LOG("slapi_mods_new failed.\n");
+        ret = LDAP_OPERATIONS_ERROR;
+        goto done;
+    }
+
+    if (objectclass_to_add != NULL) {
+        slapi_mods_add_string(smods, LDAP_MOD_ADD,
+                              OBJECTCLASS, objectclass_to_add);
+    }
+    slapi_mods_add_string(smods, LDAP_MOD_REPLACE, IPA_SID, sid);
+
+    mod_pb = slapi_pblock_new();
+    slapi_modify_internal_set_pb(mod_pb, dn_str,
+                                 slapi_mods_get_ldapmods_byref(smods),
+                                 NULL, NULL, plugin_id, 0);
+
+    ret = slapi_modify_internal_pb(mod_pb);
+    if (ret != 0) {
+        LOG_FATAL("Modify failed with [%d] on entry [%s]\n", ret, dn_str);
+        goto done;
+    }
+
+    ret = slapi_pblock_get(mod_pb, SLAPI_PLUGIN_INTOP_RESULT, &result);
+    if (ret != 0 || result != LDAP_SUCCESS){
+        LOG_FATAL("Modify failed on entry [%s]\n", dn_str);
+        goto done;
+    }
+
+done:
+    slapi_ch_free_string(&sid);
+    slapi_pblock_destroy(mod_pb);
+    slapi_mods_free(&smods);
+    slapi_ch_array_free(objectclasses);
+
+    return ret;
+}
diff --git a/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen_task.c b/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen_task.c
new file mode 100644
index 0000000000000000000000000000000000000000..ffbc9c636e32b0c0a3960ec76eda378a94c504fe
--- /dev/null
+++ b/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen_task.c
@@ -0,0 +1,348 @@
+/** 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:
+ * Sumit Bose <sbose at redhat.com>
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+#include <pthread.h>
+#include <dirsrv/slapi-plugin.h>
+
+#include "util.h"
+#include "ipa_sidgen.h"
+
+#define NSEC_PER_SEC     1000000000UL
+
+
+#define AT_CN "cn"
+
+Slapi_ComponentId *global_sidgen_plugin_id = NULL;
+
+struct worker_ctx {
+    long delay;
+    char *base_dn;
+    Slapi_ComponentId *plugin_id;
+    pthread_t tid;
+    char *dom_sid;
+    struct range_info **ranges;
+};
+
+static const char *fetch_attr(Slapi_Entry *e, const char *attrname,
+                                              const char *default_val)
+{
+    Slapi_Attr *attr;
+    Slapi_Value *val = NULL;
+
+    if (slapi_entry_attr_find(e, attrname, &attr) != 0)
+        return default_val;
+    slapi_attr_first_value(attr, &val);
+    return slapi_value_get_string(val);
+}
+
+static void free_pblock(void *arg)
+{
+    Slapi_PBlock *pb = (Slapi_PBlock *) arg;
+
+    slapi_free_search_results_internal(pb);
+    slapi_pblock_destroy(pb);
+}
+
+static int do_work(struct worker_ctx *worker_ctx)
+{
+    Slapi_PBlock *pb;
+    int ret;
+    size_t c;
+    char *filter = NULL;
+    char *attrs[] = { OBJECTCLASS, UID_NUMBER, GID_NUMBER, NULL };
+    Slapi_Entry **e = NULL;
+    struct timespec ts;
+
+    pb = slapi_pblock_new();
+    if (pb == NULL) {
+        return ENOMEM;
+    }
+
+    pthread_cleanup_push(free_pblock, (void *) pb);
+
+    filter = slapi_ch_smprintf("(&(%s=%s)(!(%s=%s))(|(%s=%s)(%s=%s)(%s=%s))(!(%s=*)))",
+                               OBJECTCLASS, IPA_OBJECT,
+                               OBJECTCLASS, MEP_MANAGED_ENTRY,
+                               OBJECTCLASS, POSIX_ACCOUNT,
+                               OBJECTCLASS, POSIX_GROUP,
+                               OBJECTCLASS, IPA_ID_OBJECT,
+                               IPA_SID);
+    if (filter == NULL) {
+        LOG_FATAL("Cannot generate search filter for objects without a SID.\n");
+        ret = ENOMEM;
+        goto done;
+    }
+    LOG("Base DN: [%s], Filter: [%s].\n", worker_ctx->base_dn, filter);
+
+    slapi_search_internal_set_pb(pb, worker_ctx->base_dn, LDAP_SCOPE_SUBTREE,
+                                 filter, attrs, 0, NULL, NULL,
+                                 worker_ctx->plugin_id, 0);
+    ret = slapi_search_internal_pb(pb);
+    if (ret != 0) {
+        slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &ret);
+        if (ret != 0) {
+            LOG_FATAL("Search failed with [%d].\n", ret);
+        } else {
+            LOG_FATAL("slapi_search_internal_pb failed, "
+                      "but no error code available.\n");
+            ret = EFAULT;
+        }
+        goto done;
+    }
+
+    ret = slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &e);
+    if (ret != 0) {
+        LOG_FATAL("slapi_pblock_get failed.\n");
+        ret = EFAULT;
+        goto done;
+    }
+
+    if (e == NULL || e[0] == NULL) {
+        LOG("No entry with missing SID found.\n");
+        ret = 0;
+        goto done;
+    }
+
+    for (c = 0; e[c] != NULL; c++) {
+        ret = find_sid_for_ldap_entry(e[c], worker_ctx->plugin_id,
+                                      worker_ctx->base_dn, worker_ctx->dom_sid,
+                                      worker_ctx->ranges);
+        if (ret != 0) {
+            LOG_FATAL("Cannot add SID to existing entry.\n");
+            goto done;
+        }
+
+        if (worker_ctx->delay != 0) {
+            ts.tv_nsec = worker_ctx->delay % NSEC_PER_SEC;
+            ts.tv_sec = (worker_ctx->delay - ts.tv_nsec) / NSEC_PER_SEC;
+            nanosleep(&ts, NULL);
+        }
+    };
+
+done:
+    slapi_ch_free_string(&filter);
+    pthread_cleanup_pop(1);
+
+    LOG("do_work finished with [%d].\n", ret);
+
+    return ret;
+}
+
+static void *sidgen_task_thread(void *arg)
+{
+    Slapi_Task *task = (Slapi_Task *)arg;
+    struct worker_ctx *worker_ctx;
+    int ret;
+
+    if (task == NULL) {
+        LOG_FATAL("Missing task data!\n");
+        ret =SLAPI_DSE_CALLBACK_OK;
+        goto done;
+    }
+
+    worker_ctx = slapi_task_get_data(task);
+    if (worker_ctx == NULL) {
+        LOG_FATAL("Missing context!\n");
+        ret =SLAPI_DSE_CALLBACK_OK;
+        goto done;
+    }
+
+    slapi_task_begin(task, 1);
+    LOG_FATAL("Sidgen task starts ...\n");
+
+    ret = do_work(worker_ctx);
+
+done:
+    LOG_FATAL("Sidgen task finished [%d].\n", ret);
+    slapi_task_inc_progress(task);
+    slapi_task_finish(task, ret);
+
+    return NULL;
+}
+
+static void sidgen_task_destructor(Slapi_Task *task)
+{
+    struct worker_ctx *worker_ctx;
+
+    if (task != NULL) {
+        worker_ctx = slapi_task_get_data(task);
+        if (worker_ctx != NULL) {
+            free_ranges(&worker_ctx->ranges);
+            slapi_ch_free_string(&worker_ctx->dom_sid);
+            slapi_ch_free_string(&worker_ctx->base_dn);
+            slapi_ch_free((void **) &worker_ctx);
+        }
+    }
+}
+
+int sidgen_task_add(Slapi_PBlock *pb, Slapi_Entry *e,
+                    Slapi_Entry *eAfter, int *returncode,
+                    char *returntext, void *arg)
+{
+    int ret = SLAPI_DSE_CALLBACK_ERROR;
+    const char *str;
+    struct worker_ctx *worker_ctx = NULL;
+    char *endptr;
+    Slapi_Task *task = NULL;
+
+    *returncode = LDAP_OPERATIONS_ERROR;
+    returntext[0] = '\0';
+
+    worker_ctx = (struct worker_ctx *) slapi_ch_calloc(1,
+                                                     sizeof(struct worker_ctx));
+    if (worker_ctx == NULL) {
+        LOG_FATAL("slapi_ch_malloc failed!\n");
+        *returncode = LDAP_OPERATIONS_ERROR;
+        ret = SLAPI_DSE_CALLBACK_ERROR;
+        goto done;
+    }
+
+    worker_ctx->plugin_id = global_sidgen_plugin_id;
+
+    str = fetch_attr(e, "delay", NULL);
+    if (str != NULL) {
+        errno = 0;
+        worker_ctx->delay = strtol(str, &endptr, 10);
+        if (errno != 0 || worker_ctx->delay < 0) {
+            LOG_FATAL("invalid delay [%s]!\n", str);
+            *returncode = LDAP_CONSTRAINT_VIOLATION;
+            ret = SLAPI_DSE_CALLBACK_ERROR;
+            goto done;
+        }
+    }
+    LOG("delay is [%li].\n", worker_ctx->delay);
+
+    str = fetch_attr(e, "nsslapd-basedn", NULL);
+    if (str == NULL) {
+        LOG_FATAL("Missing nsslapd-basedn!\n");
+        *returncode = LDAP_CONSTRAINT_VIOLATION;
+        ret = SLAPI_DSE_CALLBACK_ERROR;
+        goto done;
+    }
+    worker_ctx->base_dn = slapi_ch_strdup(str);
+    if (worker_ctx->base_dn == NULL) {
+        LOG_FATAL("Failed to copy base DN.\n");
+        *returncode = LDAP_OPERATIONS_ERROR;
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = get_dom_sid(worker_ctx->plugin_id, worker_ctx->base_dn,
+                      &worker_ctx->dom_sid);
+    if (ret != 0) {
+        LOG_FATAL("Cannot find domain SID.\n");
+        goto done;
+    }
+
+    ret = get_ranges(worker_ctx->plugin_id, worker_ctx->base_dn,
+                     &worker_ctx->ranges);
+    if (ret != 0) {
+        LOG_FATAL("Cannot find ranges.\n");
+        goto done;
+    }
+
+    task = slapi_new_task(slapi_entry_get_ndn(e));
+    if (task == NULL) {
+        LOG_FATAL("unable to allocate new task!\n");
+        *returncode = LDAP_OPERATIONS_ERROR;
+        ret = SLAPI_DSE_CALLBACK_ERROR;
+        goto done;
+    }
+
+    slapi_task_set_destructor_fn(task, sidgen_task_destructor);
+    slapi_task_set_data(task, worker_ctx);
+
+    ret = pthread_create(&worker_ctx->tid, NULL, sidgen_task_thread, task);
+    if (ret != 0) {
+        LOG_FATAL("unable to create sidgen task thread!\n");
+        *returncode = LDAP_OPERATIONS_ERROR;
+        ret = SLAPI_DSE_CALLBACK_ERROR;
+        slapi_task_finish(task, *returncode);
+        goto done;
+    }
+
+    ret = SLAPI_DSE_CALLBACK_OK;
+    *returncode = LDAP_SUCCESS;
+
+done:
+    if (ret != SLAPI_DSE_CALLBACK_OK) {
+        slapi_ch_free((void **) &worker_ctx->base_dn);
+        slapi_ch_free((void **) &worker_ctx);
+    }
+    return ret;
+}
+
+static int sigden_task_start(Slapi_PBlock *pb)
+{
+    int ret = 0;
+
+    ret = slapi_task_register_handler("ipa-sidgen-task", sidgen_task_add);
+
+    return ret;
+}
+
+int sidgen_task_init(Slapi_PBlock *pb)
+{
+    int ret = 0;
+
+    ret = slapi_pblock_get(pb, SLAPI_PLUGIN_IDENTITY,
+                           &global_sidgen_plugin_id);
+    if (ret != 0 || global_sidgen_plugin_id == NULL) {
+        LOG_FATAL("Plugin identity not available.\n");
+        ret = (ret != 0) ? ret : EINVAL;
+        goto done;
+    }
+
+    ret = slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION,
+                            (void *) SLAPI_PLUGIN_VERSION_03);
+
+    ret |= slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN,
+                            (void *) sigden_task_start);
+
+done:
+    if (ret != 0) {
+        LOG_FATAL("Failed to initialize plug-in\n" );
+    }
+
+    return ret;
+}
diff --git a/freeipa.spec.in b/freeipa.spec.in
index 7c1dc4312e89decb5b911a9962fbb020761b28d2..58393bb0f788cba9bc9c60b6ab85899fc89bcdc9 100644
--- a/freeipa.spec.in
+++ b/freeipa.spec.in
@@ -355,6 +355,8 @@ 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}/%{plugin_dir}/libipa_sidgen.la
+rm %{buildroot}/%{plugin_dir}/libipa_sidgen_task.la
 rm %{buildroot}/%{_libdir}/krb5/plugins/kdb/ipadb.la
 rm %{buildroot}/%{_libdir}/samba/pdb/ipasam.la
 
@@ -664,6 +666,8 @@ fi
 %{_sbindir}/ipa-adtrust-install
 %{_usr}/share/ipa/smb.conf.empty
 %attr(755,root,root) %{_libdir}/samba/pdb/ipasam.so
+%attr(755,root,root) %{plugin_dir}/libipa_sidgen.so
+%attr(755,root,root) %{plugin_dir}/libipa_sidgen_task.so
 %{_mandir}/man1/ipa-adtrust-install.1.gz
 %{python_sitelib}/ipaserver/dcerpc*
 %{python_sitelib}/ipaserver/install/adtrustinstance*
diff --git a/ipaserver/install/adtrustinstance.py b/ipaserver/install/adtrustinstance.py
index 4d417c8d1d15e4e7a799e871f886232cbf888331..ba2e6ef5dfe1b2ff6f588adf5ec53882e0f81d9b 100644
--- a/ipaserver/install/adtrustinstance.py
+++ b/ipaserver/install/adtrustinstance.py
@@ -223,6 +223,13 @@ class ADTRUSTInstance(service.Service):
         except:
             pass
 
+    def __add_sidgen_module(self):
+        try:
+            self._ldap_mod("ipa-sidgen-conf.ldif", self.sub_dict)
+            self._ldap_mod("ipa-sidgen-task-conf.ldif", self.sub_dict)
+        except:
+            pass
+
     def __write_smb_registry(self):
         template = os.path.join(ipautil.SHARE_DIR, "smb.conf.template")
         conf = ipautil.template_file(template, self.sub_dict)
@@ -430,6 +437,7 @@ class ADTRUSTInstance(service.Service):
         self.step("adding cifs Kerberos principal", self.__setup_principal)
         self.step("adding admin(group) SIDs", self.__add_admin_sids)
         self.step("activating CLDAP plugin", self.__add_cldap_module)
+        self.step("activating sidgen plugin and task", self.__add_sidgen_module)
         self.step("configuring smbd to start on boot", self.__enable)
         if not self.no_msdcs:
             self.step("adding special DNS service records", \
-- 
1.7.10.2



More information about the Freeipa-devel mailing list