From 39be701c1378fd426179280299f056e2b3c93388 Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <sgallagh@redhat.com>
Date: Sun, 22 Apr 2012 20:52:58 -0400
Subject: [PATCH 15/21] LDAP: Map the user's primaryGroupID

---
 src/config/SSSDConfig.py                 |    1 +
 src/config/etc/sssd.api.d/sssd-ipa.conf  |    1 +
 src/config/etc/sssd.api.d/sssd-ldap.conf |    1 +
 src/db/sysdb.h                           |    1 +
 src/providers/ipa/ipa_opts.h             |    1 +
 src/providers/ldap/ldap_opts.h           |    3 ++
 src/providers/ldap/sdap.h                |    1 +
 src/providers/ldap/sdap_async_users.c    |   76 +++++++++++++++++++++++++-----
 8 files changed, 73 insertions(+), 12 deletions(-)

diff --git a/src/config/SSSDConfig.py b/src/config/SSSDConfig.py
index b9c484fe508812c298dee98d02d884c40cf2c0ab..aa35f9c6caff0106eb698a043b876ca053070373 100644
--- a/src/config/SSSDConfig.py
+++ b/src/config/SSSDConfig.py
@@ -207,6 +207,7 @@ option_strings = {
     'ldap_user_shell' : _('Shell attribute'),
     'ldap_user_uuid' : _('UUID attribute'),
     'ldap_user_objectsid' : _("objectSID attribute"),
+    'ldap_user_primary_group' : _('Active Directory primary group attribute for ID-mapping'),
     'ldap_user_principal' : _('User principal attribute (for Kerberos)'),
     'ldap_user_fullname' : _('Full Name'),
     'ldap_user_member_of' : _('memberOf attribute'),
diff --git a/src/config/etc/sssd.api.d/sssd-ipa.conf b/src/config/etc/sssd.api.d/sssd-ipa.conf
index ac375075b986a74167697a8d3955f1716a05d2cc..20eb71f4cc0cb0d7304865fa88923fc372ce67a3 100644
--- a/src/config/etc/sssd.api.d/sssd-ipa.conf
+++ b/src/config/etc/sssd.api.d/sssd-ipa.conf
@@ -62,6 +62,7 @@ ldap_user_home_directory = str, None, false
 ldap_user_shell = str, None, false
 ldap_user_uuid = str, None, false
 ldap_user_objectsid = str, None, false
+ldap_user_primary_group = str, None, false
 ldap_user_principal = str, None, false
 ldap_user_fullname = str, None, false
 ldap_user_member_of = str, None, false
diff --git a/src/config/etc/sssd.api.d/sssd-ldap.conf b/src/config/etc/sssd.api.d/sssd-ldap.conf
index 2768366b376d042c2b2a52944dc56a2d4fac82e9..a0694c7089fec306e075f3c5b7ec25500564a09c 100644
--- a/src/config/etc/sssd.api.d/sssd-ldap.conf
+++ b/src/config/etc/sssd.api.d/sssd-ldap.conf
@@ -54,6 +54,7 @@ ldap_user_home_directory = str, None, false
 ldap_user_shell = str, None, false
 ldap_user_uuid = str, None, false
 ldap_user_objectsid = str, None, false
+ldap_user_primary_group = str, None, false
 ldap_user_principal = str, None, false
 ldap_user_fullname = str, None, false
 ldap_user_member_of = str, None, false
diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index 98255bede9e03899f80901f58ba5c9fc9ded16a5..a0d176ec7f9c04b467caf7b2c38ffc6fb263497b 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -108,6 +108,7 @@
 
 #define SYSDB_UUID "uniqueID"
 #define SYSDB_SID "objectSID"
+#define SYSDB_PRIMARY_GROUP "ADPrimaryGroupID"
 #define SYSDB_SID_STR "objectSIDString"
 #define SYSDB_UPN "userPrincipalName"
 #define SYSDB_CCACHE_FILE "ccacheFile"
diff --git a/src/providers/ipa/ipa_opts.h b/src/providers/ipa/ipa_opts.h
index 1fe78183e755b1167845d5aca710099b563d7f71..f688f765c988fa79d2ae97fcdfbeee0bd3fa523b 100644
--- a/src/providers/ipa/ipa_opts.h
+++ b/src/providers/ipa/ipa_opts.h
@@ -143,6 +143,7 @@ struct sdap_attr_map ipa_user_map[] = {
     { "ldap_user_member_of", "memberOf", SYSDB_MEMBEROF, NULL },
     { "ldap_user_uuid", "nsUniqueId", SYSDB_UUID, NULL },
     { "ldap_user_objectsid", NULL, SYSDB_SID, NULL },
+    { "ldap_user_primary_group", NULL, SYSDB_PRIMARY_GROUP, NULL },
     { "ldap_user_modify_timestamp", "modifyTimestamp", SYSDB_ORIG_MODSTAMP, NULL },
     { "ldap_user_entry_usn", NULL, SYSDB_USN, NULL },
     { "ldap_user_shadow_last_change", "shadowLastChange", SYSDB_SHADOWPW_LASTCHANGE, NULL },
diff --git a/src/providers/ldap/ldap_opts.h b/src/providers/ldap/ldap_opts.h
index 646c54ecb77f6e5dcb5db7eda6cb16bda9980dcb..62b0371339c86d0277e6842be389e696936f4ae3 100644
--- a/src/providers/ldap/ldap_opts.h
+++ b/src/providers/ldap/ldap_opts.h
@@ -137,6 +137,7 @@ struct sdap_attr_map rfc2307_user_map[] = {
     { "ldap_user_member_of", NULL, SYSDB_MEMBEROF, NULL },
     { "ldap_user_uuid", NULL, SYSDB_UUID, NULL },
     { "ldap_user_objectsid", NULL, SYSDB_SID, NULL },
+    { "ldap_user_primary_group", NULL, SYSDB_PRIMARY_GROUP, NULL },
     { "ldap_user_modify_timestamp", "modifyTimestamp", SYSDB_ORIG_MODSTAMP, NULL },
     { "ldap_user_entry_usn", NULL, SYSDB_USN, NULL },
     { "ldap_user_shadow_last_change", "shadowLastChange", SYSDB_SHADOWPW_LASTCHANGE, NULL },
@@ -189,6 +190,7 @@ struct sdap_attr_map rfc2307bis_user_map[] = {
     /* FIXME: this is 389ds specific */
     { "ldap_user_uuid", "nsUniqueId", SYSDB_UUID, NULL },
     { "ldap_user_objectsid", NULL, SYSDB_SID, NULL },
+    { "ldap_user_primary_group", NULL, SYSDB_PRIMARY_GROUP, NULL },
     { "ldap_user_modify_timestamp", "modifyTimestamp", SYSDB_ORIG_MODSTAMP, NULL },
     { "ldap_user_entry_usn", NULL, SYSDB_USN, NULL },
     { "ldap_user_shadow_last_change", "shadowLastChange", SYSDB_SHADOWPW_LASTCHANGE, NULL },
@@ -241,6 +243,7 @@ struct sdap_attr_map ad2008r2_user_map[] = {
     { "ldap_user_member_of", "memberOf", SYSDB_MEMBEROF, NULL },
     { "ldap_user_uuid", "objectGUID", SYSDB_UUID, NULL },
     { "ldap_user_objectsid", "objectSID", SYSDB_SID, NULL },
+    { "ldap_user_primary_group", "primaryGroupID", SYSDB_PRIMARY_GROUP, NULL },
     { "ldap_user_modify_timestamp", "whenChanged", SYSDB_ORIG_MODSTAMP, NULL },
     { "ldap_user_entry_usn", SDAP_AD_USN, SYSDB_USN, NULL },
     { "ldap_user_shadow_last_change", NULL, SYSDB_SHADOWPW_LASTCHANGE, NULL },
diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
index 2de4a5cb978d93c0430e07eb2e72d46a7b5ab3b7..ba19cbabe75cd365bfb2dd59a3ea3377fe7d21e1 100644
--- a/src/providers/ldap/sdap.h
+++ b/src/providers/ldap/sdap.h
@@ -244,6 +244,7 @@ enum sdap_user_attrs {
     SDAP_AT_USER_MEMBEROF,
     SDAP_AT_USER_UUID,
     SDAP_AT_USER_OBJECTSID,
+    SDAP_AT_USER_PRIMARY_GROUP,
     SDAP_AT_USER_MODSTAMP,
     SDAP_AT_USER_USN,
     SDAP_AT_SP_LSTCHG,
diff --git a/src/providers/ldap/sdap_async_users.c b/src/providers/ldap/sdap_async_users.c
index 9aa09da9830d3b1f695ec7da7486138bf2698266..c6534993a43391aee8136292e2a9f1c1686390bd 100644
--- a/src/providers/ldap/sdap_async_users.c
+++ b/src/providers/ldap/sdap_async_users.c
@@ -47,7 +47,7 @@ int sdap_save_user(TALLOC_CTX *memctx,
     const char *homedir;
     const char *shell;
     uid_t uid;
-    gid_t gid;
+    gid_t gid, primary_gid;
     struct sysdb_attrs *user_attrs;
     char *upn = NULL;
     size_t i;
@@ -58,7 +58,8 @@ int sdap_save_user(TALLOC_CTX *memctx,
     bool use_id_mapping = dp_opt_get_bool(opts->basic, SDAP_ID_MAPPING);
     struct dom_sid *dom_sid;
     char *sid_str;
-    char *dom_sid_str;
+    char *dom_sid_str = NULL;
+    char *group_sid_str;
     enum idmap_error_code err;
 
     DEBUG(9, ("Save user\n"));
@@ -126,9 +127,9 @@ int sdap_save_user(TALLOC_CTX *memctx,
                                  &el);
         if (ret != EOK || el->num_values != 1) {
             DEBUG(SSSDBG_MINOR_FAILURE,
-                  ("No [%s] attribute for user [%s] while id-mapping\n",
+                  ("No [%s] attribute for user [%s] while id-mapping. [%d][%s]\n",
                    opts->user_map[SDAP_AT_USER_OBJECTSID].name,
-                   name));
+                   name, el->num_values, strerror(ret)));
             goto fail;
         }
 
@@ -213,14 +214,65 @@ int sdap_save_user(TALLOC_CTX *memctx,
         goto fail;
     }
 
-    ret = sysdb_attrs_get_uint32_t(attrs,
-                                   opts->user_map[SDAP_AT_USER_GID].sys_name,
-                                   &gid);
-    if (ret != EOK) {
-        DEBUG(1, ("no gid provided for [%s] in domain [%s].\n",
-                  name, dom->name));
-        ret = EINVAL;
-        goto fail;
+    if (use_id_mapping) {
+        ret = sysdb_attrs_get_uint32_t(
+                attrs,
+                opts->user_map[SDAP_AT_USER_PRIMARY_GROUP].sys_name,
+                &primary_gid);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_MINOR_FAILURE,
+                  ("no primary group ID provided for [%s] in domain [%s].\n",
+                   name, dom->name));
+            ret = EINVAL;
+            goto fail;
+        }
+
+        /* The primary group ID is just the RID part of the objectSID
+         * of the group. Generate the GID by adding this to the domain
+         * SID value.
+         */
+
+        /* First, get the domain SID if we didn't do so above */
+        if (!dom_sid_str) {
+            ret = sdap_idmap_get_dom_sid_from_object(tmpctx, sid_str,
+                                                     &dom_sid_str);
+            if (ret != EOK) {
+                DEBUG(SSSDBG_MINOR_FAILURE,
+                      ("Could not parse domain SID from [%s]\n", sid_str));
+                goto fail;
+            }
+        }
+
+        /* Add the RID to the end */
+        group_sid_str = talloc_asprintf(tmpctx, "%s-%lu",
+                                        dom_sid_str,
+                                        (unsigned long)primary_gid);
+        if (!group_sid_str) {
+            ret = ENOMEM;
+            goto fail;
+        }
+
+        /* Convert the SID into a UNIX group ID */
+        err = sss_idmap_sid_to_unix(opts->idmap_ctx->map,
+                                    group_sid_str,
+                                    (uint32_t *)&gid);
+        if (err != IDMAP_SUCCESS) {
+            DEBUG(SSSDBG_MINOR_FAILURE,
+                  ("Could not convert objectSID [%s] to a UNIX ID\n",
+                   group_sid_str));
+            ret = EIO;
+            goto fail;
+        }
+    } else {
+        ret = sysdb_attrs_get_uint32_t(attrs,
+                                       opts->user_map[SDAP_AT_USER_GID].sys_name,
+                                       &gid);
+        if (ret != EOK) {
+            DEBUG(1, ("no gid provided for [%s] in domain [%s].\n",
+                      name, dom->name));
+            ret = EINVAL;
+            goto fail;
+        }
     }
 
     /* check that the gid is valid for this domain */
-- 
1.7.10

