[SSSD] [PATCH] Support flat name in the full_name_format

Jakub Hrozek jhrozek at redhat.com
Mon May 27 18:06:35 UTC 2013


On Fri, May 24, 2013 at 08:32:20AM +0200, Sumit Bose wrote:
> On Thu, May 23, 2013 at 04:39:23PM -0400, Simo Sorce wrote:
> > On Thu, 2013-05-23 at 22:20 +0200, Sumit Bose wrote:
> > > 
> > > maybe it should be added that it is expected that there is a delimiter
> > > of one character not more or less.
> > > 
> > The original code was able to cope with delimiters bigger than 1 char,
> > has that changed ?
> 
> ah, you are right, I've just see 'int delim = 1;' in fill_pwent and
> friends but not that it is reset if more space is needed.
> 
> bye,
> Sumit

I confess I wasn't quite sure about the code either when I opened it
after two weeks, so at least there is a unit test added in the latest
iteration of patches and also there is a new patch in the series that
attempts to make the flow easier by removing some "else" branches.

Thank you for the review, all your comments should be fixed now. New
patches are attached, but only patch #3 has changed and patch #4 is new.

There is a new utility function sss_fqdom_len() that is used instead of
simply strdup(domain) when formatting the name into a fully-qualified-name. I
haven't found any other places to fix, at least "git grep strlen | grep dom"
doesn't show me any :)
-------------- next part --------------
>From c3079bd06c3ed1772e87e4d9f3bdb5255273d816 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Fri, 10 May 2013 18:19:12 +0200
Subject: [PATCH 1/4] Add utility functions for formatting fully-qualified
 names

Instead of using printf-like functions directly, provide two wrappers
that would encapsulate formatting the fully-qualified names. No
functional change is present in this patch.
---
 src/db/sysdb_search.c            |  6 ++---
 src/providers/ipa/ipa_s2n_exop.c |  8 +++----
 src/responder/nss/nsssrv_cmd.c   | 49 ++++++++++++++++------------------------
 src/responder/pac/pacsrv_cmd.c   |  4 ++--
 src/responder/pac/pacsrv_utils.c |  3 +--
 src/tools/sss_cache.c            |  3 +--
 src/util/usertools.c             | 25 ++++++++++++++++++++
 src/util/util.h                  | 16 +++++++++++++
 8 files changed, 70 insertions(+), 44 deletions(-)

