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

Jakub Hrozek jhrozek at redhat.com
Thu Dec 8 10:02:05 UTC 2011


[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.

[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

[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.

[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.

[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.

[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.
-------------- next part --------------
From fdd86bdf62e38e8db9d70ab19f157b45c4a2a9a6 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/6] sss_utf8_tolower utility function+unit tests

---
 src/tests/util-tests.c |   59 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/util/sss_utf8.c    |   48 +++++++++++++++++++++++++++++++++++++++
 src/util/sss_utf8.h    |    4 +++
 3 files changed, 111 insertions(+), 0 deletions(-)

diff --git a/src/tests/util-tests.c b/src/tests/util-tests.c
index 52d3027..cf9edd9 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,56 @@ 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 };
+    const uint8_t *lcase;
+    TALLOC_CTX *test_ctx;
+
+    test_ctx = talloc_new(NULL);
+
+    lcase = sss_utf8_tolower(test_ctx, 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 +375,15 @@ 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_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.c b/src/util/sss_utf8.c
index 4a98233..2cfd56d 100644
--- a/src/util/sss_utf8.c
+++ b/src/util/sss_utf8.c
@@ -24,6 +24,54 @@
 #include "sss_utf8.h"
 
 #ifdef HAVE_LIBUNISTRING
+uint8_t *sss_utf8_tolower(TALLOC_CTX *mem_ctx, const uint8_t *s)
+{
+    size_t len, llen;
+    uint8_t *lower;
+    uint8_t *ret;
+
+    len = u8_strlen(s);
+    lower = u8_tolower(s, len, NULL, NULL, NULL, &llen);
+    if (!lower) return NULL;
+
+    ret = talloc_array(mem_ctx, uint8_t, llen+1);
+    if (!ret) return NULL;
+
+    memcpy(ret, lower, llen);
+    ret[llen] = '\0';
+
+    free(lower);
+    return ret;
+}
+
+#elif HAVE_GLIB2
+uint8_t *sss_utf8_tolower(TALLOC_CTX *mem_ctx, const uint8_t *s)
+{
+    gchar *lower;
+    const gchar *gs;
+    gssize llen;
+    uint8_t *ret;
+
+    gs = (const gchar *) s;
+
+    lower = g_utf8_strdown(gs, -1);
+    if (!lower) return NULL;
+    llen = g_utf8_strlen(lower, -1);
+
+    ret = talloc_array(mem_ctx, uint8_t, llen+1);
+    if (!ret) return NULL;
+
+    memcpy(ret, lower, llen);
+    ret[llen] = '\0';
+
+    free(lower);
+    return ret;
+}
+#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 37dcff9..89160f6 100644
--- a/src/util/sss_utf8.h
+++ b/src/util/sss_utf8.h
@@ -35,6 +35,10 @@
 #define ENOMATCH -1
 #endif
 
+uint8_t *sss_utf8_tolower(TALLOC_CTX *mem_ctx, const uint8_t *s);
+#define sss_utf8_string_tolower(mem_ctx, s) \
+    (const char *) sss_utf8_tolower(mem_ctx, (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);
-- 
1.7.7.3

-------------- next part --------------
From 6d28d1c37b87f6f9c658d793c673f889246a3c75 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/6] 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 3b5ab8a..f6784e9 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 1b28a92..99b1a23 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 720813f..f0270ac 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 7d5665d..09d07df 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 40df755..5f77697 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.3

-------------- next part --------------
From 1628804706cdd8356f2dfdc6384db201a8624956 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Wed, 16 Nov 2011 14:09:59 +0100
Subject: [PATCH 3/6] 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             |   12 +++
 src/responder/common/negcache.c     |  136 ++++++++++++++++++++++++++++++-----
 src/responder/common/negcache.h     |   10 ++--
 src/responder/nss/nsssrv_cmd.c      |   37 +++++++---
 src/responder/nss/nsssrv_netgroup.c |   21 ++++--
 src/responder/pam/pamsrv_cmd.c      |   32 ++++++++-
 11 files changed, 217 insertions(+), 44 deletions(-)

diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c
index 3f668dd..9ebe012 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 266e4d2..2ebbf4f 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 d39949f..37fcb25 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 16ddfe5..8421a09 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 6813901..c2c425c 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 1ed408f..944d8bf 100644
--- a/src/man/sssd.conf.5.xml
+++ b/src/man/sssd.conf.5.xml
@@ -931,6 +931,18 @@
                         </para>
                     </listitem>
                 </varlistentry>
+
+                <varlistentry>
+                    <term>case_sensitive (boolean)</term>
+                    <listitem>
+                        <para>
+                            Treat user and group names as case sensitive
+                        </para>
+                        <para>
+                            Default: True
+                        </para>
+                    </listitem>
+                </varlistentry>
             </variablelist>
         </para>
 
diff --git a/src/responder/common/negcache.c b/src/responder/common/negcache.c
index 3926574..658e94e 100644
--- a/src/responder/common/negcache.c
+++ b/src/responder/common/negcache.c
@@ -20,7 +20,9 @@
 */
 
 #include "util/util.h"
+#include "util/sss_utf8.h"
 #include "confdb/confdb.h"
+#include "responder/common/responder.h"
 #include <fcntl.h>
 #include <time.h>
 #include "tdb.h"
@@ -158,8 +160,8 @@ done:
     return ret;
 }
 
-int sss_ncache_check_user(struct sss_nc_ctx *ctx, int ttl,
-                          const char *domain, const char *name)
+static int sss_ncache_check_user_int(struct sss_nc_ctx *ctx, int ttl,
+                                     const char *domain, const char *name)
 {
     char *str;
     int ret;
@@ -175,8 +177,8 @@ int sss_ncache_check_user(struct sss_nc_ctx *ctx, int ttl,
     return ret;
 }
 
-int sss_ncache_check_group(struct sss_nc_ctx *ctx, int ttl,
-                           const char *domain, const char *name)
+static int sss_ncache_check_group_int(struct sss_nc_ctx *ctx, int ttl,
+                                      const char *domain, const char *name)
 {
     char *str;
     int ret;
@@ -192,8 +194,8 @@ int sss_ncache_check_group(struct sss_nc_ctx *ctx, int ttl,
     return ret;
 }
 
-int sss_ncache_check_netgr(struct sss_nc_ctx *ctx, int ttl,
-                           const char *domain, const char *name)
+static int sss_ncache_check_netgr_int(struct sss_nc_ctx *ctx, int ttl,
+                                      const char *domain, const char *name)
 {
     char *str;
     int ret;
@@ -209,6 +211,49 @@ int sss_ncache_check_netgr(struct sss_nc_ctx *ctx, int ttl,
     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 = (char *) sss_utf8_tolower(ctx, (const uint8_t *) 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,
+                          struct sss_domain_info *dom, const char *name)
+{
+    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,
+                           struct sss_domain_info *dom, const char *name)
+{
+    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,
+                           struct sss_domain_info *dom, const char *name)
+{
+    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)
 {
     char *str;
@@ -237,8 +282,8 @@ int sss_ncache_check_gid(struct sss_nc_ctx *ctx, int ttl, gid_t gid)
     return ret;
 }
 
-int sss_ncache_set_user(struct sss_nc_ctx *ctx, bool permanent,
-                        const char *domain, const char *name)
+static int sss_ncache_set_user_int(struct sss_nc_ctx *ctx, bool permanent,
+                                   const char *domain, const char *name)
 {
     char *str;
     int ret;
@@ -254,8 +299,8 @@ int sss_ncache_set_user(struct sss_nc_ctx *ctx, bool permanent,
     return ret;
 }
 
-int sss_ncache_set_group(struct sss_nc_ctx *ctx, bool permanent,
-                        const char *domain, const char *name)
+static int sss_ncache_set_group_int(struct sss_nc_ctx *ctx, bool permanent,
+                                    const char *domain, const char *name)
 {
     char *str;
     int ret;
@@ -271,8 +316,8 @@ int sss_ncache_set_group(struct sss_nc_ctx *ctx, bool permanent,
     return ret;
 }
 
-int sss_ncache_set_netgr(struct sss_nc_ctx *ctx, bool permanent,
-                         const char *domain, const char *name)
+static int sss_ncache_set_netgr_int(struct sss_nc_ctx *ctx, bool permanent,
+                                    const char *domain, const char *name)
 {
     char *str;
     int ret;
@@ -288,6 +333,47 @@ int sss_ncache_set_netgr(struct sss_nc_ctx *ctx, bool permanent,
     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 = (char *) sss_utf8_tolower(ctx, (const uint8_t *) 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,
+                        struct sss_domain_info *dom, const char *name)
+{
+    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,
+                         struct sss_domain_info *dom, const char *name)
+{
+    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,
+                         struct sss_domain_info *dom, const char *name)
+{
+    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)
 {
     char *str;
@@ -409,7 +495,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 +533,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 +549,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 +592,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 +630,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 +646,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 fc857fc..72b99c9 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/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
index f0270ac..759cf66 100644
--- a/src/responder/nss/nsssrv_cmd.c
+++ b/src/responder/nss/nsssrv_cmd.c
@@ -20,6 +20,7 @@
 */
 
 #include "util/util.h"
+#include "util/sss_utf8.h"
 #include "responder/nss/nsssrv.h"
 #include "responder/nss/nsssrv_private.h"
 #include "responder/nss/nsssrv_netgroup.h"
@@ -394,7 +395,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 +716,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;
+    const char *name;
     struct sysdb_ctx *sysdb;
     struct nss_ctx *nctx;
     int ret;
@@ -740,10 +741,14 @@ static int nss_cmd_getpwnam_search(struct nss_dom_ctx *dctx)
         /* make sure to update the dctx if we changed domain */
         dctx->domain = dom;
 
+        name = dom->case_sensitive ? talloc_strdup(dctx, cmdctx->name) :
+                                   sss_utf8_string_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;
+    const char *name;
     struct sysdb_ctx *sysdb;
     struct nss_ctx *nctx;
     int ret;
@@ -2027,10 +2032,14 @@ static int nss_cmd_getgrnam_search(struct nss_dom_ctx *dctx)
         /* make sure to update the dctx if we changed domain */
         dctx->domain = dom;
 
+        name = dom->case_sensitive ? talloc_strdup(dctx, cmdctx->name) :
+                                     sss_utf8_string_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 +2077,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 +3077,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;
+    const char *name;
     struct sysdb_ctx *sysdb;
     struct nss_ctx *nctx;
     int ret;
@@ -3093,10 +3102,14 @@ static int nss_cmd_initgroups_search(struct nss_dom_ctx *dctx)
         /* make sure to update the dctx if we changed domain */
         dctx->domain = dom;
 
+        name = dom->case_sensitive ? talloc_strdup(dctx, cmdctx->name) :
+                                     sss_utf8_string_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 +3143,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 09d07df..f6f06d9 100644
--- a/src/responder/nss/nsssrv_netgroup.c
+++ b/src/responder/nss/nsssrv_netgroup.c
@@ -24,6 +24,7 @@
 
 #include <collection.h>
 #include "util/util.h"
+#include "util/sss_utf8.h"
 #include "responder/nss/nsssrv.h"
 #include "responder/nss/nsssrv_private.h"
 #include "responder/nss/nsssrv_netgroup.h"
@@ -378,6 +379,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;
 
     /* Check each domain for this netgroup name */
     while (dom) {
@@ -400,8 +402,12 @@ 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;
 
+        name = dom->case_sensitive ? \
+                    talloc_strdup(step_ctx, step_ctx->name) :
+                    (char *) sss_utf8_tolower(step_ctx, (const uint8_t *) 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 5f77697..4bfbd95 100644
--- a/src/responder/pam/pamsrv_cmd.c
+++ b/src/responder/pam/pamsrv_cmd.c
@@ -22,6 +22,7 @@
 
 #include <time.h>
 #include "util/util.h"
+#include "util/sss_utf8.h"
 #include "db/sysdb.h"
 #include "confdb/confdb.h"
 #include "responder/common/responder_packet.h"
@@ -93,6 +94,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, 0);
+    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)
@@ -767,7 +787,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
@@ -835,6 +855,9 @@ static int pam_check_user_search(struct pam_auth_req *preq)
         /* make sure to update the preq if we changed domain */
         preq->domain = dom;
 
+        name = dom->case_sensitive ? talloc_strdup(preq, preq->pd->user) :
+                                sss_utf8_string_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
@@ -890,6 +913,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.3

-------------- next part --------------
From 1628804706cdd8356f2dfdc6384db201a8624956 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Wed, 16 Nov 2011 14:09:59 +0100
Subject: [PATCH 3/6] 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             |   12 +++
 src/responder/common/negcache.c     |  136 ++++++++++++++++++++++++++++++-----
 src/responder/common/negcache.h     |   10 ++--
 src/responder/nss/nsssrv_cmd.c      |   37 +++++++---
 src/responder/nss/nsssrv_netgroup.c |   21 ++++--
 src/responder/pam/pamsrv_cmd.c      |   32 ++++++++-
 11 files changed, 217 insertions(+), 44 deletions(-)

diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c
index 3f668dd..9ebe012 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 266e4d2..2ebbf4f 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 d39949f..37fcb25 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 16ddfe5..8421a09 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 6813901..c2c425c 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 1ed408f..944d8bf 100644
--- a/src/man/sssd.conf.5.xml
+++ b/src/man/sssd.conf.5.xml
@@ -931,6 +931,18 @@
                         </para>
                     </listitem>
                 </varlistentry>
+
+                <varlistentry>
+                    <term>case_sensitive (boolean)</term>
+                    <listitem>
+                        <para>
+                            Treat user and group names as case sensitive
+                        </para>
+                        <para>
+                            Default: True
+                        </para>
+                    </listitem>
+                </varlistentry>
             </variablelist>
         </para>
 
diff --git a/src/responder/common/negcache.c b/src/responder/common/negcache.c
index 3926574..658e94e 100644
--- a/src/responder/common/negcache.c
+++ b/src/responder/common/negcache.c
@@ -20,7 +20,9 @@
 */
 
 #include "util/util.h"
+#include "util/sss_utf8.h"
 #include "confdb/confdb.h"
+#include "responder/common/responder.h"
 #include <fcntl.h>
 #include <time.h>
 #include "tdb.h"
@@ -158,8 +160,8 @@ done:
     return ret;
 }
 
-int sss_ncache_check_user(struct sss_nc_ctx *ctx, int ttl,
-                          const char *domain, const char *name)
+static int sss_ncache_check_user_int(struct sss_nc_ctx *ctx, int ttl,
+                                     const char *domain, const char *name)
 {
     char *str;
     int ret;
@@ -175,8 +177,8 @@ int sss_ncache_check_user(struct sss_nc_ctx *ctx, int ttl,
     return ret;
 }
 
-int sss_ncache_check_group(struct sss_nc_ctx *ctx, int ttl,
-                           const char *domain, const char *name)
+static int sss_ncache_check_group_int(struct sss_nc_ctx *ctx, int ttl,
+                                      const char *domain, const char *name)
 {
     char *str;
     int ret;
@@ -192,8 +194,8 @@ int sss_ncache_check_group(struct sss_nc_ctx *ctx, int ttl,
     return ret;
 }
 
-int sss_ncache_check_netgr(struct sss_nc_ctx *ctx, int ttl,
-                           const char *domain, const char *name)
+static int sss_ncache_check_netgr_int(struct sss_nc_ctx *ctx, int ttl,
+                                      const char *domain, const char *name)
 {
     char *str;
     int ret;
@@ -209,6 +211,49 @@ int sss_ncache_check_netgr(struct sss_nc_ctx *ctx, int ttl,
     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 = (char *) sss_utf8_tolower(ctx, (const uint8_t *) 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,
+                          struct sss_domain_info *dom, const char *name)
+{
+    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,
+                           struct sss_domain_info *dom, const char *name)
+{
+    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,
+                           struct sss_domain_info *dom, const char *name)
+{
+    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)
 {
     char *str;
@@ -237,8 +282,8 @@ int sss_ncache_check_gid(struct sss_nc_ctx *ctx, int ttl, gid_t gid)
     return ret;
 }
 
-int sss_ncache_set_user(struct sss_nc_ctx *ctx, bool permanent,
-                        const char *domain, const char *name)
+static int sss_ncache_set_user_int(struct sss_nc_ctx *ctx, bool permanent,
+                                   const char *domain, const char *name)
 {
     char *str;
     int ret;
@@ -254,8 +299,8 @@ int sss_ncache_set_user(struct sss_nc_ctx *ctx, bool permanent,
     return ret;
 }
 
-int sss_ncache_set_group(struct sss_nc_ctx *ctx, bool permanent,
-                        const char *domain, const char *name)
+static int sss_ncache_set_group_int(struct sss_nc_ctx *ctx, bool permanent,
+                                    const char *domain, const char *name)
 {
     char *str;
     int ret;
@@ -271,8 +316,8 @@ int sss_ncache_set_group(struct sss_nc_ctx *ctx, bool permanent,
     return ret;
 }
 
-int sss_ncache_set_netgr(struct sss_nc_ctx *ctx, bool permanent,
-                         const char *domain, const char *name)
+static int sss_ncache_set_netgr_int(struct sss_nc_ctx *ctx, bool permanent,
+                                    const char *domain, const char *name)
 {
     char *str;
     int ret;
@@ -288,6 +333,47 @@ int sss_ncache_set_netgr(struct sss_nc_ctx *ctx, bool permanent,
     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 = (char *) sss_utf8_tolower(ctx, (const uint8_t *) 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,
+                        struct sss_domain_info *dom, const char *name)
+{
+    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,
+                         struct sss_domain_info *dom, const char *name)
+{
+    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,
+                         struct sss_domain_info *dom, const char *name)
+{
+    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)
 {
     char *str;
@@ -409,7 +495,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 +533,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 +549,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 +592,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 +630,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 +646,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 fc857fc..72b99c9 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/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
index f0270ac..759cf66 100644
--- a/src/responder/nss/nsssrv_cmd.c
+++ b/src/responder/nss/nsssrv_cmd.c
@@ -20,6 +20,7 @@
 */
 
 #include "util/util.h"
+#include "util/sss_utf8.h"
 #include "responder/nss/nsssrv.h"
 #include "responder/nss/nsssrv_private.h"
 #include "responder/nss/nsssrv_netgroup.h"
@@ -394,7 +395,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 +716,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;
+    const char *name;
     struct sysdb_ctx *sysdb;
     struct nss_ctx *nctx;
     int ret;
@@ -740,10 +741,14 @@ static int nss_cmd_getpwnam_search(struct nss_dom_ctx *dctx)
         /* make sure to update the dctx if we changed domain */
         dctx->domain = dom;
 
+        name = dom->case_sensitive ? talloc_strdup(dctx, cmdctx->name) :
+                                   sss_utf8_string_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;
+    const char *name;
     struct sysdb_ctx *sysdb;
     struct nss_ctx *nctx;
     int ret;
@@ -2027,10 +2032,14 @@ static int nss_cmd_getgrnam_search(struct nss_dom_ctx *dctx)
         /* make sure to update the dctx if we changed domain */
         dctx->domain = dom;
 
+        name = dom->case_sensitive ? talloc_strdup(dctx, cmdctx->name) :
+                                     sss_utf8_string_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 +2077,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 +3077,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;
+    const char *name;
     struct sysdb_ctx *sysdb;
     struct nss_ctx *nctx;
     int ret;
@@ -3093,10 +3102,14 @@ static int nss_cmd_initgroups_search(struct nss_dom_ctx *dctx)
         /* make sure to update the dctx if we changed domain */
         dctx->domain = dom;
 
+        name = dom->case_sensitive ? talloc_strdup(dctx, cmdctx->name) :
+                                     sss_utf8_string_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 +3143,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 09d07df..f6f06d9 100644
--- a/src/responder/nss/nsssrv_netgroup.c
+++ b/src/responder/nss/nsssrv_netgroup.c
@@ -24,6 +24,7 @@
 
 #include <collection.h>
 #include "util/util.h"
+#include "util/sss_utf8.h"
 #include "responder/nss/nsssrv.h"
 #include "responder/nss/nsssrv_private.h"
 #include "responder/nss/nsssrv_netgroup.h"
@@ -378,6 +379,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;
 
     /* Check each domain for this netgroup name */
     while (dom) {
@@ -400,8 +402,12 @@ 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;
 
+        name = dom->case_sensitive ? \
+                    talloc_strdup(step_ctx, step_ctx->name) :
+                    (char *) sss_utf8_tolower(step_ctx, (const uint8_t *) 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 5f77697..4bfbd95 100644
--- a/src/responder/pam/pamsrv_cmd.c
+++ b/src/responder/pam/pamsrv_cmd.c
@@ -22,6 +22,7 @@
 
 #include <time.h>
 #include "util/util.h"
+#include "util/sss_utf8.h"
 #include "db/sysdb.h"
 #include "confdb/confdb.h"
 #include "responder/common/responder_packet.h"
@@ -93,6 +94,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, 0);
+    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)
@@ -767,7 +787,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
@@ -835,6 +855,9 @@ static int pam_check_user_search(struct pam_auth_req *preq)
         /* make sure to update the preq if we changed domain */
         preq->domain = dom;
 
+        name = dom->case_sensitive ? talloc_strdup(preq, preq->pd->user) :
+                                sss_utf8_string_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
@@ -890,6 +913,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.3

-------------- next part --------------
From 3371366eeb91db71391da21444258a28781fc54c 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 4/6] 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    |   47 +++-----------
 src/providers/ldap/sdap_async_netgroups.c |   76 +++++------------------
 src/providers/ldap/sdap_async_users.c     |   95 ++++++-----------------------
 5 files changed, 146 insertions(+), 173 deletions(-)

diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c
index b1177e2..98291e6 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 4ba2770..f53af1e 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 ead3fd5..1b26ec1 100644
--- a/src/providers/ldap/sdap_async_groups.c
+++ b/src/providers/ldap/sdap_async_groups.c
@@ -282,38 +282,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 +350,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 bb2e1bb..9c66963 100644
--- a/src/providers/ldap/sdap_async_netgroups.c
+++ b/src/providers/ldap/sdap_async_netgroups.c
@@ -66,21 +66,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 +96,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 cf9a8d3..2d2a64b 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,
@@ -62,7 +61,7 @@ int sdap_save_user(TALLOC_CTX *memctx,
 
     DEBUG(9, ("Save user\n"));
 
-    tmpctx = talloc_new(memctx);
+    tmpctx = talloc_new(NULL);
     if (!tmpctx) {
         ret = ENOMEM;
         goto fail;
@@ -151,57 +150,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 +187,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 +219,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 +237,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 +265,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.3

-------------- next part --------------
From d669962c40ca83a9912c1c977b09e7488794f4df 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 5/6] 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           |   10 +++++---
 src/providers/ldap/sdap_async.h           |    1 +
 src/providers/ldap/sdap_async_groups.c    |    4 +-
 src/providers/ldap/sdap_async_netgroups.c |    8 ++++++
 src/providers/ldap/sdap_async_users.c     |    2 +-
 7 files changed, 51 insertions(+), 11 deletions(-)

diff --git a/src/db/sysdb.c b/src/db/sysdb.c
index c49399f..e557bf2 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, *c;
 
     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 = (char *) sss_utf8_tolower(tmp_ctx, (const uint8_t *) 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 5fc36ab..82d1fd0 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 98291e6..db9bf76 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,16 +2025,17 @@ 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,
+                    struct sss_domain_info *dom,
                     struct sysdb_attrs *attrs)
 {
     const char **aliases = NULL;
     errno_t ret;
     TALLOC_CTX *tmp_ctx;
     int i;
+    char *lowername;
 
     tmp_ctx = talloc_new(NULL);
     if (!tmp_ctx) {
@@ -2041,7 +2043,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,
+                                  !dom->case_sensitive, &aliases);
     if (ret != EOK) {
         DEBUG(SSSDBG_OP_FAILURE, ("Failed to get the alias list"));
         goto done;
@@ -2062,4 +2065,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 f53af1e..8d3fd40 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,
+                            struct sss_domain_info *dom,
                             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 1b26ec1..caa0129 100644
--- a/src/providers/ldap/sdap_async_groups.c
+++ b/src/providers/ldap/sdap_async_groups.c
@@ -350,9 +350,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, 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_netgroups.c b/src/providers/ldap/sdap_async_netgroups.c
index 9c66963..fcc609e 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,
@@ -120,6 +121,12 @@ 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, 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);
@@ -672,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 2d2a64b..8bd6409 100644
--- a/src/providers/ldap/sdap_async_users.c
+++ b/src/providers/ldap/sdap_async_users.c
@@ -237,7 +237,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, user_attrs);
     if (ret != EOK) {
         DEBUG(1, ("Failed to save user names\n"));
         goto fail;
-- 
1.7.7.3

-------------- next part --------------
From f651d0d224490ab05877658d84657cdddc3b7440 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 6/6] Use the case sensitivity flag in the simple access
 provider

---
 src/providers/simple/simple_access.c |   12 ++++++++----
 1 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/src/providers/simple/simple_access.c b/src/providers/simple/simple_access.c
index 4b9c313..614a8b4 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;
                 }
-- 
1.7.7.3



More information about the sssd-devel mailing list