From 6dc3bcd1558179569063f78a759c6c6d1b100aa9 Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <sgallagh@redhat.com>
Date: Wed, 16 Mar 2011 12:35:27 -0400
Subject: [PATCH 3/5] Handle multi-valued usernames correctly

Users in ldap with multiple values for their username attribute
will now be compared against the RDN of the entry to determine the
"primary" username. We will save all of the alternate names to the
ldb cache as well, so a lookup for any of them will return the
values for the primary name.

e.g.
getent passwd altusername
primaryuser:*:800014:800014:primaryuser:/home/primaryuser:/bin/sh
---
 src/providers/ldap/sdap_async_accounts.c |   59 ++++++++++++++++++++++--------
 1 files changed, 44 insertions(+), 15 deletions(-)

diff --git a/src/providers/ldap/sdap_async_accounts.c b/src/providers/ldap/sdap_async_accounts.c
index 3fedf07da7fbdc9409f5360ba8301158a65014cd..71c25c883fbaf03becbbe9804865ba0ac7cc7513 100644
--- a/src/providers/ldap/sdap_async_accounts.c
+++ b/src/providers/ldap/sdap_async_accounts.c
@@ -40,7 +40,7 @@ static int sdap_save_user(TALLOC_CTX *memctx,
 {
     struct ldb_message_element *el;
     int ret;
-    const char *name;
+    const char *name = NULL;
     const char *pwd;
     const char *gecos;
     const char *homedir;
@@ -49,15 +49,28 @@ static int sdap_save_user(TALLOC_CTX *memctx,
     gid_t gid;
     struct sysdb_attrs *user_attrs;
     char *upn = NULL;
-    int i;
+    size_t i;
     char *val = NULL;
     int cache_timeout;
     char *usn_value = NULL;
     size_t c;
     char **missing = NULL;
+    TALLOC_CTX *tmpctx = NULL;
 
     DEBUG(9, ("Save user\n"));
 
+    tmpctx = talloc_new(memctx);
+    if (!tmpctx) {
+        ret = ENOMEM;
+        goto fail;
+    }
+
+    user_attrs = sysdb_new_attrs(tmpctx);
+    if (user_attrs == NULL) {
+        ret = ENOMEM;
+        goto fail;
+    }
+
     ret = sysdb_attrs_get_el(attrs,
                              opts->user_map[SDAP_AT_USER_NAME].sys_name, &el);
     if (el->num_values == 0) {
@@ -65,9 +78,13 @@ static int sdap_save_user(TALLOC_CTX *memctx,
     }
     if (ret) {
         DEBUG(1, ("Failed to save the user - entry has no name attribute\n"));
-        return ret;
+        goto fail;
+    }
+
+    ret = sysdb_attrs_primary_name(ctx, attrs, el, &name);
+    if (ret != EOK) {
+        goto fail;
     }
-    name = (const char *)el->values[0].data;
 
     ret = sysdb_attrs_get_el(attrs,
                              opts->user_map[SDAP_AT_USER_PWD].sys_name, &el);
@@ -129,12 +146,6 @@ static int sdap_save_user(TALLOC_CTX *memctx,
         goto fail;
     }
 
-    user_attrs = sysdb_new_attrs(memctx);
-    if (user_attrs == NULL) {
-        ret = ENOMEM;
-        goto fail;
-    }
-
     ret = sysdb_attrs_get_el(attrs, SYSDB_ORIG_DN, &el);
     if (ret) {
         goto fail;
@@ -151,6 +162,22 @@ static int sdap_save_user(TALLOC_CTX *memctx,
         }
     }
 
+    /* Save alternate names */
+    ret = sysdb_attrs_get_el(attrs, SYSDB_NAME, &el);
+    if (ret != EOK) {
+        goto fail;
+    }
+
+    for(i = 0; i < el->num_values; i++) {
+        DEBUG(7, ("Adding alternate name [%s] to attributes of [%s]\n",
+                  el->values[i].data, name));
+        ret = sysdb_attrs_add_string(user_attrs, SYSDB_NAME,
+                                     (const char *)el->values[i].data);
+        if (ret != EOK) {
+            goto fail;
+        }
+    }
+
     ret = sysdb_attrs_get_el(attrs, SYSDB_MEMBEROF, &el);
     if (ret) {
         goto fail;
@@ -271,7 +298,7 @@ static int sdap_save_user(TALLOC_CTX *memctx,
     /* Make sure that any attributes we requested from LDAP that we
      * did not receive are also removed from the sysdb
      */
-    ret = list_missing_attrs(NULL, opts->user_map, SDAP_OPTS_USER,
+    ret = list_missing_attrs(user_attrs, opts->user_map, SDAP_OPTS_USER,
                              ldap_attrs, attrs, &missing);
     if (ret != EOK) {
         goto fail;
@@ -285,21 +312,23 @@ static int sdap_save_user(TALLOC_CTX *memctx,
 
     DEBUG(6, ("Storing info for user %s\n", name));
 
-    ret = sysdb_store_user(memctx, ctx, dom,
+    ret = sysdb_store_user(user_attrs, ctx, dom,
                            name, pwd, uid, gid, gecos, homedir, shell,
                            user_attrs, missing, cache_timeout);
     if (ret) goto fail;
-    talloc_zfree(missing);
 
     if (_usn_value) {
         *_usn_value = usn_value;
     }
 
+    talloc_steal(memctx, user_attrs);
+    talloc_free(tmpctx);
     return EOK;
 
 fail:
-    DEBUG(2, ("Failed to save user %s\n", name));
-    talloc_free(missing);
+    DEBUG(2, ("Failed to save user [%s]\n",
+              name ? name : "Unknown"));
+    talloc_free(tmpctx);
     return ret;
 }
 
-- 
1.7.4

