[SSSD] [PATCH] Ability to set a domain as case sensitive or insensitive

Jakub Hrozek jhrozek at redhat.com
Tue Dec 13 13:44:43 UTC 2011


On Mon, Dec 12, 2011 at 08:40:26AM +0100, Jan Zeleny wrote:
> Jakub Hrozek <jhrozek at redhat.com> wrote:
> > On Fri, Dec 09, 2011 at 03:18:38PM +0100, Jan Zelený wrote:
> > > > On Thu, Dec 08, 2011 at 11:02:05AM +0100, Jakub Hrozek wrote:
> > > > > [PATCH 1/6] sss_utf8_tolower utility function+unit tests
> > > > > This will be used later on to lowercase the usernames. Also includes
> > > > > unit tests for the whole sss_utf8 module.
> > > 
> > > Nack, it seems that this patch breaks the test suite (or perhaps it's the
> > > last one, I'm not 100% sure.
> > 
> > I ran "make check" in-tree and didn't see any error, but I think I see
> > the bug now.
> > 
> > The root cause was that I included sss_tc_utf8_tolower() into util.c which
> > made it depend on sss_utf8.c and by extension on the UTF8 library of
> > choice. At the same time the memberof plugin depends on util.c so we would
> > had linked the plugin with the UTF8 library.
> > 
> > I decided to include the talloc wrapper in a new module "sss_tc_utf8.c"
> > -- I think a module with a single function is a lesser evil than linking
> > the whole memberof module with an UTF8 library (which might be even GLib..)
> > 
> > A revised patch is attached.
> 
> Everything works fine now, thanks for fixing that. Also, as you said, the 
> approach is much better I think. Ack
> 
> > > > > [PATCH 2/6] Responders: Split getting domain by name into separate
> > > > > function A utility function originally written for the SUDO
> > > > > responder, but it turns out it's useful earlier
> > > 
> > > Ack
> > > 
> > > > > [PATCH 3/6] Use the case sensitivity flag in responders
> > > > > Reads the configuration option and includes its handling in the
> > > > > responders.
> > > > > Unfortunately some parts like negative cache are more complex because
> > > > > one domain can be case sensitive and another insensitive during
> > > > > multidomain searches.
> > > 
> > > Nack,
> > > why are you using talloc strdup in functions like
> > > nss_cmd_getgrnam_search? I mean talloc_strdup(dctx, cmdctx->name). I
> > > suspect it's for better consistency with behavior of the
> > > sss_tc_utf8_tolower() but there is no real need for it IMO.
> > 
> > To be able to free the domain-specific name inside the domain loop which
> > I forgot to do in the first iteration of patches.
> > 
> > I changed the patch to free "name" on every iteration to avoid clinging
> > to allocated memory.
> 
> Now it makes sense, thanks. Please check those free() calls on lines 637, 675 
> and 793 of the patch. Do I miss something or should there be name as their 
> argument instead of NULL?
> 

That's..an embarassing bug. I was trying to remember to initialize the
pointer to NULL and this came out.

> > > The pd_set_primary_name() doesn't seem like a part of the patch, or is
> > > it?
> > >
> > >I'd
> > >
> > > prefer separate patch for it and places where it is used. I'm also
> > > thinking whether or not should it also detect the case_sensitive flag.
> > 
> > The reasoning begind pd_set_primary_name() is username canonicalization.
> > 
> > sysdb_getpwnam() can return data based on both the real name or the
> > lowercased alias, because the filter it uses matches both "name" and
> > "nameAlias".  Only "name" corresponds to RDN, though. On many places,
> > including auth and access, SSSD depends on searching "user by name" by
> > constructing a user DN based on the username and domain name,.
> > 
> > There is no need to pass the case_sensitive flag, strcmp is already case
> > sensitive and the name we search with is lowercased in the previous
> > hunk if case_sensitive is true.
> 
> I'm not saying that the function is useless or anything, I understand its 
> purpose very well. I'm just saying that it should probably have its own patch. 
> Of course, I don't insist on it.

Splitted.

> 
> > > > > [PATCH 4/6] Refactor saving sdap entities
> > > > > There was too much code duplication between
> > > > > sdap_save_{user,group,netgroup} and my later patch would add even
> > > > > more. This patch removes the most egregious cases.
> > > 
> > > Nack,
> > > I think that the "multivalued" argument is really not necessary, is it?
> > > Without it, there is also no need for those two wrapper macros.
> > 
> > It's actually required to maintain the same behaviour as the original code.
> 
> Ah, ok. I didn't see that use case, sorry for the fuss.
> 
> > In some cases such as when storing modifyTimestamp we would only store
> > the first value unconditionally even if the attribute was multivalued on
> > the server. This is the case for both original and refactored code.
> > 
> > I haven't used the macro for storing all string attributes. Some attributes
> > like ldap_user_principal are munged before saving to sysdb and that's
> > difficult to generalize withut some kind of callback, but still, only the
> > first value is saved even if the original attribute was multivalued.
> > 
> > Is there any value in throwing an error like we do with the POSIX set
> > of attributes?
> 
> I think a DEBUG, let's say on SSSDBG_MINOR_FAILURE should be enough. In case 
> the attribute is trimmed, it is important to know that this happened.
> 
> > > I noticed that at one place, there was strdup() called before adding the
> > > string to sysdb_attrs. I didn't inspect this much further, so my question
> > > is whether it would make any sense to do that in
> > > sdap_attrs_add_ldap_attr() and sdap_save_all_names()?
> > 
> > Which strdup was that? At one place isn't really descriptive.
> 
> The place isn't really important, the idea counts ;-) Anyway, there is only 
> one such place in the code in question: sdap_async_users.c:202
> 
> I think it's safe to discard the strup there but as I said, I haven't 
> inspected this extensively.
> 
> > I haven't touched the cases where we need to pass the attribute values out
> > (like USN), the other cases were duping the value on user_attrs which is
> > allocated on tmpctx and never stolen or moved elsewhere.
> > 
> > > > > [PATCH 5/6] Use the case sensitivity flag in the LDAP provider
> > > > > When saving users,groups and netgroups, saves the lowercase version
> > > > > of the name as an alias in addition to the original name that is
> > > > > still stored as name as well as part of RDN.
> > > 
> > > Nack,
> > > I don't think there is a need for aliases to be both in the list both
> > > untransformed and in lowercase. Please check that and if it isn't
> > > necessary, please remove it.
> > 
> > If the duplicate lowercase attribute is removed, aliases wouldn't work
> > if the user switches the case sensitivity flag of a domain from false to
> > true (because only secondaryname would be stored and client might ask for
> > secondaryName as stored on server).
> > 
> > An extra sysdb attribute is not much harm, really.
> 
> Ok, no problem. If it has its purpose, I have no problem with it.
> 
> > 
> > > Variable lowername in sdap_save_all_names() is not used. Also instead of
> > > argument "dom", I would prefer "case_sensitive" being directly given to
> > > the sdap_save_all_names().
> > 
> > Thanks, fixed.
> > 
> > > > > [PATCH 6/6] Use the case sensitivity flag in the simple access
> > > > > provider Performs string comparisons in case sensitive or
> > > > > insensitive manner depending on the configuration.
> > > 
> > > Ack
> > > 
> > > Jan
> > 
> > It seems that there are no issues with the general approach so I will
> > file a ticket to handle LOCAL provider (which will probably get deferred)
> > and prepare another patch to handle the proxy provider.
> 
> Agreed.

A new patch to handle the proxy provider is attached and the lack of
support in the LOCAL domain is mentioned in the docs.

https://fedorahosted.org/sssd/ticket/1104 is tracking the support in
local domain now.
-------------- next part --------------
From 9c39ae340bf5607563d1a12d624ac281c844f936 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Tue, 6 Dec 2011 14:57:58 +0100
Subject: [PATCH 1/9] sss_utf8_tolower utility function+unit tests

---
 Makefile.am                            |    3 +-
 src/tests/util-tests.c                 |   72 ++++++++++++++++++++++++++++++++
 src/util/{sss_utf8.h => sss_tc_utf8.c} |   34 ++++++---------
 src/util/sss_utf8.c                    |   38 +++++++++++++++++
 src/util/sss_utf8.h                    |    5 ++
 src/util/util.c                        |    1 +
 src/util/util.h                        |    4 ++
 7 files changed, 136 insertions(+), 21 deletions(-)
 copy src/util/{sss_utf8.h => sss_tc_utf8.c} (63%)

diff --git a/Makefile.am b/Makefile.am
index 8d75b8767bd30532f9a241ca1518545d602beffb..b8fb9e094c57c1c1ddbc51d10232ea64236e813a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -382,7 +382,8 @@ libsss_util_la_SOURCES = \
     src/util/strtonum.c \
     src/util/check_and_open.c \
     src/util/refcount.c \
-    src/util/sss_utf8.c
+    src/util/sss_utf8.c \
+    src/util/sss_tc_utf8.c
 libsss_util_la_LIBADD = \
     $(SSSD_LIBS) \
     $(UNICODE_LIBS) \
diff --git a/src/tests/util-tests.c b/src/tests/util-tests.c
index 52d302778ed3c819d3ffeef96e7b52c778a15825..d0636651f1abecb10240927aa2a011841e74447b 100644
--- a/src/tests/util-tests.c
+++ b/src/tests/util-tests.c
@@ -26,6 +26,7 @@
 #include <talloc.h>
 #include <check.h>
 #include "util/util.h"
+#include "util/sss_utf8.h"
 #include "tests/common.h"
 
 START_TEST(test_parse_args)
@@ -312,6 +313,68 @@ START_TEST(test_size_t_overflow)
 }
 END_TEST
 
+START_TEST(test_utf8_lowercase)
+{
+    const uint8_t munchen_utf8_upcase[] = { 'M', 0xC3, 0x9C, 'N', 'C', 'H', 'E', 'N', 0x0 };
+    const uint8_t munchen_utf8_lowcase[] = { 'm', 0xC3, 0xBC, 'n', 'c', 'h', 'e', 'n', 0x0 };
+    uint8_t *lcase;
+
+    lcase = sss_utf8_tolower(munchen_utf8_upcase);
+    fail_if(memcmp(lcase, munchen_utf8_lowcase, strlen((const char *) lcase)));
+    sss_utf8_free(lcase);
+}
+END_TEST
+
+START_TEST(test_utf8_talloc_lowercase)
+{
+    const uint8_t munchen_utf8_upcase[] = { 'M', 0xC3, 0x9C, 'N', 'C', 'H', 'E', 'N', 0x0 };
+    const uint8_t munchen_utf8_lowcase[] = { 'm', 0xC3, 0xBC, 'n', 'c', 'h', 'e', 'n', 0x0 };
+    char *lcase;
+
+    TALLOC_CTX *test_ctx;
+    test_ctx = talloc_new(NULL);
+    fail_if(test_ctx == NULL);
+
+    lcase = sss_tc_utf8_tolower(test_ctx, (const char *) munchen_utf8_upcase);
+    fail_if(memcmp(lcase, munchen_utf8_lowcase, strlen((const char *) lcase)));
+    talloc_free(test_ctx);
+}
+END_TEST
+
+START_TEST(test_utf8_caseeq)
+{
+    const uint8_t munchen_utf8_upcase[] = { 'M', 0xC3, 0x9C, 'N', 'C', 'H', 'E', 'N', 0x0 };
+    const uint8_t munchen_utf8_lowcase[] = { 'm', 0xC3, 0xBC, 'n', 'c', 'h', 'e', 'n', 0x0 };
+    const uint8_t czech_utf8_lowcase[] = { 0xC4, 0x8D, 'e', 'c', 'h', 0x0 };
+    const uint8_t czech_utf8_upcase[] = { 0xC4, 0x8C, 'e', 'c', 'h', 0x0 };
+    const uint8_t czech_utf8_lowcase_neg[] = { 0xC4, 0x8E, 'e', 'c', 'h', 0x0 };
+    errno_t ret;
+
+    ret = sss_utf8_case_eq(munchen_utf8_upcase, munchen_utf8_lowcase);
+    fail_unless(ret == EOK, "Latin 1 Supplement comparison failed\n");
+
+    ret = sss_utf8_case_eq(czech_utf8_upcase, czech_utf8_lowcase);
+    fail_unless(ret == EOK, "Latin Extended A comparison failed\n");
+
+    ret = sss_utf8_case_eq(czech_utf8_upcase, czech_utf8_lowcase_neg);
+    fail_if(ret == EOK, "Negative test succeeded\n");
+}
+END_TEST
+
+START_TEST(test_utf8_check)
+{
+    const char *invalid = "ad\351la\357d";
+    const uint8_t valid[] = { 'M', 0xC3, 0x9C, 'N', 'C', 'H', 'E', 'N', 0x0 };
+    bool ret;
+
+    ret = sss_utf8_check(valid, strlen((const char *) valid));
+    fail_unless(ret == true, "Positive test failed\n");
+
+    ret = sss_utf8_check((const uint8_t *) invalid, strlen(invalid));
+    fail_unless(ret == false, "Negative test succeeded\n");
+}
+END_TEST
+
 Suite *util_suite(void)
 {
     Suite *s = suite_create("util");
@@ -324,7 +387,16 @@ Suite *util_suite(void)
     tcase_add_test (tc_util, test_parse_args);
     tcase_set_timeout(tc_util, 60);
 
+    TCase *tc_utf8 = tcase_create("utf8");
+    tcase_add_test (tc_util, test_utf8_lowercase);
+    tcase_add_test (tc_util, test_utf8_talloc_lowercase);
+    tcase_add_test (tc_util, test_utf8_caseeq);
+    tcase_add_test (tc_util, test_utf8_check);
+
+    tcase_set_timeout(tc_utf8, 60);
+
     suite_add_tcase (s, tc_util);
+    suite_add_tcase (s, tc_utf8);
 
     return s;
 }