diff --git a/src/db/sysdb_search.c b/src/db/sysdb_search.c
index 843c746d2a724aa63d885ff40d025633ba401833..344ff6fae476c984132acb19064958135d750b1f 100644
--- a/src/db/sysdb_search.c
+++ b/src/db/sysdb_search.c
@@ -57,8 +57,7 @@ int sysdb_getpwnam(TALLOC_CTX *mem_ctx,
      * search as well by default */
     if (IS_SUBDOMAIN(domain) && domain->fqnames) {
         ret = ENOMEM;
-        src_name = talloc_asprintf(tmp_ctx, domain->names->fq_fmt,
-                                   name, domain->name);
+        src_name = sss_tc_fqname(tmp_ctx, domain->names, domain, name);
     } else {
         ret = EINVAL;
         src_name = name;
@@ -245,8 +244,7 @@ int sysdb_getgrnam(TALLOC_CTX *mem_ctx,
      * search as well by default */
     if (IS_SUBDOMAIN(domain) && domain->fqnames) {
         ret = ENOMEM;
-        src_name = talloc_asprintf(tmp_ctx, domain->names->fq_fmt,
-                                   name, domain->name);
+        src_name = sss_tc_fqname(tmp_ctx, domain->names, domain, name);
     } else {
         ret = EINVAL;
         src_name = name;
diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
index 02a7bc2298e01adb0972fef588d002ee2328b869..f589a06fe12ff3bb02129b3fa5ad78feddcb7724 100644
--- a/src/providers/ipa/ipa_s2n_exop.c
+++ b/src/providers/ipa/ipa_s2n_exop.c
@@ -757,8 +757,8 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq)
             }
 
             /* we always use the fully qualified name for subdomain users */
-            name = talloc_asprintf(state, state->dom->names->fq_fmt,
-                                   attrs->a.user.pw_name, state->dom->name);
+            name = sss_tc_fqname(state, state->dom->names, state->dom,
+                                 attrs->a.user.pw_name);
             if (!name) {
                 DEBUG(SSSDBG_OP_FAILURE, ("failed to format user name.\n"));
                 ret = ENOMEM;
@@ -822,8 +822,8 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq)
             break;
         case RESP_GROUP:
             /* we always use the fully qualified name for subdomain users */
-            name = talloc_asprintf(state, state->dom->names->fq_fmt,
-                                   attrs->a.group.gr_name, state->dom->name);
+            name = sss_tc_fqname(state, state->dom->names, state->dom,
+                                 attrs->a.group.gr_name);
             if (!name) {
                 DEBUG(SSSDBG_OP_FAILURE, ("failed to format user name,\n"));
                 ret = ENOMEM;
diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
index 57b5786f3106d3f9c307b25c1940520fd03be0c2..268cfc83e63c710661ac712a834e5a19ae12fdbd 100644
--- a/src/responder/nss/nsssrv_cmd.c
+++ b/src/responder/nss/nsssrv_cmd.c
@@ -303,13 +303,10 @@ static int fill_pwent(struct sss_packet *packet,
     int i, ret, num, t;
     bool add_domain = (!IS_SUBDOMAIN(dom) && dom->fqnames);
     const char *domain = dom->name;
-    const char *namefmt;
     bool packet_initialized = false;
     int ncret;
     TALLOC_CTX *tmp_ctx = NULL;
 
-    namefmt = dom->names->fq_fmt;
-
     if (add_domain) dom_len = strlen(domain);
 
     to_sized_string(&pwfield, nctx->pwfield);
@@ -394,9 +391,8 @@ static int fill_pwent(struct sss_packet *packet,
         SAFEALIGN_SET_UINT32(&body[rp], gid, &rp);
 
         if (add_domain) {
-            ret = snprintf((char *)&body[rp],
-                            name.len + delim + dom_len,
-                            namefmt, name.str, domain);
+            ret = sss_fqname((char *) &body[rp], name.len + delim + dom_len,
+                             dom->names, dom, name.str);
             if (ret >= (name.len + delim + dom_len)) {
                 /* need more space, got creative with the print format ? */
                 t = ret - (name.len + delim + dom_len) + 1;
@@ -409,9 +405,8 @@ static int fill_pwent(struct sss_packet *packet,
                 sss_packet_get_body(packet, &body, &blen);
 
                 /* retry */
-                ret = snprintf((char *)&body[rp],
-                            name.len + delim + dom_len,
-                            namefmt, name.str, domain);
+                ret = sss_fqname((char *) &body[rp], name.len + delim + dom_len,
+                                 dom->names, dom, name.str);
             }
 
             if (ret != name.len + delim + dom_len - 1) {
@@ -665,7 +660,7 @@ static int delete_entry_from_memcache(struct sss_domain_info *dom, char *name,
     }
 
     if (dom->fqnames) {
-        fqdn = talloc_asprintf(tmp_ctx, dom->names->fq_fmt, name, dom->name);
+        fqdn = sss_tc_fqname(tmp_ctx, dom->names, dom, name);
         if (fqdn == NULL) {
             DEBUG(SSSDBG_CRIT_FAILURE, ("Out of memory.\n"));
             ret = ENOMEM;
@@ -2153,7 +2148,6 @@ static int fill_members(struct sss_packet *packet,
     size_t rsize = *_rsize;
     char *tmpstr;
     struct sized_string name;
-    const char *namefmt = dom->names->fq_fmt;
     TALLOC_CTX *tmp_ctx = NULL;
 
     size_t delim;
@@ -2214,9 +2208,9 @@ static int fill_members(struct sss_packet *packet,
         sss_packet_get_body(packet, &body, &blen);
 
         if (add_domain) {
-            ret = snprintf((char *)&body[rzero + rsize],
-                           name.len + delim + dom_len,
-                           namefmt, name.str, domain);
+            ret = sss_fqname((char *)&body[rzero + rsize],
+                             name.len + delim + dom_len,
+                             dom->names, dom, name.str);
             if (ret >= (name.len + delim + dom_len)) {
                 /* need more space,
                  * got creative with the print format ? */
@@ -2229,9 +2223,9 @@ static int fill_members(struct sss_packet *packet,
                 delim += t;
 
                 /* retry */
-                ret = snprintf((char *)&body[rzero + rsize],
-                               name.len + delim + dom_len,
-                               namefmt, name.str, domain);
+                ret = sss_fqname((char *)&body[rzero + rsize],
+                                name.len + delim + dom_len,
+                                dom->names, dom, name.str);
             }
 
             if (ret != name.len + delim + dom_len - 1) {
@@ -2294,11 +2288,8 @@ static int fill_grent(struct sss_packet *packet,
     size_t rzero, rsize;
     bool add_domain = (!IS_SUBDOMAIN(dom) && dom->fqnames);
     const char *domain = dom->name;
-    const char *namefmt;
     TALLOC_CTX *tmp_ctx = NULL;
 
-    namefmt = dom->names->fq_fmt;
-
     if (add_domain) {
         delim = 1;
         dom_len = strlen(domain);
@@ -2384,9 +2375,9 @@ static int fill_grent(struct sss_packet *packet,
 
         /*  8-X: sequence of strings (name, passwd, mem..) */
         if (add_domain) {
-            ret = snprintf((char *)&body[rzero+STRS_ROFFSET],
-                            name.len + delim + dom_len,
-                            namefmt, name.str, domain);
+            ret = sss_fqname((char *)&body[rzero+STRS_ROFFSET],
+                             name.len + delim + dom_len,
+                             dom->names, dom, name.str);
             if (ret >= (name.len + delim + dom_len)) {
                 /* need more space, got creative with the print format ? */
                 int t = ret - (name.len + delim + dom_len) + 1;
@@ -2400,9 +2391,9 @@ static int fill_grent(struct sss_packet *packet,
                 delim += t;
 
                 /* retry */
-                ret = snprintf((char *)&body[rzero+STRS_ROFFSET],
-                                name.len + delim + dom_len,
-                                namefmt, name.str, domain);
+                ret = sss_fqname((char *)&body[rzero+STRS_ROFFSET],
+                                 name.len + delim + dom_len,
+                                 dom->names, dom, name.str);
             }
 
             if (ret != name.len + delim + dom_len - 1) {
@@ -3675,8 +3666,7 @@ static errno_t nss_cmd_getsidby_search(struct nss_dom_ctx *dctx)
             /* For subdomains a fully qualified name is needed for
              * sysdb_search_user_by_name and sysdb_search_group_by_name. */
             if (IS_SUBDOMAIN(dom)) {
-                sysdb_name = talloc_asprintf(cmdctx, dom->names->fq_fmt,
-                                             name, dom->name);
+                sysdb_name = sss_tc_fqname(cmdctx, dom->names, dom, name);
                 if (sysdb_name == NULL) {
                     DEBUG(SSSDBG_OP_FAILURE, ("talloc_asprintf failed.\n"));
                     return ENOMEM;
@@ -4045,8 +4035,7 @@ static errno_t fill_name(struct sss_packet *packet,
     }
 
     if (add_domain) {
-        fq_name = talloc_asprintf(tmp_ctx, dom->names->fq_fmt, cased_name,
-                                  dom->name);
+        fq_name = sss_tc_fqname(tmp_ctx, dom->names, dom, cased_name);
         if (fq_name == NULL) {
             DEBUG(SSSDBG_OP_FAILURE, ("talloc_asprintf failed.\n"));
             ret = ENOMEM;
diff --git a/src/responder/pac/pacsrv_cmd.c b/src/responder/pac/pacsrv_cmd.c
index 2b6cd965ea06288cab2c6bc22d9d2c4f1774e075..8f5617c7f63871ee897db89f382c7d0133009d79 100644
--- a/src/responder/pac/pacsrv_cmd.c
+++ b/src/responder/pac/pacsrv_cmd.c
@@ -204,8 +204,8 @@ static errno_t pac_add_user_next(struct pac_req_ctx *pr_ctx)
 
     /* this is a subdomain so we need to search for the fully qualified
      * name in the database */
-    pr_ctx->fq_name = talloc_asprintf(pr_ctx, pr_ctx->dom->names->fq_fmt,
-                                      pr_ctx->user_name, pr_ctx->dom->name);
+    pr_ctx->fq_name= sss_tc_fqname(pr_ctx, pr_ctx->dom->names,
+                                   pr_ctx->dom, pr_ctx->user_name);
     if (!pr_ctx->fq_name) {
         ret = ENOMEM;
         DEBUG(SSSDBG_OP_FAILURE, ("talloc_sprintf failed.\n"));
diff --git a/src/responder/pac/pacsrv_utils.c b/src/responder/pac/pacsrv_utils.c
index cb480d3ec081035166423d59e3835d41ff6070a9..bcea640b88d0aeea86f69a58be2bc34cd9a42f59 100644
--- a/src/responder/pac/pacsrv_utils.c
+++ b/src/responder/pac/pacsrv_utils.c
@@ -765,8 +765,7 @@ errno_t get_pwd_from_pac(TALLOC_CTX *mem_ctx,
         ret = ENOMEM;
         goto done;
     }
-    pwd->pw_name = talloc_asprintf(pwd, dom->names->fq_fmt,
-                                   lname, dom->name);
+    pwd->pw_name = sss_tc_fqname(pwd, dom->names, dom, lname);
     if (!pwd->pw_name) {
         DEBUG(SSSDBG_OP_FAILURE, ("talloc_sprintf failed.\n"));
         ret = ENOMEM;
diff --git a/src/tools/sss_cache.c b/src/tools/sss_cache.c
index 9942e6a7f4a252f55bf2a01ec7c80b202db72f51..f888608a0aef5d19cf13501003991a02c12e05b0 100644
--- a/src/tools/sss_cache.c
+++ b/src/tools/sss_cache.c
@@ -221,8 +221,7 @@ static errno_t update_filter(struct cache_tool_ctx *tctx,
     if (parsed_domain) {
         if (IS_SUBDOMAIN(dinfo)) {
             /* Use fqdn for subdomains */
-            use_name = talloc_asprintf(tmp_ctx, tctx->nctx->fq_fmt, use_name,
-                                       dinfo->name);
+            use_name = sss_tc_fqname(tmp_ctx, tctx->nctx, dinfo, name);
             if (use_name == NULL) {
                 DEBUG(SSSDBG_CRIT_FAILURE, ("Out of memory\n"));
                 ret = ENOMEM;
diff --git a/src/util/usertools.c b/src/util/usertools.c
index 91110f263657de9ba53ed305e7c4710eb006bec6..20ca407f333dc94335c5b2229085c2d52b82eb42 100644
--- a/src/util/usertools.c
+++ b/src/util/usertools.c
@@ -507,3 +507,28 @@ sss_get_cased_name_list(TALLOC_CTX *mem_ctx, const char * const *orig,
     *_cased = out;
     return EOK;
 }
+
+static inline const char *
+safe_fq_str(struct sss_names_ctx *nctx, uint8_t part, const char *str)
+{
+
+    return nctx->fq_flags & part ? str : "";
+}
+
+char *
+sss_tc_fqname(TALLOC_CTX *mem_ctx, struct sss_names_ctx *nctx,
+              struct sss_domain_info *domain, const char *name)
+{
+    if (domain == NULL || nctx == NULL) return NULL;
+
+    return talloc_asprintf(mem_ctx, nctx->fq_fmt, name, domain->name);
+}
+
+int
+sss_fqname(char *str, size_t size, struct sss_names_ctx *nctx,
+           struct sss_domain_info *domain, const char *name)
+{
+    if (domain == NULL || nctx == NULL) return -EINVAL;
+
+    return snprintf(str, size, nctx->fq_fmt, name, domain->name);
+}
diff --git a/src/util/util.h b/src/util/util.h
index bdb04a8f3f6cf565743edded84fd798043cbe286..2f65fa2017e742d4d6e373392aa76ad64536a232 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -43,6 +43,7 @@
 #include <ldb.h>
 #include <dhash.h>
 
+#include "confdb/confdb.h"
 #include "util/atomic_io.h"
 #include "util/util_errors.h"
 #include "util/util_safealign.h"
@@ -365,6 +366,21 @@ errno_t
 sss_get_cased_name_list(TALLOC_CTX *mem_ctx, const char * const *orig,
                         bool case_sensitive, const char ***_cased);
 
+/* Return fully-qualified name according to the fq_fmt. The name is allocated using
+ * talloc on top of mem_ctx
+ */
+char *
+sss_tc_fqname(TALLOC_CTX *mem_ctx, struct sss_names_ctx *nctx,
+              struct sss_domain_info *domain, const char *name);
+
+/* Return fully-qualified name formatted according to the fq_fmt. The buffer in "str" is
+ * "size" bytes long. Returns the number of bytes written on success or a negative
+ * value of failure.
+ */
+int
+sss_fqname(char *str, size_t size, struct sss_names_ctx *nctx,
+           struct sss_domain_info *domain, const char *name);
+
 /* from backup-file.c */
 int backup_file(const char *src, int dbglvl);
 
-- 
1.8.2.1

-------------- next part --------------
>From 1502e68b0b3f2027c9616674006362e945be6f31 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Thu, 9 May 2013 16:24:03 +0200
Subject: [PATCH 2/4] Check the validity of FQname format prior to using it

Adds a sanity check of the fqname pattern. Fails if the username pattern
is not specified at all and warns if the domain pattern is not
specified.
---
 src/util/usertools.c | 46 +++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 43 insertions(+), 3 deletions(-)

diff --git a/src/util/usertools.c b/src/util/usertools.c
index 20ca407f333dc94335c5b2229085c2d52b82eb42..835b9e3467c9345fc50cd96cbadd8c99b69d9e0a 100644
--- a/src/util/usertools.c
+++ b/src/util/usertools.c
@@ -135,6 +135,45 @@ done:
 #endif
 }
 
+static errno_t sss_fqnames_init(struct sss_names_ctx *nctx, const char *fq_fmt)
+{
+    struct pattern_desc {
+        const char *pattern;
+        const char *desc;
+    };
+
+    struct pattern_desc fqname_patterns[] = {
+        { "%1$s", "user name" },
+        { "%2$s", "domain name" },
+        { NULL, NULL }
+    };
+
+    nctx->fq_fmt = talloc_strdup(nctx, fq_fmt);
+    if (nctx->fq_fmt == NULL) {
+        return ENOMEM;
+    }
+
+    DEBUG(SSSDBG_CONF_SETTINGS, ("Using fq format [%s].\n", nctx->fq_fmt));
+
+    /* Fail if the name specifier is missing and warn if the domain
+     * specifier is missing
+     */
+    if (strstr(fq_fmt, fqname_patterns[0].pattern) == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE,
+              ("Username pattern not found in [%s]\n", nctx->fq_fmt));
+        return ENOENT;
+    }
+
+    if (strstr(fq_fmt, fqname_patterns[1].pattern) == NULL) {
+        DEBUG(SSSDBG_MINOR_FAILURE,
+              ("The pattern for %s was not found, fully-qualified names "
+               "might not work as expected\n", fqname_patterns[1].desc));
+        /* Ignore this error */
+    }
+
+    return EOK;
+}
+
 int sss_names_init_from_args(TALLOC_CTX *mem_ctx, const char *re_pattern,
                              const char *fq_fmt, struct sss_names_ctx **out)
 {
@@ -156,9 +195,10 @@ int sss_names_init_from_args(TALLOC_CTX *mem_ctx, const char *re_pattern,
 
     DEBUG(SSSDBG_CONF_SETTINGS, ("Using re [%s].\n", ctx->re_pattern));
 
-    ctx->fq_fmt = talloc_strdup(ctx, fq_fmt);
-    if (ctx->fq_fmt == NULL) {
-        ret = ENOMEM;
+    ret = sss_fqnames_init(ctx, fq_fmt);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, ("Could not check the FQ names format"
+              "[%d]: %s\n", ret, sss_strerror(ret)));
         goto done;
     }
 
-- 
1.8.2.1

-------------- next part --------------
>From b65a92d0a31eed9dbe5ded361cb44eae04ce9572 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Sat, 11 May 2013 10:53:12 +0200
Subject: [PATCH 3/4] Allow flat name in the FQname format

https://fedorahosted.org/sssd/ticket/1648

Adds another expansion in the printf format that allows the user to use
the domain flat name in the format.
---
 Makefile.am                     |  13 +-
 src/man/sssd.conf.5.xml         |  68 +++++++++-
 src/responder/nss/nsssrv_cmd.c  |   6 +-
 src/tests/cmocka/test_fqnames.c | 287 ++++++++++++++++++++++++++++++++++++++++
 src/tests/cmocka/test_nss_srv.c | 141 +++++++++++++++++++-
 src/util/usertools.c            |  77 +++++++++--
 src/util/util.h                 |   9 ++
 7 files changed, 576 insertions(+), 25 deletions(-)
 create mode 100644 src/tests/cmocka/test_fqnames.c

diff --git a/Makefile.am b/Makefile.am
index 2bcb71457af4a21ab4144a379148bc31820b7469..0cc98734a414383a64ba79fc2ece52664daf09cb 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -151,7 +151,8 @@ if HAVE_CMOCKA
         test-io \
         sss_nss_idmap-tests \
         test-io	      \
-        dyndns-tests
+        dyndns-tests \
+        fqnames-tests
 endif
 
 check_PROGRAMS = \
@@ -1305,6 +1306,16 @@ dyndns_tests_LDADD = \
     $(CARES_LIBS) \
     $(CMOCKA_LIBS) \
     libsss_util.la
+
+fqnames_tests_SOURCES = \
+    $(TEST_MOCK_OBJ) \
+    src/tests/cmocka/test_fqnames.c
+fqnames_tests_CFLAGS = \
+    $(AM_CFLAGS)
+fqnames_tests_LDADD = \
+    $(CMOCKA_LIBS) \
+    libsss_util.la
+
 endif
 
 noinst_PROGRAMS = pam_test_client
diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
index b902964fb0afe221dc2669a3a75ab6b8a435e54f..3bb1ca760f146857336f837cf5e6cebba0742a27 100644
--- a/src/man/sssd.conf.5.xml
+++ b/src/man/sssd.conf.5.xml
@@ -143,12 +143,41 @@
                         <term>full_name_format (string)</term>
                         <listitem>
                             <para>
-                                The default <citerefentry>
+                                A <citerefentry>
                                     <refentrytitle>printf</refentrytitle>
                                     <manvolnum>3</manvolnum>
                                 </citerefentry>-compatible format that describes how to
-                                translate a (name, domain) tuple into a fully qualified
-                                name.
+                                compose a fully qualified name from user name
+                                and domain name components.
+                            </para>
+                            <para>
+                                The following expansions are supported:
+                                <variablelist>
+                                    <varlistentry>
+                                        <term>%1$s</term>
+                                        <listitem><para>user name</para></listitem>
+                                    </varlistentry>
+                                    <varlistentry>
+                                        <term>%2$s</term>
+                                        <listitem>
+                                            <para>
+                                                domain name as specified in the
+                                                SSSD config file.
+                                            </para>
+                                        </listitem>
+                                    </varlistentry>
+                                    <varlistentry>
+                                        <term>%3$s</term>
+                                        <listitem>
+                                            <para>
+                                                domain flat name. Mostly usable
+                                                for Active Directory domains, both
+                                                directly configured or disovered
+                                                via IPA trusts.
+                                            </para>
+                                        </listitem>
+                                    </varlistentry>
+                                </variablelist>
                             </para>
                             <para>
                                 Each domain can have an individual format string configured.
@@ -1533,8 +1562,37 @@ override_homedir = /home/%u
                                 <refentrytitle>printf</refentrytitle>
                                 <manvolnum>3</manvolnum>
                             </citerefentry>-compatible format that describes how to
-                             translate a (name, domain) tuple for this domain into a fully
-                             qualified name.
+                            compose a fully qualified name from user name
+                            and domain name components.
+                        </para>
+                        <para>
+                            The following expansions are supported:
+                            <variablelist>
+                                <varlistentry>
+                                    <term>%1$s</term>
+                                    <listitem><para>user name</para></listitem>
+                                </varlistentry>
+                                <varlistentry>
+                                    <term>%2$s</term>
+                                    <listitem>
+                                        <para>
+                                            domain name as specified in the
+                                            SSSD config file.
+                                        </para>
+                                    </listitem>
+                                </varlistentry>
+                                <varlistentry>
+                                    <term>%3$s</term>
+                                    <listitem>
+                                        <para>
+                                            domain flat name. Mostly usable
+                                            for Active Directory domains, both
+                                            directly configured or disovered
+                                            via IPA trusts.
+                                        </para>
+                                    </listitem>
+                                </varlistentry>
+                            </variablelist>
                         </para>
                         <para>
                             Default: <quote>%1$s@%2$s</quote>.
diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
index 268cfc83e63c710661ac712a834e5a19ae12fdbd..39076e2b7e15be6737408bf4a8ec72df618d6968 100644
--- a/src/responder/nss/nsssrv_cmd.c
+++ b/src/responder/nss/nsssrv_cmd.c
@@ -307,7 +307,7 @@ static int fill_pwent(struct sss_packet *packet,
     int ncret;
     TALLOC_CTX *tmp_ctx = NULL;
 
-    if (add_domain) dom_len = strlen(domain);
+    if (add_domain) dom_len = sss_fqdom_len(dom->names, dom);
 
     to_sized_string(&pwfield, nctx->pwfield);
 
@@ -2161,7 +2161,7 @@ static int fill_members(struct sss_packet *packet,
 
     if (add_domain) {
         delim = 1;
-        dom_len = strlen(domain);
+        dom_len = sss_fqdom_len(dom->names, dom);
     } else {
         delim = 0;
         dom_len = 0;
@@ -2292,7 +2292,7 @@ static int fill_grent(struct sss_packet *packet,
 
     if (add_domain) {
         delim = 1;
-        dom_len = strlen(domain);
+        dom_len = sss_fqdom_len(dom->names, dom);
     } else {
         delim = 0;
         dom_len = 0;
diff --git a/src/tests/cmocka/test_fqnames.c b/src/tests/cmocka/test_fqnames.c
new file mode 100644
index 0000000000000000000000000000000000000000..e0735083a632a253afc9c676782968fc495b6305
--- /dev/null
+++ b/src/tests/cmocka/test_fqnames.c
@@ -0,0 +1,287 @@
+/*
+    Authors:
+        Jakub Hrozek <jhrozek at redhat.com>
+
+    Copyright (C) 2013 Red Hat
+
+    SSSD tests: Fully Qualified Names Tests
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <popt.h>
+
+#include "tests/cmocka/common_mock.h"
+
+#define NAME        "name"
+#define DOMNAME     "domname"
+#define FLATNAME    "flatname"
+
+struct fqdn_test_ctx {
+    struct sss_domain_info *dom;
+
+    struct sss_names_ctx *nctx;
+};
+
+void fqdn_test_setup(void **state)
+{
+    struct fqdn_test_ctx *test_ctx;
+
+    assert_true(leak_check_setup());
+
+    test_ctx = talloc_zero(global_talloc_context, struct fqdn_test_ctx);
+    assert_non_null(test_ctx);
+
+    test_ctx->dom = talloc_zero(test_ctx, struct sss_domain_info);
+    assert_non_null(test_ctx->dom);
+    test_ctx->dom->name = discard_const(DOMNAME);
+    test_ctx->dom->flat_name = discard_const(FLATNAME);
+
+    check_leaks_push(test_ctx);
+    *state = test_ctx;
+}
+
+void fqdn_test_teardown(void **state)
+{
+    struct fqdn_test_ctx *test_ctx = talloc_get_type(*state,
+                                                     struct fqdn_test_ctx);
+
+    if (test_ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Type mismatch\n"));
+        return;
+    }
+
+    assert_true(check_leaks_pop(test_ctx) == true);
+    talloc_free(test_ctx);
+    assert_true(leak_check_teardown());
+}
+
+void test_default(void **state)
+{
+    struct fqdn_test_ctx *test_ctx = talloc_get_type(*state,
+                                                     struct fqdn_test_ctx);
+    errno_t ret;
+
+    char *fqdn;
+    const int fqdn_size = 255;
+    char fqdn_s[fqdn_size];
+    size_t domsize;
+
+    if (test_ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Type mismatch\n"));
+        return;
+    }
+
+    ret = sss_names_init_from_args(test_ctx,
+                                   "(?P<name>[^@]+)@?(?P<domain>[^@]*$)",
+                                   "%1$s@%2$s", &test_ctx->nctx);
+    assert_int_equal(ret, EOK);
+    assert_int_equal(test_ctx->nctx->fq_flags, FQ_FMT_NAME | FQ_FMT_DOMAIN);
+
+    fqdn = sss_tc_fqname(test_ctx, test_ctx->nctx, test_ctx->dom, NAME);
+    assert_non_null(fqdn);
+    assert_string_equal(fqdn, NAME"@"DOMNAME);
+    talloc_free(fqdn);
+
+    ret = sss_fqname(fqdn_s, fqdn_size, test_ctx->nctx, test_ctx->dom, NAME);
+    assert_int_equal(ret + 1, sizeof(NAME"@"DOMNAME));
+    assert_string_equal(fqdn_s, NAME"@"DOMNAME);
+
+    domsize = sss_fqdom_len(test_ctx->nctx, test_ctx->dom);
+    assert_int_equal(domsize, sizeof(DOMNAME)-1);
+
+    talloc_free(test_ctx->nctx);
+}
+
+void test_all(void **state)
+{
+    struct fqdn_test_ctx *test_ctx = talloc_get_type(*state,
+                                                     struct fqdn_test_ctx);
+    errno_t ret;
+
+    char *fqdn;
+    const int fqdn_size = 255;
+    char fqdn_s[fqdn_size];
+    size_t domsize;
+
+    if (test_ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Type mismatch\n"));
+        return;
+    }
+
+    ret = sss_names_init_from_args(test_ctx,
+                                   "(?P<name>[^@]+)@?(?P<domain>[^@]*$)",
+                                   "%1$s@%2$s@%3$s", &test_ctx->nctx);
+    assert_int_equal(ret, EOK);
+    assert_int_equal(test_ctx->nctx->fq_flags,
+                     FQ_FMT_NAME | FQ_FMT_DOMAIN | FQ_FMT_FLAT_NAME);
+
+    fqdn = sss_tc_fqname(test_ctx, test_ctx->nctx, test_ctx->dom, NAME);
+    assert_non_null(fqdn);
+    assert_string_equal(fqdn, NAME"@"DOMNAME"@"FLATNAME);
+    talloc_free(fqdn);
+
+    ret = sss_fqname(fqdn_s, fqdn_size, test_ctx->nctx, test_ctx->dom, NAME);
+    assert_int_equal(ret + 1, sizeof(NAME"@"DOMNAME"@"FLATNAME));
+    assert_string_equal(fqdn_s, NAME"@"DOMNAME"@"FLATNAME);
+
+    domsize = sss_fqdom_len(test_ctx->nctx, test_ctx->dom);
+    assert_int_equal(domsize, sizeof(DOMNAME)-1 + sizeof(FLATNAME)-1);
+
+    talloc_free(test_ctx->nctx);
+}
+
+void test_flat(void **state)
+{
+    struct fqdn_test_ctx *test_ctx = talloc_get_type(*state,
+                                                     struct fqdn_test_ctx);
+    errno_t ret;
+
+    char *fqdn;
+    const int fqdn_size = 255;
+    char fqdn_s[fqdn_size];
+    size_t domsize;
+
+    if (test_ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Type mismatch\n"));
+        return;
+    }
+
+    ret = sss_names_init_from_args(test_ctx,
+                                   "(?P<name>[^@]+)@?(?P<domain>[^@]*$)",
+                                   "%1$s@%3$s", &test_ctx->nctx);
+    assert_int_equal(ret, EOK);
+    assert_int_equal(test_ctx->nctx->fq_flags, FQ_FMT_NAME | FQ_FMT_FLAT_NAME);
+
+    fqdn = sss_tc_fqname(test_ctx, test_ctx->nctx, test_ctx->dom, NAME);
+    assert_non_null(fqdn);
+    assert_string_equal(fqdn, NAME"@"FLATNAME);
+    talloc_free(fqdn);
+
+    ret = sss_fqname(fqdn_s, fqdn_size, test_ctx->nctx, test_ctx->dom, NAME);
+    assert_int_equal(ret + 1, sizeof(NAME"@"FLATNAME));
+    assert_string_equal(fqdn_s, NAME"@"FLATNAME);
+
+    domsize = sss_fqdom_len(test_ctx->nctx, test_ctx->dom);
+    assert_int_equal(domsize, sizeof(FLATNAME)-1);
+
+    talloc_free(test_ctx->nctx);
+}
+
+void test_flat_fallback(void **state)
+{
+    struct fqdn_test_ctx *test_ctx = talloc_get_type(*state,
+                                                     struct fqdn_test_ctx);
+    errno_t ret;
+
+    char *fqdn;
+    const int fqdn_size = 255;
+    char fqdn_s[fqdn_size];
+    size_t domsize;
+
+    if (test_ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Type mismatch\n"));
+        return;
+    }
+
+    ret = sss_names_init_from_args(test_ctx,
+                                   "(?P<name>[^@]+)@?(?P<domain>[^@]*$)",
+                                   "%1$s@%3$s", &test_ctx->nctx);
+    assert_int_equal(ret, EOK);
+    assert_int_equal(test_ctx->nctx->fq_flags, FQ_FMT_NAME | FQ_FMT_FLAT_NAME);
+
+    test_ctx->dom->flat_name = NULL;
+
+    /* If flat name is requested but does not exist, the code falls back to domain
+     * name
+     */
+    fqdn = sss_tc_fqname(test_ctx, test_ctx->nctx, test_ctx->dom, NAME);
+    assert_non_null(fqdn);
+    assert_string_equal(fqdn, NAME"@"DOMNAME);
+    talloc_free(fqdn);
+
+    ret = sss_fqname(fqdn_s, fqdn_size, test_ctx->nctx, test_ctx->dom, NAME);
+    assert_int_equal(ret + 1, sizeof(NAME"@"DOMNAME));
+    assert_string_equal(fqdn_s, NAME"@"DOMNAME);
+
+    domsize = sss_fqdom_len(test_ctx->nctx, test_ctx->dom);
+    assert_int_equal(domsize, sizeof(DOMNAME)-1);
+
+    talloc_free(test_ctx->nctx);
+}
+
+void test_init_nouser(void **state)
+{
+    struct fqdn_test_ctx *test_ctx = talloc_get_type(*state,
+                                                     struct fqdn_test_ctx);
+    errno_t ret;
+
+    if (test_ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Type mismatch\n"));
+        return;
+    }
+
+    ret = sss_names_init_from_args(test_ctx,
+                                   "(?P<name>[^@]+)@?(?P<domain>[^@]*$)",
+                                   "%2$s@%3$s", &test_ctx->nctx);
+    /* Initialization with no user name must fail */
+    assert_int_not_equal(ret, EOK);
+}
+
+int main(int argc, const char *argv[])
+{
+    poptContext pc;
+    int opt;
+    struct poptOption long_options[] = {
+        POPT_AUTOHELP
+        SSSD_DEBUG_OPTS
+        POPT_TABLEEND
+    };
+
+    const UnitTest tests[] = {
+        unit_test_setup_teardown(test_default,
+                                 fqdn_test_setup, fqdn_test_teardown),
+        unit_test_setup_teardown(test_all,
+                                 fqdn_test_setup, fqdn_test_teardown),
+        unit_test_setup_teardown(test_flat,
+                                 fqdn_test_setup, fqdn_test_teardown),
+        unit_test_setup_teardown(test_flat_fallback,
+                                 fqdn_test_setup, fqdn_test_teardown),
+        unit_test_setup_teardown(test_init_nouser,
+                                 fqdn_test_setup, fqdn_test_teardown),
+    };
+
+    /* Set debug level to invalid value so we can deside if -d 0 was used. */
+    debug_level = SSSDBG_INVALID;
+
+    pc = poptGetContext(argv[0], argc, argv, long_options, 0);
+    while((opt = poptGetNextOpt(pc)) != -1) {
+        switch(opt) {
+        default:
+            fprintf(stderr, "\nInvalid option %s: %s\n\n",
+                    poptBadOption(pc, 0), poptStrerror(opt));
+            poptPrintUsage(pc, stderr, 0);
+            return 1;
+        }
+    }
+    poptFreeContext(pc);
+
+    DEBUG_INIT(debug_level);
+
+    /* Even though normally the tests should clean up after themselves
+     * they might not after a failed run. Remove the old db to be sure */
+    tests_set_cwd();
+
+    return run_tests(tests);
+}
diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c
index 092e6803eae5e2471e7ff566b8366e83f7b6fb19..e8cc9aaea3d9f3452b4f2c77c9ba47c1de2d22db 100644
--- a/src/tests/cmocka/test_nss_srv.c
+++ b/src/tests/cmocka/test_nss_srv.c
@@ -411,14 +411,109 @@ void test_nss_getpwnam_update(void **state)
     assert_string_equal(shell, "/bin/ksh");
 }
 
+/* Check that a FQDN is returned if the domain is FQDN-only and a
+ * FQDN is requested
+ */
+static int test_nss_getpwnam_check_fqdn(uint8_t *body, size_t blen)
+{
+    struct passwd pwd;
+    errno_t ret;
+
+    nss_test_ctx->cctx->rctx->domains[0].fqnames = false;
+
+    ret = parse_user_packet(body, blen, &pwd);
+    assert_int_equal(ret, EOK);
+
+    assert_int_equal(pwd.pw_uid, 124);
+    assert_int_equal(pwd.pw_gid, 457);
+    assert_string_equal(pwd.pw_name, "testuser_fqdn@"TEST_DOM_NAME);
+    assert_string_equal(pwd.pw_shell, "/bin/sh");
+    return EOK;
+}
+
+void test_nss_getpwnam_fqdn(void **state)
+{
+    errno_t ret;
+
+    /* Prime the cache with a valid user */
+    ret = sysdb_add_user(nss_test_ctx->tctx->sysdb,
+                         nss_test_ctx->tctx->dom,
+                         "testuser_fqdn", 124, 457, "test user",
+                         "/home/testuser", "/bin/sh", NULL,
+                         NULL, 300, 0);
+    assert_int_equal(ret, EOK);
+
+    mock_input_user("testuser_fqdn@"TEST_DOM_NAME);
+    will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWNAM);
+    mock_fill_user();
+
+    /* Query for that user, call a callback when command finishes */
+    set_cmd_cb(test_nss_getpwnam_check_fqdn);
+    nss_test_ctx->cctx->rctx->domains[0].fqnames = true;
+    ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWNAM,
+                          nss_test_ctx->nss_cmds);
+    assert_int_equal(ret, EOK);
+
+    /* Wait until the test finishes with EOK */
+    ret = test_ev_loop(nss_test_ctx->tctx);
+    assert_int_equal(ret, EOK);
+}
+
+/*
+ * Check that FQDN processing is able to handle arbitrarily sized
+ * delimeter
+ */
+static int test_nss_getpwnam_check_resize_fqdn(uint8_t *body, size_t blen)
+{
+    struct passwd pwd;
+    errno_t ret;
+
+    nss_test_ctx->cctx->rctx->domains[0].fqnames = false;
+
+    ret = parse_user_packet(body, blen, &pwd);
+    assert_int_equal(ret, EOK);
+
+    assert_int_equal(pwd.pw_uid, 125);
+    assert_int_equal(pwd.pw_gid, 458);
+    assert_string_equal(pwd.pw_name, "testuser_fqdn_resize@@@@@"TEST_DOM_NAME);
+    assert_string_equal(pwd.pw_shell, "/bin/sh");
+    return EOK;
+}
+
+void test_nss_getpwnam_fqdn_resize(void **state)
+{
+    errno_t ret;
+
+    /* Prime the cache with a valid user */
+    ret = sysdb_add_user(nss_test_ctx->tctx->sysdb,
+                         nss_test_ctx->tctx->dom,
+                         "testuser_fqdn_resize", 125, 458, "test user",
+                         "/home/testuser", "/bin/sh", NULL,
+                         NULL, 300, 0);
+    assert_int_equal(ret, EOK);
+
+    mock_input_user("testuser_fqdn_resize@"TEST_DOM_NAME);
+    will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWNAM);
+    mock_fill_user();
+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
+
+    /* Query for that user, call a callback when command finishes */
+    set_cmd_cb(test_nss_getpwnam_check_resize_fqdn);
+    nss_test_ctx->cctx->rctx->domains[0].fqnames = true;
+    ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWNAM,
+                          nss_test_ctx->nss_cmds);
+    assert_int_equal(ret, EOK);
+
+    /* Wait until the test finishes with EOK */
+    ret = test_ev_loop(nss_test_ctx->tctx);
+    assert_int_equal(ret, EOK);
+}
+
 /* Testsuite setup and teardown */
-void nss_test_setup(void **state)
+void test_nss_setup(struct sss_test_conf_param params[],
+                    void **state)
 {
     errno_t ret;
-    struct sss_test_conf_param params[] = {
-        { "enumerate", "false" },
-        { NULL, NULL },             /* Sentinel */
-    };
 
     nss_test_ctx = talloc_zero(NULL, struct nss_test_ctx);
     assert_non_null(nss_test_ctx);
@@ -451,6 +546,38 @@ void nss_test_setup(void **state)
     assert_non_null(nss_test_ctx->cctx);
 }
 
+void nss_test_setup(void **state)
+{
+    struct sss_test_conf_param params[] = {
+        { "enumerate", "false" },
+        { NULL, NULL },             /* Sentinel */
+    };
+
+    test_nss_setup(params, state);
+}
+
+void nss_fqdn_test_setup(void **state)
+{
+    struct sss_test_conf_param params[] = {
+        { "enumerate", "false" },
+        { "full_name_format", "%1$s@%2$s" },
+        { NULL, NULL },             /* Sentinel */
+    };
+
+    test_nss_setup(params, state);
+}
+
+void nss_fqdn_resize_test_setup(void **state)
+{
+    struct sss_test_conf_param params[] = {
+        { "enumerate", "false" },
+        { "full_name_format", "%1$s@@@@@%2$s" },
+        { NULL, NULL },             /* Sentinel */
+    };
+
+    test_nss_setup(params, state);
+}
+
 void nss_test_teardown(void **state)
 {
     talloc_free(nss_test_ctx);
@@ -479,6 +606,10 @@ int main(int argc, const char *argv[])
                                  nss_test_setup, nss_test_teardown),
         unit_test_setup_teardown(test_nss_getpwnam_update,
                                  nss_test_setup, nss_test_teardown),
+        unit_test_setup_teardown(test_nss_getpwnam_fqdn,
+                                 nss_fqdn_test_setup, nss_test_teardown),
+        unit_test_setup_teardown(test_nss_getpwnam_fqdn_resize,
+                                 nss_fqdn_resize_test_setup, nss_test_teardown),
     };
 
     /* Set debug level to invalid value so we can deside if -d 0 was used. */
diff --git a/src/util/usertools.c b/src/util/usertools.c
index 835b9e3467c9345fc50cd96cbadd8c99b69d9e0a..cc8f583b9d99ef0bc817f737f8bfa7792215c730 100644
--- a/src/util/usertools.c
+++ b/src/util/usertools.c
@@ -140,12 +140,14 @@ static errno_t sss_fqnames_init(struct sss_names_ctx *nctx, const char *fq_fmt)
     struct pattern_desc {
         const char *pattern;
         const char *desc;
+        int flag;
     };
 
     struct pattern_desc fqname_patterns[] = {
-        { "%1$s", "user name" },
-        { "%2$s", "domain name" },
-        { NULL, NULL }
+        { "%1$s", "user name", FQ_FMT_NAME },
+        { "%2$s", "domain name", FQ_FMT_DOMAIN },
+        { "%3$s", "domain flat name", FQ_FMT_FLAT_NAME },
+        { NULL, NULL, 0 }
     };
 
     nctx->fq_fmt = talloc_strdup(nctx, fq_fmt);
@@ -163,12 +165,24 @@ static errno_t sss_fqnames_init(struct sss_names_ctx *nctx, const char *fq_fmt)
               ("Username pattern not found in [%s]\n", nctx->fq_fmt));
         return ENOENT;
     }
+    nctx->fq_flags = FQ_FMT_NAME;
 
-    if (strstr(fq_fmt, fqname_patterns[1].pattern) == NULL) {
-        DEBUG(SSSDBG_MINOR_FAILURE,
-              ("The pattern for %s was not found, fully-qualified names "
-               "might not work as expected\n", fqname_patterns[1].desc));
-        /* Ignore this error */
+    for (int i = 1; fqname_patterns[i].pattern; i++) {
+        char *s;
+        s = strstr(fq_fmt, fqname_patterns[i].pattern);
+        if (s == NULL) {
+            /* Append the format specifier */
+            nctx->fq_fmt = talloc_strdup_append(nctx->fq_fmt,
+                                                fqname_patterns[i].pattern);
+            if (nctx->fq_fmt == NULL) {
+                return ENOMEM;
+            }
+            continue;
+        }
+
+        DEBUG(SSSDBG_CONF_SETTINGS,
+              ("Found the pattern for %s\n", fqname_patterns[i].desc));
+        nctx->fq_flags |= fqname_patterns[i].flag;
     }
 
     return EOK;
@@ -551,17 +565,46 @@ sss_get_cased_name_list(TALLOC_CTX *mem_ctx, const char * const *orig,
 static inline const char *
 safe_fq_str(struct sss_names_ctx *nctx, uint8_t part, const char *str)
 {
-
     return nctx->fq_flags & part ? str : "";
 }
 
+static inline const char *
+safe_flat_name(struct sss_names_ctx *nctx, struct sss_domain_info *domain)
+{
+    const char *s;
+
+    s = safe_fq_str(nctx, FQ_FMT_FLAT_NAME, domain->flat_name);
+    if (s == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Flat name requested but domain has no"
+              "flat name set, falling back to domain name\n"));
+        s = domain->name;
+    }
+
+    return s;
+}
+
+static inline size_t
+fq_part_len(struct sss_names_ctx *nctx, struct sss_domain_info *dom,
+            uint8_t part, const char *str)
+{
+    const char *s = str;
+
+    if (part == FQ_FMT_FLAT_NAME) {
+        s = safe_flat_name(nctx, dom);
+    }
+    return nctx->fq_flags & part ? strlen(s) : 0;
+}
+
 char *
 sss_tc_fqname(TALLOC_CTX *mem_ctx, struct sss_names_ctx *nctx,
               struct sss_domain_info *domain, const char *name)
 {
     if (domain == NULL || nctx == NULL) return NULL;
 
-    return talloc_asprintf(mem_ctx, nctx->fq_fmt, name, domain->name);
+    return talloc_asprintf(mem_ctx, nctx->fq_fmt,
+                           safe_fq_str(nctx, FQ_FMT_NAME, name),
+                           safe_fq_str(nctx, FQ_FMT_DOMAIN, domain->name),
+                           safe_flat_name(nctx, domain));
 }
 
 int
@@ -570,5 +613,17 @@ sss_fqname(char *str, size_t size, struct sss_names_ctx *nctx,
 {
     if (domain == NULL || nctx == NULL) return -EINVAL;
 
-    return snprintf(str, size, nctx->fq_fmt, name, domain->name);
+    return snprintf(str, size, nctx->fq_fmt,
+                    safe_fq_str(nctx, FQ_FMT_NAME, name),
+                    safe_fq_str(nctx, FQ_FMT_DOMAIN, domain->name),
+                    safe_flat_name(nctx, domain));
+}
+
+size_t
+sss_fqdom_len(struct sss_names_ctx *nctx,
+              struct sss_domain_info *domain)
+{
+    size_t len = fq_part_len(nctx, domain, FQ_FMT_DOMAIN, domain->name);
+    len += fq_part_len(nctx, domain, FQ_FMT_FLAT_NAME, domain->flat_name);
+    return len;
 }
diff --git a/src/util/util.h b/src/util/util.h
index 2f65fa2017e742d4d6e373392aa76ad64536a232..87a4061e67444c8538e22a88cfe05de6b5556b6e 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -335,9 +335,14 @@ char *get_username_from_uid(TALLOC_CTX *mem_ctx, uid_t uid);
 
 char *get_uppercase_realm(TALLOC_CTX *memctx, const char *name);
 
+#define FQ_FMT_NAME         0x01
+#define FQ_FMT_DOMAIN       0x02
+#define FQ_FMT_FLAT_NAME    0x04
+
 struct sss_names_ctx {
     char *re_pattern;
     char *fq_fmt;
+    uint8_t fq_flags;
 
     pcre *re;
 };
@@ -381,6 +386,10 @@ int
 sss_fqname(char *str, size_t size, struct sss_names_ctx *nctx,
            struct sss_domain_info *domain, const char *name);
 
+size_t
+sss_fqdom_len(struct sss_names_ctx *nctx,
+              struct sss_domain_info *domain);
+
 /* from backup-file.c */
 int backup_file(const char *src, int dbglvl);
 
-- 
1.8.2.1

-------------- next part --------------
>From 0ee9171a97b62d5c090fc5c89da7a5c763c9d757 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Mon, 27 May 2013 11:49:58 +0200
Subject: [PATCH 4/4] Remove branching to improve readability

---
 src/responder/nss/nsssrv_cmd.c | 34 +++++++++++-----------------------
 1 file changed, 11 insertions(+), 23 deletions(-)

diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
index 39076e2b7e15be6737408bf4a8ec72df618d6968..3e5e8a78cf16550130be86114380df2c8a8d7a42 100644
--- a/src/responder/nss/nsssrv_cmd.c
+++ b/src/responder/nss/nsssrv_cmd.c
@@ -299,7 +299,7 @@ static int fill_pwent(struct sss_packet *packet,
     uint32_t gid;
     size_t rsize, rp, blen;
     size_t dom_len = 0;
-    int delim = 1;
+    int delim = 0;
     int i, ret, num, t;
     bool add_domain = (!IS_SUBDOMAIN(dom) && dom->fqnames);
     const char *domain = dom->name;
@@ -307,7 +307,10 @@ static int fill_pwent(struct sss_packet *packet,
     int ncret;
     TALLOC_CTX *tmp_ctx = NULL;
 
-    if (add_domain) dom_len = sss_fqdom_len(dom->names, dom);
+    if (add_domain) {
+        delim = 1;
+        dom_len = sss_fqdom_len(dom->names, dom);
+    }
 
     to_sized_string(&pwfield, nctx->pwfield);
 
@@ -2150,8 +2153,8 @@ static int fill_members(struct sss_packet *packet,
     struct sized_string name;
     TALLOC_CTX *tmp_ctx = NULL;
 
-    size_t delim;
-    size_t dom_len;
+    size_t delim = 0;
+    size_t dom_len = 0;
 
     uint8_t *body;
     size_t blen;
@@ -2162,9 +2165,6 @@ static int fill_members(struct sss_packet *packet,
     if (add_domain) {
         delim = 1;
         dom_len = sss_fqdom_len(dom->names, dom);
-    } else {
-        delim = 0;
-        dom_len = 0;
     }
 
     tmp_ctx = talloc_new(NULL);
@@ -2197,11 +2197,7 @@ static int fill_members(struct sss_packet *packet,
 
         to_sized_string(&name, tmpstr);
 
-        if (add_domain) {
-            ret = sss_packet_grow(packet, name.len + delim + dom_len);
-        } else {
-            ret = sss_packet_grow(packet, name.len);
-        }
+        ret = sss_packet_grow(packet, name.len + delim + dom_len);
         if (ret != EOK) {
             goto done;
         }
@@ -2245,12 +2241,7 @@ static int fill_members(struct sss_packet *packet,
             memcpy(&body[rzero + rsize], name.str, name.len);
         }
 
-        if (add_domain) {
-            rsize += name.len + delim + dom_len;
-        } else {
-            rsize += name.len;
-        }
-
+        rsize += name.len + delim + dom_len;
         memnum++;
     }
 
@@ -2281,8 +2272,8 @@ static int fill_grent(struct sss_packet *packet,
     struct sized_string name;
     struct sized_string pwfield;
     struct sized_string fullname;
-    size_t delim;
-    size_t dom_len;
+    size_t delim = 0;
+    size_t dom_len = 0;
     int i = 0;
     int ret, num, memnum;
     size_t rzero, rsize;
@@ -2293,9 +2284,6 @@ static int fill_grent(struct sss_packet *packet,
     if (add_domain) {
         delim = 1;
         dom_len = sss_fqdom_len(dom->names, dom);
-    } else {
-        delim = 0;
-        dom_len = 0;
     }
 
     to_sized_string(&pwfield, nctx->pwfield);
-- 
1.8.2.1



More information about the sssd-devel mailing list