[SSSD] [PATCH] Support flat name in the full_name_format
Jakub Hrozek
jhrozek at redhat.com
Sat May 11 18:45:40 UTC 2013
Hi,
the attached patches add support for using flat name in the FQDN output
specifier.
The problem with this RFE was that the format is a printf-like format
specifier and backwards compatibility must be maintained. I used an idea
that originally came from Sumit to add a new expansion to the existing
name and domain ones. But in order to avoid compile-time warnings, I had
to make sure the format specifier and the arguments match 1:1 -- so the
code adds the unused format specifier and defaults the unused arguments
to "".
[PATCH 1/3] 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.
[PATCH 2/3] 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.
[PATCH 3/3] 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. Includes a unit test.
-------------- next part --------------
>From 695b233d2aaba1c61ecfa0f14d5e58b69f96cae5 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/3] 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 c409e794716c8763ea78b029d777be96cd4ef3a5..4f175dc50e834b3eb36da0af01f59c2864ef01a8 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;
@@ -2148,7 +2143,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;
@@ -2209,9 +2203,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 ? */
@@ -2224,9 +2218,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) {
@@ -2289,11 +2283,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);
@@ -2379,9 +2370,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;
@@ -2395,9 +2386,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) {
@@ -3670,8 +3661,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;
@@ -4040,8 +4030,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 49dc850c36cedd83755034367357fab41bd32ec6..8c46a643d38845f13002e75f6c9af9f179a8f708 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"
@@ -425,6 +426,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 62fa93fe1e439b5d9b530cce37c4a3d035bd8bca 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/3] 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 7ee9eddb67626c016422ab0cc1bf5e3eb36535d0 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/3] 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 | 58 ++++++++-
src/tests/cmocka/test_fqnames.c | 271 ++++++++++++++++++++++++++++++++++++++++
src/util/usertools.c | 56 +++++++--
src/util/util.h | 5 +
5 files changed, 386 insertions(+), 17 deletions(-)
create mode 100644 src/tests/cmocka/test_fqnames.c
diff --git a/Makefile.am b/Makefile.am
index b72384a77fe5bb3d2d40229026c463fefabc1387..22984445d3f765ef6b29ee15e3620173c9fcf284 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 = \
@@ -1303,6 +1304,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 99337fbba9fb8d39a62eb84313c5b89761ee950d..85ed1fe55f2d14dddcf960795ab4469f82a9525b 100644
--- a/src/man/sssd.conf.5.xml
+++ b/src/man/sssd.conf.5.xml
@@ -143,12 +143,36 @@
<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</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 +1557,32 @@ 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</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/tests/cmocka/test_fqnames.c b/src/tests/cmocka/test_fqnames.c
new file mode 100644
index 0000000000000000000000000000000000000000..c0f36389e1b84748ac9ac6d6a6ca6cd24b20df0e
--- /dev/null
+++ b/src/tests/cmocka/test_fqnames.c
@@ -0,0 +1,271 @@
+/*
+ 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];
+
+ 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);
+
+ 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];
+
+ 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);
+
+ 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];
+
+ 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);
+
+ 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];
+
+ 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);
+
+ 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/util/usertools.c b/src/util/usertools.c
index 835b9e3467c9345fc50cd96cbadd8c99b69d9e0a..991975cbb0867a10c258447cfd073250c6a7b801 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,34 @@ 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;
+}
+
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 +601,8 @@ 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));
}
diff --git a/src/util/util.h b/src/util/util.h
index 8c46a643d38845f13002e75f6c9af9f179a8f708..bc81ffb6619699bfbba9370bb16d585c9b1c80c4 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -395,9 +395,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;
};
--
1.8.2.1
More information about the sssd-devel
mailing list