diff --git a/src/util/sss_utf8.h b/src/util/sss_tc_utf8.c
similarity index 63%
copy from src/util/sss_utf8.h
copy to src/util/sss_tc_utf8.c
index 37dcff959b1a86110fba919082b075c7f4963f02..28d4f3f18fbb9c38412d6aac34a05c2d09fc33d7 100644
--- a/src/util/sss_utf8.h
+++ b/src/util/sss_tc_utf8.c
@@ -1,8 +1,6 @@
 /*
-    SSSD
-
     Authors:
-        Stephen Gallagher <sgallagh at redhat.com>
+        Jakub Hrozek <jhrozek at redhat.com>
 
     Copyright (C) 2011 Red Hat
 
@@ -20,24 +18,20 @@
     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-#ifndef SSS_UTF8_H_
-#define SSS_UTF8_H_
+#include <talloc.h>
+#include "util/sss_utf8.h"
 
-#ifdef HAVE_LIBUNISTRING
-#include <unistr.h>
-#include <unicase.h>
-#elif HAVE_GLIB2
-#include <glib.h>
-#endif
-#include "util/util.h"
+char *
+sss_tc_utf8_tolower(TALLOC_CTX *mem_ctx, const char *s)
+{
+    uint8_t *lower;
+    char *ret;
 
-#ifndef ENOMATCH
-#define ENOMATCH -1
-#endif
+    lower = sss_utf8_tolower((const uint8_t *) s);
+    if (!lower) return NULL;
 
-bool sss_utf8_check(const uint8_t *s, size_t n);
+    ret = talloc_strdup(mem_ctx, (const char *) lower);
+    sss_utf8_free(lower);
+    return ret;
+}
 
-errno_t sss_utf8_case_eq(const uint8_t *s1, const uint8_t *s2);
-
-
-#endif /* SSS_UTF8_H_ */
diff --git a/src/util/sss_utf8.c b/src/util/sss_utf8.c
index 4a98233bb97bbfc77a60bba6a24ef04bf78bfa56..82487683110cb371b998e5cccbcc4352fbed50a4 100644
--- a/src/util/sss_utf8.c
+++ b/src/util/sss_utf8.c
@@ -24,6 +24,44 @@
 #include "sss_utf8.h"
 
 #ifdef HAVE_LIBUNISTRING
+void sss_utf8_free(void *ptr)
+{
+    return free(ptr);
+}
+#elif HAVE_GLIB2
+void sss_utf8_free(void *ptr)
+{
+    return g_free(ptr);
+}
+#else
+#error No unicode library
+#endif
+
+#ifdef HAVE_LIBUNISTRING
+uint8_t *sss_utf8_tolower(const uint8_t *s)
+{
+    size_t llen;
+    uint8_t *lower;
+
+    lower = u8_tolower(s, u8_strlen(s), NULL, NULL, NULL, &llen);
+    if (!lower) return NULL;
+
+    lower = realloc(lower, sizeof(uint8_t) * (llen+1));
+    if (!lower) return NULL;
+
+    lower[llen] = '\0';
+    return lower;
+}
+#elif HAVE_GLIB2
+uint8_t *sss_utf8_tolower(const uint8_t *s)
+{
+    return (uint8_t *) g_utf8_strdown((const gchar *) s, -1);
+}
+#else
+#error No unicode library
+#endif
+
+#ifdef HAVE_LIBUNISTRING
 bool sss_utf8_check(const uint8_t *s, size_t n)
 {
     if (u8_check(s, n) == NULL) {
diff --git a/src/util/sss_utf8.h b/src/util/sss_utf8.h
index 37dcff959b1a86110fba919082b075c7f4963f02..7be54d69b1ca347dd477d6b68cf5eb8af85c4c46 100644
--- a/src/util/sss_utf8.h
+++ b/src/util/sss_utf8.h
@@ -35,6 +35,11 @@
 #define ENOMATCH -1
 #endif
 
+void sss_utf8_free(void *ptr);
+
+/* The result must be freed with sss_utf8_free() */
+uint8_t *sss_utf8_tolower(const uint8_t *s);
+
 bool sss_utf8_check(const uint8_t *s, size_t n);
 
 errno_t sss_utf8_case_eq(const uint8_t *s1, const uint8_t *s2);
diff --git a/src/util/util.c b/src/util/util.c
index b4b1b124317377fe22612576e8e2d8d3256c14ce..f525c915b6886f8f0e51f0026831e6301c2df8ff 100644
--- a/src/util/util.c
+++ b/src/util/util.c
@@ -23,6 +23,7 @@
 
 #include "talloc.h"
 #include "util/util.h"
+#include "util/sss_utf8.h"
 #include "dhash.h"
 
 /* split a string into an allocated array of strings.
diff --git a/src/util/util.h b/src/util/util.h
index 9a00647179b010f7dd1b9744b3aaa013cc6e5769..00fb67d3800c33b1949441e6da4a36de64ed5671 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -502,4 +502,8 @@ errno_t sss_filter_sanitize(TALLOC_CTX *mem_ctx,
 char *
 sss_escape_ip_address(TALLOC_CTX *mem_ctx, int family, const char *addr);
 
+/* from sss_tc_utf8.c */
+char *
+sss_tc_utf8_tolower(TALLOC_CTX *mem_ctx, const char *s);
+
 #endif /* __SSSD_UTIL_H__ */
-- 
1.7.7.4

-------------- next part --------------
From 7193ce8c8071786725b3e4094f1ebbb4dc9e9e79 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Mon, 5 Dec 2011 16:00:44 +0100
Subject: [PATCH 2/9] Responders: Split getting domain by name into separate
 function

---
 src/responder/common/responder.h        |    2 ++
 src/responder/common/responder_common.c |   13 +++++++++++++
 src/responder/nss/nsssrv_cmd.c          |   19 +++----------------
 src/responder/nss/nsssrv_netgroup.c     |    2 +-
 src/responder/pam/pamsrv_cmd.c          |    7 ++-----
 5 files changed, 21 insertions(+), 22 deletions(-)

diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h
index 3b5ab8a42136c17f0f71a202f8ae9367edfa6afb..f6784e916bbf2b7f191d2a53b6670c2a29adb996 100644
--- a/src/responder/common/responder.h
+++ b/src/responder/common/responder.h
@@ -150,6 +150,8 @@ int sss_parse_name(TALLOC_CTX *memctx,
 
 int sss_dp_get_domain_conn(struct resp_ctx *rctx, const char *domain,
                            struct be_conn **_conn);
+struct sss_domain_info *
+responder_get_domain(struct sss_domain_info *doms, const char *domain);
 
 /* responder_cmd.c */
 int sss_cmd_execute(struct cli_ctx *cctx, struct sss_cmd_table *sss_cmds);
diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c
index 1b28a92ef6c6569a52aecf37a4e37a1c7af95de1..99b1a23aa8581e01fb2a02d36657df6c20717812 100644
--- a/src/responder/common/responder_common.c
+++ b/src/responder/common/responder_common.c
@@ -624,6 +624,19 @@ int sss_dp_get_domain_conn(struct resp_ctx *rctx, const char *domain,
     return EOK;
 }
 
+struct sss_domain_info *
+responder_get_domain(struct sss_domain_info *doms, const char *domain)
+{
+    struct sss_domain_info *dom;
+
+    for (dom = doms; dom; dom = dom->next) {
+        if (strcasecmp(dom->name, domain) == 0) break;
+    }
+    if (!dom) DEBUG(SSSDBG_CRIT_FAILURE, ("Unknown domain [%s]!\n", domain));
+
+    return dom;
+}
+
 int responder_logrotate(DBusMessage *message,
                         struct sbus_connection *conn)
 {
diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
index 720813fda1efb0004b6add4fdcfa01156f1c3f12..f0270acd26659e8005a043fd9e154723cc868d0d 100644
--- a/src/responder/nss/nsssrv_cmd.c
+++ b/src/responder/nss/nsssrv_cmd.c
@@ -45,19 +45,6 @@ static int nss_cmd_send_error(struct nss_cmd_ctx *cmdctx, int err)
     return EOK;
 }
 
-struct sss_domain_info *nss_get_dom(struct sss_domain_info *doms,
-                                    const char *domain)
-{
-    struct sss_domain_info *dom;
-
-    for (dom = doms; dom; dom = dom->next) {
-        if (strcasecmp(dom->name, domain) == 0) break;
-    }
-    if (!dom) DEBUG(2, ("Unknown domain [%s]!\n", domain));
-
-    return dom;
-}
-
 int fill_empty(struct sss_packet *packet)
 {
     uint8_t *body;
@@ -932,7 +919,7 @@ static int nss_cmd_getpwnam(struct cli_ctx *cctx)
               cmdctx->name, domname?domname:"<ALL>"));
 
     if (domname) {
-        dctx->domain = nss_get_dom(cctx->rctx->domains, domname);
+        dctx->domain = responder_get_domain(cctx->rctx->domains, domname);
         if (!dctx->domain) {
             ret = ENOENT;
             goto done;
@@ -2219,7 +2206,7 @@ static int nss_cmd_getgrnam(struct cli_ctx *cctx)
               cmdctx->name, domname?domname:"<ALL>"));
 
     if (domname) {
-        dctx->domain = nss_get_dom(cctx->rctx->domains, domname);
+        dctx->domain = responder_get_domain(cctx->rctx->domains, domname);
         if (!dctx->domain) {
             ret = ENOENT;
             goto done;
@@ -3277,7 +3264,7 @@ static int nss_cmd_initgroups(struct cli_ctx *cctx)
               cmdctx->name, domname?domname:"<ALL>"));
 
     if (domname) {
-        dctx->domain = nss_get_dom(cctx->rctx->domains, domname);
+        dctx->domain = responder_get_domain(cctx->rctx->domains, domname);
         if (!dctx->domain) {
             ret = ENOENT;
             goto done;
diff --git a/src/responder/nss/nsssrv_netgroup.c b/src/responder/nss/nsssrv_netgroup.c
index 189f852485053307698720e27463456d1f97eac3..09b7fa6355421c941631775c71d33a2851edbe4e 100644
--- a/src/responder/nss/nsssrv_netgroup.c
+++ b/src/responder/nss/nsssrv_netgroup.c
@@ -204,7 +204,7 @@ static struct tevent_req *setnetgrent_send(TALLOC_CTX *mem_ctx,
               state->netgr_shortname, domname?domname:"<ALL>"));
 
     if (domname) {
-        dctx->domain = nss_get_dom(client->rctx->domains, domname);
+        dctx->domain = responder_get_domain(client->rctx->domains, domname);
         if (!dctx->domain) {
             goto error;
         }
diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c
index 40df755d6af7e83d51c923f75bd0c19e4e7044de..5f77697fd33779d9cb48f993d7a8368cef8b3928 100644
--- a/src/responder/pam/pamsrv_cmd.c
+++ b/src/responder/pam/pamsrv_cmd.c
@@ -756,14 +756,11 @@ static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd)
 
     /* now check user is valid */
     if (pd->domain) {
-        for (dom = cctx->rctx->domains; dom; dom = dom->next) {
-            if (strcasecmp(dom->name, pd->domain) == 0) break;
-        }
-        if (!dom) {
+        preq->domain = responder_get_domain(cctx->rctx->domains, pd->domain);
+        if (preq->domain) {
             ret = ENOENT;
             goto done;
         }
-        preq->domain = dom;
     }
     else {
         for (dom = preq->cctx->rctx->domains; dom; dom = dom->next) {
-- 
1.7.7.4

-------------- next part --------------
From 52fea33434312e4375cb90ca210358391d444c15 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Mon, 12 Dec 2011 16:35:53 +0100
Subject: [PATCH 3/9] Canonicalize username in PAM provider

---
 src/responder/pam/pamsrv_cmd.c |   26 ++++++++++++++++++++++++++
 1 files changed, 26 insertions(+), 0 deletions(-)

diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c
index 5f77697fd33779d9cb48f993d7a8368cef8b3928..14251389dadd4408adc78d5c28b9ccf85fda7f8d 100644
--- a/src/responder/pam/pamsrv_cmd.c
+++ b/src/responder/pam/pamsrv_cmd.c
@@ -93,6 +93,25 @@ static int extract_uint32_t(uint32_t *var, size_t size, uint8_t *body,
     return EOK;
 }
 
+static int pd_set_primary_name(const struct ldb_message *msg,struct pam_data *pd)
+{
+    const char *name;
+
+    name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
+    if (!name) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("A user with no name?\n"));
+        return EIO;
+    }
+
+    if (strcmp(pd->user, name)) {
+        DEBUG(SSSDBG_TRACE_FUNC, ("User's primary name is %s\n", name));
+        pd->user = talloc_strdup(pd, name);
+        if (!pd->user) return ENOMEM;
+    }
+
+    return EOK;
+}
+
 static int pam_parse_in_data_v2(struct sss_names_ctx *snctx,
                              struct pam_data *pd,
                              uint8_t *body, size_t blen)
@@ -890,6 +909,13 @@ static int pam_check_user_search(struct pam_auth_req *preq)
 
         DEBUG(6, ("Returning info for user [%s@%s]\n", name, dom->name));
 
+        /* We might have searched by alias. Pass on the primary name */
+        ret = pd_set_primary_name(preq->res->msgs[0], preq->pd);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_CRIT_FAILURE, ("Could not canonicalize username\n"));
+            return ret;
+        }
+
         return EOK;
     }
 
-- 
1.7.7.4

-------------- next part --------------
From 7bc86ebdfa569bced2a26c43efe52cc2ccab41b5 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Mon, 12 Dec 2011 16:35:22 +0100
Subject: [PATCH 4/9] Use the case sensitivity flag in responders

---
 src/confdb/confdb.c                     |    7 +
 src/confdb/confdb.h                     |    2 +
 src/config/SSSDConfig.py                |    1 +
 src/config/SSSDConfigTest.py            |    2 +
 src/config/etc/sssd.api.conf            |    1 +
 src/man/sssd.conf.5.xml                 |   14 ++
 src/responder/common/negcache.c         |  267 +++++++++++++++++++++----------
 src/responder/common/negcache.h         |   10 +-
 src/responder/common/responder_common.c |    1 -
 src/responder/nss/nsssrv_cmd.c          |   39 +++--
 src/responder/nss/nsssrv_netgroup.c     |   21 ++-
 src/responder/pam/pamsrv_cmd.c          |    8 +-
 12 files changed, 261 insertions(+), 112 deletions(-)

diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c
index 3f668dd3dec337afc05cea4459a4eff123161cb9..9ebe0127da81c7d26e75eca4e4136472317e534d 100644
--- a/src/confdb/confdb.c
+++ b/src/confdb/confdb.c
@@ -856,6 +856,13 @@ static int confdb_get_domain_internal(struct confdb_ctx *cdb,
         goto done;
     }
 
+    ret = get_entry_as_bool(res->msgs[0], &domain->case_sensitive,
+                            CONFDB_DOMAIN_CASE_SENSITIVE, true);
+    if(ret != EOK) {
+        DEBUG(0, ("Invalid value for %s\n", CONFDB_DOMAIN_CASE_SENSITIVE));
+        goto done;
+    }
+
     *_domain = domain;
     ret = EOK;
 done:
diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
index 266e4d27189dd14d282045cc5c7e857ebc00f974..2ebbf4f46369161a443b5ba80a58245990651948 100644
--- a/src/confdb/confdb.h
+++ b/src/confdb/confdb.h
@@ -117,6 +117,7 @@
 #define CONFDB_DOMAIN_FAMILY_ORDER "lookup_family_order"
 #define CONFDB_DOMAIN_ACCOUNT_CACHE_EXPIRATION "account_cache_expiration"
 #define CONFDB_DOMAIN_OVERRIDE_GID "override_gid"
+#define CONFDB_DOMAIN_CASE_SENSITIVE "case_sensitive"
 
 /* Local Provider */
 #define CONFDB_LOCAL_DEFAULT_SHELL   "default_shell"
@@ -150,6 +151,7 @@ struct sss_domain_info {
 
     bool cache_credentials;
     bool legacy_passwords;
+    bool case_sensitive;
 
     gid_t override_gid;
     const char *override_homedir;
diff --git a/src/config/SSSDConfig.py b/src/config/SSSDConfig.py
index cb55d3de1b5ab0f08724682978e6966435b860fa..44bfb69f532adbcce88f2f0e5786987e21e69e7b 100644
--- a/src/config/SSSDConfig.py
+++ b/src/config/SSSDConfig.py
@@ -92,6 +92,7 @@ option_strings = {
     'dns_resolver_timeout' : _('How long to wait for replies from DNS when resolving servers (seconds)'),
     'dns_discovery_domain' : _('The domain part of service discovery DNS query'),
     'override_gid' : _('Override GID value from the identity provider with this value'),
+    'case_sensitive' : _('Treat usernames as case sensitive'),
 
     # [provider/ipa]
     'ipa_domain' : _('IPA domain'),
diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py
index 16ddfe5012654dc1600b79ad90493a409b0d5c9d..8421a09147dcbc25f628b4b75f278b4824413d18 100755
--- a/src/config/SSSDConfigTest.py
+++ b/src/config/SSSDConfigTest.py
@@ -484,6 +484,7 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase):
             'dns_resolver_timeout',
             'dns_discovery_domain',
             'override_gid',
+            'case_sensitive',
             'override_homedir',
             'id_provider',
             'auth_provider',
@@ -801,6 +802,7 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase):
             'dns_resolver_timeout',
             'dns_discovery_domain',
             'override_gid',
+            'case_sensitive',
             'override_homedir',
             'id_provider',
             'auth_provider',
diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf
index 6813901ed7c2598724323a5c06529ddd62121a58..c2c425cefa9ebbb2a4169e0a13d4de2594a275dd 100644
--- a/src/config/etc/sssd.api.conf
+++ b/src/config/etc/sssd.api.conf
@@ -72,6 +72,7 @@ filter_groups = list, str, false
 dns_resolver_timeout = int, None, false
 dns_discovery_domain = str, None, false
 override_gid = int, None, false
+case_sensitive = bool, None, false
 override_homedir = str, None, false
 
 
diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
index 1ed408f2e1b5ccda3f551744cbc3ea8cac7a74bf..72998b44f6637734e372b26eb7889b220ce8ac36 100644
--- a/src/man/sssd.conf.5.xml
+++ b/src/man/sssd.conf.5.xml
@@ -931,6 +931,20 @@
                         </para>
                     </listitem>
                 </varlistentry>
+
+                <varlistentry>
+                    <term>case_sensitive (boolean)</term>
+                    <listitem>
+                        <para>
+                            Treat user and group names as case sensitive. At
+                            the moment, this option is not supported in
+                            the local provider.
+                        </para>
+                        <para>
+                            Default: True
+                        </para>
+                    </listitem>
+                </varlistentry>
             </variablelist>
         </para>
 
diff --git a/src/responder/common/negcache.c b/src/responder/common/negcache.c
index 3926574a12c898db30a1fe22ec763c2ed1d94f72..aa89bc2ab38096f98d95c032aa4df105828c2345 100644
--- a/src/responder/common/negcache.c
+++ b/src/responder/common/negcache.c
@@ -21,6 +21,7 @@
 
 #include "util/util.h"
 #include "confdb/confdb.h"
+#include "responder/common/responder.h"
 #include <fcntl.h>
 #include <time.h>
 #include "tdb.h"
@@ -158,55 +159,98 @@ done:
     return ret;
 }
 
+static int sss_ncache_check_user_int(struct sss_nc_ctx *ctx, int ttl,
+                                     const char *domain, const char *name)
+{
+    char *str;
+    int ret;
+
+    if (!name || !*name) return EINVAL;
+
+    str = talloc_asprintf(ctx, "%s/%s/%s", NC_USER_PREFIX, domain, name);
+    if (!str) return ENOMEM;
+
+    ret = sss_ncache_check_str(ctx, str, ttl);
+
+    talloc_free(str);
+    return ret;
+}
+
+static int sss_ncache_check_group_int(struct sss_nc_ctx *ctx, int ttl,
+                                      const char *domain, const char *name)
+{
+    char *str;
+    int ret;
+
+    if (!name || !*name) return EINVAL;
+
+    str = talloc_asprintf(ctx, "%s/%s/%s", NC_GROUP_PREFIX, domain, name);
+    if (!str) return ENOMEM;
+
+    ret = sss_ncache_check_str(ctx, str, ttl);
+
+    talloc_free(str);
+    return ret;
+}
+
+static int sss_ncache_check_netgr_int(struct sss_nc_ctx *ctx, int ttl,
+                                      const char *domain, const char *name)
+{
+    char *str;
+    int ret;
+
+    if (!name || !*name) return EINVAL;
+
+    str = talloc_asprintf(ctx, "%s/%s/%s", NC_NETGROUP_PREFIX, domain, name);
+    if (!str) return ENOMEM;
+
+    ret = sss_ncache_check_str(ctx, str, ttl);
+
+    talloc_free(str);
+    return ret;
+}
+
+typedef int (*ncache_check_byname_fn_t)(struct sss_nc_ctx *, int,
+                                        const char *, const char *);
+
+static int sss_cache_check_ent(struct sss_nc_ctx *ctx, int ttl,
+                               struct sss_domain_info *dom, const char *name,
+                               ncache_check_byname_fn_t checker)
+{
+    char *lower;
+    errno_t ret;
+
+    if (dom->case_sensitive == false) {
+        lower = sss_tc_utf8_tolower(ctx, name);
+        if (!lower) return ENOMEM;
+        ret = checker(ctx, ttl, dom->name, lower);
+        talloc_free(lower);
+    } else {
+        ret = checker(ctx, ttl, dom->name, name);
+    }
+
+    return ret;
+}
+
 int sss_ncache_check_user(struct sss_nc_ctx *ctx, int ttl,
-                          const char *domain, const char *name)
+                          struct sss_domain_info *dom, const char *name)
 {
-    char *str;
-    int ret;
-
-    if (!name || !*name) return EINVAL;
-
-    str = talloc_asprintf(ctx, "%s/%s/%s", NC_USER_PREFIX, domain, name);
-    if (!str) return ENOMEM;
-
-    ret = sss_ncache_check_str(ctx, str, ttl);
-
-    talloc_free(str);
-    return ret;
+    return sss_cache_check_ent(ctx, ttl, dom, name,
+                               sss_ncache_check_user_int);
 }
 
 int sss_ncache_check_group(struct sss_nc_ctx *ctx, int ttl,
-                           const char *domain, const char *name)
+                           struct sss_domain_info *dom, const char *name)
 {
-    char *str;
-    int ret;
-
-    if (!name || !*name) return EINVAL;
-
-    str = talloc_asprintf(ctx, "%s/%s/%s", NC_GROUP_PREFIX, domain, name);
-    if (!str) return ENOMEM;
-
-    ret = sss_ncache_check_str(ctx, str, ttl);
-
-    talloc_free(str);
-    return ret;
+    return sss_cache_check_ent(ctx, ttl, dom, name,
+                               sss_ncache_check_group_int);
 }
 
 int sss_ncache_check_netgr(struct sss_nc_ctx *ctx, int ttl,
-                           const char *domain, const char *name)
+                           struct sss_domain_info *dom, const char *name)
 {
-    char *str;
-    int ret;
-
-    if (!name || !*name) return EINVAL;
-
-    str = talloc_asprintf(ctx, "%s/%s/%s", NC_NETGROUP_PREFIX, domain, name);
-    if (!str) return ENOMEM;
-
-    ret = sss_ncache_check_str(ctx, str, ttl);
-
-    talloc_free(str);
-    return ret;
+    return sss_cache_check_ent(ctx, ttl, dom, name,
+                               sss_ncache_check_netgr_int);
 }
 
 int sss_ncache_check_uid(struct sss_nc_ctx *ctx, int ttl, uid_t uid)
@@ -237,55 +281,96 @@ int sss_ncache_check_gid(struct sss_nc_ctx *ctx, int ttl, gid_t gid)
     return ret;
 }
 
+static int sss_ncache_set_user_int(struct sss_nc_ctx *ctx, bool permanent,
+                                   const char *domain, const char *name)
+{
+    char *str;
+    int ret;
+
+    if (!name || !*name) return EINVAL;
+
+    str = talloc_asprintf(ctx, "%s/%s/%s", NC_USER_PREFIX, domain, name);
+    if (!str) return ENOMEM;
+
+    ret = sss_ncache_set_str(ctx, str, permanent);
+
+    talloc_free(str);
+    return ret;
+}
+
+static int sss_ncache_set_group_int(struct sss_nc_ctx *ctx, bool permanent,
+                                    const char *domain, const char *name)
+{
+    char *str;
+    int ret;
+
+    if (!name || !*name) return EINVAL;
+
+    str = talloc_asprintf(ctx, "%s/%s/%s", NC_GROUP_PREFIX, domain, name);
+    if (!str) return ENOMEM;
+
+    ret = sss_ncache_set_str(ctx, str, permanent);
+
+    talloc_free(str);
+    return ret;
+}
+
+static int sss_ncache_set_netgr_int(struct sss_nc_ctx *ctx, bool permanent,
+                                    const char *domain, const char *name)
+{
+    char *str;
+    int ret;
+
+    if (!name || !*name) return EINVAL;
+
+    str = talloc_asprintf(ctx, "%s/%s/%s", NC_NETGROUP_PREFIX, domain, name);
+    if (!str) return ENOMEM;
+
+    ret = sss_ncache_set_str(ctx, str, permanent);
+
+    talloc_free(str);
+    return ret;
+}
+
+typedef int (*ncache_set_byname_fn_t)(struct sss_nc_ctx *, bool,
+                                      const char *, const char *);
+
+static int sss_ncache_set_ent(struct sss_nc_ctx *ctx, bool permanent,
+                              struct sss_domain_info *dom, const char *name,
+                              ncache_set_byname_fn_t setter)
+{
+    char *lower;
+    errno_t ret;
+
+    if (dom->case_sensitive == false) {
+        lower = sss_tc_utf8_tolower(ctx, name);
+        if (!lower) return ENOMEM;
+        ret = setter(ctx, permanent, dom->name, lower);
+        talloc_free(lower);
+    } else {
+        ret = setter(ctx, permanent, dom->name, name);
+    }
+
+    return ret;
+}
+
+
 int sss_ncache_set_user(struct sss_nc_ctx *ctx, bool permanent,
-                        const char *domain, const char *name)
+                        struct sss_domain_info *dom, const char *name)
 {
-    char *str;
-    int ret;
-
-    if (!name || !*name) return EINVAL;
-
-    str = talloc_asprintf(ctx, "%s/%s/%s", NC_USER_PREFIX, domain, name);
-    if (!str) return ENOMEM;
-
-    ret = sss_ncache_set_str(ctx, str, permanent);
-
-    talloc_free(str);
-    return ret;
+    return sss_ncache_set_ent(ctx, permanent, dom, name, sss_ncache_set_user_int);
 }
 
 int sss_ncache_set_group(struct sss_nc_ctx *ctx, bool permanent,
-                        const char *domain, const char *name)
+                         struct sss_domain_info *dom, const char *name)
 {
-    char *str;
-    int ret;
-
-    if (!name || !*name) return EINVAL;
-
-    str = talloc_asprintf(ctx, "%s/%s/%s", NC_GROUP_PREFIX, domain, name);
-    if (!str) return ENOMEM;
-
-    ret = sss_ncache_set_str(ctx, str, permanent);
-
-    talloc_free(str);
-    return ret;
+    return sss_ncache_set_ent(ctx, permanent, dom, name, sss_ncache_set_group_int);
 }
 
 int sss_ncache_set_netgr(struct sss_nc_ctx *ctx, bool permanent,
-                         const char *domain, const char *name)
+                         struct sss_domain_info *dom, const char *name)
 {
-    char *str;
-    int ret;
-
-    if (!name || !*name) return EINVAL;
-
-    str = talloc_asprintf(ctx, "%s/%s/%s", NC_NETGROUP_PREFIX, domain, name);
-    if (!str) return ENOMEM;
-
-    ret = sss_ncache_set_str(ctx, str, permanent);
-
-    talloc_free(str);
-    return ret;
+    return sss_ncache_set_ent(ctx, permanent, dom, name, sss_ncache_set_netgr_int);
 }
 
 int sss_ncache_set_uid(struct sss_nc_ctx *ctx, bool permanent, uid_t uid)
@@ -409,7 +494,7 @@ errno_t sss_ncache_prepopulate(struct sss_nc_ctx *ncache,
                 continue;
             }
 
-            ret = sss_ncache_set_user(ncache, true, dom->name, name);
+            ret = sss_ncache_set_user(ncache, true, dom, name);
             if (ret != EOK) {
                 DEBUG(1, ("Failed to store permanent user filter for [%s]"
                           " (%d [%s])\n", filter_list[i],
@@ -447,7 +532,14 @@ errno_t sss_ncache_prepopulate(struct sss_nc_ctx *ncache,
             continue;
         }
         if (domainname) {
-            ret = sss_ncache_set_user(ncache, true, domainname, name);
+            dom = responder_get_domain(domain_list, domainname);
+            if (!dom) {
+                DEBUG(SSSDBG_CRIT_FAILURE,
+                      ("Invalid domain name [%s]\n", domainname));
+                continue;
+            }
+
+            ret = sss_ncache_set_user(ncache, true, dom, name);
             if (ret != EOK) {
                 DEBUG(1, ("Failed to store permanent user filter for [%s]"
                           " (%d [%s])\n", filter_list[i],
@@ -456,7 +548,7 @@ errno_t sss_ncache_prepopulate(struct sss_nc_ctx *ncache,
             }
         } else {
             for (dom = domain_list; dom; dom = dom->next) {
-                ret = sss_ncache_set_user(ncache, true, dom->name, name);
+                ret = sss_ncache_set_user(ncache, true, dom, name);
                 if (ret != EOK) {
                    DEBUG(1, ("Failed to store permanent user filter for"
                              " [%s:%s] (%d [%s])\n",
@@ -499,7 +591,7 @@ errno_t sss_ncache_prepopulate(struct sss_nc_ctx *ncache,
                 continue;
             }
 
-            ret = sss_ncache_set_group(ncache, true, dom->name, name);
+            ret = sss_ncache_set_group(ncache, true, dom, name);
             if (ret != EOK) {
                 DEBUG(1, ("Failed to store permanent group filter for [%s]"
                           " (%d [%s])\n", filter_list[i],
@@ -537,7 +629,14 @@ errno_t sss_ncache_prepopulate(struct sss_nc_ctx *ncache,
             continue;
         }
         if (domainname) {
-            ret = sss_ncache_set_group(ncache, true, domainname, name);
+            dom = responder_get_domain(domain_list, domainname);
+            if (!dom) {
+                DEBUG(SSSDBG_CRIT_FAILURE,
+                      ("Invalid domain name [%s]\n", domainname));
+                continue;
+            }
+
+            ret = sss_ncache_set_group(ncache, true, dom, name);
             if (ret != EOK) {
                 DEBUG(1, ("Failed to store permanent group filter for"
                           " [%s] (%d [%s])\n", filter_list[i],
@@ -546,7 +645,7 @@ errno_t sss_ncache_prepopulate(struct sss_nc_ctx *ncache,
             }
         } else {
             for (dom = domain_list; dom; dom = dom->next) {
-                ret = sss_ncache_set_group(ncache, true, dom->name, name);
+                ret = sss_ncache_set_group(ncache, true, dom, name);
                 if (ret != EOK) {
                    DEBUG(1, ("Failed to store permanent group filter for"
                              " [%s:%s] (%d [%s])\n",
diff --git a/src/responder/common/negcache.h b/src/responder/common/negcache.h
index fc857fce1608b2d71a75de10a6d63158dc20ce1e..72b99c969043d42c6f1329d8b0d549cadaddb998 100644
--- a/src/responder/common/negcache.h
+++ b/src/responder/common/negcache.h
@@ -29,9 +29,9 @@ int sss_ncache_init(TALLOC_CTX *memctx, struct sss_nc_ctx **_ctx);
 
 /* check if the user is expired according to the passed in time to live */
 int sss_ncache_check_user(struct sss_nc_ctx *ctx, int ttl,
-                          const char *domain, const char *name);
+                          struct sss_domain_info *dom, const char *name);
 int sss_ncache_check_group(struct sss_nc_ctx *ctx, int ttl,
-                          const char *domain, const char *name);
+                           struct sss_domain_info *dom, const char *name);
 int sss_ncache_check_netgr(struct sss_nc_ctx *ctx, int ttl,
                            const char *domain, const char *name);
 int sss_ncache_check_uid(struct sss_nc_ctx *ctx, int ttl, uid_t uid);
@@ -42,11 +42,11 @@ int sss_ncache_check_gid(struct sss_nc_ctx *ctx, int ttl, gid_t gid);
  * and the negative cache never expires (used to permanently filter out
  * users and groups) */
 int sss_ncache_set_user(struct sss_nc_ctx *ctx, bool permanent,
-                        const char *domain, const char *name);
+                        struct sss_domain_info *dom, const char *name);
 int sss_ncache_set_group(struct sss_nc_ctx *ctx, bool permanent,
-                        const char *domain, const char *name);
+                         struct sss_domain_info *dom, const char *name);
 int sss_ncache_set_netgr(struct sss_nc_ctx *ctx, bool permanent,
-                         const char *domain, const char *name);
+                         struct sss_domain_info *dom, const char *name);
 int sss_ncache_set_uid(struct sss_nc_ctx *ctx, bool permanent, uid_t uid);
 int sss_ncache_set_gid(struct sss_nc_ctx *ctx, bool permanent, gid_t gid);
 
diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c
index 99b1a23aa8581e01fb2a02d36657df6c20717812..a48ac556abe82579bf9455bf7b1eb94917e391b6 100644
--- a/src/responder/common/responder_common.c
+++ b/src/responder/common/responder_common.c
@@ -33,7 +33,6 @@
 #include <errno.h>
 #include <popt.h>
 #include "util/util.h"
-#include "util/sss_utf8.h"
 #include "db/sysdb.h"
 #include "confdb/confdb.h"
 #include "dbus/dbus.h"
diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
index f0270acd26659e8005a043fd9e154723cc868d0d..ae796578e42c71b9d2f76dc2fb143f14f269df5b 100644
--- a/src/responder/nss/nsssrv_cmd.c
+++ b/src/responder/nss/nsssrv_cmd.c
@@ -394,7 +394,7 @@ static int fill_pwent(struct sss_packet *packet,
         if (filter_users) {
             ncret = sss_ncache_check_user(nctx->ncache,
                                         nctx->neg_timeout,
-                                        domain, name);
+                                        dom, name);
             if (ncret == EEXIST) {
                 DEBUG(4, ("User [%s@%s] filtered out! (negative cache)\n",
                           name, domain));
@@ -715,7 +715,7 @@ static int nss_cmd_getpwnam_search(struct nss_dom_ctx *dctx)
     struct nss_cmd_ctx *cmdctx = dctx->cmdctx;
     struct sss_domain_info *dom = dctx->domain;
     struct cli_ctx *cctx = cmdctx->cctx;
-    const char *name = cmdctx->name;
+    char *name = NULL;
     struct sysdb_ctx *sysdb;
     struct nss_ctx *nctx;
     int ret;
@@ -740,10 +740,15 @@ static int nss_cmd_getpwnam_search(struct nss_dom_ctx *dctx)
         /* make sure to update the dctx if we changed domain */
         dctx->domain = dom;
 
+        talloc_free(name);
+        name = dom->case_sensitive ? talloc_strdup(dctx, cmdctx->name) :
+                                   sss_tc_utf8_tolower(dctx, cmdctx->name);
+        if (!name) return ENOMEM;
+
         /* verify this user has not yet been negatively cached,
         * or has been permanently filtered */
         ret = sss_ncache_check_user(nctx->ncache, nctx->neg_timeout,
-                                    dom->name, name);
+                                    dom, name);
 
         /* if neg cached, return we didn't find it */
         if (ret == EEXIST) {
@@ -781,7 +786,7 @@ static int nss_cmd_getpwnam_search(struct nss_dom_ctx *dctx)
 
         if (dctx->res->count == 0 && !dctx->check_provider) {
             /* set negative cache only if not result of cache check */
-            ret = sss_ncache_set_user(nctx->ncache, false, dom->name, name);
+            ret = sss_ncache_set_user(nctx->ncache, false, dom, name);
             if (ret != EOK) {
                 return ret;
             }
@@ -1788,7 +1793,7 @@ static int fill_grent(struct sss_packet *packet,
 
         if (filter_groups) {
             ret = sss_ncache_check_group(nctx->ncache,
-                                         nctx->neg_timeout, domain, name);
+                                         nctx->neg_timeout, dom, name);
             if (ret == EEXIST) {
                 DEBUG(4, ("Group [%s@%s] filtered out! (negative cache)\n",
                           name, domain));
@@ -1866,7 +1871,7 @@ static int fill_grent(struct sss_packet *packet,
                 if (nctx->filter_users_in_groups) {
                     ret = sss_ncache_check_user(nctx->ncache,
                                                 nctx->neg_timeout,
-                                                domain, name);
+                                                dom, name);
                     if (ret == EEXIST) {
                         DEBUG(6, ("Group [%s] member [%s@%s] filtered out!"
                                   " (negative cache)\n",
@@ -2002,7 +2007,7 @@ static int nss_cmd_getgrnam_search(struct nss_dom_ctx *dctx)
     struct nss_cmd_ctx *cmdctx = dctx->cmdctx;
     struct sss_domain_info *dom = dctx->domain;
     struct cli_ctx *cctx = cmdctx->cctx;
-    const char *name = cmdctx->name;
+    char *name = NULL;
     struct sysdb_ctx *sysdb;
     struct nss_ctx *nctx;
     int ret;
@@ -2027,10 +2032,15 @@ static int nss_cmd_getgrnam_search(struct nss_dom_ctx *dctx)
         /* make sure to update the dctx if we changed domain */
         dctx->domain = dom;
 
+        talloc_free(name);
+        name = dom->case_sensitive ? talloc_strdup(dctx, cmdctx->name) :
+                                     sss_tc_utf8_tolower(dctx, cmdctx->name);
+        if (!name) return ENOMEM;
+
         /* verify this group has not yet been negatively cached,
         * or has been permanently filtered */
         ret = sss_ncache_check_group(nctx->ncache, nctx->neg_timeout,
-                                     dom->name, name);
+                                     dom, name);
 
         /* if neg cached, return we didn't find it */
         if (ret == EEXIST) {
@@ -2068,7 +2078,7 @@ static int nss_cmd_getgrnam_search(struct nss_dom_ctx *dctx)
 
         if (dctx->res->count == 0 && !dctx->check_provider) {
             /* set negative cache only if not result of cache check */
-            ret = sss_ncache_set_group(nctx->ncache, false, dom->name, name);
+            ret = sss_ncache_set_group(nctx->ncache, false, dom, name);
             if (ret != EOK) {
                 return ret;
             }
@@ -3068,7 +3078,7 @@ static int nss_cmd_initgroups_search(struct nss_dom_ctx *dctx)
     struct nss_cmd_ctx *cmdctx = dctx->cmdctx;
     struct sss_domain_info *dom = dctx->domain;
     struct cli_ctx *cctx = cmdctx->cctx;
-    const char *name = cmdctx->name;
+    char *name = NULL;
     struct sysdb_ctx *sysdb;
     struct nss_ctx *nctx;
     int ret;
@@ -3093,10 +3103,15 @@ static int nss_cmd_initgroups_search(struct nss_dom_ctx *dctx)
         /* make sure to update the dctx if we changed domain */
         dctx->domain = dom;
 
+        talloc_free(name);
+        name = dom->case_sensitive ? talloc_strdup(dctx, cmdctx->name) :
+                                     sss_tc_utf8_tolower(dctx, cmdctx->name);
+        if (!name) return ENOMEM;
+
         /* verify this user has not yet been negatively cached,
         * or has been permanently filtered */
         ret = sss_ncache_check_user(nctx->ncache, nctx->neg_timeout,
-                                    dom->name, name);
+                                    dom, name);
 
         /* if neg cached, return we didn't find it */
         if (ret == EEXIST) {
@@ -3130,7 +3145,7 @@ static int nss_cmd_initgroups_search(struct nss_dom_ctx *dctx)
 
         if (dctx->res->count == 0 && !dctx->check_provider) {
             /* set negative cache only if not result of cache check */
-            ret = sss_ncache_set_user(nctx->ncache, false, dom->name, name);
+            ret = sss_ncache_set_user(nctx->ncache, false, dom, name);
             if (ret != EOK) {
                 return ret;
             }
diff --git a/src/responder/nss/nsssrv_netgroup.c b/src/responder/nss/nsssrv_netgroup.c
index 09b7fa6355421c941631775c71d33a2851edbe4e..200e77b80ded1042472da982b85516c4d455f9b2 100644
--- a/src/responder/nss/nsssrv_netgroup.c
+++ b/src/responder/nss/nsssrv_netgroup.c
@@ -378,6 +378,7 @@ static errno_t lookup_netgr_step(struct setent_step_ctx *step_ctx)
     struct sss_domain_info *dom = step_ctx->dctx->domain;
     struct getent_ctx *netgr;
     struct sysdb_ctx *sysdb;
+    char *name = NULL;
 
     /* Check each domain for this netgroup name */
     while (dom) {
@@ -400,8 +401,13 @@ static errno_t lookup_netgr_step(struct setent_step_ctx *step_ctx)
         /* make sure to update the dctx if we changed domain */
         step_ctx->dctx->domain = dom;
 
+        talloc_free(name);
+        name = dom->case_sensitive ? \
+                    talloc_strdup(step_ctx, step_ctx->name) :
+                    sss_tc_utf8_tolower(step_ctx, step_ctx->name);
+
         DEBUG(4, ("Requesting info for [%s@%s]\n",
-                  step_ctx->name, dom->name));
+                  name, dom->name));
         ret = sysdb_get_ctx_from_list(step_ctx->rctx->db_list, dom, &sysdb);
         if (ret != EOK) {
             DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n"));
@@ -409,7 +415,7 @@ static errno_t lookup_netgr_step(struct setent_step_ctx *step_ctx)
         }
 
         /* Look up the netgroup in the cache */
-        ret = sysdb_getnetgr(step_ctx->dctx, sysdb, step_ctx->name,
+        ret = sysdb_getnetgr(step_ctx->dctx, sysdb, name,
                              &step_ctx->dctx->res);
         if (ret == ENOENT) {
             /* This netgroup was not found in this domain */
@@ -442,7 +448,7 @@ static errno_t lookup_netgr_step(struct setent_step_ctx *step_ctx)
         if (ret == ENOENT) {
             /* This netgroup was not found in this domain */
             DEBUG(2, ("No results for netgroup %s (domain %s)\n",
-                      step_ctx->name, dom->name));
+                      name, dom->name));
 
             if (!step_ctx->dctx->check_provider) {
                 if (step_ctx->check_next) {
@@ -469,7 +475,7 @@ static errno_t lookup_netgr_step(struct setent_step_ctx *step_ctx)
                               step_ctx->nctx,
                               step_ctx->dctx->res,
                               SSS_DP_NETGR,
-                              step_ctx->name, 0,
+                              name, 0,
                               lookup_netgr_dp_callback,
                               step_ctx);
             if (ret != EOK) {
@@ -482,7 +488,7 @@ static errno_t lookup_netgr_step(struct setent_step_ctx *step_ctx)
 
         /* Results found */
         DEBUG(6, ("Returning info for netgroup [%s@%s]\n",
-                  step_ctx->name, dom->name));
+                  name, dom->name));
         netgr->ready = true;
         netgr->found = true;
         set_netgr_lifetime(dom->entry_cache_timeout, step_ctx, netgr);
@@ -490,8 +496,7 @@ static errno_t lookup_netgr_step(struct setent_step_ctx *step_ctx)
     }
 
     /* If we've gotten here, then no domain contained this netgroup */
-    DEBUG(2, ("No matching domain found for [%s], fail!\n",
-              step_ctx->name));
+    DEBUG(2, ("No matching domain found for [%s], fail!\n", name));
 
     netgr = talloc_zero(step_ctx->nctx, struct getent_ctx);
     if (netgr == NULL) {
@@ -501,7 +506,7 @@ static errno_t lookup_netgr_step(struct setent_step_ctx *step_ctx)
         netgr->found = false;
         netgr->entries = NULL;
         netgr->lookup_table = step_ctx->nctx->netgroups;
-        netgr->name = talloc_strdup(netgr, step_ctx->name);
+        netgr->name = talloc_strdup(netgr, name);
         if (netgr->name == NULL) {
             DEBUG(1, ("talloc_strdup failed.\n"));
             talloc_free(netgr);
diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c
index 14251389dadd4408adc78d5c28b9ccf85fda7f8d..f6412a862e754b8059e8888201a529f359989f75 100644
--- a/src/responder/pam/pamsrv_cmd.c
+++ b/src/responder/pam/pamsrv_cmd.c
@@ -786,7 +786,7 @@ static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd)
             if (dom->fqnames) continue;
 
             ncret = sss_ncache_check_user(pctx->ncache, pctx->neg_timeout,
-                                          dom->name, pd->user);
+                                          dom, pd->user);
             if (ncret == ENOENT) {
                 /* User not found in the negative cache
                  * Proceed with PAM actions
@@ -829,7 +829,7 @@ static int pam_check_user_search(struct pam_auth_req *preq)
 {
     struct sss_domain_info *dom = preq->domain;
     struct cli_ctx *cctx = preq->cctx;
-    const char *name = preq->pd->user;
+    char *name = NULL;
     struct sysdb_ctx *sysdb;
     time_t cacheExpire;
     int ret;
@@ -854,6 +854,10 @@ static int pam_check_user_search(struct pam_auth_req *preq)
         /* make sure to update the preq if we changed domain */
         preq->domain = dom;
 
+        talloc_free(name);
+        name = dom->case_sensitive ? talloc_strdup(preq, preq->pd->user) :
+                                sss_tc_utf8_tolower(preq, preq->pd->user);
+
         /* Refresh the user's cache entry on any PAM query
          * We put a timeout in the client context so that we limit
          * the number of updates within a reasonable timeout
-- 
1.7.7.4

-------------- next part --------------
From 7800be8de78bb7c569266dc51165b3e7c3687c77 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Wed, 16 Nov 2011 13:57:26 +0100
Subject: [PATCH 5/9] Refactor saving sdap entities

There was too much code duplication between
sdap_save_{user,group,netgroup}. This patch removes the most egregious ones.
---
 src/providers/ldap/sdap_async.c           |   80 +++++++++++++++++++++++
 src/providers/ldap/sdap_async.h           |   21 ++++++
 src/providers/ldap/sdap_async_groups.c    |   49 +++-----------
 src/providers/ldap/sdap_async_netgroups.c |   77 +++++------------------
 src/providers/ldap/sdap_async_users.c     |   98 ++++++-----------------------
 5 files changed, 146 insertions(+), 179 deletions(-)

diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c
index b1177e274bd3cf6d00d4cfa773556731b5997e97..98291e6e2e8ac13fe244c8cb1f332df30e20aa4e 100644
--- a/src/providers/ldap/sdap_async.c
+++ b/src/providers/ldap/sdap_async.c
@@ -1983,3 +1983,83 @@ done:
     return ret;
 }
 
+errno_t
+sdap_attrs_add_ldap_attr(struct sysdb_attrs *ldap_attrs,
+                         const char *attr_name,
+                         const char *attr_desc,
+                         bool multivalued,
+                         const char *name,
+                         struct sysdb_attrs *attrs)
+{
+    errno_t ret;
+    struct ldb_message_element *el;
+    const char *objname = name ?: "object";
+    const char *desc = attr_desc ?: attr_name;
+    unsigned int num_values, i;
+
+    ret = sysdb_attrs_get_el(ldap_attrs, attr_name, &el);
+    if (ret) {
+        DEBUG(SSSDBG_OP_FAILURE, ("Could not get %s from the "
+              "list of the LDAP attributes [%d]: %s\n", ret, strerror(ret)));
+        return ret;
+    }
+
+    if (el->num_values == 0) {
+        DEBUG(SSSDBG_TRACE_INTERNAL, ("%s is not available "
+              "for [%s].\n", desc, objname));
+    } else {
+        num_values = multivalued ? el->num_values : 1;
+        for (i = 0; i < num_values; i++) {
+            DEBUG(SSSDBG_TRACE_INTERNAL, ("Adding %s [%s] to attributes "
+                  "of [%s].\n", desc, el->values[i].data, objname));
+
+            ret = sysdb_attrs_add_string(attrs, attr_name,
+                                         (const char *) el->values[i].data);
+            if (ret) {
+                return ret;
+            }
+        }
+    }
+
+    return EOK;
+}
+
+
+errno_t
+sdap_save_all_names(const char *name,
+                    struct sysdb_attrs *ldap_attrs,
+                    struct sysdb_attrs *attrs)
+{
+    const char **aliases = NULL;
+    errno_t ret;
+    TALLOC_CTX *tmp_ctx;
+    int i;
+
+    tmp_ctx = talloc_new(NULL);
+    if (!tmp_ctx) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = sysdb_attrs_get_aliases(tmp_ctx, ldap_attrs, name, &aliases);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, ("Failed to get the alias list"));
+        goto done;
+    }
+
+    for (i = 0; aliases[i]; i++) {
+        ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS,
+                                     aliases[i]);
+        if (ret) {
+            DEBUG(SSSDBG_OP_FAILURE, ("Failed to add alias [%s] into the "
+                                      "attribute list\n", aliases[i]));
+            goto done;
+        }
+    }
+
+    ret = EOK;
+done:
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h
index 4ba2770c989968e5398feeca0dbeb8a99206a009..f53af1e01e683ac0918f8ee5d74e1c19713c4bb7 100644
--- a/src/providers/ldap/sdap_async.h
+++ b/src/providers/ldap/sdap_async.h
@@ -189,4 +189,25 @@ errno_t sdap_check_aliases(struct sysdb_ctx *sysdb,
                            struct sss_domain_info *dom,
                            struct sdap_options *opts,
                            bool steal_memberships);
+
+errno_t
+sdap_attrs_add_ldap_attr(struct sysdb_attrs *ldap_attrs,
+                         const char *attr_name,
+                         const char *attr_desc,
+                         bool multivalued,
+                         const char *name,
+                         struct sysdb_attrs *attrs);
+
+#define sdap_attrs_add_string(ldap_attrs, attr_name, attr_desc, name, attrs) \
+        sdap_attrs_add_ldap_attr(ldap_attrs, attr_name, attr_desc, \
+                                 false, name, attrs)
+
+#define sdap_attrs_add_list(ldap_attrs, attr_name, attr_desc, name, attrs) \
+    sdap_attrs_add_ldap_attr(ldap_attrs, attr_name, attr_desc,   \
+                             true, name, attrs)
+
+errno_t sdap_save_all_names(const char *name,
+                            struct sysdb_attrs *ldap_attrs,
+                            struct sysdb_attrs *attrs);
+
 #endif /* _SDAP_ASYNC_H_ */
diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c
index ead3fd544ae74923332c0a3780c2454845b5f1e6..d2c15dedaf7417d97a91a587bc1145b21c3ebf92 100644
--- a/src/providers/ldap/sdap_async_groups.c
+++ b/src/providers/ldap/sdap_async_groups.c
@@ -222,11 +222,9 @@ static int sdap_save_group(TALLOC_CTX *memctx,
     const char *name = NULL;
     gid_t gid;
     int ret;
-    int i;
     char *usn_value = NULL;
     TALLOC_CTX *tmpctx = NULL;
     bool posix_group;
-    const char **aliases = NULL;
 
     tmpctx = talloc_new(memctx);
     if (!tmpctx) {
@@ -282,38 +280,19 @@ static int sdap_save_group(TALLOC_CTX *memctx,
         /* Group ID OK */
     }
 
-    ret = sysdb_attrs_get_el(attrs, SYSDB_ORIG_DN, &el);
-    if (ret) {
+    ret = sdap_attrs_add_string(attrs, SYSDB_ORIG_DN, "original DN",
+                                name, group_attrs);
+    if (ret != EOK) {
         goto fail;
     }
-    if (el->num_values == 0) {
-        DEBUG(7, ("Original DN is not available for [%s].\n", name));
-    } else {
-        DEBUG(7, ("Adding original DN [%s] to attributes of [%s].\n",
-                  el->values[0].data, name));
-        ret = sysdb_attrs_add_string(group_attrs, SYSDB_ORIG_DN,
-                                     (const char *) el->values[0].data);
-        if (ret) {
-            goto fail;
-        }
-    }
 
-    ret = sysdb_attrs_get_el(attrs,
-                      opts->group_map[SDAP_AT_GROUP_MODSTAMP].sys_name, &el);
-    if (ret) {
+    ret = sdap_attrs_add_string(attrs,
+                            opts->group_map[SDAP_AT_GROUP_MODSTAMP].sys_name,
+                            "original mod-Timestamp",
+                            name, group_attrs);
+    if (ret != EOK) {
         goto fail;
     }
-    if (el->num_values == 0) {
-        DEBUG(7, ("Original mod-Timestamp is not available for [%s].\n",
-                  name));
-    } else {
-        ret = sysdb_attrs_add_string(group_attrs,
-                          opts->group_map[SDAP_AT_GROUP_MODSTAMP].sys_name,
-                          (const char*)el->values[0].data);
-        if (ret) {
-            goto fail;
-        }
-    }
 
     ret = sysdb_attrs_get_el(attrs,
                       opts->group_map[SDAP_AT_GROUP_USN].sys_name, &el);
@@ -369,20 +348,12 @@ static int sdap_save_group(TALLOC_CTX *memctx,
         }
     }
 
-    ret = sysdb_attrs_get_aliases(tmpctx, attrs, name, &aliases);
+    ret = sdap_save_all_names(name, attrs, group_attrs);
     if (ret != EOK) {
-        DEBUG(1, ("Failed to get the alias list\n"));
+        DEBUG(1, ("Failed to save user names\n"));
         goto fail;
     }
 
-    for (i = 0; aliases[i]; i++) {
-        ret = sysdb_attrs_add_string(group_attrs, SYSDB_NAME_ALIAS,
-                                        aliases[i]);
-        if (ret) {
-            goto fail;
-        }
-    }
-
     DEBUG(6, ("Storing info for group %s\n", name));
 
     ret = sdap_store_group_with_gid(ctx,
diff --git a/src/providers/ldap/sdap_async_netgroups.c b/src/providers/ldap/sdap_async_netgroups.c
index bb2e1bb2ce85b16e1437140cb841264d206ff7c0..2cc8d42ad4e7d47bbf020d932e605a6e3dc5a1db 100644
--- a/src/providers/ldap/sdap_async_netgroups.c
+++ b/src/providers/ldap/sdap_async_netgroups.c
@@ -48,7 +48,6 @@ static errno_t sdap_save_netgroup(TALLOC_CTX *memctx,
     const char *name = NULL;
     int ret;
     char *timestamp = NULL;
-    size_t c;
 
     ret = sysdb_attrs_get_el(attrs,
                              opts->netgroup_map[SDAP_AT_NETGROUP_NAME].sys_name,
@@ -66,21 +65,12 @@ static errno_t sdap_save_netgroup(TALLOC_CTX *memctx,
         goto fail;
     }
 
-    ret = sysdb_attrs_get_el(attrs, SYSDB_ORIG_DN, &el);
-    if (ret) {
+    ret = sdap_attrs_add_string(attrs, SYSDB_ORIG_DN,
+                                "original DN",
+                                name, netgroup_attrs);
+    if (ret != EOK) {
         goto fail;
     }
-    if (el->num_values == 0) {
-        DEBUG(7, ("Original DN is not available for [%s].\n", name));
-    } else {
-        DEBUG(7, ("Adding original DN [%s] to attributes of [%s].\n",
-                  el->values[0].data, name));
-        ret = sysdb_attrs_add_string(netgroup_attrs, SYSDB_ORIG_DN,
-                                     (const char *)el->values[0].data);
-        if (ret) {
-            goto fail;
-        }
-    }
 
     ret = sysdb_attrs_get_el(attrs,
                          opts->netgroup_map[SDAP_AT_NETGROUP_MODSTAMP].sys_name,
@@ -105,64 +95,27 @@ static errno_t sdap_save_netgroup(TALLOC_CTX *memctx,
         }
     }
 
-    ret = sysdb_attrs_get_el(attrs,
-                           opts->netgroup_map[SDAP_AT_NETGROUP_TRIPLE].sys_name,
-                           &el);
-    if (ret) {
+    ret = sdap_attrs_add_list(attrs,
+                        opts->netgroup_map[SDAP_AT_NETGROUP_TRIPLE].sys_name,
+                        "netgroup triple",
+                        name, netgroup_attrs);
+    if (ret != EOK) {
         goto fail;
     }
-    if (el->num_values == 0) {
-        DEBUG(7, ("No netgroup triples for netgroup [%s].\n", name));
-    } else {
-        for(c = 0; c < el->num_values; c++) {
-            ret = sysdb_attrs_add_string(netgroup_attrs,
-                           opts->netgroup_map[SDAP_AT_NETGROUP_TRIPLE].sys_name,
-                            (const char*)el->values[c].data);
-            if (ret) {
-                goto fail;
-            }
-        }
-    }
 
-    ret = sysdb_attrs_get_el(attrs,
-                       opts->netgroup_map[SDAP_AT_NETGROUP_MEMBER].sys_name,
-                       &el);
+    ret = sdap_attrs_add_list(attrs,
+                        opts->netgroup_map[SDAP_AT_NETGROUP_MEMBER].sys_name,
+                        "original members",
+                        name, netgroup_attrs);
     if (ret != EOK) {
         goto fail;
     }
-    if (el->num_values == 0) {
-        DEBUG(7, ("No original members for netgroup [%s]\n", name));
-
-    } else {
-        DEBUG(7, ("Adding original members to netgroup [%s]\n", name));
-        for(c = 0; c < el->num_values; c++) {
-            ret = sysdb_attrs_add_string(netgroup_attrs,
-                       opts->netgroup_map[SDAP_AT_NETGROUP_MEMBER].sys_name,
-                       (const char*)el->values[c].data);
-            if (ret) {
-                goto fail;
-            }
-        }
-    }
 
-
-    ret = sysdb_attrs_get_el(attrs, SYSDB_NETGROUP_MEMBER, &el);
+    ret = sdap_attrs_add_list(attrs, SYSDB_NETGROUP_MEMBER,
+                        "members", name, netgroup_attrs);
     if (ret != EOK) {
         goto fail;
     }
-    if (el->num_values == 0) {
-        DEBUG(7, ("No members for netgroup [%s]\n", name));
-
-    } else {
-        DEBUG(7, ("Adding members to netgroup [%s]\n", name));
-        for(c = 0; c < el->num_values; c++) {
-            ret = sysdb_attrs_add_string(netgroup_attrs, SYSDB_NETGROUP_MEMBER,
-                                         (const char*)el->values[c].data);
-            if (ret) {
-                goto fail;
-            }
-        }
-    }
 
     DEBUG(6, ("Storing info for netgroup %s\n", name));
 
diff --git a/src/providers/ldap/sdap_async_users.c b/src/providers/ldap/sdap_async_users.c
index cf9a8d33cbd4deac12287852cbe78ce465f0ac61..c929e2048b310803c26be619f48cbda5d7a6bfc1 100644
--- a/src/providers/ldap/sdap_async_users.c
+++ b/src/providers/ldap/sdap_async_users.c
@@ -29,7 +29,6 @@
 /* ==Save-User-Entry====================================================== */
 
 /* FIXME: support storing additional attributes */
-
 int sdap_save_user(TALLOC_CTX *memctx,
                    struct sysdb_ctx *ctx,
                    struct sdap_options *opts,
@@ -52,17 +51,14 @@ int sdap_save_user(TALLOC_CTX *memctx,
     struct sysdb_attrs *user_attrs;
     char *upn = NULL;
     size_t i;
-    char *val = NULL;
     int cache_timeout;
     char *usn_value = NULL;
-    size_t c;
     char **missing = NULL;
-    const char **aliases = NULL;
     TALLOC_CTX *tmpctx = NULL;
 
     DEBUG(9, ("Save user\n"));
 
-    tmpctx = talloc_new(memctx);
+    tmpctx = talloc_new(NULL);
     if (!tmpctx) {
         ret = ENOMEM;
         goto fail;
@@ -151,57 +147,27 @@ int sdap_save_user(TALLOC_CTX *memctx,
         goto fail;
     }
 
-    ret = sysdb_attrs_get_el(attrs, SYSDB_ORIG_DN, &el);
-    if (ret) {
+    ret = sdap_attrs_add_string(attrs, SYSDB_ORIG_DN,
+                                "original DN",
+                                name, user_attrs);
+    if (ret != EOK) {
         goto fail;
     }
-    if (el->num_values == 0) {
-        DEBUG(7, ("Original DN is not available for [%s].\n", name));
-    } else {
-        DEBUG(7, ("Adding original DN [%s] to attributes of [%s].\n",
-                  el->values[0].data, name));
-        ret = sysdb_attrs_add_string(user_attrs, SYSDB_ORIG_DN,
-                                     (const char *) el->values[0].data);
-        if (ret) {
-            goto fail;
-        }
-    }
 
-    ret = sysdb_attrs_get_el(attrs, SYSDB_MEMBEROF, &el);
-    if (ret) {
+    ret = sdap_attrs_add_list(attrs, SYSDB_MEMBEROF,
+                              "original memberOf",
+                              name, user_attrs);
+    if (ret != EOK) {
         goto fail;
     }
-    if (el->num_values == 0) {
-        DEBUG(7, ("Original memberOf is not available for [%s].\n",
-                  name));
-    } else {
-        DEBUG(7, ("Adding original memberOf attributes to [%s].\n",
-                  name));
-        for (i = 0; i < el->num_values; i++) {
-            ret = sysdb_attrs_add_string(user_attrs, SYSDB_ORIG_MEMBEROF,
-                                         (const char *) el->values[i].data);
-            if (ret) {
-                goto fail;
-            }
-        }
-    }
 
-    ret = sysdb_attrs_get_el(attrs,
-                      opts->user_map[SDAP_AT_USER_MODSTAMP].sys_name, &el);
-    if (ret) {
+    ret = sdap_attrs_add_string(attrs,
+                            opts->user_map[SDAP_AT_USER_MODSTAMP].sys_name,
+                            "original mod-Timestamp",
+                            name, user_attrs);
+    if (ret != EOK) {
         goto fail;
     }
-    if (el->num_values == 0) {
-        DEBUG(7, ("Original mod-Timestamp is not available for [%s].\n",
-                  name));
-    } else {
-        ret = sysdb_attrs_add_string(user_attrs,
-                          opts->user_map[SDAP_AT_USER_MODSTAMP].sys_name,
-                          (const char*)el->values[0].data);
-        if (ret) {
-            goto fail;
-        }
-    }
 
     ret = sysdb_attrs_get_el(attrs,
                       opts->user_map[SDAP_AT_USER_USN].sys_name, &el);
@@ -218,7 +184,7 @@ int sdap_save_user(TALLOC_CTX *memctx,
         if (ret) {
             goto fail;
         }
-        usn_value = talloc_strdup(memctx, (const char*)el->values[0].data);
+        usn_value = talloc_strdup(tmpctx, (const char*)el->values[0].data);
         if (!usn_value) {
             ret = ENOMEM;
             goto fail;
@@ -250,27 +216,11 @@ int sdap_save_user(TALLOC_CTX *memctx,
     }
 
     for (i = SDAP_FIRST_EXTRA_USER_AT; i < SDAP_OPTS_USER; i++) {
-        ret = sysdb_attrs_get_el(attrs, opts->user_map[i].sys_name, &el);
+        ret = sdap_attrs_add_list(attrs, opts->user_map[i].sys_name,
+                                  NULL, name, user_attrs);
         if (ret) {
             goto fail;
         }
-        if (el->num_values > 0) {
-            for (c = 0; c < el->num_values; c++) {
-                DEBUG(9, ("Adding [%s]=[%s] to user attributes.\n",
-                          opts->user_map[i].sys_name,
-                          (const char*) el->values[c].data));
-                val = talloc_strdup(user_attrs, (const char*) el->values[c].data);
-                if (val == NULL) {
-                    ret = ENOMEM;
-                    goto fail;
-                }
-                ret = sysdb_attrs_add_string(user_attrs,
-                                             opts->user_map[i].sys_name, val);
-                if (ret) {
-                    goto fail;
-                }
-            }
-        }
     }
 
     cache_timeout = dp_opt_get_int(opts->basic, SDAP_ENTRY_CACHE_TIMEOUT);
@@ -284,20 +234,12 @@ int sdap_save_user(TALLOC_CTX *memctx,
         }
     }
 
-    ret = sysdb_attrs_get_aliases(tmpctx, attrs, name, &aliases);
+    ret = sdap_save_all_names(name, attrs, user_attrs);
     if (ret != EOK) {
-        DEBUG(1, ("Failed to get the alias list"));
+        DEBUG(1, ("Failed to save user names\n"));
         goto fail;
     }
 
-    for (i = 0; aliases[i]; i++) {
-        ret = sysdb_attrs_add_string(user_attrs, SYSDB_NAME_ALIAS,
-                                     aliases[i]);
-        if (ret) {
-            goto fail;
-        }
-    }
-
     /* Make sure that any attributes we requested from LDAP that we
      * did not receive are also removed from the sysdb
      */
@@ -320,7 +262,7 @@ int sdap_save_user(TALLOC_CTX *memctx,
     if (ret) goto fail;
 
     if (_usn_value) {
-        *_usn_value = usn_value;
+        *_usn_value = talloc_steal(memctx, usn_value);
     }
 
     talloc_steal(memctx, user_attrs);
-- 
1.7.7.4

-------------- next part --------------
From b6790de31e85b4d1d81c9d620e8993a0364fb1ea Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Mon, 12 Dec 2011 18:47:27 +0100
Subject: [PATCH 6/9] sysdb_get_real_name helper function

---
 src/db/sysdb.c |   46 ++++++++++++++++++++++++++++++++++++++++++++++
 src/db/sysdb.h |    4 ++++
 2 files changed, 50 insertions(+), 0 deletions(-)

diff --git a/src/db/sysdb.c b/src/db/sysdb.c
index c49399f7df37d946b975a403ac522b9fbbb82c97..d66cc53ccfc407c6823a8aa96321ec1bf0c5e35c 100644
--- a/src/db/sysdb.c
+++ b/src/db/sysdb.c
@@ -1691,3 +1691,49 @@ done:
     }
     return ret;
 }
+
+errno_t sysdb_get_real_name(TALLOC_CTX *mem_ctx,
+                            struct sysdb_ctx *sysdb,
+                            const char *name,
+                            const char **_cname)
+{
+    errno_t ret;
+    TALLOC_CTX *tmp_ctx;
+    struct ldb_result *res;
+    const char *cname;
+
+    tmp_ctx = talloc_new(NULL);
+    if (!tmp_ctx) {
+        return ENOMEM;
+    }
+
+    ret = sysdb_getpwnam(tmp_ctx, sysdb, name, &res);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, ("Cannot canonicalize username\n"));
+        goto done;
+    }
+
+    if (res->count == 0) {
+        /* User is not cached yet */
+        ret = ENOENT;
+        goto done;
+    } else if (res->count != 1) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              ("sysdb_getpwnam returned count: [%d]\n", res->count));
+        ret = EIO;
+        goto done;
+    }
+
+    cname = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_NAME, NULL);
+    if (!cname) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("A user with no name?\n"));
+        ret = ENOENT;
+        goto done;
+    }
+
+    ret = EOK;
+    *_cname = talloc_steal(mem_ctx, cname);
+done:
+    talloc_free(tmp_ctx);
+    return ret;
+}
diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index 5fc36ab5a39542838354a29c54a17ff4541b5a98..e5e781f6acc2ae26d1d387d8b8c6931bb1213367 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -248,6 +248,10 @@ errno_t sysdb_attrs_primary_name_list(struct sysdb_ctx *sysdb,
                                       size_t attr_count,
                                       const char *ldap_attr,
                                       char ***name_list);
+errno_t sysdb_get_real_name(TALLOC_CTX *mem_ctx,
+                            struct sysdb_ctx *sysdb,
+                            const char *name,
+                            const char **_cname);
 
 /* convert an ldb error into an errno error */
 int sysdb_error_to_errno(int ldberr);
-- 
1.7.7.4

-------------- next part --------------
From 4f5fbc9964694ef4d7e2df1dffc0fc5cbc0ecbdd Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Tue, 6 Dec 2011 15:02:37 +0100
Subject: [PATCH 7/9] Use the case sensitivity flag in the LDAP provider

---
 src/db/sysdb.c                             |   36 ++++++++++++++++++++++++---
 src/db/sysdb.h                             |    1 +
 src/providers/ldap/sdap_async.c            |    9 ++++---
 src/providers/ldap/sdap_async.h            |    1 +
 src/providers/ldap/sdap_async_groups.c     |    4 +-
 src/providers/ldap/sdap_async_initgroups.c |   17 ++++++++++---
 src/providers/ldap/sdap_async_netgroups.c  |    9 +++++++
 src/providers/ldap/sdap_async_users.c      |    2 +-
 8 files changed, 64 insertions(+), 15 deletions(-)

diff --git a/src/db/sysdb.c b/src/db/sysdb.c
index d66cc53ccfc407c6823a8aa96321ec1bf0c5e35c..1bf0e7f1fdd5b74afa206333766786d79b11f2d9 100644
--- a/src/db/sysdb.c
+++ b/src/db/sysdb.c
@@ -22,6 +22,7 @@
 
 #include "util/util.h"
 #include "util/strtonum.h"
+#include "util/sss_utf8.h"
 #include "db/sysdb_private.h"
 #include "confdb/confdb.h"
 #include <time.h>
@@ -1587,18 +1588,22 @@ done:
  * Given a primary name returned by sysdb_attrs_primary_name(), this function
  * returns the other SYSDB_NAME attribute values so they can be saved as
  * SYSDB_NAME_ALIAS into cache.
+ *
+ * If lowercase is set, all aliases are duplicated in lowercase as well.
  */
 errno_t sysdb_attrs_get_aliases(TALLOC_CTX *mem_ctx,
                                 struct sysdb_attrs *attrs,
                                 const char *primary,
+                                bool lowercase,
                                 const char ***_aliases)
 {
     TALLOC_CTX *tmp_ctx = NULL;
     struct ldb_message_element *sysdb_name_el;
-    size_t i, ai;
+    size_t i, ai, num;
     errno_t ret;
     const char **aliases = NULL;
     const char *name;
+    char *lower;
 
     if (_aliases == NULL) return EINVAL;
 
@@ -1615,8 +1620,8 @@ errno_t sysdb_attrs_get_aliases(TALLOC_CTX *mem_ctx,
         goto done;
     }
 
-    aliases = talloc_array(tmp_ctx, const char *,
-                           sysdb_name_el->num_values);
+    num = lowercase ? 2 * sysdb_name_el->num_values : sysdb_name_el->num_values;
+    aliases = talloc_array(tmp_ctx, const char *, num+1);
     if (!aliases) {
         ret = ENOMEM;
         goto done;
@@ -1626,11 +1631,34 @@ errno_t sysdb_attrs_get_aliases(TALLOC_CTX *mem_ctx,
     for (i=0; i < sysdb_name_el->num_values; i++) {
         name = (const char *)sysdb_name_el->values[i].data;
         if (strcmp(primary, name) != 0) {
-            aliases[ai] = name;
+            aliases[ai] = talloc_strdup(aliases, name);
+            if (!aliases[ai]) {
+                ret = ENOMEM;
+                goto done;
+            }
             ai++;
         }
     }
 
+    if (lowercase) {
+        DEBUG(SSSDBG_TRACE_INTERNAL,
+              ("Domain is case-insensitive; will add lowercased aliases\n"));
+        for (i=0; i < sysdb_name_el->num_values; i++) {
+            name = (const char *)sysdb_name_el->values[i].data;
+            lower = sss_tc_utf8_tolower(tmp_ctx, name);
+            if (!lower) {
+                ret = ENOMEM;
+                goto done;
+            }
+
+            if (strcmp(name, lower) != 0) {
+                aliases[ai] = talloc_strdup(aliases, lower);
+                ai++;
+            }
+            talloc_free(lower);
+        }
+    }
+
     aliases[ai] = NULL;
     ret = EOK;
 done:
diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index e5e781f6acc2ae26d1d387d8b8c6931bb1213367..6094a4aaab2c9453f4de40075abb3ec6e321c3b9 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -241,6 +241,7 @@ errno_t sysdb_attrs_primary_name(struct sysdb_ctx *sysdb,
 errno_t sysdb_attrs_get_aliases(TALLOC_CTX *mem_ctx,
                                 struct sysdb_attrs *attrs,
                                 const char *primary,
+                                bool lowercase,
                                 const char ***_aliases);
 errno_t sysdb_attrs_primary_name_list(struct sysdb_ctx *sysdb,
                                       TALLOC_CTX *mem_ctx,
diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c
index 98291e6e2e8ac13fe244c8cb1f332df30e20aa4e..0719f74be6b8b167f00a69abcd13a98ea36fc2e1 100644
--- a/src/providers/ldap/sdap_async.c
+++ b/src/providers/ldap/sdap_async.c
@@ -1920,7 +1920,8 @@ errno_t sdap_check_aliases(struct sysdb_ctx *sysdb,
         goto done;
     }
 
-    ret = sysdb_attrs_get_aliases(tmp_ctx, user_attrs, name, &aliases);
+    ret = sysdb_attrs_get_aliases(tmp_ctx, user_attrs, name,
+                                  !dom->case_sensitive, &aliases);
     if (ret != EOK) {
         DEBUG(1, ("Failed to get the alias list\n"));
         goto done;
@@ -2024,10 +2025,10 @@ sdap_attrs_add_ldap_attr(struct sysdb_attrs *ldap_attrs,
     return EOK;
 }
 
-
 errno_t
 sdap_save_all_names(const char *name,
                     struct sysdb_attrs *ldap_attrs,
+                    bool lowercase,
                     struct sysdb_attrs *attrs)
 {
     const char **aliases = NULL;
@@ -2041,7 +2042,8 @@ sdap_save_all_names(const char *name,
         goto done;
     }
 
-    ret = sysdb_attrs_get_aliases(tmp_ctx, ldap_attrs, name, &aliases);
+    ret = sysdb_attrs_get_aliases(tmp_ctx, ldap_attrs, name,
+                                  lowercase, &aliases);
     if (ret != EOK) {
         DEBUG(SSSDBG_OP_FAILURE, ("Failed to get the alias list"));
         goto done;
@@ -2062,4 +2064,3 @@ done:
     talloc_free(tmp_ctx);
     return ret;
 }
-
diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h
index f53af1e01e683ac0918f8ee5d74e1c19713c4bb7..2fd606bcaa52d557dee4c85782df0e2b4e6c6522 100644
--- a/src/providers/ldap/sdap_async.h
+++ b/src/providers/ldap/sdap_async.h
@@ -208,6 +208,7 @@ sdap_attrs_add_ldap_attr(struct sysdb_attrs *ldap_attrs,
 
 errno_t sdap_save_all_names(const char *name,
                             struct sysdb_attrs *ldap_attrs,
+                            bool lowercase,
                             struct sysdb_attrs *attrs);
 
 #endif /* _SDAP_ASYNC_H_ */
diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c
index d2c15dedaf7417d97a91a587bc1145b21c3ebf92..357c28c191df1c01dbf3cdb2a11feb11aee86d29 100644
--- a/src/providers/ldap/sdap_async_groups.c
+++ b/src/providers/ldap/sdap_async_groups.c
@@ -348,9 +348,9 @@ static int sdap_save_group(TALLOC_CTX *memctx,
         }
     }
 
-    ret = sdap_save_all_names(name, attrs, group_attrs);
+    ret = sdap_save_all_names(name, attrs, !dom->case_sensitive, group_attrs);
     if (ret != EOK) {
-        DEBUG(1, ("Failed to save user names\n"));
+        DEBUG(1, ("Failed to save group names\n"));
         goto fail;
     }
 
diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c
index 631ce1522803103e7ea962003562e2a7dcb2fffc..73ab25ea79cd66ff5fe7131ee7606cf71aa382e5 100644
--- a/src/providers/ldap/sdap_async_initgroups.c
+++ b/src/providers/ldap/sdap_async_initgroups.c
@@ -444,8 +444,9 @@ static void sdap_initgr_rfc2307_process(struct tevent_req *subreq)
     /* Search for all groups for which this user is a member */
     attrs[0] = SYSDB_MEMBEROF;
     attrs[1] = NULL;
-    ret = sysdb_search_user_by_name(state, state->sysdb, state->name, attrs,
-                                    &msg);
+
+    ret = sysdb_search_user_by_name(state, state->sysdb, state->name,
+                                    attrs, &msg);
     if (ret != EOK) {
         tevent_req_error(req, ret);
         return;
@@ -2462,6 +2463,7 @@ static void sdap_get_initgr_user(struct tevent_req *subreq)
     size_t count;
     int ret;
     const char *orig_dn;
+    const char *cname;
 
     DEBUG(9, ("Receiving info for the user\n"));
 
@@ -2520,6 +2522,13 @@ static void sdap_get_initgr_user(struct tevent_req *subreq)
         return;
     }
 
+    ret = sysdb_get_real_name(state, state->sysdb, state->name, &cname);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, ("Cannot canonicalize username\n"));
+        tevent_req_error(req, ret);
+        return;
+    }
+
     DEBUG(9, ("Process user's groups\n"));
 
     switch (state->opts->schema_type) {
@@ -2533,7 +2542,7 @@ static void sdap_get_initgr_user(struct tevent_req *subreq)
 
         subreq = sdap_initgr_rfc2307_send(state, state->ev, state->opts,
                                           state->sysdb, state->sh,
-                                          state->name);
+                                          cname);
         if (!subreq) {
             tevent_req_error(req, ENOMEM);
             return;
@@ -2553,7 +2562,7 @@ static void sdap_get_initgr_user(struct tevent_req *subreq)
         subreq = sdap_initgr_rfc2307bis_send(
                 state, state->ev, state->opts, state->sysdb,
                 state->dom, state->sh,
-                state->name, orig_dn);
+                cname, orig_dn);
         if (!subreq) {
             tevent_req_error(req, ENOMEM);
             return;
diff --git a/src/providers/ldap/sdap_async_netgroups.c b/src/providers/ldap/sdap_async_netgroups.c
index 2cc8d42ad4e7d47bbf020d932e605a6e3dc5a1db..2a24128a9b3a1594813346fea98503b9a9af432b 100644
--- a/src/providers/ldap/sdap_async_netgroups.c
+++ b/src/providers/ldap/sdap_async_netgroups.c
@@ -38,6 +38,7 @@ bool is_dn(const char *str)
 
 static errno_t sdap_save_netgroup(TALLOC_CTX *memctx,
                                   struct sysdb_ctx *ctx,
+                                  struct sss_domain_info *dom,
                                   struct sdap_options *opts,
                                   struct sysdb_attrs *attrs,
                                   char **_timestamp,
@@ -119,6 +120,13 @@ static errno_t sdap_save_netgroup(TALLOC_CTX *memctx,
 
     DEBUG(6, ("Storing info for netgroup %s\n", name));
 
+    ret = sdap_save_all_names(name, attrs, !dom->case_sensitive,
+                              netgroup_attrs);
+    if (ret != EOK) {
+        DEBUG(1, ("Failed to save netgroup names\n"));
+        goto fail;
+    }
+
     ret = sysdb_add_netgroup(ctx, name, NULL, netgroup_attrs,
                              dp_opt_get_int(opts->basic,
                                             SDAP_ENTRY_CACHE_TIMEOUT), now);
@@ -671,6 +679,7 @@ static void netgr_translate_members_done(struct tevent_req *subreq)
     now = time(NULL);
     for (c = 0; c < state->count; c++) {
         ret = sdap_save_netgroup(state, state->sysdb,
+                                 state->dom,
                                  state->opts,
                                  state->netgroups[c],
                                  &state->higher_timestamp,
diff --git a/src/providers/ldap/sdap_async_users.c b/src/providers/ldap/sdap_async_users.c
index c929e2048b310803c26be619f48cbda5d7a6bfc1..cccf75b8caecd34ba6d562e2e8b8e7e3d0e18e49 100644
--- a/src/providers/ldap/sdap_async_users.c
+++ b/src/providers/ldap/sdap_async_users.c
@@ -234,7 +234,7 @@ int sdap_save_user(TALLOC_CTX *memctx,
         }
     }
 
-    ret = sdap_save_all_names(name, attrs, user_attrs);
+    ret = sdap_save_all_names(name, attrs, !dom->case_sensitive, user_attrs);
     if (ret != EOK) {
         DEBUG(1, ("Failed to save user names\n"));
         goto fail;
-- 
1.7.7.4

-------------- next part --------------
From ebba942cdd9393ffdfeefcd29290992898d07465 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Tue, 6 Dec 2011 17:08:27 +0100
Subject: [PATCH 8/9] Use the case sensitivity flag in the simple access
 provider

---
 src/providers/simple/simple_access.c |   12 ++++++++----
 src/tests/simple_access-tests.c      |   30 ++++++++++++++++++++++++++++++
 2 files changed, 38 insertions(+), 4 deletions(-)

diff --git a/src/providers/simple/simple_access.c b/src/providers/simple/simple_access.c
index 4b9c3139853adc2c65eb65af69199f820a75ca89..614a8b40b3da366eb73691706e88e8c059d4a1ab 100644
--- a/src/providers/simple/simple_access.c
+++ b/src/providers/simple/simple_access.c
@@ -34,6 +34,8 @@
 #define CONFDB_SIMPLE_ALLOW_GROUPS "simple_allow_groups"
 #define CONFDB_SIMPLE_DENY_GROUPS "simple_deny_groups"
 
+typedef int (*strcmp_fn_t)(const char *, const char *);
+
 errno_t simple_access_check(struct simple_ctx *ctx, const char *username,
                             bool *access_granted)
 {
@@ -51,13 +53,15 @@ errno_t simple_access_check(struct simple_ctx *ctx, const char *username,
     const char *primary_group;
     gid_t gid;
     bool matched;
+    strcmp_fn_t string_compare;
 
+    string_compare = ctx->domain->case_sensitive ? strcmp : strcasecmp;
     *access_granted = false;
 
     /* First, check whether the user is in the allowed users list */
     if (ctx->allow_users != NULL) {
         for(i = 0; ctx->allow_users[i] != NULL; i++) {
-            if (strcmp(username, ctx->allow_users[i]) == 0) {
+            if (string_compare(username, ctx->allow_users[i]) == 0) {
                 DEBUG(9, ("User [%s] found in allow list, access granted.\n",
                       username));
 
@@ -78,7 +82,7 @@ errno_t simple_access_check(struct simple_ctx *ctx, const char *username,
     /* Next check whether this user has been specifically denied */
     if (ctx->deny_users != NULL) {
         for(i = 0; ctx->deny_users[i] != NULL; i++) {
-            if (strcmp(username, ctx->deny_users[i]) == 0) {
+            if (string_compare(username, ctx->deny_users[i]) == 0) {
                 DEBUG(9, ("User [%s] found in deny list, access denied.\n",
                       username));
 
@@ -189,7 +193,7 @@ errno_t simple_access_check(struct simple_ctx *ctx, const char *username,
         matched = false;
         for (i = 0; ctx->allow_groups[i]; i++) {
             for(j = 0; groups[j]; j++) {
-                if (strcmp(groups[j], ctx->allow_groups[i])== 0) {
+                if (string_compare(groups[j], ctx->allow_groups[i])== 0) {
                     matched = true;
                     break;
                 }
@@ -210,7 +214,7 @@ errno_t simple_access_check(struct simple_ctx *ctx, const char *username,
         matched = false;
         for (i = 0; ctx->deny_groups[i]; i++) {
             for(j = 0; groups[j]; j++) {
-                if (strcmp(groups[j], ctx->deny_groups[i])== 0) {
+                if (string_compare(groups[j], ctx->deny_groups[i])== 0) {
                     matched = true;
                     break;
                 }
diff --git a/src/tests/simple_access-tests.c b/src/tests/simple_access-tests.c
index 9cd73d84c91b29fcc5a43bf12e22696d74aae545..5fa62a89b920b28f644398ac33bb31e204890af9 100644
--- a/src/tests/simple_access-tests.c
+++ b/src/tests/simple_access-tests.c
@@ -26,6 +26,7 @@
 #include <popt.h>
 #include <check.h>
 
+#include "confdb/confdb.h"
 #include "providers/simple/simple_access.h"
 
 const char *ulist_1[] = {"u1", "u2", NULL};
@@ -37,6 +38,10 @@ void setup_simple(void)
     fail_unless(ctx == NULL, "Simple context already initialized.");
     ctx = talloc_zero(NULL, struct simple_ctx);
     fail_unless(ctx != NULL, "Cannot create simple context.");
+
+    ctx->domain = talloc_zero(ctx, struct sss_domain_info);
+    fail_unless(ctx != NULL, "Cannot create domain in simple context.");
+    ctx->domain->case_sensitive = true;
 }
 
 void teardown_simple(void)
@@ -123,6 +128,30 @@ START_TEST(test_both_set)
 }
 END_TEST
 
+START_TEST(test_case)
+{
+    int ret;
+    bool access_granted = false;
+
+    ctx->allow_users = discard_const(ulist_1);
+    ctx->deny_users = discard_const(ulist_1);
+
+    ret = simple_access_check(ctx, "U1", &access_granted);
+    fail_unless(ret == EOK, "access_simple_check failed.");
+    fail_unless(access_granted == false, "Access granted "
+                                         "for user with different case "
+                                         "in case-sensitive domain");
+
+    ctx->domain->case_sensitive = false;
+
+    ret = simple_access_check(ctx, "U1", &access_granted);
+    fail_unless(ret == EOK, "access_simple_check failed.");
+    fail_unless(access_granted == false, "Access denied "
+                                         "for user with different case "
+                                         "in case-insensitive domain");
+}
+END_TEST
+
 Suite *access_simple_suite (void)
 {
     Suite *s = suite_create("access_simple");
@@ -133,6 +162,7 @@ Suite *access_simple_suite (void)
     tcase_add_test(tc_allow_deny, test_allow_empty);
     tcase_add_test(tc_allow_deny, test_deny_empty);
     tcase_add_test(tc_allow_deny, test_both_set);
+    tcase_add_test(tc_allow_deny, test_case);
     suite_add_tcase(s, tc_allow_deny);
 
     return s;
-- 
1.7.7.4

-------------- next part --------------
From b80d5bf8f12ff1af0ef62e489e5c62d7c572d6d1 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Mon, 12 Dec 2011 15:28:13 +0100
Subject: [PATCH 9/9] Use the case sensitivity flag in the proxy provider

---
 src/providers/proxy/proxy.h          |    2 +-
 src/providers/proxy/proxy_id.c       |  294 +++++++++++++++++-----------------
 src/providers/proxy/proxy_netgroup.c |   38 ++++-
 3 files changed, 181 insertions(+), 153 deletions(-)

diff --git a/src/providers/proxy/proxy.h b/src/providers/proxy/proxy.h
index c75242890f9683d80c0ec8892a7d23326ffa78a2..41981fd85f44fa4cdfa40cc2833b972d82cdb5ab 100644
--- a/src/providers/proxy/proxy.h
+++ b/src/providers/proxy/proxy.h
@@ -142,7 +142,7 @@ void proxy_pam_handler(struct be_req *req);
 /* From proxy_netgroup.c */
 errno_t get_netgroup(struct proxy_id_ctx *ctx,
                      struct sysdb_ctx *sysdb,
+                     struct sss_domain_info *dom,
                      const char *name);
 
-
 #endif /* __PROXY_H__ */
diff --git a/src/providers/proxy/proxy_id.c b/src/providers/proxy/proxy_id.c
index 0a5f5427e8758c8d8f4db023ac4ef60c70f2e39d..61043d7e87c6e5ea229b311182bb0aa4c70fc88c 100644
--- a/src/providers/proxy/proxy_id.c
+++ b/src/providers/proxy/proxy_id.c
@@ -30,6 +30,9 @@
 static int delete_user(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb,
                        struct sss_domain_info *domain, const char *name);
 
+static int save_user(struct sysdb_ctx *sysdb, bool lowercase,
+                     struct passwd *pwd, uint64_t cache_timeout);
+
 static int get_pw_name(TALLOC_CTX *mem_ctx,
                        struct proxy_id_ctx *ctx,
                        struct sysdb_ctx *sysdb,
@@ -42,7 +45,6 @@ static int get_pw_name(TALLOC_CTX *mem_ctx,
     char *buffer;
     size_t buflen;
     int ret;
-    const char *shell;
 
     DEBUG(7, ("Searching user by name (%s)\n", name));
 
@@ -98,23 +100,7 @@ static int get_pw_name(TALLOC_CTX *mem_ctx,
             break;
         }
 
-        if (pwd->pw_shell && pwd->pw_shell[0] != '\0') {
-            shell = pwd->pw_shell;
-        } else {
-            shell = NULL;
-        }
-
-        ret = sysdb_store_user(sysdb,
-                               pwd->pw_name,
-                               pwd->pw_passwd,
-                               pwd->pw_uid,
-                               pwd->pw_gid,
-                               pwd->pw_gecos,
-                               pwd->pw_dir,
-                               shell,
-                               NULL, NULL,
-                               ctx->entry_cache_timeout,
-                               0);
+        ret = save_user(sysdb, !dom->case_sensitive, pwd, ctx->entry_cache_timeout);
         if (ret) {
             goto done;
         }
@@ -139,6 +125,63 @@ done:
     return ret;
 }
 
+static int save_user(struct sysdb_ctx *sysdb, bool lowercase,
+                     struct passwd *pwd, uint64_t cache_timeout)
+{
+    const char *shell;
+    char *lower;
+    struct sysdb_attrs *attrs;
+    errno_t ret;
+
+    if (pwd->pw_shell && pwd->pw_shell[0] != '\0') {
+        shell = pwd->pw_shell;
+    } else {
+        shell = NULL;
+    }
+
+    if (lowercase) {
+        attrs = sysdb_new_attrs(NULL);
+        if (!attrs) {
+            DEBUG(SSSDBG_CRIT_FAILURE, ("Allocation error ?!\n"));
+            return ENOMEM;
+        }
+
+        lower = sss_tc_utf8_tolower(attrs, pwd->pw_name);
+        if (!lower) {
+            DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot convert name to lowercase\n"));
+            talloc_zfree(attrs);
+            return ENOMEM;
+        }
+
+        ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, lower);
+        if (ret) {
+            DEBUG(SSSDBG_OP_FAILURE, ("Could not add name alias\n"));
+            talloc_zfree(attrs);
+            return ret;
+        }
+    }
+
+    ret = sysdb_store_user(sysdb,
+                           pwd->pw_name,
+                           pwd->pw_passwd,
+                           pwd->pw_uid,
+                           pwd->pw_gid,
+                           pwd->pw_gecos,
+                           pwd->pw_dir,
+                           shell,
+                           attrs,
+                           NULL,
+                           cache_timeout,
+                           0);
+    talloc_zfree(attrs);
+    if (ret) {
+        DEBUG(SSSDBG_OP_FAILURE, ("Could not add user to cache\n"));
+        return ret;
+    }
+
+    return EOK;
+}
+
 static int delete_user(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb,
                        struct sss_domain_info *domain, const char *name)
 {
@@ -170,7 +213,6 @@ static int get_pw_uid(TALLOC_CTX *mem_ctx,
     size_t buflen;
     bool del_user = false;
     int ret;
-    const char *shell;
 
     DEBUG(7, ("Searching user by uid (%d)\n", uid));
 
@@ -221,23 +263,7 @@ static int get_pw_uid(TALLOC_CTX *mem_ctx,
             break;
         }
 
-        if (pwd->pw_shell && pwd->pw_shell[0] != '\0') {
-            shell = pwd->pw_shell;
-        } else {
-            shell = NULL;
-        }
-
-        ret = sysdb_store_user(sysdb,
-                               pwd->pw_name,
-                               pwd->pw_passwd,
-                               pwd->pw_uid,
-                               pwd->pw_gid,
-                               pwd->pw_gecos,
-                               pwd->pw_dir,
-                               shell,
-                               NULL, NULL,
-                               ctx->entry_cache_timeout,
-                               0);
+        ret = save_user(sysdb, !dom->case_sensitive, pwd, ctx->entry_cache_timeout);
         if (ret) {
             goto done;
         }
@@ -286,7 +312,6 @@ static int enum_users(TALLOC_CTX *mem_ctx,
     char *buffer;
     char *newbuf;
     int ret;
-    const char *shell;
 
     DEBUG(7, ("Enumerating users\n"));
 
@@ -369,23 +394,7 @@ again:
             goto again; /* skip */
         }
 
-        if (pwd->pw_shell && pwd->pw_shell[0] != '\0') {
-            shell = pwd->pw_shell;
-        } else {
-            shell = NULL;
-        }
-
-        ret = sysdb_store_user(sysdb,
-                               pwd->pw_name,
-                               pwd->pw_passwd,
-                               pwd->pw_uid,
-                               pwd->pw_gid,
-                               pwd->pw_gecos,
-                               pwd->pw_dir,
-                               shell,
-                               NULL, NULL,
-                               ctx->entry_cache_timeout,
-                               0);
+        ret = save_user(sysdb, !dom->case_sensitive, pwd, ctx->entry_cache_timeout);
         if (ret) {
             /* Do not fail completely on errors.
              * Just report the failure to save and go on */
@@ -415,8 +424,7 @@ done:
     return ret;
 }
 
-/* =Getgrnam-wrapper======================================================*/
-
+/* =Save-group-utilities=================================================*/
 #define DEBUG_GR_MEM(level, grp) \
     do { \
         if (DEBUG_IS_SET(debug_get_level(level))) { \
@@ -435,6 +443,81 @@ done:
         } \
     } while(0)
 
+static int save_group(struct sysdb_ctx *sysdb, struct sss_domain_info *dom,
+                      struct group *grp, uint64_t cache_timeout)
+{
+    errno_t ret;
+    struct sysdb_attrs *attrs = NULL;
+    char *lower;
+    TALLOC_CTX *tmp_ctx;
+
+    tmp_ctx = talloc_new(NULL);
+    if (!tmp_ctx) {
+        return ENOMEM;
+    }
+
+    DEBUG_GR_MEM(7, grp);
+
+    if (grp->gr_mem && grp->gr_mem[0]) {
+        attrs = sysdb_new_attrs(tmp_ctx);
+        if (!attrs) {
+            DEBUG(SSSDBG_CRIT_FAILURE, ("Allocation error ?!\n"));
+            ret = ENOMEM;
+            goto done;
+        }
+
+        ret = sysdb_attrs_users_from_str_list(
+                attrs, SYSDB_MEMBER, dom->name,
+                (const char *const *)grp->gr_mem);
+        if (ret) {
+            DEBUG(SSSDBG_OP_FAILURE, ("Could not add group members\n"));
+            goto done;
+        }
+    }
+
+    if (dom->case_sensitive == false) {
+        if (!attrs) {
+            attrs = sysdb_new_attrs(tmp_ctx);
+            if (!attrs) {
+                DEBUG(SSSDBG_CRIT_FAILURE, ("Allocation error ?!\n"));
+                ret = ENOMEM;
+                goto done;
+            }
+        }
+
+        lower = sss_tc_utf8_tolower(attrs, grp->gr_name);
+        if (!lower) {
+            DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot convert name to lowercase\n"));
+            ret = ENOMEM;
+            goto done;
+        }
+
+        ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, lower);
+        if (ret) {
+            DEBUG(SSSDBG_OP_FAILURE, ("Could not add name alias\n"));
+            ret = ENOMEM;
+            goto done;
+        }
+    }
+
+    ret = sysdb_store_group(sysdb,
+                            grp->gr_name,
+                            grp->gr_gid,
+                            attrs,
+                            cache_timeout,
+                            0);
+    if (ret) {
+        DEBUG(SSSDBG_OP_FAILURE, ("Could not add group to cache\n"));
+        goto done;
+    }
+
+    ret = EOK;
+done:
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
+/* =Getgrnam-wrapper======================================================*/
 static int get_gr_name(TALLOC_CTX *mem_ctx,
                        struct proxy_id_ctx *ctx,
                        struct sysdb_ctx *sysdb,
@@ -448,7 +531,6 @@ static int get_gr_name(TALLOC_CTX *mem_ctx,
     char *newbuf;
     size_t buflen;
     bool delete_group = false;
-    struct sysdb_attrs *members;
     int ret;
 
     DEBUG(7, ("Searching group by name (%s)\n", name));
@@ -521,30 +603,7 @@ again:
             break;
         }
 
-        DEBUG_GR_MEM(7, grp);
-
-        if (grp->gr_mem && grp->gr_mem[0]) {
-            members = sysdb_new_attrs(tmpctx);
-            if (!members) {
-                ret = ENOMEM;
-                goto done;
-            }
-            ret = sysdb_attrs_users_from_str_list(
-                    members, SYSDB_MEMBER, dom->name,
-                    (const char *const *)grp->gr_mem);
-            if (ret) {
-                goto done;
-            }
-        } else {
-            members = NULL;
-        }
-
-        ret = sysdb_store_group(sysdb,
-                                grp->gr_name,
-                                grp->gr_gid,
-                                members,
-                                ctx->entry_cache_timeout,
-                                0);
+        ret = save_group(sysdb, dom, grp, ctx->entry_cache_timeout);
         if (ret) {
             goto done;
         }
@@ -603,7 +662,6 @@ static int get_gr_gid(TALLOC_CTX *mem_ctx,
     char *newbuf;
     size_t buflen;
     bool delete_group = false;
-    struct sysdb_attrs *members;
     int ret;
 
     DEBUG(7, ("Searching group by gid (%d)\n", gid));
@@ -674,30 +732,7 @@ again:
             break;
         }
 
-        DEBUG_GR_MEM(7, grp);
-
-        if (grp->gr_mem && grp->gr_mem[0]) {
-            members = sysdb_new_attrs(tmpctx);
-            if (!members) {
-                ret = ENOMEM;
-                goto done;
-            }
-            ret = sysdb_attrs_users_from_str_list(
-                    members, SYSDB_MEMBER, dom->name,
-                    (const char *const *)grp->gr_mem);
-            if (ret) {
-                goto done;
-            }
-        } else {
-            members = NULL;
-        }
-
-        ret = sysdb_store_group(sysdb,
-                                grp->gr_name,
-                                grp->gr_gid,
-                                members,
-                                ctx->entry_cache_timeout,
-                                now);
+        ret = save_group(sysdb, dom, grp, ctx->entry_cache_timeout);
         if (ret) {
             goto done;
         }
@@ -746,7 +781,6 @@ static int enum_groups(TALLOC_CTX *mem_ctx,
     enum nss_status status;
     size_t buflen;
     char *buffer;
-    struct sysdb_attrs *members;
     char *newbuf;
     int ret;
 
@@ -830,30 +864,7 @@ again:
             goto again; /* skip */
         }
 
-        DEBUG_GR_MEM(7, grp);
-
-        if (grp->gr_mem && grp->gr_mem[0]) {
-            members = sysdb_new_attrs(tmpctx);
-            if (!members) {
-                ret = ENOMEM;
-                goto done;
-            }
-            ret = sysdb_attrs_users_from_str_list(
-                    members, SYSDB_MEMBER, dom->name,
-                    (const char *const *)grp->gr_mem);
-            if (ret) {
-                goto done;
-            }
-        } else {
-            members = NULL;
-        }
-
-        ret = sysdb_store_group(sysdb,
-                                grp->gr_name,
-                                grp->gr_gid,
-                                members,
-                                ctx->entry_cache_timeout,
-                                0);
+        ret = save_group(sysdb, dom, grp, ctx->entry_cache_timeout);
         if (ret) {
             /* Do not fail completely on errors.
              * Just report the failure to save and go on */
@@ -904,7 +915,6 @@ static int get_initgr(TALLOC_CTX *mem_ctx,
     char *buffer;
     size_t buflen;
     int ret;
-    const char *shell;
 
     tmpctx = talloc_new(mem_ctx);
     if (!tmpctx) {
@@ -957,23 +967,7 @@ static int get_initgr(TALLOC_CTX *mem_ctx,
             break;
         }
 
-        if (pwd->pw_shell && pwd->pw_shell[0] != '\0') {
-            shell = pwd->pw_shell;
-        } else {
-            shell = NULL;
-        }
-
-        ret = sysdb_store_user(sysdb,
-                               pwd->pw_name,
-                               pwd->pw_passwd,
-                               pwd->pw_uid,
-                               pwd->pw_gid,
-                               pwd->pw_gecos,
-                               pwd->pw_dir,
-                               shell,
-                               NULL, NULL,
-                               ctx->entry_cache_timeout,
-                               0);
+        ret = save_user(sysdb, !dom->case_sensitive, pwd, ctx->entry_cache_timeout);
         if (ret) {
             goto done;
         }
@@ -1176,7 +1170,7 @@ void proxy_get_account_info(struct be_req *breq)
                                ENODEV, "Netgroups are not supported");
         }
 
-        ret = get_netgroup(ctx, sysdb, ar->filter_value);
+        ret = get_netgroup(ctx, sysdb, domain, ar->filter_value);
         break;
 
     default: /*fail*/
diff --git a/src/providers/proxy/proxy_netgroup.c b/src/providers/proxy/proxy_netgroup.c
index d0dd819e7ec23be71a30620914678a6389cc9727..c9cee33011d385a8bda477fc66a063f1aa89ee29 100644
--- a/src/providers/proxy/proxy_netgroup.c
+++ b/src/providers/proxy/proxy_netgroup.c
@@ -63,8 +63,42 @@ static errno_t make_netgroup_attr(struct __netgrent netgrent,
     return EOK;
 }
 
+static errno_t save_netgroup(struct sysdb_ctx *sysdb,
+                             const char *name,
+                             struct sysdb_attrs *attrs,
+                             bool lowercase,
+                             uint64_t cache_timeout)
+{
+    errno_t ret;
+    char *lower;
+
+    if (lowercase) {
+        lower = sss_tc_utf8_tolower(NULL, name);
+        if (!lower) {
+            DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot convert name to lowercase\n"));
+            return ENOMEM;
+        }
+
+        ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, lower);
+        talloc_free(lower);
+        if (ret) {
+            DEBUG(SSSDBG_OP_FAILURE, ("Could not add name alias\n"));
+            return ret;
+        }
+    }
+
+    ret = sysdb_add_netgroup(sysdb, name, NULL, attrs, cache_timeout, 0);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, ("sysdb_add_netgroup failed.\n"));
+        return ret;
+    }
+
+    return EOK;
+}
+
 errno_t get_netgroup(struct proxy_id_ctx *ctx,
                      struct sysdb_ctx *sysdb,
+                     struct sss_domain_info *dom,
                      const char *name)
 {
     struct __netgrent result;
@@ -117,8 +151,8 @@ errno_t get_netgroup(struct proxy_id_ctx *ctx,
         goto done;
     }
 
-    ret = sysdb_add_netgroup(sysdb, name, NULL, attrs,
-                             ctx->entry_cache_timeout, 0);
+    ret = save_netgroup(sysdb, name, attrs,
+                        !dom->case_sensitive, ctx->entry_cache_timeout);
     if (ret != EOK) {
         DEBUG(1, ("sysdb_add_netgroup failed.\n"));
         goto done;
-- 
1.7.7.4



More information about the sssd-devel mailing list