New upstream release 1.15.3

https://docs.pagure.org/SSSD.sssd/users/relnotes/notes_1_15_3.html
This commit is contained in:
Lukas Slebodnik 2017-07-25 13:58:49 +02:00
parent ca67484fda
commit 6302a22355
140 changed files with 104 additions and 41079 deletions

1
.gitignore vendored
View File

@ -76,3 +76,4 @@ sssd-1.2.91.tar.gz
/sssd-1.15.0.tar.gz
/sssd-1.15.1.tar.gz
/sssd-1.15.2.tar.gz
/sssd-1.15.3.tar.gz

View File

@ -1,23 +0,0 @@
From 012ee7c3fe24a5e75d9b0465268c1bb8187b8337 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Wed, 15 Mar 2017 18:00:37 +0100
Subject: [PATCH 01/97] Updating the version for the 1.15.3 release
---
version.m4 | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/version.m4 b/version.m4
index 11e5e71b08b8af7c8d4f39410fea99d5d2ce3a00..da96ecd2e2d58e3e6079741f81a07f99259010b4 100644
--- a/version.m4
+++ b/version.m4
@@ -1,5 +1,5 @@
# Primary version number
-m4_define([VERSION_NUMBER], [1.15.2])
+m4_define([VERSION_NUMBER], [1.15.3])
# If the PRERELEASE_VERSION_NUMBER is set, we'll append
# it to the release tag when creating an RPM or SRPM
--
2.12.2

View File

@ -1,29 +0,0 @@
From 6fb643c75e59e093c8c52def162ce1f1956430c7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
Date: Tue, 14 Mar 2017 18:20:43 +0100
Subject: [PATCH 02/97] UTIL: Typo in comment
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
---
src/util/safe-format-string.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/util/safe-format-string.h b/src/util/safe-format-string.h
index 2f4796de7cea66d9ff0cd808e9e7c33de053feb8..fdebcf966554bcce150ed531173e991973698da0 100644
--- a/src/util/safe-format-string.h
+++ b/src/util/safe-format-string.h
@@ -42,7 +42,7 @@
* Features:
* - Only string 's' fields are supported
* - All the varargs should be strings, followed by a NULL argument
- * - Both positional '%$1s' and non-positional '%s' are supported
+ * - Both positional '%1$s' and non-positional '%s' are supported
* - Field widths '%8s' work as expected
* - Precision '%.8s' works, but precision cannot be read from a field
* - Left alignment flag is supported '%-8s'.
--
2.12.2

View File

@ -1,36 +0,0 @@
From 3c071c4d6ec0d8f798eb862ebc4584123ff44663 Mon Sep 17 00:00:00 2001
From: Lukas Slebodnik <lslebodn@redhat.com>
Date: Tue, 21 Mar 2017 12:27:16 +0100
Subject: [PATCH 03/97] MAN: Mention sssd-secrets in "SEE ALSO" section
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Resolves:
https://pagure.io/SSSD/sssd/issue/3344
Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
---
src/man/include/seealso.xml | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/man/include/seealso.xml b/src/man/include/seealso.xml
index 25b421748fb19881552de8b6384af2c794063e11..2e9c646c475887bce3612472975ade375edbd819 100644
--- a/src/man/include/seealso.xml
+++ b/src/man/include/seealso.xml
@@ -28,6 +28,12 @@
<manvolnum>5</manvolnum>
</citerefentry>,
</phrase>
+ <phrase condition="with_secrets">
+ <citerefentry>
+ <refentrytitle>sssd-secrets</refentrytitle>
+ <manvolnum>5</manvolnum>
+ </citerefentry>,
+ </phrase>
<citerefentry>
<refentrytitle>sss_cache</refentrytitle><manvolnum>8</manvolnum>
</citerefentry>,
--
2.12.2

View File

@ -1,369 +0,0 @@
From 843bc50c04afa6e4f4a4561d887bbbd5f7101ce1 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Wed, 8 Feb 2017 14:28:28 +0100
Subject: [PATCH 04/97] split_on_separator: move to a separate file
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
To be able to include split_on_separator() without additional
dependencies (only talloc), it is moved into a separate file.
Related to https://pagure.io/SSSD/sssd/issue/3050
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
---
Makefile.am | 30 ++++++++++---
src/util/util.c | 93 ----------------------------------------
src/util/util_ext.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 144 insertions(+), 100 deletions(-)
create mode 100644 src/util/util_ext.c
diff --git a/Makefile.am b/Makefile.am
index 45b04de2638a745a189c0b4e5794ccd29913b10d..6dae4f2dd7f2dee501add82c7ab4f15fcbcc59ac 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -987,6 +987,7 @@ libsss_util_la_SOURCES = \
src/sbus/sssd_dbus_common_signals.c \
src/sbus/sssd_dbus_utils.c \
src/util/util.c \
+ src/util/util_ext.c \
src/util/memory.c \
src/util/safe-format-string.c \
src/util/server.c \
@@ -2355,19 +2356,23 @@ test_authtok_SOURCES = \
src/tests/cmocka/test_authtok.c \
src/util/authtok.c \
src/util/authtok-utils.c \
- src/util/util.c
+ src/util/util.c \
+ src/util/util_ext.c \
+ $(NULL)
test_authtok_CFLAGS = \
$(AM_CFLAGS) \
$(TALLOC_CFLAGS) \
$(POPT_CFLAGS) \
- $(DHASH_CFLAGS)
+ $(DHASH_CFLAGS) \
+ $(NULL)
test_authtok_LDADD = \
$(TALLOC_LIBS) \
$(CMOCKA_LIBS) \
$(DHASH_LIBS) \
$(POPT_LIBS) \
libsss_test_common.la \
- libsss_debug.la
+ libsss_debug.la \
+ $(NULL)
sss_nss_idmap_tests_SOURCES = \
src/tests/cmocka/sss_nss_idmap-tests.c
@@ -2839,6 +2844,7 @@ test_child_common_SOURCES = \
src/util/atomic_io.c \
src/util/util_errors.c \
src/util/util.c \
+ src/util/util_ext.c \
$(NULL)
test_child_common_CFLAGS = \
$(AM_CFLAGS) \
@@ -3774,6 +3780,7 @@ krb5_child_SOURCES = \
src/util/authtok.c \
src/util/authtok-utils.c \
src/util/util.c \
+ src/util/util_ext.c \
src/util/signal.c \
src/util/strtonum.c \
src/util/become_user.c \
@@ -3807,6 +3814,7 @@ ldap_child_SOURCES = \
src/util/authtok.c \
src/util/authtok-utils.c \
src/util/util.c \
+ src/util/util_ext.c \
src/util/signal.c \
src/util/become_user.c \
$(NULL)
@@ -3827,6 +3835,7 @@ selinux_child_SOURCES = \
src/util/sss_semanage.c \
src/util/atomic_io.c \
src/util/util.c \
+ src/util/util_ext.c \
$(NULL)
selinux_child_CFLAGS = \
$(AM_CFLAGS) \
@@ -3845,6 +3854,7 @@ gpo_child_SOURCES = \
src/providers/ad/ad_gpo_child.c \
src/util/atomic_io.c \
src/util/util.c \
+ src/util/util_ext.c \
src/util/signal.c
gpo_child_CFLAGS = \
$(AM_CFLAGS) \
@@ -3876,6 +3886,7 @@ p11_child_SOURCES = \
src/p11_child/p11_child_nss.c \
src/util/atomic_io.c \
src/util/util.c \
+ src/util/util_ext.c \
$(NULL)
p11_child_CFLAGS = \
$(AM_CFLAGS) \
@@ -3893,16 +3904,21 @@ p11_child_LDADD = \
memberof_la_SOURCES = \
src/ldb_modules/memberof.c \
- src/util/util.c
+ src/util/util.c \
+ src/util/util_ext.c \
+ $(NULL)
memberof_la_CFLAGS = \
- $(AM_CFLAGS)
+ $(AM_CFLAGS) \
+ $(NULL)
memberof_la_LIBADD = \
libsss_debug.la \
$(LDB_LIBS) \
- $(DHASH_LIBS)
+ $(DHASH_LIBS) \
+ $(NULL)
memberof_la_LDFLAGS = \
-avoid-version \
- -module
+ -module \
+ $(NULL)
if BUILD_KRB5_LOCATOR_PLUGIN
sssd_krb5_locator_plugin_la_SOURCES = \
diff --git a/src/util/util.c b/src/util/util.c
index a528f0c0249c33bfc3d3275250e74d5edcef2e6f..9d6202f695d516f20d648621da81a2d5e746daa5 100644
--- a/src/util/util.c
+++ b/src/util/util.c
@@ -35,99 +35,6 @@
int socket_activated = 0;
int dbus_activated = 0;
-int split_on_separator(TALLOC_CTX *mem_ctx, const char *str,
- const char sep, bool trim, bool skip_empty,
- char ***_list, int *size)
-{
- int ret;
- const char *substr_end = str;
- const char *substr_begin = str;
- const char *sep_pos = NULL;
- size_t substr_len;
- char **list = NULL;
- int num_strings = 0;
- TALLOC_CTX *tmp_ctx = NULL;
-
- if (str == NULL || *str == '\0' || _list == NULL) {
- return EINVAL;
- }
-
- tmp_ctx = talloc_new(NULL);
- if (tmp_ctx == NULL) {
- return ENOMEM;
- }
-
- do {
- substr_len = 0;
-
- /* If this is not the first substring, then move from the separator. */
- if (sep_pos != NULL) {
- substr_end = sep_pos + 1;
- substr_begin = sep_pos + 1;
- }
-
- /* Find end of the first substring */
- while (*substr_end != sep && *substr_end != '\0') {
- substr_end++;
- substr_len++;
- }
-
- sep_pos = substr_end;
-
- if (trim) {
- /* Trim leading whitespace */
- while (isspace(*substr_begin) && substr_begin < substr_end) {
- substr_begin++;
- substr_len--;
- }
-
- /* Trim trailing whitespace */
- while (substr_end - 1 > substr_begin && isspace(*(substr_end-1))) {
- substr_end--;
- substr_len--;
- }
- }
-
- /* Copy the substring to the output list of strings */
- if (skip_empty == false || substr_len > 0) {
- list = talloc_realloc(tmp_ctx, list, char*, num_strings + 2);
- if (list == NULL) {
- ret = ENOMEM;
- goto done;
- }
-
- /* empty string is stored for substr_len == 0 */
- list[num_strings] = talloc_strndup(list, substr_begin, substr_len);
- if (list[num_strings] == NULL) {
- ret = ENOMEM;
- goto done;
- }
- num_strings++;
- }
-
- } while (*sep_pos != '\0');
-
- if (list == NULL) {
- /* No allocations were done, make space for the NULL */
- list = talloc(tmp_ctx, char *);
- if (list == NULL) {
- ret = ENOMEM;
- goto done;
- }
- }
- list[num_strings] = NULL;
-
- if (size) {
- *size = num_strings;
- }
-
- *_list = talloc_steal(mem_ctx, list);
- ret = EOK;
-done:
- talloc_free(tmp_ctx);
- return ret;
-}
-
static void free_args(char **args)
{
int i;
diff --git a/src/util/util_ext.c b/src/util/util_ext.c
new file mode 100644
index 0000000000000000000000000000000000000000..fceb8c873a26471d476b39d5d4e567c445ed8d0b
--- /dev/null
+++ b/src/util/util_ext.c
@@ -0,0 +1,121 @@
+/*
+ SSSD helper calls - can be used by libraries for external use as well
+
+ Authors:
+ Simo Sorce <ssorce@redhat.com>
+
+ Copyright (C) 2017 Red Hat
+
+ 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 <talloc.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <ctype.h>
+
+#define EOK 0
+
+int split_on_separator(TALLOC_CTX *mem_ctx, const char *str,
+ const char sep, bool trim, bool skip_empty,
+ char ***_list, int *size)
+{
+ int ret;
+ const char *substr_end = str;
+ const char *substr_begin = str;
+ const char *sep_pos = NULL;
+ size_t substr_len;
+ char **list = NULL;
+ int num_strings = 0;
+ TALLOC_CTX *tmp_ctx = NULL;
+
+ if (str == NULL || *str == '\0' || _list == NULL) {
+ return EINVAL;
+ }
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ do {
+ substr_len = 0;
+
+ /* If this is not the first substring, then move from the separator. */
+ if (sep_pos != NULL) {
+ substr_end = sep_pos + 1;
+ substr_begin = sep_pos + 1;
+ }
+
+ /* Find end of the first substring */
+ while (*substr_end != sep && *substr_end != '\0') {
+ substr_end++;
+ substr_len++;
+ }
+
+ sep_pos = substr_end;
+
+ if (trim) {
+ /* Trim leading whitespace */
+ while (isspace(*substr_begin) && substr_begin < substr_end) {
+ substr_begin++;
+ substr_len--;
+ }
+
+ /* Trim trailing whitespace */
+ while (substr_end - 1 > substr_begin && isspace(*(substr_end-1))) {
+ substr_end--;
+ substr_len--;
+ }
+ }
+
+ /* Copy the substring to the output list of strings */
+ if (skip_empty == false || substr_len > 0) {
+ list = talloc_realloc(tmp_ctx, list, char*, num_strings + 2);
+ if (list == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ /* empty string is stored for substr_len == 0 */
+ list[num_strings] = talloc_strndup(list, substr_begin, substr_len);
+ if (list[num_strings] == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ num_strings++;
+ }
+
+ } while (*sep_pos != '\0');
+
+ if (list == NULL) {
+ /* No allocations were done, make space for the NULL */
+ list = talloc(tmp_ctx, char *);
+ if (list == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+ list[num_strings] = NULL;
+
+ if (size) {
+ *size = num_strings;
+ }
+
+ *_list = talloc_steal(mem_ctx, list);
+ ret = EOK;
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
--
2.12.2

View File

@ -1,91 +0,0 @@
From 8b7548f65a0d812a47d26895671ec6f01b6813c1 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Mon, 20 Feb 2017 17:28:51 +0100
Subject: [PATCH 05/97] util: move string_in_list to util_ext
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
To be able to include string_in_list() without additional
dependencies it is moved into a separate file.
Related to https://pagure.io/SSSD/sssd/issue/3050
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
---
src/util/util.c | 20 --------------------
src/util/util_ext.c | 22 ++++++++++++++++++++++
2 files changed, 22 insertions(+), 20 deletions(-)
diff --git a/src/util/util.c b/src/util/util.c
index 9d6202f695d516f20d648621da81a2d5e746daa5..f0e8f9dd6a4bceed6befb74c57aa066b19a72bb7 100644
--- a/src/util/util.c
+++ b/src/util/util.c
@@ -617,26 +617,6 @@ errno_t add_string_to_list(TALLOC_CTX *mem_ctx, const char *string,
return EOK;
}
-bool string_in_list(const char *string, char **list, bool case_sensitive)
-{
- size_t c;
- int(*compare)(const char *s1, const char *s2);
-
- if (string == NULL || list == NULL || *list == NULL) {
- return false;
- }
-
- compare = case_sensitive ? strcmp : strcasecmp;
-
- for (c = 0; list[c] != NULL; c++) {
- if (compare(string, list[c]) == 0) {
- return true;
- }
- }
-
- return false;
-}
-
void safezero(void *data, size_t size)
{
volatile uint8_t *p = data;
diff --git a/src/util/util_ext.c b/src/util/util_ext.c
index fceb8c873a26471d476b39d5d4e567c445ed8d0b..04dc02a8adf32bd0590fe6eba230658e67d0a362 100644
--- a/src/util/util_ext.c
+++ b/src/util/util_ext.c
@@ -24,6 +24,8 @@
#include <stdbool.h>
#include <errno.h>
#include <ctype.h>
+#include <string.h>
+#include <strings.h>
#define EOK 0
@@ -119,3 +121,23 @@ done:
talloc_free(tmp_ctx);
return ret;
}
+
+bool string_in_list(const char *string, char **list, bool case_sensitive)
+{
+ size_t c;
+ int(*compare)(const char *s1, const char *s2);
+
+ if (string == NULL || list == NULL || *list == NULL) {
+ return false;
+ }
+
+ compare = case_sensitive ? strcmp : strcasecmp;
+
+ for (c = 0; list[c] != NULL; c++) {
+ if (compare(string, list[c]) == 0) {
+ return true;
+ }
+ }
+
+ return false;
+}
--
2.12.2

File diff suppressed because it is too large Load Diff

View File

@ -1,151 +0,0 @@
From 31a6661ff2a640fbcf97460df2415fd1bab309b5 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Wed, 15 Mar 2017 10:57:09 +0100
Subject: [PATCH 07/97] certmap: add placeholder for OpenSSL implementation
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
---
Makefile.am | 30 +++++++++++++++++++++--------
src/lib/certmap/sss_cert_content_crypto.c | 32 +++++++++++++++++++++++++++++++
src/lib/certmap/sss_certmap_int.h | 8 +++++---
3 files changed, 59 insertions(+), 11 deletions(-)
create mode 100644 src/lib/certmap/sss_cert_content_crypto.c
diff --git a/Makefile.am b/Makefile.am
index 8ca12c10d2713b6a72361d84b25486500c79f407..7947b7a5fbe3ca1034baac1c13c53300994b1bf8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -278,9 +278,12 @@ if HAVE_CMOCKA
simple-access-tests \
krb5_common_test \
test_iobuf \
- sss_certmap_test \
$(NULL)
+if HAVE_NSS
+non_interactive_cmocka_based_tests += sss_certmap_test
+endif #HAVE_NSS
+
if HAVE_LIBRESOLV
non_interactive_cmocka_based_tests += test_resolv_fake
endif # HAVE_LIBRESOLV
@@ -1715,7 +1718,6 @@ sssd_check_socket_activated_responders_LDADD = \
$(NULL)
endif
-if HAVE_NSS
pkgconfig_DATA += src/lib/certmap/sss_certmap.pc
libsss_certmap_la_DEPENDENCIES = src/lib/certmap/sss_certmap.exports
libsss_certmap_la_SOURCES = \
@@ -1726,26 +1728,38 @@ libsss_certmap_la_SOURCES = \
src/lib/certmap/sss_certmap_ldap_mapping.c \
src/util/util_ext.c \
src/util/cert/cert_common.c \
- src/util/crypto/nss/nss_base64.c \
- src/util/cert/nss/cert.c \
- src/util/crypto/nss/nss_util.c \
$(NULL)
libsss_certmap_la_CFLAGS = \
$(AM_CFLAGS) \
$(TALLOC_CFLAGS) \
- $(NSS_CFLAGS) \
$(NULL)
libsss_certmap_la_LIBADD = \
$(TALLOC_LIBS) \
- $(NSS_LIBS) \
$(NULL)
libsss_certmap_la_LDFLAGS = \
-Wl,--version-script,$(srcdir)/src/lib/certmap/sss_certmap.exports \
-version-info 0:0:0
+if HAVE_NSS
+libsss_certmap_la_SOURCES += \
+ src/util/crypto/nss/nss_base64.c \
+ src/util/cert/nss/cert.c \
+ src/util/crypto/nss/nss_util.c \
+ $(NULL)
+libsss_certmap_la_CFLAGS += $(NSS_CFLAGS)
+libsss_certmap_la_LIBADD += $(NSS_LIBS)
+else
+libsss_certmap_la_SOURCES += \
+ src/util/crypto/libcrypto/crypto_base64.c \
+ src/util/cert/libcrypto/cert.c \
+ $(NULL)
+
+libsss_certmap_la_CFLAGS += $(CRYPTO_CFLAGS)
+libsss_certmap_la_LIBADD += $(CRYPTO_LIBS)
+endif
+
dist_noinst_DATA += src/lib/certmap/sss_certmap.exports
dist_noinst_HEADERS += src/lib/certmap/sss_certmap_int.h
-endif
#################
# Feature Tests #
diff --git a/src/lib/certmap/sss_cert_content_crypto.c b/src/lib/certmap/sss_cert_content_crypto.c
new file mode 100644
index 0000000000000000000000000000000000000000..bddcf9bce986bd986aa0aa5f16a0744a97ab36d6
--- /dev/null
+++ b/src/lib/certmap/sss_cert_content_crypto.c
@@ -0,0 +1,32 @@
+/*
+ SSSD - certificate handling utils - OpenSSL version
+ The calls defined here should be useable outside of SSSD as well, e.g. in
+ libsss_certmap.
+
+ Copyright (C) Sumit Bose <sbose@redhat.com> 2017
+
+ 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 <errno.h>
+
+#include "lib/certmap/sss_certmap.h"
+#include "lib/certmap/sss_certmap_int.h"
+
+int sss_cert_get_content(TALLOC_CTX *mem_ctx,
+ const uint8_t *der_blob, size_t der_size,
+ struct sss_cert_content **content)
+{
+ return EINVAL;
+}
diff --git a/src/lib/certmap/sss_certmap_int.h b/src/lib/certmap/sss_certmap_int.h
index 28f1c596cfb5e78077b6a8e9baefa88b4900a022..0b4cda73639be9b323ac3388f97be90bc1a771f2 100644
--- a/src/lib/certmap/sss_certmap_int.h
+++ b/src/lib/certmap/sss_certmap_int.h
@@ -22,12 +22,14 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <sys/types.h>
-#include <regex.h>
-
#ifndef __SSS_CERTMAP_INT_H__
#define __SSS_CERTMAP_INT_H__
+#include <sys/types.h>
+#include <regex.h>
+#include <stdint.h>
+#include <talloc.h>
+
#define CM_DEBUG(cm_ctx, format, ...) do { \
if (cm_ctx != NULL && cm_ctx->debug != NULL) { \
cm_ctx->debug(cm_ctx->debug_priv, __FILE__, __LINE__, __FUNCTION__, \
--
2.12.2

View File

@ -1,173 +0,0 @@
From 3994e8779d16db3e9fb30f03e5ecf5e811095ac2 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Mon, 21 Sep 2015 12:32:48 +0200
Subject: [PATCH 08/97] sysdb: add sysdb_attrs_copy()
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Related to https://pagure.io/SSSD/sssd/issue/3050
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
---
src/db/sysdb.c | 24 ++++++++++++++
src/db/sysdb.h | 1 +
src/tests/sysdb-tests.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 112 insertions(+)
diff --git a/src/db/sysdb.c b/src/db/sysdb.c
index 5160e3df3810a113d4ec1371350e51a074aaa146..98b7afbfab5141fa9b63a4aab31c620545b3c1f2 100644
--- a/src/db/sysdb.c
+++ b/src/db/sysdb.c
@@ -752,6 +752,30 @@ done:
return ret;
}
+errno_t sysdb_attrs_copy(struct sysdb_attrs *src, struct sysdb_attrs *dst)
+{
+ int ret;
+ size_t c;
+ size_t d;
+
+ if (src == NULL || dst == NULL) {
+ return EINVAL;
+ }
+
+ for (c = 0; c < src->num; c++) {
+ for (d = 0; d < src->a[c].num_values; d++) {
+ ret = sysdb_attrs_add_val_safe(dst, src->a[c].name,
+ &src->a[c].values[d]);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_val failed.\n");
+ return ret;
+ }
+ }
+ }
+
+ return EOK;
+}
+
int sysdb_attrs_users_from_str_list(struct sysdb_attrs *attrs,
const char *attr_name,
const char *domain,
diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index 83d0d794c737c094d1fd52e7cc7f2113b5d9a7a0..c677957bb639e40db2f985205160612094302e78 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -352,6 +352,7 @@ int sysdb_attrs_add_lc_name_alias_safe(struct sysdb_attrs *attrs,
int sysdb_attrs_copy_values(struct sysdb_attrs *src,
struct sysdb_attrs *dst,
const char *name);
+errno_t sysdb_attrs_copy(struct sysdb_attrs *src, struct sysdb_attrs *dst);
int sysdb_attrs_get_el(struct sysdb_attrs *attrs, const char *name,
struct ldb_message_element **el);
int sysdb_attrs_get_el_ext(struct sysdb_attrs *attrs, const char *name,
diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c
index 013b01a9a68d9de87d796d3aff41d98cef8cccc3..c343c734a27a335303974b6866a5d9e88d4c307e 100644
--- a/src/tests/sysdb-tests.c
+++ b/src/tests/sysdb-tests.c
@@ -4997,6 +4997,92 @@ START_TEST(test_sysdb_attrs_add_string_safe)
}
END_TEST
+START_TEST(test_sysdb_attrs_copy)
+{
+ int ret;
+ struct sysdb_attrs *src;
+ struct sysdb_attrs *dst;
+ TALLOC_CTX *tmp_ctx;
+ const char *val;
+ const char **array;
+
+ ret = sysdb_attrs_copy(NULL, NULL);
+ fail_unless(ret == EINVAL, "Wrong return code");
+
+ tmp_ctx = talloc_new(NULL);
+ fail_unless(tmp_ctx != NULL, "talloc_new failed");
+
+ src = sysdb_new_attrs(tmp_ctx);
+ fail_unless(src != NULL, "sysdb_new_attrs failed");
+
+ ret = sysdb_attrs_copy(src, NULL);
+ fail_unless(ret == EINVAL, "Wrong return code");
+
+ dst = sysdb_new_attrs(tmp_ctx);
+ fail_unless(dst != NULL, "sysdb_new_attrs failed");
+
+ ret = sysdb_attrs_copy(NULL, dst);
+ fail_unless(ret == EINVAL, "Wrong return code");
+
+ ret = sysdb_attrs_copy(src, dst);
+ fail_unless(ret == EOK, "sysdb_attrs_copy failed");
+ fail_unless(dst->num == 0, "Wrong number of elements");
+
+ ret = sysdb_attrs_add_string(src, TEST_ATTR_NAME, TEST_ATTR_VALUE);
+ fail_unless(ret == EOK, "sysdb_attrs_add_val failed.");
+
+ ret = sysdb_attrs_copy(src, dst);
+ fail_unless(ret == EOK, "sysdb_attrs_copy failed");
+ fail_unless(dst->num == 1, "Wrong number of elements");
+ ret = sysdb_attrs_get_string(dst, TEST_ATTR_NAME, &val);
+ fail_unless(ret == EOK, "sysdb_attrs_get_string failed.\n");
+ fail_unless(strcmp(val, TEST_ATTR_VALUE) == 0, "Wrong attribute value.");
+
+ /* Make sure the same entry is not copied twice */
+ ret = sysdb_attrs_copy(src, dst);
+ fail_unless(ret == EOK, "sysdb_attrs_copy failed");
+ fail_unless(dst->num == 1, "Wrong number of elements");
+ ret = sysdb_attrs_get_string(dst, TEST_ATTR_NAME, &val);
+ fail_unless(ret == EOK, "sysdb_attrs_get_string failed.\n");
+ fail_unless(strcmp(val, TEST_ATTR_VALUE) == 0, "Wrong attribute value.");
+
+ /* Add new value to existing attribute */
+ ret = sysdb_attrs_add_string(src, TEST_ATTR_NAME, TEST_ATTR_VALUE"_2nd");
+ fail_unless(ret == EOK, "sysdb_attrs_add_val failed.");
+
+ ret = sysdb_attrs_copy(src, dst);
+ fail_unless(ret == EOK, "sysdb_attrs_copy failed");
+ fail_unless(dst->num == 1, "Wrong number of elements");
+ ret = sysdb_attrs_get_string_array(dst, TEST_ATTR_NAME, tmp_ctx, &array);
+ fail_unless(ret == EOK, "sysdb_attrs_get_string_array failed.\n");
+ fail_unless(strcmp(array[0], TEST_ATTR_VALUE) == 0,
+ "Wrong attribute value.");
+ fail_unless(strcmp(array[1], TEST_ATTR_VALUE"_2nd") == 0,
+ "Wrong attribute value.");
+ fail_unless(array[2] == NULL, "Wrong number of values.");
+
+ /* Add new attribute */
+ ret = sysdb_attrs_add_string(src, TEST_ATTR_NAME"_2nd", TEST_ATTR_VALUE);
+ fail_unless(ret == EOK, "sysdb_attrs_add_val failed.");
+
+ ret = sysdb_attrs_copy(src, dst);
+ fail_unless(ret == EOK, "sysdb_attrs_copy failed");
+ fail_unless(dst->num == 2, "Wrong number of elements");
+ ret = sysdb_attrs_get_string_array(dst, TEST_ATTR_NAME, tmp_ctx, &array);
+ fail_unless(ret == EOK, "sysdb_attrs_get_string_array failed.\n");
+ fail_unless(strcmp(array[0], TEST_ATTR_VALUE) == 0,
+ "Wrong attribute value.");
+ fail_unless(strcmp(array[1], TEST_ATTR_VALUE"_2nd") == 0,
+ "Wrong attribute value.");
+ fail_unless(array[2] == NULL, "Wrong number of values.");
+ ret = sysdb_attrs_get_string(dst, TEST_ATTR_NAME"_2nd", &val);
+ fail_unless(ret == EOK, "sysdb_attrs_get_string failed.\n");
+ fail_unless(strcmp(val, TEST_ATTR_VALUE) == 0, "Wrong attribute value.");
+
+ talloc_free(tmp_ctx);
+}
+END_TEST
+
START_TEST (test_sysdb_search_return_ENOENT)
{
struct sysdb_test_ctx *test_ctx;
@@ -6995,6 +7081,7 @@ Suite *create_sysdb_suite(void)
tcase_add_test(tc_sysdb, test_sysdb_attrs_add_val);
tcase_add_test(tc_sysdb, test_sysdb_attrs_add_val_safe);
tcase_add_test(tc_sysdb, test_sysdb_attrs_add_string_safe);
+ tcase_add_test(tc_sysdb, test_sysdb_attrs_copy);
/* ===== Test search return empty result ===== */
tcase_add_test(tc_sysdb, test_sysdb_search_return_ENOENT);
--
2.12.2

View File

@ -1,316 +0,0 @@
From 70c0648f021ded3d31313eb962e1ad140f242673 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Sun, 12 Mar 2017 18:31:03 +0100
Subject: [PATCH 09/97] sdap_get_users_send(): new argument mapped_attrs
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
mapped_attrs can be a list of sysdb_attrs which are not available on
the server side but should be store with the cached user entry. This is
needed e.g. when the input to look up the user in LDAP is not an
attribute which is stored in LDAP but some data where LDAP attributes
are extracted from. The current use case is the certificate mapping
library which can create LDAP search filters based on content of the
certificate. To allow upcoming cache lookup to use the input directly it
is stored in the user object in the cache.
Related to https://pagure.io/SSSD/sssd/issue/3050
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
---
src/db/sysdb.h | 3 ++
src/db/sysdb_ops.c | 61 ++++++++++++++++++++++++++++++
src/providers/ldap/ldap_id.c | 4 +-
src/providers/ldap/sdap_async.h | 3 +-
src/providers/ldap/sdap_async_enum.c | 2 +-
src/providers/ldap/sdap_async_initgroups.c | 2 +-
src/providers/ldap/sdap_async_private.h | 1 +
src/providers/ldap/sdap_async_users.c | 41 +++++++++++++++++++-
src/providers/ldap/sdap_users.h | 1 +
9 files changed, 111 insertions(+), 7 deletions(-)
diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index c677957bb639e40db2f985205160612094302e78..098f47f91187aac75c58c02f0af738c344765762 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -1246,6 +1246,9 @@ errno_t sysdb_search_user_by_cert(TALLOC_CTX *mem_ctx,
errno_t sysdb_remove_cert(struct sss_domain_info *domain,
const char *cert);
+errno_t sysdb_remove_mapped_data(struct sss_domain_info *domain,
+ struct sysdb_attrs *mapped_attr);
+
/* === Functions related to GPOs === */
#define SYSDB_GPO_CONTAINER "cn=gpos,cn=ad,cn=custom"
diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c
index 242d3ce3bb795691e329790a07c3493672e8f523..6c2254df2b75d3d3419528523103ad9cddb40c9d 100644
--- a/src/db/sysdb_ops.c
+++ b/src/db/sysdb_ops.c
@@ -4685,6 +4685,67 @@ errno_t sysdb_search_user_by_cert(TALLOC_CTX *mem_ctx,
return sysdb_search_object_by_cert(mem_ctx, domain, cert, user_attrs, res);
}
+errno_t sysdb_remove_mapped_data(struct sss_domain_info *domain,
+ struct sysdb_attrs *mapped_attr)
+{
+ int ret;
+ char *val;
+ char *filter;
+ const char *attrs[] = {SYSDB_NAME, NULL};
+ struct ldb_result *res = NULL;
+ size_t c;
+ bool all_ok = true;
+
+ if (mapped_attr->num != 1 || mapped_attr->a[0].num_values != 1) {
+ DEBUG(SSSDBG_OP_FAILURE, "Unsupported number of attributes.\n");
+ return EINVAL;
+ }
+
+ ret = bin_to_ldap_filter_value(NULL, mapped_attr->a[0].values[0].data,
+ mapped_attr->a[0].values[0].length, &val);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "bin_to_ldap_filter_value failed.\n");
+ return ret;
+ }
+
+ filter = talloc_asprintf(NULL, "(&("SYSDB_UC")(%s=%s))",
+ mapped_attr->a[0].name, val);
+ talloc_free(val);
+ if (filter == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
+ return ENOMEM;
+ }
+
+ ret = sysdb_search_object_attr(NULL, domain, filter, attrs, false, &res);
+ talloc_free(filter);
+ if (ret == ENOENT || res == NULL) {
+ DEBUG(SSSDBG_TRACE_ALL, "Mapped data not found.\n");
+ talloc_free(res);
+ return EOK;
+ } else if (ret != EOK) {
+ talloc_free(res);
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_search_object_attr failed.\n");
+ return ret;
+ }
+
+ for (c = 0; c < res->count; c++) {
+ DEBUG(SSSDBG_TRACE_ALL, "Removing mapped data from [%s].\n",
+ ldb_dn_get_linearized(res->msgs[c]->dn));
+ /* The timestamp cache is skipped on purpose here. */
+ ret = sysdb_set_cache_entry_attr(domain->sysdb->ldb, res->msgs[c]->dn,
+ mapped_attr, SYSDB_MOD_DEL);
+ if (ret != EOK) {
+ all_ok = false;
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Failed to remove mapped data from [%s], skipping.\n",
+ ldb_dn_get_linearized(res->msgs[c]->dn));
+ }
+ }
+ talloc_free(res);
+
+ return (all_ok ? EOK : EIO);
+}
+
errno_t sysdb_remove_cert(struct sss_domain_info *domain,
const char *cert)
{
diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c
index e9455b538daa2d65d944dbb68022a2773623d7b7..898ddb18689d55fcc3fdf021b38df0e574003eb2 100644
--- a/src/providers/ldap/ldap_id.c
+++ b/src/providers/ldap/ldap_id.c
@@ -442,7 +442,7 @@ static void users_get_search(struct tevent_req *req)
state->attrs, state->filter,
dp_opt_get_int(state->ctx->opts->basic,
SDAP_SEARCH_TIMEOUT),
- lookup_type);
+ lookup_type, NULL);
if (!subreq) {
tevent_req_error(req, ENOMEM);
return;
@@ -507,7 +507,7 @@ static void users_get_done(struct tevent_req *subreq)
ret = sdap_fallback_local_user(state, state->shortname, uid, &usr_attrs);
if (ret == EOK) {
ret = sdap_save_user(state, state->ctx->opts, state->domain,
- usr_attrs[0], NULL, 0);
+ usr_attrs[0], NULL, NULL, 0);
}
}
}
diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h
index 2ebde6b83646408e446c91cb324809cb767b2617..6e5800b42ba4a045fa7985b09a80b6b86b8c6055 100644
--- a/src/providers/ldap/sdap_async.h
+++ b/src/providers/ldap/sdap_async.h
@@ -90,7 +90,8 @@ struct tevent_req *sdap_get_users_send(TALLOC_CTX *memctx,
const char **attrs,
const char *filter,
int timeout,
- enum sdap_entry_lookup_type lookup_type);
+ enum sdap_entry_lookup_type lookup_type,
+ struct sysdb_attrs *mapped_attrs);
int sdap_get_users_recv(struct tevent_req *req,
TALLOC_CTX *mem_ctx, char **timestamp);
diff --git a/src/providers/ldap/sdap_async_enum.c b/src/providers/ldap/sdap_async_enum.c
index 387e53155b567ce106cc68009c7cb99e27d24a17..3f65059e18d5c8b548da0babec867d27c3a64198 100644
--- a/src/providers/ldap/sdap_async_enum.c
+++ b/src/providers/ldap/sdap_async_enum.c
@@ -635,7 +635,7 @@ static struct tevent_req *enum_users_send(TALLOC_CTX *memctx,
state->attrs, state->filter,
dp_opt_get_int(state->ctx->opts->basic,
SDAP_ENUM_SEARCH_TIMEOUT),
- SDAP_LOOKUP_ENUMERATE);
+ SDAP_LOOKUP_ENUMERATE, NULL);
if (!subreq) {
ret = ENOMEM;
goto fail;
diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c
index 8c7a65bf36abf341e077cf9eac18a234d3a07c07..79af7a3eda3fe8533933535c98c2b4b4698dfda2 100644
--- a/src/providers/ldap/sdap_async_initgroups.c
+++ b/src/providers/ldap/sdap_async_initgroups.c
@@ -2991,7 +2991,7 @@ static void sdap_get_initgr_user(struct tevent_req *subreq)
DEBUG(SSSDBG_TRACE_ALL, "Storing the user\n");
ret = sdap_save_user(state, state->opts, state->dom, state->orig_user,
- NULL, 0);
+ NULL, NULL, 0);
if (ret) {
goto fail;
}
diff --git a/src/providers/ldap/sdap_async_private.h b/src/providers/ldap/sdap_async_private.h
index 266bc03115e2bdd6a283f5f7da565fd00d3a77be..72507442a9ffd5c0e24ccbd95d75d3ebf9bf0940 100644
--- a/src/providers/ldap/sdap_async_private.h
+++ b/src/providers/ldap/sdap_async_private.h
@@ -94,6 +94,7 @@ int sdap_save_users(TALLOC_CTX *memctx,
struct sdap_options *opts,
struct sysdb_attrs **users,
int num_users,
+ struct sysdb_attrs *mapped_attrs,
char **_usn_value);
int sdap_initgr_common_store(struct sysdb_ctx *sysdb,
diff --git a/src/providers/ldap/sdap_async_users.c b/src/providers/ldap/sdap_async_users.c
index 87d91d8247c37a4c6a1d83b7189399056528fc90..3d957ab584865f74499bc732395388a78965fe5f 100644
--- a/src/providers/ldap/sdap_async_users.c
+++ b/src/providers/ldap/sdap_async_users.c
@@ -117,6 +117,7 @@ int sdap_save_user(TALLOC_CTX *memctx,
struct sdap_options *opts,
struct sss_domain_info *dom,
struct sysdb_attrs *attrs,
+ struct sysdb_attrs *mapped_attrs,
char **_usn_value,
time_t now)
{
@@ -511,6 +512,11 @@ int sdap_save_user(TALLOC_CTX *memctx,
user_attrs, missing, cache_timeout, now);
if (ret) goto done;
+ if (mapped_attrs != NULL) {
+ ret = sysdb_set_user_attr(dom, user_name, mapped_attrs, SYSDB_MOD_ADD);
+ if (ret) return ret;
+ }
+
if (_usn_value) {
*_usn_value = talloc_steal(memctx, usn_value);
}
@@ -537,6 +543,7 @@ int sdap_save_users(TALLOC_CTX *memctx,
struct sdap_options *opts,
struct sysdb_attrs **users,
int num_users,
+ struct sysdb_attrs *mapped_attrs,
char **_usn_value)
{
TALLOC_CTX *tmpctx;
@@ -565,11 +572,20 @@ int sdap_save_users(TALLOC_CTX *memctx,
}
in_transaction = true;
+ if (mapped_attrs != NULL) {
+ ret = sysdb_remove_mapped_data(dom, mapped_attrs);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_remove_mapped_data failed, "
+ "some cached entries might contain invalid mapping data.\n");
+ }
+ }
+
now = time(NULL);
for (i = 0; i < num_users; i++) {
usn_value = NULL;
- ret = sdap_save_user(tmpctx, opts, dom, users[i], &usn_value, now);
+ ret = sdap_save_user(tmpctx, opts, dom, users[i], mapped_attrs,
+ &usn_value, now);
/* Do not fail completely on errors.
* Just report the failure to save and go on */
@@ -868,6 +884,7 @@ struct sdap_get_users_state {
char *higher_usn;
struct sysdb_attrs **users;
+ struct sysdb_attrs *mapped_attrs;
size_t count;
};
@@ -883,7 +900,8 @@ struct tevent_req *sdap_get_users_send(TALLOC_CTX *memctx,
const char **attrs,
const char *filter,
int timeout,
- enum sdap_entry_lookup_type lookup_type)
+ enum sdap_entry_lookup_type lookup_type,
+ struct sysdb_attrs *mapped_attrs)
{
errno_t ret;
struct tevent_req *req;
@@ -900,6 +918,23 @@ struct tevent_req *sdap_get_users_send(TALLOC_CTX *memctx,
state->filter = filter;
PROBE(SDAP_SEARCH_USER_SEND, state->filter);
+ if (mapped_attrs == NULL) {
+ state->mapped_attrs = NULL;
+ } else {
+ state->mapped_attrs = sysdb_new_attrs(state);
+ if (state->mapped_attrs == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_new_attrs failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = sysdb_attrs_copy(mapped_attrs, state->mapped_attrs);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_copy failed.\n");
+ goto done;
+ }
+ }
+
subreq = sdap_search_user_send(state, ev, dom, opts, search_bases,
sh, attrs, filter, timeout, lookup_type);
if (subreq == NULL) {
@@ -938,9 +973,11 @@ static void sdap_get_users_done(struct tevent_req *subreq)
}
PROBE(SDAP_SEARCH_USER_SAVE_BEGIN, state->filter);
+
ret = sdap_save_users(state, state->sysdb,
state->dom, state->opts,
state->users, state->count,
+ state->mapped_attrs,
&state->higher_usn);
PROBE(SDAP_SEARCH_USER_SAVE_END, state->filter);
if (ret) {
diff --git a/src/providers/ldap/sdap_users.h b/src/providers/ldap/sdap_users.h
index 78dafb31a2a07e7289055daec77c5dc5da1bdeef..a6d088a6d7114db75b0f0ea22ef85c57da6fab0f 100644
--- a/src/providers/ldap/sdap_users.h
+++ b/src/providers/ldap/sdap_users.h
@@ -34,6 +34,7 @@ int sdap_save_user(TALLOC_CTX *memctx,
struct sdap_options *opts,
struct sss_domain_info *dom,
struct sysdb_attrs *attrs,
+ struct sysdb_attrs *mapped_attrs,
char **_usn_value,
time_t now);
--
2.12.2

View File

@ -1,178 +0,0 @@
From 81c564a0692aa4b719af2219f52894e6cd4bdf9f Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Mon, 30 Nov 2015 12:14:55 +0100
Subject: [PATCH 10/97] LDAP: always store the certificate from the request
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Store the certificate used to lookup a user as mapped attribute in the
cached user object.
Related to https://pagure.io/SSSD/sssd/issue/3050
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
---
src/db/sysdb.h | 1 +
src/db/sysdb_ops.c | 4 ++--
src/providers/ldap/ldap_id.c | 19 ++++++++++++++++++-
src/tests/cmocka/test_nss_srv.c | 2 +-
src/tests/cmocka/test_pam_srv.c | 6 +++---
src/tests/sysdb-tests.c | 4 ++--
6 files changed, 27 insertions(+), 9 deletions(-)
diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index 098f47f91187aac75c58c02f0af738c344765762..3db22b3689bf6ffd9a48e29c229916e3fac9ca1b 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -139,6 +139,7 @@
#define SYSDB_AUTH_TYPE "authType"
#define SYSDB_USER_CERT "userCertificate"
+#define SYSDB_USER_MAPPED_CERT "userMappedCertificate"
#define SYSDB_USER_EMAIL "mail"
#define SYSDB_SUBDOMAIN_REALM "realmName"
diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c
index 6c2254df2b75d3d3419528523103ad9cddb40c9d..8ae25764478e522255b177f9e8de1d3ca1ad43fd 100644
--- a/src/db/sysdb_ops.c
+++ b/src/db/sysdb_ops.c
@@ -4660,7 +4660,7 @@ errno_t sysdb_search_object_by_cert(TALLOC_CTX *mem_ctx,
int ret;
char *user_filter;
- ret = sss_cert_derb64_to_ldap_filter(mem_ctx, cert, SYSDB_USER_CERT,
+ ret = sss_cert_derb64_to_ldap_filter(mem_ctx, cert, SYSDB_USER_MAPPED_CERT,
&user_filter);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "sss_cert_derb64_to_ldap_filter failed.\n");
@@ -4749,7 +4749,7 @@ errno_t sysdb_remove_mapped_data(struct sss_domain_info *domain,
errno_t sysdb_remove_cert(struct sss_domain_info *domain,
const char *cert)
{
- struct ldb_message_element el = { 0, SYSDB_USER_CERT, 0, NULL };
+ struct ldb_message_element el = { 0, SYSDB_USER_MAPPED_CERT, 0, NULL };
struct sysdb_attrs del_attrs = { 1, &el };
const char *attrs[] = {SYSDB_NAME, NULL};
struct ldb_result *res = NULL;
diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c
index 898ddb18689d55fcc3fdf021b38df0e574003eb2..a8b4bc2cfc6e9d4e0d74b0e3e036afbcbf7eb26e 100644
--- a/src/providers/ldap/ldap_id.c
+++ b/src/providers/ldap/ldap_id.c
@@ -60,6 +60,7 @@ struct users_get_state {
int dp_error;
int sdap_ret;
bool noexist_delete;
+ struct sysdb_attrs *extra_attrs;
};
static int users_get_retry(struct tevent_req *req);
@@ -99,6 +100,7 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx,
state->conn = conn;
state->dp_error = DP_ERR_FATAL;
state->noexist_delete = noexist_delete;
+ state->extra_attrs = NULL;
state->op = sdap_id_op_create(state, state->conn->conn_cache);
if (!state->op) {
@@ -251,6 +253,21 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx,
"sss_cert_derb64_to_ldap_filter failed.\n");
goto done;
}
+
+ state->extra_attrs = sysdb_new_attrs(state);
+ if (state->extra_attrs == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_new_attrs failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = sysdb_attrs_add_base64_blob(state->extra_attrs,
+ SYSDB_USER_MAPPED_CERT, filter_value);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_base64_blob failed.\n");
+ goto done;
+ }
+
break;
default:
ret = EINVAL;
@@ -442,7 +459,7 @@ static void users_get_search(struct tevent_req *req)
state->attrs, state->filter,
dp_opt_get_int(state->ctx->opts->basic,
SDAP_SEARCH_TIMEOUT),
- lookup_type, NULL);
+ lookup_type, state->extra_attrs);
if (!subreq) {
tevent_req_error(req, ENOMEM);
return;
diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c
index 72bbaf9bf35ebb3fc4208afaa3c7af95922afcb0..76b9c6fb05673130de0957e93291919c263a28f3 100644
--- a/src/tests/cmocka/test_nss_srv.c
+++ b/src/tests/cmocka/test_nss_srv.c
@@ -3508,7 +3508,7 @@ static void test_nss_getnamebycert(void **state)
der = sss_base64_decode(nss_test_ctx, TEST_TOKEN_CERT, &der_size);
assert_non_null(der);
- ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_CERT, der, der_size);
+ ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_MAPPED_CERT, der, der_size);
talloc_free(der);
assert_int_equal(ret, EOK);
diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c
index ae2e555f7024027d1c0063031f8882bf81a31905..847419658bb983e6548722d6fa6fb22c63ee86b8 100644
--- a/src/tests/cmocka/test_pam_srv.c
+++ b/src/tests/cmocka/test_pam_srv.c
@@ -1598,7 +1598,7 @@ static int test_lookup_by_cert_cb(void *pvt)
der = sss_base64_decode(pam_test_ctx, pvt, &der_size);
assert_non_null(der);
- ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_CERT, der, der_size);
+ ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_MAPPED_CERT, der, der_size);
talloc_free(der);
assert_int_equal(ret, EOK);
@@ -1630,7 +1630,7 @@ static int test_lookup_by_cert_double_cb(void *pvt)
der = sss_base64_decode(pam_test_ctx, pvt, &der_size);
assert_non_null(der);
- ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_CERT, der, der_size);
+ ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_MAPPED_CERT, der, der_size);
talloc_free(der);
assert_int_equal(ret, EOK);
@@ -1658,7 +1658,7 @@ static int test_lookup_by_cert_wrong_user_cb(void *pvt)
der = sss_base64_decode(pam_test_ctx, pvt, &der_size);
assert_non_null(der);
- ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_CERT, der, der_size);
+ ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_MAPPED_CERT, der, der_size);
talloc_free(der);
assert_int_equal(ret, EOK);
diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c
index c343c734a27a335303974b6866a5d9e88d4c307e..5bdd631fbfa1b4463fb169e5f07b65fb2c784096 100644
--- a/src/tests/sysdb-tests.c
+++ b/src/tests/sysdb-tests.c
@@ -5721,7 +5721,7 @@ START_TEST(test_sysdb_search_user_by_cert)
val.data = sss_base64_decode(test_ctx, TEST_USER_CERT_DERB64, &val.length);
fail_unless(val.data != NULL, "sss_base64_decode failed.");
- ret = sysdb_attrs_add_val(data->attrs, SYSDB_USER_CERT, &val);
+ ret = sysdb_attrs_add_val(data->attrs, SYSDB_USER_MAPPED_CERT, &val);
fail_unless(ret == EOK, "sysdb_attrs_add_val failed with [%d][%s].",
ret, strerror(ret));
@@ -5750,7 +5750,7 @@ START_TEST(test_sysdb_search_user_by_cert)
data2 = test_data_new_user(test_ctx, 2345671);
fail_if(data2 == NULL);
- ret = sysdb_attrs_add_val(data2->attrs, SYSDB_USER_CERT, &val);
+ ret = sysdb_attrs_add_val(data2->attrs, SYSDB_USER_MAPPED_CERT, &val);
fail_unless(ret == EOK, "sysdb_attrs_add_val failed with [%d][%s].",
ret, strerror(ret));
--
2.12.2

View File

@ -1,235 +0,0 @@
From b341ee51cffd98b642b9c68a417f8a7504e303a1 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Thu, 2 Feb 2017 16:34:32 +0100
Subject: [PATCH 11/97] sss_cert_derb64_to_ldap_filter: add sss_certmap support
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Use certificate mapping library if available to lookup a user by
certificate in LDAP.
Related to https://pagure.io/SSSD/sssd/issue/3050
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
---
Makefile.am | 1 +
src/db/sysdb_ops.c | 2 +-
src/db/sysdb_views.c | 4 +-
src/providers/ipa/ipa_views.c | 2 +-
src/providers/ldap/ldap_id.c | 2 +-
src/tests/cmocka/test_cert_utils.c | 4 +-
src/util/cert.h | 3 ++
src/util/cert/cert_common.c | 76 ++++++++++++++++++++++++++++++++------
8 files changed, 76 insertions(+), 18 deletions(-)
diff --git a/Makefile.am b/Makefile.am
index 7947b7a5fbe3ca1034baac1c13c53300994b1bf8..f262cc24832358910dbb92ccd46f93c9eda8a295 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -952,6 +952,7 @@ libsss_cert_la_LIBADD = \
$(TALLOC_LIBS) \
libsss_crypt.la \
libsss_debug.la \
+ libsss_certmap.la \
$(NULL)
libsss_cert_la_LDFLAGS = \
-avoid-version \
diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c
index 8ae25764478e522255b177f9e8de1d3ca1ad43fd..919f22370ff87eff2bf0bb569ca90f1ee699a61e 100644
--- a/src/db/sysdb_ops.c
+++ b/src/db/sysdb_ops.c
@@ -4661,7 +4661,7 @@ errno_t sysdb_search_object_by_cert(TALLOC_CTX *mem_ctx,
char *user_filter;
ret = sss_cert_derb64_to_ldap_filter(mem_ctx, cert, SYSDB_USER_MAPPED_CERT,
- &user_filter);
+ NULL, NULL, &user_filter);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "sss_cert_derb64_to_ldap_filter failed.\n");
return ret;
diff --git a/src/db/sysdb_views.c b/src/db/sysdb_views.c
index 9dc48f5b6c414bbc7c64bcd1fe73553f388588bd..1c416dd14049237e9f35d52f154035e3ff861469 100644
--- a/src/db/sysdb_views.c
+++ b/src/db/sysdb_views.c
@@ -862,8 +862,8 @@ errno_t sysdb_search_override_by_cert(TALLOC_CTX *mem_ctx,
goto done;
}
- ret = sss_cert_derb64_to_ldap_filter(tmp_ctx, cert, SYSDB_USER_CERT,
- &cert_filter);
+ ret = sss_cert_derb64_to_ldap_filter(tmp_ctx, cert, SYSDB_USER_CERT, NULL,
+ NULL, &cert_filter);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "sss_cert_derb64_to_ldap_filter failed.\n");
diff --git a/src/providers/ipa/ipa_views.c b/src/providers/ipa/ipa_views.c
index 29f589ec1fd05f59175dcc4592e6395941e6e034..5b6fcbc9b7c6f2ea7dbeecb01a5a3fd11b8a6854 100644
--- a/src/providers/ipa/ipa_views.c
+++ b/src/providers/ipa/ipa_views.c
@@ -156,7 +156,7 @@ static errno_t dp_id_data_to_override_filter(TALLOC_CTX *mem_ctx,
if ((ar->entry_type & BE_REQ_TYPE_MASK) == BE_REQ_BY_CERT) {
ret = sss_cert_derb64_to_ldap_filter(mem_ctx, ar->filter_value,
ipa_opts->override_map[IPA_AT_OVERRIDE_USER_CERT].name,
- &cert_filter);
+ NULL, NULL, &cert_filter);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"sss_cert_derb64_to_ldap_filter failed.\n");
diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c
index a8b4bc2cfc6e9d4e0d74b0e3e036afbcbf7eb26e..8e60769d09383ac8ebe33e5f64fd4fd9788e82cd 100644
--- a/src/providers/ldap/ldap_id.c
+++ b/src/providers/ldap/ldap_id.c
@@ -247,7 +247,7 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx,
}
ret = sss_cert_derb64_to_ldap_filter(state, filter_value, attr_name,
- &user_filter);
+ NULL, NULL, &user_filter);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"sss_cert_derb64_to_ldap_filter failed.\n");
diff --git a/src/tests/cmocka/test_cert_utils.c b/src/tests/cmocka/test_cert_utils.c
index 35e8cb7513968079861048a7e8b0631229f202c0..5830131754e4cf318273151b586ef36d6a349829 100644
--- a/src/tests/cmocka/test_cert_utils.c
+++ b/src/tests/cmocka/test_cert_utils.c
@@ -297,11 +297,11 @@ void test_sss_cert_derb64_to_ldap_filter(void **state)
struct test_state *ts = talloc_get_type_abort(*state, struct test_state);
assert_non_null(ts);
- ret = sss_cert_derb64_to_ldap_filter(ts, NULL, NULL, NULL);
+ ret = sss_cert_derb64_to_ldap_filter(ts, NULL, NULL, NULL, NULL, NULL);
assert_int_equal(ret, EINVAL);
ret = sss_cert_derb64_to_ldap_filter(ts, "AAECAwQFBgcICQ==", "attrName",
- &filter);
+ NULL, NULL, &filter);
assert_int_equal(ret, EOK);
assert_string_equal(filter,
"(attrName=\\00\\01\\02\\03\\04\\05\\06\\07\\08\\09)");
diff --git a/src/util/cert.h b/src/util/cert.h
index bb64d0d7a0a48207df60f6e6e554da5e16a16b03..4598aa8df0cd860fed71d9cd2e4beec7f1910578 100644
--- a/src/util/cert.h
+++ b/src/util/cert.h
@@ -21,6 +21,7 @@
#include <talloc.h>
#include "util/util.h"
+#include "lib/certmap/sss_certmap.h"
#ifndef __CERT_H__
#define __CERT_H__
@@ -39,6 +40,8 @@ errno_t sss_cert_pem_to_derb64(TALLOC_CTX *mem_ctx, const char *pem,
errno_t sss_cert_derb64_to_ldap_filter(TALLOC_CTX *mem_ctx, const char *derb64,
const char *attr_name,
+ struct sss_certmap_ctx *certmap_ctx,
+ struct sss_domain_info *dom,
char **ldap_filter);
errno_t bin_to_ldap_filter_value(TALLOC_CTX *mem_ctx,
diff --git a/src/util/cert/cert_common.c b/src/util/cert/cert_common.c
index a29696ed3cd9f2168f47323fac97d44e9b49f921..766877089429ff1c01000a3986316c74583e3fa4 100644
--- a/src/util/cert/cert_common.c
+++ b/src/util/cert/cert_common.c
@@ -72,12 +72,17 @@ errno_t sss_cert_pem_to_derb64(TALLOC_CTX *mem_ctx, const char *pem,
errno_t sss_cert_derb64_to_ldap_filter(TALLOC_CTX *mem_ctx, const char *derb64,
const char *attr_name,
+ struct sss_certmap_ctx *certmap_ctx,
+ struct sss_domain_info *dom,
char **ldap_filter)
{
int ret;
unsigned char *der;
size_t der_size;
char *val;
+ char *filter = NULL;
+ char **domains = NULL;
+ size_t c;
if (derb64 == NULL || attr_name == NULL) {
return EINVAL;
@@ -89,18 +94,67 @@ errno_t sss_cert_derb64_to_ldap_filter(TALLOC_CTX *mem_ctx, const char *derb64,
return EINVAL;
}
- ret = bin_to_ldap_filter_value(mem_ctx, der, der_size, &val);
- talloc_free(der);
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "bin_to_ldap_filter_value failed.\n");
- return ret;
- }
+ if (certmap_ctx == NULL) {
+ ret = bin_to_ldap_filter_value(mem_ctx, der, der_size, &val);
+ talloc_free(der);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "bin_to_ldap_filter_value failed.\n");
+ return ret;
+ }
- *ldap_filter = talloc_asprintf(mem_ctx, "(%s=%s)", attr_name, val);
- talloc_free(val);
- if (*ldap_filter == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
- return ENOMEM;
+ *ldap_filter = talloc_asprintf(mem_ctx, "(%s=%s)", attr_name, val);
+ talloc_free(val);
+ if (*ldap_filter == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
+ return ENOMEM;
+ }
+ } else {
+ ret = sss_certmap_get_search_filter(certmap_ctx, der, der_size,
+ &filter, &domains);
+ talloc_free(der);
+ if (ret != 0) {
+ if (ret == ENOENT) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Certificate does not match matching-rules.\n");
+ } else {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "sss_certmap_get_search_filter failed.\n");
+ }
+ } else {
+ if (domains == NULL) {
+ if (IS_SUBDOMAIN(dom)) {
+ DEBUG(SSSDBG_TRACE_FUNC,
+ "Rule applies only to local domain.\n");
+ ret = ENOENT;
+ }
+ } else {
+ for (c = 0; domains[c] != NULL; c++) {
+ if (strcasecmp(dom->name, domains[c]) == 0) {
+ DEBUG(SSSDBG_TRACE_FUNC,
+ "Rule applies to current domain [%s].\n",
+ dom->name);
+ ret = EOK;
+ break;
+ }
+ }
+ if (domains[c] == NULL) {
+ DEBUG(SSSDBG_TRACE_FUNC,
+ "Rule does not apply to current domain [%s].\n",
+ dom->name);
+ ret = ENOENT;
+ }
+ }
+ }
+
+ if (ret == EOK) {
+ *ldap_filter = talloc_strdup(mem_ctx, filter);
+ if (*ldap_filter == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
+ ret = ENOMEM;
+ }
+ }
+ sss_certmap_free_filter_and_domains(filter, domains);
+ return ret;
}
return EOK;
--
2.12.2

View File

@ -1,846 +0,0 @@
From 49f8ec8e0a3723a748bdb043d6dc1fb2a3977a8a Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Mon, 6 Feb 2017 10:27:22 +0100
Subject: [PATCH 12/97] sysdb: add certmap related calls
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Add sysdb calls to write and read data for the certificate mapping
library to the cache.
Related to https://pagure.io/SSSD/sssd/issue/3050
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
---
Makefile.am | 17 ++
src/db/sysdb.h | 27 +++
src/db/sysdb_certmap.c | 425 ++++++++++++++++++++++++++++++++++
src/tests/cmocka/test_sysdb_certmap.c | 260 +++++++++++++++++++++
4 files changed, 729 insertions(+)
create mode 100644 src/db/sysdb_certmap.c
create mode 100644 src/tests/cmocka/test_sysdb_certmap.c
diff --git a/Makefile.am b/Makefile.am
index f262cc24832358910dbb92ccd46f93c9eda8a295..bd0ca0d303e1742ad26c7648cd24e2c0135af34e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -254,6 +254,7 @@ if HAVE_CMOCKA
test_sysdb_ts_cache \
test_sysdb_views \
test_sysdb_subdomains \
+ test_sysdb_certmap \
test_sysdb_sudo \
test_sysdb_utils \
test_wbc_calls \
@@ -974,6 +975,7 @@ libsss_util_la_SOURCES = \
src/db/sysdb_ranges.c \
src/db/sysdb_idmap.c \
src/db/sysdb_gpo.c \
+ src/db/sysdb_certmap.c \
src/monitor/monitor_sbus.c \
src/providers/dp_auth_util.c \
src/providers/dp_pam_data_util.c \
@@ -2773,6 +2775,21 @@ test_sysdb_subdomains_LDADD = \
libsss_test_common.la \
$(NULL)
+test_sysdb_certmap_SOURCES = \
+ src/tests/cmocka/test_sysdb_certmap.c \
+ $(NULL)
+test_sysdb_certmap_CFLAGS = \
+ $(AM_CFLAGS) \
+ $(NULL)
+test_sysdb_certmap_LDADD = \
+ $(CMOCKA_LIBS) \
+ $(LDB_LIBS) \
+ $(POPT_LIBS) \
+ $(TALLOC_LIBS) \
+ $(SSSD_INTERNAL_LTLIBS) \
+ libsss_test_common.la \
+ $(NULL)
+
test_sysdb_sudo_SOURCES = \
src/tests/cmocka/test_sysdb_sudo.c \
$(NULL)
diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index 3db22b3689bf6ffd9a48e29c229916e3fac9ca1b..0cbb2c5c02355e9e9a4e73b075f92d16e4855045 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -39,6 +39,7 @@
#define SYSDB_NETGROUP_CONTAINER "cn=Netgroups"
#define SYSDB_RANGE_CONTAINER "cn=ranges"
#define SYSDB_VIEW_CONTAINER "cn=views"
+#define SYSDB_CERTMAP_CONTAINER "cn=certmap"
#define SYSDB_TMPL_USER_BASE SYSDB_USERS_CONTAINER","SYSDB_DOM_BASE
#define SYSDB_TMPL_GROUP_BASE SYSDB_GROUPS_CONTAINER","SYSDB_DOM_BASE
#define SYSDB_TMPL_CUSTOM_BASE SYSDB_CUSTOM_CONTAINER","SYSDB_DOM_BASE
@@ -46,6 +47,7 @@
#define SYSDB_TMPL_RANGE_BASE SYSDB_RANGE_CONTAINER","SYSDB_BASE
#define SYSDB_TMPL_VIEW_BASE SYSDB_VIEW_CONTAINER","SYSDB_BASE
#define SYSDB_TMPL_VIEW_SEARCH_BASE "cn=%s,"SYSDB_TMPL_VIEW_BASE
+#define SYSDB_TMPL_CERTMAP_BASE SYSDB_CERTMAP_CONTAINER","SYSDB_BASE
#define SYSDB_SUBDOMAIN_CLASS "subdomain"
#define SYSDB_USER_CLASS "user"
@@ -58,6 +60,7 @@
#define SYSDB_ID_RANGE_CLASS "idRange"
#define SYSDB_DOMAIN_ID_RANGE_CLASS "domainIDRange"
#define SYSDB_TRUSTED_AD_DOMAIN_RANGE_CLASS "TrustedADDomainRange"
+#define SYSDB_CERTMAP_CLASS "certificateMappingRule"
#define SYSDB_DN "dn"
#define SYSDB_NAME "name"
@@ -158,6 +161,12 @@
#define SYSDB_DOMAIN_ID "domainID"
#define SYSDB_ID_RANGE_TYPE "idRangeType"
+#define SYSDB_CERTMAP_PRIORITY "priority"
+#define SYSDB_CERTMAP_MATCHING_RULE "matchingRule"
+#define SYSDB_CERTMAP_MAPPING_RULE "mappingRule"
+#define SYSDB_CERTMAP_DOMAINS "domains"
+#define SYSDB_CERTMAP_USER_NAME_HINT "userNameHint"
+
#define ORIGINALAD_PREFIX "originalAD"
#define OVERRIDE_PREFIX "override"
#define SYSDB_DEFAULT_OVERRIDE_NAME "defaultOverrideName"
@@ -264,6 +273,7 @@
#define SYSDB_TMPL_CUSTOM SYSDB_NAME"=%s,cn=%s,"SYSDB_TMPL_CUSTOM_BASE
#define SYSDB_TMPL_RANGE SYSDB_NAME"=%s,"SYSDB_TMPL_RANGE_BASE
#define SYSDB_TMPL_OVERRIDE SYSDB_OVERRIDE_ANCHOR_UUID"=%s,"SYSDB_TMPL_VIEW_SEARCH_BASE
+#define SYSDB_TMPL_CERTMAP SYSDB_NAME"=%s,"SYSDB_TMPL_CERTMAP_BASE
#define SYSDB_MOD_ADD LDB_FLAG_MOD_ADD
#define SYSDB_MOD_DEL LDB_FLAG_MOD_DELETE
@@ -320,6 +330,15 @@ struct range_info {
char *range_type;
};
+struct certmap_info {
+ char *name;
+ uint32_t priority;
+ char *match_rule;
+ char *map_rule;
+ const char **domains;
+};
+
+
/* These attributes are stored in the timestamp cache */
extern const char *sysdb_ts_cache_attrs[];
@@ -619,6 +638,14 @@ uint64_t sss_view_ldb_msg_find_attr_as_uint64(struct sss_domain_info *dom,
const char *attr_name,
uint64_t default_value);
+errno_t sysdb_update_certmap(struct sysdb_ctx *sysdb,
+ struct certmap_info **certmaps,
+ bool user_name_hint);
+
+errno_t sysdb_get_certmap(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb,
+ struct certmap_info ***certmaps,
+ bool *user_name_hint);
+
/* Sysdb initialization.
* call this function *only* once to initialize the database and get
* the sysdb ctx */
diff --git a/src/db/sysdb_certmap.c b/src/db/sysdb_certmap.c
new file mode 100644
index 0000000000000000000000000000000000000000..4917796b11c3967b4d147ebee7c7e83f09b872ce
--- /dev/null
+++ b/src/db/sysdb_certmap.c
@@ -0,0 +1,425 @@
+/*
+ SSSD
+
+ System Database - certificate mapping rules related calls
+
+ Copyright (C) 2017 Sumit Bose <sbose@redhat.com>
+
+ 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 "util/util.h"
+#include "db/sysdb_private.h"
+
+static errno_t sysdb_create_certmap_container(struct sysdb_ctx *sysdb,
+ bool user_name_hint)
+{
+ struct ldb_message *msg = NULL;
+ errno_t ret;
+
+ msg = ldb_msg_new(sysdb);
+ if (msg == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ msg->dn = ldb_dn_new(msg, sysdb->ldb, SYSDB_TMPL_CERTMAP_BASE);
+ if (msg->dn == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ ret = ldb_msg_add_string(msg, "cn", "certmap");
+ if (ret != LDB_SUCCESS) {
+ ret = sysdb_error_to_errno(ret);
+ goto done;
+ }
+
+ ret = ldb_msg_add_string(msg, SYSDB_CERTMAP_USER_NAME_HINT,
+ user_name_hint ? "TRUE" : "FALSE");
+ if (ret != LDB_SUCCESS) {
+ ret = sysdb_error_to_errno(ret);
+ goto done;
+ }
+
+ /* do a synchronous add */
+ ret = ldb_add(sysdb->ldb, msg);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Failed to add certmap container (%d, [%s])!\n",
+ ret, ldb_errstring(sysdb->ldb));
+ ret = EIO;
+ goto done;
+ }
+
+ ret = EOK;
+
+done:
+ talloc_free(msg);
+
+ return ret;
+}
+
+static errno_t sysdb_certmap_add(struct sysdb_ctx *sysdb,
+ struct certmap_info *certmap)
+{
+ struct ldb_message *msg;
+ struct ldb_message_element *el;
+ int ret;
+ TALLOC_CTX *tmp_ctx;
+ size_t c;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed");
+ return ENOMEM;
+ }
+
+ msg = ldb_msg_new(tmp_ctx);
+ if (msg == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_new failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ msg->dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb,
+ SYSDB_TMPL_CERTMAP, certmap->name);
+ if (msg->dn == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_new_fmt failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = sysdb_add_string(msg, SYSDB_OBJECTCLASS, SYSDB_CERTMAP_CLASS);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_add_string failed.\n");
+ goto done;
+ }
+
+ ret = sysdb_add_string(msg, SYSDB_NAME, certmap->name);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_add_string failed.\n");
+ goto done;
+ }
+
+ if (certmap->map_rule != NULL) {
+ ret = sysdb_add_string(msg, SYSDB_CERTMAP_MAPPING_RULE,
+ certmap->map_rule);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_add_string failed.\n");
+ goto done;
+ }
+ }
+
+ if (certmap->match_rule != NULL) {
+ ret = sysdb_add_string(msg, SYSDB_CERTMAP_MATCHING_RULE,
+ certmap->match_rule);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_add_string failed.\n");
+ goto done;
+ }
+ }
+
+ if (certmap->domains != NULL) {
+ for (c = 0; certmap->domains[c] != NULL; c++);
+ el = talloc_zero(tmp_ctx, struct ldb_message_element);
+ if (el == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ el->name = talloc_strdup(el, SYSDB_CERTMAP_DOMAINS);
+ if(el->name == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+ el->num_values = c;
+ el->values = talloc_zero_array(el, struct ldb_val, c + 1);
+ if (el->values == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_array failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ for (c = 0; certmap->domains[c] != NULL; c++) {
+ el->values[c].data = (uint8_t *) talloc_strdup(el->values,
+ certmap->domains[c]);
+ if (el->values[c].data == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+ el->values[c].length = strlen(certmap->domains[c]);
+ }
+
+ ret = ldb_msg_add(msg, el, LDB_FLAG_MOD_ADD);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add failed.\n");
+ ret = sysdb_error_to_errno(ret);
+ goto done;
+ }
+ }
+
+ ret = sysdb_add_ulong(msg, SYSDB_CERTMAP_PRIORITY,
+ (unsigned long)certmap->priority);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_add_ulong failed.\n");
+ goto done;
+ }
+
+ ret = ldb_add(sysdb->ldb, msg);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(SSSDBG_OP_FAILURE, "ldb_add failed.\n");
+ ret = sysdb_error_to_errno(ret);
+ goto done;
+ }
+
+ ret = EOK;
+
+done:
+ if (ret) {
+ DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, sss_strerror(ret));
+ }
+ talloc_zfree(tmp_ctx);
+ return ret;
+}
+
+errno_t sysdb_update_certmap(struct sysdb_ctx *sysdb,
+ struct certmap_info **certmaps,
+ bool user_name_hint)
+{
+ size_t c;
+ struct ldb_dn *container_dn = NULL;
+ bool in_transaction = false;
+ int ret;
+ int sret;
+
+ if (certmaps == NULL) {
+ return EINVAL;
+ }
+
+ container_dn = ldb_dn_new(sysdb, sysdb->ldb, SYSDB_TMPL_CERTMAP_BASE);
+ if (container_dn == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_new failed.\n");
+ return ENOMEM;
+ }
+
+ ret = sysdb_transaction_start(sysdb);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_transaction_start failed.\n");
+ goto done;
+ }
+ in_transaction = true;
+
+ ret = sysdb_delete_recursive(sysdb, container_dn, true);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_delete_recursive failed.\n");
+ goto done;
+ }
+ ret = sysdb_create_certmap_container(sysdb, user_name_hint);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_create_certmap_container failed.\n");
+ goto done;
+ }
+
+ for (c = 0; certmaps[c] != NULL; c++) {
+ ret = sysdb_certmap_add(sysdb, certmaps[c]);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_certmap_add failed.\n");
+ goto done;
+ }
+ }
+
+ ret = sysdb_transaction_commit(sysdb);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_transaction_commit failed.\n");
+ goto done;
+ }
+ in_transaction = false;
+
+done:
+ if (in_transaction) {
+ sret = sysdb_transaction_cancel(sysdb);
+ if (sret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Could not cancel transaction.\n");
+ }
+ }
+
+ talloc_free(container_dn);
+
+ return ret;
+}
+
+errno_t sysdb_get_certmap(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb,
+ struct certmap_info ***certmaps, bool *user_name_hint)
+{
+ size_t c;
+ size_t d;
+ struct ldb_dn *container_dn = NULL;
+ int ret;
+ struct certmap_info **maps;
+ TALLOC_CTX *tmp_ctx = NULL;
+ struct ldb_result *res;
+ const char *tmp_str;
+ uint64_t tmp_uint;
+ struct ldb_message_element *tmp_el;
+ const char *attrs[] = {SYSDB_NAME,
+ SYSDB_CERTMAP_PRIORITY,
+ SYSDB_CERTMAP_MATCHING_RULE,
+ SYSDB_CERTMAP_MAPPING_RULE,
+ SYSDB_CERTMAP_DOMAINS,
+ NULL};
+ const char *config_attrs[] = {SYSDB_CERTMAP_USER_NAME_HINT,
+ NULL};
+ size_t num_values;
+ bool hint = false;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ container_dn = ldb_dn_new(tmp_ctx, sysdb->ldb, SYSDB_TMPL_CERTMAP_BASE);
+ if (container_dn == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_new failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_search(sysdb->ldb, tmp_ctx, &res, container_dn, LDB_SCOPE_BASE,
+ config_attrs, SYSDB_CERTMAP_USER_NAME_HINT"=*");
+ if (ret != LDB_SUCCESS || res->count != 1) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to read certmap config, skipping.\n");
+ } else {
+ hint = ldb_msg_find_attr_as_bool(res->msgs[0],
+ SYSDB_CERTMAP_USER_NAME_HINT, false);
+ }
+
+ ret = ldb_search(sysdb->ldb, tmp_ctx, &res,
+ container_dn, LDB_SCOPE_SUBTREE,
+ attrs, "objectclass=%s", SYSDB_CERTMAP_CLASS);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(SSSDBG_OP_FAILURE, "ldb_search failed.\n");
+ ret = EIO;
+ goto done;
+ }
+
+ if (res->count == 0) {
+ DEBUG(SSSDBG_TRACE_FUNC, "No certificate maps found.\n");
+ ret = ENOENT;
+ goto done;
+ }
+
+ maps = talloc_zero_array(tmp_ctx, struct certmap_info *, res->count + 1);
+ if (maps == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_array failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ for (c = 0; c < res->count; c++) {
+ maps[c] = talloc_zero(maps, struct certmap_info);
+ if (maps[c] == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ tmp_str = ldb_msg_find_attr_as_string(res->msgs[c], SYSDB_NAME, NULL);
+ if (tmp_str == NULL) {
+ DEBUG(SSSDBG_MINOR_FAILURE, "The object [%s] doesn't have a name.\n",
+ ldb_dn_get_linearized(res->msgs[c]->dn));
+ ret = EINVAL;
+ goto done;
+ }
+
+ maps[c]->name = talloc_strdup(maps, tmp_str);
+ if (maps[c]->name == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ tmp_str = ldb_msg_find_attr_as_string(res->msgs[c],
+ SYSDB_CERTMAP_MAPPING_RULE, NULL);
+ if (tmp_str != NULL) {
+ maps[c]->map_rule = talloc_strdup(maps, tmp_str);
+ if (maps[c]->map_rule == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+
+ tmp_str = ldb_msg_find_attr_as_string(res->msgs[c],
+ SYSDB_CERTMAP_MATCHING_RULE, NULL);
+ if (tmp_str != NULL) {
+ maps[c]->match_rule = talloc_strdup(maps, tmp_str);
+ if (maps[c]->match_rule == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+
+ tmp_uint = ldb_msg_find_attr_as_uint64(res->msgs[c],
+ SYSDB_CERTMAP_PRIORITY,
+ (uint64_t) -1);
+ if (tmp_uint != (uint64_t) -1) {
+ if (tmp_uint >= UINT32_MAX) {
+ DEBUG(SSSDBG_OP_FAILURE, "Priority value [%lu] too large.\n",
+ (unsigned long) tmp_uint);
+ ret = EINVAL;
+ goto done;
+ }
+
+ maps[c]->priority = (uint32_t) tmp_uint;
+ }
+
+ tmp_el = ldb_msg_find_element(res->msgs[c], SYSDB_CERTMAP_DOMAINS);
+ if (tmp_el != NULL) {
+ num_values = tmp_el->num_values;
+ } else {
+ num_values = 0;
+ }
+
+ maps[c]->domains = talloc_zero_array(maps[c], const char *,
+ num_values + 1);
+ if (maps[c]->domains == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_array failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ for (d = 0; d < num_values; d++) {
+ maps[c]->domains[d] = talloc_strndup(maps[c]->domains,
+ (char *) tmp_el->values[d].data,
+ tmp_el->values[d].length);
+ if (maps[c]->domains[d] == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+ }
+
+ *certmaps = talloc_steal(mem_ctx, maps);
+ *user_name_hint = hint;
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+
+ return ret;
+}
diff --git a/src/tests/cmocka/test_sysdb_certmap.c b/src/tests/cmocka/test_sysdb_certmap.c
new file mode 100644
index 0000000000000000000000000000000000000000..fb07165561779226935f436c308c85abfc305635
--- /dev/null
+++ b/src/tests/cmocka/test_sysdb_certmap.c
@@ -0,0 +1,260 @@
+/*
+ SSSD
+
+ sysdb_certmap - Tests for sysdb certmap realted calls
+
+ Authors:
+ Jakub Hrozek <jhrozek@redhat.com>
+
+ Copyright (C) 2017 Red Hat
+
+ 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 <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+#include <popt.h>
+
+#include "tests/cmocka/common_mock.h"
+#include "tests/common.h"
+
+#define TESTS_PATH "certmap_" BASE_FILE_STEM
+#define TEST_CONF_DB "test_sysdb_certmap.ldb"
+#define TEST_ID_PROVIDER "ldap"
+#define TEST_DOM_NAME "certmap_test"
+
+struct certmap_test_ctx {
+ struct sss_test_ctx *tctx;
+};
+
+static int test_sysdb_setup(void **state)
+{
+ struct certmap_test_ctx *test_ctx;
+ struct sss_test_conf_param params[] = {
+ { NULL, NULL }, /* Sentinel */
+ };
+
+ assert_true(leak_check_setup());
+
+ test_ctx = talloc_zero(global_talloc_context,
+ struct certmap_test_ctx);
+ assert_non_null(test_ctx);
+ check_leaks_push(test_ctx);
+
+ test_dom_suite_setup(TESTS_PATH);
+
+ test_ctx->tctx = create_dom_test_ctx(test_ctx, TESTS_PATH,
+ TEST_CONF_DB, TEST_DOM_NAME,
+ TEST_ID_PROVIDER, params);
+ assert_non_null(test_ctx->tctx);
+
+ *state = test_ctx;
+ return 0;
+}
+
+static int test_sysdb_teardown(void **state)
+{
+ struct certmap_test_ctx *test_ctx =
+ talloc_get_type(*state, struct certmap_test_ctx);
+
+ test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, TEST_DOM_NAME);
+ talloc_free(test_ctx->tctx);
+ assert_true(check_leaks_pop(test_ctx));
+ talloc_free(test_ctx);
+ assert_true(leak_check_teardown());
+ return 0;
+}
+
+static void test_sysdb_get_certmap_not_exists(void **state)
+{
+ int ret;
+ struct certmap_info **certmap;
+ bool user_name_hint;
+ struct certmap_test_ctx *ctctx = talloc_get_type(*state,
+ struct certmap_test_ctx);
+
+ ret = sysdb_get_certmap(ctctx, ctctx->tctx->sysdb, &certmap,
+ &user_name_hint);
+ assert_int_equal(ret, ENOENT);
+
+}
+
+static void check_certmap(struct certmap_info *m, struct certmap_info *r,
+ size_t exp_domains)
+{
+ size_t d;
+
+ assert_non_null(r);
+ assert_non_null(m);
+ assert_string_equal(m->name, r->name);
+
+ if (r->map_rule == NULL) {
+ assert_null(m->map_rule);
+ } else {
+ assert_string_equal(m->map_rule, r->map_rule);
+ }
+
+ if (r->match_rule == NULL) {
+ assert_null(m->match_rule);
+ } else {
+ assert_string_equal(m->match_rule, r->match_rule);
+ }
+
+ assert_int_equal(m->priority, r->priority);
+ assert_non_null(m->domains);
+ if (r->domains == NULL) {
+ assert_null(m->domains[0]);
+ } else {
+ for (d = 0; r->domains[d]; d++) {
+ assert_non_null(m->domains[d]);
+ assert_true(string_in_list(m->domains[d], discard_const(r->domains),
+ true));
+ }
+
+ assert_int_equal(d, exp_domains);
+ }
+
+}
+
+static void test_sysdb_update_certmap(void **state)
+{
+ int ret;
+ const char *domains[] = { "dom1.test", "dom2.test", "dom3.test", NULL };
+ struct certmap_info map_a = { discard_const("map_a"), 11, discard_const("abc"), discard_const("def"), NULL };
+ struct certmap_info map_b = { discard_const("map_b"), 22, discard_const("abc"), NULL, domains };
+ struct certmap_info *certmap_empty[] = { NULL };
+ struct certmap_info *certmap_a[] = { &map_a, NULL };
+ struct certmap_info *certmap_b[] = { &map_b, NULL };
+ struct certmap_info *certmap_ab[] = { &map_a, &map_b, NULL };
+ struct certmap_info **certmap;
+ struct certmap_test_ctx *ctctx = talloc_get_type(*state,
+ struct certmap_test_ctx);
+ bool user_name_hint;
+
+ ret = sysdb_update_certmap(ctctx->tctx->sysdb, NULL, false);
+ assert_int_equal(ret, EINVAL);
+
+ ret = sysdb_update_certmap(ctctx->tctx->sysdb, certmap_empty, false);
+ assert_int_equal(ret, EOK);
+
+ ret = sysdb_get_certmap(ctctx, ctctx->tctx->sysdb, &certmap,
+ &user_name_hint);
+ assert_int_equal(ret, ENOENT);
+
+ ret = sysdb_update_certmap(ctctx->tctx->sysdb, certmap_a, false);
+ assert_int_equal(ret, EOK);
+
+ ret = sysdb_get_certmap(ctctx, ctctx->tctx->sysdb, &certmap,
+ &user_name_hint);
+ assert_int_equal(ret, EOK);
+ assert_false(user_name_hint);
+ assert_non_null(certmap);
+ assert_non_null(certmap[0]);
+ assert_string_equal(certmap[0]->name, map_a.name);
+ assert_string_equal(certmap[0]->map_rule, map_a.map_rule);
+ assert_string_equal(certmap[0]->match_rule, map_a.match_rule);
+ assert_int_equal(certmap[0]->priority, map_a.priority);
+ assert_non_null(certmap[0]->domains);
+ assert_null(certmap[0]->domains[0]);
+ assert_null(certmap[1]);
+ check_certmap(certmap[0], &map_a, 0);
+ talloc_free(certmap);
+
+ ret = sysdb_update_certmap(ctctx->tctx->sysdb, certmap_b, true);
+ assert_int_equal(ret, EOK);
+
+ ret = sysdb_get_certmap(ctctx, ctctx->tctx->sysdb, &certmap,
+ &user_name_hint);
+ assert_int_equal(ret, EOK);
+ assert_true(user_name_hint);
+ assert_non_null(certmap);
+ assert_non_null(certmap[0]);
+
+ check_certmap(certmap[0], &map_b, 3);
+ assert_null(certmap[1]);
+ talloc_free(certmap);
+
+ ret = sysdb_update_certmap(ctctx->tctx->sysdb, certmap_ab, false);
+ assert_int_equal(ret, EOK);
+
+ ret = sysdb_get_certmap(ctctx, ctctx->tctx->sysdb, &certmap,
+ &user_name_hint);
+ assert_int_equal(ret, EOK);
+ assert_false(user_name_hint);
+ assert_non_null(certmap);
+ assert_non_null(certmap[0]);
+ assert_non_null(certmap[1]);
+ assert_null(certmap[2]);
+ if (strcmp(certmap[0]->name, "map_a") == 0) {
+ check_certmap(certmap[0], &map_a, 0);
+ check_certmap(certmap[1], &map_b, 3);
+ } else {
+ check_certmap(certmap[0], &map_b, 3);
+ check_certmap(certmap[1], &map_a, 0);
+ }
+ talloc_free(certmap);
+}
+
+int main(int argc, const char *argv[])
+{
+ int rv;
+ int no_cleanup = 0;
+ poptContext pc;
+ int opt;
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ SSSD_DEBUG_OPTS
+ {"no-cleanup", 'n', POPT_ARG_NONE, &no_cleanup, 0,
+ _("Do not delete the test database after a test run"), NULL },
+ POPT_TABLEEND
+ };
+
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(test_sysdb_get_certmap_not_exists,
+ test_sysdb_setup,
+ test_sysdb_teardown),
+ cmocka_unit_test_setup_teardown(test_sysdb_update_certmap,
+ test_sysdb_setup,
+ test_sysdb_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_CLI_INIT(debug_level);
+
+ tests_set_cwd();
+ test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, LOCAL_SYSDB_FILE);
+ test_dom_suite_setup(TESTS_PATH);
+ rv = cmocka_run_group_tests(tests, NULL, NULL);
+
+ if (rv == 0 && no_cleanup == 0) {
+ test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, LOCAL_SYSDB_FILE);
+ }
+ return rv;
+}
--
2.12.2

View File

@ -1,484 +0,0 @@
From c44728a02d5e2c9eaced11e74820a6ae6a985f61 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Mon, 6 Feb 2017 10:28:46 +0100
Subject: [PATCH 13/97] IPA: add certmap support
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Read certificate mapping data from the IPA server and configure the
certificate mapping library accordingly.
Related to https://pagure.io/SSSD/sssd/issue/3050
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
---
src/providers/ipa/ipa_config.h | 2 +
src/providers/ipa/ipa_subdomains.c | 354 ++++++++++++++++++++++++++++++
src/providers/ipa/ipa_subdomains_server.c | 4 +
src/providers/ldap/ldap_id.c | 4 +-
src/providers/ldap/sdap.h | 4 +
5 files changed, 367 insertions(+), 1 deletion(-)
diff --git a/src/providers/ipa/ipa_config.h b/src/providers/ipa/ipa_config.h
index 2f1e147d7edab0aca2a16269c6a73bc607b21bd5..60f2d5d7b71227a1d86889ceaf6f0f9ac868480d 100644
--- a/src/providers/ipa/ipa_config.h
+++ b/src/providers/ipa/ipa_config.h
@@ -37,6 +37,8 @@
#define IPA_CONFIG_SEARCH_BASE_TEMPLATE "cn=etc,%s"
#define IPA_CONFIG_FILTER "(&(cn=ipaConfig)(objectClass=ipaGuiConfig))"
+#define IPA_OC_CONFIG "ipaConfig"
+
struct tevent_req * ipa_get_config_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct sdap_handle *sh,
diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
index b2e96b204213a52014edcc6042ffa1ff8152b8bf..7537550606ef09c0b87a80932c75aa4f93c0efab 100644
--- a/src/providers/ipa/ipa_subdomains.c
+++ b/src/providers/ipa/ipa_subdomains.c
@@ -56,6 +56,24 @@
#define IPA_SUBDOMAIN_DISABLED_PERIOD 3600
+#define IPA_OC_CERTMAP_CONFIG_OBJECT "ipaCertMapConfigObject"
+#define IPA_CERTMAP_PROMPT_USERNAME "ipaCertMapPromptUserName"
+
+#define IPA_OC_CERTMAP_RULE "ipaCertMapRule"
+#define IPA_CERTMAP_MAPRULE "ipaCertMapMapRule"
+#define IPA_CERTMAP_MATCHRULE "ipaCertMapMatchRule"
+#define IPA_CERTMAP_PRIORITY "ipaCertMapPriority"
+#define IPA_ENABLED_FLAG "ipaEnabledFlag"
+#define IPA_TRUE_VALUE "TRUE"
+#define IPA_ASSOCIATED_DOMAIN "associatedDomain"
+
+#define OBJECTCLASS "objectClass"
+
+#define CERTMAP_FILTER "(|(&("OBJECTCLASS"="IPA_OC_CERTMAP_RULE")" \
+ "("IPA_ENABLED_FLAG"="IPA_TRUE_VALUE"))" \
+ "("OBJECTCLASS"="IPA_OC_CERTMAP_CONFIG_OBJECT"))"
+
+
struct ipa_subdomains_ctx {
struct be_ctx *be_ctx;
struct ipa_id_ctx *ipa_id_ctx;
@@ -286,6 +304,193 @@ done:
return ret;
}
+struct priv_sss_debug {
+ int level;
+};
+
+void ext_debug(void *private, const char *file, long line, const char *function,
+ const char *format, ...)
+{
+ va_list ap;
+ struct priv_sss_debug *data = private;
+ int level = SSSDBG_OP_FAILURE;
+
+ if (data != NULL) {
+ level = data->level;
+ }
+
+ if (DEBUG_IS_SET(level)) {
+ va_start(ap, format);
+ sss_vdebug_fn(file, line, function, level, APPEND_LINE_FEED,
+ format, ap);
+ va_end(ap);
+ }
+}
+
+static errno_t ipa_certmap_parse_results(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domain,
+ struct sdap_options *sdap_opts,
+ size_t count,
+ struct sysdb_attrs **reply,
+ struct certmap_info ***_certmap_list)
+{
+ struct certmap_info **certmap_list = NULL;
+ struct certmap_info *m;
+ const char *value;
+ const char **values;
+ size_t c;
+ size_t lc = 0;
+ int ret;
+ struct sss_certmap_ctx *certmap_ctx = NULL;
+ const char **ocs = NULL;
+ bool user_name_hint = false;
+
+ certmap_list = talloc_zero_array(mem_ctx, struct certmap_info *, count + 1);
+ if (certmap_list == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_array failed.\n");
+ return ENOMEM;
+ }
+
+ for (c = 0; c < count; c++) {
+ ret = sysdb_attrs_get_string_array(reply[c], SYSDB_OBJECTCLASS, mem_ctx,
+ &ocs);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Missing objectclasses for config objects.\n");
+ ret = EINVAL;
+ goto done;
+ }
+
+ if (string_in_list(IPA_OC_CERTMAP_CONFIG_OBJECT, discard_const(ocs),
+ false)) {
+ ret = sysdb_attrs_get_bool(reply[c], IPA_CERTMAP_PROMPT_USERNAME,
+ &user_name_hint);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to read user name hint option, skipping.\n");
+ }
+ continue;
+ }
+
+ m = talloc_zero(certmap_list, struct certmap_info);
+ if (m == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = sysdb_attrs_get_string(reply[c], IPA_CN, &value);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
+ goto done;
+ }
+
+ m->name = talloc_strdup(m, value);
+ if (m->name == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = sysdb_attrs_get_string(reply[c], IPA_CERTMAP_MATCHRULE, &value);
+ if (ret == EOK) {
+ m->match_rule = talloc_strdup(m, value);
+ if (m->match_rule == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+ } else if (ret != ENOENT) {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
+ goto done;
+ }
+
+ ret = sysdb_attrs_get_string(reply[c], IPA_CERTMAP_MAPRULE, &value);
+ if (ret == EOK) {
+ m->map_rule = talloc_strdup(m, value);
+ if (m->map_rule == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+ } else if (ret != ENOENT) {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
+ goto done;
+ }
+
+ ret = sysdb_attrs_get_string_array(reply[c], IPA_ASSOCIATED_DOMAIN, m,
+ &values);
+ if (ret == EOK) {
+ m->domains = values;
+ } else if (ret != ENOENT) {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
+ goto done;
+ }
+
+ ret = sysdb_attrs_get_uint32_t(reply[c], IPA_CERTMAP_PRIORITY,
+ &m->priority);
+ if (ret != EOK && ret != ENOENT) {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
+ goto done;
+ } else if (ret == ENOENT) {
+ m->priority = SSS_CERTMAP_MIN_PRIO;
+ }
+
+ certmap_list[lc++] = m;
+ }
+
+ certmap_list[lc] = NULL;
+
+ ret = sss_certmap_init(mem_ctx, ext_debug, NULL, &certmap_ctx);
+ if (ret != 0) {
+ DEBUG(SSSDBG_OP_FAILURE, "sss_certmap_init failed.\n");
+ goto done;
+ }
+
+ for (c = 0; certmap_list[c] != NULL; c++) {
+ DEBUG(SSSDBG_TRACE_ALL, "Trying to add rule [%s][%d][%s][%s].\n",
+ certmap_list[c]->name,
+ certmap_list[c]->priority,
+ certmap_list[c]->match_rule,
+ certmap_list[c]->map_rule);
+
+ ret = sss_certmap_add_rule(certmap_ctx, certmap_list[c]->priority,
+ certmap_list[c]->match_rule,
+ certmap_list[c]->map_rule,
+ certmap_list[c]->domains);
+ if (ret != 0) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "sss_certmap_add_rule failed for rule [%s], skipping. "
+ "Please check for typos and if rule syntax is supported.\n",
+ certmap_list[c]->name);
+ goto done;
+ }
+ }
+
+ ret = sysdb_update_certmap(domain->sysdb, certmap_list, user_name_hint);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_update_certmap failed");
+ goto done;
+ }
+
+ sss_certmap_free_ctx(sdap_opts->certmap_ctx);
+ sdap_opts->certmap_ctx = talloc_steal(sdap_opts, certmap_ctx);
+
+ if (_certmap_list != NULL) {
+ *_certmap_list = certmap_list;
+ }
+ ret = EOK;
+
+done:
+ talloc_free(ocs);
+ if (ret != EOK) {
+ sss_certmap_free_ctx(certmap_ctx);
+ talloc_free(certmap_list);
+ }
+
+ return ret;
+}
+
static errno_t ipa_subdom_enumerates(struct sss_domain_info *parent,
struct sysdb_attrs *attrs,
bool *_enumerates)
@@ -801,6 +1006,125 @@ static errno_t ipa_subdomains_ranges_recv(struct tevent_req *req)
return EOK;
}
+#define IPA_CERTMAP_SEARCH_BASE_TEMPLATE "cn=certmap,%s"
+
+struct ipa_subdomains_certmap_state {
+ struct sss_domain_info *domain;
+ struct sdap_options *sdap_opts;
+};
+
+static void ipa_subdomains_certmap_done(struct tevent_req *subreq);
+
+static struct tevent_req *
+ipa_subdomains_certmap_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct ipa_subdomains_ctx *sd_ctx,
+ struct sdap_handle *sh)
+{
+ struct ipa_subdomains_certmap_state *state;
+ struct tevent_req *subreq;
+ struct tevent_req *req;
+ errno_t ret;
+ char *ldap_basedn;
+ char *search_base;
+ const char *attrs[] = { OBJECTCLASS, IPA_CN,
+ IPA_CERTMAP_MAPRULE, IPA_CERTMAP_MATCHRULE,
+ IPA_CERTMAP_PRIORITY, IPA_ASSOCIATED_DOMAIN,
+ IPA_CERTMAP_PROMPT_USERNAME,
+ NULL };
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct ipa_subdomains_certmap_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+ return NULL;
+ }
+
+ state->domain = sd_ctx->be_ctx->domain;
+ state->sdap_opts = sd_ctx->sdap_id_ctx->opts;
+
+ ret = domain_to_basedn(state, state->domain->name, &ldap_basedn);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "domain_to_basedn failed.\n");
+ goto immediately;
+ }
+
+ search_base = talloc_asprintf(state, IPA_CERTMAP_SEARCH_BASE_TEMPLATE,
+ ldap_basedn);
+ if (search_base == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
+ ret = ENOMEM;
+ goto immediately;
+ }
+
+ subreq = sdap_get_generic_send(state, ev, sd_ctx->sdap_id_ctx->opts, sh,
+ search_base, LDAP_SCOPE_SUBTREE,
+ CERTMAP_FILTER,
+ attrs, NULL, 0, 0, false);
+ if (subreq == NULL) {
+ ret = ENOMEM;
+ goto immediately;
+ }
+
+ tevent_req_set_callback(subreq, ipa_subdomains_certmap_done, req);
+
+ return req;
+
+immediately:
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
+ }
+ tevent_req_post(req, ev);
+
+ return req;
+}
+
+static void ipa_subdomains_certmap_done(struct tevent_req *subreq)
+{
+ struct ipa_subdomains_certmap_state *state;
+ struct tevent_req *req;
+ struct sysdb_attrs **reply;
+ size_t reply_count;
+ errno_t ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct ipa_subdomains_certmap_state);
+
+ ret = sdap_get_generic_recv(subreq, state, &reply_count, &reply);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get data from LDAP [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ ret = ipa_certmap_parse_results(state, state->domain,
+ state->sdap_opts,
+ reply_count, reply, NULL);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "Unable to parse certmap results [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+done:
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+static errno_t ipa_subdomains_certmap_recv(struct tevent_req *req)
+{
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ return EOK;
+}
+
struct ipa_subdomains_master_state {
struct sss_domain_info *domain;
struct ipa_options *ipa_options;
@@ -1365,6 +1689,7 @@ struct ipa_subdomains_refresh_state {
static errno_t ipa_subdomains_refresh_retry(struct tevent_req *req);
static void ipa_subdomains_refresh_connect_done(struct tevent_req *subreq);
static void ipa_subdomains_refresh_ranges_done(struct tevent_req *subreq);
+static void ipa_subdomains_refresh_certmap_done(struct tevent_req *subreq);
static void ipa_subdomains_refresh_master_done(struct tevent_req *subreq);
static void ipa_subdomains_refresh_slave_done(struct tevent_req *subreq);
static void ipa_subdomains_refresh_view_done(struct tevent_req *subreq);
@@ -1487,6 +1812,35 @@ static void ipa_subdomains_refresh_ranges_done(struct tevent_req *subreq)
return;
}
+ subreq = ipa_subdomains_certmap_send(state, state->ev, state->sd_ctx,
+ sdap_id_op_handle(state->sdap_op));
+ if (subreq == NULL) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+
+ tevent_req_set_callback(subreq, ipa_subdomains_refresh_certmap_done, req);
+ return;
+}
+
+static void ipa_subdomains_refresh_certmap_done(struct tevent_req *subreq)
+{
+ struct ipa_subdomains_refresh_state *state;
+ struct tevent_req *req;
+ errno_t ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct ipa_subdomains_refresh_state);
+
+ ret = ipa_subdomains_certmap_recv(subreq);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to read certificate mapping rules "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ tevent_req_error(req, ret);
+ return;
+ }
+
subreq = ipa_subdomains_master_send(state, state->ev, state->sd_ctx,
sdap_id_op_handle(state->sdap_op));
if (subreq == NULL) {
diff --git a/src/providers/ipa/ipa_subdomains_server.c b/src/providers/ipa/ipa_subdomains_server.c
index 1af8676c5a9c49121d0f0118a46796c6637f04f9..ae3baf036e4278fb67d86b42742fb7e80b46724e 100644
--- a/src/providers/ipa/ipa_subdomains_server.c
+++ b/src/providers/ipa/ipa_subdomains_server.c
@@ -362,6 +362,10 @@ ipa_ad_ctx_new(struct be_ctx *be_ctx,
ad_id_ctx->sdap_id_ctx->opts->idmap_ctx =
id_ctx->sdap_id_ctx->opts->idmap_ctx;
+ /* Set up the certificate mapping context */
+ ad_id_ctx->sdap_id_ctx->opts->certmap_ctx =
+ id_ctx->sdap_id_ctx->opts->certmap_ctx;
+
*_ad_id_ctx = ad_id_ctx;
return EOK;
}
diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c
index 8e60769d09383ac8ebe33e5f64fd4fd9788e82cd..0bee0ca8d71abece6749fdb8393b9ceacb64417d 100644
--- a/src/providers/ldap/ldap_id.c
+++ b/src/providers/ldap/ldap_id.c
@@ -247,7 +247,9 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx,
}
ret = sss_cert_derb64_to_ldap_filter(state, filter_value, attr_name,
- NULL, NULL, &user_filter);
+ ctx->opts->certmap_ctx,
+ state->domain,
+ &user_filter);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"sss_cert_derb64_to_ldap_filter failed.\n");
diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
index 6079a8bf62d0bdf23c8d462dc0f19c705e391a6e..afdc01948eefe9dda943c8c7ad01a42dd76a1da8 100644
--- a/src/providers/ldap/sdap.h
+++ b/src/providers/ldap/sdap.h
@@ -25,6 +25,7 @@
#include "providers/backend.h"
#include <ldap.h>
#include "util/sss_ldap.h"
+#include "lib/certmap/sss_certmap.h"
struct sdap_msg {
struct sdap_msg *next;
@@ -478,6 +479,9 @@ struct sdap_options {
bool support_matching_rule;
enum dc_functional_level dc_functional_level;
+
+ /* Certificate mapping support */
+ struct sss_certmap_ctx *certmap_ctx;
};
struct sdap_server_opts {
--
2.12.2

View File

@ -1,736 +0,0 @@
From 440797cba931aa491bf418035f55935943e22b4b Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Wed, 15 Mar 2017 14:21:26 +0100
Subject: [PATCH 14/97] nss-idmap: add sss_nss_getlistbycert()
This patch adds a getlistbycert() call to libsss_nss_idmap to make it on
par with InfoPipe.
Related to https://pagure.io/SSSD/sssd/issue/3050
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
---
Makefile.am | 2 +-
src/python/pysss_nss_idmap.c | 103 ++++++++++++++++++-
src/responder/nss/nss_cmd.c | 7 ++
src/responder/nss/nss_protocol.h | 6 ++
src/responder/nss/nss_protocol_sid.c | 63 ++++++++++++
src/sss_client/idmap/sss_nss_idmap.c | 110 +++++++++++++++++++-
src/sss_client/idmap/sss_nss_idmap.exports | 6 ++
src/sss_client/idmap/sss_nss_idmap.h | 17 +++-
src/sss_client/sss_cli.h | 5 +
src/tests/cmocka/test_nss_srv.c | 158 +++++++++++++++++++++++++++++
10 files changed, 471 insertions(+), 6 deletions(-)
diff --git a/Makefile.am b/Makefile.am
index bd0ca0d303e1742ad26c7648cd24e2c0135af34e..7516338bc6fd95045d20db8155a0c82fd7003358 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1128,7 +1128,7 @@ libsss_nss_idmap_la_LIBADD = \
$(CLIENT_LIBS)
libsss_nss_idmap_la_LDFLAGS = \
-Wl,--version-script,$(srcdir)/src/sss_client/idmap/sss_nss_idmap.exports \
- -version-info 2:0:2
+ -version-info 3:0:3
dist_noinst_DATA += src/sss_client/idmap/sss_nss_idmap.exports
diff --git a/src/python/pysss_nss_idmap.c b/src/python/pysss_nss_idmap.c
index c57cc10a86a7a9a22a791c1eae027a1aafa8f780..2e5851c7a6e48629fd93e428aada499fcbe36ebb 100644
--- a/src/python/pysss_nss_idmap.c
+++ b/src/python/pysss_nss_idmap.c
@@ -36,9 +36,37 @@ enum lookup_type {
SIDBYID,
NAMEBYSID,
IDBYSID,
- NAMEBYCERT
+ NAMEBYCERT,
+ LISTBYCERT
};
+static int add_dict_to_list(PyObject *py_list, PyObject *res_type,
+ PyObject *res, PyObject *id_type)
+{
+ int ret;
+ PyObject *py_dict;
+
+ py_dict = PyDict_New();
+ if (py_dict == NULL) {
+ return ENOMEM;
+ }
+
+ ret = PyDict_SetItem(py_dict, res_type, res);
+ if (ret != 0) {
+ Py_XDECREF(py_dict);
+ return ret;
+ }
+
+ ret = PyDict_SetItem(py_dict, PyBytes_FromString(SSS_TYPE_KEY), id_type);
+ if (ret != 0) {
+ Py_XDECREF(py_dict);
+ return ret;
+ }
+
+ ret = PyList_Append(py_list, py_dict);
+
+ return ret;
+}
static int add_dict(PyObject *py_result, PyObject *key, PyObject *res_type,
PyObject *res, PyObject *id_type)
{
@@ -191,6 +219,57 @@ static int do_getnamebycert(PyObject *py_result, PyObject *py_cert)
return ret;
}
+static int do_getlistbycert(PyObject *py_result, PyObject *py_cert)
+{
+ int ret;
+ const char *cert;
+ char **names = NULL;
+ enum sss_id_type *id_types = NULL;
+ size_t c;
+
+ cert = py_string_or_unicode_as_string(py_cert);
+ if (cert == NULL) {
+ return EINVAL;
+ }
+
+ ret = sss_nss_getlistbycert(cert, &names, &id_types);
+ if (ret == 0) {
+
+ PyObject *py_list;
+
+ py_list = PyList_New(0);
+ if (py_list == NULL) {
+ return ENOMEM;
+ }
+
+ for (c = 0; names[c] != NULL; c++) {
+ ret = add_dict_to_list(py_list,
+ PyBytes_FromString(SSS_NAME_KEY),
+ PyUnicode_FromString(names[c]),
+ PYNUMBER_FROMLONG(id_types[c]));
+ if (ret != 0) {
+ goto done;
+ }
+ }
+ ret = PyDict_SetItem(py_result, py_cert, py_list);
+ if (ret != 0) {
+ goto done;
+ }
+ }
+
+done:
+ free(id_types);
+ if (names != NULL) {
+ for (c = 0; names[c] != NULL; c++) {
+ free(names[c]);
+ }
+ free(names);
+ }
+
+ return ret;
+}
+
+
static int do_getidbysid(PyObject *py_result, PyObject *py_sid)
{
const char *sid;
@@ -231,6 +310,9 @@ static int do_lookup(enum lookup_type type, PyObject *py_result,
case NAMEBYCERT:
return do_getnamebycert(py_result, py_inp);
break;
+ case LISTBYCERT:
+ return do_getlistbycert(py_result, py_inp);
+ break;
default:
return ENOSYS;
}
@@ -368,7 +450,7 @@ static PyObject * py_getidbysid(PyObject *module, PyObject *args)
}
PyDoc_STRVAR(getnamebycert_doc,
-"getnamebycert(sid or list/tuple of certificates) -> dict(sid => dict(results))\n\
+"getnamebycert(certificate or list/tuple of certificates) -> dict(certificate => dict(results))\n\
\n\
Returns a dictionary with a dictonary of results for each given certificates.\n\
The result dictonary contain the name and the type of the object which can be\n\
@@ -382,6 +464,21 @@ static PyObject * py_getnamebycert(PyObject *module, PyObject *args)
return check_args(NAMEBYCERT, args);
}
+PyDoc_STRVAR(getlistbycert_doc,
+"getnamebycert(certificate or list/tuple of certificates) -> dict(certificate => dict(results))\n\
+\n\
+Returns a dictionary with a dictonary of results for each given certificates.\n\
+The result dictonary contain the name and the type of the object which can be\n\
+accessed with the key constants NAME_KEY and TYPE_KEY, respectively.\n\
+\n\
+NOTE: getlistbycert currently works only with id_provider set as \"ad\" or \"ipa\""
+);
+
+static PyObject * py_getlistbycert(PyObject *module, PyObject *args)
+{
+ return check_args(LISTBYCERT, args);
+}
+
static PyMethodDef methods[] = {
{ sss_py_const_p(char, "getsidbyname"), (PyCFunction) py_getsidbyname,
METH_VARARGS, getsidbyname_doc },
@@ -393,6 +490,8 @@ static PyMethodDef methods[] = {
METH_VARARGS, getidbysid_doc },
{ sss_py_const_p(char, "getnamebycert"), (PyCFunction) py_getnamebycert,
METH_VARARGS, getnamebycert_doc },
+ { sss_py_const_p(char, "getlistbycert"), (PyCFunction) py_getlistbycert,
+ METH_VARARGS, getlistbycert_doc },
{ NULL,NULL, 0, NULL }
};
diff --git a/src/responder/nss/nss_cmd.c b/src/responder/nss/nss_cmd.c
index 08b3d32f2662efc1cc803f6e9e5f2d064f7d3033..1931bf62a686c7f30852dac547866609cf54a81b 100644
--- a/src/responder/nss/nss_cmd.c
+++ b/src/responder/nss/nss_cmd.c
@@ -932,6 +932,12 @@ static errno_t nss_cmd_getnamebycert(struct cli_ctx *cli_ctx)
nss_protocol_fill_single_name);
}
+static errno_t nss_cmd_getlistbycert(struct cli_ctx *cli_ctx)
+{
+ return nss_getby_cert(cli_ctx, CACHE_REQ_USER_BY_CERT,
+ nss_protocol_fill_name_list);
+}
+
struct sss_cmd_table *get_nss_cmds(void)
{
static struct sss_cmd_table nss_cmds[] = {
@@ -961,6 +967,7 @@ struct sss_cmd_table *get_nss_cmds(void)
{ SSS_NSS_GETIDBYSID, nss_cmd_getidbysid },
{ SSS_NSS_GETORIGBYNAME, nss_cmd_getorigbyname },
{ SSS_NSS_GETNAMEBYCERT, nss_cmd_getnamebycert },
+ { SSS_NSS_GETLISTBYCERT, nss_cmd_getlistbycert },
{ SSS_CLI_NULL, NULL }
};
diff --git a/src/responder/nss/nss_protocol.h b/src/responder/nss/nss_protocol.h
index c94e7b911eb3c0f97b8c06b1766573311cde41ae..e4c0e52c0e642e885ef2c8423ea564beff7242cf 100644
--- a/src/responder/nss/nss_protocol.h
+++ b/src/responder/nss/nss_protocol.h
@@ -175,6 +175,12 @@ nss_protocol_fill_single_name(struct nss_ctx *nss_ctx,
struct cache_req_result *result);
errno_t
+nss_protocol_fill_name_list(struct nss_ctx *nss_ctx,
+ struct nss_cmd_ctx *cmd_ctx,
+ struct sss_packet *packet,
+ struct cache_req_result *result);
+
+errno_t
nss_protocol_fill_id(struct nss_ctx *nss_ctx,
struct nss_cmd_ctx *cmd_ctx,
struct sss_packet *packet,
diff --git a/src/responder/nss/nss_protocol_sid.c b/src/responder/nss/nss_protocol_sid.c
index 0b97e65f75412d40832d861568d8e2f9de5e1732..a6a4e27d039c67ef98f6d5900d5e3fcadb3ee717 100644
--- a/src/responder/nss/nss_protocol_sid.c
+++ b/src/responder/nss/nss_protocol_sid.c
@@ -498,3 +498,66 @@ nss_protocol_fill_id(struct nss_ctx *nss_ctx,
return EOK;
}
+
+errno_t
+nss_protocol_fill_name_list(struct nss_ctx *nss_ctx,
+ struct nss_cmd_ctx *cmd_ctx,
+ struct sss_packet *packet,
+ struct cache_req_result *result)
+{
+ enum sss_id_type *id_types;
+ size_t rp = 0;
+ size_t body_len;
+ uint8_t *body;
+ errno_t ret;
+ struct sized_string *sz_names;
+ size_t len;
+ size_t c;
+ const char *tmp_str;
+
+ sz_names = talloc_array(cmd_ctx, struct sized_string, result->count);
+ if (sz_names == NULL) {
+ return ENOMEM;
+ }
+
+ id_types = talloc_array(cmd_ctx, enum sss_id_type, result->count);
+ if (id_types == NULL) {
+ return ENOMEM;
+ }
+
+ len = 0;
+ for (c = 0; c < result->count; c++) {
+ ret = nss_get_id_type(cmd_ctx, result, &(id_types[c]));
+ if (ret != EOK) {
+ return ret;
+ }
+
+ tmp_str = nss_get_name_from_msg(result->domain, result->msgs[c]);
+ if (tmp_str == NULL) {
+ return EINVAL;
+ }
+ to_sized_string(&(sz_names[c]), tmp_str);
+
+ len += sz_names[c].len;
+ }
+
+ len += (2 + result->count) * sizeof(uint32_t);
+
+ ret = sss_packet_grow(packet, len);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "sss_packet_grow failed.\n");
+ return ret;
+ }
+
+ sss_packet_get_body(packet, &body, &body_len);
+
+ SAFEALIGN_SET_UINT32(&body[rp], result->count, &rp); /* Num results. */
+ SAFEALIGN_SET_UINT32(&body[rp], 0, &rp); /* Reserved. */
+ for (c = 0; c < result->count; c++) {
+ SAFEALIGN_SET_UINT32(&body[rp], id_types[c], &rp);
+ SAFEALIGN_SET_STRING(&body[rp], sz_names[c].str, sz_names[c].len,
+ &rp);
+ }
+
+ return EOK;
+}
diff --git a/src/sss_client/idmap/sss_nss_idmap.c b/src/sss_client/idmap/sss_nss_idmap.c
index fa5a499e3606f7e45a406de4d63002ba35365cb1..6f3af267a1e763e7dce77e3862be377ae2bfe984 100644
--- a/src/sss_client/idmap/sss_nss_idmap.c
+++ b/src/sss_client/idmap/sss_nss_idmap.c
@@ -31,6 +31,7 @@
#include "util/strtonum.h"
#define DATA_START (3 * sizeof(uint32_t))
+#define LIST_START (2 * sizeof(uint32_t))
union input {
const char *str;
uint32_t id;
@@ -38,10 +39,12 @@ union input {
struct output {
enum sss_id_type type;
+ enum sss_id_type *types;
union {
char *str;
uint32_t id;
struct sss_nss_kv *kv_list;
+ char **names;
} d;
};
@@ -72,6 +75,63 @@ void sss_nss_free_kv(struct sss_nss_kv *kv_list)
}
}
+void sss_nss_free_list(char **l)
+{
+ size_t c;
+
+ if (l != NULL) {
+ for (c = 0; l[c] != NULL; c++) {
+ free(l[c]);
+ }
+ free(l);
+ }
+}
+
+static int buf_to_name_type_list(uint8_t *buf, size_t buf_len, uint32_t num,
+ char ***names, enum sss_id_type **types)
+{
+ int ret;
+ size_t c;
+ char **n = NULL;
+ enum sss_id_type *t = NULL;
+ size_t rp = 0;
+
+ n = calloc(num + 1, sizeof(char *));
+ if (n == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ t = calloc(num + 1, sizeof(enum sss_id_type));
+ if (t == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ for (c = 0; c < num; c++) {
+ SAFEALIGN_COPY_UINT32(&(t[c]), buf + rp, &rp);
+ n[c] = strdup((char *) buf + rp);
+ if (n[c] == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ rp += strlen(n[c]) + 1;
+ }
+
+ ret = EOK;
+
+done:
+ if (ret != EOK) {
+ sss_nss_free_list(n);
+ free(t);
+ } else {
+ *names = n;
+ *types = t;
+ }
+
+ return ret;
+}
+
static int buf_to_kv_list(uint8_t *buf, size_t buf_len,
struct sss_nss_kv **kv_list)
{
@@ -153,13 +213,14 @@ static int sss_nss_getyyybyxxx(union input inp, enum sss_cli_command cmd ,
size_t data_len;
uint32_t c;
struct sss_nss_kv *kv_list;
+ char **names;
+ enum sss_id_type *types;
switch (cmd) {
case SSS_NSS_GETSIDBYNAME:
case SSS_NSS_GETNAMEBYSID:
case SSS_NSS_GETIDBYSID:
case SSS_NSS_GETORIGBYNAME:
- case SSS_NSS_GETNAMEBYCERT:
ret = sss_strnlen(inp.str, 2048, &inp_len);
if (ret != EOK) {
return EINVAL;
@@ -169,6 +230,17 @@ static int sss_nss_getyyybyxxx(union input inp, enum sss_cli_command cmd ,
rd.data = inp.str;
break;
+ case SSS_NSS_GETNAMEBYCERT:
+ case SSS_NSS_GETLISTBYCERT:
+ ret = sss_strnlen(inp.str, 10 * 1024 , &inp_len);
+ if (ret != EOK) {
+ return EINVAL;
+ }
+
+ rd.len = inp_len + 1;
+ rd.data = inp.str;
+
+ break;
case SSS_NSS_GETSIDBYID:
rd.len = sizeof(uint32_t);
rd.data = &inp.id;
@@ -195,7 +267,7 @@ static int sss_nss_getyyybyxxx(union input inp, enum sss_cli_command cmd ,
if (num_results == 0) {
ret = ENOENT;
goto done;
- } else if (num_results > 1) {
+ } else if (num_results > 1 && cmd != SSS_NSS_GETLISTBYCERT) {
ret = EBADMSG;
goto done;
}
@@ -237,6 +309,18 @@ static int sss_nss_getyyybyxxx(union input inp, enum sss_cli_command cmd ,
out->d.id = c;
break;
+ case SSS_NSS_GETLISTBYCERT:
+ ret = buf_to_name_type_list(repbuf + LIST_START, replen - LIST_START,
+ num_results,
+ &names, &types);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ out->types = types;
+ out->d.names = names;
+
+ break;
case SSS_NSS_GETORIGBYNAME:
ret = buf_to_kv_list(repbuf + DATA_START, data_len, &kv_list);
if (ret != EOK) {
@@ -392,3 +476,25 @@ int sss_nss_getnamebycert(const char *cert, char **fq_name,
return ret;
}
+
+int sss_nss_getlistbycert(const char *cert, char ***fq_name,
+ enum sss_id_type **type)
+{
+ int ret;
+ union input inp;
+ struct output out;
+
+ if (fq_name == NULL || cert == NULL || *cert == '\0') {
+ return EINVAL;
+ }
+
+ inp.str = cert;
+
+ ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETLISTBYCERT, &out);
+ if (ret == EOK) {
+ *fq_name = out.d.names;
+ *type = out.types;
+ }
+
+ return ret;
+}
diff --git a/src/sss_client/idmap/sss_nss_idmap.exports b/src/sss_client/idmap/sss_nss_idmap.exports
index bd5d80212017d38334c3cdeefa47d6029f42aebb..49dac6fc9351b0ca98cd46e83b85ec8ef0075a0d 100644
--- a/src/sss_client/idmap/sss_nss_idmap.exports
+++ b/src/sss_client/idmap/sss_nss_idmap.exports
@@ -25,3 +25,9 @@ SSS_NSS_IDMAP_0.2.0 {
global:
sss_nss_getnamebycert;
} SSS_NSS_IDMAP_0.1.0;
+
+SSS_NSS_IDMAP_0.3.0 {
+ # public functions
+ global:
+ sss_nss_getlistbycert;
+} SSS_NSS_IDMAP_0.2.0;
diff --git a/src/sss_client/idmap/sss_nss_idmap.h b/src/sss_client/idmap/sss_nss_idmap.h
index 8a6299194e7b91e084b26c0c96e2f93875a832e7..cbf19479ff9ec6e0d6e07e1f7e48a1571e147740 100644
--- a/src/sss_client/idmap/sss_nss_idmap.h
+++ b/src/sss_client/idmap/sss_nss_idmap.h
@@ -130,7 +130,7 @@ int sss_nss_getorigbyname(const char *fq_name, struct sss_nss_kv **kv_list,
* @param[in] cert base64 encoded certificate
* @param[out] fq_name Fully qualified name of a user or a group,
* must be freed by the caller
- * @param[out] type Type of the object related to the SID
+ * @param[out] type Type of the object related to the cert
*
* @return
* - see #sss_nss_getsidbyname
@@ -139,6 +139,21 @@ int sss_nss_getnamebycert(const char *cert, char **fq_name,
enum sss_id_type *type);
/**
+ * @brief Return a list of fully qualified names for the given base64 encoded
+ * X.509 certificate in DER format
+ *
+ * @param[in] cert base64 encoded certificate
+ * @param[out] fq_name List of fully qualified name of users or groups,
+ * must be freed by the caller
+ * @param[out] type List of types of the objects related to the cert
+ *
+ * @return
+ * - see #sss_nss_getsidbyname
+ */
+int sss_nss_getlistbycert(const char *cert, char ***fq_name,
+ enum sss_id_type **type);
+
+/**
* @brief Free key-value list returned by sss_nss_getorigbyname()
*
* @param[in] kv_list Key-value list returned by sss_nss_getorigbyname().
diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h
index 8091e11515184dc9b7f32eed535055d9eee3143f..59fee7a4eceb2c185e156e812af7f2f4c6b2a0dd 100644
--- a/src/sss_client/sss_cli.h
+++ b/src/sss_client/sss_cli.h
@@ -260,6 +260,11 @@ SSS_NSS_GETNAMEBYCERT = 0x0116, /**< Takes the zero terminated string
of a X509 certificate and returns the zero
terminated fully qualified name of the
related object. */
+SSS_NSS_GETLISTBYCERT = 0x0117, /**< Takes the zero terminated string
+ of the base64 encoded DER representation
+ of a X509 certificate and returns a list
+ of zero terminated fully qualified names
+ of the related objects. */
};
/**
diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c
index 76b9c6fb05673130de0957e93291919c263a28f3..50714715cc80338640f2a77ecbe17bd5e0d6e911 100644
--- a/src/tests/cmocka/test_nss_srv.c
+++ b/src/tests/cmocka/test_nss_srv.c
@@ -3454,6 +3454,16 @@ struct passwd testbycert = {
.pw_passwd = discard_const("*"),
};
+struct passwd testbycert2 = {
+ .pw_name = discard_const("testcertuser2"),
+ .pw_uid = 23457,
+ .pw_gid = 6890,
+ .pw_dir = discard_const("/home/testcertuser2"),
+ .pw_gecos = discard_const("test cert user2"),
+ .pw_shell = discard_const("/bin/sh"),
+ .pw_passwd = discard_const("*"),
+};
+
#define TEST_TOKEN_CERT \
"MIIECTCCAvGgAwIBAgIBCDANBgkqhkiG9w0BAQsFADA0MRIwEAYDVQQKDAlJUEEu" \
"REVWRUwxHjAcBgNVBAMMFUNlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNTA2MjMx" \
@@ -3495,6 +3505,57 @@ static int test_nss_getnamebycert_check(uint32_t status, uint8_t *body, size_t b
return EOK;
}
+static int test_nss_getlistbycert_check(uint32_t status, uint8_t *body, size_t blen)
+{
+ size_t rp = 0;
+ uint32_t id_type;
+ uint32_t num;
+ uint32_t reserved;
+ const char *name;
+ int found = 0;
+ const char *fq_name1 = "testcertuser@"TEST_DOM_NAME ;
+ const char *fq_name2 = "testcertuser2@"TEST_DOM_NAME;
+
+ assert_int_equal(status, EOK);
+
+ /* num_results and reserved */
+ SAFEALIGN_COPY_UINT32(&num, body + rp, &rp);
+ assert_in_range(num, 1, 2);
+ SAFEALIGN_COPY_UINT32(&reserved, body + rp, &rp);
+ assert_int_equal(reserved, 0);
+
+ SAFEALIGN_COPY_UINT32(&id_type, body + rp, &rp);
+ assert_int_equal(id_type, SSS_ID_TYPE_UID);
+
+ name = (const char *)body + rp;
+ if (num == 1) {
+ assert_string_equal(name, fq_name1);
+ return EOK;
+ }
+
+ rp += strlen(name) + 1;
+ if (strcmp(name, fq_name1) == 0) {
+ found = 1;
+ } else if (strcmp(name, fq_name2) == 0) {
+ found = 2;
+ }
+ assert_in_range(found, 1, 2);
+
+ SAFEALIGN_COPY_UINT32(&id_type, body + rp, &rp);
+ assert_int_equal(id_type, SSS_ID_TYPE_UID);
+
+ name = (const char *)body + rp;
+ if (found == 1) {
+ assert_string_equal(name, fq_name2);
+ } else {
+ assert_string_equal(name, fq_name1);
+ }
+
+
+ return EOK;
+}
+
+
static void test_nss_getnamebycert(void **state)
{
errno_t ret;
@@ -3572,6 +3633,99 @@ void test_nss_getnamebycert_neg(void **state)
assert_int_equal(nss_test_ctx->ncache_hits, 1);
}
+static void test_nss_getlistbycert(void **state)
+{
+ errno_t ret;
+ struct sysdb_attrs *attrs;
+ unsigned char *der = NULL;
+ size_t der_size;
+
+ attrs = sysdb_new_attrs(nss_test_ctx);
+ assert_non_null(attrs);
+
+ der = sss_base64_decode(nss_test_ctx, TEST_TOKEN_CERT, &der_size);
+ assert_non_null(der);
+
+ ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_CERT, der, der_size);
+ talloc_free(der);
+ assert_int_equal(ret, EOK);
+
+ /* Prime the cache with a valid user */
+ ret = store_user(nss_test_ctx, nss_test_ctx->tctx->dom,
+ &testbycert, attrs, 0);
+ assert_int_equal(ret, EOK);
+ talloc_free(attrs);
+
+ mock_input_cert(TEST_TOKEN_CERT);
+ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETLISTBYCERT);
+ mock_fill_bysid();
+
+ /* Query for that user, call a callback when command finishes */
+ /* Should go straight to back end, without contacting DP. */
+ /* If there is only a single user mapped the result will look like the */
+ /* result of getnamebycert. */
+ set_cmd_cb(test_nss_getlistbycert_check);
+ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETLISTBYCERT,
+ 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);
+}
+
+static void test_nss_getlistbycert_multi(void **state)
+{
+ errno_t ret;
+ struct sysdb_attrs *attrs;
+ unsigned char *der = NULL;
+ size_t der_size;
+
+ der = sss_base64_decode(nss_test_ctx, TEST_TOKEN_CERT, &der_size);
+ assert_non_null(der);
+
+ attrs = sysdb_new_attrs(nss_test_ctx);
+ assert_non_null(attrs);
+
+ ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_CERT, der, der_size);
+ assert_int_equal(ret, EOK);
+
+ /* Prime the cache with two valid user */
+ ret = store_user(nss_test_ctx, nss_test_ctx->tctx->dom,
+ &testbycert, attrs, 0);
+ assert_int_equal(ret, EOK);
+ talloc_free(attrs);
+
+ /* Looks like attrs is modified during store_user() makes sure we start
+ * with fresh data. */
+ attrs = sysdb_new_attrs(nss_test_ctx);
+ assert_non_null(attrs);
+
+ ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_CERT, der, der_size);
+ talloc_free(der);
+ assert_int_equal(ret, EOK);
+
+ ret = store_user(nss_test_ctx, nss_test_ctx->tctx->dom,
+ &testbycert2, attrs, 0);
+ assert_int_equal(ret, EOK);
+ talloc_free(attrs);
+
+ mock_input_cert(TEST_TOKEN_CERT);
+ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETLISTBYCERT);
+ mock_fill_bysid();
+
+ /* Query for that user, call a callback when command finishes */
+ /* Should go straight to back end, without contacting DP */
+ set_cmd_cb(test_nss_getlistbycert_check);
+ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETLISTBYCERT,
+ 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);
+}
+
struct passwd sid_user = {
.pw_name = discard_const("testusersid"),
.pw_uid = 1234,
@@ -3818,6 +3972,10 @@ int main(int argc, const char *argv[])
nss_test_setup, nss_test_teardown),
cmocka_unit_test_setup_teardown(test_nss_getnamebycert,
nss_test_setup, nss_test_teardown),
+ cmocka_unit_test_setup_teardown(test_nss_getlistbycert,
+ nss_test_setup, nss_test_teardown),
+ cmocka_unit_test_setup_teardown(test_nss_getlistbycert_multi,
+ nss_test_setup, nss_test_teardown),
cmocka_unit_test_setup_teardown(test_nss_getsidbyname,
nss_test_setup, nss_test_teardown),
cmocka_unit_test_setup_teardown(test_nss_getsidbyupn,
--
2.12.2

View File

@ -1,70 +0,0 @@
From a0b1bfa76073d3ce3208e67e6d72bb92088edac5 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Tue, 28 Feb 2017 14:19:53 +0100
Subject: [PATCH 15/97] nss: allow larger buffer for certificate based requests
To make sure larger certificates can be processed as well the maximal
buffer size is increased for requests by certificate.
Related to https://pagure.io/SSSD/sssd/issue/3050
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
---
src/responder/common/responder_packet.c | 21 ++++++++++++++++++++-
src/responder/common/responder_packet.h | 1 +
2 files changed, 21 insertions(+), 1 deletion(-)
diff --git a/src/responder/common/responder_packet.c b/src/responder/common/responder_packet.c
index 4f5e110837eb76609d31a77c62a00e00530ffc90..cc4d66995965cca4c86a80c31d2afd4c9ac3e0e4 100644
--- a/src/responder/common/responder_packet.c
+++ b/src/responder/common/responder_packet.c
@@ -179,6 +179,8 @@ int sss_packet_recv(struct sss_packet *packet, int fd)
size_t rb;
size_t len;
void *buf;
+ size_t new_len;
+ int ret;
buf = (uint8_t *)packet->buffer + packet->iop;
if (packet->iop > 4) len = sss_packet_get_len(packet) - packet->iop;
@@ -205,7 +207,24 @@ int sss_packet_recv(struct sss_packet *packet, int fd)
}
if (sss_packet_get_len(packet) > packet->memsize) {
- return EINVAL;
+ /* Allow certificate based requests to use larger buffer but not
+ * larger than SSS_CERT_PACKET_MAX_RECV_SIZE. Due to the way
+ * sss_packet_grow() works the packet len must be set to '0' first and
+ * then grow to the expected size. */
+ if ((sss_packet_get_cmd(packet) == SSS_NSS_GETNAMEBYCERT
+ || sss_packet_get_cmd(packet) == SSS_NSS_GETLISTBYCERT)
+ && packet->memsize < SSS_CERT_PACKET_MAX_RECV_SIZE
+ && (new_len = sss_packet_get_len(packet))
+ < SSS_CERT_PACKET_MAX_RECV_SIZE) {
+ new_len = sss_packet_get_len(packet);
+ sss_packet_set_len(packet, 0);
+ ret = sss_packet_grow(packet, new_len);
+ if (ret != EOK) {
+ return ret;
+ }
+ } else {
+ return EINVAL;
+ }
}
packet->iop += rb;
diff --git a/src/responder/common/responder_packet.h b/src/responder/common/responder_packet.h
index 3ad0eee28477e446c9e4996617beb55f32923d47..afceb4aaefa40fd86bdfde820c92c09b65cd8702 100644
--- a/src/responder/common/responder_packet.h
+++ b/src/responder/common/responder_packet.h
@@ -25,6 +25,7 @@
#include "sss_client/sss_cli.h"
#define SSS_PACKET_MAX_RECV_SIZE 1024
+#define SSS_CERT_PACKET_MAX_RECV_SIZE ( 10 * SSS_PACKET_MAX_RECV_SIZE )
struct sss_packet;
--
2.12.2

View File

@ -1,44 +0,0 @@
From a04bef313508c423ed06cc54805a3b8106ab90cd Mon Sep 17 00:00:00 2001
From: Justin Stephenson <jstephen@redhat.com>
Date: Mon, 20 Mar 2017 11:51:05 -0400
Subject: [PATCH 16/97] IPA: Add s2n request to string function
Add a function to convert request_types to string allowing the
ability to print request type information for ipa_s2n functions during
IPA client operations.
Reviewed-by: Sumit Bose <sbose@redhat.com>
---
src/providers/ipa/ipa_s2n_exop.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
index 07bbb2b4d252c8ca9ada4d890c36c903c9f75773..4fe20689fe4c0f2bb5217691dd05b37d2a1cc820 100644
--- a/src/providers/ipa/ipa_s2n_exop.c
+++ b/src/providers/ipa/ipa_s2n_exop.c
@@ -979,6 +979,22 @@ done:
return ret;
}
+static const char *ipa_s2n_reqtype2str(enum request_types request_type)
+{
+ switch (request_type) {
+ case REQ_SIMPLE:
+ return "REQ_SIMPLE";
+ case REQ_FULL:
+ return "REQ_FULL";
+ case REQ_FULL_WITH_MEMBERS:
+ return "REQ_FULL_WITH_MEMBERS";
+ default:
+ break;
+ }
+
+ return "Unknown request type";
+}
+
struct ipa_s2n_get_list_state {
struct tevent_context *ev;
struct ipa_id_ctx *ipa_ctx;
--
2.12.2

View File

@ -1,82 +0,0 @@
From cd83aead3c9799ac05d8f8977dbb92bbd399c6d5 Mon Sep 17 00:00:00 2001
From: Justin Stephenson <jstephen@redhat.com>
Date: Thu, 16 Mar 2017 14:46:55 -0400
Subject: [PATCH 17/97] IPA: Enhance debug logging for ipa s2n operations
Add log messages to provide useful debug logging surrounding
IPA client extended operations to the IPA Server during AD trust
requests to retrieve information. Print more details about the
objects requested and received during the ipa_s2n operations.
This will improve log analysis and troubleshooting efforts during AD
trust user and group resolution failures on IPA clients, such as missing
groups.
Reviewed-by: Sumit Bose <sbose@redhat.com>
---
src/providers/ipa/ipa_s2n_exop.c | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
index 4fe20689fe4c0f2bb5217691dd05b37d2a1cc820..c99312274073858e5e03f3e82c069dafc839eb61 100644
--- a/src/providers/ipa/ipa_s2n_exop.c
+++ b/src/providers/ipa/ipa_s2n_exop.c
@@ -1156,6 +1156,13 @@ static errno_t ipa_s2n_get_list_step(struct tevent_req *req)
need_v1 = true;
}
+ if (state->req_input.type == REQ_INP_NAME
+ && state->req_input.inp.name != NULL) {
+ DEBUG(SSSDBG_TRACE_FUNC, "Sending request_type: [%s] for group [%s].\n",
+ ipa_s2n_reqtype2str(state->request_type),
+ state->list[state->list_idx]);
+ }
+
subreq = ipa_s2n_exop_send(state, state->ev, state->sh, need_v1,
state->exop_timeout, bv_req);
if (subreq == NULL) {
@@ -1194,6 +1201,9 @@ static void ipa_s2n_get_list_next(struct tevent_req *subreq)
goto fail;
}
+ DEBUG(SSSDBG_TRACE_FUNC, "Received [%s] attributes from IPA server.\n",
+ state->attrs->a.name);
+
if (is_default_view(state->ipa_ctx->view_name)) {
ret = ipa_s2n_get_list_save_step(req);
if (ret == EOK) {
@@ -1375,6 +1385,11 @@ struct tevent_req *ipa_s2n_get_acct_info_send(TALLOC_CTX *mem_ctx,
goto fail;
}
+ DEBUG(SSSDBG_TRACE_FUNC, "Sending request_type: [%s] for trust user [%s] "
+ "to IPA server\n",
+ ipa_s2n_reqtype2str(state->request_type),
+ req_input->inp.name);
+
subreq = ipa_s2n_exop_send(state, state->ev, state->sh, is_v1,
state->exop_timeout, bv_req);
if (subreq == NULL) {
@@ -1661,6 +1676,19 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq)
state->attrs = attrs;
if (attrs->response_type == RESP_USER_GROUPLIST) {
+
+ if (DEBUG_IS_SET(SSSDBG_TRACE_FUNC)) {
+ size_t c;
+
+ DEBUG(SSSDBG_TRACE_FUNC, "Received [%zu] groups in group list "
+ "from IPA Server\n", attrs->ngroups);
+
+ for (c = 0; c < attrs->ngroups; c++) {
+ DEBUG(SSSDBG_TRACE_FUNC, "[%s].\n", attrs->groups[c]);
+ }
+ }
+
+
ret = get_group_dn_list(state, state->dom,
attrs->ngroups, attrs->groups,
&group_dn_list, &missing_list);
--
2.12.2

View File

@ -1,45 +0,0 @@
From 3a4a88259ba90d3dc45c1adbbfd39bd7c0204a12 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Wed, 15 Mar 2017 13:32:42 +0100
Subject: [PATCH 18/97] UTIL: iobuf: Make input parameter for the readonly
operation const
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Reviewed-by: Michal Židek <mzidek@redhat.com>
Reviewed-by: Simo Sorce <simo@redhat.com>
---
src/util/sss_iobuf.c | 2 +-
src/util/sss_iobuf.h | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/util/sss_iobuf.c b/src/util/sss_iobuf.c
index 7c72ea94d7a005dfd9671793b3ad470a6de7967a..900418b750a3455ebc2c3bb1893db726692260b8 100644
--- a/src/util/sss_iobuf.c
+++ b/src/util/sss_iobuf.c
@@ -49,7 +49,7 @@ struct sss_iobuf *sss_iobuf_init_empty(TALLOC_CTX *mem_ctx,
}
struct sss_iobuf *sss_iobuf_init_readonly(TALLOC_CTX *mem_ctx,
- uint8_t *data,
+ const uint8_t *data,
size_t size)
{
struct sss_iobuf *iobuf;
diff --git a/src/util/sss_iobuf.h b/src/util/sss_iobuf.h
index eae357a40f2948e63df189f2842edee68691a542..900faaa212230f72f52e344c085167e80ae2b465 100644
--- a/src/util/sss_iobuf.h
+++ b/src/util/sss_iobuf.h
@@ -47,7 +47,7 @@ struct sss_iobuf *sss_iobuf_init_empty(TALLOC_CTX *mem_ctx,
* @return The newly created buffer on success or NULL on an error.
*/
struct sss_iobuf *sss_iobuf_init_readonly(TALLOC_CTX *mem_ctx,
- uint8_t *data,
+ const uint8_t *data,
size_t size);
/*
--
2.12.2

View File

@ -1,32 +0,0 @@
From 24889dc5e7eb7bc992ab0fa05edfdfa1d157131a Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Wed, 15 Mar 2017 13:42:03 +0100
Subject: [PATCH 19/97] UTIL: Fix a typo in the tcurl test tool
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Reviewed-by: Michal Židek <mzidek@redhat.com>
Reviewed-by: Simo Sorce <simo@redhat.com>
---
src/tests/tcurl_test_tool.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/tests/tcurl_test_tool.c b/src/tests/tcurl_test_tool.c
index 35ea979780df47c92ed92bc5bba713faa8909b90..38cea432885c97ca3827c8f158bf7e3ebfc67b31 100644
--- a/src/tests/tcurl_test_tool.c
+++ b/src/tests/tcurl_test_tool.c
@@ -204,8 +204,8 @@ int main(int argc, const char *argv[])
urls[i],
headers,
inbufs[i],
- 10);
- if (ctx == NULL) {
+ 5);
+ if (req == NULL) {
DEBUG(SSSDBG_FATAL_FAILURE, "Could not create request\n");
talloc_zfree(tool_ctx);
return 1;
--
2.12.2

View File

@ -1,36 +0,0 @@
From c194e8d7cad0184d710d9979e9f12d5cfe176f4a Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Thu, 23 Feb 2017 20:55:05 +0100
Subject: [PATCH 20/97] UTIL: Add SAFEALIGN_COPY_UINT8_CHECK
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This macro will be used later in the KCM code
Reviewed-by: Michal Židek <mzidek@redhat.com>
Reviewed-by: Simo Sorce <simo@redhat.com>
---
src/util/util_safealign.h | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/util/util_safealign.h b/src/util/util_safealign.h
index 0d9a579cdbfafc30bf2d0a6ad2651c71428ebd93..57f04a17d4a38300b959c1593d756b351ebd89e8 100644
--- a/src/util/util_safealign.h
+++ b/src/util/util_safealign.h
@@ -130,6 +130,12 @@ safealign_memcpy(void *dest, const void *src, size_t n, size_t *counter)
safealign_memcpy(dest, src, srclen, pctr); \
} while(0)
+#define SAFEALIGN_COPY_UINT8_CHECK(dest, src, len, pctr) do { \
+ if ((*(pctr) + sizeof(uint8_t)) > (len) || \
+ SIZE_T_OVERFLOW(*(pctr), sizeof(uint8_t))) { return EINVAL; } \
+ safealign_memcpy(dest, src, sizeof(uint8_t), pctr); \
+} while(0)
+
/* Aliases for backward compatibility. */
#define SAFEALIGN_SET_VALUE SAFEALIGN_SETMEM_VALUE
#define SAFEALIGN_SET_INT64 SAFEALIGN_SETMEM_INT64
--
2.12.2

View File

@ -1,34 +0,0 @@
From 4f511a4c5f0084e22ce4c7613f1b279533c68cc5 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Tue, 20 Sep 2016 22:00:27 +0200
Subject: [PATCH 21/97] UTIL: Add utility macro cli_creds_get_gid()
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The KCM responder checks the owneship of the ccache based on both UID
and GID of the peer. In order to reuse the already existing creds
structure, let's just add a new macro that returns the GID from the
creds structure.
Reviewed-by: Michal Židek <mzidek@redhat.com>
Reviewed-by: Simo Sorce <simo@redhat.com>
---
src/util/util_creds.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/util/util_creds.h b/src/util/util_creds.h
index 65468fa12b8c6921859574c40f5759c936a10e86..936b9965d1ccd2b437d93b38d789b6f8389f47a6 100644
--- a/src/util/util_creds.h
+++ b/src/util/util_creds.h
@@ -71,6 +71,7 @@ struct cli_creds {
};
#define cli_creds_get_uid(x) x->ucred.uid
+#define cli_creds_get_gid(x) x->ucred.gid
#else /* not HAVE_UCRED */
struct cli_creds {
--
2.12.2

View File

@ -1,194 +0,0 @@
From 5f7f45a64bdb9353f15b945db4ad2564b4b28ab2 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Thu, 23 Feb 2017 21:57:13 +0100
Subject: [PATCH 22/97] UTIL: Add type-specific getsetters to sss_iobuf
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The KCM responder receives its input as unstructured data. To make the
parsing easier, this commit adds several type-specific getsetters to the
iobuf module.
Reviewed-by: Michal Židek <mzidek@redhat.com>
Reviewed-by: Simo Sorce <simo@redhat.com>
---
src/util/sss_iobuf.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++
src/util/sss_iobuf.h | 33 ++++++++++++++++
2 files changed, 141 insertions(+)
diff --git a/src/util/sss_iobuf.c b/src/util/sss_iobuf.c
index 900418b750a3455ebc2c3bb1893db726692260b8..fc288d2df2bfaaba393dd490d4da8976de804cb5 100644
--- a/src/util/sss_iobuf.c
+++ b/src/util/sss_iobuf.c
@@ -184,6 +184,25 @@ errno_t sss_iobuf_read(struct sss_iobuf *iobuf,
return EOK;
}
+errno_t sss_iobuf_read_len(struct sss_iobuf *iobuf,
+ size_t len,
+ uint8_t *_buf)
+{
+ size_t read;
+ errno_t ret;
+
+ ret = sss_iobuf_read(iobuf, len, _buf, &read);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ if (read != len) {
+ return ENOBUFS;
+ }
+
+ return EOK;
+}
+
errno_t sss_iobuf_write_len(struct sss_iobuf *iobuf,
uint8_t *buf,
size_t len)
@@ -203,3 +222,92 @@ errno_t sss_iobuf_write_len(struct sss_iobuf *iobuf,
return EOK;
}
+
+errno_t sss_iobuf_read_uint32(struct sss_iobuf *iobuf,
+ uint32_t *_val)
+{
+ SAFEALIGN_COPY_UINT32_CHECK(_val, iobuf_ptr(iobuf),
+ iobuf->capacity, &iobuf->dp);
+ return EOK;
+}
+
+errno_t sss_iobuf_read_int32(struct sss_iobuf *iobuf,
+ int32_t *_val)
+{
+ SAFEALIGN_COPY_INT32_CHECK(_val, iobuf_ptr(iobuf),
+ iobuf->capacity, &iobuf->dp);
+ return EOK;
+}
+
+errno_t sss_iobuf_write_uint32(struct sss_iobuf *iobuf,
+ uint32_t val)
+{
+ errno_t ret;
+
+ ret = ensure_bytes(iobuf, sizeof(uint32_t));
+ if (ret != EOK) {
+ return ret;
+ }
+
+ SAFEALIGN_SETMEM_UINT32(iobuf_ptr(iobuf), val, &iobuf->dp);
+ return EOK;
+}
+
+errno_t sss_iobuf_write_int32(struct sss_iobuf *iobuf,
+ int32_t val)
+{
+ errno_t ret;
+
+ ret = ensure_bytes(iobuf, sizeof(int32_t));
+ if (ret != EOK) {
+ return ret;
+ }
+
+ SAFEALIGN_SETMEM_INT32(iobuf_ptr(iobuf), val, &iobuf->dp);
+ return EOK;
+}
+
+errno_t sss_iobuf_read_stringz(struct sss_iobuf *iobuf,
+ const char **_out)
+{
+ uint8_t *end;
+ size_t len;
+
+ if (iobuf == NULL) {
+ return EINVAL;
+ }
+
+ if (_out == NULL) {
+ return EINVAL;
+ }
+
+ *_out = NULL;
+
+ end = memchr(iobuf_ptr(iobuf), '\0', sss_iobuf_get_size(iobuf));
+ if (end == NULL) {
+ return EINVAL;
+ }
+
+ len = end + 1 - iobuf_ptr(iobuf);
+ if (sss_iobuf_get_size(iobuf) < len) {
+ return EINVAL;
+ }
+
+ *_out = (const char *) iobuf_ptr(iobuf);
+ iobuf->dp += len;
+ return EOK;
+}
+
+errno_t sss_iobuf_write_stringz(struct sss_iobuf *iobuf,
+ const char *str)
+{
+ if (iobuf == NULL || str == NULL) {
+ return EINVAL;
+ }
+
+ SAFEALIGN_MEMCPY_CHECK(iobuf_ptr(iobuf),
+ str, strlen(str)+1,
+ sss_iobuf_get_size(iobuf),
+ &iobuf->dp);
+ return EOK;
+}
diff --git a/src/util/sss_iobuf.h b/src/util/sss_iobuf.h
index 900faaa212230f72f52e344c085167e80ae2b465..cc3dfd1e98eeb49b979ac321bd0253bffa8a6dff 100644
--- a/src/util/sss_iobuf.h
+++ b/src/util/sss_iobuf.h
@@ -96,6 +96,22 @@ errno_t sss_iobuf_read(struct sss_iobuf *iobuf,
size_t *_read);
/*
+ * @brief Read an exact number of bytes from an IO buffer
+ *
+ * Read exactly len bytes from an IO buffer. If the buffer contains fewer
+ * bytes than len, ENOBUFS is returned.
+ *
+ * @param[in] iobuf The IO buffer to read from
+ * @param[in] len The maximum number of bytes to read
+ * @param[out] _buf The buffer to read data into from iobuf
+ *
+ * @return EOK on success, errno otherwise
+ */
+errno_t sss_iobuf_read_len(struct sss_iobuf *iobuf,
+ size_t len,
+ uint8_t *_buf);
+
+/*
* @brief Write into an IO buffer
*
* Attempts to write len bytes into the iobuf. If the capacity is exceeded,
@@ -115,4 +131,21 @@ errno_t sss_iobuf_write_len(struct sss_iobuf *iobuf,
uint8_t *buf,
size_t len);
+errno_t sss_iobuf_read_uint32(struct sss_iobuf *iobuf,
+ uint32_t *_val);
+
+errno_t sss_iobuf_write_uint32(struct sss_iobuf *iobuf,
+ uint32_t val);
+
+errno_t sss_iobuf_read_int32(struct sss_iobuf *iobuf,
+ int32_t *_val);
+
+errno_t sss_iobuf_write_int32(struct sss_iobuf *iobuf,
+ int32_t val);
+
+errno_t sss_iobuf_read_stringz(struct sss_iobuf *iobuf,
+ const char **_out);
+
+errno_t sss_iobuf_write_stringz(struct sss_iobuf *iobuf,
+ const char *str);
#endif /* __SSS_IOBUF_H_ */
--
2.12.2

View File

@ -1,262 +0,0 @@
From 1dbf09404e20b6e30a24afe72b6d349734aee62f Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Tue, 20 Sep 2016 22:03:30 +0200
Subject: [PATCH 23/97] UTIL: krb5 principal (un)marshalling
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The KCM responder needs to read the contents of the principal blob that
the Kerberos library sends. Since libkrb5 doesn't export any API to do
so, we need to implement marshalling and unmarshalling of the principal
ourselves.
In future, when the KCM server also supports renewals, we will also need
to unmarshall the credentials, but until that is not really needed, the
credentials will be stored as a blob.
Reviewed-by: Michal Židek <mzidek@redhat.com>
Reviewed-by: Simo Sorce <simo@redhat.com>
---
src/util/sss_krb5.c | 195 ++++++++++++++++++++++++++++++++++++++++++++++++++++
src/util/sss_krb5.h | 9 +++
2 files changed, 204 insertions(+)
diff --git a/src/util/sss_krb5.c b/src/util/sss_krb5.c
index 4808a7703d07bb4eba91f14a7a515aadaec1774b..d461cf881566af37f31524c16f6a5f1511a5dc89 100644
--- a/src/util/sss_krb5.c
+++ b/src/util/sss_krb5.c
@@ -24,6 +24,7 @@
#include "config.h"
+#include "util/sss_iobuf.h"
#include "util/util.h"
#include "util/sss_krb5.h"
@@ -1128,3 +1129,197 @@ done:
return res;
}
+
+static errno_t iobuf_read_uint32be(struct sss_iobuf *iobuf,
+ uint32_t *_val)
+{
+ uint32_t beval;
+ errno_t ret;
+
+ ret = sss_iobuf_read_uint32(iobuf, &beval);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ *_val = be32toh(beval);
+ return EOK;
+}
+
+static errno_t iobuf_write_uint32be(struct sss_iobuf *iobuf,
+ uint32_t val)
+{
+ uint32_t beval;
+
+ beval = htobe32(val);
+ return sss_iobuf_write_uint32(iobuf, beval);
+}
+
+static errno_t iobuf_get_len_bytes(TALLOC_CTX *mem_ctx,
+ struct sss_iobuf *iobuf,
+ uint32_t *_nbytes,
+ uint8_t **_bytes)
+{
+ errno_t ret;
+ uint32_t nbytes;
+ uint8_t *bytes = NULL;
+
+ ret = iobuf_read_uint32be(iobuf, &nbytes);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ bytes = talloc_zero_size(mem_ctx, nbytes);
+ if (bytes == NULL) {
+ return ENOMEM;
+ }
+
+ ret = sss_iobuf_read_len(iobuf, nbytes, bytes);
+ if (ret != EOK) {
+ talloc_free(bytes);
+ return ret;
+ }
+
+ *_bytes = bytes;
+ *_nbytes = nbytes;
+ return EOK;
+}
+
+static errno_t get_krb5_data(TALLOC_CTX *mem_ctx,
+ struct sss_iobuf *iobuf,
+ krb5_data *k5data)
+{
+ errno_t ret;
+ uint32_t nbytes;
+ uint8_t *bytes = NULL;
+
+ ret = iobuf_get_len_bytes(mem_ctx, iobuf, &nbytes, &bytes);
+ if (ret != EOK) {
+ talloc_free(bytes);
+ return ret;
+ }
+
+ k5data->data = (char *) bytes; /* FIXME - the cast is ugly */
+ k5data->length = nbytes;
+ return EOK;
+}
+
+static errno_t set_krb5_data(struct sss_iobuf *iobuf,
+ krb5_data *k5data)
+{
+ errno_t ret;
+
+ ret = iobuf_write_uint32be(iobuf, k5data->length);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ if (k5data->length > 0) {
+ ret = sss_iobuf_write_len(iobuf,
+ (uint8_t *) k5data->data,
+ k5data->length);
+ if (ret != EOK) {
+ return ret;
+ }
+ }
+
+ return EOK;
+}
+
+/* FIXME - it would be nice if Kerberos exported these APIs.. */
+krb5_error_code sss_krb5_unmarshal_princ(TALLOC_CTX *mem_ctx,
+ struct sss_iobuf *iobuf,
+ krb5_principal *_princ)
+{
+ krb5_principal princ = NULL;
+ krb5_error_code ret;
+ uint32_t ncomps;
+
+ if (iobuf == NULL || _princ == NULL) {
+ return EINVAL;
+ }
+
+ princ = talloc_zero(mem_ctx, struct krb5_principal_data);
+ if (princ == NULL) {
+ return ENOMEM;
+ }
+
+ princ->magic = KV5M_PRINCIPAL;
+
+ ret = iobuf_read_uint32be(iobuf, (uint32_t *) &princ->type);
+ if (ret != EOK) {
+ goto fail;
+ }
+
+ ret = iobuf_read_uint32be(iobuf, &ncomps);
+ if (ret != EOK) {
+ goto fail;
+ }
+
+ if (ncomps > sss_iobuf_get_capacity(iobuf)) {
+ /* Sanity check to avoid large allocations */
+ ret = EINVAL;
+ goto fail;
+ }
+
+ if (ncomps != 0) {
+ princ->data = talloc_zero_array(princ, krb5_data, ncomps);
+ if (princ->data == NULL) {
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ princ->length = ncomps;
+ }
+
+ ret = get_krb5_data(princ, iobuf, &princ->realm);
+ if (ret != EOK) {
+ goto fail;
+ }
+
+ for (size_t i = 0; i < ncomps; i++) {
+ ret = get_krb5_data(princ->data, iobuf, &princ->data[i]);
+ if (ret != EOK) {
+ goto fail;
+ }
+ }
+
+ *_princ = princ;
+ return 0;
+
+fail:
+ talloc_free(princ);
+ return ret;
+}
+
+krb5_error_code sss_krb5_marshal_princ(krb5_principal princ,
+ struct sss_iobuf *iobuf)
+{
+ krb5_error_code ret;
+
+ if (iobuf == NULL || princ == NULL) {
+ return EINVAL;
+ }
+
+ ret = iobuf_write_uint32be(iobuf, princ->type);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ ret = iobuf_write_uint32be(iobuf, princ->length);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ ret = set_krb5_data(iobuf, &princ->realm);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ for (int i = 0; i < princ->length; i++) {
+ ret = set_krb5_data(iobuf, &princ->data[i]);
+ if (ret != EOK) {
+ return ret;
+ }
+ }
+ return EOK;
+}
diff --git a/src/util/sss_krb5.h b/src/util/sss_krb5.h
index ac0f6082c75a8878f72346733e592b7575d44089..0d9043be98749b1a21a1b74c68f07298fa27f230 100644
--- a/src/util/sss_krb5.h
+++ b/src/util/sss_krb5.h
@@ -32,6 +32,7 @@
#include <krb5.h>
#endif
+#include "util/sss_iobuf.h"
#include "util/util.h"
#define KRB5_CHILD_LOG_FILE "krb5_child"
@@ -186,4 +187,12 @@ krb5_error_code sss_krb5_kt_have_content(krb5_context context,
krb5_keytab keytab);
bool sss_krb5_realm_has_proxy(const char *realm);
+
+krb5_error_code sss_krb5_marshal_princ(krb5_principal princ,
+ struct sss_iobuf *iobuf);
+
+krb5_error_code sss_krb5_unmarshal_princ(TALLOC_CTX *mem_ctx,
+ struct sss_iobuf *iobuf,
+ krb5_principal *_princ);
+
#endif /* __SSS_KRB5_H__ */
--
2.12.2

File diff suppressed because it is too large Load Diff

View File

@ -1,578 +0,0 @@
From 9dcdbf596e138df3eec202487549a67cd3b0091b Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Fri, 23 Sep 2016 14:00:10 +0200
Subject: [PATCH 25/97] KCM: request parsing and sending a reply
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Implements parsing the KCM client request into per-client buffers and
sending a response for both the failure case and for success.
The protocol is documented at:
http://k5wiki.kerberos.org/wiki/Projects/KCM_client
Several places don't use the sss_iobuf structure, because they don't
parse variable-length data from the buffer and it's much more efficient
to just allocate the needed request and reply structure on the stack.
Reviewed-by: Michal Židek <mzidek@redhat.com>
Reviewed-by: Simo Sorce <simo@redhat.com>
---
src/responder/kcm/kcmsrv_cmd.c | 467 ++++++++++++++++++++++++++++++++++++++++-
src/responder/kcm/kcmsrv_pvt.h | 21 +-
2 files changed, 474 insertions(+), 14 deletions(-)
diff --git a/src/responder/kcm/kcmsrv_cmd.c b/src/responder/kcm/kcmsrv_cmd.c
index e9a03cbd41169c93e00b0630dc1e05e205881ec9..cbf70353730d8a4e03d8f75c97395f4ef007e77f 100644
--- a/src/responder/kcm/kcmsrv_cmd.c
+++ b/src/responder/kcm/kcmsrv_cmd.c
@@ -19,14 +19,430 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <krb5/krb5.h>
+
#include "config.h"
#include "util/util.h"
+#include "util/sss_iobuf.h"
#include "responder/common/responder.h"
+#include "responder/kcm/kcmsrv_pvt.h"
+#include "responder/kcm/kcm.h"
-struct kcm_proto_ctx {
- void *unused;
+/* The first four bytes of a message is always the size */
+#define KCM_MSG_LEN_SIZE 4
+
+/* The return code is 32bits */
+#define KCM_RETCODE_SIZE 4
+
+/* The maximum length of a request or reply as defined by the RPC
+ * protocol. This is the same constant size as MIT KRB5 uses
+ */
+#define KCM_PACKET_MAX_SIZE 2048
+
+/* KCM operation, its raw input and raw output and result */
+struct kcm_op_io {
+ struct kcm_op *op;
+ struct kcm_data request;
+ struct sss_iobuf *reply;
+};
+
+/**
+ * KCM IO-vector operations
+ */
+struct kcm_iovec {
+ /* We don't use iovec b/c void pointers don't allow for
+ * pointer arithmetics and it's convenient to keep track
+ * of processed bytes
+ */
+ uint8_t *kiov_base;
+ size_t kiov_len;
+ size_t nprocessed;
+};
+
+static errno_t kcm_iovec_op(int fd, struct kcm_iovec *kiov, bool do_read)
+{
+ ssize_t len;
+ struct iovec iov[1];
+
+ iov[0].iov_base = kiov->kiov_base + kiov->nprocessed;
+ iov[0].iov_len = kiov->kiov_len - kiov->nprocessed;
+ if (iov[0].iov_len == 0) {
+ /* This iovec is full (read) or depleted (write), proceed to the next one */
+ return EOK;
+ }
+
+ if (do_read) {
+ len = readv(fd, iov, 1);
+ } else {
+ len = writev(fd, iov, 1);
+ }
+
+ if (len == -1) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
+ return EAGAIN;
+ } else {
+ return errno;
+ }
+ }
+
+ if (len == 0) {
+ /* Read event on fd that doesn't yield data? error */
+ return ENODATA;
+ }
+
+ /* Decrease the amount of available free space in the iovec */
+ kiov->nprocessed += len;
+ return EOK;
+}
+
+static errno_t kcm_read_iovec(int fd, struct kcm_iovec *kiov)
+{
+ return kcm_iovec_op(fd, kiov, true);
+}
+
+static errno_t kcm_write_iovec(int fd, struct kcm_iovec *kiov)
+{
+ return kcm_iovec_op(fd, kiov, false);
+}
+
+/**
+ * Parsing KCM input
+ *
+ * The request is received as two IO vectors:
+ *
+ * first iovec:
+ * length 32-bit big-endian integer
+ *
+ * second iovec:
+ * major protocol number 8-bit big-endian integer
+ * minor protocol number 8-bit big-endian integer
+ * opcode 16-bit big-endian integer
+ * message payload buffer
+ */
+struct kcm_reqbuf {
+ uint8_t lenbuf[KCM_MSG_LEN_SIZE];
+ struct kcm_iovec v_len;
+
+ /* Includes the major, minor versions etc */
+ uint8_t msgbuf[KCM_PACKET_MAX_SIZE];
+ struct kcm_iovec v_msg;
+};
+
+static errno_t kcm_input_parse(struct kcm_reqbuf *reqbuf,
+ struct kcm_op_io *op_io)
+{
+ size_t lc = 0;
+ size_t mc = 0;
+ uint16_t opcode = 0;
+ uint16_t opcode_be = 0;
+ uint32_t len_be = 0;
+ uint32_t msglen;
+ uint8_t proto_maj = 0;
+ uint8_t proto_min = 0;
+
+ /* The first 4 bytes before the payload is message length */
+ SAFEALIGN_COPY_UINT32_CHECK(&len_be,
+ reqbuf->v_len.kiov_base,
+ reqbuf->v_len.kiov_len,
+ &lc);
+ msglen = be32toh(len_be);
+ DEBUG(SSSDBG_TRACE_LIBS,
+ "Received message with length %"PRIu32"\n", msglen);
+
+ if (msglen == 0) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Illegal zero-length message\n");
+ return EBADMSG;
+ }
+
+ if (msglen != reqbuf->v_msg.nprocessed) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Sender claims the message is %"PRIu32" bytes, "
+ "but received %zu\n",
+ msglen, reqbuf->v_msg.nprocessed);
+ return EBADMSG;
+ }
+
+ /* First 16 bits are 8 bit major and 8bit major protocol version */
+ SAFEALIGN_COPY_UINT8_CHECK(&proto_maj,
+ reqbuf->v_msg.kiov_base + mc,
+ reqbuf->v_msg.kiov_len,
+ &mc);
+ SAFEALIGN_COPY_UINT8_CHECK(&proto_min,
+ reqbuf->v_msg.kiov_base + mc,
+ reqbuf->v_msg.kiov_len,
+ &mc);
+
+ if (proto_maj != KCM_PROTOCOL_VERSION_MAJOR) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Expected major version %d, got %"PRIu16"\n",
+ KCM_PROTOCOL_VERSION_MAJOR, (uint16_t) proto_maj);
+ return ERR_KCM_MALFORMED_IN_PKT;
+ }
+
+ if (proto_min != KCM_PROTOCOL_VERSION_MINOR) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Expected minor version %d, got %"PRIu16"\n",
+ KCM_PROTOCOL_VERSION_MINOR, (uint16_t) proto_maj);
+ return ERR_KCM_MALFORMED_IN_PKT;
+ }
+
+ SAFEALIGN_COPY_UINT16_CHECK(&opcode_be,
+ reqbuf->v_msg.kiov_base + mc,
+ reqbuf->v_msg.kiov_len,
+ &mc);
+
+ opcode = be16toh(opcode_be);
+ DEBUG(SSSDBG_TRACE_LIBS, "Received operation code %"PRIu16"\n", opcode);
+
+ return EOK;
+}
+
+/**
+ * Constructing a reply for failure and success
+ *
+ * The reply consists of three IO vectors:
+ * 1) length iovec:
+ * length: 32-bit big-endian
+ *
+ * 2) return code iovec:
+ * retcode: 32-bit big-endian. Non-zero on failure in the KCM server,
+ * zero if the KCM operation ran (even if the operation itself
+ * failed)
+ *
+ * 3) reply iovec
+ * message: buffer, first 32-bits of the buffer is the return code of
+ * the KCM operation, the rest depends on the operation itself.
+ * The buffer's length is specified by the first integer in the
+ * reply (very intuitive, right?)
+ *
+ * The client always reads the length and return code iovectors. However, the
+ * client reads the reply iovec only if retcode is 0 in the return code iovector
+ * (see kcmio_unix_socket_read() in the MIT tree)
+ */
+struct kcm_repbuf {
+ uint8_t lenbuf[KCM_MSG_LEN_SIZE];
+ struct kcm_iovec v_len;
+
+ uint8_t rcbuf[KCM_RETCODE_SIZE];
+ struct kcm_iovec v_rc;
+
+ uint8_t msgbuf[KCM_PACKET_MAX_SIZE];
+ struct kcm_iovec v_msg;
+};
+
+static errno_t kcm_failbuf_construct(errno_t ret,
+ struct kcm_repbuf *repbuf)
+{
+ size_t c;
+
+ c = 0;
+ SAFEALIGN_SETMEM_UINT32(repbuf->lenbuf, 0, &c);
+ c = 0;
+ SAFEALIGN_SETMEM_UINT32(repbuf->rcbuf, htobe32(ret), &c);
+
+ return EOK;
+}
+
+/**
+ * Construct a reply buffer and send it to the KCM client
+ */
+static void kcm_reply_error(struct cli_ctx *cctx,
+ errno_t retcode,
+ struct kcm_repbuf *repbuf)
+{
+ errno_t ret;
+ krb5_error_code kerr;
+
+ DEBUG(SSSDBG_OP_FAILURE,
+ "KCM operation returs failure [%d]: %s\n",
+ retcode, sss_strerror(retcode));
+ kerr = sss2krb5_error(retcode);
+
+ ret = kcm_failbuf_construct(kerr, repbuf);
+ if (ret != EOK) {
+ /* If we can't construct the reply buffer, just terminate the client */
+ talloc_free(cctx);
+ return;
+ }
+
+ TEVENT_FD_WRITEABLE(cctx->cfde);
+}
+
+/**
+ * Request-reply dispatcher
+ */
+struct kcm_req_ctx {
+ /* client context owns per-client buffers including this one */
+ struct cli_ctx *cctx;
+
+ /* raw IO buffers */
+ struct kcm_reqbuf reqbuf;
+ struct kcm_repbuf repbuf;
+
+ /* long-lived responder structures */
+ struct kcm_ctx *kctx;
+
+ struct kcm_op_io op_io;
};
+static errno_t kcm_recv_data(int fd, struct kcm_reqbuf *reqbuf)
+{
+ errno_t ret;
+
+ ret = kcm_read_iovec(fd, &reqbuf->v_len);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ ret = kcm_read_iovec(fd, &reqbuf->v_msg);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ return EOK;
+}
+
+static struct kcm_req_ctx *kcm_new_req(TALLOC_CTX *mem_ctx,
+ struct cli_ctx *cctx,
+ struct kcm_ctx *kctx)
+{
+ struct kcm_req_ctx *req;
+
+ req = talloc_zero(cctx, struct kcm_req_ctx);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ req->reqbuf.v_len.kiov_base = req->reqbuf.lenbuf;
+ req->reqbuf.v_len.kiov_len = KCM_MSG_LEN_SIZE;
+
+ req->reqbuf.v_msg.kiov_base = req->reqbuf.msgbuf;
+ req->reqbuf.v_msg.kiov_len = KCM_PACKET_MAX_SIZE;
+
+ req->repbuf.v_len.kiov_base = req->repbuf.lenbuf;
+ req->repbuf.v_len.kiov_len = KCM_MSG_LEN_SIZE;
+
+ req->repbuf.v_rc.kiov_base = req->repbuf.rcbuf;
+ req->repbuf.v_rc.kiov_len = KCM_RETCODE_SIZE;
+
+ req->repbuf.v_msg.kiov_base = req->repbuf.msgbuf;
+ /* Length of the msg iobuf will be adjusted later, so far use the full
+ * length so that constructing the reply can use that capacity
+ */
+ req->repbuf.v_msg.kiov_len = KCM_PACKET_MAX_SIZE;
+
+ req->cctx = cctx;
+ req->kctx = kctx;
+
+ return req;
+}
+
+static void kcm_recv(struct cli_ctx *cctx)
+{
+ struct kcm_req_ctx *req;
+ struct kcm_ctx *kctx;
+ int ret;
+
+ kctx = talloc_get_type(cctx->rctx->pvt_ctx, struct kcm_ctx);
+ req = talloc_get_type(cctx->state_ctx, struct kcm_req_ctx);
+ if (req == NULL) {
+ /* A new request comes in, setup data structures */
+ req = kcm_new_req(cctx, cctx, kctx);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Cannot set up client connection\n");
+ talloc_free(cctx);
+ return;
+ }
+
+ cctx->state_ctx = req;
+ }
+
+ ret = kcm_recv_data(cctx->cfd, &req->reqbuf);
+ switch (ret) {
+ case ENODATA:
+ DEBUG(SSSDBG_TRACE_ALL, "Client closed connection.\n");
+ talloc_free(cctx);
+ return;
+ case EAGAIN:
+ DEBUG(SSSDBG_TRACE_ALL, "Retry later\n");
+ return;
+ case EOK:
+ /* all fine */
+ break;
+ default:
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Failed to receive data (%d, %s), aborting client\n",
+ ret, sss_strerror(ret));
+ talloc_free(cctx);
+ return;
+ }
+
+ ret = kcm_input_parse(&req->reqbuf, &req->op_io);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Failed to parse data (%d, %s), aborting client\n",
+ ret, sss_strerror(ret));
+ goto fail;
+ }
+
+ /* do not read anymore, client is done sending */
+ TEVENT_FD_NOT_READABLE(cctx->cfde);
+
+ kcm_reply_error(cctx, ret, &req->repbuf);
+ return;
+
+fail:
+ /* Fail with reply */
+ kcm_reply_error(cctx, ret, &req->repbuf);
+}
+
+static int kcm_send_data(struct cli_ctx *cctx)
+{
+ struct kcm_req_ctx *req;
+ errno_t ret;
+
+ req = talloc_get_type(cctx->state_ctx, struct kcm_req_ctx);
+
+ ret = kcm_write_iovec(cctx->cfd, &req->repbuf.v_len);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ ret = kcm_write_iovec(cctx->cfd, &req->repbuf.v_rc);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ ret = kcm_write_iovec(cctx->cfd, &req->repbuf.v_msg);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ return EOK;
+}
+
+static void kcm_send(struct cli_ctx *cctx)
+{
+ errno_t ret;
+
+ ret = kcm_send_data(cctx);
+ if (ret == EAGAIN) {
+ /* not all data was sent, loop again */
+ return;
+ } else if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Failed to send data, aborting client!\n");
+ talloc_free(cctx);
+ return;
+ }
+
+ /* ok all sent */
+ TEVENT_FD_NOT_WRITEABLE(cctx->cfde);
+ TEVENT_FD_READABLE(cctx->cfde);
+ talloc_zfree(cctx->state_ctx);
+ return;
+}
+
static void kcm_fd_handler(struct tevent_context *ev,
struct tevent_fd *fde,
uint16_t flags, void *ptr)
@@ -39,25 +455,54 @@ static void kcm_fd_handler(struct tevent_context *ev,
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
"Could not create idle timer for client. "
- "This connection may not auto-terminate\n");
+ "This connection may not auto-terminate\n");
/* Non-fatal, continue */
}
+
+ if (flags & TEVENT_FD_READ) {
+ kcm_recv(cctx);
+ return;
+ }
+ if (flags & TEVENT_FD_WRITE) {
+ kcm_send(cctx);
+ return;
+ }
}
int kcm_connection_setup(struct cli_ctx *cctx)
{
- struct kcm_proto_ctx *protocol_ctx;
-
- protocol_ctx = talloc_zero(cctx, struct kcm_proto_ctx);
- if (protocol_ctx == NULL) {
- return ENOMEM;
- }
-
- cctx->protocol_ctx = protocol_ctx;
cctx->cfd_handler = kcm_fd_handler;
return EOK;
}
+krb5_error_code sss2krb5_error(errno_t err)
+{
+ switch (err) {
+ case EOK:
+ return 0;
+ case ENOMEM:
+ return KRB5_CC_NOMEM;
+ case EACCES:
+ return KRB5_FCC_PERM;
+ case ERR_KCM_OP_NOT_IMPLEMENTED:
+ return KRB5_CC_NOSUPP;
+ case ERR_WRONG_NAME_FORMAT:
+ return KRB5_CC_BADNAME;
+ case ERR_NO_MATCHING_CREDS:
+ return KRB5_FCC_NOFILE;
+ case ERR_NO_CREDS:
+ return KRB5_CC_NOTFOUND;
+ case ERR_KCM_CC_END:
+ return KRB5_CC_END;
+ case ERR_KCM_MALFORMED_IN_PKT:
+ case EINVAL:
+ case EIO:
+ return KRB5_CC_IO;
+ }
+
+ return KRB5_FCC_INTERNAL;
+}
+
/* Dummy, not used here but required to link to other responder files */
struct cli_protocol_version *register_cli_protocol_version(void)
{
diff --git a/src/responder/kcm/kcmsrv_pvt.h b/src/responder/kcm/kcmsrv_pvt.h
index a7c9d062c17f09986d894064176c3a461d396ac0..fd1fd9fa32d59a323d465def68999f24f84e3923 100644
--- a/src/responder/kcm/kcmsrv_pvt.h
+++ b/src/responder/kcm/kcmsrv_pvt.h
@@ -27,13 +27,20 @@
#include <sys/types.h>
#include "responder/common/responder.h"
-/* KCM IO structure */
+/*
+ * KCM IO structure
+ *
+ * In theory we cold use sss_iobuf there, but since iobuf was
+ * made opaque, this allows it to allocate the structures on
+ * the stack in one go.
+ * */
struct kcm_data {
uint8_t *data;
size_t length;
};
-/* To avoid leaking the sssd-specific responder data to other
+/*
+ * To avoid leaking the sssd-specific responder data to other
* modules, the ccache databases and other KCM specific data
* are kept separately
*/
@@ -41,7 +48,8 @@ struct kcm_resp_ctx {
krb5_context k5c;
};
-/* responder context that contains both the responder data,
+/*
+ * responder context that contains both the responder data,
* like the ccaches and the sssd-specific stuff like the
* generic responder ctx
*/
@@ -55,4 +63,11 @@ struct kcm_ctx {
int kcm_connection_setup(struct cli_ctx *cctx);
+/*
+ * Internally in SSSD-KCM we use SSSD-internal error codes so that we
+ * can always the same sss_strerror() functions to format the errors
+ * nicely, but the client expects libkrb5 error codes.
+ */
+krb5_error_code sss2krb5_error(errno_t err);
+
#endif /* __KCMSRV_PVT_H__ */
--
2.12.2

File diff suppressed because it is too large Load Diff

View File

@ -1,907 +0,0 @@
From 70fe6e2bb398b8669ad1aebeaf0abcbffc307475 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Tue, 7 Mar 2017 13:49:43 +0100
Subject: [PATCH 27/97] KCM: Add a in-memory credential storage
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Implements a simple back end for the ccache module that lets the KCM
server store credentials directly in memory.
Reviewed-by: Michal Židek <mzidek@redhat.com>
Reviewed-by: Simo Sorce <simo@redhat.com>
---
Makefile.am | 1 +
src/responder/kcm/kcm.c | 13 +-
src/responder/kcm/kcmsrv_ccache.c | 2 +-
src/responder/kcm/kcmsrv_ccache_mem.c | 805 ++++++++++++++++++++++++++++++++++
4 files changed, 817 insertions(+), 4 deletions(-)
create mode 100644 src/responder/kcm/kcmsrv_ccache_mem.c
diff --git a/Makefile.am b/Makefile.am
index a2b9dc49e95fa2d025f5174d2902866fab180a78..5605c1a53c44fd9e83394e80b7f71828df1d39b6 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1492,6 +1492,7 @@ sssd_kcm_SOURCES = \
src/responder/kcm/kcm.c \
src/responder/kcm/kcmsrv_cmd.c \
src/responder/kcm/kcmsrv_ccache.c \
+ src/responder/kcm/kcmsrv_ccache_mem.c \
src/util/sss_sockets.c \
src/util/sss_krb5.c \
src/util/sss_iobuf.c \
diff --git a/src/responder/kcm/kcm.c b/src/responder/kcm/kcm.c
index 90a6999c5e39d48a1a2ea8168d171612a65077d5..2c12ef215ce3967df183e51c20590c5f439d278f 100644
--- a/src/responder/kcm/kcm.c
+++ b/src/responder/kcm/kcm.c
@@ -22,9 +22,9 @@
#include "config.h"
#include <popt.h>
-#include <krb5/krb5.h>
#include "responder/kcm/kcm.h"
+#include "responder/kcm/kcmsrv_ccache.h"
#include "responder/kcm/kcmsrv_pvt.h"
#include "responder/common/responder.h"
#include "util/util.h"
@@ -110,7 +110,8 @@ static int kcm_data_destructor(void *ptr)
return 0;
}
-static struct kcm_resp_ctx *kcm_data_setup(TALLOC_CTX *mem_ctx)
+static struct kcm_resp_ctx *kcm_data_setup(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev)
{
struct kcm_resp_ctx *kcm_data;
krb5_error_code kret;
@@ -121,6 +122,12 @@ static struct kcm_resp_ctx *kcm_data_setup(TALLOC_CTX *mem_ctx)
return NULL;
}
+ kcm_data->db = kcm_ccdb_init(kcm_data, ev, CCDB_BE_MEMORY);
+ if (kcm_data->db == NULL) {
+ talloc_free(kcm_data);
+ return NULL;
+ }
+
kret = krb5_init_context(&kcm_data->k5c);
if (kret != EOK) {
talloc_free(kcm_data);
@@ -169,7 +176,7 @@ static int kcm_process_init(TALLOC_CTX *mem_ctx,
goto fail;
}
- kctx->kcm_data = kcm_data_setup(kctx);
+ kctx->kcm_data = kcm_data_setup(kctx, ev);
if (kctx->kcm_data == NULL) {
DEBUG(SSSDBG_FATAL_FAILURE,
"fatal error initializing responder data\n");
diff --git a/src/responder/kcm/kcmsrv_ccache.c b/src/responder/kcm/kcmsrv_ccache.c
index 2c565b8378e3ec297faf655d3c48d7ab902713d3..2ae120269b0c62275ba2acdff6d6daa8b7077708 100644
--- a/src/responder/kcm/kcmsrv_ccache.c
+++ b/src/responder/kcm/kcmsrv_ccache.c
@@ -240,7 +240,7 @@ struct kcm_ccdb *kcm_ccdb_init(TALLOC_CTX *mem_ctx,
switch (cc_be) {
case CCDB_BE_MEMORY:
DEBUG(SSSDBG_FUNC_DATA, "KCM back end: memory\n");
- /* Not implemented yet */
+ ccdb->ops = &ccdb_mem_ops;
break;
case CCDB_BE_SECRETS:
DEBUG(SSSDBG_FUNC_DATA, "KCM back end: sssd-secrets\n");
diff --git a/src/responder/kcm/kcmsrv_ccache_mem.c b/src/responder/kcm/kcmsrv_ccache_mem.c
new file mode 100644
index 0000000000000000000000000000000000000000..1c4f3df8d3b35b0428a143d4b545562d9cc0e574
--- /dev/null
+++ b/src/responder/kcm/kcmsrv_ccache_mem.c
@@ -0,0 +1,805 @@
+/*
+ SSSD
+
+ KCM Server - ccache in-memory storage
+
+ Copyright (C) Red Hat, 2016
+
+ 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 "config.h"
+
+#include <talloc.h>
+#include <stdio.h>
+
+#include "util/util.h"
+#include "responder/kcm/kcmsrv_ccache_pvt.h"
+#include "responder/kcm/kcmsrv_ccache_be.h"
+
+struct ccdb_mem;
+
+/*
+ * The KCM memory database is just a double-linked list of kcm_ccache structures
+ */
+struct ccache_mem_wrap {
+ struct kcm_ccache *cc;
+ bool is_default;
+
+ struct ccache_mem_wrap *next;
+ struct ccache_mem_wrap *prev;
+
+ struct ccdb_mem *mem_be;
+};
+
+struct ccdb_mem {
+ /* Both ccaches and the next-id are kept in memory */
+ struct ccache_mem_wrap *head;
+ unsigned int nextid;
+};
+
+/* In order to provide a consistent interface, we need to let the caller
+ * of getbyXXX own the ccache, therefore the memory back end returns a shallow
+ * copy of the ccache
+ */
+static struct kcm_ccache *kcm_ccache_dup(TALLOC_CTX *mem_ctx,
+ struct kcm_ccache *in)
+{
+ struct kcm_ccache *out;
+
+ out = talloc_zero(mem_ctx, struct kcm_ccache);
+ if (out == NULL) {
+ return NULL;
+ }
+ memcpy(out, in, sizeof(struct kcm_ccache));
+
+ return out;
+}
+
+static struct ccache_mem_wrap *memdb_get_by_uuid(struct ccdb_mem *memdb,
+ struct cli_creds *client,
+ uuid_t uuid)
+{
+ uid_t uid;
+ struct ccache_mem_wrap *ccwrap = NULL;
+ struct ccache_mem_wrap *out = NULL;
+
+ uid = cli_creds_get_uid(client);
+
+ DLIST_FOR_EACH(ccwrap, memdb->head) {
+ if (ccwrap->cc == NULL) {
+ /* since KCM stores ccaches, better not crash.. */
+ DEBUG(SSSDBG_CRIT_FAILURE, "BUG: ccwrap contains NULL cc\n");
+ continue;
+ }
+
+ if (ccwrap->cc->owner.uid == uid) {
+ if (uuid_compare(uuid, ccwrap->cc->uuid) == 0) {
+ out = ccwrap;
+ break;
+ }
+ }
+ }
+
+ return out;
+}
+
+static struct ccache_mem_wrap *memdb_get_by_name(struct ccdb_mem *memdb,
+ struct cli_creds *client,
+ const char *name)
+{
+ uid_t uid;
+ struct ccache_mem_wrap *ccwrap = NULL;
+ struct ccache_mem_wrap *out = NULL;
+
+ uid = cli_creds_get_uid(client);
+
+ DLIST_FOR_EACH(ccwrap, memdb->head) {
+ if (ccwrap->cc == NULL) {
+ /* since KCM stores ccaches, better not crash.. */
+ DEBUG(SSSDBG_CRIT_FAILURE, "BUG: ccwrap contains NULL cc\n");
+ continue;
+ }
+
+ if (ccwrap->cc->owner.uid == uid) {
+ if (strcmp(ccwrap->cc->name, name) == 0) {
+ out = ccwrap;
+ break;
+ }
+ }
+ }
+
+ return out;
+}
+
+/* Since with the in-memory database, the database operations are just
+ * fake-async wrappers around otherwise sync operations, we don't often
+ * need any state, so we use this empty structure instead
+ */
+struct ccdb_mem_dummy_state {
+};
+
+static int ccwrap_destructor(void *ptr)
+{
+ struct ccache_mem_wrap *ccwrap = talloc_get_type(ptr, struct ccache_mem_wrap);
+
+ if (ccwrap == NULL) {
+ return 0;
+ }
+
+ if (ccwrap->cc != NULL) {
+ if (ccwrap->cc->creds) {
+ safezero(sss_iobuf_get_data(ccwrap->cc->creds->cred_blob),
+ sss_iobuf_get_size(ccwrap->cc->creds->cred_blob));
+ }
+ }
+
+
+ DLIST_REMOVE(ccwrap->mem_be->head, ccwrap);
+
+ return 0;
+}
+
+static errno_t ccdb_mem_init(struct kcm_ccdb *db)
+{
+ struct ccdb_mem *memdb = NULL;
+
+ memdb = talloc_zero(db, struct ccdb_mem);
+ if (memdb == NULL) {
+ return ENOMEM;
+ }
+ db->db_handle = memdb;
+
+ return EOK;
+}
+
+struct ccdb_mem_nextid_state {
+ unsigned int nextid;
+};
+
+static struct tevent_req *ccdb_mem_nextid_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct kcm_ccdb *db,
+ struct cli_creds *client)
+{
+ struct tevent_req *req = NULL;
+ struct ccdb_mem_nextid_state *state = NULL;
+ struct ccdb_mem *memdb = NULL;
+ errno_t ret;
+
+ req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_nextid_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ memdb = talloc_get_type(db->db_handle, struct ccdb_mem);
+ if (memdb == NULL) {
+ ret = EIO;
+ goto immediate;
+ }
+
+ state->nextid = memdb->nextid++;
+
+ ret = EOK;
+immediate:
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
+ }
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static errno_t ccdb_mem_nextid_recv(struct tevent_req *req,
+ unsigned int *_nextid)
+{
+ struct ccdb_mem_nextid_state *state = tevent_req_data(req,
+ struct ccdb_mem_nextid_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+ *_nextid = state->nextid;
+ return EOK;
+}
+
+struct ccdb_mem_list_state {
+ uuid_t *uuid_list;
+};
+
+static struct tevent_req *ccdb_mem_list_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct kcm_ccdb *db,
+ struct cli_creds *client)
+{
+ struct tevent_req *req = NULL;
+ struct ccache_mem_wrap *ccwrap = NULL;
+ struct ccdb_mem_list_state *state = NULL;
+ struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem);
+ size_t num_ccaches = 0;
+ size_t cc_index = 0;
+ errno_t ret;
+ uid_t uid;
+
+ req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_list_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ uid = cli_creds_get_uid(client);
+
+ DLIST_FOR_EACH(ccwrap, memdb->head) {
+ if (ccwrap->cc->owner.uid == uid) {
+ num_ccaches++;
+ }
+ }
+
+ state->uuid_list = talloc_zero_array(state, uuid_t, num_ccaches+1);
+ if (state->uuid_list == NULL) {
+ ret = ENOMEM;
+ goto immediate;
+ }
+
+ cc_index = 0;
+ DLIST_FOR_EACH(ccwrap, memdb->head) {
+ if (ccwrap->cc->owner.uid == uid) {
+ uuid_copy(state->uuid_list[cc_index], ccwrap->cc->uuid);
+ cc_index++;
+ }
+ }
+ uuid_clear(state->uuid_list[num_ccaches]);
+
+ ret = EOK;
+immediate:
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
+ }
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static errno_t ccdb_mem_list_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ uuid_t **_uuid_list)
+{
+ struct ccdb_mem_list_state *state = tevent_req_data(req,
+ struct ccdb_mem_list_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+ *_uuid_list = talloc_steal(mem_ctx, state->uuid_list);
+ return EOK;
+}
+
+static struct tevent_req *ccdb_mem_set_default_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct kcm_ccdb *db,
+ struct cli_creds *client,
+ uuid_t uuid)
+{
+ struct tevent_req *req = NULL;
+ struct ccdb_mem_dummy_state *state = NULL;
+ struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem);
+ struct ccache_mem_wrap *ccwrap = NULL;
+ uid_t uid = cli_creds_get_uid(client);
+
+ req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_dummy_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ /* Reset all ccache defaults first */
+ DLIST_FOR_EACH(ccwrap, memdb->head) {
+ if (ccwrap->cc == NULL) {
+ /* since KCM stores ccaches, better not crash.. */
+ DEBUG(SSSDBG_CRIT_FAILURE, "BUG: ccwrap contains NULL cc\n");
+ continue;
+ }
+
+ if (ccwrap->cc->owner.uid == uid) {
+ ccwrap->is_default = false;
+ }
+ }
+
+ /* Then set the default for the right ccache. This also allows to
+ * pass a null uuid to just reset the old ccache (for example after
+ * deleting the default
+ */
+ ccwrap = memdb_get_by_uuid(memdb, client, uuid);
+ if (ccwrap != NULL) {
+ ccwrap->is_default = true;
+ }
+
+ tevent_req_done(req);
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static errno_t ccdb_mem_set_default_recv(struct tevent_req *req)
+{
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+ return EOK;
+}
+
+struct ccdb_mem_get_default_state {
+ uuid_t dfl_uuid;
+};
+
+static struct tevent_req *ccdb_mem_get_default_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct kcm_ccdb *db,
+ struct cli_creds *client)
+{
+ struct tevent_req *req = NULL;
+ struct ccdb_mem_get_default_state *state = NULL;
+ struct ccache_mem_wrap *ccwrap = NULL;
+ struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem);
+ uid_t uid = cli_creds_get_uid(client);
+
+ req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_get_default_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+
+ /* Reset all ccache defaults first */
+ DLIST_FOR_EACH(ccwrap, memdb->head) {
+ if (ccwrap->cc == NULL) {
+ /* since KCM stores ccaches, better not crash.. */
+ DEBUG(SSSDBG_CRIT_FAILURE, "BUG: ccwrap contains NULL cc\n");
+ continue;
+ }
+
+ if (ccwrap->cc->owner.uid == uid && ccwrap->is_default == true) {
+ break;
+ }
+ }
+
+ if (ccwrap == NULL) {
+ DEBUG(SSSDBG_TRACE_FUNC,
+ "No ccache marked as default, returning null ccache\n");
+ uuid_clear(state->dfl_uuid);
+ } else {
+ uuid_copy(state->dfl_uuid, ccwrap->cc->uuid);
+ }
+
+ tevent_req_done(req);
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static errno_t ccdb_mem_get_default_recv(struct tevent_req *req,
+ uuid_t dfl)
+{
+ struct ccdb_mem_get_default_state *state = tevent_req_data(req,
+ struct ccdb_mem_get_default_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ uuid_copy(dfl, state->dfl_uuid);
+ return EOK;
+}
+
+struct ccdb_mem_getbyuuid_state {
+ struct kcm_ccache *cc;
+};
+
+static struct tevent_req *ccdb_mem_getbyuuid_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct kcm_ccdb *db,
+ struct cli_creds *client,
+ uuid_t uuid)
+{
+ struct tevent_req *req = NULL;
+ struct ccdb_mem_getbyuuid_state *state = NULL;
+ struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem);
+ struct ccache_mem_wrap *ccwrap = NULL;
+
+ req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_getbyuuid_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ ccwrap = memdb_get_by_uuid(memdb, client, uuid);
+ if (ccwrap != NULL) {
+ state->cc = kcm_ccache_dup(state, ccwrap->cc);
+ }
+
+ tevent_req_done(req);
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static errno_t ccdb_mem_getbyuuid_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct kcm_ccache **_cc)
+{
+ struct ccdb_mem_getbyuuid_state *state = tevent_req_data(req,
+ struct ccdb_mem_getbyuuid_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+ *_cc = talloc_steal(mem_ctx, state->cc);
+ return EOK;
+}
+
+struct ccdb_mem_getbyname_state {
+ struct kcm_ccache *cc;
+};
+
+static struct tevent_req *ccdb_mem_getbyname_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct kcm_ccdb *db,
+ struct cli_creds *client,
+ const char *name)
+{
+ struct tevent_req *req = NULL;
+ struct ccdb_mem_getbyname_state *state = NULL;
+ struct ccache_mem_wrap *ccwrap = NULL;
+ struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem);
+
+ req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_getbyname_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ ccwrap = memdb_get_by_name(memdb, client, name);
+ if (ccwrap != NULL) {
+ state->cc = kcm_ccache_dup(state, ccwrap->cc);
+ }
+
+ tevent_req_done(req);
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static errno_t ccdb_mem_getbyname_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct kcm_ccache **_cc)
+{
+ struct ccdb_mem_getbyname_state *state = tevent_req_data(req,
+ struct ccdb_mem_getbyname_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+ *_cc = talloc_steal(mem_ctx, state->cc);
+ return EOK;
+}
+
+struct ccdb_mem_name_by_uuid_state {
+ const char *name;
+};
+
+struct tevent_req *ccdb_mem_name_by_uuid_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct kcm_ccdb *db,
+ struct cli_creds *client,
+ uuid_t uuid)
+{
+ struct tevent_req *req = NULL;
+ struct ccdb_mem_name_by_uuid_state *state = NULL;
+ struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem);
+ struct ccache_mem_wrap *ccwrap = NULL;
+ errno_t ret;
+
+ req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_name_by_uuid_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ ccwrap = memdb_get_by_uuid(memdb, client, uuid);
+ if (ccwrap == NULL) {
+ ret = ERR_KCM_CC_END;
+ goto immediate;
+ }
+
+ state->name = talloc_strdup(state, ccwrap->cc->name);
+ if (state->name == NULL) {
+ ret = ENOMEM;
+ goto immediate;
+ }
+
+ ret = EOK;
+immediate:
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
+ }
+ tevent_req_post(req, ev);
+ return req;
+}
+
+errno_t ccdb_mem_name_by_uuid_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ const char **_name)
+{
+ struct ccdb_mem_name_by_uuid_state *state = tevent_req_data(req,
+ struct ccdb_mem_name_by_uuid_state);
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+ *_name = talloc_steal(mem_ctx, state->name);
+ return EOK;
+}
+
+struct ccdb_mem_uuid_by_name_state {
+ uuid_t uuid;
+};
+
+struct tevent_req *ccdb_mem_uuid_by_name_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct kcm_ccdb *db,
+ struct cli_creds *client,
+ const char *name)
+{
+ struct tevent_req *req = NULL;
+ struct ccdb_mem_uuid_by_name_state *state = NULL;
+ struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem);
+ struct ccache_mem_wrap *ccwrap = NULL;
+ errno_t ret;
+
+ req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_uuid_by_name_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ ccwrap = memdb_get_by_name(memdb, client, name);
+ if (ccwrap == NULL) {
+ ret = ERR_KCM_CC_END;
+ goto immediate;
+ }
+
+ uuid_copy(state->uuid, ccwrap->cc->uuid);
+
+ ret = EOK;
+immediate:
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
+ }
+ tevent_req_post(req, ev);
+ return req;
+}
+
+errno_t ccdb_mem_uuid_by_name_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ uuid_t _uuid)
+{
+ struct ccdb_mem_uuid_by_name_state *state = tevent_req_data(req,
+ struct ccdb_mem_uuid_by_name_state);
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+ uuid_copy(_uuid, state->uuid);
+ return EOK;
+}
+
+static struct tevent_req *ccdb_mem_create_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct kcm_ccdb *db,
+ struct cli_creds *client,
+ struct kcm_ccache *cc)
+{
+ struct tevent_req *req = NULL;
+ struct ccdb_mem_dummy_state *state = NULL;
+ struct ccache_mem_wrap *ccwrap;
+ struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem);
+ errno_t ret;
+
+ req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_dummy_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ ccwrap = talloc_zero(memdb, struct ccache_mem_wrap);
+ if (ccwrap == NULL) {
+ ret = ENOMEM;
+ goto immediate;
+ }
+ ccwrap->cc = cc;
+ ccwrap->mem_be = memdb;
+ talloc_steal(ccwrap, cc);
+
+ DLIST_ADD(memdb->head, ccwrap);
+ talloc_set_destructor((TALLOC_CTX *) ccwrap, ccwrap_destructor);
+
+ ret = EOK;
+immediate:
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
+ }
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static errno_t ccdb_mem_create_recv(struct tevent_req *req)
+{
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+ return EOK;
+}
+
+static struct tevent_req *ccdb_mem_mod_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct kcm_ccdb *db,
+ struct cli_creds *client,
+ uuid_t uuid,
+ struct kcm_mod_ctx *mod_cc)
+{
+ errno_t ret;
+ struct tevent_req *req = NULL;
+ struct ccdb_mem_dummy_state *state = NULL;
+ struct ccache_mem_wrap *ccwrap = NULL;
+ struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem);
+
+ req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_dummy_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ /* UUID is immutable, so search by that */
+ ccwrap = memdb_get_by_uuid(memdb, client, uuid);
+ if (ccwrap == NULL) {
+ ret = ERR_KCM_CC_END;
+ goto immediate;
+ }
+
+ kcm_mod_cc(ccwrap->cc, mod_cc);
+
+ ret = EOK;
+immediate:
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
+ }
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static errno_t ccdb_mem_mod_recv(struct tevent_req *req)
+{
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+ return EOK;
+}
+
+static struct tevent_req *ccdb_mem_store_cred_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct kcm_ccdb *db,
+ struct cli_creds *client,
+ uuid_t uuid,
+ struct sss_iobuf *cred_blob)
+{
+ struct tevent_req *req = NULL;
+ struct ccdb_mem_dummy_state *state = NULL;
+ struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem);
+ struct ccache_mem_wrap *ccwrap = NULL;
+ errno_t ret;
+
+ req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_dummy_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ ccwrap = memdb_get_by_uuid(memdb, client, uuid);
+ if (ccwrap == NULL) {
+ ret = ERR_KCM_CC_END;
+ goto immediate;
+ }
+
+ ret = kcm_cc_store_cred_blob(ccwrap->cc, cred_blob);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Cannot store credentials to ccache [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto immediate;
+ }
+
+ ret = EOK;
+immediate:
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
+ }
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static errno_t ccdb_mem_store_cred_recv(struct tevent_req *req)
+{
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+ return EOK;
+}
+
+static struct tevent_req *ccdb_mem_delete_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct kcm_ccdb *db,
+ struct cli_creds *client,
+ uuid_t uuid)
+{
+ struct tevent_req *req = NULL;
+ struct ccdb_mem_dummy_state *state = NULL;
+ struct ccache_mem_wrap *ccwrap;
+ struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem);
+ errno_t ret;
+
+ req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_dummy_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ ccwrap = memdb_get_by_uuid(memdb, client, uuid);
+ if (ccwrap == NULL) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "BUG: Attempting to free unknown ccache\n");
+ ret = ERR_KCM_CC_END;
+ goto immediate;
+ }
+
+ ret = EOK;
+ /* Destructor takes care of everything */
+ talloc_free(ccwrap);
+immediate:
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
+ }
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static errno_t ccdb_mem_delete_recv(struct tevent_req *req)
+{
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+ return EOK;
+}
+
+const struct kcm_ccdb_ops ccdb_mem_ops = {
+ .init = ccdb_mem_init,
+
+ .nextid_send = ccdb_mem_nextid_send,
+ .nextid_recv = ccdb_mem_nextid_recv,
+
+ .set_default_send = ccdb_mem_set_default_send,
+ .set_default_recv = ccdb_mem_set_default_recv,
+
+ .get_default_send = ccdb_mem_get_default_send,
+ .get_default_recv = ccdb_mem_get_default_recv,
+
+ .list_send = ccdb_mem_list_send,
+ .list_recv = ccdb_mem_list_recv,
+
+ .getbyname_send = ccdb_mem_getbyname_send,
+ .getbyname_recv = ccdb_mem_getbyname_recv,
+
+ .getbyuuid_send = ccdb_mem_getbyuuid_send,
+ .getbyuuid_recv = ccdb_mem_getbyuuid_recv,
+
+ .name_by_uuid_send = ccdb_mem_name_by_uuid_send,
+ .name_by_uuid_recv = ccdb_mem_name_by_uuid_recv,
+
+ .uuid_by_name_send = ccdb_mem_uuid_by_name_send,
+ .uuid_by_name_recv = ccdb_mem_uuid_by_name_recv,
+
+ .create_send = ccdb_mem_create_send,
+ .create_recv = ccdb_mem_create_recv,
+
+ .mod_send = ccdb_mem_mod_send,
+ .mod_recv = ccdb_mem_mod_recv,
+
+ .store_cred_send = ccdb_mem_store_cred_send,
+ .store_cred_recv = ccdb_mem_store_cred_recv,
+
+ .delete_send = ccdb_mem_delete_send,
+ .delete_recv = ccdb_mem_delete_recv,
+};
--
2.12.2

File diff suppressed because it is too large Load Diff

View File

@ -1,278 +0,0 @@
From ba89271f594e5ed381b4dcb876a2d2787cf51902 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Wed, 8 Mar 2017 17:46:09 +0100
Subject: [PATCH 29/97] MAN: Add a manual page for sssd-kcm
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Reviewed-by: Michal Židek <mzidek@redhat.com>
Reviewed-by: Simo Sorce <simo@redhat.com>
---
contrib/sssd.spec.in | 1 +
src/man/Makefile.am | 9 ++-
src/man/po/po4a.cfg | 1 +
src/man/sssd-kcm.8.xml | 193 +++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 203 insertions(+), 1 deletion(-)
create mode 100644 src/man/sssd-kcm.8.xml
diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in
index 52d33b4de281dc1d91a9027ac1c8c878e66fb396..1d4d020415ee28292bb4d88c78de205465d812f1 100644
--- a/contrib/sssd.spec.in
+++ b/contrib/sssd.spec.in
@@ -1206,6 +1206,7 @@ done
%config(noreplace) %{_sysconfdir}/krb5.conf.d/kcm_default_ccache
%{_unitdir}/sssd-kcm.socket
%{_unitdir}/sssd-kcm.service
+%{_mandir}/man8/sssd-kcm.8*
%endif
%pre common
diff --git a/src/man/Makefile.am b/src/man/Makefile.am
index 142d6e2743f814294e3d92c8342070b8230bb3e5..3a063614f085691652db32d76315375466e0d3de 100644
--- a/src/man/Makefile.am
+++ b/src/man/Makefile.am
@@ -27,6 +27,9 @@ endif
if BUILD_SECRETS
SEC_CONDS = ;with_secrets
endif
+if BUILD_SECRETS
+KCM_CONDS = ;with_kcm
+endif
if GPO_DEFAULT_ENFORCING
GPO_CONDS = ;gpo_default_enforcing
else
@@ -40,7 +43,7 @@ FILES_CONDS = ;enable_files_domain
else
FILES_CONDS = ;no_enable_files_domain
endif
-CONDS = with_false$(SUDO_CONDS)$(AUTOFS_CONDS)$(SSH_CONDS)$(PAC_RESPONDER_CONDS)$(IFP_CONDS)$(GPO_CONDS)$(SEC_CONDS)$(SYSTEMD_CONDS)$(FILES_CONDS)
+CONDS = with_false$(SUDO_CONDS)$(AUTOFS_CONDS)$(SSH_CONDS)$(PAC_RESPONDER_CONDS)$(IFP_CONDS)$(GPO_CONDS)$(SEC_CONDS)$(SYSTEMD_CONDS)$(FILES_CONDS)$(KCM_CONDS)
#Special Rules:
@@ -85,6 +88,10 @@ if BUILD_SECRETS
man_MANS += sssd-secrets.5
endif
+if BUILD_KCM
+man_MANS += sssd-kcm.8
+endif
+
if BUILD_NFS_IDMAP
man_MANS += sss_rpcidmapd.5
endif
diff --git a/src/man/po/po4a.cfg b/src/man/po/po4a.cfg
index d1f6ac39f841c61ae3d2393fb3402dc21b9cbd69..a02f97e777fa76615e4d5cbcfc788956706d8cd0 100644
--- a/src/man/po/po4a.cfg
+++ b/src/man/po/po4a.cfg
@@ -31,6 +31,7 @@
[type:docbook] sssctl.8.xml $lang:$(builddir)/$lang/sssctl.8.xml
[type:docbook] sssd-files.5.xml $lang:$(builddir)/$lang/sssd-files.5.xml
[type:docbook] sssd-secrets.5.xml $lang:$(builddir)/$lang/sssd-secrets.5.xml
+[type:docbook] sssd-kcm.8.xml $lang:$(builddir)/$lang/sssd-kcm.8.xml
[type:docbook] include/service_discovery.xml $lang:$(builddir)/$lang/include/service_discovery.xml opt:"-k 0"
[type:docbook] include/upstream.xml $lang:$(builddir)/$lang/include/upstream.xml opt:"-k 0"
[type:docbook] include/failover.xml $lang:$(builddir)/$lang/include/failover.xml opt:"-k 0"
diff --git a/src/man/sssd-kcm.8.xml b/src/man/sssd-kcm.8.xml
new file mode 100644
index 0000000000000000000000000000000000000000..5dc93838e48723bdb470c0a9c8575bd17c7593e8
--- /dev/null
+++ b/src/man/sssd-kcm.8.xml
@@ -0,0 +1,193 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE reference PUBLIC "-//OASIS//DTD DocBook V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
+<reference>
+<title>SSSD Manual pages</title>
+<refentry>
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="include/upstream.xml" />
+
+ <refmeta>
+ <refentrytitle>sssd-kcm</refentrytitle>
+ <manvolnum>8</manvolnum>
+ <refmiscinfo class="manual">File Formats and Conventions</refmiscinfo>
+ </refmeta>
+
+ <refnamediv id='name'>
+ <refname>sssd-kcm</refname>
+ <refpurpose>SSSD Kerberos Cache Manager</refpurpose>
+ </refnamediv>
+
+ <refsect1 id='description'>
+ <title>DESCRIPTION</title>
+ <para>
+ This manual page describes the configuration of the SSSD Kerberos
+ Cache Manager (KCM). KCM is a process that stores, tracks and
+ manages Kerberos credential caches. It originates in the Heimdal
+ Kerberos project, although the MIT Kerberos library also provides
+ client side (more details on that below) support for the KCM
+ credential cache.
+ </para>
+ <para>
+ In a setup where Kerberos caches are managed by KCM, the
+ Kerberos library (typically used through an application, like
+ e.g.,
+ <citerefentry>
+ <refentrytitle>kinit</refentrytitle><manvolnum>1</manvolnum>
+ </citerefentry>,
+ is a <quote>"KCM client"</quote> and the KCM daemon
+ is being referred to as a <quote>"KCM server"</quote>. The client
+ and server communicate over a UNIX socket.
+ </para>
+ <para>
+ The KCM server keeps track of each credential caches's owner and
+ performs access check control based on the UID and GID of the
+ KCM client. The root user has access to all credential caches.
+ </para>
+ <para>
+ The KCM credential cache has several interesting properties:
+ <itemizedlist>
+ <listitem>
+ <para>
+ since the process runs in userspace, it is subject to UID namespacing, ulike the kernel keyring
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ unlike the kernel keyring-based cache, which is shared between all containers, the KCM server is a separate process whose entry point is a UNIX socket
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ the SSSD implementation stores the ccaches in the SSSD
+ <citerefentry>
+ <refentrytitle>sssd-secrets</refentrytitle><manvolnum>5</manvolnum>
+ </citerefentry>
+ secrets store, allowing the ccaches to survive KCM server restarts or machine reboots.
+ </para>
+ </listitem>
+ </itemizedlist>
+ This allows the system to use a collection-aware credential
+ cache, yet share the credential cache between some or no
+ containers by bind-mounting the socket.
+ </para>
+ </refsect1>
+
+ <refsect1 id='usage'>
+ <title>USING THE KCM CREDENTIAL CACHE</title>
+ <para>
+ In order to use KCM credential cache, it must be selected as the default
+ credential type in
+ <citerefentry>
+ <refentrytitle>krb5.conf</refentrytitle><manvolnum>5</manvolnum>
+ </citerefentry>,
+ The credentials cache name must be only <quote>KCM:</quote>
+ without any template expansions. For example:
+ <programlisting>
+[libdefaults]
+ default_ccache_name = KCM:
+ </programlisting>
+ </para>
+ <para>
+ Next, make sure the Kerberos client libraries and the KCM server must agree
+ on the UNIX socket path. By default, both use the same path
+ <replaceable>/var/run/.heim_org.h5l.kcm-socket</replaceable>. To configure
+ the Kerberos library, change its <quote>kcm_socket</quote> option which
+ is described in the
+ <citerefentry>
+ <refentrytitle>krb5.conf</refentrytitle><manvolnum>5</manvolnum>
+ </citerefentry>
+ manual page.
+ </para>
+ <para>
+ Finally, make sure the SSSD KCM server can be contacted.
+ The KCM service is typically socket-activated by
+ <citerefentry>
+ <refentrytitle>systemd</refentrytitle>
+ <manvolnum>1</manvolnum>
+ </citerefentry>.
+ Unlike
+ other SSSD services, it cannot be started by adding the
+ <quote>kcm</quote> string to the <quote>service</quote>
+ directive.
+ <programlisting>
+systemctl start sssd-kcm.socket
+systemctl enable sssd-kcm.socket
+systemctl enable sssd-kcm.service
+ </programlisting>
+ Please note your distribution may already configure the units
+ for you.
+ </para>
+ </refsect1>
+
+ <refsect1 id='storage'>
+ <title>THE CREDENTIAL CACHE STORAGE</title>
+ <para>
+ The credential caches are stored in the SSSD secrets service (see
+ <citerefentry>
+ <refentrytitle>sssd-secrets</refentrytitle><manvolnum>5</manvolnum>
+ </citerefentry>
+ for more details). Therefore it is important that also the sssd-secrets
+ service is enabled and its socket is started:
+ <programlisting>
+systemctl start sssd-secrets.socket
+systemctl enable sssd-secrets.socket
+systemctl enable sssd-secrets.service
+ </programlisting>
+ Your distribution should already set the dependencies between the services.
+ </para>
+ </refsect1>
+
+ <refsect1 id='options'>
+ <title>CONFIGURATION OPTIONS</title>
+ <para>
+ The KCM service is configured in the <quote>kcm</quote>
+ section of the sssd.conf file. Please note that currently,
+ is it not sufficient to restart the sssd-kcm service, because
+ the sssd configuration is only parsed and read to an internal
+ configuration database by the sssd service. Therefore you
+ must restart the sssd service if you change anything in the
+ <quote>kcm</quote> section of sssd.conf.
+ For a detailed syntax reference, refer to the <quote>FILE FORMAT</quote> section of the
+ <citerefentry>
+ <refentrytitle>sssd.conf</refentrytitle>
+ <manvolnum>5</manvolnum>
+ </citerefentry> manual page.
+ </para>
+ <para>
+ The generic SSSD service options such as
+ <quote>debug_level</quote> or <quote>fd_limit</quote> are
+ accepted by the kcm service. Please refer to the
+ <citerefentry>
+ <refentrytitle>sssd.conf</refentrytitle>
+ <manvolnum>5</manvolnum>
+ </citerefentry> manual page for a complete list. In addition,
+ there are some KCM-specific options as well.
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>socket_path (string)</term>
+ <listitem>
+ <para>
+ The socket the KCM service will listen on.
+ </para>
+ <para>
+ Default: <replaceable>/var/run/.heim_org.h5l.kcm-socket</replaceable>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1 id='see_also'>
+ <title>SEE ALSO</title>
+ <para>
+ <citerefentry>
+ <refentrytitle>sssd</refentrytitle><manvolnum>8</manvolnum>
+ </citerefentry>,
+ <citerefentry>
+ <refentrytitle>sssd.conf</refentrytitle><manvolnum>5</manvolnum>
+ </citerefentry>,
+ </para>
+ </refsect1>
+</refentry>
+</reference>
--
2.12.2

View File

@ -1,799 +0,0 @@
From 0700118d8388c38b8cb28279510b206b76a3a411 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Tue, 13 Dec 2016 17:17:16 +0100
Subject: [PATCH 30/97] TESTS: Add integration tests for the KCM responder
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Reviewed-by: Michal Židek <mzidek@redhat.com>
Reviewed-by: Simo Sorce <simo@redhat.com>
Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
---
contrib/ci/configure.sh | 7 +
contrib/ci/deps.sh | 6 +
src/tests/intg/Makefile.am | 4 +
src/tests/intg/kdc.py | 175 +++++++++++++++++++++
src/tests/intg/krb5utils.py | 156 +++++++++++++++++++
src/tests/intg/test_kcm.py | 361 ++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 709 insertions(+)
create mode 100644 src/tests/intg/kdc.py
create mode 100644 src/tests/intg/krb5utils.py
create mode 100644 src/tests/intg/test_kcm.py
diff --git a/contrib/ci/configure.sh b/contrib/ci/configure.sh
index 8e779cfe634a7555e0e8e3b52f42c07e62980fbc..7590743c2aa5fe31bcdf1a3e92a3f482dbec699b 100644
--- a/contrib/ci/configure.sh
+++ b/contrib/ci/configure.sh
@@ -38,6 +38,13 @@ if [[ "$DISTRO_BRANCH" == -redhat-redhatenterprise*-6.*- ||
"--disable-cifs-idmap-plugin"
"--with-syslog=syslog"
"--without-python3-bindings"
+ "--without-kcm"
+ )
+fi
+
+if [[ "$DISTRO_BRANCH" == -redhat-fedora-2[0-2]* ]]; then
+ CONFIGURE_ARG_LIST+=(
+ "--without-kcm"
)
fi
diff --git a/contrib/ci/deps.sh b/contrib/ci/deps.sh
index c525e62e8c1d5b9fa042dee4ad03790dbceba242..4467e117c3a896a7f01ef7cb9e94fe28c2ea2838 100644
--- a/contrib/ci/deps.sh
+++ b/contrib/ci/deps.sh
@@ -47,6 +47,8 @@ if [[ "$DISTRO_BRANCH" == -redhat-* ]]; then
uid_wrapper
python-requests
curl-devel
+ krb5-server
+ krb5-workstation
)
_DEPS_LIST_SPEC=`
sed -e 's/@PACKAGE_VERSION@/0/g' \
@@ -122,6 +124,10 @@ if [[ "$DISTRO_BRANCH" == -debian-* ]]; then
libhttp-parser-dev
libjansson-dev
libcurl4-openssl-dev
+ krb5-kdc
+ krb5-admin-server
+ krb5-user
+ uuid-dev
)
DEPS_INTGCHECK_SATISFIED=true
fi
diff --git a/src/tests/intg/Makefile.am b/src/tests/intg/Makefile.am
index 1d36fa0d2d50307fbc871f5b2a6f0cb1cc95db81..8526beace09b15c99aa27ac98d5038d1980f6a71 100644
--- a/src/tests/intg/Makefile.am
+++ b/src/tests/intg/Makefile.am
@@ -26,6 +26,9 @@ dist_noinst_DATA = \
files_ops.py \
test_files_ops.py \
test_files_provider.py \
+ kdc.py \
+ krb5utils.py \
+ test_kcm.py \
$(NULL)
config.py: config.py.m4
@@ -80,5 +83,6 @@ intgcheck-installed: config.py passwd group
NSS_WRAPPER_MODULE_FN_PREFIX="sss" \
UID_WRAPPER=1 \
UID_WRAPPER_ROOT=1 \
+ NON_WRAPPED_UID=$$(echo $$UID) \
fakeroot $(PYTHON2) $(PYTEST) -v --tb=native $(INTGCHECK_PYTEST_ARGS) .
rm -f $(DESTDIR)$(logpath)/*
diff --git a/src/tests/intg/kdc.py b/src/tests/intg/kdc.py
new file mode 100644
index 0000000000000000000000000000000000000000..dec33a979916c0979561afb22dc39d6eb8894ff3
--- /dev/null
+++ b/src/tests/intg/kdc.py
@@ -0,0 +1,175 @@
+#
+# MIT Kerberos server class
+#
+# Copyright (c) 2016 Red Hat, Inc.
+#
+# This 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; version 2 only
+#
+# 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/>.
+#
+import os
+import signal
+import shutil
+import subprocess
+
+from util import *
+
+
+class KDC(object):
+ """
+ MIT Kerberos KDC instance
+ """
+
+ def __init__(self, basedir, realm,
+ includedir=None,
+ kdc_port=10088,
+ kadmin_port=10749,
+ master_key='master'):
+ self.basedir = basedir
+ self.realm = realm
+ self.kdc_port = kdc_port
+ self.kadmin_port = kadmin_port
+ self.master_key = master_key
+
+ self.kdc_basedir = self.basedir + "/var/krb5kdc"
+ self.includedir = includedir or (self.kdc_basedir + "/include")
+ self.kdc_logdir = self.kdc_basedir + "/log"
+ self.kdc_conf_path = self.kdc_basedir + "/kdc.conf"
+ self.krb5_conf_path = self.kdc_basedir + "/krb5.conf"
+
+ self.kdc_pid_file = self.kdc_basedir + "/kdc.pid"
+
+ self.acl_file = self.kdc_basedir + "/kadm5.acl"
+
+ self.admin_princ = "admin/admin@" + self.realm
+
+ def start_kdc(self, extra_args=[]):
+ args = ["krb5kdc", '-P', self.kdc_pid_file] + extra_args
+ return self._run_in_env(args, self.get_krb5_env())
+
+ def stop_kdc(self):
+ try:
+ with open(self.kdc_pid_file, "r") as pid_file:
+ os.kill(int(pid_file.read()), signal.SIGTERM)
+ except IOError as ioex:
+ if ioex.errno == 2:
+ pass
+ else:
+ raise ioex
+
+ def teardown(self):
+ self.stop_kdc()
+ shutil.rmtree(self.kdc_basedir)
+
+ def set_up(self):
+ self._create_config()
+ self._create_acl()
+ self._create_kdb()
+
+ def get_krb5_env(self):
+ my_env = os.environ
+ my_env['KRB5_CONFIG'] = self.krb5_conf_path
+ my_env['KRB5_KDC_PROFILE'] = self.kdc_conf_path
+ return my_env
+
+ def add_config(self, include_files):
+ for name, contents in include_files.items():
+ include_fpath = os.path.join(self.includedir, name)
+ with open(include_fpath, 'w') as include_file:
+ include_file.write(contents)
+
+ def add_principal(self, princ, password=None):
+ args = ["kadmin.local", "-q"]
+ if password is None:
+ args += ["addprinc -randkey %s" % (princ)]
+ else:
+ args += ["addprinc -pw %s %s" % (password, princ)]
+ return self._run_in_env(args, self.get_krb5_env())
+
+ def _run_in_env(self, args, env):
+ cmd = subprocess.Popen(args, env=env)
+ out, err = cmd.communicate()
+ return cmd.returncode, out, err
+
+ def _create_config(self):
+ try:
+ os.makedirs(self.kdc_basedir)
+ os.makedirs(self.kdc_logdir)
+ os.makedirs(self.includedir)
+ except OSError as osex:
+ if osex.errno == 17:
+ pass
+
+ kdc_conf = self._format_kdc_conf()
+ with open(self.kdc_conf_path, 'w') as kdc_conf_file:
+ kdc_conf_file.write(kdc_conf)
+
+ krb5_conf = self._format_krb5_conf()
+ with open(self.krb5_conf_path, 'w') as krb5_conf_file:
+ krb5_conf_file.write(krb5_conf)
+
+ def _create_acl(self):
+ with open(self.acl_file, 'w') as acl_fobject:
+ acl_fobject.write(self.admin_princ)
+
+ def _create_kdb(self):
+ self._run_in_env(
+ ['kdb5_util', 'create', '-W', '-s', '-P', self.master_key],
+ self.get_krb5_env()
+ )
+
+ def _format_kdc_conf(self):
+ database_path = self.kdc_basedir + "/principal"
+ key_stash = self.kdc_basedir + "/stash." + self.realm
+
+ kdc_logfile = "FILE:" + self.kdc_logdir + "/krb5kdc.log"
+ kadmin_logfile = "FILE:" + self.kdc_logdir + "/kadmin.log"
+ libkrb5_logfile = "FILE:" + self.kdc_logdir + "/libkrb5.log"
+
+ kdc_conf = unindent("""
+ [kdcdefaults]
+ kdc_ports = {self.kdc_port}
+ kdc_tcp_ports = {self.kdc_port}
+
+ [realms]
+ {self.realm} = {{
+ kadmind_port = {self.kadmin_port}
+ database_name = {database_path}
+ key_stash_file = {key_stash}
+ acl_file = {self.acl_file}
+ }}
+
+ [logging]
+ kdc = {kdc_logfile}
+ admin_server = {kadmin_logfile}
+ default = {libkrb5_logfile}
+ """).format(**locals())
+ return kdc_conf
+
+ def _format_krb5_conf(self):
+ kdc_uri = "localhost:%d" % self.kdc_port
+ kadmin_uri = "localhost:%d" % self.kadmin_port
+
+ krb5_conf = unindent("""
+ includedir {self.includedir}
+
+ [libdefaults]
+ default_realm = {self.realm}
+ dns_lookup_kdc = false
+ dns_lookup_realm = false
+
+ [realms]
+ {self.realm} = {{
+ kdc = {kdc_uri}
+ admin_server = {kadmin_uri}
+ }}
+ """).format(**locals())
+ return krb5_conf
diff --git a/src/tests/intg/krb5utils.py b/src/tests/intg/krb5utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..775cffd0bbfa011f2d8ffc1169dccfef96d78fab
--- /dev/null
+++ b/src/tests/intg/krb5utils.py
@@ -0,0 +1,156 @@
+#
+# MIT Kerberos server class
+#
+# Copyright (c) 2016 Red Hat, Inc.
+#
+# This 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; version 2 only
+#
+# 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/>.
+#
+import os
+import subprocess
+
+
+class NoPrincipals(Exception):
+ def __init__(self):
+ Exception.__init__(self, 'No principals in the collection')
+
+
+class PrincNotFound(Exception):
+ def __init__(self, principal):
+ Exception.__init__(self, 'Principal %s not found' % principal)
+
+
+class Krb5Utils(object):
+ """
+ Helper class to test Kerberos command line utilities
+ """
+ def __init__(self, krb5_conf_path):
+ self.krb5_conf_path = krb5_conf_path
+
+ def _run_in_env(self, args, stdin=None, extra_env=None):
+ my_env = os.environ
+ my_env['KRB5_CONFIG'] = self.krb5_conf_path
+
+ if 'KRB5CCNAME' in my_env:
+ del my_env['KRB5CCNAME']
+ if extra_env is not None:
+ my_env.update(extra_env)
+
+ cmd = subprocess.Popen(args,
+ env=my_env,
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ out, err = cmd.communicate(stdin)
+ return cmd.returncode, out.decode('utf-8'), err.decode('utf-8')
+
+ def kinit(self, principal, password, env=None):
+ args = ["kinit", principal]
+ return self._run_in_env(args, password.encode('utf-8'), env)
+
+ def kvno(self, principal, env=None):
+ args = ["kvno", principal]
+ return self._run_in_env(args, env)
+
+ def kdestroy(self, all_ccaches=False, env=None):
+ args = ["kdestroy"]
+ if all_ccaches is True:
+ args += ["-A"]
+ retval, _, _ = self._run_in_env(args, env)
+ return retval
+
+ def kswitch(self, principal, env=None):
+ args = ["kswitch", '-p', principal]
+ retval, _, _ = self._run_in_env(args, env)
+ return retval
+
+ def _check_klist_l(self, line, exp_principal, exp_cache):
+ try:
+ princ, cache = line.split()
+ except ValueError:
+ return False
+
+ if exp_cache is not None and cache != exp_cache:
+ return False
+
+ if exp_principal != princ:
+ return False
+
+ return True
+
+ def num_princs(self, env=None):
+ args = ["klist", "-l"]
+ retval, out, err = self._run_in_env(args, extra_env=env)
+ if retval != 0:
+ return 0
+
+ outlines = [l for l in out.split('\n') if len(l) > 1]
+ return len(outlines) - 2
+
+ def list_princs(self, env=None):
+ args = ["klist", "-l"]
+ retval, out, err = self._run_in_env(args, extra_env=env)
+ if retval == 1:
+ raise NoPrincipals
+ elif retval != 0:
+ raise Exception("klist failed: %d: %s\n", retval, err)
+
+ outlines = out.split('\n')
+ if len(outlines) < 2:
+ raise Exception("Not enough output from klist -l")
+
+ return [l for l in outlines[2:] if len(l) > 0]
+
+ def has_principal(self, exp_principal, exp_cache=None, env=None):
+ try:
+ princlist = self.list_princs(env)
+ except NoPrincipals:
+ return False
+
+ for line in princlist:
+ matches = self._check_klist_l(line, exp_principal, exp_cache)
+ if matches is True:
+ return True
+
+ return False
+
+ def default_principal(self, env=None):
+ principals = self.list_princs(env)
+ return principals[0].split()[0]
+
+ def _parse_klist_a(self, out):
+ dflprinc = None
+ thisrealm = None
+ ccache_dict = dict()
+
+ for line in [l for l in out.split('\n') if len(l) > 0]:
+ if line.startswith("Default principal"):
+ dflprinc = line.split()[2]
+ thisrealm = '@' + dflprinc.split('@')[1]
+ elif thisrealm is not None and line.endswith(thisrealm):
+ svc = line.split()[-1]
+ if dflprinc in ccache_dict:
+ ccache_dict[dflprinc].append(svc)
+ else:
+ ccache_dict[dflprinc] = [svc]
+
+ return ccache_dict
+
+ def list_all_princs(self, env=None):
+ args = ["klist", "-A"]
+ retval, out, err = self._run_in_env(args, extra_env=env)
+ if retval == 1:
+ raise NoPrincipals
+ elif retval != 0:
+ raise Exception("klist -A failed: %d: %s\n", retval, err)
+
+ return self._parse_klist_a(out)
diff --git a/src/tests/intg/test_kcm.py b/src/tests/intg/test_kcm.py
new file mode 100644
index 0000000000000000000000000000000000000000..ad1e4923bfe339cb040464757431d2ef3bf57ce1
--- /dev/null
+++ b/src/tests/intg/test_kcm.py
@@ -0,0 +1,361 @@
+#
+# KCM responder integration tests
+#
+# Copyright (c) 2016 Red Hat, Inc.
+#
+# This 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; version 2 only
+#
+# 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/>.
+#
+import os
+import os.path
+import stat
+import subprocess
+import pytest
+import socket
+import time
+import signal
+
+import kdc
+import krb5utils
+import config
+from util import unindent, run_shell
+
+class KcmTestEnv(object):
+ def __init__(self, k5kdc, k5util):
+ self.k5kdc = k5kdc
+ self.k5util = k5util
+ self.counter = 0
+
+ def my_uid(self):
+ s_myuid = os.environ['NON_WRAPPED_UID']
+ return int(s_myuid)
+
+ def ccname(self, my_uid=None):
+ if my_uid is None:
+ my_uid = self.my_uid()
+
+ return "KCM:%d" % my_uid
+
+
+@pytest.fixture(scope="module")
+def kdc_instance(request):
+ """Kerberos server instance fixture"""
+ kdc_instance = kdc.KDC(config.PREFIX, "KCMTEST")
+ try:
+ kdc_instance.set_up()
+ kdc_instance.start_kdc()
+ except:
+ kdc_instance.teardown()
+ raise
+ request.addfinalizer(kdc_instance.teardown)
+ return kdc_instance
+
+
+def create_conf_fixture(request, contents):
+ """Generate sssd.conf and add teardown for removing it"""
+ with open(config.CONF_PATH, "w") as conf:
+ conf.write(contents)
+ os.chmod(config.CONF_PATH, stat.S_IRUSR | stat.S_IWUSR)
+ request.addfinalizer(lambda: os.unlink(config.CONF_PATH))
+
+
+def create_sssd_kcm_fixture(sock_path, request):
+ if subprocess.call(['sssd', "--genconf"]) != 0:
+ raise Exception("failed to regenerate confdb")
+
+ resp_path = os.path.join(config.LIBEXEC_PATH, "sssd", "sssd_kcm")
+ if not os.access(resp_path, os.X_OK):
+ # It would be cleaner to use pytest.mark.skipif on the package level
+ # but upstream insists on supporting RHEL-6..
+ pytest.skip("No KCM responder, skipping")
+
+ kcm_pid = os.fork()
+ assert kcm_pid >= 0
+
+ if kcm_pid == 0:
+ if subprocess.call([resp_path, "--uid=0", "--gid=0"]) != 0:
+ print("sssd_kcm failed to start")
+ sys.exit(99)
+ else:
+ abs_sock_path = os.path.join(config.RUNSTATEDIR, sock_path)
+ sck = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ for _ in range(1, 10):
+ try:
+ sck.connect(abs_sock_path)
+ except:
+ time.sleep(0.1)
+ else:
+ break
+ sck.close()
+ assert os.path.exists(abs_sock_path)
+
+ def kcm_teardown():
+ if kcm_pid == 0:
+ return
+ os.kill(kcm_pid, signal.SIGTERM)
+
+ request.addfinalizer(kcm_teardown)
+ return kcm_pid
+
+
+@pytest.fixture
+def setup_for_kcm(request, kdc_instance):
+ """
+ Just set up the local provider for tests and enable the KCM
+ responder
+ """
+ kcm_path = os.path.join(config.RUNSTATEDIR, "kcm.socket")
+
+ sssd_conf = unindent("""\
+ [sssd]
+ domains = local
+ services = nss
+
+ [domain/local]
+ id_provider = local
+
+ [kcm]
+ socket_path = {kcm_path}
+ """).format(**locals())
+
+ kcm_socket_include = unindent("""
+ [libdefaults]
+ default_ccache_name = KCM:
+ kcm_socket = {kcm_path}
+ """).format(**locals())
+ kdc_instance.add_config({'kcm_socket': kcm_socket_include})
+
+ create_conf_fixture(request, sssd_conf)
+ create_sssd_kcm_fixture(kcm_path, request)
+
+ k5util = krb5utils.Krb5Utils(kdc_instance.krb5_conf_path)
+
+ return KcmTestEnv(kdc_instance, k5util)
+
+
+def test_kcm_init_list_destroy(setup_for_kcm):
+ """
+ Test that kinit, kdestroy and klist work with KCM
+ """
+ testenv = setup_for_kcm
+ testenv.k5kdc.add_principal("kcmtest", "Secret123")
+
+ ok = testenv.k5util.has_principal("kcmtest@KCMTEST")
+ assert ok is False
+ nprincs = testenv.k5util.num_princs()
+ assert nprincs == 0
+
+ out, _, _ = testenv.k5util.kinit("kcmtest", "Secret123")
+ assert out == 0
+ nprincs = testenv.k5util.num_princs()
+ assert nprincs == 1
+
+ exp_ccname = testenv.ccname()
+ ok = testenv.k5util.has_principal("kcmtest@KCMTEST", exp_ccname)
+ assert ok is True
+
+ out = testenv.k5util.kdestroy()
+ assert out == 0
+
+ ok = testenv.k5util.has_principal("kcmtest@KCMTEST")
+ assert ok is False
+ nprincs = testenv.k5util.num_princs()
+ assert nprincs == 0
+
+
+def test_kcm_overwrite(setup_for_kcm):
+ """
+ That that reusing a ccache reinitializes the cache and doesn't
+ add the same principal twice
+ """
+ testenv = setup_for_kcm
+ testenv.k5kdc.add_principal("kcmtest", "Secret123")
+ exp_ccache = {'kcmtest@KCMTEST': ['krbtgt/KCMTEST@KCMTEST']}
+
+ assert testenv.k5util.num_princs() == 0
+
+ out, _, _ = testenv.k5util.kinit("kcmtest", "Secret123")
+ assert out == 0
+ assert exp_ccache == testenv.k5util.list_all_princs()
+
+ out, _, _ = testenv.k5util.kinit("kcmtest", "Secret123")
+ assert out == 0
+ assert exp_ccache == testenv.k5util.list_all_princs()
+
+
+def test_collection_init_list_destroy(setup_for_kcm):
+ """
+ Test that multiple principals and service tickets can be stored
+ in a collection.
+ """
+ testenv = setup_for_kcm
+ testenv.k5kdc.add_principal("alice", "alicepw")
+ testenv.k5kdc.add_principal("bob", "bobpw")
+ testenv.k5kdc.add_principal("carol", "carolpw")
+ testenv.k5kdc.add_principal("host/somehostname")
+
+ assert testenv.k5util.num_princs() == 0
+
+ out, _, _ = testenv.k5util.kinit("alice", "alicepw")
+ assert out == 0
+ assert testenv.k5util.default_principal() == 'alice@KCMTEST'
+ cc_coll = testenv.k5util.list_all_princs()
+ assert len(cc_coll) == 1
+ assert cc_coll['alice@KCMTEST'] == ['krbtgt/KCMTEST@KCMTEST']
+ assert 'bob@KCMTEST' not in cc_coll
+ assert 'carol@KCMTEST' not in cc_coll
+
+ out, _, _ = testenv.k5util.kinit("bob", "bobpw")
+ assert out == 0
+ assert testenv.k5util.default_principal() == 'bob@KCMTEST'
+ cc_coll = testenv.k5util.list_all_princs()
+ assert len(cc_coll) == 2
+ assert cc_coll['alice@KCMTEST'] == ['krbtgt/KCMTEST@KCMTEST']
+ assert cc_coll['bob@KCMTEST'] == ['krbtgt/KCMTEST@KCMTEST']
+ assert 'carol@KCMTEST' not in cc_coll
+
+ out, _, _ = testenv.k5util.kinit("carol", "carolpw")
+ assert out == 0
+ assert testenv.k5util.default_principal() == 'carol@KCMTEST'
+ cc_coll = testenv.k5util.list_all_princs()
+ assert len(cc_coll) == 3
+ assert cc_coll['alice@KCMTEST'] == ['krbtgt/KCMTEST@KCMTEST']
+ assert cc_coll['bob@KCMTEST'] == ['krbtgt/KCMTEST@KCMTEST']
+ assert cc_coll['carol@KCMTEST'] == ['krbtgt/KCMTEST@KCMTEST']
+
+ out, _, _ = testenv.k5util.kvno('host/somehostname')
+ assert out == 0
+ cc_coll = testenv.k5util.list_all_princs()
+ assert len(cc_coll) == 3
+ assert set(cc_coll['carol@KCMTEST']) == set(['krbtgt/KCMTEST@KCMTEST',
+ 'host/somehostname@KCMTEST'])
+
+ out = testenv.k5util.kdestroy()
+ assert out == 0
+ assert testenv.k5util.default_principal() == 'bob@KCMTEST'
+ cc_coll = testenv.k5util.list_all_princs()
+ assert len(cc_coll) == 2
+ assert cc_coll['alice@KCMTEST'] == ['krbtgt/KCMTEST@KCMTEST']
+ assert cc_coll['bob@KCMTEST'] == ['krbtgt/KCMTEST@KCMTEST']
+ assert 'carol@KCMTEST' not in cc_coll
+
+ # FIXME - a bug in libkrb5?
+ #out = testenv.k5util.kdestroy(all_ccaches=True)
+ #assert out == 0
+ #cc_coll = testenv.k5util.list_all_princs()
+ #assert len(cc_coll) == 0
+
+
+def test_kswitch(setup_for_kcm):
+ """
+ Test switching between principals
+ """
+ testenv = setup_for_kcm
+ testenv.k5kdc.add_principal("alice", "alicepw")
+ testenv.k5kdc.add_principal("bob", "bobpw")
+ testenv.k5kdc.add_principal("host/somehostname")
+ testenv.k5kdc.add_principal("host/differenthostname")
+
+ out, _, _ = testenv.k5util.kinit("alice", "alicepw")
+ assert out == 0
+ assert testenv.k5util.default_principal() == 'alice@KCMTEST'
+
+ out, _, _ = testenv.k5util.kinit("bob", "bobpw")
+ assert out == 0
+ assert testenv.k5util.default_principal() == 'bob@KCMTEST'
+
+ cc_coll = testenv.k5util.list_all_princs()
+ assert len(cc_coll) == 2
+ assert cc_coll['alice@KCMTEST'] == ['krbtgt/KCMTEST@KCMTEST']
+ assert cc_coll['bob@KCMTEST'] == ['krbtgt/KCMTEST@KCMTEST']
+
+ out = testenv.k5util.kswitch("alice@KCMTEST")
+ assert testenv.k5util.default_principal() == 'alice@KCMTEST'
+ out, _, _ = testenv.k5util.kvno('host/somehostname')
+ assert out == 0
+ cc_coll = testenv.k5util.list_all_princs()
+ assert len(cc_coll) == 2
+ assert set(cc_coll['alice@KCMTEST']) == set(['krbtgt/KCMTEST@KCMTEST',
+ 'host/somehostname@KCMTEST'])
+ assert cc_coll['bob@KCMTEST'] == ['krbtgt/KCMTEST@KCMTEST']
+
+ out = testenv.k5util.kswitch("bob@KCMTEST")
+ assert testenv.k5util.default_principal() == 'bob@KCMTEST'
+ out, _, _ = testenv.k5util.kvno('host/differenthostname')
+ assert out == 0
+ cc_coll = testenv.k5util.list_all_princs()
+ assert len(cc_coll) == 2
+ assert set(cc_coll['alice@KCMTEST']) == set(['krbtgt/KCMTEST@KCMTEST',
+ 'host/somehostname@KCMTEST'])
+ assert set(cc_coll['bob@KCMTEST']) == set([
+ 'krbtgt/KCMTEST@KCMTEST',
+ 'host/differenthostname@KCMTEST'])
+
+
+def test_subsidiaries(setup_for_kcm):
+ """
+ Test that subsidiary caches are usable and KCM: without specifying UID
+ can be used to identify the collection
+ """
+ testenv = setup_for_kcm
+ testenv.k5kdc.add_principal("alice", "alicepw")
+ testenv.k5kdc.add_principal("bob", "bobpw")
+ testenv.k5kdc.add_principal("host/somehostname")
+ testenv.k5kdc.add_principal("host/differenthostname")
+
+ out, _, _ = testenv.k5util.kinit("alice", "alicepw")
+ assert out == 0
+ out, _, _ = testenv.k5util.kvno('host/somehostname')
+
+ out, _, _ = testenv.k5util.kinit("bob", "bobpw")
+ assert out == 0
+ out, _, _ = testenv.k5util.kvno('host/differenthostname')
+
+ exp_cc_coll = dict()
+ exp_cc_coll['alice@KCMTEST'] = 'host/somehostname@KCMTEST'
+ exp_cc_coll['bob@KCMTEST'] = 'host/differenthostname@KCMTEST'
+
+ klist_l = testenv.k5util.list_princs()
+ princ_ccache = dict()
+ for line in klist_l:
+ princ, subsidiary = line.split()
+ princ_ccache[princ] = subsidiary
+
+ for princ, subsidiary in princ_ccache.items():
+ env = {'KRB5CCNAME': subsidiary}
+ cc_coll = testenv.k5util.list_all_princs(env=env)
+ assert len(cc_coll) == 1
+ assert princ in cc_coll
+ assert exp_cc_coll[princ] in cc_coll[princ]
+
+ cc_coll = testenv.k5util.list_all_princs(env={'KRB5CCNAME': 'KCM:'})
+ assert len(cc_coll) == 2
+ assert set(cc_coll['alice@KCMTEST']) == set(['krbtgt/KCMTEST@KCMTEST',
+ 'host/somehostname@KCMTEST'])
+ assert set(cc_coll['bob@KCMTEST']) == set([
+ 'krbtgt/KCMTEST@KCMTEST',
+ 'host/differenthostname@KCMTEST'])
+
+
+def test_kdestroy_nocache(setup_for_kcm):
+ """
+ Destroying a non-existing ccache should not throw an error
+ """
+ testenv = setup_for_kcm
+ testenv.k5kdc.add_principal("alice", "alicepw")
+ out, _, _ = testenv.k5util.kinit("alice", "alicepw")
+ assert out == 0
+
+ testenv.k5util.kdestroy()
+ assert out == 0
+ out = testenv.k5util.kdestroy()
+ assert out == 0
--
2.12.2

View File

@ -1,405 +0,0 @@
From 8bb2fcbce7c3fcfd986f1bc835fbcc43ac7cd9d1 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Tue, 3 Jan 2017 16:00:38 +0100
Subject: [PATCH 31/97] SECRETS: Create DB path before the operation itself
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This is a refactoring where instead of creating the ldb path in the
operation itself, we create the ldb path when creating the local db request
and pass the path to the operation.
This would allow us to store different kind of objects in the secrets
storage later.
Reviewed-by: Michal Židek <mzidek@redhat.com>
Reviewed-by: Simo Sorce <simo@redhat.com>
---
src/responder/secrets/local.c | 170 +++++++++++++++++++++---------------------
1 file changed, 84 insertions(+), 86 deletions(-)
diff --git a/src/responder/secrets/local.c b/src/responder/secrets/local.c
index ed70193bcb27d84eaf449f6f7571c94f466c9896..9dcdd9925e542499d3a962b4998103b07c26a5ab 100644
--- a/src/responder/secrets/local.c
+++ b/src/responder/secrets/local.c
@@ -199,39 +199,36 @@ static char *local_dn_to_path(TALLOC_CTX *mem_ctx,
return path;
}
+struct local_db_req {
+ char *path;
+ struct ldb_dn *basedn;
+};
+
#define LOCAL_SIMPLE_FILTER "(type=simple)"
#define LOCAL_CONTAINER_FILTER "(type=container)"
static int local_db_get_simple(TALLOC_CTX *mem_ctx,
struct local_context *lctx,
- const char *req_path,
+ struct local_db_req *lc_req,
char **secret)
{
TALLOC_CTX *tmp_ctx;
static const char *attrs[] = { "secret", "enctype", NULL };
struct ldb_result *res;
- struct ldb_dn *dn;
const char *attr_secret;
const char *attr_enctype;
int ret;
- DEBUG(SSSDBG_TRACE_FUNC, "Retrieving a secret from [%s]\n", req_path);
+ DEBUG(SSSDBG_TRACE_FUNC, "Retrieving a secret from [%s]\n", lc_req->path);
tmp_ctx = talloc_new(mem_ctx);
if (!tmp_ctx) return ENOMEM;
- ret = local_db_dn(tmp_ctx, lctx->ldb, req_path, &dn);
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE,
- "local_db_dn failed [%d]: %s\n", ret, sss_strerror(ret));
- goto done;
- }
-
DEBUG(SSSDBG_TRACE_INTERNAL,
"Searching for [%s] at [%s] with scope=base\n",
- LOCAL_SIMPLE_FILTER, ldb_dn_get_linearized(dn));
+ LOCAL_SIMPLE_FILTER, ldb_dn_get_linearized(lc_req->basedn));
- ret = ldb_search(lctx->ldb, tmp_ctx, &res, dn, LDB_SCOPE_BASE,
+ ret = ldb_search(lctx->ldb, tmp_ctx, &res, lc_req->basedn, LDB_SCOPE_BASE,
attrs, "%s", LOCAL_SIMPLE_FILTER);
if (ret != EOK) {
DEBUG(SSSDBG_TRACE_LIBS,
@@ -278,34 +275,26 @@ done:
static int local_db_list_keys(TALLOC_CTX *mem_ctx,
struct local_context *lctx,
- const char *req_path,
+ struct local_db_req *lc_req,
char ***_keys,
int *num_keys)
{
TALLOC_CTX *tmp_ctx;
static const char *attrs[] = { "secret", NULL };
struct ldb_result *res;
- struct ldb_dn *dn;
char **keys;
int ret;
tmp_ctx = talloc_new(mem_ctx);
if (!tmp_ctx) return ENOMEM;
- DEBUG(SSSDBG_TRACE_FUNC, "Listing keys at [%s]\n", req_path);
-
- ret = local_db_dn(tmp_ctx, lctx->ldb, req_path, &dn);
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE,
- "local_db_dn failed [%d]: %s\n", ret, sss_strerror(ret));
- goto done;
- }
+ DEBUG(SSSDBG_TRACE_FUNC, "Listing keys at [%s]\n", lc_req->path);
DEBUG(SSSDBG_TRACE_INTERNAL,
"Searching for [%s] at [%s] with scope=subtree\n",
- LOCAL_SIMPLE_FILTER, ldb_dn_get_linearized(dn));
+ LOCAL_SIMPLE_FILTER, ldb_dn_get_linearized(lc_req->basedn));
- ret = ldb_search(lctx->ldb, tmp_ctx, &res, dn, LDB_SCOPE_SUBTREE,
+ ret = ldb_search(lctx->ldb, tmp_ctx, &res, lc_req->basedn, LDB_SCOPE_SUBTREE,
attrs, "%s", LOCAL_SIMPLE_FILTER);
if (ret != EOK) {
DEBUG(SSSDBG_TRACE_LIBS,
@@ -327,7 +316,7 @@ static int local_db_list_keys(TALLOC_CTX *mem_ctx,
}
for (unsigned i = 0; i < res->count; i++) {
- keys[i] = local_dn_to_path(keys, dn, res->msgs[i]->dn);
+ keys[i] = local_dn_to_path(keys, lc_req->basedn, res->msgs[i]->dn);
if (!keys[i]) {
ret = ENOMEM;
goto done;
@@ -474,7 +463,7 @@ static int local_check_max_payload_size(struct local_context *lctx,
static int local_db_put_simple(TALLOC_CTX *mem_ctx,
struct local_context *lctx,
- const char *req_path,
+ struct local_db_req *lc_req,
const char *secret)
{
struct ldb_message *msg;
@@ -482,20 +471,14 @@ static int local_db_put_simple(TALLOC_CTX *mem_ctx,
char *enc_secret;
int ret;
+ DEBUG(SSSDBG_TRACE_FUNC, "Adding a secret to [%s]\n", lc_req->path);
+
msg = ldb_msg_new(mem_ctx);
if (!msg) {
ret = ENOMEM;
goto done;
}
-
- DEBUG(SSSDBG_TRACE_FUNC, "Adding a secret to [%s]\n", req_path);
-
- ret = local_db_dn(msg, lctx->ldb, req_path, &msg->dn);
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE,
- "local_db_dn failed [%d]: %s\n", ret, sss_strerror(ret));
- goto done;
- }
+ msg->dn = lc_req->basedn;
/* make sure containers exist */
ret = local_db_check_containers(msg, lctx, msg->dn);
@@ -585,32 +568,24 @@ done:
static int local_db_delete(TALLOC_CTX *mem_ctx,
struct local_context *lctx,
- const char *req_path)
+ struct local_db_req *lc_req)
{
TALLOC_CTX *tmp_ctx;
- struct ldb_dn *dn;
static const char *attrs[] = { NULL };
struct ldb_result *res;
int ret;
- DEBUG(SSSDBG_TRACE_FUNC, "Removing a secret from [%s]\n", req_path);
+ DEBUG(SSSDBG_TRACE_FUNC, "Removing a secret from [%s]\n", lc_req->path);
tmp_ctx = talloc_new(mem_ctx);
if (!tmp_ctx) return ENOMEM;
- ret = local_db_dn(mem_ctx, lctx->ldb, req_path, &dn);
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE,
- "local_db_dn failed [%d]: %s\n", ret, sss_strerror(ret));
- goto done;
- }
-
DEBUG(SSSDBG_TRACE_INTERNAL,
"Searching for [%s] at [%s] with scope=base\n",
- LOCAL_CONTAINER_FILTER, ldb_dn_get_linearized(dn));
+ LOCAL_CONTAINER_FILTER, ldb_dn_get_linearized(lc_req->basedn));
- ret = ldb_search(lctx->ldb, tmp_ctx, &res, dn, LDB_SCOPE_BASE,
- attrs, LOCAL_CONTAINER_FILTER);
+ ret = ldb_search(lctx->ldb, tmp_ctx, &res, lc_req->basedn, LDB_SCOPE_BASE,
+ attrs, LOCAL_CONTAINER_FILTER);
if (ret != EOK) {
DEBUG(SSSDBG_TRACE_LIBS,
"ldb_search returned %d: %s\n", ret, ldb_strerror(ret));
@@ -619,8 +594,8 @@ static int local_db_delete(TALLOC_CTX *mem_ctx,
if (res->count == 1) {
DEBUG(SSSDBG_TRACE_INTERNAL,
- "Searching for children of [%s]\n", ldb_dn_get_linearized(dn));
- ret = ldb_search(lctx->ldb, tmp_ctx, &res, dn, LDB_SCOPE_ONELEVEL,
+ "Searching for children of [%s]\n", ldb_dn_get_linearized(lc_req->basedn));
+ ret = ldb_search(lctx->ldb, tmp_ctx, &res, lc_req->basedn, LDB_SCOPE_ONELEVEL,
attrs, NULL);
if (ret != EOK) {
DEBUG(SSSDBG_TRACE_LIBS,
@@ -632,13 +607,13 @@ static int local_db_delete(TALLOC_CTX *mem_ctx,
ret = EEXIST;
DEBUG(SSSDBG_OP_FAILURE,
"Failed to remove '%s': Container is not empty\n",
- ldb_dn_get_linearized(dn));
+ ldb_dn_get_linearized(lc_req->basedn));
goto done;
}
}
- ret = ldb_delete(lctx->ldb, dn);
+ ret = ldb_delete(lctx->ldb, lc_req->basedn);
if (ret != EOK) {
DEBUG(SSSDBG_TRACE_LIBS,
"ldb_delete returned %d: %s\n", ret, ldb_strerror(ret));
@@ -653,25 +628,19 @@ done:
static int local_db_create(TALLOC_CTX *mem_ctx,
struct local_context *lctx,
- const char *req_path)
+ struct local_db_req *lc_req)
{
struct ldb_message *msg;
int ret;
+ DEBUG(SSSDBG_TRACE_FUNC, "Creating a container at [%s]\n", lc_req->path);
+
msg = ldb_msg_new(mem_ctx);
if (!msg) {
ret = ENOMEM;
goto done;
}
-
- DEBUG(SSSDBG_TRACE_FUNC, "Creating a container at [%s]\n", req_path);
-
- ret = local_db_dn(msg, lctx->ldb, req_path, &msg->dn);
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE,
- "local_db_dn failed [%d]: %s\n", ret, sss_strerror(ret));
- goto done;
- }
+ msg->dn = lc_req->basedn;
/* make sure containers exist */
ret = local_db_check_containers(msg, lctx, msg->dn);
@@ -724,10 +693,13 @@ done:
}
static int local_secrets_map_path(TALLOC_CTX *mem_ctx,
+ struct ldb_context *ldb,
struct sec_req_ctx *secreq,
- char **local_db_path)
+ struct local_db_req **_lc_req)
{
int ret;
+ struct local_db_req *lc_req;
+ const char *basedn;
/* be strict for now */
if (secreq->parsed_url.fragment != NULL) {
@@ -755,20 +727,46 @@ static int local_secrets_map_path(TALLOC_CTX *mem_ctx,
}
}
- /* drop SEC_BASEPATH prefix */
- *local_db_path =
- talloc_strdup(mem_ctx, &secreq->mapped_path[sizeof(SEC_BASEPATH) - 1]);
- if (!*local_db_path) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- "Failed to map request to local db path\n");
+ lc_req = talloc(mem_ctx, struct local_db_req);
+ if (lc_req == NULL) {
return ENOMEM;
}
- DEBUG(SSSDBG_TRACE_LIBS, "Local DB path is %s\n", *local_db_path);
- return EOK;
+ /* drop the prefix and select a basedn instead */
+ if (strncmp(secreq->mapped_path,
+ SEC_BASEPATH, sizeof(SEC_BASEPATH) - 1) == 0) {
+ lc_req->path = talloc_strdup(lc_req,
+ secreq->mapped_path + (sizeof(SEC_BASEPATH) - 1));
+ basedn = SECRETS_BASEDN;
+ } else {
+ ret = EINVAL;
+ goto done;
+ }
+
+ if (lc_req->path == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to map request to local db path\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = local_db_dn(mem_ctx, ldb, basedn, lc_req->path, &lc_req->basedn);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to map request to local db DN\n");
+ goto done;
+ }
+
+ DEBUG(SSSDBG_TRACE_LIBS, "Local DB path is %s\n", lc_req->path);
+ ret = EOK;
+ *_lc_req = lc_req;
+done:
+ if (ret != EOK) {
+ talloc_free(lc_req);
+ }
+ return ret;
}
-
struct local_secret_state {
struct tevent_context *ev;
struct sec_req_ctx *secreq;
@@ -785,7 +783,7 @@ static struct tevent_req *local_secret_req(TALLOC_CTX *mem_ctx,
struct sec_data body = { 0 };
const char *content_type;
bool body_is_json;
- char *req_path;
+ struct local_db_req *lc_req;
char *secret;
char **keys;
int nkeys;
@@ -821,14 +819,14 @@ static struct tevent_req *local_secret_req(TALLOC_CTX *mem_ctx,
}
DEBUG(SSSDBG_TRACE_LIBS, "Content-Type: %s\n", content_type);
- ret = local_secrets_map_path(state, secreq, &req_path);
+ ret = local_secrets_map_path(state, lctx->ldb, secreq, &lc_req);
if (ret) goto done;
switch (secreq->method) {
case HTTP_GET:
- DEBUG(SSSDBG_TRACE_LIBS, "Processing HTTP GET at [%s]\n", req_path);
- if (req_path[strlen(req_path) - 1] == '/') {
- ret = local_db_list_keys(state, lctx, req_path, &keys, &nkeys);
+ DEBUG(SSSDBG_TRACE_LIBS, "Processing HTTP GET at [%s]\n", lc_req->path);
+ if (lc_req->path[strlen(lc_req->path) - 1] == '/') {
+ ret = local_db_list_keys(state, lctx, lc_req, &keys, &nkeys);
if (ret) goto done;
ret = sec_array_to_json(state, keys, nkeys, &body.data);
@@ -838,7 +836,7 @@ static struct tevent_req *local_secret_req(TALLOC_CTX *mem_ctx,
break;
}
- ret = local_db_get_simple(state, lctx, req_path, &secret);
+ ret = local_db_get_simple(state, lctx, lc_req, &secret);
if (ret) goto done;
if (body_is_json) {
@@ -855,7 +853,7 @@ static struct tevent_req *local_secret_req(TALLOC_CTX *mem_ctx,
break;
case HTTP_PUT:
- DEBUG(SSSDBG_TRACE_LIBS, "Processing HTTP PUT at [%s]\n", req_path);
+ DEBUG(SSSDBG_TRACE_LIBS, "Processing HTTP PUT at [%s]\n", lc_req->path);
if (body_is_json) {
ret = sec_json_to_simple_secret(state, secreq->body.data,
&secret);
@@ -866,27 +864,27 @@ static struct tevent_req *local_secret_req(TALLOC_CTX *mem_ctx,
}
if (ret) goto done;
- ret = local_db_put_simple(state, lctx, req_path, secret);
+ ret = local_db_put_simple(state, lctx, lc_req, secret);
if (ret) goto done;
break;
case HTTP_DELETE:
- ret = local_db_delete(state, lctx, req_path);
+ ret = local_db_delete(state, lctx, lc_req);
if (ret) goto done;
break;
case HTTP_POST:
- DEBUG(SSSDBG_TRACE_LIBS, "Processing HTTP POST at [%s]\n", req_path);
- plen = strlen(req_path);
+ DEBUG(SSSDBG_TRACE_LIBS, "Processing HTTP POST at [%s]\n", lc_req->path);
+ plen = strlen(lc_req->path);
- if (req_path[plen - 1] != '/') {
+ if (lc_req->path[plen - 1] != '/') {
ret = EINVAL;
goto done;
}
- req_path[plen - 1] = '\0';
+ lc_req->path[plen - 1] = '\0';
- ret = local_db_create(state, lctx, req_path);
+ ret = local_db_create(state, lctx, lc_req);
if (ret) goto done;
break;
--
2.12.2

View File

@ -1,40 +0,0 @@
From 73ce539aa70f43ccd5302b3ef8a02ff028558b12 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Fri, 3 Feb 2017 14:33:47 +0100
Subject: [PATCH 32/97] SECRETS: Return a nicer error message on request with
no PUT data
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
I managed to create this pathological situation with the tcurl tool
which didn't send any PUT data. The error in sssd-secrets was quite
strange (ENOMEM). This patch just adds a safeguard sooner so that we
return a graceful error.
Reviewed-by: Michal Židek <mzidek@redhat.com>
Reviewed-by: Simo Sorce <simo@redhat.com>
---
src/responder/secrets/local.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/responder/secrets/local.c b/src/responder/secrets/local.c
index 9dcdd9925e542499d3a962b4998103b07c26a5ab..26c97a2849febbf0ac482d526cf927bfc103b4f2 100644
--- a/src/responder/secrets/local.c
+++ b/src/responder/secrets/local.c
@@ -853,6 +853,12 @@ static struct tevent_req *local_secret_req(TALLOC_CTX *mem_ctx,
break;
case HTTP_PUT:
+ if (secreq->body.length == 0) {
+ DEBUG(SSSDBG_OP_FAILURE, "PUT with no data\n");
+ ret = EINVAL;
+ goto done;
+ }
+
DEBUG(SSSDBG_TRACE_LIBS, "Processing HTTP PUT at [%s]\n", lc_req->path);
if (body_is_json) {
ret = sec_json_to_simple_secret(state, secreq->body.data,
--
2.12.2

View File

@ -1,206 +0,0 @@
From 60612b5fbdaaa62ebe6c7f4c27200316f08506d6 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Tue, 21 Mar 2017 14:14:42 +0100
Subject: [PATCH 33/97] SECRETS: Store ccaches in secrets for the KCM responder
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Adds a new "hive" to the secrets responder whose base path is /kcm. Only
root can contact the /kcm hive, because the KCM responder only runs as
root and it must impersonate other users and store ccaches on their behalf.
Reviewed-by: Michal Židek <mzidek@redhat.com>
Reviewed-by: Simo Sorce <simo@redhat.com>
---
src/responder/secrets/local.c | 16 +++++++-
src/responder/secrets/providers.c | 71 ++++++++++++++++++++++++++++++----
src/responder/secrets/secsrv_private.h | 10 ++++-
3 files changed, 86 insertions(+), 11 deletions(-)
diff --git a/src/responder/secrets/local.c b/src/responder/secrets/local.c
index 26c97a2849febbf0ac482d526cf927bfc103b4f2..02007ada8b673071ecba033df0eb3f81af93fcbd 100644
--- a/src/responder/secrets/local.c
+++ b/src/responder/secrets/local.c
@@ -26,6 +26,9 @@
#define MKEY_SIZE (256 / 8)
+#define SECRETS_BASEDN "cn=secrets"
+#define KCM_BASEDN "cn=kcm"
+
struct local_context {
struct ldb_context *ldb;
struct sec_data master_key;
@@ -119,6 +122,7 @@ static int local_encrypt(struct local_context *lctx, TALLOC_CTX *mem_ctx,
static int local_db_dn(TALLOC_CTX *mem_ctx,
struct ldb_context *ldb,
+ const char *basedn,
const char *req_path,
struct ldb_dn **req_dn)
{
@@ -126,7 +130,7 @@ static int local_db_dn(TALLOC_CTX *mem_ctx,
const char *s, *e;
int ret;
- dn = ldb_dn_new(mem_ctx, ldb, "cn=secrets");
+ dn = ldb_dn_new(mem_ctx, ldb, basedn);
if (!dn) {
ret = ENOMEM;
goto done;
@@ -738,6 +742,11 @@ static int local_secrets_map_path(TALLOC_CTX *mem_ctx,
lc_req->path = talloc_strdup(lc_req,
secreq->mapped_path + (sizeof(SEC_BASEPATH) - 1));
basedn = SECRETS_BASEDN;
+ } else if (strncmp(secreq->mapped_path,
+ SEC_KCM_BASEPATH, sizeof(SEC_KCM_BASEPATH) - 1) == 0) {
+ lc_req->path = talloc_strdup(lc_req,
+ secreq->mapped_path + (sizeof(SEC_KCM_BASEPATH) - 1));
+ basedn = KCM_BASEDN;
} else {
ret = EINVAL;
goto done;
@@ -820,7 +829,10 @@ static struct tevent_req *local_secret_req(TALLOC_CTX *mem_ctx,
DEBUG(SSSDBG_TRACE_LIBS, "Content-Type: %s\n", content_type);
ret = local_secrets_map_path(state, lctx->ldb, secreq, &lc_req);
- if (ret) goto done;
+ if (ret) {
+ DEBUG(SSSDBG_OP_FAILURE, "Cannot map request path to local path\n");
+ goto done;
+ }
switch (secreq->method) {
case HTTP_GET:
diff --git a/src/responder/secrets/providers.c b/src/responder/secrets/providers.c
index eba555d2e422d08db211979422a2957e48b51589..94831c73036d269addca45c0117811a2c68873fd 100644
--- a/src/responder/secrets/providers.c
+++ b/src/responder/secrets/providers.c
@@ -24,6 +24,14 @@
#include "responder/secrets/secsrv_proxy.h"
#include <jansson.h>
+typedef int (*url_mapper_fn)(struct sec_req_ctx *secreq,
+ char **mapped_path);
+
+struct url_pfx_router {
+ const char *prefix;
+ url_mapper_fn mapper_fn;
+};
+
static int sec_map_url_to_user_path(struct sec_req_ctx *secreq,
char **mapped_path)
{
@@ -42,10 +50,43 @@ static int sec_map_url_to_user_path(struct sec_req_ctx *secreq,
return ENOMEM;
}
- DEBUG(SSSDBG_TRACE_LIBS, "User-specific path is [%s]\n", *mapped_path);
+ DEBUG(SSSDBG_TRACE_LIBS,
+ "User-specific secrets path is [%s]\n", *mapped_path);
return EOK;
}
+static int kcm_map_url_to_path(struct sec_req_ctx *secreq,
+ char **mapped_path)
+{
+ uid_t c_euid;
+
+ c_euid = client_euid(secreq->cctx->creds);
+ if (c_euid != KCM_PEER_UID) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "UID %"SPRIuid" is not allowed to access "
+ "the "SEC_KCM_BASEPATH" hive\n",
+ c_euid);
+ return EPERM;
+ }
+
+ *mapped_path = talloc_strdup(secreq, secreq->parsed_url.path );
+ if (!*mapped_path) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to map request to user specific url\n");
+ return ENOMEM;
+ }
+
+ DEBUG(SSSDBG_TRACE_LIBS,
+ "User-specific KCM path is [%s]\n", *mapped_path);
+ return EOK;
+}
+
+static struct url_pfx_router secrets_url_mapping[] = {
+ { SEC_BASEPATH, sec_map_url_to_user_path },
+ { SEC_KCM_BASEPATH, kcm_map_url_to_path },
+ { NULL, NULL },
+};
+
int sec_req_routing(TALLOC_CTX *mem_ctx, struct sec_req_ctx *secreq,
struct provider_handle **handle)
{
@@ -55,21 +96,35 @@ int sec_req_routing(TALLOC_CTX *mem_ctx, struct sec_req_ctx *secreq,
char *provider;
int num_sections;
int ret;
+ url_mapper_fn mapper_fn = NULL;
sctx = talloc_get_type(secreq->cctx->rctx->pvt_ctx, struct sec_ctx);
- /* patch must start with /secrets/ for now */
- ret = strncasecmp(secreq->parsed_url.path,
- SEC_BASEPATH, sizeof(SEC_BASEPATH) - 1);
- if (ret != 0) {
+ for (int i = 0; secrets_url_mapping[i].prefix != NULL; i++) {
+ if (strncasecmp(secreq->parsed_url.path,
+ secrets_url_mapping[i].prefix,
+ strlen(secrets_url_mapping[i].prefix)) == 0) {
+ DEBUG(SSSDBG_TRACE_LIBS,
+ "Mapping prefix %s\n", secrets_url_mapping[i].prefix);
+ mapper_fn = secrets_url_mapping[i].mapper_fn;
+ break;
+ }
+ }
+
+ if (mapper_fn == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE,
- "Path [%s] does not start with "SEC_BASEPATH"\n",
+ "Path [%s] does not start with any allowed prefix\n",
secreq->parsed_url.path);
return EPERM;
}
- ret = sec_map_url_to_user_path(secreq, &secreq->mapped_path);
- if (ret) return ret;
+ ret = mapper_fn(secreq, &secreq->mapped_path);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to map the user path [%d]: %s\n",
+ ret, sss_strerror(ret));
+ return ret;
+ }
/* source default provider */
ret = confdb_get_string(secreq->cctx->rctx->cdb, mem_ctx,
diff --git a/src/responder/secrets/secsrv_private.h b/src/responder/secrets/secsrv_private.h
index 1c3fbd8eadb237551233f048503ddc01b4ba00ae..a8544f656517a17fe4576247779bff4850beaf97 100644
--- a/src/responder/secrets/secsrv_private.h
+++ b/src/responder/secrets/secsrv_private.h
@@ -101,7 +101,15 @@ int sec_get_provider(struct sec_ctx *sctx, const char *name,
struct provider_handle **out_handle);
int sec_add_provider(struct sec_ctx *sctx, struct provider_handle *handle);
-#define SEC_BASEPATH "/secrets/"
+#define SEC_BASEPATH "/secrets/"
+#define SEC_KCM_BASEPATH "/kcm/"
+
+/* The KCM responder must "impersonate" the owner of the credentials.
+ * Only a trusted UID can do that -- root by default, but unit
+ * tests might choose otherwise */
+#ifndef KCM_PEER_UID
+#define KCM_PEER_UID 0
+#endif /* KCM_PEER_UID */
/* providers.c */
int sec_req_routing(TALLOC_CTX *mem_ctx, struct sec_req_ctx *secreq,
--
2.12.2

View File

@ -1,129 +0,0 @@
From c9db8b8b19827c3d492b8d2769aa77a37dbc12d3 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Tue, 14 Mar 2017 15:34:57 +0100
Subject: [PATCH 34/97] TCURL: Support HTTP POST for creating containers
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The curl integration must allow us to create containers, therefore we
also add support of the POST HTTP request type.
Reviewed-by: Michal Židek <mzidek@redhat.com>
Reviewed-by: Simo Sorce <simo@redhat.com>
---
src/tests/intg/test_secrets.py | 28 ++++++++++++++++++++++++++++
src/tests/tcurl_test_tool.c | 5 +++++
src/util/tev_curl.c | 7 +++++++
src/util/tev_curl.h | 1 +
4 files changed, 41 insertions(+)
diff --git a/src/tests/intg/test_secrets.py b/src/tests/intg/test_secrets.py
index cbc1a1f06d2abb826bc0a880cb5a842f577657ea..d71c1904558cc6f8a6eee36c4049582705bc30ac 100644
--- a/src/tests/intg/test_secrets.py
+++ b/src/tests/intg/test_secrets.py
@@ -271,6 +271,34 @@ def test_curlwrap_crd_ops(setup_for_secrets,
'http://localhost/secrets/foo'],
404)
+ # Create a container
+ run_curlwrap_tool([curlwrap_tool, '-o',
+ '-v', '-s', sock_path,
+ 'http://localhost/secrets/cont/'],
+ 200)
+
+ # set a secret foo:bar
+ run_curlwrap_tool([curlwrap_tool, '-p',
+ '-v', '-s', sock_path,
+ 'http://localhost/secrets/cont/cfoo',
+ 'foo_under_cont'],
+ 200)
+
+ # list secrets
+ output = run_curlwrap_tool([curlwrap_tool,
+ '-v', '-s', sock_path,
+ 'http://localhost/secrets/cont/'],
+ 200)
+ assert "cfoo" in output
+
+ # get the foo secret
+ output = run_curlwrap_tool([curlwrap_tool,
+ '-v', '-s', sock_path,
+ 'http://localhost/secrets/cont/cfoo'],
+ 200)
+ assert "foo_under_cont" in output
+
+
def test_curlwrap_parallel(setup_for_secrets,
curlwrap_tool):
diff --git a/src/tests/tcurl_test_tool.c b/src/tests/tcurl_test_tool.c
index 38cea432885c97ca3827c8f158bf7e3ebfc67b31..2af950ebb76a22bdf4a6dfd58442b10486e64293 100644
--- a/src/tests/tcurl_test_tool.c
+++ b/src/tests/tcurl_test_tool.c
@@ -88,6 +88,7 @@ int main(int argc, const char *argv[])
{ "get", 'g', POPT_ARG_NONE, NULL, 'g', "Perform a HTTP GET (default)", NULL },
{ "put", 'p', POPT_ARG_NONE, NULL, 'p', "Perform a HTTP PUT", NULL },
{ "del", 'd', POPT_ARG_NONE, NULL, 'd', "Perform a HTTP DELETE", NULL },
+ { "post", 'o', POPT_ARG_NONE, NULL, 'o', "Perform a HTTP POST", NULL },
{ "verbose", 'v', POPT_ARG_NONE, NULL, 'v', "Print response code and body", NULL },
POPT_TABLEEND
};
@@ -118,6 +119,9 @@ int main(int argc, const char *argv[])
case 'd':
req_type = TCURL_HTTP_DELETE;
break;
+ case 'o':
+ req_type = TCURL_HTTP_POST;
+ break;
case 'v':
pc_verbose = 1;
break;
@@ -145,6 +149,7 @@ int main(int argc, const char *argv[])
switch (req_type) {
case TCURL_HTTP_GET:
case TCURL_HTTP_DELETE:
+ case TCURL_HTTP_POST:
urls[n_reqs++] = extra_arg_ptr;
break;
case TCURL_HTTP_PUT:
diff --git a/src/util/tev_curl.c b/src/util/tev_curl.c
index fd436653b5aeb611a9648a8b81a330fd3fcfe875..645d1182d10f825f209f48e0ba7e6804dde1971c 100644
--- a/src/util/tev_curl.c
+++ b/src/util/tev_curl.c
@@ -154,6 +154,8 @@ static const char *http_req2str(enum tcurl_http_request req)
return "PUT";
case TCURL_HTTP_DELETE:
return "DELETE";
+ case TCURL_HTTP_POST:
+ return "POST";
}
return "Uknown request type";
@@ -815,6 +817,11 @@ static errno_t tcurl_set_options(struct tcurl_http_state *state,
}
switch (req_type) {
+ case TCURL_HTTP_POST:
+ crv = curl_easy_setopt(state->http_handle,
+ CURLOPT_CUSTOMREQUEST,
+ "POST");
+ break;
case TCURL_HTTP_PUT:
/* CURLOPT_UPLOAD enables HTTP_PUT */
crv = curl_easy_setopt(state->http_handle,
diff --git a/src/util/tev_curl.h b/src/util/tev_curl.h
index de0601df4327d97001a8a825cd4709936f6c8466..444eb286e09d189b4588e2b2152b5202df3914d8 100644
--- a/src/util/tev_curl.h
+++ b/src/util/tev_curl.h
@@ -34,6 +34,7 @@ enum tcurl_http_request {
TCURL_HTTP_GET,
TCURL_HTTP_PUT,
TCURL_HTTP_DELETE,
+ TCURL_HTTP_POST,
};
/**
--
2.12.2

File diff suppressed because it is too large Load Diff

View File

@ -1,219 +0,0 @@
From 35c9dfe9ba78d3a635cd1af0fb6349ba44344623 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Tue, 14 Mar 2017 11:17:05 +0100
Subject: [PATCH 36/97] KCM: Make the secrets ccache back end configurable,
make secrets the default
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Adds a new option 'ccache_storage' that allows to select either the
memory back end or the secrets back end. The secrets back end is the
default one and this option is even undocumented.
Reviewed-by: Michal Židek <mzidek@redhat.com>
Reviewed-by: Simo Sorce <simo@redhat.com>
---
src/confdb/confdb.h | 1 +
src/config/cfg_rules.ini | 1 +
src/responder/kcm/kcm.c | 49 ++++++++++++++++++++++++++++++++----
src/responder/kcm/kcmsrv_ccache.c | 2 +-
src/responder/kcm/kcmsrv_ccache.h | 6 +----
src/responder/kcm/kcmsrv_ccache_be.h | 1 +
src/responder/kcm/kcmsrv_pvt.h | 7 ++++++
7 files changed, 56 insertions(+), 11 deletions(-)
diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
index c443e869a7a6782265b42c4ad122867c4e3dd8e0..fb60675ca8beb2c2a157bf021ed9cad362742988 100644
--- a/src/confdb/confdb.h
+++ b/src/confdb/confdb.h
@@ -234,6 +234,7 @@
/* KCM Service */
#define CONFDB_KCM_CONF_ENTRY "config/kcm"
#define CONFDB_KCM_SOCKET "socket_path"
+#define CONFDB_KCM_DB "ccache_storage" /* Undocumented on purpose */
struct confdb_ctx;
struct config_file_ctx;
diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini
index 5e789c51658c51c0af1338d23d6c0f30f40bf119..67a5d1f5ad447a942b437ffd04a7f5d7cfe77d7f 100644
--- a/src/config/cfg_rules.ini
+++ b/src/config/cfg_rules.ini
@@ -280,6 +280,7 @@ option = fd_limit
option = client_idle_timeout
option = description
option = socket_path
+option = ccache_storage
[rule/allowed_domain_options]
validator = ini_allowed_options
diff --git a/src/responder/kcm/kcm.c b/src/responder/kcm/kcm.c
index 2c12ef215ce3967df183e51c20590c5f439d278f..063c27b915b4b92f6259496feee891aa94a498b6 100644
--- a/src/responder/kcm/kcm.c
+++ b/src/responder/kcm/kcm.c
@@ -47,6 +47,37 @@ static int kcm_responder_ctx_destructor(void *ptr)
return 0;
}
+static errno_t kcm_get_ccdb_be(struct kcm_ctx *kctx)
+{
+ errno_t ret;
+ char *str_db;
+
+ ret = confdb_get_string(kctx->rctx->cdb,
+ kctx->rctx,
+ kctx->rctx->confdb_service_path,
+ CONFDB_KCM_DB,
+ "secrets",
+ &str_db);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Cannot get the KCM database type [%d]: %s\n",
+ ret, strerror(ret));
+ return ret;
+ }
+
+ DEBUG(SSSDBG_CONF_SETTINGS, "KCM database type: %s\n", str_db);
+ if (strcasecmp(str_db, "memory") == 0) {
+ kctx->cc_be = CCDB_BE_MEMORY;
+ return EOK;
+ } else if (strcasecmp(str_db, "secrets") == 0) {
+ kctx->cc_be = CCDB_BE_SECRETS;
+ return EOK;
+ }
+
+ DEBUG(SSSDBG_FATAL_FAILURE, "Unexpected KCM database type %s\n", str_db);
+ return EOK;
+}
+
static int kcm_get_config(struct kcm_ctx *kctx)
{
int ret;
@@ -88,14 +119,21 @@ static int kcm_get_config(struct kcm_ctx *kctx)
&sock_name);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
- "Cannot get the client idle timeout [%d]: %s\n",
+ "Cannot get KCM socket path [%d]: %s\n",
ret, strerror(ret));
goto done;
}
kctx->rctx->sock_name = sock_name;
+ ret = kcm_get_ccdb_be(kctx);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Cannot get KCM ccache DB [%d]: %s\n",
+ ret, strerror(ret));
+ goto done;
+ }
+
ret = EOK;
-
done:
return ret;
}
@@ -111,7 +149,8 @@ static int kcm_data_destructor(void *ptr)
}
static struct kcm_resp_ctx *kcm_data_setup(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev)
+ struct tevent_context *ev,
+ enum kcm_ccdb_be cc_be)
{
struct kcm_resp_ctx *kcm_data;
krb5_error_code kret;
@@ -122,7 +161,7 @@ static struct kcm_resp_ctx *kcm_data_setup(TALLOC_CTX *mem_ctx,
return NULL;
}
- kcm_data->db = kcm_ccdb_init(kcm_data, ev, CCDB_BE_MEMORY);
+ kcm_data->db = kcm_ccdb_init(kcm_data, ev, cc_be);
if (kcm_data->db == NULL) {
talloc_free(kcm_data);
return NULL;
@@ -176,7 +215,7 @@ static int kcm_process_init(TALLOC_CTX *mem_ctx,
goto fail;
}
- kctx->kcm_data = kcm_data_setup(kctx, ev);
+ kctx->kcm_data = kcm_data_setup(kctx, ev, kctx->cc_be);
if (kctx->kcm_data == NULL) {
DEBUG(SSSDBG_FATAL_FAILURE,
"fatal error initializing responder data\n");
diff --git a/src/responder/kcm/kcmsrv_ccache.c b/src/responder/kcm/kcmsrv_ccache.c
index 2ae120269b0c62275ba2acdff6d6daa8b7077708..a22184e0f2b1300f3678bb343b6a110bf144a36b 100644
--- a/src/responder/kcm/kcmsrv_ccache.c
+++ b/src/responder/kcm/kcmsrv_ccache.c
@@ -244,7 +244,7 @@ struct kcm_ccdb *kcm_ccdb_init(TALLOC_CTX *mem_ctx,
break;
case CCDB_BE_SECRETS:
DEBUG(SSSDBG_FUNC_DATA, "KCM back end: sssd-secrets\n");
- /* Not implemented yet */
+ ccdb->ops = &ccdb_sec_ops;
break;
default:
DEBUG(SSSDBG_CRIT_FAILURE, "Unknown ccache database\n");
diff --git a/src/responder/kcm/kcmsrv_ccache.h b/src/responder/kcm/kcmsrv_ccache.h
index 18c8c47ad4ecb24521a85a1833b239c7a2a8bb45..36c481c5335d557318f0ed0204d93e533b4b6c41 100644
--- a/src/responder/kcm/kcmsrv_ccache.h
+++ b/src/responder/kcm/kcmsrv_ccache.h
@@ -29,6 +29,7 @@
#include "util/util.h"
#include "util/sss_iobuf.h"
#include "util/util_creds.h"
+#include "responder/kcm/kcmsrv_pvt.h"
#define UUID_BYTES 16
#define UUID_STR_SIZE 37
@@ -113,11 +114,6 @@ errno_t kcm_cc_store_cred_blob(struct kcm_ccache *cc,
struct kcm_cred *kcm_cc_get_cred(struct kcm_ccache *cc);
struct kcm_cred *kcm_cc_next_cred(struct kcm_cred *crd);
-enum kcm_ccdb_be {
- CCDB_BE_MEMORY,
- CCDB_BE_SECRETS,
-};
-
/* An opaque database that contains all the ccaches */
struct kcm_ccdb;
diff --git a/src/responder/kcm/kcmsrv_ccache_be.h b/src/responder/kcm/kcmsrv_ccache_be.h
index 1bd2b6981e227675866e82e0a5389445cac4df66..a0796c298bae15a01adf612a6195a494ba6b4d23 100644
--- a/src/responder/kcm/kcmsrv_ccache_be.h
+++ b/src/responder/kcm/kcmsrv_ccache_be.h
@@ -200,5 +200,6 @@ struct kcm_ccdb_ops {
};
extern const struct kcm_ccdb_ops ccdb_mem_ops;
+extern const struct kcm_ccdb_ops ccdb_sec_ops;
#endif /* _KCMSRV_CCACHE_BE_ */
diff --git a/src/responder/kcm/kcmsrv_pvt.h b/src/responder/kcm/kcmsrv_pvt.h
index a29680246c1e616da75e1bbff951ce2fad66fb65..74f30c00014105ed533744779b02c5d42523722d 100644
--- a/src/responder/kcm/kcmsrv_pvt.h
+++ b/src/responder/kcm/kcmsrv_pvt.h
@@ -49,6 +49,12 @@ struct kcm_resp_ctx {
struct kcm_ccdb *db;
};
+/* Supported ccache back ends */
+enum kcm_ccdb_be {
+ CCDB_BE_MEMORY,
+ CCDB_BE_SECRETS,
+};
+
/*
* responder context that contains both the responder data,
* like the ccaches and the sssd-specific stuff like the
@@ -58,6 +64,7 @@ struct kcm_ctx {
struct resp_ctx *rctx;
int fd_limit;
char *socket_path;
+ enum kcm_ccdb_be cc_be;
struct kcm_resp_ctx *kcm_data;
};
--
2.12.2

View File

@ -1,909 +0,0 @@
From 2b5518eeaacc6245cfa77ee4a7086f16208060fc Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Tue, 21 Mar 2017 13:25:11 +0100
Subject: [PATCH 37/97] KCM: Queue requests by the same UID
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
In order to avoid race conditions, we queue requests towards the KCM
responder coming from the same client UID.
Reviewed-by: Michal Židek <mzidek@redhat.com>
Reviewed-by: Simo Sorce <simo@redhat.com>
Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
---
Makefile.am | 21 ++-
src/responder/kcm/kcm.c | 7 +
src/responder/kcm/kcmsrv_cmd.c | 10 +-
src/responder/kcm/kcmsrv_op_queue.c | 264 ++++++++++++++++++++++++++
src/responder/kcm/kcmsrv_ops.c | 44 ++++-
src/responder/kcm/kcmsrv_ops.h | 1 +
src/responder/kcm/kcmsrv_pvt.h | 20 ++
src/tests/cmocka/test_kcm_queue.c | 365 ++++++++++++++++++++++++++++++++++++
8 files changed, 721 insertions(+), 11 deletions(-)
create mode 100644 src/responder/kcm/kcmsrv_op_queue.c
create mode 100644 src/tests/cmocka/test_kcm_queue.c
diff --git a/Makefile.am b/Makefile.am
index e9eaa312c91e3aee40bcf13c90a0ad8c683045d5..91afdd669aa11a3cc316588d3b51d7e8e9c91cb8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -304,7 +304,10 @@ non_interactive_cmocka_based_tests += test_inotify
endif # HAVE_INOTIFY
if BUILD_KCM
-non_interactive_cmocka_based_tests += test_kcm_json
+non_interactive_cmocka_based_tests += \
+ test_kcm_json \
+ test_kcm_queue \
+ $(NULL)
endif # BUILD_KCM
if BUILD_SAMBA
@@ -1501,6 +1504,7 @@ sssd_kcm_SOURCES = \
src/responder/kcm/kcmsrv_ccache_json.c \
src/responder/kcm/kcmsrv_ccache_secrets.c \
src/responder/kcm/kcmsrv_ops.c \
+ src/responder/kcm/kcmsrv_op_queue.c \
src/util/sss_sockets.c \
src/util/sss_krb5.c \
src/util/sss_iobuf.c \
@@ -3402,6 +3406,21 @@ test_kcm_json_LDADD = \
$(SSSD_INTERNAL_LTLIBS) \
libsss_test_common.la \
$(NULL)
+
+test_kcm_queue_SOURCES = \
+ src/tests/cmocka/test_kcm_queue.c \
+ src/responder/kcm/kcmsrv_op_queue.c \
+ $(NULL)
+test_kcm_queue_CFLAGS = \
+ $(AM_CFLAGS) \
+ $(NULL)
+test_kcm_queue_LDADD = \
+ $(CMOCKA_LIBS) \
+ $(SSSD_LIBS) \
+ $(SSSD_INTERNAL_LTLIBS) \
+ libsss_test_common.la \
+ $(NULL)
+
endif # BUILD_KCM
endif # HAVE_CMOCKA
diff --git a/src/responder/kcm/kcm.c b/src/responder/kcm/kcm.c
index 063c27b915b4b92f6259496feee891aa94a498b6..3ee978066c589a5cc38b0ae358f741d389d00e7a 100644
--- a/src/responder/kcm/kcm.c
+++ b/src/responder/kcm/kcm.c
@@ -133,6 +133,13 @@ static int kcm_get_config(struct kcm_ctx *kctx)
goto done;
}
+ kctx->qctx = kcm_ops_queue_create(kctx);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Cannot create KCM request queue [%d]: %s\n",
+ ret, strerror(ret));
+ goto done;
+ }
ret = EOK;
done:
return ret;
diff --git a/src/responder/kcm/kcmsrv_cmd.c b/src/responder/kcm/kcmsrv_cmd.c
index 537e88953fd1a190a9a73bcdd430d8e0db8f9291..81015de4a91617de3dca444cde95b636c8d5c0d1 100644
--- a/src/responder/kcm/kcmsrv_cmd.c
+++ b/src/responder/kcm/kcmsrv_cmd.c
@@ -353,14 +353,18 @@ struct kcm_req_ctx {
static void kcm_cmd_request_done(struct tevent_req *req);
-static errno_t kcm_cmd_dispatch(struct kcm_req_ctx *req_ctx)
+static errno_t kcm_cmd_dispatch(struct kcm_ctx *kctx,
+ struct kcm_req_ctx *req_ctx)
{
struct tevent_req *req;
struct cli_ctx *cctx;
cctx = req_ctx->cctx;
- req = kcm_cmd_send(req_ctx, cctx->ev, req_ctx->kctx->kcm_data,
+ req = kcm_cmd_send(req_ctx,
+ cctx->ev,
+ kctx->qctx,
+ req_ctx->kctx->kcm_data,
req_ctx->cctx->creds,
&req_ctx->op_io.request,
req_ctx->op_io.op);
@@ -505,7 +509,7 @@ static void kcm_recv(struct cli_ctx *cctx)
/* do not read anymore, client is done sending */
TEVENT_FD_NOT_READABLE(cctx->cfde);
- ret = kcm_cmd_dispatch(req);
+ ret = kcm_cmd_dispatch(kctx, req);
if (ret != EOK) {
DEBUG(SSSDBG_FATAL_FAILURE,
"Failed to dispatch KCM operation [%d]: %s\n",
diff --git a/src/responder/kcm/kcmsrv_op_queue.c b/src/responder/kcm/kcmsrv_op_queue.c
new file mode 100644
index 0000000000000000000000000000000000000000..f6c425dd5b64877c8b7401e488dd6565157fc9b5
--- /dev/null
+++ b/src/responder/kcm/kcmsrv_op_queue.c
@@ -0,0 +1,264 @@
+/*
+ SSSD
+
+ KCM Server - the KCM operations wait queue
+
+ Copyright (C) Red Hat, 2017
+
+ 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 "util/util.h"
+#include "util/util_creds.h"
+#include "responder/kcm/kcmsrv_pvt.h"
+
+#define QUEUE_HASH_SIZE 32
+
+struct kcm_ops_queue_entry {
+ struct tevent_req *req;
+ uid_t uid;
+
+ hash_table_t *wait_queue_hash;
+
+ struct kcm_ops_queue_entry *head;
+ struct kcm_ops_queue_entry *next;
+ struct kcm_ops_queue_entry *prev;
+};
+
+struct kcm_ops_queue_ctx {
+ /* UID: dlist of kcm_ops_queue_entry */
+ hash_table_t *wait_queue_hash;
+};
+
+/*
+ * Per-UID wait queue
+ *
+ * They key in the hash table is the UID of the peer. The value of each
+ * hash table entry is a linked list of kcm_ops_queue_entry structures
+ * which primarily hold the tevent request being queued.
+ */
+struct kcm_ops_queue_ctx *kcm_ops_queue_create(TALLOC_CTX *mem_ctx)
+{
+ errno_t ret;
+ struct kcm_ops_queue_ctx *queue_ctx;
+
+ queue_ctx = talloc_zero(mem_ctx, struct kcm_ops_queue_ctx);
+ if (queue_ctx == NULL) {
+ return NULL;
+ }
+
+ ret = sss_hash_create_ex(mem_ctx, QUEUE_HASH_SIZE,
+ &queue_ctx->wait_queue_hash, 0, 0, 0, 0,
+ NULL, NULL);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "sss_hash_create failed [%d]: %s\n", ret, sss_strerror(ret));
+ talloc_free(queue_ctx);
+ return NULL;
+ }
+
+ return queue_ctx;
+}
+
+static int kcm_op_queue_entry_destructor(struct kcm_ops_queue_entry *entry)
+{
+ int ret;
+ struct kcm_ops_queue_entry *next_entry;
+ hash_key_t key;
+
+ if (entry == NULL) {
+ return 1;
+ }
+
+ /* Take the next entry from the queue */
+ next_entry = entry->next;
+
+ /* Remove the current entry from the queue */
+ DLIST_REMOVE(entry->head, entry);
+
+ if (next_entry == NULL) {
+ key.type = HASH_KEY_ULONG;
+ key.ul = entry->uid;
+
+ /* If this was the last entry, remove the key (the UID) from the
+ * hash table to signal the queue is empty
+ */
+ ret = hash_delete(entry->wait_queue_hash, &key);
+ if (ret != HASH_SUCCESS) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to remove wait queue for user %"SPRIuid"\n",
+ entry->uid);
+ return 1;
+ }
+ return 0;
+ }
+
+ /* Otherwise, mark the current head as done to run the next request */
+ tevent_req_done(next_entry->req);
+ return 0;
+}
+
+static errno_t kcm_op_queue_add(hash_table_t *wait_queue_hash,
+ struct kcm_ops_queue_entry *entry,
+ uid_t uid)
+{
+ errno_t ret;
+ hash_key_t key;
+ hash_value_t value;
+ struct kcm_ops_queue_entry *head = NULL;
+
+ key.type = HASH_KEY_ULONG;
+ key.ul = uid;
+
+ ret = hash_lookup(wait_queue_hash, &key, &value);
+ switch (ret) {
+ case HASH_SUCCESS:
+ /* The key with this UID already exists. Its value is request queue
+ * for the UID, so let's just add the current request to the end
+ * of the queue and wait for the previous requests to finish
+ */
+ if (value.type != HASH_VALUE_PTR) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected hash value type.\n");
+ return EINVAL;
+ }
+
+ head = talloc_get_type(value.ptr, struct kcm_ops_queue_entry);
+ if (head == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Invalid queue pointer\n");
+ return EINVAL;
+ }
+
+ entry->head = head;
+ DLIST_ADD_END(head, entry, struct kcm_ops_queue_entry *);
+
+ DEBUG(SSSDBG_TRACE_LIBS, "Waiting in queue\n");
+ ret = EAGAIN;
+ break;
+
+ case HASH_ERROR_KEY_NOT_FOUND:
+ /* No request for this UID yet. Enqueue this request in case
+ * another one comes in and return EOK to run the current request
+ * immediatelly
+ */
+ entry->head = entry;
+
+ value.type = HASH_VALUE_PTR;
+ value.ptr = entry;
+
+ ret = hash_enter(wait_queue_hash, &key, &value);
+ if (ret != HASH_SUCCESS) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "hash_enter failed.\n");
+ return EIO;
+ }
+
+ DEBUG(SSSDBG_TRACE_LIBS,
+ "Added a first request to the queue, running immediately\n");
+ ret = EOK;
+ break;
+
+ default:
+ DEBUG(SSSDBG_CRIT_FAILURE, "hash_lookup failed.\n");
+ return EIO;
+ }
+
+ talloc_steal(wait_queue_hash, entry);
+ talloc_set_destructor(entry, kcm_op_queue_entry_destructor);
+ return ret;
+}
+
+struct kcm_op_queue_state {
+ struct kcm_ops_queue_entry *entry;
+};
+
+/*
+ * Enqueue a request.
+ *
+ * If the request queue /for the given ID/ is empty, that is, if this
+ * request is the first one in the queue, run the request immediatelly.
+ *
+ * Otherwise just add it to the queue and wait until the previous request
+ * finishes and only at that point mark the current request as done, which
+ * will trigger calling the recv function and allow the request to continue.
+ */
+struct tevent_req *kcm_op_queue_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct kcm_ops_queue_ctx *qctx,
+ struct cli_creds *client)
+{
+ errno_t ret;
+ struct tevent_req *req;
+ struct kcm_op_queue_state *state;
+ uid_t uid;
+
+ uid = cli_creds_get_uid(client);
+
+ req = tevent_req_create(mem_ctx, &state, struct kcm_op_queue_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->entry = talloc_zero(state, struct kcm_ops_queue_entry);
+ if (state->entry == NULL) {
+ ret = ENOMEM;
+ goto immediate;
+ }
+ state->entry->req = req;
+ state->entry->uid = uid;
+ state->entry->wait_queue_hash = qctx->wait_queue_hash;
+
+ DEBUG(SSSDBG_FUNC_DATA,
+ "Adding request by %"SPRIuid" to the wait queue\n", uid);
+
+ ret = kcm_op_queue_add(qctx->wait_queue_hash, state->entry, uid);
+ if (ret == EOK) {
+ DEBUG(SSSDBG_TRACE_LIBS,
+ "Wait queue was empty, running immediately\n");
+ goto immediate;
+ } else if (ret != EAGAIN) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Cannot enqueue request [%d]: %s\n", ret, sss_strerror(ret));
+ goto immediate;
+ }
+
+ DEBUG(SSSDBG_TRACE_LIBS, "Waiting our turn in the queue\n");
+ return req;
+
+immediate:
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
+ }
+ tevent_req_post(req, ev);
+ return req;
+}
+
+/*
+ * The queue recv function is called when this request is 'activated'. The queue
+ * entry should be allocated on the same memory context as the enqueued request
+ * to trigger freeing the kcm_ops_queue_entry structure destructor when the
+ * parent request is done and its tevent_req freed. This would in turn unblock
+ * the next request in the queue
+ */
+errno_t kcm_op_queue_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct kcm_ops_queue_entry **_entry)
+{
+ struct kcm_op_queue_state *state = tevent_req_data(req,
+ struct kcm_op_queue_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+ *_entry = talloc_steal(mem_ctx, state->entry);
+ return EOK;
+}
diff --git a/src/responder/kcm/kcmsrv_ops.c b/src/responder/kcm/kcmsrv_ops.c
index 50e8cc635424e15d53e3c8d122c5525044f59c8a..2feaf51f227ce9d90f706229ce7ac201b282dc6f 100644
--- a/src/responder/kcm/kcmsrv_ops.c
+++ b/src/responder/kcm/kcmsrv_ops.c
@@ -67,17 +67,21 @@ struct kcm_op {
struct kcm_cmd_state {
struct kcm_op *op;
+ struct tevent_context *ev;
+ struct kcm_ops_queue_entry *queue_entry;
struct kcm_op_ctx *op_ctx;
struct sss_iobuf *reply;
uint32_t op_ret;
};
+static void kcm_cmd_queue_done(struct tevent_req *subreq);
static void kcm_cmd_done(struct tevent_req *subreq);
struct tevent_req *kcm_cmd_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
+ struct kcm_ops_queue_ctx *qctx,
struct kcm_resp_ctx *kcm_data,
struct cli_creds *client,
struct kcm_data *input,
@@ -93,6 +97,7 @@ struct tevent_req *kcm_cmd_send(TALLOC_CTX *mem_ctx,
return NULL;
}
state->op = op;
+ state->ev = ev;
if (op == NULL) {
ret = EINVAL;
@@ -154,18 +159,43 @@ struct tevent_req *kcm_cmd_send(TALLOC_CTX *mem_ctx,
goto immediate;
}
- subreq = op->fn_send(state, ev, state->op_ctx);
+ subreq = kcm_op_queue_send(state, ev, qctx, client);
if (subreq == NULL) {
ret = ENOMEM;
goto immediate;
}
+ tevent_req_set_callback(subreq, kcm_cmd_queue_done, req);
+ return req;
+
+immediate:
+ tevent_req_error(req, ret);
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static void kcm_cmd_queue_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req);
+ struct kcm_cmd_state *state = tevent_req_data(req, struct kcm_cmd_state);
+ errno_t ret;
+
+ /* When this request finishes, it frees the queue_entry which unblocks
+ * other requests by the same UID
+ */
+ ret = kcm_op_queue_recv(subreq, state, &state->queue_entry);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot acquire queue slot\n");
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ subreq = state->op->fn_send(state, state->ev, state->op_ctx);
+ if (subreq == NULL) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
tevent_req_set_callback(subreq, kcm_cmd_done, req);
- return req;
-
-immediate:
- tevent_req_error(req, ret);
- tevent_req_post(req, ev);
- return req;
}
static void kcm_cmd_done(struct tevent_req *subreq)
diff --git a/src/responder/kcm/kcmsrv_ops.h b/src/responder/kcm/kcmsrv_ops.h
index 8e6feaf56a10b73c8b6375aea9ef26c392b5b492..67d9f86026bf949548471f2280c130ebefd2f865 100644
--- a/src/responder/kcm/kcmsrv_ops.h
+++ b/src/responder/kcm/kcmsrv_ops.h
@@ -34,6 +34,7 @@ const char *kcm_opt_name(struct kcm_op *op);
struct tevent_req *kcm_cmd_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
+ struct kcm_ops_queue_ctx *qctx,
struct kcm_resp_ctx *kcm_data,
struct cli_creds *client,
struct kcm_data *input,
diff --git a/src/responder/kcm/kcmsrv_pvt.h b/src/responder/kcm/kcmsrv_pvt.h
index 74f30c00014105ed533744779b02c5d42523722d..f081a6bf0c6e40d2f8a83b07f9bbc2abacff359d 100644
--- a/src/responder/kcm/kcmsrv_pvt.h
+++ b/src/responder/kcm/kcmsrv_pvt.h
@@ -25,6 +25,7 @@
#include "config.h"
#include <sys/types.h>
+#include <krb5/krb5.h>
#include "responder/common/responder.h"
/*
@@ -65,6 +66,7 @@ struct kcm_ctx {
int fd_limit;
char *socket_path;
enum kcm_ccdb_be cc_be;
+ struct kcm_ops_queue_ctx *qctx;
struct kcm_resp_ctx *kcm_data;
};
@@ -78,4 +80,22 @@ int kcm_connection_setup(struct cli_ctx *cctx);
*/
krb5_error_code sss2krb5_error(errno_t err);
+/* We enqueue all requests by the same UID to avoid concurrency issues
+ * especially when performing multiple round-trips to sssd-secrets. In
+ * future, we should relax the queue to allow multiple read-only operations
+ * if no write operations are in progress.
+ */
+struct kcm_ops_queue_entry;
+
+struct kcm_ops_queue_ctx *kcm_ops_queue_create(TALLOC_CTX *mem_ctx);
+
+struct tevent_req *kcm_op_queue_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct kcm_ops_queue_ctx *qctx,
+ struct cli_creds *client);
+
+errno_t kcm_op_queue_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct kcm_ops_queue_entry **_entry);
+
#endif /* __KCMSRV_PVT_H__ */
diff --git a/src/tests/cmocka/test_kcm_queue.c b/src/tests/cmocka/test_kcm_queue.c
new file mode 100644
index 0000000000000000000000000000000000000000..ba0d2405629960df5c623848f3207b7c80fa948d
--- /dev/null
+++ b/src/tests/cmocka/test_kcm_queue.c
@@ -0,0 +1,365 @@
+/*
+ Copyright (C) 2017 Red Hat
+
+ SSSD tests: Test KCM wait queue
+
+ 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 "config.h"
+
+#include <stdio.h>
+#include <popt.h>
+
+#include "util/util.h"
+#include "util/util_creds.h"
+#include "tests/cmocka/common_mock.h"
+#include "responder/kcm/kcmsrv_pvt.h"
+
+#define INVALID_ID -1
+#define FAST_REQ_ID 0
+#define SLOW_REQ_ID 1
+
+#define FAST_REQ_DELAY 1
+#define SLOW_REQ_DELAY 2
+
+struct timed_request_state {
+ struct tevent_context *ev;
+ struct kcm_ops_queue_ctx *qctx;
+ struct cli_creds *client;
+ int delay;
+ int req_id;
+
+ struct kcm_ops_queue_entry *queue_entry;
+};
+
+static void timed_request_start(struct tevent_req *subreq);
+static void timed_request_done(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval current_time,
+ void *pvt);
+
+static struct tevent_req *timed_request_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct kcm_ops_queue_ctx *qctx,
+ struct cli_creds *client,
+ int delay,
+ int req_id)
+{
+ struct tevent_req *req;
+ struct tevent_req *subreq;
+ struct timed_request_state *state;
+
+ req = tevent_req_create(mem_ctx, &state, struct timed_request_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->qctx = qctx;
+ state->client = client;
+ state->delay = delay;
+ state->req_id = req_id;
+
+ DEBUG(SSSDBG_TRACE_ALL, "Request %p with delay %d\n", req, delay);
+
+ subreq = kcm_op_queue_send(state, ev, qctx, client);
+ if (subreq == NULL) {
+ return NULL;
+ }
+ tevent_req_set_callback(subreq, timed_request_start, req);
+
+ return req;
+}
+
+static void timed_request_start(struct tevent_req *subreq)
+{
+ struct timeval tv;
+ struct tevent_timer *timeout = NULL;
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct timed_request_state *state = tevent_req_data(req,
+ struct timed_request_state);
+ errno_t ret;
+
+ ret = kcm_op_queue_recv(subreq, state, &state->queue_entry);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ tv = tevent_timeval_current_ofs(state->delay, 0);
+ timeout = tevent_add_timer(state->ev, state, tv, timed_request_done, req);
+ if (timeout == NULL) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+
+ return;
+}
+
+static void timed_request_done(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval current_time,
+ void *pvt)
+{
+ struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
+ DEBUG(SSSDBG_TRACE_ALL, "Request %p done\n", req);
+ tevent_req_done(req);
+}
+
+static errno_t timed_request_recv(struct tevent_req *req,
+ int *req_id)
+{
+ struct timed_request_state *state = tevent_req_data(req,
+ struct timed_request_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+ *req_id = state->req_id;
+ return EOK;
+}
+
+struct test_ctx {
+ struct kcm_ops_queue_ctx *qctx;
+ struct tevent_context *ev;
+
+ int *req_ids;
+
+ int num_requests;
+ int finished_requests;
+ bool done;
+ errno_t error;
+};
+
+static int setup_kcm_queue(void **state)
+{
+ struct test_ctx *tctx;
+
+ tctx = talloc_zero(NULL, struct test_ctx);
+ assert_non_null(tctx);
+
+ tctx->ev = tevent_context_init(tctx);
+ assert_non_null(tctx->ev);
+
+ tctx->qctx = kcm_ops_queue_create(tctx);
+ assert_non_null(tctx->qctx);
+
+ *state = tctx;
+ return 0;
+}
+
+static int teardown_kcm_queue(void **state)
+{
+ struct test_ctx *tctx = talloc_get_type(*state, struct test_ctx);
+ talloc_free(tctx);
+ return 0;
+}
+
+static void test_kcm_queue_done(struct tevent_req *req)
+{
+ struct test_ctx *test_ctx = tevent_req_callback_data(req,
+ struct test_ctx);
+ int req_id = INVALID_ID;
+
+ test_ctx->error = timed_request_recv(req, &req_id);
+ talloc_zfree(req);
+ if (test_ctx->error != EOK) {
+ test_ctx->done = true;
+ return;
+ }
+
+ if (test_ctx->req_ids[test_ctx->finished_requests] != req_id) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Request %d finished, expected %d\n",
+ req_id, test_ctx->req_ids[test_ctx->finished_requests]);
+ test_ctx->error = EIO;
+ test_ctx->done = true;
+ return;
+ }
+
+ test_ctx->finished_requests++;
+ if (test_ctx->finished_requests == test_ctx->num_requests) {
+ test_ctx->done = true;
+ return;
+ }
+}
+
+/*
+ * Just make sure that a single pass through the queue works
+ */
+static void test_kcm_queue_single(void **state)
+{
+ struct test_ctx *test_ctx = talloc_get_type(*state, struct test_ctx);
+ struct tevent_req *req;
+ struct cli_creds client;
+ static int req_ids[] = { 0 };
+
+ client.ucred.uid = getuid();
+ client.ucred.gid = getgid();
+
+ req = timed_request_send(test_ctx,
+ test_ctx->ev,
+ test_ctx->qctx,
+ &client, 1, 0);
+ assert_non_null(req);
+ tevent_req_set_callback(req, test_kcm_queue_done, test_ctx);
+
+ test_ctx->num_requests = 1;
+ test_ctx->req_ids = req_ids;
+
+ while (test_ctx->done == false) {
+ tevent_loop_once(test_ctx->ev);
+ }
+ assert_int_equal(test_ctx->error, EOK);
+}
+
+/*
+ * Test that multiple requests from the same ID wait for one another
+ */
+static void test_kcm_queue_multi_same_id(void **state)
+{
+ struct test_ctx *test_ctx = talloc_get_type(*state, struct test_ctx);
+ struct tevent_req *req;
+ struct cli_creds client;
+ /* The slow request will finish first because request from
+ * the same ID are serialized
+ */
+ static int req_ids[] = { SLOW_REQ_ID, FAST_REQ_ID };
+
+ client.ucred.uid = getuid();
+ client.ucred.gid = getgid();
+
+ req = timed_request_send(test_ctx,
+ test_ctx->ev,
+ test_ctx->qctx,
+ &client,
+ SLOW_REQ_DELAY,
+ SLOW_REQ_ID);
+ assert_non_null(req);
+ tevent_req_set_callback(req, test_kcm_queue_done, test_ctx);
+
+ req = timed_request_send(test_ctx,
+ test_ctx->ev,
+ test_ctx->qctx,
+ &client,
+ FAST_REQ_DELAY,
+ FAST_REQ_ID);
+ assert_non_null(req);
+ tevent_req_set_callback(req, test_kcm_queue_done, test_ctx);
+
+ test_ctx->num_requests = 2;
+ test_ctx->req_ids = req_ids;
+
+ while (test_ctx->done == false) {
+ tevent_loop_once(test_ctx->ev);
+ }
+ assert_int_equal(test_ctx->error, EOK);
+}
+
+/*
+ * Test that multiple requests from different IDs don't wait for one
+ * another and can run concurrently
+ */
+static void test_kcm_queue_multi_different_id(void **state)
+{
+ struct test_ctx *test_ctx = talloc_get_type(*state, struct test_ctx);
+ struct tevent_req *req;
+ struct cli_creds client;
+ /* In this test, the fast request will finish sooner because
+ * both requests are from different IDs, allowing them to run
+ * concurrently
+ */
+ static int req_ids[] = { FAST_REQ_ID, SLOW_REQ_ID };
+
+ client.ucred.uid = getuid();
+ client.ucred.gid = getgid();
+
+ req = timed_request_send(test_ctx,
+ test_ctx->ev,
+ test_ctx->qctx,
+ &client,
+ SLOW_REQ_DELAY,
+ SLOW_REQ_ID);
+ assert_non_null(req);
+ tevent_req_set_callback(req, test_kcm_queue_done, test_ctx);
+
+ client.ucred.uid = getuid() + 1;
+ client.ucred.gid = getgid() + 1;
+
+ req = timed_request_send(test_ctx,
+ test_ctx->ev,
+ test_ctx->qctx,
+ &client,
+ FAST_REQ_DELAY,
+ FAST_REQ_ID);
+ assert_non_null(req);
+ tevent_req_set_callback(req, test_kcm_queue_done, test_ctx);
+
+ test_ctx->num_requests = 2;
+ test_ctx->req_ids = req_ids;
+
+ while (test_ctx->done == false) {
+ tevent_loop_once(test_ctx->ev);
+ }
+ assert_int_equal(test_ctx->error, EOK);
+}
+
+int main(int argc, const char *argv[])
+{
+ poptContext pc;
+ int opt;
+ int rv;
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ SSSD_DEBUG_OPTS
+ POPT_TABLEEND
+ };
+
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(test_kcm_queue_single,
+ setup_kcm_queue,
+ teardown_kcm_queue),
+ cmocka_unit_test_setup_teardown(test_kcm_queue_multi_same_id,
+ setup_kcm_queue,
+ teardown_kcm_queue),
+ cmocka_unit_test_setup_teardown(test_kcm_queue_multi_different_id,
+ setup_kcm_queue,
+ teardown_kcm_queue),
+ };
+
+ /* 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_CLI_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();
+
+ rv = cmocka_run_group_tests(tests, NULL, NULL);
+
+ return rv;
+}
--
2.12.2

View File

@ -1,55 +0,0 @@
From e89ba95737202d551db2c9524127e6c4cf308796 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Tue, 21 Mar 2017 14:26:54 +0100
Subject: [PATCH 38/97] KCM: Idle-terminate the responder if the secrets back
end is used
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Existing with memory database would be fatal as we keep the ccaches in
memory then, but if the ccaches are stored in sssd-secrets, we can just
exit on idle.
Reviewed-by: Michal Židek <mzidek@redhat.com>
Reviewed-by: Simo Sorce <simo@redhat.com>
---
src/config/cfg_rules.ini | 1 +
src/responder/kcm/kcm.c | 9 +++++++++
2 files changed, 10 insertions(+)
diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini
index 67a5d1f5ad447a942b437ffd04a7f5d7cfe77d7f..933ebccd828189d923d2186753dfbc0b5c0814ce 100644
--- a/src/config/cfg_rules.ini
+++ b/src/config/cfg_rules.ini
@@ -281,6 +281,7 @@ option = client_idle_timeout
option = description
option = socket_path
option = ccache_storage
+option = responder_idle_timeout
[rule/allowed_domain_options]
validator = ini_allowed_options
diff --git a/src/responder/kcm/kcm.c b/src/responder/kcm/kcm.c
index 3ee978066c589a5cc38b0ae358f741d389d00e7a..2202f96381a2622a2c5433e281172287b325f960 100644
--- a/src/responder/kcm/kcm.c
+++ b/src/responder/kcm/kcm.c
@@ -133,6 +133,15 @@ static int kcm_get_config(struct kcm_ctx *kctx)
goto done;
}
+ if (kctx->cc_be == CCDB_BE_SECRETS) {
+ ret = responder_setup_idle_timeout_config(kctx->rctx);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "Cannot set up idle responder timeout\n");
+ /* Not fatal */
+ }
+ }
+
kctx->qctx = kcm_ops_queue_create(kctx);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
--
2.12.2

View File

@ -1,34 +0,0 @@
From 00172861b6908a72c41046e1b2b48d2b009127dd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ville=20Skytt=C3=A4?= <ville.skytta@iki.fi>
Date: Wed, 22 Mar 2017 20:32:21 +0000
Subject: [PATCH 39/97] SSSDConfig: Python 3.6 invalid escape sequence
deprecation fix
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
https://docs.python.org/3/whatsnew/3.6.html#deprecated-python-behavior
Merges: https://pagure.io/SSSD/sssd/pull-request/3346
Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
---
src/config/SSSDConfig/__init__.py.in | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in
index 03a1a43336604bb815626e64cb54052bdf87acf2..29e9b4fae6835db4ccb9937fd93457d462e4a15d 100644
--- a/src/config/SSSDConfig/__init__.py.in
+++ b/src/config/SSSDConfig/__init__.py.in
@@ -483,7 +483,7 @@ class SSSDConfigSchema(SSSDChangeConf):
self.readfp(fd)
fd.close()
# Read in the provider files
- for file in filter(lambda f: re.search('^sssd-.*\.conf$', f),
+ for file in filter(lambda f: re.search(r'^sssd-.*\.conf$', f),
os.listdir(schemaplugindir)):
fd = open(schemaplugindir+ "/" + file)
self.readfp(fd)
--
2.12.2

View File

@ -1,30 +0,0 @@
From 7c67679ba86682d8c2afea404ec0229641a7f473 Mon Sep 17 00:00:00 2001
From: Lukas Slebodnik <lslebodn@redhat.com>
Date: Mon, 27 Mar 2017 11:59:01 +0200
Subject: [PATCH 40/97] CONFIGURE: Fix fallback if pkg-config for uuid is
missing
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
---
src/external/libuuid.m4 | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/external/libuuid.m4 b/src/external/libuuid.m4
index 55411a2118bd787c9d50ba61f9cb791e1c76088d..323521c9224e443f40a15b417038d2dcea9b66f3 100644
--- a/src/external/libuuid.m4
+++ b/src/external/libuuid.m4
@@ -4,7 +4,7 @@ AC_SUBST(UUID_CFLAGS)
PKG_CHECK_MODULES([UUID], [uuid], [found_uuid=yes], [found_uuid=no])
SSS_AC_EXPAND_LIB_DIR()
-AS_IF([test x"$found_uuid" = xyes],
+AS_IF([test x"$found_uuid" != xyes],
[AC_CHECK_HEADERS([uuid/uuid.h],
[AC_CHECK_LIB([uuid],
[uuid_generate],
--
2.12.2

View File

@ -1,52 +0,0 @@
From 8e785c7478e1a79179842106a62f3f85118b6690 Mon Sep 17 00:00:00 2001
From: Lukas Slebodnik <lslebodn@redhat.com>
Date: Tue, 28 Mar 2017 12:18:13 +0200
Subject: [PATCH 41/97] intg: fix configure failure with strict cflags
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The warning -Wstrict-prototypes is a part of AM_CFLAGS which was appended
for CFLAGS in make target intgcheck-prepare. And combination with
strict CFLAGS in environment variable (e.g. -Werror) caused failures.
sh$ CFLAGS="-Werror" make intgcheck-prepare
checking for gcc... gcc
checking whether the C compiler works... no
configure: error: in `/home/build/sssd/ci-build-debug/intg/bld':
configure: error: C compiler cannot create executables
configure:3719: checking whether the C compiler works
configure:3741: gcc -g3 -O2 -Werror -D_FILE_OFFSET_BITS=64
-D_LARGEFILE_SOURCE -Wall -Wshadow -Wstrict-prototypes
-Wpointer-arith -Wcast-qual -Wcast-align -Wwrite-strings
-Wundef -Werror-implicit-function-declaration
-Winit-self -Wmissing-include-dirs -fno-strict-aliasing
-std=gnu99 -DKCM_PEER_UID=1000 conftest.c >&5
conftest.c:11:1: error: function declaration isn't a prototype [-Werror=strict-prototypes]
main ()
^~~~
cc1: all warnings being treated as errors
Reviewed-by: Pavel Březina <pbrezina@redhat.com>
---
Makefile.am | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Makefile.am b/Makefile.am
index 91afdd669aa11a3cc316588d3b51d7e8e9c91cb8..359feddef298b0013c726409b7ba8b86504abf09 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -3486,7 +3486,7 @@ intgcheck-prepare:
--without-semanage \
--enable-files-domain \
$(INTGCHECK_CONFIGURE_FLAGS) \
- CFLAGS="$$CFLAGS $(AM_CFLAGS) -DKCM_PEER_UID=$$(id -u)"; \
+ CFLAGS="$$CFLAGS -DKCM_PEER_UID=$$(id -u)"; \
$(MAKE) $(AM_MAKEFLAGS) ; \
: Force single-thread install to workaround concurrency issues; \
$(MAKE) $(AM_MAKEFLAGS) -j1 install; \
--
2.12.2

View File

@ -1,54 +0,0 @@
From f75ba99fc8dd64e45af2f642d9fb7660860fd28f Mon Sep 17 00:00:00 2001
From: Lukas Slebodnik <lslebodn@redhat.com>
Date: Mon, 27 Mar 2017 14:44:29 +0200
Subject: [PATCH 42/97] intg: Remove bashism from intgcheck-prepare
env variable UID is not defined in all shells (eg. dash)
We also need to move invocation of "id -u" before nss_wraper
is enabled otherwise we would get root instead of real user.
=================================== FAILURES ===================================
________________________ test_kcm_mem_init_list_destroy ________________________
Traceback (most recent call last):
File "/home/build/sssd/src/tests/intg/test_kcm.py", line 198, in test_kcm_mem_init_list_destroy
kcm_init_list_destroy(testenv)
File "/home/build/sssd/src/tests/intg/test_kcm.py", line 183, in kcm_init_list_destroy
exp_ccname = testenv.ccname()
File "/home/build/sssd/src/tests/intg/test_kcm.py", line 45, in ccname
my_uid = self.my_uid()
File "/home/build/sssd/src/tests/intg/test_kcm.py", line 41, in my_uid
return int(s_myuid)
ValueError: invalid literal for int() with base 10: ''
And we already use different approach in top level Makefile.am
3488) $(INTGCHECK_CONFIGURE_FLAGS) \
3489) CFLAGS="$$CFLAGS $(AM_CFLAGS) -DKCM_PEER_UID=$$(id -u)"; \
3490) $(MAKE) $(AM_MAKEFLAGS) ; \
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
---
src/tests/intg/Makefile.am | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/tests/intg/Makefile.am b/src/tests/intg/Makefile.am
index 8526beace09b15c99aa27ac98d5038d1980f6a71..8566106e9017a8d3c9e7a3898a3a886e2966e346 100644
--- a/src/tests/intg/Makefile.am
+++ b/src/tests/intg/Makefile.am
@@ -76,6 +76,7 @@ intgcheck-installed: config.py passwd group
PATH="$(abs_builddir):$(abs_srcdir):$$PATH" \
PYTHONPATH="$(abs_builddir):$(abs_srcdir)" \
LDB_MODULES_PATH="$(DESTDIR)$(ldblibdir)" \
+ NON_WRAPPED_UID=$$(id -u) \
LD_PRELOAD="$$nss_wrapper $$uid_wrapper" \
NSS_WRAPPER_PASSWD="$(abs_builddir)/passwd" \
NSS_WRAPPER_GROUP="$(abs_builddir)/group" \
@@ -83,6 +84,5 @@ intgcheck-installed: config.py passwd group
NSS_WRAPPER_MODULE_FN_PREFIX="sss" \
UID_WRAPPER=1 \
UID_WRAPPER_ROOT=1 \
- NON_WRAPPED_UID=$$(echo $$UID) \
fakeroot $(PYTHON2) $(PYTEST) -v --tb=native $(INTGCHECK_PYTEST_ARGS) .
rm -f $(DESTDIR)$(logpath)/*
--
2.12.2

View File

@ -1,127 +0,0 @@
From e0e038218580166648ac24f23180f0f4c2769d99 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
Date: Tue, 28 Mar 2017 18:33:46 +0200
Subject: [PATCH 43/97] UTIL: Introduce subdomain_create_conf_path()
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This is a utility function that replaces the create_subdom_conf_path().
Differently than the latter, it only takes one parameter and is going to
be used in a few different places (thus adding it to util.h).
Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
Reviewed-by: Lukas Slebodnik <lslebodn@redhat.com>
---
src/providers/ad/ad_common.c | 7 -------
src/providers/ad/ad_common.h | 4 ----
src/providers/ad/ad_subdomains.c | 4 +---
src/providers/ipa/ipa_subdomains_server.c | 4 +---
src/util/domain_info_utils.c | 15 +++++++++++++++
src/util/util.h | 3 +++
6 files changed, 20 insertions(+), 17 deletions(-)
diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c
index ec952d3bb4587516ea26fd27c212d5620e2f3dda..f893b748a2ddcff1eab6e8d919d2aa950b825446 100644
--- a/src/providers/ad/ad_common.c
+++ b/src/providers/ad/ad_common.c
@@ -33,13 +33,6 @@ errno_t ad_set_search_bases(struct sdap_options *id_opts);
static errno_t ad_set_sdap_options(struct ad_options *ad_opts,
struct sdap_options *id_opts);
-char *create_subdom_conf_path(TALLOC_CTX *mem_ctx,
- const char *conf_path,
- const char *subdom_name)
-{
- return talloc_asprintf(mem_ctx, "%s/%s", conf_path, subdom_name);
-}
-
static struct sdap_options *
ad_create_default_sdap_options(TALLOC_CTX *mem_ctx)
{
diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h
index e02b932cd2da737254de8417d5c82fcdcf14e8d7..2981550f6c390929501ec8942e861b16ea0a5cb0 100644
--- a/src/providers/ad/ad_common.h
+++ b/src/providers/ad/ad_common.h
@@ -99,10 +99,6 @@ struct ad_options {
struct be_nsupdate_ctx *dyndns_ctx;
};
-char *create_subdom_conf_path(TALLOC_CTX *mem_ctx,
- const char *conf_path,
- const char *subdom_name);
-
errno_t
ad_get_common_options(TALLOC_CTX *mem_ctx,
struct confdb_ctx *cdb,
diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
index 156ecab4272029d69c8b596eff041498a7524ce4..eecae9c9ca82ad67874c13a3c7b7c617d6232d5c 100644
--- a/src/providers/ad/ad_subdomains.c
+++ b/src/providers/ad/ad_subdomains.c
@@ -171,9 +171,7 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx,
return EINVAL;
}
- subdom_conf_path = create_subdom_conf_path(id_ctx,
- be_ctx->conf_path,
- subdom->name);
+ subdom_conf_path = subdomain_create_conf_path(id_ctx, subdom);
if (subdom_conf_path == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "subdom_conf_path failed\n");
return ENOMEM;
diff --git a/src/providers/ipa/ipa_subdomains_server.c b/src/providers/ipa/ipa_subdomains_server.c
index ae3baf036e4278fb67d86b42742fb7e80b46724e..e8ee30392d84f84e30bcdaa3d2110ba130b1ad73 100644
--- a/src/providers/ipa/ipa_subdomains_server.c
+++ b/src/providers/ipa/ipa_subdomains_server.c
@@ -176,9 +176,7 @@ static struct ad_options *ipa_ad_options_new(struct be_ctx *be_ctx,
forest_realm = subdom->forest_root->realm;
forest = subdom->forest_root->forest;
- subdom_conf_path = create_subdom_conf_path(id_ctx,
- be_ctx->conf_path,
- subdom->name);
+ subdom_conf_path = subdomain_create_conf_path(id_ctx, subdom);
if (subdom_conf_path == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "subdom_conf_path failed\n");
return NULL;
diff --git a/src/util/domain_info_utils.c b/src/util/domain_info_utils.c
index 6ef6bcfb8c078a360673b6bdd2364fc2918cb324..a7f118842aa8ba870143b2f2b425a3e3c0ea5a78 100644
--- a/src/util/domain_info_utils.c
+++ b/src/util/domain_info_utils.c
@@ -870,3 +870,18 @@ bool is_email_from_domain(const char *email, struct sss_domain_info *dom)
return false;
}
+
+char *subdomain_create_conf_path(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *subdomain)
+{
+ if (!IS_SUBDOMAIN(subdomain)) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "The domain \"%s\" is not a subdomain.\n",
+ subdomain->name);
+ return NULL;
+ }
+
+ return talloc_asprintf(mem_ctx, CONFDB_DOMAIN_PATH_TMPL "/%s",
+ subdomain->parent->name,
+ subdomain->name);
+}
diff --git a/src/util/util.h b/src/util/util.h
index a2dc89b8ddb999437eda551ac17af28672d8759c..82760940269ad8883e725e3a5cf463486c9cfd36 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -551,6 +551,9 @@ find_domain_by_object_name(struct sss_domain_info *domain,
bool subdomain_enumerates(struct sss_domain_info *parent,
const char *sd_name);
+char *subdomain_create_conf_path(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *subdomain);
+
errno_t sssd_domain_init(TALLOC_CTX *mem_ctx,
struct confdb_ctx *cdb,
const char *domain_name,
--
2.12.2

View File

@ -1,531 +0,0 @@
From a63d74f65db2db7389cd373cb37adcdaaa2d56ea Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
Date: Thu, 23 Mar 2017 13:14:56 +0100
Subject: [PATCH 44/97] SUBDOMAINS: Allow use_fully_qualified_names for
subdomains
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Allow option use_fully_qualified_names in subdomain section.
This option was recently added to subdomain_inherit.
Resolves:
https://pagure.io/SSSD/sssd/issue/3337
Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
---
src/db/sysdb.h | 3 +-
src/db/sysdb_private.h | 3 +-
src/db/sysdb_subdomains.c | 63 +++++++++++++++++++++++++--
src/man/sssd.conf.5.xml | 3 +-
src/providers/ad/ad_subdomains.c | 3 +-
src/providers/ipa/ipa_subdomains.c | 10 +++--
src/responder/common/responder_get_domains.c | 9 ++--
src/tests/cmocka/test_fqnames.c | 2 +-
src/tests/cmocka/test_ipa_subdomains_server.c | 2 +-
src/tests/cmocka/test_nss_srv.c | 6 ++-
src/tests/cmocka/test_sysdb_subdomains.c | 25 ++++++-----
src/tests/sysdb-tests.c | 14 +++---
src/tools/common/sss_tools.c | 2 +-
src/tools/sss_cache.c | 2 +-
14 files changed, 107 insertions(+), 40 deletions(-)
diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index 0cbb2c5c02355e9e9a4e73b075f92d16e4855045..6762b51bee02911fb97d5d393fad2495504ee5ad 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -494,7 +494,8 @@ errno_t sysdb_subdomain_store(struct sysdb_ctx *sysdb,
uint32_t trust_direction,
struct ldb_message_element *upn_suffixes);
-errno_t sysdb_update_subdomains(struct sss_domain_info *domain);
+errno_t sysdb_update_subdomains(struct sss_domain_info *domain,
+ struct confdb_ctx *confdb);
errno_t sysdb_master_domain_update(struct sss_domain_info *domain);
diff --git a/src/db/sysdb_private.h b/src/db/sysdb_private.h
index bfd24799950ab3b31d57df11b8f91c0b2572f13a..dfddd2dda9e593bd02d52dee7d06f520a11bbdf6 100644
--- a/src/db/sysdb_private.h
+++ b/src/db/sysdb_private.h
@@ -191,7 +191,8 @@ struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx,
bool enumerate,
const char *forest,
const char **upn_suffixes,
- uint32_t trust_direction);
+ uint32_t trust_direction,
+ struct confdb_ctx *confdb);
/* Helper functions to deal with the timestamp cache should not be used
* outside the sysdb itself. The timestamp cache should be completely
diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c
index 01f49763b712769f4f74df47961526e5b1514cd4..916dbba153d8c08837425f6fd29a20f5a6aa9fc9 100644
--- a/src/db/sysdb_subdomains.c
+++ b/src/db/sysdb_subdomains.c
@@ -23,6 +23,10 @@
#include "util/util.h"
#include "db/sysdb_private.h"
+static errno_t
+check_subdom_config_file(struct confdb_ctx *confdb,
+ struct sss_domain_info *subdomain);
+
struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx,
struct sss_domain_info *parent,
const char *name,
@@ -33,10 +37,12 @@ struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx,
bool enumerate,
const char *forest,
const char **upn_suffixes,
- uint32_t trust_direction)
+ uint32_t trust_direction,
+ struct confdb_ctx *confdb)
{
struct sss_domain_info *dom;
bool inherit_option;
+ errno_t ret;
DEBUG(SSSDBG_TRACE_FUNC,
"Creating [%s] as subdomain of [%s]!\n", name, parent->name);
@@ -160,6 +166,17 @@ struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx,
}
dom->sysdb = parent->sysdb;
+ if (confdb != NULL) {
+ /* If confdb was provided, also check for sssd.conf */
+ ret = check_subdom_config_file(confdb, dom);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to read subdomain configuration [%d]: %s",
+ ret, sss_strerror(ret));
+ goto fail;
+ }
+ }
+
return dom;
fail:
@@ -167,6 +184,45 @@ fail:
return NULL;
}
+static errno_t
+check_subdom_config_file(struct confdb_ctx *confdb,
+ struct sss_domain_info *subdomain)
+{
+ char *sd_conf_path;
+ TALLOC_CTX *tmp_ctx;
+ errno_t ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ sd_conf_path = subdomain_create_conf_path(tmp_ctx, subdomain);
+ if (sd_conf_path == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ /* use_fully_qualified_names */
+ ret = confdb_get_bool(confdb, sd_conf_path, CONFDB_DOMAIN_FQ,
+ true, &subdomain->fqnames);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Failed to get %s option for the subdomain: %s\n",
+ CONFDB_DOMAIN_FQ, subdomain->name);
+ goto done;
+ }
+
+ DEBUG(SSSDBG_CONF_SETTINGS, "%s/%s has value %s\n",
+ sd_conf_path, CONFDB_DOMAIN_FQ,
+ subdomain->fqnames ? "TRUE" : "FALSE");
+
+ ret = EOK;
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
static bool is_forest_root(struct sss_domain_info *d)
{
if (d->forest == NULL) {
@@ -232,7 +288,8 @@ static void link_forest_roots(struct sss_domain_info *domain)
}
}
-errno_t sysdb_update_subdomains(struct sss_domain_info *domain)
+errno_t sysdb_update_subdomains(struct sss_domain_info *domain,
+ struct confdb_ctx *confdb)
{
int i;
errno_t ret;
@@ -451,7 +508,7 @@ errno_t sysdb_update_subdomains(struct sss_domain_info *domain)
if (dom == NULL) {
dom = new_subdomain(domain, domain, name, realm,
flat, id, mpg, enumerate, forest,
- upn_suffixes, trust_direction);
+ upn_suffixes, trust_direction, confdb);
if (dom == NULL) {
ret = ENOMEM;
goto done;
diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
index 284402bc00d37c6c33bf195d2bd719300f265851..1c27742cf0c1b6ffad23ab5b044bf4a168ed8f69 100644
--- a/src/man/sssd.conf.5.xml
+++ b/src/man/sssd.conf.5.xml
@@ -2780,7 +2780,8 @@ subdomain_inherit = ldap_purge_cache_timeout
<para>ldap_service_search_base,</para>
<para>ad_server,</para>
<para>ad_backup_server,</para>
- <para>ad_site.</para>
+ <para>ad_site,</para>
+ <para>use_fully_qualified_names</para>
<para>
For more details about these options see their individual description
in the manual page.
diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
index eecae9c9ca82ad67874c13a3c7b7c617d6232d5c..bc659b2cb0a02723437d24d0021ec3592381e84c 100644
--- a/src/providers/ad/ad_subdomains.c
+++ b/src/providers/ad/ad_subdomains.c
@@ -656,7 +656,8 @@ static errno_t ad_subdom_reinit(struct ad_subdomains_ctx *subdoms_ctx)
/* Just continue */
}
- ret = sysdb_update_subdomains(subdoms_ctx->be_ctx->domain);
+ ret = sysdb_update_subdomains(subdoms_ctx->be_ctx->domain,
+ subdoms_ctx->be_ctx->cdb);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "sysdb_update_subdomains failed.\n");
return ret;
diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
index 7537550606ef09c0b87a80932c75aa4f93c0efab..a07b88fe2f499353293ba90345552413c9792f4b 100644
--- a/src/providers/ipa/ipa_subdomains.c
+++ b/src/providers/ipa/ipa_subdomains.c
@@ -126,7 +126,7 @@ ipa_subdom_reinit(struct ipa_subdomains_ctx *ctx)
return ret;
}
- ret = sysdb_update_subdomains(ctx->be_ctx->domain);
+ ret = sysdb_update_subdomains(ctx->be_ctx->domain, ctx->be_ctx->cdb);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "sysdb_update_subdomains failed.\n");
return ret;
@@ -780,7 +780,8 @@ done:
static errno_t ipa_apply_view(struct sss_domain_info *domain,
struct ipa_id_ctx *ipa_id_ctx,
const char *view_name,
- bool read_at_init)
+ bool read_at_init,
+ struct confdb_ctx *confdb)
{
const char *current = ipa_id_ctx->view_name;
struct sysdb_ctx *sysdb = domain->sysdb;
@@ -876,7 +877,7 @@ static errno_t ipa_apply_view(struct sss_domain_info *domain,
goto done;
}
- ret = sysdb_update_subdomains(domain);
+ ret = sysdb_update_subdomains(domain, confdb);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "sysdb_update_subdomains failed "
"[%d]: %s\n", ret, sss_strerror(ret));
@@ -1654,7 +1655,8 @@ static void ipa_subdomains_view_name_done(struct tevent_req *subreq)
ret = ipa_apply_view(state->sd_ctx->be_ctx->domain,
state->sd_ctx->ipa_id_ctx, view_name,
- state->sd_ctx->view_read_at_init);
+ state->sd_ctx->view_read_at_init,
+ state->sd_ctx->be_ctx->cdb);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, "Unable to set view [%d]: %s\n",
ret, sss_strerror(ret));
diff --git a/src/responder/common/responder_get_domains.c b/src/responder/common/responder_get_domains.c
index 0f39d107dad6c458785b1b8d708e60d7c34e3901..0f9c01214631200f9687635f6302fa5c07e8a1fe 100644
--- a/src/responder/common/responder_get_domains.c
+++ b/src/responder/common/responder_get_domains.c
@@ -126,7 +126,8 @@ get_next_domain_recv(TALLOC_CTX *mem_ctx,
}
/* ====== Iterate over all domains, searching for their subdomains ======= */
-static errno_t process_subdomains(struct sss_domain_info *dom);
+static errno_t process_subdomains(struct sss_domain_info *dom,
+ struct confdb_ctx *confdb);
static void set_time_of_last_request(struct resp_ctx *rctx);
static errno_t check_last_request(struct resp_ctx *rctx, const char *hint);
@@ -234,7 +235,7 @@ sss_dp_get_domains_process(struct tevent_req *subreq)
goto fail;
}
- ret = process_subdomains(state->dom);
+ ret = process_subdomains(state->dom, state->rctx->cdb);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "process_subdomains failed, "
"trying next domain.\n");
@@ -270,7 +271,7 @@ fail:
}
static errno_t
-process_subdomains(struct sss_domain_info *domain)
+process_subdomains(struct sss_domain_info *domain, struct confdb_ctx *confdb)
{
int ret;
@@ -288,7 +289,7 @@ process_subdomains(struct sss_domain_info *domain)
/* Retrieve all subdomains of this domain from sysdb
* and create their struct sss_domain_info representations
*/
- ret = sysdb_update_subdomains(domain);
+ ret = sysdb_update_subdomains(domain, confdb);
if (ret != EOK) {
DEBUG(SSSDBG_FUNC_DATA, "sysdb_update_subdomains failed.\n");
goto done;
diff --git a/src/tests/cmocka/test_fqnames.c b/src/tests/cmocka/test_fqnames.c
index 19788248a39774bb4509363145ac4ce0815b7d28..0ed42a597b7787635c4971b4f1c3d9976949ccd2 100644
--- a/src/tests/cmocka/test_fqnames.c
+++ b/src/tests/cmocka/test_fqnames.c
@@ -309,7 +309,7 @@ static int parse_name_test_setup(void **state)
* discovered
*/
test_ctx->subdom = new_subdomain(dom, dom, SUBDOMNAME, NULL, SUBFLATNAME,
- NULL, false, false, NULL, NULL, 0);
+ NULL, false, false, NULL, NULL, 0, NULL);
assert_non_null(test_ctx->subdom);
check_leaks_push(test_ctx);
diff --git a/src/tests/cmocka/test_ipa_subdomains_server.c b/src/tests/cmocka/test_ipa_subdomains_server.c
index 123cf11c01ef4687eecad31a9d73120a87c643e1..ca48425aca69e58358f5fd37e4b8238bfa9efe15 100644
--- a/src/tests/cmocka/test_ipa_subdomains_server.c
+++ b/src/tests/cmocka/test_ipa_subdomains_server.c
@@ -263,7 +263,7 @@ static void add_test_subdomains(struct trust_test_ctx *test_ctx,
direction, NULL);
assert_int_equal(ret, EOK);
- ret = sysdb_update_subdomains(test_ctx->tctx->dom);
+ ret = sysdb_update_subdomains(test_ctx->tctx->dom, test_ctx->tctx->confdb);
assert_int_equal(ret, EOK);
}
diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c
index 50714715cc80338640f2a77ecbe17bd5e0d6e911..3d7e0382197401cb2264671712152fe0709296b6 100644
--- a/src/tests/cmocka/test_nss_srv.c
+++ b/src/tests/cmocka/test_nss_srv.c
@@ -3206,7 +3206,8 @@ static int nss_subdom_test_setup(void **state)
subdomain = new_subdomain(nss_test_ctx, nss_test_ctx->tctx->dom,
testdom[0], testdom[1], testdom[2], testdom[3],
- false, false, NULL, NULL, 0);
+ false, false, NULL, NULL, 0,
+ nss_test_ctx->tctx->confdb);
assert_non_null(subdomain);
ret = sysdb_subdomain_store(nss_test_ctx->tctx->sysdb,
@@ -3214,7 +3215,8 @@ static int nss_subdom_test_setup(void **state)
false, false, NULL, 0, NULL);
assert_int_equal(ret, EOK);
- ret = sysdb_update_subdomains(nss_test_ctx->tctx->dom);
+ ret = sysdb_update_subdomains(nss_test_ctx->tctx->dom,
+ nss_test_ctx->tctx->confdb);
assert_int_equal(ret, EOK);
nss_test_ctx->subdom = subdomain;
diff --git a/src/tests/cmocka/test_sysdb_subdomains.c b/src/tests/cmocka/test_sysdb_subdomains.c
index 49f44998a06740d1df70ac354ee741824acd8f50..84bcdc17b39dbc8822097c2006f157a09ea5e466 100644
--- a/src/tests/cmocka/test_sysdb_subdomains.c
+++ b/src/tests/cmocka/test_sysdb_subdomains.c
@@ -103,7 +103,7 @@ static void test_sysdb_subdomain_create(void **state)
false, false, NULL, 0, NULL);
assert_int_equal(ret, EOK);
- ret = sysdb_update_subdomains(test_ctx->tctx->dom);
+ ret = sysdb_update_subdomains(test_ctx->tctx->dom, test_ctx->tctx->confdb);
assert_int_equal(ret, EOK);
assert_non_null(test_ctx->tctx->dom->subdomains);
@@ -115,7 +115,7 @@ static void test_sysdb_subdomain_create(void **state)
false, false, NULL, 1, NULL);
assert_int_equal(ret, EOK);
- ret = sysdb_update_subdomains(test_ctx->tctx->dom);
+ ret = sysdb_update_subdomains(test_ctx->tctx->dom, test_ctx->tctx->confdb);
assert_int_equal(ret, EOK);
assert_non_null(test_ctx->tctx->dom->subdomains->next);
@@ -133,7 +133,7 @@ static void test_sysdb_subdomain_create(void **state)
false, false, NULL, 0, NULL);
assert_int_equal(ret, EOK);
- ret = sysdb_update_subdomains(test_ctx->tctx->dom);
+ ret = sysdb_update_subdomains(test_ctx->tctx->dom, test_ctx->tctx->confdb);
assert_int_equal(ret, EOK);
assert_int_equal(test_ctx->tctx->dom->subdomains->trust_direction, 1);
@@ -145,7 +145,7 @@ static void test_sysdb_subdomain_create(void **state)
ret = sysdb_subdomain_delete(test_ctx->tctx->sysdb, dom1[0]);
assert_int_equal(ret, EOK);
- ret = sysdb_update_subdomains(test_ctx->tctx->dom);
+ ret = sysdb_update_subdomains(test_ctx->tctx->dom, test_ctx->tctx->confdb);
assert_int_equal(ret, EOK);
assert_int_equal(sss_domain_get_state(test_ctx->tctx->dom->subdomains),
@@ -235,11 +235,11 @@ static void test_sysdb_link_forest_root_ipa(void **state)
0, NULL);
assert_int_equal(ret, EOK);
- ret = sysdb_update_subdomains(test_ctx->tctx->dom);
+ ret = sysdb_update_subdomains(test_ctx->tctx->dom, test_ctx->tctx->confdb);
assert_int_equal(ret, EOK);
/* Also update dom2 */
- ret = sysdb_update_subdomains(test_ctx->tctx->dom->next);
+ ret = sysdb_update_subdomains(test_ctx->tctx->dom->next, test_ctx->tctx->confdb);
assert_int_equal(ret, EOK);
sub = find_domain_by_name(test_ctx->tctx->dom, dom1[0], true);
@@ -315,11 +315,11 @@ static void test_sysdb_link_forest_root_ad(void **state)
0, NULL);
assert_int_equal(ret, EOK);
- ret = sysdb_update_subdomains(test_ctx->tctx->dom);
+ ret = sysdb_update_subdomains(test_ctx->tctx->dom, test_ctx->tctx->confdb);
assert_int_equal(ret, EOK);
/* Also update dom2 */
- ret = sysdb_update_subdomains(test_ctx->tctx->dom->next);
+ ret = sysdb_update_subdomains(test_ctx->tctx->dom->next, test_ctx->tctx->confdb);
assert_int_equal(ret, EOK);
assert_non_null(test_ctx->tctx->dom->forest_root);
@@ -395,14 +395,15 @@ static void test_sysdb_link_forest_member_ad(void **state)
ret = sysdb_master_domain_update(test_ctx->tctx->dom);
assert_int_equal(ret, EOK);
- ret = sysdb_update_subdomains(test_ctx->tctx->dom);
+ ret = sysdb_update_subdomains(test_ctx->tctx->dom, test_ctx->tctx->confdb);
assert_int_equal(ret, EOK);
/* Also update dom2 */
ret = sysdb_master_domain_update(test_ctx->tctx->dom->next);
assert_int_equal(ret, EOK);
- ret = sysdb_update_subdomains(test_ctx->tctx->dom->next);
+ ret = sysdb_update_subdomains(test_ctx->tctx->dom->next,
+ test_ctx->tctx->confdb);
assert_int_equal(ret, EOK);
/* Checks */
@@ -472,7 +473,7 @@ static void test_sysdb_link_ad_multidom(void **state)
ret = sysdb_master_domain_update(main_dom1);
assert_int_equal(ret, EOK);
- ret = sysdb_update_subdomains(main_dom1);
+ ret = sysdb_update_subdomains(main_dom1, NULL);
assert_int_equal(ret, EOK);
ret = sysdb_master_domain_add_info(main_dom2,
@@ -492,7 +493,7 @@ static void test_sysdb_link_ad_multidom(void **state)
ret = sysdb_master_domain_update(main_dom2);
assert_int_equal(ret, EOK);
- ret = sysdb_update_subdomains(main_dom2);
+ ret = sysdb_update_subdomains(main_dom2, NULL);
assert_int_equal(ret, EOK);
main_dom1 = find_domain_by_name(test_ctx->tctx->dom, TEST_DOM1_NAME, true);
diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c
index 5bdd631fbfa1b4463fb169e5f07b65fb2c784096..1767dc3c734c6b2e5f74564debd603e2442f491b 100644
--- a/src/tests/sysdb-tests.c
+++ b/src/tests/sysdb-tests.c
@@ -1395,7 +1395,7 @@ START_TEST (test_sysdb_get_user_attr_subdomain)
/* Create subdomain */
subdomain = new_subdomain(test_ctx, test_ctx->domain,
"test.sub", "TEST.SUB", "test", "S-3",
- false, false, NULL, NULL, 0);
+ false, false, NULL, NULL, 0, NULL);
fail_if(subdomain == NULL, "Failed to create new subdomain.");
ret = sss_names_init_from_args(test_ctx,
@@ -5821,14 +5821,14 @@ START_TEST(test_sysdb_subdomain_store_user)
subdomain = new_subdomain(test_ctx, test_ctx->domain,
testdom[0], testdom[1], testdom[2], testdom[3],
- false, false, NULL, NULL, 0);
+ false, false, NULL, NULL, 0, NULL);
fail_unless(subdomain != NULL, "Failed to create new subdomin.");
ret = sysdb_subdomain_store(test_ctx->sysdb,
testdom[0], testdom[1], testdom[2], testdom[3],
false, false, NULL, 0, NULL);
fail_if(ret != EOK, "Could not set up the test (test subdom)");
- ret = sysdb_update_subdomains(test_ctx->domain);
+ ret = sysdb_update_subdomains(test_ctx->domain, NULL);
fail_unless(ret == EOK, "sysdb_update_subdomains failed with [%d][%s]",
ret, strerror(ret));
@@ -5900,14 +5900,14 @@ START_TEST(test_sysdb_subdomain_user_ops)
subdomain = new_subdomain(test_ctx, test_ctx->domain,
testdom[0], testdom[1], testdom[2], testdom[3],
- false, false, NULL, NULL, 0);
+ false, false, NULL, NULL, 0, NULL);
fail_unless(subdomain != NULL, "Failed to create new subdomin.");
ret = sysdb_subdomain_store(test_ctx->sysdb,
testdom[0], testdom[1], testdom[2], testdom[3],
false, false, NULL, 0, NULL);
fail_if(ret != EOK, "Could not set up the test (test subdom)");
- ret = sysdb_update_subdomains(test_ctx->domain);
+ ret = sysdb_update_subdomains(test_ctx->domain, NULL);
fail_unless(ret == EOK, "sysdb_update_subdomains failed with [%d][%s]",
ret, strerror(ret));
@@ -5973,14 +5973,14 @@ START_TEST(test_sysdb_subdomain_group_ops)
subdomain = new_subdomain(test_ctx, test_ctx->domain,
testdom[0], testdom[1], testdom[2], testdom[3],
- false, false, NULL, NULL, 0);
+ false, false, NULL, NULL, 0, NULL);
fail_unless(subdomain != NULL, "Failed to create new subdomin.");
ret = sysdb_subdomain_store(test_ctx->sysdb,
testdom[0], testdom[1], testdom[2], testdom[3],
false, false, NULL, 0, NULL);
fail_if(ret != EOK, "Could not set up the test (test subdom)");
- ret = sysdb_update_subdomains(test_ctx->domain);
+ ret = sysdb_update_subdomains(test_ctx->domain, NULL);
fail_unless(ret == EOK, "sysdb_update_subdomains failed with [%d][%s]",
ret, strerror(ret));
diff --git a/src/tools/common/sss_tools.c b/src/tools/common/sss_tools.c
index 0f4f46894130daf722641f25a4cdfaae220252cc..97a3caab3bec88c5727eea2f08b200f1d3b23f0c 100644
--- a/src/tools/common/sss_tools.c
+++ b/src/tools/common/sss_tools.c
@@ -154,7 +154,7 @@ static errno_t sss_tool_domains_init(TALLOC_CTX *mem_ctx,
}
/* Update list of subdomains for this domain */
- ret = sysdb_update_subdomains(dom);
+ ret = sysdb_update_subdomains(dom, confdb);
if (ret != EOK) {
DEBUG(SSSDBG_MINOR_FAILURE,
"Failed to update subdomains for domain %s.\n",
diff --git a/src/tools/sss_cache.c b/src/tools/sss_cache.c
index 59e49a8aa92e3a08ec80e0597304f1a4af0a02be..8a40b38c07f7e76cde5b98e5916816581fea7973 100644
--- a/src/tools/sss_cache.c
+++ b/src/tools/sss_cache.c
@@ -158,7 +158,7 @@ int main(int argc, const char *argv[])
dinfo = get_next_domain(dinfo, SSS_GND_DESCEND)) {
if (!IS_SUBDOMAIN(dinfo)) {
/* Update list of subdomains for this domain */
- ret = sysdb_update_subdomains(dinfo);
+ ret = sysdb_update_subdomains(dinfo, tctx->confdb);
if (ret != EOK) {
DEBUG(SSSDBG_MINOR_FAILURE,
"Failed to update subdomains for domain %s.\n", dinfo->name);
--
2.12.2

View File

@ -1,172 +0,0 @@
From dcc52d9c6411528bab815351d1e6145d211a4765 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= <fidencio@redhat.com>
Date: Wed, 1 Mar 2017 08:34:57 +0000
Subject: [PATCH 45/97] CACHE_REQ: Descend into subdomains on lookups
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Let's make all plugins, but the "host_by_name", to descend into the
subdomains on lookups.
This patch basically prepares the field for the coming up patches that
will allow group/user resolution in all domains (or a subset of the
domains) to be possible by only using the short names without the domain
component.
The "host_by_name" plugin was not changed as it's a specific IPA plugin
and won't find anything on its subdomains.
Related:
https://pagure.io/SSSD/sssd/issue/3001
Signed-off-by: Fabiano Fidêncio <fidencio@redhat.com>
Reviewed-by: Pavel Březina <pbrezina@redhat.com>
Reviewed-by: Sumit Bose <sbose@redhat.com>
---
src/responder/common/cache_req/plugins/cache_req_enum_svc.c | 2 +-
src/responder/common/cache_req/plugins/cache_req_group_by_filter.c | 2 +-
src/responder/common/cache_req/plugins/cache_req_group_by_name.c | 2 +-
src/responder/common/cache_req/plugins/cache_req_initgroups_by_name.c | 2 +-
src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c | 2 +-
src/responder/common/cache_req/plugins/cache_req_object_by_name.c | 2 +-
src/responder/common/cache_req/plugins/cache_req_svc_by_name.c | 2 +-
src/responder/common/cache_req/plugins/cache_req_svc_by_port.c | 2 +-
src/responder/common/cache_req/plugins/cache_req_user_by_filter.c | 2 +-
src/responder/common/cache_req/plugins/cache_req_user_by_name.c | 2 +-
10 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/src/responder/common/cache_req/plugins/cache_req_enum_svc.c b/src/responder/common/cache_req/plugins/cache_req_enum_svc.c
index 2c4917cde750c9063d898c16d3a58ca8c179bc70..28dea33c601f500b9c7af0de3eb9e1c342f03522 100644
--- a/src/responder/common/cache_req/plugins/cache_req_enum_svc.c
+++ b/src/responder/common/cache_req/plugins/cache_req_enum_svc.c
@@ -68,7 +68,7 @@ const struct cache_req_plugin cache_req_enum_svc = {
.allow_missing_fqn = true,
.allow_switch_to_upn = false,
.upn_equivalent = CACHE_REQ_SENTINEL,
- .get_next_domain_flags = 0,
+ .get_next_domain_flags = SSS_GND_DESCEND,
.is_well_known_fn = NULL,
.prepare_domain_data_fn = NULL,
diff --git a/src/responder/common/cache_req/plugins/cache_req_group_by_filter.c b/src/responder/common/cache_req/plugins/cache_req_group_by_filter.c
index 88e1137a3976308aaf404b684c6d88cc43708bca..6ce6ae0d63967ac50b813a47ac938251619948da 100644
--- a/src/responder/common/cache_req/plugins/cache_req_group_by_filter.c
+++ b/src/responder/common/cache_req/plugins/cache_req_group_by_filter.c
@@ -123,7 +123,7 @@ const struct cache_req_plugin cache_req_group_by_filter = {
.allow_missing_fqn = false,
.allow_switch_to_upn = false,
.upn_equivalent = CACHE_REQ_SENTINEL,
- .get_next_domain_flags = 0,
+ .get_next_domain_flags = SSS_GND_DESCEND,
.is_well_known_fn = NULL,
.prepare_domain_data_fn = cache_req_group_by_filter_prepare_domain_data,
diff --git a/src/responder/common/cache_req/plugins/cache_req_group_by_name.c b/src/responder/common/cache_req/plugins/cache_req_group_by_name.c
index be1eb9bd8552156d777e934b0be397b0e66df7cc..af6f23ccfd68f952027462ba3e74ed7219d04651 100644
--- a/src/responder/common/cache_req/plugins/cache_req_group_by_name.c
+++ b/src/responder/common/cache_req/plugins/cache_req_group_by_name.c
@@ -186,7 +186,7 @@ const struct cache_req_plugin cache_req_group_by_name = {
.allow_missing_fqn = false,
.allow_switch_to_upn = false,
.upn_equivalent = CACHE_REQ_SENTINEL,
- .get_next_domain_flags = 0,
+ .get_next_domain_flags = SSS_GND_DESCEND,
.is_well_known_fn = NULL,
.prepare_domain_data_fn = cache_req_group_by_name_prepare_domain_data,
diff --git a/src/responder/common/cache_req/plugins/cache_req_initgroups_by_name.c b/src/responder/common/cache_req/plugins/cache_req_initgroups_by_name.c
index 10fb67cbf6e78cfae33bc7208585cb80ea6a9bc4..307b65a24282838b99c472b50a71f06865aed3f0 100644
--- a/src/responder/common/cache_req/plugins/cache_req_initgroups_by_name.c
+++ b/src/responder/common/cache_req/plugins/cache_req_initgroups_by_name.c
@@ -201,7 +201,7 @@ const struct cache_req_plugin cache_req_initgroups_by_name = {
.allow_missing_fqn = false,
.allow_switch_to_upn = true,
.upn_equivalent = CACHE_REQ_INITGROUPS_BY_UPN,
- .get_next_domain_flags = 0,
+ .get_next_domain_flags = SSS_GND_DESCEND,
.is_well_known_fn = NULL,
.prepare_domain_data_fn = cache_req_initgroups_by_name_prepare_domain_data,
diff --git a/src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c b/src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c
index bc6fc9a8f476f97cc4bc5004bc19ba35258a2b6d..e49d6d84a41ce8dabf18c87373826f8e7b684bda 100644
--- a/src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c
+++ b/src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c
@@ -120,7 +120,7 @@ const struct cache_req_plugin cache_req_netgroup_by_name = {
.allow_missing_fqn = true,
.allow_switch_to_upn = false,
.upn_equivalent = CACHE_REQ_SENTINEL,
- .get_next_domain_flags = 0,
+ .get_next_domain_flags = SSS_GND_DESCEND,
.is_well_known_fn = NULL,
.prepare_domain_data_fn = cache_req_netgroup_by_name_prepare_domain_data,
diff --git a/src/responder/common/cache_req/plugins/cache_req_object_by_name.c b/src/responder/common/cache_req/plugins/cache_req_object_by_name.c
index 2b2caeea172b23b1b1b226def5d926e26c5c0090..74d2b3dea287e890b38e4d5bb176ad2dc6337b7e 100644
--- a/src/responder/common/cache_req/plugins/cache_req_object_by_name.c
+++ b/src/responder/common/cache_req/plugins/cache_req_object_by_name.c
@@ -196,7 +196,7 @@ const struct cache_req_plugin cache_req_object_by_name = {
.allow_missing_fqn = false,
.allow_switch_to_upn = true,
.upn_equivalent = CACHE_REQ_USER_BY_UPN,
- .get_next_domain_flags = 0,
+ .get_next_domain_flags = SSS_GND_DESCEND,
.is_well_known_fn = cache_req_object_by_name_well_known,
.prepare_domain_data_fn = cache_req_object_by_name_prepare_domain_data,
diff --git a/src/responder/common/cache_req/plugins/cache_req_svc_by_name.c b/src/responder/common/cache_req/plugins/cache_req_svc_by_name.c
index cbb186df04c7ca7c02dceb98bd5700c984285a4d..ef13f097a8ae78ec9db5b7f6e14924b511578b34 100644
--- a/src/responder/common/cache_req/plugins/cache_req_svc_by_name.c
+++ b/src/responder/common/cache_req/plugins/cache_req_svc_by_name.c
@@ -144,7 +144,7 @@ const struct cache_req_plugin cache_req_svc_by_name = {
.allow_missing_fqn = false,
.allow_switch_to_upn = false,
.upn_equivalent = CACHE_REQ_SENTINEL,
- .get_next_domain_flags = 0,
+ .get_next_domain_flags = SSS_GND_DESCEND,
.is_well_known_fn = NULL,
.prepare_domain_data_fn = cache_req_svc_by_name_prepare_domain_data,
diff --git a/src/responder/common/cache_req/plugins/cache_req_svc_by_port.c b/src/responder/common/cache_req/plugins/cache_req_svc_by_port.c
index 1da23d4505a1dad3b2425a996134f8298c03518a..afa2eeeda12794de26e798aee4b88900bc87ed93 100644
--- a/src/responder/common/cache_req/plugins/cache_req_svc_by_port.c
+++ b/src/responder/common/cache_req/plugins/cache_req_svc_by_port.c
@@ -117,7 +117,7 @@ const struct cache_req_plugin cache_req_svc_by_port = {
.allow_missing_fqn = false,
.allow_switch_to_upn = false,
.upn_equivalent = CACHE_REQ_SENTINEL,
- .get_next_domain_flags = 0,
+ .get_next_domain_flags = SSS_GND_DESCEND,
.is_well_known_fn = NULL,
.prepare_domain_data_fn = cache_req_svc_by_port_prepare_domain_data,
diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_filter.c b/src/responder/common/cache_req/plugins/cache_req_user_by_filter.c
index ee7e69399e318b9835f1623bddc635bf09aa7a1c..eb71b42dad3a805298df0c8425409d571befb31b 100644
--- a/src/responder/common/cache_req/plugins/cache_req_user_by_filter.c
+++ b/src/responder/common/cache_req/plugins/cache_req_user_by_filter.c
@@ -123,7 +123,7 @@ const struct cache_req_plugin cache_req_user_by_filter = {
.allow_missing_fqn = false,
.allow_switch_to_upn = false,
.upn_equivalent = CACHE_REQ_SENTINEL,
- .get_next_domain_flags = 0,
+ .get_next_domain_flags = SSS_GND_DESCEND,
.is_well_known_fn = NULL,
.prepare_domain_data_fn = cache_req_user_by_filter_prepare_domain_data,
diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_name.c b/src/responder/common/cache_req/plugins/cache_req_user_by_name.c
index 4289f5fd4c79f0e512f0249abe4422589fa800a0..0670febdce2d51e0373045570dd07f56255db7bc 100644
--- a/src/responder/common/cache_req/plugins/cache_req_user_by_name.c
+++ b/src/responder/common/cache_req/plugins/cache_req_user_by_name.c
@@ -191,7 +191,7 @@ const struct cache_req_plugin cache_req_user_by_name = {
.allow_missing_fqn = false,
.allow_switch_to_upn = true,
.upn_equivalent = CACHE_REQ_USER_BY_UPN,
- .get_next_domain_flags = 0,
+ .get_next_domain_flags = SSS_GND_DESCEND,
.is_well_known_fn = NULL,
.prepare_domain_data_fn = cache_req_user_by_name_prepare_domain_data,
--
2.12.2

View File

@ -1,35 +0,0 @@
From 46c99a59c8d6501aa3ad701c567fba577924b48b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Wed, 1 Mar 2017 13:21:19 +0000
Subject: [PATCH 46/97] NSS/TESTS: Fix subdomains attribution
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Related:
https://pagure.io/SSSD/sssd/issue/3001
Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
Reviewed-by: Sumit Bose <sbose@redhat.com>
Reviewed-by: Pavel Březina <pbrezina@redhat.com>
---
src/tests/cmocka/test_nss_srv.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c
index 3d7e0382197401cb2264671712152fe0709296b6..cbe0dccdc1d883eae1a9621f12997ef43d05178e 100644
--- a/src/tests/cmocka/test_nss_srv.c
+++ b/src/tests/cmocka/test_nss_srv.c
@@ -3219,7 +3219,7 @@ static int nss_subdom_test_setup(void **state)
nss_test_ctx->tctx->confdb);
assert_int_equal(ret, EOK);
- nss_test_ctx->subdom = subdomain;
+ nss_test_ctx->subdom = nss_test_ctx->tctx->dom->subdomains;
return 0;
}
--
2.12.2

View File

@ -1,274 +0,0 @@
From a3442e4a268ad2172c89d58e6daa759eb4b39e7c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= <fidencio@redhat.com>
Date: Wed, 1 Mar 2017 20:46:10 +0000
Subject: [PATCH 47/97] NSS/TESTS: Improve setup/teardown for subdomains tests
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This patch basically makes the getgrnam_members_subdom(),
getgrnam_mix_dom(), getgrnam_mix_dom_fqdn() and getgrnam_mix_subdom()
more independent of each other.
Related:
https://pagure.io/SSSD/sssd/issue/3001
Signed-off-by: Fabiano Fidêncio <fidencio@redhat.com>
Reviewed-by: Sumit Bose <sbose@redhat.com>
Reviewed-by: Pavel Březina <pbrezina@redhat.com>
---
src/tests/cmocka/test_nss_srv.c | 182 +++++++++++++++++++++++++++++++++-------
1 file changed, 150 insertions(+), 32 deletions(-)
diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c
index cbe0dccdc1d883eae1a9621f12997ef43d05178e..b468204fb1729618830513322f0d901c4c801e94 100644
--- a/src/tests/cmocka/test_nss_srv.c
+++ b/src/tests/cmocka/test_nss_srv.c
@@ -418,6 +418,26 @@ static errno_t store_user(struct nss_test_ctx *ctx,
return ret;
}
+static errno_t delete_user(struct nss_test_ctx *ctx,
+ struct sss_domain_info *dom,
+ struct passwd *user)
+{
+ errno_t ret;
+ char *fqname;
+
+ fqname = sss_create_internal_fqname(ctx,
+ user->pw_name,
+ dom->name);
+ if (fqname == NULL) {
+ return ENOMEM;
+ }
+
+ ret = sysdb_delete_user(dom, fqname, user->pw_uid);
+
+ talloc_free(fqname);
+ return ret;
+}
+
static errno_t set_user_attr(struct nss_test_ctx *ctx,
struct sss_domain_info *dom,
struct passwd *user,
@@ -491,6 +511,27 @@ static errno_t store_group(struct nss_test_ctx *ctx,
return ret;
}
+static errno_t delete_group(struct nss_test_ctx *ctx,
+ struct sss_domain_info *dom,
+ struct group *group)
+{
+ errno_t ret;
+ char *fqname;
+
+ fqname = sss_create_internal_fqname(ctx,
+ group->gr_name,
+ dom->name);
+
+ if (fqname == NULL) {
+ return ENOMEM;
+ }
+
+ ret = sysdb_delete_group(dom, fqname, group->gr_gid);
+
+ talloc_free(fqname);
+ return ret;
+}
+
static void assert_groups_equal(struct group *expected,
struct group *gr, const int nmem)
{
@@ -540,6 +581,42 @@ static errno_t store_group_member(struct nss_test_ctx *ctx,
return ret;
}
+static errno_t remove_group_member(struct nss_test_ctx *ctx,
+ const char *shortname_group,
+ struct sss_domain_info *group_dom,
+ const char *shortname_member,
+ struct sss_domain_info *member_dom,
+ enum sysdb_member_type type)
+{
+ errno_t ret;
+ char *group_fqname = NULL;
+ char *member_fqname = NULL;
+
+ group_fqname = sss_create_internal_fqname(ctx,
+ shortname_group,
+ group_dom->name);
+ if (group_fqname == NULL) {
+ return ENOMEM;
+ }
+
+ member_fqname = sss_create_internal_fqname(ctx,
+ shortname_member,
+ member_dom->name);
+ if (member_fqname == NULL) {
+ talloc_free(group_fqname);
+ return ENOMEM;
+ }
+
+ ret = sysdb_remove_group_member(group_dom,
+ group_fqname,
+ member_fqname,
+ type,
+ false);
+
+ talloc_free(group_fqname);
+ talloc_free(member_fqname);
+ return ret;
+}
/* ====================== The tests =============================== */
struct passwd getpwnam_usr = {
@@ -1599,34 +1676,6 @@ void test_nss_getgrnam_members_subdom(void **state)
{
errno_t ret;
- ret = store_group(nss_test_ctx, nss_test_ctx->subdom,
- &testsubdomgroup, 0);
- assert_int_equal(ret, EOK);
-
- ret = store_user(nss_test_ctx, nss_test_ctx->subdom,
- &submember1, NULL, 0);
- assert_int_equal(ret, EOK);
-
- ret = store_user(nss_test_ctx, nss_test_ctx->subdom,
- &submember2, NULL, 0);
- assert_int_equal(ret, EOK);
-
- ret = store_group_member(nss_test_ctx,
- testsubdomgroup.gr_name,
- nss_test_ctx->subdom,
- submember1.pw_name,
- nss_test_ctx->subdom,
- SYSDB_MEMBER_USER);
- assert_int_equal(ret, EOK);
-
- ret = store_group_member(nss_test_ctx,
- testsubdomgroup.gr_name,
- nss_test_ctx->subdom,
- submember2.pw_name,
- nss_test_ctx->subdom,
- SYSDB_MEMBER_USER);
- assert_int_equal(ret, EOK);
-
mock_input_user_or_group("testsubdomgroup@"TEST_SUBDOM_NAME);
will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRNAM);
will_return_always(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
@@ -1757,6 +1806,14 @@ void test_nss_getgrnam_mix_dom_fqdn(void **state)
{
errno_t ret;
+ ret = store_group_member(nss_test_ctx,
+ testgroup_members.gr_name,
+ nss_test_ctx->tctx->dom,
+ submember1.pw_name,
+ nss_test_ctx->subdom,
+ SYSDB_MEMBER_USER);
+ assert_int_equal(ret, EOK);
+
nss_test_ctx->tctx->dom->fqnames = true;
mock_input_user_or_group("testgroup_members@"TEST_DOM_NAME);
@@ -3220,6 +3277,35 @@ static int nss_subdom_test_setup(void **state)
assert_int_equal(ret, EOK);
nss_test_ctx->subdom = nss_test_ctx->tctx->dom->subdomains;
+
+ ret = store_group(nss_test_ctx, nss_test_ctx->subdom,
+ &testsubdomgroup, 0);
+ assert_int_equal(ret, EOK);
+
+ ret = store_user(nss_test_ctx, nss_test_ctx->subdom,
+ &submember1, NULL, 0);
+ assert_int_equal(ret, EOK);
+
+ ret = store_user(nss_test_ctx, nss_test_ctx->subdom,
+ &submember2, NULL, 0);
+ assert_int_equal(ret, EOK);
+
+ ret = store_group_member(nss_test_ctx,
+ testsubdomgroup.gr_name,
+ nss_test_ctx->subdom,
+ submember1.pw_name,
+ nss_test_ctx->subdom,
+ SYSDB_MEMBER_USER);
+ assert_int_equal(ret, EOK);
+
+ ret = store_group_member(nss_test_ctx,
+ testsubdomgroup.gr_name,
+ nss_test_ctx->subdom,
+ submember2.pw_name,
+ nss_test_ctx->subdom,
+ SYSDB_MEMBER_USER);
+ assert_int_equal(ret, EOK);
+
return 0;
}
@@ -3241,6 +3327,38 @@ static int nss_test_teardown(void **state)
return 0;
}
+static int nss_subdom_test_teardown(void **state)
+{
+ errno_t ret;
+
+ ret = remove_group_member(nss_test_ctx,
+ testsubdomgroup.gr_name,
+ nss_test_ctx->subdom,
+ submember2.pw_name,
+ nss_test_ctx->subdom,
+ SYSDB_MEMBER_USER);
+ assert_int_equal(ret, EOK);
+
+ ret = remove_group_member(nss_test_ctx,
+ testsubdomgroup.gr_name,
+ nss_test_ctx->subdom,
+ submember1.pw_name,
+ nss_test_ctx->subdom,
+ SYSDB_MEMBER_USER);
+ assert_int_equal(ret, EOK);
+
+ ret = delete_user(nss_test_ctx, nss_test_ctx->subdom, &submember2);
+ assert_int_equal(ret, EOK);
+
+ ret = delete_user(nss_test_ctx, nss_test_ctx->subdom, &submember1);
+ assert_int_equal(ret, EOK);
+
+ ret = delete_group(nss_test_ctx, nss_test_ctx->subdom, &testsubdomgroup);
+ assert_int_equal(ret, EOK);
+
+ return nss_test_teardown(state);
+}
+
struct passwd testbysid = {
.pw_name = discard_const("testsiduser"),
.pw_uid = 12345,
@@ -3904,16 +4022,16 @@ int main(int argc, const char *argv[])
nss_fqdn_test_setup, nss_test_teardown),
cmocka_unit_test_setup_teardown(test_nss_getgrnam_members_subdom,
nss_subdom_test_setup,
- nss_test_teardown),
+ nss_subdom_test_teardown),
cmocka_unit_test_setup_teardown(test_nss_getgrnam_mix_dom,
nss_subdom_test_setup,
- nss_test_teardown),
+ nss_subdom_test_teardown),
cmocka_unit_test_setup_teardown(test_nss_getgrnam_mix_dom_fqdn,
nss_subdom_test_setup,
- nss_test_teardown),
+ nss_subdom_test_teardown),
cmocka_unit_test_setup_teardown(test_nss_getgrnam_mix_subdom,
nss_subdom_test_setup,
- nss_test_teardown),
+ nss_subdom_test_teardown),
cmocka_unit_test_setup_teardown(test_nss_getgrnam_space,
nss_test_setup, nss_test_teardown),
cmocka_unit_test_setup_teardown(test_nss_getgrnam_space_sub,
--
2.12.2

View File

@ -1,355 +0,0 @@
From 5856a621ac5909ca96520ac5a809eb83fd46d8bc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= <fidencio@redhat.com>
Date: Wed, 1 Mar 2017 08:33:06 +0000
Subject: [PATCH 48/97] NSS/TESTS: Include searches for non-fqnames members of
a subdomain
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Let's extend the NSS tests in order to also test looking up users, from
a subdomain, by their short names (non fully qualified names).
Related:
https://pagure.io/SSSD/sssd/issue/3001
Signed-off-by: Fabiano Fidêncio <fidencio@redhat.com>
Reviewed-by: Sumit Bose <sbose@redhat.com>
Reviewed-by: Pavel Březina <pbrezina@redhat.com>
---
src/tests/cmocka/test_nss_srv.c | 246 ++++++++++++++++++++++++++++++++++------
1 file changed, 211 insertions(+), 35 deletions(-)
diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c
index b468204fb1729618830513322f0d901c4c801e94..ede72b341b60842ad470df2794aa90ea9797e999 100644
--- a/src/tests/cmocka/test_nss_srv.c
+++ b/src/tests/cmocka/test_nss_srv.c
@@ -1648,16 +1648,29 @@ static int test_nss_getgrnam_members_check_subdom(uint32_t status,
tmp_ctx = talloc_new(nss_test_ctx);
assert_non_null(tmp_ctx);
- exp_members[0] = sss_tc_fqname(tmp_ctx, nss_test_ctx->subdom->names,
- nss_test_ctx->subdom, submember1.pw_name);
- assert_non_null(exp_members[0]);
- exp_members[1] = sss_tc_fqname(tmp_ctx, nss_test_ctx->subdom->names,
- nss_test_ctx->subdom, submember2.pw_name);
- assert_non_null(exp_members[1]);
+ if (nss_test_ctx->subdom->fqnames) {
+ exp_members[0] = sss_tc_fqname(tmp_ctx,
+ nss_test_ctx->subdom->names,
+ nss_test_ctx->subdom,
+ submember1.pw_name);
+ assert_non_null(exp_members[0]);
- expected.gr_name = sss_tc_fqname(tmp_ctx, nss_test_ctx->subdom->names,
- nss_test_ctx->subdom, testsubdomgroup.gr_name);
- assert_non_null(expected.gr_name);
+ exp_members[1] = sss_tc_fqname(tmp_ctx,
+ nss_test_ctx->subdom->names,
+ nss_test_ctx->subdom,
+ submember2.pw_name);
+ assert_non_null(exp_members[1]);
+
+ expected.gr_name = sss_tc_fqname(tmp_ctx,
+ nss_test_ctx->subdom->names,
+ nss_test_ctx->subdom,
+ testsubdomgroup.gr_name);
+ assert_non_null(expected.gr_name);
+ } else {
+ exp_members[0] = submember1.pw_name;
+ exp_members[1] = submember2.pw_name;
+ expected.gr_name = testsubdomgroup.gr_name;
+ }
assert_int_equal(status, EOK);
@@ -1692,6 +1705,29 @@ void test_nss_getgrnam_members_subdom(void **state)
assert_int_equal(ret, EOK);
}
+void test_nss_getgrnam_members_subdom_nonfqnames(void **state)
+{
+ errno_t ret;
+
+ nss_test_ctx->subdom->fqnames = false;
+
+ mock_input_user_or_group("testsubdomgroup");
+ mock_account_recv_simple();
+ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRNAM);
+ will_return_always(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
+
+ /* Query for that group, call a callback when command finishes */
+ set_cmd_cb(test_nss_getgrnam_members_check_subdom);
+ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRNAM,
+ 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);
+}
+
static int test_nss_getgrnam_check_mix_dom(uint32_t status,
uint8_t *body, size_t blen)
{
@@ -1710,9 +1746,15 @@ static int test_nss_getgrnam_check_mix_dom(uint32_t status,
tmp_ctx = talloc_new(nss_test_ctx);
assert_non_null(tmp_ctx);
- exp_members[0] = sss_tc_fqname(tmp_ctx, nss_test_ctx->subdom->names,
- nss_test_ctx->subdom, submember1.pw_name);
- assert_non_null(exp_members[0]);
+ if (nss_test_ctx->subdom->fqnames) {
+ exp_members[0] = sss_tc_fqname(tmp_ctx,
+ nss_test_ctx->subdom->names,
+ nss_test_ctx->subdom,
+ submember1.pw_name);
+ assert_non_null(exp_members[0]);
+ } else {
+ exp_members[0] = submember1.pw_name;
+ }
exp_members[1] = testmember1.pw_name;
exp_members[2] = testmember2.pw_name;
@@ -1756,6 +1798,35 @@ void test_nss_getgrnam_mix_dom(void **state)
assert_int_equal(ret, EOK);
}
+void test_nss_getgrnam_mix_dom_nonfqnames(void **state)
+{
+ errno_t ret;
+
+ nss_test_ctx->subdom->fqnames = false;
+
+ ret = store_group_member(nss_test_ctx,
+ testgroup_members.gr_name,
+ nss_test_ctx->tctx->dom,
+ submember1.pw_name,
+ nss_test_ctx->subdom,
+ SYSDB_MEMBER_USER);
+ assert_int_equal(ret, EOK);
+
+ mock_input_user_or_group("testgroup_members");
+ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRNAM);
+ will_return_always(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
+
+ /* Query for that group, call a callback when command finishes */
+ set_cmd_cb(test_nss_getgrnam_check_mix_dom);
+ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRNAM,
+ 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);
+}
+
static int test_nss_getgrnam_check_mix_dom_fqdn(uint32_t status,
uint8_t *body, size_t blen)
{
@@ -1773,21 +1844,33 @@ static int test_nss_getgrnam_check_mix_dom_fqdn(uint32_t status,
tmp_ctx = talloc_new(nss_test_ctx);
assert_non_null(tmp_ctx);
- exp_members[0] = sss_tc_fqname(tmp_ctx, nss_test_ctx->subdom->names,
- nss_test_ctx->subdom, submember1.pw_name);
- assert_non_null(exp_members[0]);
- exp_members[1] = sss_tc_fqname(tmp_ctx, nss_test_ctx->tctx->dom->names,
- nss_test_ctx->tctx->dom, testmember1.pw_name);
- assert_non_null(exp_members[1]);
- exp_members[2] = sss_tc_fqname(tmp_ctx, nss_test_ctx->tctx->dom->names,
- nss_test_ctx->tctx->dom, testmember2.pw_name);
- assert_non_null(exp_members[2]);
+ if (nss_test_ctx->subdom->fqnames) {
+ exp_members[0] = sss_tc_fqname(tmp_ctx,
+ nss_test_ctx->subdom->names,
+ nss_test_ctx->subdom,
+ submember1.pw_name);
+ assert_non_null(exp_members[0]);
+ } else {
+ exp_members[0] = submember1.pw_name;
+ }
+ if (nss_test_ctx->tctx->dom->fqnames) {
+ exp_members[1] = sss_tc_fqname(tmp_ctx, nss_test_ctx->tctx->dom->names,
+ nss_test_ctx->tctx->dom, testmember1.pw_name);
+ assert_non_null(exp_members[1]);
+ exp_members[2] = sss_tc_fqname(tmp_ctx, nss_test_ctx->tctx->dom->names,
+ nss_test_ctx->tctx->dom, testmember2.pw_name);
+ assert_non_null(exp_members[2]);
- expected.gr_name = sss_tc_fqname(tmp_ctx,
- nss_test_ctx->tctx->dom->names,
- nss_test_ctx->tctx->dom,
- testgroup_members.gr_name);
- assert_non_null(expected.gr_name);
+ expected.gr_name = sss_tc_fqname(tmp_ctx,
+ nss_test_ctx->tctx->dom->names,
+ nss_test_ctx->tctx->dom,
+ testgroup_members.gr_name);
+ assert_non_null(expected.gr_name);
+ } else {
+ exp_members[1] = testmember1.pw_name;
+ exp_members[2] = testmember2.pw_name;
+ expected.gr_name = testgroup_members.gr_name;
+ }
assert_int_equal(status, EOK);
@@ -1834,6 +1917,40 @@ void test_nss_getgrnam_mix_dom_fqdn(void **state)
assert_int_equal(ret, EOK);
}
+void test_nss_getgrnam_mix_dom_fqdn_nonfqnames(void **state)
+{
+ errno_t ret;
+
+ ret = store_group_member(nss_test_ctx,
+ testgroup_members.gr_name,
+ nss_test_ctx->tctx->dom,
+ submember1.pw_name,
+ nss_test_ctx->subdom,
+ SYSDB_MEMBER_USER);
+ assert_int_equal(ret, EOK);
+
+ nss_test_ctx->tctx->dom->fqnames = false;
+ nss_test_ctx->subdom->fqnames = false;
+
+
+ mock_input_user_or_group("testgroup_members");
+ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRNAM);
+ will_return_always(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
+
+ /* Query for that group, call a callback when command finishes */
+ set_cmd_cb(test_nss_getgrnam_check_mix_dom_fqdn);
+ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRNAM,
+ 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);
+
+ /* Restore FQDN settings */
+ nss_test_ctx->tctx->dom->fqnames = false;
+ assert_int_equal(ret, EOK);
+}
+
static int test_nss_getgrnam_check_mix_subdom(uint32_t status,
uint8_t *body, size_t blen)
{
@@ -1851,20 +1968,37 @@ static int test_nss_getgrnam_check_mix_subdom(uint32_t status,
tmp_ctx = talloc_new(nss_test_ctx);
assert_non_null(tmp_ctx);
- exp_members[0] = sss_tc_fqname(tmp_ctx, nss_test_ctx->subdom->names,
- nss_test_ctx->subdom, submember1.pw_name);
- assert_non_null(exp_members[0]);
- exp_members[1] = sss_tc_fqname(tmp_ctx, nss_test_ctx->subdom->names,
- nss_test_ctx->subdom, submember2.pw_name);
- assert_non_null(exp_members[1]);
+ if (nss_test_ctx->subdom->fqnames) {
+ exp_members[0] = sss_tc_fqname(tmp_ctx,
+ nss_test_ctx->subdom->names,
+ nss_test_ctx->subdom,
+ submember1.pw_name);
+ assert_non_null(exp_members[0]);
+
+ exp_members[1] = sss_tc_fqname(tmp_ctx,
+ nss_test_ctx->subdom->names,
+ nss_test_ctx->subdom,
+ submember2.pw_name);
+ assert_non_null(exp_members[1]);
+ } else {
+ exp_members[0] = submember1.pw_name;
+ exp_members[1] = submember2.pw_name;
+ }
+
/* Important: this member is from a non-qualified domain, so his name will
* not be qualified either
*/
exp_members[2] = testmember1.pw_name;
- expected.gr_name = sss_tc_fqname(tmp_ctx, nss_test_ctx->subdom->names,
- nss_test_ctx->subdom, testsubdomgroup.gr_name);
- assert_non_null(expected.gr_name);
+ if (nss_test_ctx->subdom->fqnames) {
+ expected.gr_name = sss_tc_fqname(tmp_ctx,
+ nss_test_ctx->subdom->names,
+ nss_test_ctx->subdom,
+ testsubdomgroup.gr_name);
+ assert_non_null(expected.gr_name);
+ } else {
+ expected.gr_name = testsubdomgroup.gr_name;
+ }
assert_int_equal(status, EOK);
@@ -1906,6 +2040,36 @@ void test_nss_getgrnam_mix_subdom(void **state)
assert_int_equal(ret, EOK);
}
+void test_nss_getgrnam_mix_subdom_nonfqnames(void **state)
+{
+ errno_t ret;
+
+ nss_test_ctx->subdom->fqnames = false;
+
+ ret = store_group_member(nss_test_ctx,
+ testsubdomgroup.gr_name,
+ nss_test_ctx->subdom,
+ testmember1.pw_name,
+ nss_test_ctx->tctx->dom,
+ SYSDB_MEMBER_USER);
+ assert_int_equal(ret, EOK);
+
+ mock_input_user_or_group("testsubdomgroup");
+ mock_account_recv_simple();
+ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRNAM);
+ will_return_always(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
+
+ /* Query for that group, call a callback when command finishes */
+ set_cmd_cb(test_nss_getgrnam_check_mix_subdom);
+ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRNAM,
+ 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);
+}
+
struct group space_group = {
.gr_gid = 2123,
.gr_name = discard_const("space group"),
@@ -4023,15 +4187,27 @@ int main(int argc, const char *argv[])
cmocka_unit_test_setup_teardown(test_nss_getgrnam_members_subdom,
nss_subdom_test_setup,
nss_subdom_test_teardown),
+ cmocka_unit_test_setup_teardown(test_nss_getgrnam_members_subdom_nonfqnames,
+ nss_subdom_test_setup,
+ nss_subdom_test_teardown),
cmocka_unit_test_setup_teardown(test_nss_getgrnam_mix_dom,
nss_subdom_test_setup,
nss_subdom_test_teardown),
+ cmocka_unit_test_setup_teardown(test_nss_getgrnam_mix_dom_nonfqnames,
+ nss_subdom_test_setup,
+ nss_subdom_test_teardown),
cmocka_unit_test_setup_teardown(test_nss_getgrnam_mix_dom_fqdn,
nss_subdom_test_setup,
nss_subdom_test_teardown),
+ cmocka_unit_test_setup_teardown(test_nss_getgrnam_mix_dom_fqdn_nonfqnames,
+ nss_subdom_test_setup,
+ nss_subdom_test_teardown),
cmocka_unit_test_setup_teardown(test_nss_getgrnam_mix_subdom,
nss_subdom_test_setup,
nss_subdom_test_teardown),
+ cmocka_unit_test_setup_teardown(test_nss_getgrnam_mix_subdom_nonfqnames,
+ nss_subdom_test_setup,
+ nss_subdom_test_teardown),
cmocka_unit_test_setup_teardown(test_nss_getgrnam_space,
nss_test_setup, nss_test_teardown),
cmocka_unit_test_setup_teardown(test_nss_getgrnam_space_sub,
--
2.12.2

View File

@ -1,289 +0,0 @@
From 2e85b015d8dd231094a09eab69b86e8b6fcc8b2b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= <fidencio@redhat.com>
Date: Fri, 24 Mar 2017 15:29:23 +0100
Subject: [PATCH 49/97] SYSDB: Add methods to deal with the domain's resolution
order
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
In the following-up patches those newly introduced methods will be used
to deal with the domainResolutionOrder attribute.
The sysdb_update_domain_resolution_order() method is purposely not
checking whether a value has changed or not before writing to sysdb and
while may not be optimal, the readability of the code has increased a
lot by keeping it as simple as possible.
Tests for these new methods are part of the next commit.
Related:
https://pagure.io/SSSD/sssd/issue/3001
Signed-off-by: Fabiano Fidêncio <fidencio@redhat.com>
Reviewed-by: Sumit Bose <sbose@redhat.com>
Reviewed-by: Pavel Březina <pbrezina@redhat.com>
---
Makefile.am | 2 +
src/db/sysdb.h | 2 +
src/db/sysdb_domain_resolution_order.c | 169 +++++++++++++++++++++++++++++++++
src/db/sysdb_domain_resolution_order.h | 37 ++++++++
4 files changed, 210 insertions(+)
create mode 100644 src/db/sysdb_domain_resolution_order.c
create mode 100644 src/db/sysdb_domain_resolution_order.h
diff --git a/Makefile.am b/Makefile.am
index 359feddef298b0013c726409b7ba8b86504abf09..8052150be32d89813764e9bc436dfcb211a738d6 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -736,6 +736,7 @@ dist_noinst_HEADERS = \
src/db/sysdb_private.h \
src/db/sysdb_services.h \
src/db/sysdb_ssh.h \
+ src/db/sysdb_domain_resolution_order.h \
src/confdb/confdb.h \
src/confdb/confdb_private.h \
src/confdb/confdb_setup.h \
@@ -995,6 +996,7 @@ libsss_util_la_SOURCES = \
src/db/sysdb_idmap.c \
src/db/sysdb_gpo.c \
src/db/sysdb_certmap.c \
+ src/db/sysdb_domain_resolution_order.c \
src/monitor/monitor_sbus.c \
src/providers/dp_auth_util.c \
src/providers/dp_pam_data_util.c \
diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index 6762b51bee02911fb97d5d393fad2495504ee5ad..42d2857ed7765c17e7d84b0da93ed07758fbe012 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -184,6 +184,8 @@
#define SYSDB_OVERRIDE_GROUP_CLASS "groupOverride"
#define SYSDB_OVERRIDE_DN "overrideDN"
#define SYSDB_OVERRIDE_OBJECT_DN "overrideObjectDN"
+#define SYSDB_USE_DOMAIN_RESOLUTION_ORDER "useDomainResolutionOrder"
+#define SYSDB_DOMAIN_RESOLUTION_ORDER "domainResolutionOrder"
#define SYSDB_NEXTID_FILTER "("SYSDB_NEXTID"=*)"
diff --git a/src/db/sysdb_domain_resolution_order.c b/src/db/sysdb_domain_resolution_order.c
new file mode 100644
index 0000000000000000000000000000000000000000..63774461a1e9f3dc863220d418e29e06d6e6e6df
--- /dev/null
+++ b/src/db/sysdb_domain_resolution_order.c
@@ -0,0 +1,169 @@
+/*
+ Authors:
+ Fabiano Fidêncio <fidencio@redhat.com>
+
+ Copyright (C) 2017 Red Hat
+
+ 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 <ldb.h>
+
+#include "db/sysdb.h"
+#include "db/sysdb_private.h"
+
+static errno_t
+sysdb_get_domain_resolution_order_string_attr(TALLOC_CTX *mem_ctx,
+ struct sysdb_ctx *sysdb,
+ struct ldb_dn *dn,
+ const char *const *attrs,
+ const char **_attr)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_result *res;
+ const char *attr;
+ errno_t ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ ret = ldb_search(sysdb->ldb, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs,
+ NULL);
+ if (ret != LDB_SUCCESS) {
+ ret = EIO;
+ goto done;
+ }
+
+ if (res->count > 1) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Base search returned [%d] results, expected 1.\n", res->count);
+ ret = EINVAL;
+ goto done;
+ } else if (res->count == 0) {
+ ret = ENOENT;
+ goto done;
+ } else {
+ /* res->count == 1 */
+ attr = ldb_msg_find_attr_as_string(res->msgs[0], attrs[0], NULL);
+ if (attr == NULL) {
+ ret = ENOENT;
+ goto done;
+ }
+ }
+
+ *_attr = talloc_steal(mem_ctx, attr);
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+errno_t
+sysdb_get_domain_resolution_order(TALLOC_CTX *mem_ctx,
+ struct sysdb_ctx *sysdb,
+ struct ldb_dn *dn,
+ const char **_domain_resolution_order)
+{
+ TALLOC_CTX *tmp_ctx;
+ const char *domain_resolution_order = NULL;
+ const char *attrs[] = { SYSDB_DOMAIN_RESOLUTION_ORDER, NULL };
+ errno_t ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ ret = sysdb_get_domain_resolution_order_string_attr(
+ tmp_ctx, sysdb, dn, attrs, &domain_resolution_order);
+ if (ret != EOK && ret != ENOENT) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "sysdb_get_domain_resolution_order_string_attr() failed "
+ "[%d]: [%s]",
+ ret, sss_strerror(ret));
+ goto done;
+ } else if (ret == ENOENT) {
+ *_domain_resolution_order = NULL;
+ goto done;
+ } else {
+ /* ret == EOK */
+ *_domain_resolution_order = talloc_steal(mem_ctx,
+ domain_resolution_order);
+ }
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+errno_t
+sysdb_update_domain_resolution_order(struct sysdb_ctx *sysdb,
+ struct ldb_dn *dn,
+ const char *domain_resolution_order)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_message *msg;
+ errno_t ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ msg = ldb_msg_new(tmp_ctx);
+ if (msg == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ msg->dn = dn;
+
+ ret = ldb_msg_add_empty(msg, SYSDB_DOMAIN_RESOLUTION_ORDER,
+ LDB_FLAG_MOD_REPLACE, NULL);
+ if (ret != LDB_SUCCESS) {
+ ret = sysdb_error_to_errno(ret);
+ goto done;
+ }
+
+ if (domain_resolution_order != NULL) {
+ ret = ldb_msg_add_string(msg, SYSDB_DOMAIN_RESOLUTION_ORDER,
+ domain_resolution_order);
+ if (ret != LDB_SUCCESS) {
+ ret = sysdb_error_to_errno(ret);
+ goto done;
+ }
+ }
+
+ ret = ldb_modify(sysdb->ldb, msg);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "ldb_modify()_failed: [%s][%d][%s]\n",
+ ldb_strerror(ret), ret, ldb_errstring(sysdb->ldb));
+ ret = sysdb_error_to_errno(ret);
+ goto done;
+ }
+
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
diff --git a/src/db/sysdb_domain_resolution_order.h b/src/db/sysdb_domain_resolution_order.h
new file mode 100644
index 0000000000000000000000000000000000000000..45d2ea63f6bc14cd3184994530846ee6f762d4d0
--- /dev/null
+++ b/src/db/sysdb_domain_resolution_order.h
@@ -0,0 +1,37 @@
+/*
+ Authors:
+ Fabiano Fidêncio <fidencio@redhat.com>
+
+ Copyright (C) 2017 Red Hat
+
+ 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/>.
+*/
+
+#ifndef _SYSDB_DOMAIN_RESOLUTION_ORDER_H_
+#define _SYSDB_DOMAIN_RESOLUTION_ORDER_H_
+
+#include "db/sysdb.h"
+
+errno_t
+sysdb_get_domain_resolution_order(TALLOC_CTX *mem_ctx,
+ struct sysdb_ctx *sysdb,
+ struct ldb_dn *dn,
+ const char **_domain_resolution_order);
+
+errno_t
+sysdb_update_domain_resolution_order(struct sysdb_ctx *sysdb,
+ struct ldb_dn *dn,
+ const char *domain_resolution_order);
+
+#endif /* _SYSDB_DOMAIN_RESOLUTION_ORDER_H_ */
--
2.12.2

View File

@ -1,259 +0,0 @@
From 723d514f641e2b5a5cbfe1c6c7bdd2a6f3c5070e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= <fidencio@redhat.com>
Date: Fri, 24 Mar 2017 23:15:04 +0100
Subject: [PATCH 50/97] SYSDB/TESTS: Add tests for the domain's resolution
order methods
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Introduce a new and small set of tests for these new helper methods that
are going to be used in different parts of the code in the follow-up
patches.
Related:
https://pagure.io/SSSD/sssd/issue/3001
Signed-off-by: Fabiano Fidêncio <fidencio@redhat.com>
Reviewed-by: Sumit Bose <sbose@redhat.com>
Reviewed-by: Pavel Březina <pbrezina@redhat.com>
---
Makefile.am | 16 ++
.../cmocka/test_sysdb_domain_resolution_order.c | 190 +++++++++++++++++++++
2 files changed, 206 insertions(+)
create mode 100644 src/tests/cmocka/test_sysdb_domain_resolution_order.c
diff --git a/Makefile.am b/Makefile.am
index 8052150be32d89813764e9bc436dfcb211a738d6..450785bf4c482cce1e1440f1336879150537888e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -263,6 +263,7 @@ if HAVE_CMOCKA
test_sysdb_certmap \
test_sysdb_sudo \
test_sysdb_utils \
+ test_sysdb_domain_resolution_order \
test_wbc_calls \
test_be_ptask \
test_copy_ccache \
@@ -2875,6 +2876,21 @@ test_sysdb_utils_LDADD = \
libsss_test_common.la \
$(NULL)
+test_sysdb_domain_resolution_order_SOURCES = \
+ src/tests/cmocka/test_sysdb_domain_resolution_order.c \
+ $(NULL)
+test_sysdb_domain_resolution_order_CFLAGS = \
+ $(AM_CFLAGS) \
+ $(NULL)
+test_sysdb_domain_resolution_order_LDADD = \
+ $(CMOCKA_LIBS) \
+ $(LDB_LIBS) \
+ $(POPT_LIBS) \
+ $(TALLOC_LIBS) \
+ $(SSSD_INTERNAL_LTLIBS) \
+ libsss_test_common.la \
+ $(NULL)
+
test_wbc_calls_SOURCES = \
src/tests/cmocka/test_wbc_calls.c \
src/sss_client/idmap/sss_nss_idmap.c \
diff --git a/src/tests/cmocka/test_sysdb_domain_resolution_order.c b/src/tests/cmocka/test_sysdb_domain_resolution_order.c
new file mode 100644
index 0000000000000000000000000000000000000000..59a85ce431be9ac27c1e8e6b5e4e5f8300af549e
--- /dev/null
+++ b/src/tests/cmocka/test_sysdb_domain_resolution_order.c
@@ -0,0 +1,190 @@
+/*
+ SSSD
+
+ sysdb_domain_resolution_order - Tests for domain resolution order calls
+
+ Authors:
+ Fabiano Fidêncio <fidencio@redhat.com>
+
+ Copyright (C) 2017 Red Hat
+
+ 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 <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+#include <popt.h>
+
+#include "tests/cmocka/common_mock.h"
+#include "tests/common.h"
+#include "db/sysdb_domain_resolution_order.h"
+#include "db/sysdb_private.h" /* for sysdb->ldb member */
+
+#define TESTS_PATH "tp_" BASE_FILE_STEM
+#define TEST_CONF_DB "test_sysdb_domain_resolution_order.ldb"
+
+#define TEST_DOM_NAME "test_sysdb_domain_resolution_order"
+
+#define TEST_ID_PROVIDER "ldap"
+
+struct domain_resolution_order_test_ctx {
+ struct sss_test_ctx *tctx;
+};
+
+static int test_sysdb_domain_resolution_order_setup(void **state)
+{
+ struct domain_resolution_order_test_ctx *test_ctx;
+
+ assert_true(leak_check_setup());
+
+ test_ctx = talloc_zero(global_talloc_context,
+ struct domain_resolution_order_test_ctx);
+ assert_non_null(test_ctx);
+
+ test_dom_suite_setup(TESTS_PATH);
+
+ test_ctx->tctx = create_dom_test_ctx(test_ctx, TESTS_PATH,
+ TEST_CONF_DB, TEST_DOM_NAME,
+ TEST_ID_PROVIDER, NULL);
+ assert_non_null(test_ctx->tctx);
+
+ *state = test_ctx;
+ return 0;
+}
+
+static int test_sysdb_domain_resolution_order_teardown(void **state)
+{
+ struct domain_resolution_order_test_ctx *test_ctx =
+ talloc_get_type(*state, struct domain_resolution_order_test_ctx);
+
+ test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, TEST_DOM_NAME);
+ talloc_free(test_ctx);
+ assert_true(leak_check_teardown());
+ return 0;
+}
+
+static void test_sysdb_domain_resolution_order_ops(void **state)
+{
+ errno_t ret;
+ struct domain_resolution_order_test_ctx *test_ctx =
+ talloc_get_type(*state, struct domain_resolution_order_test_ctx);
+ const char *domains_in = NULL;
+ const char *domains_out = NULL;
+ struct ldb_dn *dn;
+
+ dn = ldb_dn_new_fmt(test_ctx, test_ctx->tctx->dom->sysdb->ldb,
+ SYSDB_DOM_BASE, test_ctx->tctx->dom->name);
+
+ /* Adding domainResolutionOrder for the first time */
+ domains_in = "foo:bar:foobar";
+ ret = sysdb_update_domain_resolution_order(test_ctx->tctx->dom->sysdb,
+ dn, domains_in);
+ assert_int_equal(ret, EOK);
+
+ ret = sysdb_get_domain_resolution_order(test_ctx,
+ test_ctx->tctx->dom->sysdb, dn,
+ &domains_out);
+ assert_int_equal(ret, EOK);
+ assert_true(strcmp(domains_in, domains_out) == 0);
+
+ /* Setting the domainResolutionOrder to ":" ...
+ *
+ * It means, the domainResolutionOrder is set, but if there's another
+ * domainResolutionOrder with lower precedence those must be ignored.
+ */
+ domains_in = ":";
+ ret = sysdb_update_domain_resolution_order(test_ctx->tctx->dom->sysdb,
+ dn, domains_in);
+ assert_int_equal(ret, EOK);
+
+ ret = sysdb_get_domain_resolution_order(test_ctx,
+ test_ctx->tctx->dom->sysdb, dn,
+ &domains_out);
+ assert_int_equal(ret, EOK);
+ assert_true(strcmp(domains_in, domains_out) == 0);
+
+ /* Changing the domainResolutionOrder */
+ domains_in = "bar:foobar:foo";
+ ret = sysdb_update_domain_resolution_order(test_ctx->tctx->dom->sysdb,
+ dn, domains_in);
+ assert_int_equal(ret, EOK);
+
+ ret = sysdb_get_domain_resolution_order(test_ctx,
+ test_ctx->tctx->dom->sysdb, dn,
+ &domains_out);
+ assert_int_equal(ret, EOK);
+ assert_true(strcmp(domains_out, domains_out) == 0);
+
+ /* Removing the domainResolutionOrder attribute */
+ domains_in = NULL;
+ ret = sysdb_update_domain_resolution_order(test_ctx->tctx->dom->sysdb,
+ dn, domains_in);
+ assert_int_equal(ret, EOK);
+
+ ret = sysdb_get_domain_resolution_order(test_ctx,
+ test_ctx->tctx->dom->sysdb, dn,
+ &domains_out);
+ assert_int_equal(ret, ENOENT);
+ assert_true(domains_out == NULL);
+}
+
+int main(int argc, const char *argv[])
+{
+ int rv;
+ int no_cleanup = 0;
+ poptContext pc;
+ int opt;
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ SSSD_DEBUG_OPTS
+ {"no-cleanup", 'n', POPT_ARG_NONE, &no_cleanup, 0,
+ _("Do not delete the test database after a test run"), NULL },
+ POPT_TABLEEND
+ };
+
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(test_sysdb_domain_resolution_order_ops,
+ test_sysdb_domain_resolution_order_setup,
+ test_sysdb_domain_resolution_order_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_CLI_INIT(debug_level);
+
+ tests_set_cwd();
+ test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, LOCAL_SYSDB_FILE);
+ test_dom_suite_setup(TESTS_PATH);
+ rv = cmocka_run_group_tests(tests, NULL, NULL);
+
+ if (rv == 0 && no_cleanup == 0) {
+ test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, LOCAL_SYSDB_FILE);
+ }
+ return rv;
+}
--
2.12.2

View File

@ -1,369 +0,0 @@
From 3cbf0e7b63e8e6888917e9215bbdc5674c2fa852 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= <fidencio@redhat.com>
Date: Wed, 22 Mar 2017 13:40:20 +0100
Subject: [PATCH 51/97] IPA: Get ipaDomainsResolutionOrder from ipaConfig
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
ipaDomainsResolutionOrder provides a list of domains that have to be
looked up firstly during cache_req searches.
This commit only fetches this list from the server and stores its value
at sysdb so we can make use of it later on this patch series.
There are no tests for newly introduced sysdb methods are those are
basically only calling sysdb_update_domain_resolution_order(),
sysdb_get_domain_resolution_order() and
sysdb_get_use_domain_resolution_order() which are have tests written
for.
Related:
https://pagure.io/SSSD/sssd/issue/3001
Signed-off-by: Fabiano Fidêncio <fidencio@redhat.com>
Reviewed-by: Sumit Bose <sbose@redhat.com>
Reviewed-by: Pavel Březina <pbrezina@redhat.com>
---
src/db/sysdb.h | 11 +++
src/db/sysdb_subdomains.c | 67 +++++++++++++++
src/providers/ipa/ipa_subdomains.c | 168 ++++++++++++++++++++++++++++++++++---
3 files changed, 234 insertions(+), 12 deletions(-)
diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index 42d2857ed7765c17e7d84b0da93ed07758fbe012..75a07d4d2effb028ec654342113f8478e1eba10e 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -489,6 +489,17 @@ int sysdb_transaction_cancel(struct sysdb_ctx *sysdb);
/* functions related to subdomains */
errno_t sysdb_domain_create(struct sysdb_ctx *sysdb, const char *domain_name);
+errno_t sysdb_domain_get_domain_resolution_order(
+ TALLOC_CTX *mem_ctx,
+ struct sysdb_ctx *sysdb,
+ const char *domain_name,
+ const char **_domain_resolution_order);
+
+errno_t sysdb_domain_update_domain_resolution_order(
+ struct sysdb_ctx *sysdb,
+ const char *domain_name,
+ const char *domain_resolution_order);
+
errno_t sysdb_subdomain_store(struct sysdb_ctx *sysdb,
const char *name, const char *realm,
const char *flat_name, const char *domain_id,
diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c
index 916dbba153d8c08837425f6fd29a20f5a6aa9fc9..e2a4f7bb1fcdf20b6b7e04efc7f396d1c3d08f0f 100644
--- a/src/db/sysdb_subdomains.c
+++ b/src/db/sysdb_subdomains.c
@@ -22,6 +22,7 @@
#include "util/util.h"
#include "db/sysdb_private.h"
+#include "db/sysdb_domain_resolution_order.h"
static errno_t
check_subdom_config_file(struct confdb_ctx *confdb,
@@ -1210,3 +1211,69 @@ done:
talloc_free(tmp_ctx);
return ret;
}
+
+errno_t
+sysdb_domain_get_domain_resolution_order(TALLOC_CTX *mem_ctx,
+ struct sysdb_ctx *sysdb,
+ const char *domain_name,
+ const char **_domain_resolution_order)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_dn *dn;
+ errno_t ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb, SYSDB_DOM_BASE, domain_name);
+ if (dn == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = sysdb_get_domain_resolution_order(mem_ctx, sysdb, dn,
+ _domain_resolution_order);
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+errno_t
+sysdb_domain_update_domain_resolution_order(struct sysdb_ctx *sysdb,
+ const char *domain_name,
+ const char *domain_resolution_order)
+{
+
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_dn *dn;
+ errno_t ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb, SYSDB_DOM_BASE, domain_name);
+ if (dn == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = sysdb_update_domain_resolution_order(sysdb, dn,
+ domain_resolution_order);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "sysdb_update_domain_resolution_order() failed [%d]: [%s].\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
index a07b88fe2f499353293ba90345552413c9792f4b..01a0ce812d861b24565d2f71f27d6b8ceb2965bc 100644
--- a/src/providers/ipa/ipa_subdomains.c
+++ b/src/providers/ipa/ipa_subdomains.c
@@ -29,6 +29,7 @@
#include "providers/ipa/ipa_common.h"
#include "providers/ipa/ipa_id.h"
#include "providers/ipa/ipa_opts.h"
+#include "providers/ipa/ipa_config.h"
#include <ctype.h>
@@ -51,6 +52,8 @@
#define IPA_ASSIGNED_ID_VIEW "ipaAssignedIDView"
+#define IPA_DOMAIN_RESOLUTION_ORDER "ipaDomainResolutionOrder"
+
/* do not refresh more often than every 5 seconds for now */
#define IPA_SUBDOMAIN_REFRESH_LIMIT 5
@@ -1681,6 +1684,117 @@ static errno_t ipa_subdomains_view_name_recv(struct tevent_req *req)
return EOK;
}
+struct ipa_domain_resolution_order_state {
+ struct sss_domain_info *domain;
+};
+
+static void ipa_domain_resolution_order_done(struct tevent_req *subreq);
+
+static struct tevent_req *
+ipa_domain_resolution_order_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct ipa_subdomains_ctx *sd_ctx,
+ struct sdap_handle *sh)
+{
+ struct ipa_domain_resolution_order_state *state;
+ struct tevent_req *subreq;
+ struct tevent_req *req;
+ const char *attrs[] = {IPA_DOMAIN_RESOLUTION_ORDER, NULL};
+ errno_t ret;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct ipa_domain_resolution_order_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+ return NULL;
+ }
+
+ state->domain = sd_ctx->be_ctx->domain;
+
+ subreq = ipa_get_config_send(state, ev, sh, sd_ctx->sdap_id_ctx->opts,
+ state->domain->name, attrs);
+ if (subreq == NULL) {
+ ret = ENOMEM;
+ goto immediately;
+ }
+
+ tevent_req_set_callback(subreq, ipa_domain_resolution_order_done, req);
+
+ return req;
+
+immediately:
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
+ }
+ tevent_req_post(req, ev);
+
+ return req;
+}
+
+static void ipa_domain_resolution_order_done(struct tevent_req *subreq)
+{
+ struct ipa_domain_resolution_order_state *state;
+ struct tevent_req *req;
+ struct sysdb_attrs *config = NULL;
+ const char *domain_resolution_order = NULL;
+ errno_t ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct ipa_domain_resolution_order_state);
+
+ ret = ipa_get_config_recv(subreq, state, &config);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Failed to get the domains' resolution order configuration "
+ "from the server [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ if (config != NULL) {
+ ret = sysdb_attrs_get_string(config, IPA_DOMAIN_RESOLUTION_ORDER,
+ &domain_resolution_order);
+ if (ret != EOK && ret != ENOENT) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Failed to get the domains' resolution order configuration "
+ "value [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ } else if (ret == ENOENT) {
+ domain_resolution_order = NULL;
+ }
+ }
+
+ ret = sysdb_domain_update_domain_resolution_order(
+ state->domain->sysdb, state->domain->name,
+ domain_resolution_order);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "sysdb_domain_update_resolution_order() [%d]: [%s].\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ ret = EOK;
+
+done:
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+static errno_t ipa_domain_resolution_order_recv(struct tevent_req *req)
+{
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ return EOK;
+}
struct ipa_subdomains_refresh_state {
struct tevent_context *ev;
@@ -1695,6 +1809,7 @@ static void ipa_subdomains_refresh_certmap_done(struct tevent_req *subreq);
static void ipa_subdomains_refresh_master_done(struct tevent_req *subreq);
static void ipa_subdomains_refresh_slave_done(struct tevent_req *subreq);
static void ipa_subdomains_refresh_view_done(struct tevent_req *subreq);
+static void ipa_domain_refresh_resolution_order_done(struct tevent_req *subreq);
static struct tevent_req *
ipa_subdomains_refresh_send(TALLOC_CTX *mem_ctx,
@@ -1916,7 +2031,6 @@ static void ipa_subdomains_refresh_view_done(struct tevent_req *subreq)
{
struct ipa_subdomains_refresh_state *state;
struct tevent_req *req;
- int dp_error;
errno_t ret;
req = tevent_req_callback_data(subreq, struct tevent_req);
@@ -1924,24 +2038,55 @@ static void ipa_subdomains_refresh_view_done(struct tevent_req *subreq)
ret = ipa_subdomains_view_name_recv(subreq);
talloc_zfree(subreq);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Unable to get view name [%d]: %s\n",
+ ret, sss_strerror(ret));
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ subreq = ipa_domain_resolution_order_send(state, state->ev, state->sd_ctx,
+ sdap_id_op_handle(state->sdap_op));
+ if (subreq == NULL) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+
+ tevent_req_set_callback(subreq,
+ ipa_domain_refresh_resolution_order_done,
+ req);
+}
+
+static void
+ipa_domain_refresh_resolution_order_done(struct tevent_req *subreq)
+{
+ struct ipa_subdomains_refresh_state *state;
+ struct tevent_req *req;
+ int dp_error;
+ errno_t ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct ipa_subdomains_refresh_state);
+
+ ret = ipa_domain_resolution_order_recv(subreq);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "Unable to get the domains order resolution [%d]: %s\n",
+ ret, sss_strerror(ret));
+ tevent_req_error(req, ret);
+ return;
+ }
+
ret = sdap_id_op_done(state->sdap_op, ret, &dp_error);
if (dp_error == DP_ERR_OK && ret != EOK) {
/* retry */
ret = ipa_subdomains_refresh_retry(req);
- if (ret != EOK) {
- goto done;
- }
- return;
} else if (dp_error == DP_ERR_OFFLINE) {
ret = ERR_OFFLINE;
- goto done;
- } else if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get view name "
- "[%d]: %s\n", ret, sss_strerror(ret));
- goto done;
}
-done:
if (ret != EOK) {
DEBUG(SSSDBG_TRACE_FUNC, "Unable to refresh subdomains [%d]: %s\n",
ret, sss_strerror(ret));
@@ -1949,7 +2094,6 @@ done:
return;
}
- DEBUG(SSSDBG_TRACE_FUNC, "Subdomains refreshed.\n");
tevent_req_done(req);
}
--
2.12.2

View File

@ -1,54 +0,0 @@
From 17ab121a6c69d74acf1d40f2bbcbe90d77bb6b8a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= <fidencio@redhat.com>
Date: Fri, 24 Mar 2017 08:08:58 +0100
Subject: [PATCH 52/97] IPA_SUBDOMAINS: Rename _refresh_view() to
_refresh_view_name()
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This method got renamed in order to match better with what it does
currently.
Related:
https://pagure.io/SSSD/sssd/issue/3001
Signed-off-by: Fabiano Fidêncio <fidencio@redhat.com>
Reviewed-by: Sumit Bose <sbose@redhat.com>
Reviewed-by: Pavel Březina <pbrezina@redhat.com>
---
src/providers/ipa/ipa_subdomains.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
index 01a0ce812d861b24565d2f71f27d6b8ceb2965bc..bf6f6ab1fa8bfff7ea102dd219c9ddbbab065b2b 100644
--- a/src/providers/ipa/ipa_subdomains.c
+++ b/src/providers/ipa/ipa_subdomains.c
@@ -1808,7 +1808,7 @@ static void ipa_subdomains_refresh_ranges_done(struct tevent_req *subreq);
static void ipa_subdomains_refresh_certmap_done(struct tevent_req *subreq);
static void ipa_subdomains_refresh_master_done(struct tevent_req *subreq);
static void ipa_subdomains_refresh_slave_done(struct tevent_req *subreq);
-static void ipa_subdomains_refresh_view_done(struct tevent_req *subreq);
+static void ipa_subdomains_refresh_view_name_done(struct tevent_req *subreq);
static void ipa_domain_refresh_resolution_order_done(struct tevent_req *subreq);
static struct tevent_req *
@@ -2023,11 +2023,12 @@ static void ipa_subdomains_refresh_slave_done(struct tevent_req *subreq)
return;
}
- tevent_req_set_callback(subreq, ipa_subdomains_refresh_view_done, req);
+ tevent_req_set_callback(subreq, ipa_subdomains_refresh_view_name_done,
+ req);
return;
}
-static void ipa_subdomains_refresh_view_done(struct tevent_req *subreq)
+static void ipa_subdomains_refresh_view_name_done(struct tevent_req *subreq)
{
struct ipa_subdomains_refresh_state *state;
struct tevent_req *req;
--
2.12.2

View File

@ -1,347 +0,0 @@
From fb81f337b68c85471c3f5140850dccf549a2d0ac Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= <fidencio@redhat.com>
Date: Fri, 24 Mar 2017 17:46:04 +0100
Subject: [PATCH 53/97] IPA: Get ipaDomainsResolutionOrder from IPA ID View
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
ipaDomainsResolutionOrder provides a list of domains that have to be
looked up firstly during cache_req searches.
This commit only fetches this list from the server and stores its value
at sysdb so we can make use of it later on this patch series.
There are no tests for newly introduced sysdb methods are those are
basically only calling sysdb_update_domain_resolution_order(),
sysdb_get_domain_resolution_order() and
sysdb_get_use_domain_resolution_order() which are have tests written
for.
Related:
https://pagure.io/SSSD/sssd/issue/3001
Signed-off-by: Fabiano Fidêncio <fidencio@redhat.com>
Reviewed-by: Sumit Bose <sbose@redhat.com>
Reviewed-by: Pavel Březina <pbrezina@redhat.com>
---
src/db/sysdb.h | 9 ++
src/db/sysdb_views.c | 66 ++++++++++++++
src/providers/ipa/ipa_subdomains.c | 182 +++++++++++++++++++++++++++++++++++++
3 files changed, 257 insertions(+)
diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index 75a07d4d2effb028ec654342113f8478e1eba10e..62c561be9452a284a8ddf8ebb45720265852c8b0 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -533,6 +533,15 @@ errno_t sysdb_update_view_name(struct sysdb_ctx *sysdb, const char *view_name);
errno_t sysdb_get_view_name(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb,
char **view_name);
+errno_t sysdb_update_view_domain_resolution_order(
+ struct sysdb_ctx *sysdb,
+ const char *domain_resolution_order);
+
+errno_t sysdb_get_view_domain_resolution_order(
+ TALLOC_CTX *mem_ctx,
+ struct sysdb_ctx *sysdb,
+ const char **_domain_resolution_order);
+
static inline bool is_default_view(const char *view_name)
{
/* NULL is treated as default */
diff --git a/src/db/sysdb_views.c b/src/db/sysdb_views.c
index 1c416dd14049237e9f35d52f154035e3ff861469..20db9b06183d68b33bb19f498513d7f5cf84b1cf 100644
--- a/src/db/sysdb_views.c
+++ b/src/db/sysdb_views.c
@@ -22,6 +22,9 @@
#include "util/util.h"
#include "util/cert.h"
#include "db/sysdb_private.h"
+#include "db/sysdb_domain_resolution_order.h"
+
+#define SYSDB_VIEWS_BASE "cn=views,cn=sysdb"
/* In general is should not be possible that there is a view container without
* a view name set. But to be on the safe side we return both information
@@ -179,6 +182,69 @@ done:
return ret;
}
+errno_t
+sysdb_get_view_domain_resolution_order(TALLOC_CTX *mem_ctx,
+ struct sysdb_ctx *sysdb,
+ const char **_domain_resolution_order)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_dn *dn;
+ errno_t ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ dn = ldb_dn_new(tmp_ctx, sysdb->ldb, SYSDB_VIEWS_BASE);
+ if (dn == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = sysdb_get_domain_resolution_order(mem_ctx, sysdb, dn,
+ _domain_resolution_order);
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+errno_t
+sysdb_update_view_domain_resolution_order(struct sysdb_ctx *sysdb,
+ const char *domain_resolution_order)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_dn *dn;
+ errno_t ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ dn = ldb_dn_new(tmp_ctx, sysdb->ldb, SYSDB_VIEWS_BASE);
+ if (dn == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = sysdb_update_domain_resolution_order(sysdb, dn,
+ domain_resolution_order);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "sysdb_update_domain_resolution_order() failed [%d]: [%s].\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
errno_t sysdb_delete_view_tree(struct sysdb_ctx *sysdb, const char *view_name)
{
struct ldb_dn *dn;
diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
index bf6f6ab1fa8bfff7ea102dd219c9ddbbab065b2b..ef348adf4a36e870f44387bd700f5c2beea3bfd6 100644
--- a/src/providers/ipa/ipa_subdomains.c
+++ b/src/providers/ipa/ipa_subdomains.c
@@ -1684,6 +1684,151 @@ static errno_t ipa_subdomains_view_name_recv(struct tevent_req *req)
return EOK;
}
+struct ipa_subdomains_view_domain_resolution_order_state {
+ struct sss_domain_info *domain;
+ const char *view_name;
+};
+
+static void
+ipa_subdomains_view_domain_resolution_order_done(struct tevent_req *subreq);
+
+static struct tevent_req *
+ipa_subdomains_view_domain_resolution_order_send(
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct ipa_subdomains_ctx *sd_ctx,
+ struct sdap_handle *sh)
+{
+ struct ipa_subdomains_view_domain_resolution_order_state *state;
+ struct tevent_req *subreq;
+ struct tevent_req *req;
+ const char *attrs[] = { IPA_DOMAIN_RESOLUTION_ORDER, NULL };
+ char *ldap_basedn;
+ char *base;
+ errno_t ret;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct ipa_subdomains_view_domain_resolution_order_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+ return NULL;
+ }
+
+ state->domain = sd_ctx->be_ctx->domain;
+ state->view_name = sd_ctx->ipa_id_ctx->view_name;
+
+ ret = domain_to_basedn(state, sd_ctx->be_ctx->domain->name, &ldap_basedn);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "domain_to_basedn failed.\n");
+ goto immediately;
+ }
+
+ base = talloc_asprintf(state, "cn=%s,cn=views,cn=accounts,%s",
+ sd_ctx->ipa_id_ctx->view_name, ldap_basedn);
+ if (base == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
+ ret = ENOMEM;
+ goto immediately;
+ }
+
+ subreq = sdap_get_generic_send(
+ state, ev, sd_ctx->sdap_id_ctx->opts, sh,
+ base, LDAP_SCOPE_BASE, NULL, attrs, NULL, 0,
+ dp_opt_get_int(sd_ctx->sdap_id_ctx->opts->basic,
+ SDAP_ENUM_SEARCH_TIMEOUT),
+ false);
+ if (subreq == NULL) {
+ ret = ENOMEM;
+ goto immediately;
+ }
+
+ tevent_req_set_callback(subreq, ipa_subdomains_view_domain_resolution_order_done,
+ req);
+
+ return req;
+
+immediately:
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
+ }
+ tevent_req_post(req, ev);
+
+ return req;
+}
+
+static void
+ipa_subdomains_view_domain_resolution_order_done(struct tevent_req *subreq)
+{
+ struct ipa_subdomains_view_domain_resolution_order_state *state;
+ struct tevent_req *req;
+ size_t reply_count;
+ struct sysdb_attrs **reply;
+ const char *domain_resolution_order;
+ errno_t ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req,
+ struct ipa_subdomains_view_domain_resolution_order_state);
+
+ ret = sdap_get_generic_recv(subreq, state, &reply_count, &reply);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "Unable to get view name [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ if (reply_count > 1) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "More than one object returned.\n");
+ ret = EINVAL;
+ goto done;
+ } else if (reply_count == 0) {
+ domain_resolution_order = NULL;
+ } else {
+ /* reply_count == 1 */
+ ret = sysdb_attrs_get_string(reply[0], IPA_DOMAIN_RESOLUTION_ORDER,
+ &domain_resolution_order);
+ if (ret != EOK && ret != ENOENT) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Failed to get the view domains' resolution order "
+ "configuration value for view [%s] [%d]: %s\n",
+ state->view_name, ret, sss_strerror(ret));
+ goto done;
+ } else if (ret == ENOENT) {
+ domain_resolution_order = NULL;
+ }
+ }
+
+ ret = sysdb_update_view_domain_resolution_order(state->domain->sysdb,
+ domain_resolution_order);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "sysdb_update_view_domain_resolution_order() [%d]: [%s].\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ ret = EOK;
+
+done:
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+static errno_t
+ipa_subdomains_view_domain_resolution_order_recv(struct tevent_req *req)
+{
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ return EOK;
+}
+
struct ipa_domain_resolution_order_state {
struct sss_domain_info *domain;
};
@@ -1809,6 +1954,8 @@ static void ipa_subdomains_refresh_certmap_done(struct tevent_req *subreq);
static void ipa_subdomains_refresh_master_done(struct tevent_req *subreq);
static void ipa_subdomains_refresh_slave_done(struct tevent_req *subreq);
static void ipa_subdomains_refresh_view_name_done(struct tevent_req *subreq);
+static void ipa_subdomains_refresh_view_domain_resolution_order_done(
+ struct tevent_req *subreq);
static void ipa_domain_refresh_resolution_order_done(struct tevent_req *subreq);
static struct tevent_req *
@@ -2047,6 +2194,41 @@ static void ipa_subdomains_refresh_view_name_done(struct tevent_req *subreq)
return;
}
+ subreq = ipa_subdomains_view_domain_resolution_order_send(
+ state,
+ state->ev,
+ state->sd_ctx,
+ sdap_id_op_handle(state->sdap_op));
+ if (subreq == NULL) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+
+ tevent_req_set_callback(subreq,
+ ipa_subdomains_refresh_view_domain_resolution_order_done,
+ req);
+}
+
+static void
+ipa_subdomains_refresh_view_domain_resolution_order_done(struct tevent_req *subreq)
+{
+ struct ipa_subdomains_refresh_state *state;
+ struct tevent_req *req;
+ errno_t ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct ipa_subdomains_refresh_state);
+
+ ret = ipa_subdomains_view_domain_resolution_order_recv(subreq);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Unable to get view domain_resolution order [%d]: %s\n",
+ ret, sss_strerror(ret));
+ tevent_req_error(req, ret);
+ return;
+ }
+
subreq = ipa_domain_resolution_order_send(state, state->ev, state->sd_ctx,
sdap_id_op_handle(state->sdap_op));
if (subreq == NULL) {
--
2.12.2

View File

@ -1,37 +0,0 @@
From 34228050af1e25706f61ec9df648852284b61c2b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= <fidencio@redhat.com>
Date: Tue, 21 Mar 2017 20:56:38 +0100
Subject: [PATCH 54/97] DLINKLIST: Add DLIST_FOR_EACH_SAFE macro
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This macro, as DLIST_FOR_EACH, iterates over the whole list. The main
difference between both is that in the _SAFE version the pointer to the
next list node is stored, allowing us to delete the current node safely.
Signed-off-by: Fabiano Fidêncio <fidencio@redhat.com>
Reviewed-by: Sumit Bose <sbose@redhat.com>
Reviewed-by: Pavel Březina <pbrezina@redhat.com>
---
src/util/dlinklist.h | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/util/dlinklist.h b/src/util/dlinklist.h
index 4f6aef830e914c22654970081263d43461c1750f..017c60468e66dbec15724d5f4832da412f42136b 100644
--- a/src/util/dlinklist.h
+++ b/src/util/dlinklist.h
@@ -147,4 +147,9 @@ do { \
#define DLIST_FOR_EACH(p, list) \
for ((p) = (list); (p) != NULL; (p) = (p)->next)
+#define DLIST_FOR_EACH_SAFE(p, q, list) \
+ for ((p) = (list), (q) = (p) != NULL ? (p)->next : NULL; \
+ (p) != NULL; \
+ (p) = (q), (q) = (p) != NULL ? (p)->next : NULL)
+
#endif /* _DLINKLIST_H */
--
2.12.2

View File

@ -1,795 +0,0 @@
From 66c8e92eb5a4985bb7f64c349a53b08030a000cf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= <fidencio@redhat.com>
Date: Sun, 26 Mar 2017 00:27:50 +0100
Subject: [PATCH 55/97] CACHE_REQ: Make use of domainResolutionOrder
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
domainResolutionOrder has been introduced in the previous commits and
allows the admin to set up a specific order which the domains will be
resolved during a lookup and with this patch we can take advantage of
this.
In order to have it working a new structure has been added
(struct domain_resolution_order) to the responder context and will be
used by the cache_req to perform the lookups based on this list.
As the ipaDomainResolutionOrder may be set globally on IPA or per View,
SSSD does respect the following precedence order: View > Globally.
The way the list is built is quite simple, basically having the domains
present on ipaDomainResolutionOrder as the first domains (in that
specific order) and then appending the remaining domains to this list.
The final result is a completely flat list with all the domains
respecting the specified order (it's important to remember that the
domains not specified won't follow any specific order, they're just
"random" based on the domains list present in the responder context.
Related:
https://pagure.io/SSSD/sssd/issue/3001
Signed-off-by: Fabiano Fidêncio <fidencio@redhat.com>
Reviewed-by: Sumit Bose <sbose@redhat.com>
Reviewed-by: Pavel Březina <pbrezina@redhat.com>
---
Makefile.am | 3 +
src/responder/common/cache_req/cache_req.c | 89 +++++++-----
src/responder/common/cache_req/cache_req_domain.c | 166 ++++++++++++++++++++++
src/responder/common/cache_req/cache_req_domain.h | 46 ++++++
src/responder/common/responder.h | 5 +
src/responder/common/responder_common.c | 153 ++++++++++++++++++++
src/responder/common/responder_get_domains.c | 14 ++
src/tests/cmocka/common_mock_resp.c | 6 +
src/tests/cmocka/common_mock_resp_dp.c | 7 +
src/tests/cmocka/test_nss_srv.c | 4 +
src/tests/cwrap/Makefile.am | 1 +
11 files changed, 457 insertions(+), 37 deletions(-)
create mode 100644 src/responder/common/cache_req/cache_req_domain.c
create mode 100644 src/responder/common/cache_req/cache_req_domain.h
diff --git a/Makefile.am b/Makefile.am
index 450785bf4c482cce1e1440f1336879150537888e..573b37c52fdeab1add4ea057e1e1844ea4d348a5 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -528,6 +528,7 @@ SSSD_CACHE_REQ_OBJ = \
src/responder/common/cache_req/cache_req_result.c \
src/responder/common/cache_req/cache_req_search.c \
src/responder/common/cache_req/cache_req_data.c \
+ src/responder/common/cache_req/cache_req_domain.c \
src/responder/common/cache_req/plugins/cache_req_common.c \
src/responder/common/cache_req/plugins/cache_req_enum_users.c \
src/responder/common/cache_req/plugins/cache_req_enum_groups.c \
@@ -689,6 +690,7 @@ dist_noinst_HEADERS = \
src/responder/common/iface/responder_iface.h \
src/responder/common/iface/responder_iface_generated.h \
src/responder/common/cache_req/cache_req.h \
+ src/responder/common/cache_req/cache_req_domain.h \
src/responder/common/cache_req/cache_req_plugin.h \
src/responder/common/cache_req/cache_req_private.h \
src/responder/common/data_provider/rdp.h \
@@ -2199,6 +2201,7 @@ responder_socket_access_tests_SOURCES = \
src/responder/common/responder_common.c \
src/responder/common/responder_packet.c \
src/responder/common/responder_cmd.c \
+ src/responder/common/cache_req/cache_req_domain.c \
src/responder/common/data_provider/rdp_message.c \
src/responder/common/data_provider/rdp_client.c \
$(SSSD_RESPONDER_IFACE_OBJ) \
diff --git a/src/responder/common/cache_req/cache_req.c b/src/responder/common/cache_req/cache_req.c
index aca150d69b398ceb1a52e5cd6a87d35dbc87020b..483126396f8addbad744ae03bfc739801cd0c18b 100644
--- a/src/responder/common/cache_req/cache_req.c
+++ b/src/responder/common/cache_req/cache_req.c
@@ -24,6 +24,7 @@
#include <errno.h>
#include "util/util.h"
+#include "responder/common/responder.h"
#include "responder/common/cache_req/cache_req_private.h"
#include "responder/common/cache_req/cache_req_plugin.h"
@@ -316,7 +317,7 @@ struct cache_req_search_domains_state {
struct cache_req *cr;
/* work data */
- struct sss_domain_info *domain;
+ struct cache_req_domain *cr_domain;
struct sss_domain_info *selected_domain;
struct cache_req_result **results;
size_t num_results;
@@ -330,13 +331,14 @@ static errno_t cache_req_search_domains_next(struct tevent_req *req);
static void cache_req_search_domains_done(struct tevent_req *subreq);
-struct tevent_req *cache_req_search_domains_send(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- struct cache_req *cr,
- struct sss_domain_info *domain,
- bool check_next,
- bool bypass_cache,
- bool bypass_dp)
+struct tevent_req *
+cache_req_search_domains_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cache_req *cr,
+ struct cache_req_domain *cr_domain,
+ bool check_next,
+ bool bypass_cache,
+ bool bypass_dp)
{
struct tevent_req *req;
struct cache_req_search_domains_state *state = NULL;
@@ -352,7 +354,7 @@ struct tevent_req *cache_req_search_domains_send(TALLOC_CTX *mem_ctx,
state->ev = ev;
state->cr = cr;
- state->domain = domain;
+ state->cr_domain = cr_domain;
state->check_next = check_next;
state->dp_success = true;
state->bypass_cache = bypass_cache;
@@ -378,6 +380,7 @@ static errno_t cache_req_search_domains_next(struct tevent_req *req)
struct cache_req_search_domains_state *state;
struct tevent_req *subreq;
struct cache_req *cr;
+ struct sss_domain_info *domain;
uint32_t next_domain_flag;
bool is_domain_valid;
bool allow_no_fqn;
@@ -389,11 +392,21 @@ static errno_t cache_req_search_domains_next(struct tevent_req *req)
next_domain_flag = cr->plugin->get_next_domain_flags;
allow_no_fqn = cr->plugin->allow_missing_fqn;
- while (state->domain != NULL) {
+ while (state->cr_domain != NULL) {
+ domain = state->cr_domain->domain;
+ /* As the cr_domain list is a flatten version of the domains
+ * list, we have to ensure to only go through the subdomains in
+ * case it's specified in the plugin to do so.
+ */
+ if (next_domain_flag == 0 && IS_SUBDOMAIN(domain)) {
+ state->cr_domain = state->cr_domain->next;
+ continue;
+ }
+
/* Check if this domain is valid for this request. */
- is_domain_valid = cache_req_validate_domain(cr, state->domain);
+ is_domain_valid = cache_req_validate_domain(cr, domain);
if (!is_domain_valid) {
- state->domain = get_next_domain(state->domain, next_domain_flag);
+ state->cr_domain = state->cr_domain->next;
continue;
}
@@ -401,18 +414,18 @@ static errno_t cache_req_search_domains_next(struct tevent_req *req)
* qualified names on domain less search. We do not descend into
* subdomains here since those are implicitly qualified.
*/
- if (state->check_next && !allow_no_fqn && state->domain->fqnames) {
- state->domain = get_next_domain(state->domain, 0);
+ if (state->check_next && !allow_no_fqn && domain->fqnames) {
+ state->cr_domain = state->cr_domain->next;
continue;
}
- state->selected_domain = state->domain;
+ state->selected_domain = domain;
- if (state->domain == NULL) {
+ if (domain == NULL) {
break;
}
- ret = cache_req_set_domain(cr, state->domain);
+ ret = cache_req_set_domain(cr, domain);
if (ret != EOK) {
return ret;
}
@@ -427,8 +440,7 @@ static errno_t cache_req_search_domains_next(struct tevent_req *req)
/* we will continue with the following domain the next time */
if (state->check_next) {
- state->domain = get_next_domain(state->domain,
- cr->plugin->get_next_domain_flags);
+ state->cr_domain = state->cr_domain->next;
}
return EAGAIN;
@@ -625,11 +637,12 @@ static void cache_req_input_parsed(struct tevent_req *subreq);
static errno_t cache_req_select_domains(struct tevent_req *req,
const char *domain_name);
-static errno_t cache_req_search_domains(struct tevent_req *req,
- struct sss_domain_info *domain,
- bool check_next,
- bool bypass_cache,
- bool bypass_dp);
+static errno_t
+cache_req_search_domains(struct tevent_req *req,
+ struct cache_req_domain *oredered_domain,
+ bool check_next,
+ bool bypass_cache,
+ bool bypass_dp);
static void cache_req_done(struct tevent_req *subreq);
@@ -778,7 +791,7 @@ static errno_t cache_req_select_domains(struct tevent_req *req,
const char *domain_name)
{
struct cache_req_state *state = NULL;
- struct sss_domain_info *domain;
+ struct cache_req_domain *cr_domain;
bool check_next;
bool bypass_cache;
bool bypass_dp;
@@ -798,29 +811,30 @@ static errno_t cache_req_select_domains(struct tevent_req *req,
CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr,
"Performing a single domain search\n");
- domain = responder_get_domain(state->cr->rctx, domain_name);
- if (domain == NULL) {
+ cr_domain = cache_req_domain_get_domain_by_name(
+ state->cr->rctx->cr_domains, domain_name);
+ if (cr_domain == NULL) {
return ERR_DOMAIN_NOT_FOUND;
}
-
check_next = false;
} else {
CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr,
"Performing a multi-domain search\n");
- domain = state->cr->rctx->domains;
+ cr_domain = state->cr->rctx->cr_domains;
check_next = true;
}
- return cache_req_search_domains(req, domain, check_next,
+ return cache_req_search_domains(req, cr_domain, check_next,
bypass_cache, bypass_dp);
}
-static errno_t cache_req_search_domains(struct tevent_req *req,
- struct sss_domain_info *domain,
- bool check_next,
- bool bypass_cache,
- bool bypass_dp)
+static errno_t
+cache_req_search_domains(struct tevent_req *req,
+ struct cache_req_domain *cr_domain,
+ bool check_next,
+ bool bypass_cache,
+ bool bypass_dp)
{
struct tevent_req *subreq;
struct cache_req_state *state = NULL;
@@ -832,8 +846,9 @@ static errno_t cache_req_search_domains(struct tevent_req *req,
bypass_cache ? "bypass" : "check",
bypass_dp ? "bypass" : "check");
- subreq = cache_req_search_domains_send(state, state->ev, state->cr, domain,
- check_next, bypass_cache, bypass_dp);
+ subreq = cache_req_search_domains_send(state, state->ev, state->cr,
+ cr_domain, check_next,
+ bypass_cache, bypass_dp);
if (subreq == NULL) {
return ENOMEM;
}
diff --git a/src/responder/common/cache_req/cache_req_domain.c b/src/responder/common/cache_req/cache_req_domain.c
new file mode 100644
index 0000000000000000000000000000000000000000..bbabd695f1c6b6c29b7e61f571382ab9adfb0ea2
--- /dev/null
+++ b/src/responder/common/cache_req/cache_req_domain.c
@@ -0,0 +1,166 @@
+/*
+ Authors:
+ Fabiano Fidêncio <fidencio@redhat.com>
+
+ Copyright (C) 2017 Red Hat
+
+ 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 "responder/common/cache_req/cache_req_domain.h"
+
+struct cache_req_domain *
+cache_req_domain_get_domain_by_name(struct cache_req_domain *domains,
+ const char *name)
+{
+ struct cache_req_domain *dom;
+ struct cache_req_domain *ret = NULL;
+
+ DLIST_FOR_EACH(dom, domains) {
+ if (sss_domain_get_state(dom->domain) == DOM_DISABLED) {
+ continue;
+ }
+
+ if (strcasecmp(dom->domain->name, name) == 0 ||
+ (dom->domain->flat_name != NULL &&
+ strcasecmp(dom->domain->flat_name, name) == 0)) {
+ ret = dom;
+ break;
+ }
+ }
+
+ if (ret == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "Unknown domains [%s].\n", name);
+ }
+
+ return ret;
+}
+
+void cache_req_domain_list_zfree(struct cache_req_domain **cr_domains)
+{
+ struct cache_req_domain *p, *q, *r;
+
+ DLIST_FOR_EACH_SAFE(p, q, *cr_domains) {
+ r = p;
+ DLIST_REMOVE(*cr_domains, p);
+ talloc_zfree(r);
+ }
+
+ *cr_domains = NULL;
+}
+
+static struct cache_req_domain *
+cache_req_domain_new_list_from_string_list(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domains,
+ char **resolution_order)
+{
+ struct cache_req_domain *cr_domains = NULL;
+ struct cache_req_domain *cr_domain;
+ struct sss_domain_info *dom;
+ char *name;
+ int flag = SSS_GND_ALL_DOMAINS;
+ int i;
+ errno_t ret;
+
+ if (resolution_order != NULL) {
+ for (i = 0; resolution_order[i] != NULL; i++) {
+ name = resolution_order[i];
+ for (dom = domains; dom; dom = get_next_domain(dom, flag)) {
+ if (strcasecmp(name, dom->name) != 0) {
+ continue;
+ }
+
+ cr_domain = talloc_zero(mem_ctx, struct cache_req_domain);
+ if (cr_domain == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ cr_domain->domain = dom;
+
+ DLIST_ADD_END(cr_domains, cr_domain,
+ struct cache_req_domain *);
+ break;
+ }
+ }
+ }
+
+ for (dom = domains; dom; dom = get_next_domain(dom, flag)) {
+ if (string_in_list(dom->name, resolution_order, false)) {
+ continue;
+ }
+
+ cr_domain = talloc_zero(mem_ctx, struct cache_req_domain);
+ if (cr_domain == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ cr_domain->domain = dom;
+
+ DLIST_ADD_END(cr_domains, cr_domain, struct cache_req_domain *);
+ }
+
+ ret = EOK;
+
+done:
+ if (ret != EOK) {
+ cache_req_domain_list_zfree(&cr_domains);
+ }
+
+ return cr_domains;
+}
+
+struct cache_req_domain *
+cache_req_domain_new_list_from_domain_resolution_order(
+ TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domains,
+ const char *domain_resolution_order)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct cache_req_domain *cr_domains = NULL;
+ char **list = NULL;
+ errno_t ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return NULL;
+ }
+
+ if (domain_resolution_order != NULL) {
+ if (strcmp(domain_resolution_order, ":") != 0) {
+ ret = split_on_separator(tmp_ctx, domain_resolution_order, ':',
+ true, true, &list, NULL);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "split_on_separator() failed [%d]: [%s].\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+ }
+ }
+
+ cr_domains = cache_req_domain_new_list_from_string_list(mem_ctx, domains,
+ list);
+ if (cr_domains == NULL) {
+ ret = ENOMEM;
+ DEBUG(SSSDBG_OP_FAILURE,
+ "cache_req_domain_new_list_from_domain_resolution_order() "
+ "failed [%d]: [%s].\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+done:
+ talloc_free(tmp_ctx);
+ return cr_domains;
+}
diff --git a/src/responder/common/cache_req/cache_req_domain.h b/src/responder/common/cache_req/cache_req_domain.h
new file mode 100644
index 0000000000000000000000000000000000000000..41c50e8c293d7b032cb2f05482c40e93e4f723dc
--- /dev/null
+++ b/src/responder/common/cache_req/cache_req_domain.h
@@ -0,0 +1,46 @@
+/*
+ Authors:
+ Fabiano Fidêncio <fidencio@redhat.com>
+
+ Copyright (C) 2017 Red Hat
+
+ 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/>.
+*/
+
+#ifndef _CACHE_REQ_DOMAIN_H_
+#define _CACHE_REQ_DOMAIN_H_
+
+#include "responder/common/responder.h"
+
+struct cache_req_domain {
+ struct sss_domain_info *domain;
+
+ struct cache_req_domain *prev;
+ struct cache_req_domain *next;
+};
+
+struct cache_req_domain *
+cache_req_domain_get_domain_by_name(struct cache_req_domain *domains,
+ const char *name);
+
+struct cache_req_domain *
+cache_req_domain_new_list_from_domain_resolution_order(
+ TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domains,
+ const char *domain_resolution_order);
+
+void cache_req_domain_list_zfree(struct cache_req_domain **cr_domains);
+
+
+#endif /* _CACHE_REQ_DOMAIN_H_ */
diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h
index 4d1048a1e0c9be2cad91317d51baf670ecb3307e..29e3f95caf484f43307c9c28d4abd3f50f360a95 100644
--- a/src/responder/common/responder.h
+++ b/src/responder/common/responder.h
@@ -37,6 +37,7 @@
#include "sbus/sssd_dbus.h"
#include "responder/common/negcache.h"
#include "sss_client/sss_cli.h"
+#include "responder/common/cache_req/cache_req_domain.h"
extern hash_table_t *dp_requests;
@@ -113,6 +114,8 @@ struct resp_ctx {
int domains_timeout;
int client_idle_timeout;
+ struct cache_req_domain *cr_domains;
+
time_t last_request_time;
int idle_timeout;
struct tevent_timer *idle;
@@ -387,4 +390,6 @@ char *sss_resp_create_fqname(TALLOC_CTX *mem_ctx,
bool name_is_upn,
const char *orig_name);
+errno_t sss_resp_populate_cr_domains(struct resp_ctx *rctx);
+
#endif /* __SSS_RESPONDER_H__ */
diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c
index 76f43609651217e537ffa515aaf5b5caa98a2e90..1792a4c3771fa326c7cca31e1981dce315c03758 100644
--- a/src/responder/common/responder_common.c
+++ b/src/responder/common/responder_common.c
@@ -1453,3 +1453,156 @@ fail:
return ret;
}
+
+/* ====== Helper functions for the domain resolution order ======= */
+static struct cache_req_domain *
+sss_resp_new_cr_domains_from_ipa_id_view(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domains,
+ struct sysdb_ctx *sysdb)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct cache_req_domain *cr_domains = NULL;
+ const char *domain_resolution_order = NULL;
+ errno_t ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return NULL;
+ }
+
+ ret = sysdb_get_view_domain_resolution_order(tmp_ctx, sysdb,
+ &domain_resolution_order);
+ if (ret != EOK && ret != ENOENT) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "sysdb_get_view_cache_req_domain() failed [%d]: [%s].\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ /* Using mem_ctx (which is rctx) directly here to avoid copying
+ * this memory around. */
+ cr_domains = cache_req_domain_new_list_from_domain_resolution_order(
+ mem_ctx, domains, domain_resolution_order);
+ if (cr_domains == NULL) {
+ ret = ENOMEM;
+ DEBUG(SSSDBG_DEFAULT,
+ "cache_req_domain_new_list_from_domain_resolution_order() "
+ "failed [%d]: [%s].\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+done:
+ talloc_free(tmp_ctx);
+ return cr_domains;
+}
+
+static struct cache_req_domain *
+sss_resp_new_cr_domains_from_ipa_config(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domains,
+ struct sysdb_ctx *sysdb,
+ const char *domain)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct cache_req_domain *cr_domains = NULL;
+ const char *domain_resolution_order = NULL;
+ errno_t ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return NULL;
+ }
+
+ ret = sysdb_domain_get_domain_resolution_order(tmp_ctx, sysdb, domain,
+ &domain_resolution_order);
+
+ if (ret != EOK && ret != ENOENT) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "sysdb_domain_get_cache_req_domain() failed [%d]: [%s].\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ /* Using mem_ctx (which is rctx) directly here to avoid copying
+ * this memory around. */
+ cr_domains = cache_req_domain_new_list_from_domain_resolution_order(
+ mem_ctx, domains, domain_resolution_order);
+ if (cr_domains == NULL) {
+ DEBUG(SSSDBG_DEFAULT,
+ "cache_req_domain_new_list_from_domain_resolution_order() "
+ "failed [%d]: [%s].\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+done:
+ talloc_free(tmp_ctx);
+ return cr_domains;
+}
+
+errno_t sss_resp_populate_cr_domains(struct resp_ctx *rctx)
+{
+ struct cache_req_domain *cr_domains = NULL;
+ struct sss_domain_info *dom;
+ errno_t ret;
+
+ for (dom = rctx->domains; dom != NULL; dom = dom->next) {
+ if (dom->provider != NULL && strcmp(dom->provider, "ipa") == 0) {
+ break;
+ }
+ }
+
+ if (dom == NULL) {
+ cr_domains = cache_req_domain_new_list_from_domain_resolution_order(
+ rctx, rctx->domains, NULL);
+ if (cr_domains == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to flatten the list of domains.\n");
+ }
+ goto done;
+ }
+
+ if (dom->has_views) {
+ cr_domains = sss_resp_new_cr_domains_from_ipa_id_view(rctx,
+ rctx->domains,
+ dom->sysdb);
+ if (cr_domains == NULL) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "Failed to use ipaDomainResolutionOrder set for the "
+ "view \"%s\".\n"
+ "Trying to fallback to use ipaDomainOrderResolution "
+ "set in ipaConfig for the domain: %s.\n",
+ dom->view_name, dom->name);
+ } else {
+ goto done;
+ }
+ }
+
+ cr_domains = sss_resp_new_cr_domains_from_ipa_config(rctx, rctx->domains,
+ dom->sysdb,
+ dom->name);
+ if (cr_domains == NULL) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "Failed to use ipaDomainResolutionOrder set in ipaConfig "
+ "for the domain: \"%s\".\n"
+ "No ipaDomainResolutionOrder will be followed.\n",
+ dom->name);
+ } else {
+ goto done;
+ }
+
+ cr_domains = cache_req_domain_new_list_from_domain_resolution_order(
+ rctx, rctx->domains, NULL);
+ if (cr_domains == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to flatten the list of domains.\n");
+ goto done;
+ }
+
+done:
+ ret = cr_domains != NULL ? EOK : ENOMEM;
+
+ cache_req_domain_list_zfree(&rctx->cr_domains);
+ rctx->cr_domains = cr_domains;
+
+ return ret;
+}
diff --git a/src/responder/common/responder_get_domains.c b/src/responder/common/responder_get_domains.c
index 0f9c01214631200f9687635f6302fa5c07e8a1fe..8c90b7773e248e1dd6d846c5050e1931fc50c786 100644
--- a/src/responder/common/responder_get_domains.c
+++ b/src/responder/common/responder_get_domains.c
@@ -192,6 +192,13 @@ struct tevent_req *sss_dp_get_domains_send(TALLOC_CTX *mem_ctx,
if (state->dom == NULL) {
/* All domains were local */
+ ret = sss_resp_populate_cr_domains(state->rctx);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "sss_resp_populate_cr_domains() failed [%d]: [%s]\n",
+ ret, sss_strerror(ret));
+ goto immediately;
+ }
ret = EOK;
goto immediately;
}
@@ -253,6 +260,13 @@ sss_dp_get_domains_process(struct tevent_req *subreq)
if (state->dom == NULL) {
/* All domains were local */
set_time_of_last_request(state->rctx);
+ ret = sss_resp_populate_cr_domains(state->rctx);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "sss_resp_populate_cr_domains() failed [%d]: [%s]\n",
+ ret, sss_strerror(ret));
+ goto fail;
+ }
tevent_req_done(req);
return;
}
diff --git a/src/tests/cmocka/common_mock_resp.c b/src/tests/cmocka/common_mock_resp.c
index 88808b1b9394b7a9ee7e58b30b4fbd9d467493d3..175101fc51fd395d792b1fccaecdb327caef2b64 100644
--- a/src/tests/cmocka/common_mock_resp.c
+++ b/src/tests/cmocka/common_mock_resp.c
@@ -51,6 +51,12 @@ mock_rctx(TALLOC_CTX *mem_ctx,
rctx->ev = ev;
rctx->domains = domains;
rctx->pvt_ctx = pvt_ctx;
+ if (domains != NULL) {
+ ret = sss_resp_populate_cr_domains(rctx);
+ if (ret != EOK) {
+ return NULL;
+ }
+ }
return rctx;
}
diff --git a/src/tests/cmocka/common_mock_resp_dp.c b/src/tests/cmocka/common_mock_resp_dp.c
index 5db5255ab61231870982c4b78a39504ae8954bcd..4b38a38e6f53499132f9fe14a0ec0af157cf85ca 100644
--- a/src/tests/cmocka/common_mock_resp_dp.c
+++ b/src/tests/cmocka/common_mock_resp_dp.c
@@ -21,6 +21,7 @@
*/
#include "util/util.h"
+#include "responder/common/responder.h"
#include "tests/cmocka/common_mock_resp.h"
/* Mock DP requests that finish immediatelly and return
@@ -165,6 +166,12 @@ sss_dp_get_domains_send(TALLOC_CTX *mem_ctx,
bool force,
const char *hint)
{
+ errno_t ret;
+ ret = sss_resp_populate_cr_domains(rctx);
+ if (ret != EOK) {
+ return NULL;
+ }
+
return test_req_succeed_send(mem_ctx, rctx->ev);
}
diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c
index ede72b341b60842ad470df2794aa90ea9797e999..2f526660cbbbf2443dbae4e213c1336feb6c661e 100644
--- a/src/tests/cmocka/test_nss_srv.c
+++ b/src/tests/cmocka/test_nss_srv.c
@@ -3440,6 +3440,10 @@ static int nss_subdom_test_setup(void **state)
nss_test_ctx->tctx->confdb);
assert_int_equal(ret, EOK);
+ ret = sss_resp_populate_cr_domains(nss_test_ctx->rctx);
+ assert_int_equal(ret, EOK);
+ assert_non_null(nss_test_ctx->rctx->cr_domains);
+
nss_test_ctx->subdom = nss_test_ctx->tctx->dom->subdomains;
ret = store_group(nss_test_ctx, nss_test_ctx->subdom,
diff --git a/src/tests/cwrap/Makefile.am b/src/tests/cwrap/Makefile.am
index 4a4090df9296aadde308249f533e7ba246e92f93..c99ebde5f0fc18d1283392cbb307434579d5d811 100644
--- a/src/tests/cwrap/Makefile.am
+++ b/src/tests/cwrap/Makefile.am
@@ -41,6 +41,7 @@ SSSD_CACHE_REQ_OBJ = \
../../../src/responder/common/cache_req/cache_req_result.c \
../../../src/responder/common/cache_req/cache_req_search.c \
../../../src/responder/common/cache_req/cache_req_data.c \
+ ../../../src/responder/common/cache_req/cache_req_domain.c \
../../../src/responder/common/cache_req/plugins/cache_req_common.c \
../../../src/responder/common/cache_req/plugins/cache_req_enum_users.c \
../../../src/responder/common/cache_req/plugins/cache_req_enum_groups.c \
--
2.12.2

View File

@ -1,81 +0,0 @@
From 1e437af958f59a0b8bf2f751d3c2ea28365ac64d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= <fidencio@redhat.com>
Date: Sun, 26 Mar 2017 01:49:53 +0100
Subject: [PATCH 56/97] UTIL: Expose replace_char() as sss_replace_char()
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This method is going to be used in the follow-up patch for replacing ','
by ':' so we can keep the domain resolution order option consitent with
the way it's set on IPA side and still keep consistent with the way
lists are represented on sssd.conf file.
Related:
https://pagure.io/SSSD/sssd/issue/3001
Signed-off-by: Fabiano Fidêncio <fidencio@redhat.com>
Reviewed-by: Sumit Bose <sbose@redhat.com>
Reviewed-by: Pavel Březina <pbrezina@redhat.com>
---
src/util/string_utils.c | 12 ++++++------
src/util/util.h | 5 +++++
2 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/src/util/string_utils.c b/src/util/string_utils.c
index 872b7e29e55e8628085affd07f3363019aae5ee9..1215ec96a57089a13f455812adf5a0b0812afa6d 100644
--- a/src/util/string_utils.c
+++ b/src/util/string_utils.c
@@ -22,10 +22,10 @@
#include "util/util.h"
-static char *replace_char(TALLOC_CTX *mem_ctx,
- const char *in,
- const char match,
- const char sub)
+char *sss_replace_char(TALLOC_CTX *mem_ctx,
+ const char *in,
+ const char match,
+ const char sub)
{
char *p;
char *out;
@@ -63,7 +63,7 @@ char * sss_replace_space(TALLOC_CTX *mem_ctx,
return talloc_strdup(mem_ctx, orig_name);
}
- return replace_char(mem_ctx, orig_name, ' ', subst);
+ return sss_replace_char(mem_ctx, orig_name, ' ', subst);
}
char * sss_reverse_replace_space(TALLOC_CTX *mem_ctx,
@@ -81,7 +81,7 @@ char * sss_reverse_replace_space(TALLOC_CTX *mem_ctx,
return talloc_strdup(mem_ctx, orig_name);
}
- return replace_char(mem_ctx, orig_name, subst, ' ');
+ return sss_replace_char(mem_ctx, orig_name, subst, ' ');
}
errno_t guid_blob_to_string_buf(const uint8_t *blob, char *str_buf,
diff --git a/src/util/util.h b/src/util/util.h
index 82760940269ad8883e725e3a5cf463486c9cfd36..2170c5fb7cffda3910d2b58e33ec7abe3ec4a7d4 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -600,6 +600,11 @@ errno_t name_to_well_known_sid(const char *dom, const char *name,
const char **sid);
/* from string_utils.c */
+char *sss_replace_char(TALLOC_CTX *mem_ctx,
+ const char *in,
+ const char match,
+ const char sub);
+
char * sss_replace_space(TALLOC_CTX *mem_ctx,
const char *orig_name,
const char replace_char);
--
2.12.2

View File

@ -1,205 +0,0 @@
From 16385568547351b5d2c562f3081f35f3341f695b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= <fidencio@redhat.com>
Date: Sun, 26 Mar 2017 03:00:14 +0200
Subject: [PATCH 57/97] Add domain_resolution_order config option
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This is the local equivalent of option of ipaDomainResolutionOrder and
has precedence over the ones set on IPA side making the precedence order
to be like: Local > View > Globally.
As done for the IPA side configurations, the domains which were not
explicitly set up will be apennded to the final of the
domain_resolution_order list in the very same order they're presented in
the "domains" option of [sssd] section in the config file. There's no
guarantee of order for the subdomains though.
It's also important to mention that no expansion magic is performed on
our side. It means that if 'example.com' is set it does *not* stand for
all its subdomains DNS wise (like 'foo.example.com', 'bar.example.com',
etc).
Related:
https://pagure.io/SSSD/sssd/issue/3001
Signed-off-by: Fabiano Fidêncio <fidencio@redhat.com>
Reviewed-by: Sumit Bose <sbose@redhat.com>
Reviewed-by: Pavel Březina <pbrezina@redhat.com>
---
src/confdb/confdb.h | 1 +
src/config/SSSDConfig/__init__.py.in | 1 +
src/config/SSSDConfigTest.py | 7 ++++++-
src/config/cfg_rules.ini | 1 +
src/config/etc/sssd.api.conf | 1 +
src/man/sssd.conf.5.xml | 20 ++++++++++++++++++++
src/responder/common/responder.h | 1 +
src/responder/common/responder_common.c | 27 +++++++++++++++++++++++++++
8 files changed, 58 insertions(+), 1 deletion(-)
diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
index fb60675ca8beb2c2a157bf021ed9cad362742988..56a603652d6c8256735e7f8b125300ff7b254645 100644
--- a/src/confdb/confdb.h
+++ b/src/confdb/confdb.h
@@ -74,6 +74,7 @@
#define CONFDB_MONITOR_CERT_VERIFICATION "certificate_verification"
#define CONFDB_MONITOR_DISABLE_NETLINK "disable_netlink"
#define CONFDB_MONITOR_ENABLE_FILES_DOM "enable_files_domain"
+#define CONFDB_MONITOR_DOMAIN_RESOLUTION_ORDER "domain_resolution_order"
/* Both monitor and domains */
#define CONFDB_NAME_REGEX "re_expression"
diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in
index 29e9b4fae6835db4ccb9937fd93457d462e4a15d..0edc3ea84a1e8fb0f797546b4c223e22e22f70e9 100644
--- a/src/config/SSSDConfig/__init__.py.in
+++ b/src/config/SSSDConfig/__init__.py.in
@@ -66,6 +66,7 @@ option_strings = {
'override_space': _('All spaces in group or user names will be replaced with this character'),
'disable_netlink' : _('Tune sssd to honor or ignore netlink state changes'),
'enable_files_domain' : _('Enable or disable the implicit files domain'),
+ 'domain_resolution_order': _('A specific order of the domains to be looked up'),
# [nss]
'enum_cache_timeout' : _('Enumeration cache timeout length (seconds)'),
diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py
index 457a6f0a09e7139a05f29f8bef7e475fe3b58ec2..6899bf8ae04bf210546c8cbdba8235f094e23dc0 100755
--- a/src/config/SSSDConfigTest.py
+++ b/src/config/SSSDConfigTest.py
@@ -94,6 +94,10 @@ class SSSDConfigTestValid(unittest.TestCase):
self.assertTrue('default_domain_suffix' in new_options)
self.assertEquals(new_options['default_domain_suffix'][0], str)
+ self.assertTrue('domain_resolution_order' in new_options)
+ self.assertEquals(new_options['domain_resolution_order'][0], list)
+ self.assertEquals(new_options['domain_resolution_order'][1], str)
+
del sssdconfig
def testDomains(self):
@@ -314,7 +318,8 @@ class SSSDConfigTestSSSDService(unittest.TestCase):
'certificate_verification',
'override_space',
'disable_netlink',
- 'enable_files_domain']
+ 'enable_files_domain',
+ 'domain_resolution_order']
self.assertTrue(type(options) == dict,
"Options should be a dictionary")
diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini
index 933ebccd828189d923d2186753dfbc0b5c0814ce..41efcea552a82c5492a0d21a8d0797ee42cdc8c7 100644
--- a/src/config/cfg_rules.ini
+++ b/src/config/cfg_rules.ini
@@ -43,6 +43,7 @@ option = override_space
option = config_file_version
option = disable_netlink
option = enable_files_domain
+option = domain_resolution_order
[rule/allowed_nss_options]
validator = ini_allowed_options
diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf
index 08cecf00367aaaab3794a48bd1e728421a996e49..6965028e1ca748f8b6677d9fc1faa66d5c307a0c 100644
--- a/src/config/etc/sssd.api.conf
+++ b/src/config/etc/sssd.api.conf
@@ -32,6 +32,7 @@ certificate_verification = str, None, false
override_space = str, None, false
disable_netlink = bool, None, false
enable_files_domain = str, None, false
+domain_resolution_order = list, str, false
[nss]
# Name service
diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
index 1c27742cf0c1b6ffad23ab5b044bf4a168ed8f69..4fe13b85d511fb6a2ccc9b4de956710b05bc898c 100644
--- a/src/man/sssd.conf.5.xml
+++ b/src/man/sssd.conf.5.xml
@@ -542,6 +542,26 @@
</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>domain_resolution_order</term>
+ <listitem>
+ <para>
+ Comma separated list of domains and subdomains
+ representing the lookup order that will be
+ followed.
+ The list doesn't have to include all possible
+ domains as the missing domains will be looked
+ up based on the order they're presented in the
+ <quote>domains</quote> configuration option.
+ The subdomains which are not listed as part of
+ <quote>lookup_order</quote> will be looked up
+ in a random order for each parent domain.
+ </para>
+ <para>
+ Default: Not set
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</para>
</refsect2>
diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h
index 29e3f95caf484f43307c9c28d4abd3f50f360a95..4210307489fe25829a1674f254ecc7d185029698 100644
--- a/src/responder/common/responder.h
+++ b/src/responder/common/responder.h
@@ -115,6 +115,7 @@ struct resp_ctx {
int client_idle_timeout;
struct cache_req_domain *cr_domains;
+ const char *domain_resolution_order;
time_t last_request_time;
int idle_timeout;
diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c
index 1792a4c3771fa326c7cca31e1981dce315c03758..154d7dc7718c437d10e152fcba98161e2034fb14 100644
--- a/src/responder/common/responder_common.c
+++ b/src/responder/common/responder_common.c
@@ -1163,6 +1163,19 @@ int sss_process_init(TALLOC_CTX *mem_ctx,
rctx->override_space = tmp[0];
}
+ ret = confdb_get_string(rctx->cdb, rctx,
+ CONFDB_MONITOR_CONF_ENTRY,
+ CONFDB_MONITOR_DOMAIN_RESOLUTION_ORDER, NULL,
+ &tmp);
+ if (ret == EOK) {
+ rctx->domain_resolution_order = sss_replace_char(rctx, tmp, ',', ':');
+ } else {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "Cannot get the \"domain_resolution_order\" option.\n"
+ "The set up lookup_order won't be followed [%d]: %s.\n",
+ ret, sss_strerror(ret));
+ }
+
ret = sss_monitor_init(rctx, rctx->ev, monitor_intf,
svc_name, svc_version, MT_SVC_SERVICE,
rctx, &rctx->last_request_time,
@@ -1546,6 +1559,20 @@ errno_t sss_resp_populate_cr_domains(struct resp_ctx *rctx)
struct sss_domain_info *dom;
errno_t ret;
+ if (rctx->domain_resolution_order != NULL) {
+ cr_domains = cache_req_domain_new_list_from_domain_resolution_order(
+ rctx, rctx->domains, rctx->domain_resolution_order);
+
+ if (cr_domains == NULL) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "Failed to use domain_resolution_order set in the config file.\n"
+ "Trying to fallback to use ipaDomainOrderResolution setup by "
+ "IPA.\n");
+ } else {
+ goto done;
+ }
+ }
+
for (dom = rctx->domains; dom != NULL; dom = dom->next) {
if (dom->provider != NULL && strcmp(dom->provider, "ipa") == 0) {
break;
--
2.12.2

View File

@ -1,48 +0,0 @@
From bd1fa0ec90be717c3b7796d74b6f243f40178d16 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Thu, 16 Mar 2017 12:38:08 +0100
Subject: [PATCH 58/97] ssh: handle binary keys correctly
Related to https://pagure.io/SSSD/sssd/issue/3332
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
---
src/responder/ssh/ssh_reply.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/src/responder/ssh/ssh_reply.c b/src/responder/ssh/ssh_reply.c
index 807f4ee079128b4a3f1719de890ffac6e0d5b2e0..7093e47253b5687bab387feed5299c2d0841d43c 100644
--- a/src/responder/ssh/ssh_reply.c
+++ b/src/responder/ssh/ssh_reply.c
@@ -32,6 +32,11 @@
#include "responder/common/cache_req/cache_req.h"
#include "responder/ssh/ssh_private.h"
+/* Locally used flag for libldb's ldb_message_element structure to indicate
+ * binary data. Since the related data is only used in memory it is safe. If
+ * should be used with care if libldb's I/O operations are involved. */
+#define SSS_EL_FLAG_BIN_DATA (1<<4)
+
static errno_t get_valid_certs_keys(TALLOC_CTX *mem_ctx,
struct ssh_ctx *ssh_ctx,
struct ldb_message_element *el_cert,
@@ -148,7 +153,7 @@ static errno_t decode_and_add_base64_data(struct sss_packet *packet,
}
for (d = 0; d < el->num_values; d++) {
- if (skip_base64_decode) {
+ if (skip_base64_decode || (el->flags & SSS_EL_FLAG_BIN_DATA)) {
key = el->values[d].data;
key_len = el->values[d].length;
} else {
@@ -233,6 +238,7 @@ ssh_get_output_keys(TALLOC_CTX *mem_ctx,
}
if (elements[i] != NULL) {
+ elements[i]->flags |= SSS_EL_FLAG_BIN_DATA;
num_keys += elements[i]->num_values;
i++;
}
--
2.12.2

View File

@ -1,52 +0,0 @@
From 1b5d6b1afc9c3dc696b7b45f2d73b2634f42800a Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Thu, 16 Mar 2017 13:00:48 +0100
Subject: [PATCH 59/97] ssh: add support for certificates from non-default
views
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
---
src/responder/ssh/ssh_reply.c | 20 +++++++++++++++++++-
1 file changed, 19 insertions(+), 1 deletion(-)
diff --git a/src/responder/ssh/ssh_reply.c b/src/responder/ssh/ssh_reply.c
index 7093e47253b5687bab387feed5299c2d0841d43c..1bb9d331868cc18488718c24fd82f32af780b525 100644
--- a/src/responder/ssh/ssh_reply.c
+++ b/src/responder/ssh/ssh_reply.c
@@ -204,7 +204,7 @@ ssh_get_output_keys(TALLOC_CTX *mem_ctx,
uint32_t i = 0;
errno_t ret;
- elements = talloc_zero_array(mem_ctx, struct ldb_message_element *, 5);
+ elements = talloc_zero_array(mem_ctx, struct ldb_message_element *, 6);
if (elements == NULL) {
return ENOMEM;
}
@@ -244,6 +244,24 @@ ssh_get_output_keys(TALLOC_CTX *mem_ctx,
}
}
+ if (DOM_HAS_VIEWS(domain)) {
+ user_cert = ldb_msg_find_element(msg, OVERRIDE_PREFIX SYSDB_USER_CERT);
+ if (user_cert != NULL) {
+ ret = get_valid_certs_keys(elements, ssh_ctx, user_cert,
+ &elements[i]);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "get_valid_certs_keys failed.\n");
+ goto done;
+ }
+
+ if (elements[i] != NULL) {
+ elements[i]->flags |= SSS_EL_FLAG_BIN_DATA;
+ num_keys += elements[i]->num_values;
+ i++;
+ }
+ }
+ }
+
*_elements = elements;
*_num_keys = num_keys;
--
2.12.2

View File

@ -1,60 +0,0 @@
From 1c551b1373799643f3e9ba4f696d21b8fc57dafd Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Thu, 16 Mar 2017 20:43:08 +0100
Subject: [PATCH 60/97] krb5: return to responder that pkinit is not available
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
If pkinit is not available for a user but other authentication methods
are SSSD should still fall back to local certificate based
authentication if Smartcard credentials are provided.
Resolves https://pagure.io/SSSD/sssd/issue/3343
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
---
src/providers/krb5/krb5_child.c | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c
index 777a25f2a0ea434dde12d2396f6a35c2a1b86cd0..a4128dda6b0861a95dba223047d66c4158b1afb6 100644
--- a/src/providers/krb5/krb5_child.c
+++ b/src/providers/krb5/krb5_child.c
@@ -42,6 +42,10 @@
#define SSSD_KRB5_CHANGEPW_PRINCIPAL "kadmin/changepw"
+#define IS_SC_AUTHTOK(tok) ( \
+ sss_authtok_get_type((tok)) == SSS_AUTHTOK_TYPE_SC_PIN \
+ || sss_authtok_get_type((tok)) == SSS_AUTHTOK_TYPE_SC_KEYPAD)
+
enum k5c_fast_opt {
K5C_FAST_NEVER,
K5C_FAST_TRY,
@@ -1529,12 +1533,17 @@ static krb5_error_code get_and_save_tgt(struct krb5_req *kr,
* pre-auth module is missing or no Smartcard is inserted and only
* pkinit is available KRB5_PREAUTH_FAILED is returned.
* ERR_NO_AUTH_METHOD_AVAILABLE is used to indicate to the
- * frontend that local authentication might be tried. */
+ * frontend that local authentication might be tried.
+ * Same is true if Smartcard credentials are given but only other
+ * authentication methods are available. */
if (kr->pd->cmd == SSS_PAM_AUTHENTICATE
&& kerr == KRB5_PREAUTH_FAILED
- && kr->password_prompting == false
- && kr->otp == false
- && kr->pkinit_prompting == false) {
+ && kr->pkinit_prompting == false
+ && (( kr->password_prompting == false
+ && kr->otp == false)
+ || ((kr->otp == true
+ || kr->password_prompting == true)
+ && IS_SC_AUTHTOK(kr->pd->authtok))) ) {
return ERR_NO_AUTH_METHOD_AVAILABLE;
}
return kerr;
--
2.12.2

View File

@ -1,153 +0,0 @@
From 415d93196533a6fcd90889c67396ef5af5bf791a Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Wed, 22 Mar 2017 14:13:05 +0100
Subject: [PATCH 61/97] IPA: add mapped attributes to user from trusted domains
Allow the usage of the mapped attribute for the lookup of AD users on
IPA clients as already used for the normal LDAP lookup.
Related to https://pagure.io/SSSD/sssd/issue/3050
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
---
src/providers/ipa/ipa_s2n_exop.c | 33 ++++++++++++++++++++++++---------
1 file changed, 24 insertions(+), 9 deletions(-)
diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
index c99312274073858e5e03f3e82c069dafc839eb61..05c32a24d61947e62884f460069083fb81f40fe0 100644
--- a/src/providers/ipa/ipa_s2n_exop.c
+++ b/src/providers/ipa/ipa_s2n_exop.c
@@ -761,6 +761,7 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
struct resp_attrs *simple_attrs,
const char *view_name,
struct sysdb_attrs *override_attrs,
+ struct sysdb_attrs *mapped_attrs,
bool update_initgr_timeout);
static errno_t s2n_response_to_attrs(TALLOC_CTX *mem_ctx,
@@ -1009,6 +1010,7 @@ struct ipa_s2n_get_list_state {
struct resp_attrs *attrs;
struct sss_domain_info *obj_domain;
struct sysdb_attrs *override_attrs;
+ struct sysdb_attrs *mapped_attrs;
};
static errno_t ipa_s2n_get_list_step(struct tevent_req *req);
@@ -1025,7 +1027,8 @@ static struct tevent_req *ipa_s2n_get_list_send(TALLOC_CTX *mem_ctx,
int entry_type,
enum request_types request_type,
enum req_input_type list_type,
- char **list)
+ char **list,
+ struct sysdb_attrs *mapped_attrs)
{
int ret;
struct ipa_s2n_get_list_state *state;
@@ -1057,6 +1060,7 @@ static struct tevent_req *ipa_s2n_get_list_send(TALLOC_CTX *mem_ctx,
state->request_type = request_type;
state->attrs = NULL;
state->override_attrs = NULL;
+ state->mapped_attrs = mapped_attrs;
ret = ipa_s2n_get_list_step(req);
if (ret != EOK) {
@@ -1288,7 +1292,8 @@ static errno_t ipa_s2n_get_list_save_step(struct tevent_req *req)
ret = ipa_s2n_save_objects(state->dom, &state->req_input, state->attrs,
NULL, state->ipa_ctx->view_name,
- state->override_attrs, false);
+ state->override_attrs, state->mapped_attrs,
+ false);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_save_objects failed.\n");
return ret;
@@ -1704,7 +1709,7 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq)
BE_REQ_GROUP,
REQ_FULL_WITH_MEMBERS,
REQ_INP_NAME,
- missing_list);
+ missing_list, NULL);
if (subreq == NULL) {
DEBUG(SSSDBG_OP_FAILURE,
"ipa_s2n_get_list_send failed.\n");
@@ -1732,7 +1737,7 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq)
BE_REQ_USER,
REQ_FULL_WITH_MEMBERS,
REQ_INP_NAME,
- missing_list);
+ missing_list, NULL);
if (subreq == NULL) {
DEBUG(SSSDBG_OP_FAILURE,
"ipa_s2n_get_list_send failed.\n");
@@ -1810,7 +1815,7 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq)
if (ret == ENOENT || is_default_view(state->ipa_ctx->view_name)) {
ret = ipa_s2n_save_objects(state->dom, state->req_input, state->attrs,
- state->simple_attrs, NULL, NULL, true);
+ state->simple_attrs, NULL, NULL, NULL, true);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_save_objects failed.\n");
goto done;
@@ -1978,6 +1983,7 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
struct resp_attrs *simple_attrs,
const char *view_name,
struct sysdb_attrs *override_attrs,
+ struct sysdb_attrs *mapped_attrs,
bool update_initgr_timeout)
{
int ret;
@@ -2305,6 +2311,15 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
goto done;
}
+ if (mapped_attrs != NULL) {
+ ret = sysdb_set_user_attr(dom, name, mapped_attrs,
+ SYSDB_MOD_ADD);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_set_user_attr failed.\n");
+ goto done;
+ }
+ }
+
if (gid_override_attrs != NULL) {
ret = sysdb_set_user_attr(dom, name, gid_override_attrs,
SYSDB_MOD_REP);
@@ -2487,7 +2502,7 @@ static void ipa_s2n_get_list_done(struct tevent_req *subreq)
&sid_str);
if (ret == ENOENT) {
ret = ipa_s2n_save_objects(state->dom, state->req_input, state->attrs,
- state->simple_attrs, NULL, NULL, true);
+ state->simple_attrs, NULL, NULL, NULL, true);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_save_objects failed.\n");
goto fail;
@@ -2525,7 +2540,7 @@ static void ipa_s2n_get_list_done(struct tevent_req *subreq)
ret = ipa_s2n_save_objects(state->dom, state->req_input, state->attrs,
state->simple_attrs,
state->ipa_ctx->view_name,
- state->override_attrs, true);
+ state->override_attrs, NULL, true);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_save_objects failed.\n");
tevent_req_error(req, ret);
@@ -2561,7 +2576,7 @@ static void ipa_s2n_get_user_get_override_done(struct tevent_req *subreq)
ret = ipa_s2n_save_objects(state->dom, state->req_input, state->attrs,
state->simple_attrs, state->ipa_ctx->view_name,
- override_attrs, true);
+ override_attrs, NULL, true);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_save_objects failed.\n");
tevent_req_error(req, ret);
@@ -2662,7 +2677,7 @@ struct tevent_req *ipa_get_subdom_acct_process_pac_send(TALLOC_CTX *mem_ctx,
dp_opt_get_int(ipa_ctx->sdap_id_ctx->opts->basic,
SDAP_SEARCH_TIMEOUT),
BE_REQ_BY_SECID, REQ_FULL, REQ_INP_SECID,
- state->missing_sids);
+ state->missing_sids, NULL);
if (subreq == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_get_list_send failed.\n");
ret = ENOMEM;
--
2.12.2

View File

@ -1,209 +0,0 @@
From 2cf7becc05996eb6d8a3352d3d7b97c75652e590 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Fri, 24 Mar 2017 15:40:41 +0100
Subject: [PATCH 62/97] IPA: lookup AD users by certificates on IPA clients
Get a list of users mapped to a certificate back from the IPA server,
look them up and store them together with the certificate used for the
search as mapped attribute to the cache.
Related to https://pagure.io/SSSD/sssd/issue/3050
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
---
src/providers/ipa/ipa_s2n_exop.c | 109 +++++++++++++++++++++++++++++++++++++--
1 file changed, 105 insertions(+), 4 deletions(-)
diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
index 05c32a24d61947e62884f460069083fb81f40fe0..8a3391b4093f1547d84fe44a0f24b1d063d1e28c 100644
--- a/src/providers/ipa/ipa_s2n_exop.c
+++ b/src/providers/ipa/ipa_s2n_exop.c
@@ -52,7 +52,8 @@ enum response_types {
RESP_USER,
RESP_GROUP,
RESP_USER_GROUPLIST,
- RESP_GROUP_MEMBERS
+ RESP_GROUP_MEMBERS,
+ RESP_NAME_LIST
};
/* ==Sid2Name Extended Operation============================================= */
@@ -366,8 +367,8 @@ static errno_t s2n_encode_request(TALLOC_CTX *mem_ctx,
break;
case BE_REQ_BY_CERT:
if (req_input->type == REQ_INP_CERT) {
- ret = ber_printf(ber, "{ees}", INP_CERT, request_type,
- req_input->inp.cert);
+ ret = ber_printf(ber, "{ees}", INP_CERT, request_type,
+ req_input->inp.cert);
} else {
DEBUG(SSSDBG_OP_FAILURE, "Unexpected input type [%d].\n",
req_input->type);
@@ -463,6 +464,11 @@ done:
* GroupMemberList ::= SEQUENCE OF OCTET STRING
*/
+struct name_list {
+ char *domain_name;
+ char *name;
+};
+
struct resp_attrs {
enum response_types response_type;
char *domain_name;
@@ -475,6 +481,7 @@ struct resp_attrs {
size_t ngroups;
char **groups;
struct sysdb_attrs *sysdb_attrs;
+ char **name_list;
};
static errno_t get_extra_attrs(BerElement *ber, struct resp_attrs *resp_attrs)
@@ -782,6 +789,9 @@ static errno_t s2n_response_to_attrs(TALLOC_CTX *mem_ctx,
struct resp_attrs *attrs = NULL;
char *sid_str;
bool is_v1 = false;
+ char **name_list = NULL;
+ ber_len_t ber_len;
+ char *fq_name = NULL;
if (retoid == NULL || retdata == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "Missing OID or data.\n");
@@ -947,6 +957,53 @@ static errno_t s2n_response_to_attrs(TALLOC_CTX *mem_ctx,
goto done;
}
break;
+ case RESP_NAME_LIST:
+ tag = ber_scanf(ber, "{");
+ if (tag == LBER_ERROR) {
+ DEBUG(SSSDBG_OP_FAILURE, "ber_scanf failed.\n");
+ ret = EINVAL;
+ goto done;
+ }
+
+ while (ber_peek_tag(ber, &ber_len) == LBER_SEQUENCE) {
+ tag = ber_scanf(ber, "{aa}", &domain_name, &name);
+ if (tag == LBER_ERROR) {
+ DEBUG(SSSDBG_OP_FAILURE, "ber_scanf failed.\n");
+ ret = EINVAL;
+ goto done;
+ }
+
+ fq_name = sss_create_internal_fqname(attrs, name, domain_name);
+ if (fq_name == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "sss_create_internal_fqname failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+ DEBUG(SSSDBG_TRACE_ALL, "[%s][%s][%s].\n", domain_name, name,
+ fq_name);
+
+ ret = add_string_to_list(attrs, fq_name, &name_list);
+ ber_memfree(domain_name);
+ ber_memfree(name);
+ talloc_free(fq_name);
+ domain_name = NULL;
+ name = NULL;
+ fq_name = NULL;
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "add_to_name_list failed.\n");
+ goto done;
+ }
+ }
+
+ tag = ber_scanf(ber, "}}");
+ if (tag == LBER_ERROR) {
+ DEBUG(SSSDBG_OP_FAILURE, "ber_scanf failed.\n");
+ ret = EINVAL;
+ goto done;
+ }
+ attrs->name_list = name_list;
+ break;
default:
DEBUG(SSSDBG_OP_FAILURE, "Unexpected response type [%d].\n",
type);
@@ -955,7 +1012,7 @@ static errno_t s2n_response_to_attrs(TALLOC_CTX *mem_ctx,
}
attrs->response_type = type;
- if (type != RESP_SID) {
+ if (type != RESP_SID && type != RESP_NAME_LIST) {
attrs->domain_name = talloc_strdup(attrs, domain_name);
if (attrs->domain_name == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
@@ -969,6 +1026,7 @@ static errno_t s2n_response_to_attrs(TALLOC_CTX *mem_ctx,
done:
ber_memfree(domain_name);
ber_memfree(name);
+ talloc_free(fq_name);
ber_free(ber, 1);
if (ret == EOK) {
@@ -1332,6 +1390,7 @@ struct ipa_s2n_get_user_state {
struct resp_attrs *attrs;
struct resp_attrs *simple_attrs;
struct sysdb_attrs *override_attrs;
+ struct sysdb_attrs *mapped_attrs;
int exop_timeout;
};
@@ -1384,6 +1443,11 @@ struct tevent_req *ipa_s2n_get_acct_info_send(TALLOC_CTX *mem_ctx,
goto fail;
}
+ if (entry_type == BE_REQ_BY_CERT) {
+ /* Only REQ_SIMPLE is supported for BE_REQ_BY_CERT */
+ state->request_type = REQ_SIMPLE;
+ }
+
ret = s2n_encode_request(state, dom->name, entry_type, state->request_type,
req_input, &bv_req);
if (ret != EOK) {
@@ -1785,6 +1849,43 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq)
goto done;
}
+ if (state->simple_attrs->response_type == RESP_NAME_LIST
+ && state->req_input->type == REQ_INP_CERT) {
+ state->mapped_attrs = sysdb_new_attrs(state);
+ if (state->mapped_attrs == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_new_attrs failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = sysdb_attrs_add_base64_blob(state->mapped_attrs,
+ SYSDB_USER_MAPPED_CERT,
+ state->req_input->inp.cert);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_base64_blob failed.\n");
+ goto done;
+ }
+
+ subreq = ipa_s2n_get_list_send(state, state->ev,
+ state->ipa_ctx, state->dom,
+ state->sh, state->exop_timeout,
+ BE_REQ_USER,
+ REQ_FULL_WITH_MEMBERS,
+ REQ_INP_NAME,
+ state->simple_attrs->name_list,
+ state->mapped_attrs);
+ if (subreq == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "ipa_s2n_get_list_send failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+ tevent_req_set_callback(subreq, ipa_s2n_get_list_done,
+ req);
+
+ return;
+ }
+
break;
default:
DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected request type.\n");
--
2.12.2

View File

@ -1,30 +0,0 @@
From 82843754193b177275ce16f2901edac2060a3998 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Fri, 24 Mar 2017 15:41:37 +0100
Subject: [PATCH 63/97] IPA: enable AD user lookup by certificate
Without this the lookup by certificate for AD users on an IPA client
will just error out.
Related to https://pagure.io/SSSD/sssd/issue/3050
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
---
src/providers/ipa/ipa_subdomains_id.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c
index 4777d7cfd97fed39b807a659fd1f9000c7ff8625..3530af94ef59397db72465fcb0c4a03117a4d8bd 100644
--- a/src/providers/ipa/ipa_subdomains_id.c
+++ b/src/providers/ipa/ipa_subdomains_id.c
@@ -399,6 +399,7 @@ struct tevent_req *ipa_get_subdom_acct_send(TALLOC_CTX *memctx,
case BE_REQ_USER:
case BE_REQ_GROUP:
case BE_REQ_BY_SECID:
+ case BE_REQ_BY_CERT:
case BE_REQ_USER_AND_GROUP:
ret = EOK;
break;
--
2.12.2

View File

@ -1,242 +0,0 @@
From 6324eaf1fb321c41ca9883966118df6d45259b7e Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Wed, 22 Mar 2017 12:53:17 +0100
Subject: [PATCH 64/97] CONFDB: Introduce SSSD domain type to distinguish POSIX
and application domains
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Related to:
https://pagure.io/SSSD/sssd/issue/3310
Adds a new option that allows to distinguish domains that do contain
POSIX users and groups and those that don't. The POSIX domains are the
default. The non-POSIX domains are selected by selecting an
"application" type domain.
Reviewed-by: Sumit Bose <sbose@redhat.com>
Reviewed-by: Pavel Březina <pbrezina@redhat.com>
---
src/confdb/confdb.c | 18 +++++++++++++++++-
src/confdb/confdb.h | 15 +++++++++++++++
src/config/SSSDConfig/__init__.py.in | 1 +
src/config/SSSDConfigTest.py | 2 ++
src/config/cfg_rules.ini | 1 +
src/config/etc/sssd.api.conf | 1 +
src/man/sssd.conf.5.xml | 33 +++++++++++++++++++++++++++++++++
src/util/domain_info_utils.c | 14 ++++++++++++++
src/util/util.h | 1 +
9 files changed, 85 insertions(+), 1 deletion(-)
diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c
index d82fd98ee02928b3c20df014528bd869ec946f92..70a1eb7b2c7e83dfa9d217a15c7d3d4c8580b891 100644
--- a/src/confdb/confdb.c
+++ b/src/confdb/confdb.c
@@ -1367,6 +1367,22 @@ static int confdb_get_domain_internal(struct confdb_ctx *cdb,
}
}
+ domain->type = DOM_TYPE_POSIX;
+ tmp = ldb_msg_find_attr_as_string(res->msgs[0],
+ CONFDB_DOMAIN_TYPE,
+ CONFDB_DOMAIN_TYPE_POSIX);
+ if (tmp != NULL) {
+ if (strcasecmp(tmp, CONFDB_DOMAIN_TYPE_POSIX) == 0) {
+ domain->type = DOM_TYPE_POSIX;
+ } else if (strcasecmp(tmp, CONFDB_DOMAIN_TYPE_APP) == 0) {
+ domain->type = DOM_TYPE_APPLICATION;
+ } else {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Invalid value %s for [%s]\n", tmp, CONFDB_DOMAIN_TYPE);
+ goto done;
+ }
+ }
+
ret = get_entry_as_uint32(res->msgs[0], &domain->subdomain_refresh_interval,
CONFDB_DOMAIN_SUBDOMAIN_REFRESH, 14400);
if (ret != EOK || domain->subdomain_refresh_interval == 0) {
@@ -1444,7 +1460,7 @@ int confdb_get_domains(struct confdb_ctx *cdb,
if (ret) {
DEBUG(SSSDBG_FATAL_FAILURE,
"Error (%d [%s]) retrieving domain [%s], skipping!\n",
- ret, sss_strerror(ret), domlist[i]);
+ ret, sss_strerror(ret), domlist[i]);
continue;
}
diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
index 56a603652d6c8256735e7f8b125300ff7b254645..a4046610f3cdbdb832de8924bf4397fb0018f2db 100644
--- a/src/confdb/confdb.h
+++ b/src/confdb/confdb.h
@@ -209,6 +209,9 @@
#define CONFDB_DOMAIN_OFFLINE_TIMEOUT "offline_timeout"
#define CONFDB_DOMAIN_SUBDOMAIN_INHERIT "subdomain_inherit"
#define CONFDB_DOMAIN_CACHED_AUTH_TIMEOUT "cached_auth_timeout"
+#define CONFDB_DOMAIN_TYPE "domain_type"
+#define CONFDB_DOMAIN_TYPE_POSIX "posix"
+#define CONFDB_DOMAIN_TYPE_APP "application"
/* Local Provider */
#define CONFDB_LOCAL_DEFAULT_SHELL "default_shell"
@@ -261,11 +264,23 @@ enum sss_domain_state {
DOM_INCONSISTENT,
};
+/** Whether the domain only supports looking up POSIX entries */
+enum sss_domain_type {
+ /** This is the default domain type. It resolves only entries
+ * with the full POSIX set of attributes
+ */
+ DOM_TYPE_POSIX,
+ /** In this mode, entries are typically resolved only by name */
+ DOM_TYPE_APPLICATION,
+};
+
/**
* Data structure storing all of the basic features
* of a domain.
*/
struct sss_domain_info {
+ enum sss_domain_type type;
+
char *name;
char *conn_name;
char *provider;
diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in
index 0edc3ea84a1e8fb0f797546b4c223e22e22f70e9..070994bcd04604777019d264d12cb126d6638bfd 100644
--- a/src/config/SSSDConfig/__init__.py.in
+++ b/src/config/SSSDConfig/__init__.py.in
@@ -148,6 +148,7 @@ option_strings = {
'selinux_provider' : _('SELinux provider'),
# [domain]
+ 'domain_type' : _('Whether the domain is usable by the OS or by applications'),
'min_id' : _('Minimum user ID'),
'max_id' : _('Maximum user ID'),
'enumerate' : _('Enable enumerating all users/groups'),
diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py
index 6899bf8ae04bf210546c8cbdba8235f094e23dc0..9b3175962c697e314b3d5d94c2bc5beda537b66e 100755
--- a/src/config/SSSDConfigTest.py
+++ b/src/config/SSSDConfigTest.py
@@ -510,6 +510,7 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase):
'debug',
'debug_level',
'debug_timestamps',
+ 'domain_type',
'min_id',
'max_id',
'timeout',
@@ -878,6 +879,7 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase):
'debug',
'debug_level',
'debug_timestamps',
+ 'domain_type',
'min_id',
'max_id',
'timeout',
diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini
index 41efcea552a82c5492a0d21a8d0797ee42cdc8c7..3c857236eaa55b313d176bc4bb479918163b60d5 100644
--- a/src/config/cfg_rules.ini
+++ b/src/config/cfg_rules.ini
@@ -311,6 +311,7 @@ option = subdomains_provider
option = selinux_provider
# Options available to all domains
+option = domain_type
option = min_id
option = max_id
option = timeout
diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf
index 6965028e1ca748f8b6677d9fc1faa66d5c307a0c..a38b24208f89e4502e41625c540ea9958d5bbffe 100644
--- a/src/config/etc/sssd.api.conf
+++ b/src/config/etc/sssd.api.conf
@@ -129,6 +129,7 @@ selinux_provider = str, None, false
[domain]
# Options available to all domains
description = str, None, false
+domain_type = str, None, false
debug = int, None, false
debug_level = int, None, false
debug_timestamps = bool, None, false
diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
index 4fe13b85d511fb6a2ccc9b4de956710b05bc898c..9abcff84a95ea1b27e36845e830cc125fdc89f90 100644
--- a/src/man/sssd.conf.5.xml
+++ b/src/man/sssd.conf.5.xml
@@ -1512,6 +1512,39 @@ pam_account_locked_message = Account locked, please contact help desk.
<quote>[domain/<replaceable>NAME</replaceable>]</quote>
<variablelist>
<varlistentry>
+ <term>domain_type (string)</term>
+ <listitem>
+ <para>
+ Specifies whether the domain is meant to be used
+ by POSIX-aware clients such as the Name Service Switch
+ or by applications that do not need POSIX data to be
+ present or generated. Only objects from POSIX domains
+ are available to the operating system interfaces and
+ utilities.
+ </para>
+ <para>
+ Allowed values for this option are <quote>posix</quote>
+ and <quote>application</quote>.
+ </para>
+ <para>
+ POSIX domains are reachable by all services. Application
+ domains are only reachable from the InfoPipe responder (see
+ <citerefentry>
+ <refentrytitle>sssd-ifp</refentrytitle>
+ <manvolnum>5</manvolnum>
+ </citerefentry>) and the PAM responder.
+ </para>
+ <para>
+ NOTE: The application domains are currently well tested with
+ <quote>id_provider=ldap</quote> only.
+ </para>
+ <para>
+ Default: posix
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term>min_id,max_id (integer)</term>
<listitem>
<para>
diff --git a/src/util/domain_info_utils.c b/src/util/domain_info_utils.c
index a7f118842aa8ba870143b2f2b425a3e3c0ea5a78..2af7852f03f89b61f5b9fd8a244e98fb27b7e6a2 100644
--- a/src/util/domain_info_utils.c
+++ b/src/util/domain_info_utils.c
@@ -885,3 +885,17 @@ char *subdomain_create_conf_path(TALLOC_CTX *mem_ctx,
subdomain->parent->name,
subdomain->name);
}
+
+const char *sss_domain_type_str(struct sss_domain_info *dom)
+{
+ if (dom == NULL) {
+ return "BUG: Invalid domain";
+ }
+ switch (dom->type) {
+ case DOM_TYPE_POSIX:
+ return "POSIX";
+ case DOM_TYPE_APPLICATION:
+ return "Application";
+ }
+ return "Unknown";
+}
diff --git a/src/util/util.h b/src/util/util.h
index 2170c5fb7cffda3910d2b58e33ec7abe3ec4a7d4..436550f5078cc173b8ed8cb58836d366f813146b 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -539,6 +539,7 @@ enum sss_domain_state sss_domain_get_state(struct sss_domain_info *dom);
void sss_domain_set_state(struct sss_domain_info *dom,
enum sss_domain_state state);
bool is_email_from_domain(const char *email, struct sss_domain_info *dom);
+const char *sss_domain_type_str(struct sss_domain_info *dom);
struct sss_domain_info*
sss_get_domain_by_sid_ldap_fallback(struct sss_domain_info *domain,
--
2.12.2

View File

@ -1,531 +0,0 @@
From 825e8bf2f73a815c2eceb36ae805145fcbacf74d Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Mon, 27 Mar 2017 09:48:46 +0200
Subject: [PATCH 65/97] CONFDB: Allow configuring [application] sections as
non-POSIX domains
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Related to:
https://pagure.io/SSSD/sssd/issue/3310
Allows to add a new section:
[application/$name]
This section internally (on the confdb level) expands to:
[domain/$name]
domain_type = application
The reasons to add this new section is two-fold. One, to make the
configuration of application domains more explicit and two, to make it
possible to share configuration between two domains, one POSIX and one
non-POSIX by application domain's inherit_from option:
[application/$name]
inherit_from = posix_domain_name
Reviewed-by: Sumit Bose <sbose@redhat.com>
Reviewed-by: Pavel Březina <pbrezina@redhat.com>
---
src/confdb/confdb.c | 288 ++++++++++++++++++++++++++++++++++++++++++++---
src/confdb/confdb.h | 4 +
src/config/cfg_rules.ini | 9 +-
src/man/sssd.conf.5.xml | 77 +++++++++++++
src/monitor/monitor.c | 8 ++
5 files changed, 368 insertions(+), 18 deletions(-)
diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c
index 70a1eb7b2c7e83dfa9d217a15c7d3d4c8580b891..88e114457deac3ca50c291a131122624fb6f6fe4 100644
--- a/src/confdb/confdb.c
+++ b/src/confdb/confdb.c
@@ -813,6 +813,50 @@ done:
return ret;
}
+static int confdb_get_domain_section(TALLOC_CTX *mem_ctx,
+ struct confdb_ctx *cdb,
+ const char *section,
+ const char *name,
+ struct ldb_result **_res)
+{
+ TALLOC_CTX *tmp_ctx;
+ int ret;
+ struct ldb_result *res;
+ struct ldb_dn *dn;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ dn = ldb_dn_new_fmt(tmp_ctx, cdb->ldb, "cn=%s,%s", name, section);
+ if (dn == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_search(cdb->ldb, tmp_ctx, &res, dn,
+ LDB_SCOPE_BASE, NULL, NULL);
+ if (ret != LDB_SUCCESS) {
+ ret = sysdb_error_to_errno(ret);
+ goto done;
+ }
+
+ if (res->count == 0) {
+ ret = ENOENT;
+ goto done;
+ } else if (res->count > 1) {
+ ret = E2BIG;
+ goto done;
+ }
+
+ *_res = talloc_steal(mem_ctx, res);
+ ret = EOK;
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
static int confdb_get_domain_internal(struct confdb_ctx *cdb,
TALLOC_CTX *mem_ctx,
const char *name,
@@ -821,7 +865,6 @@ static int confdb_get_domain_internal(struct confdb_ctx *cdb,
struct sss_domain_info *domain;
struct ldb_result *res;
TALLOC_CTX *tmp_ctx;
- struct ldb_dn *dn;
const char *tmp;
int ret, val;
uint32_t entry_cache_timeout;
@@ -833,23 +876,15 @@ static int confdb_get_domain_internal(struct confdb_ctx *cdb,
tmp_ctx = talloc_new(mem_ctx);
if (!tmp_ctx) return ENOMEM;
- dn = ldb_dn_new_fmt(tmp_ctx, cdb->ldb,
- "cn=%s,%s", name, CONFDB_DOMAIN_BASEDN);
- if (!dn) {
- ret = ENOMEM;
- goto done;
- }
-
- ret = ldb_search(cdb->ldb, tmp_ctx, &res, dn,
- LDB_SCOPE_BASE, NULL, NULL);
- if (ret != LDB_SUCCESS) {
- ret = EIO;
- goto done;
- }
-
- if (res->count != 1) {
+ ret = confdb_get_domain_section(tmp_ctx, cdb, CONFDB_DOMAIN_BASEDN,
+ name, &res);
+ if (ret == ENOENT) {
DEBUG(SSSDBG_FATAL_FAILURE, "Unknown domain [%s]\n", name);
- ret = ENOENT;
+ goto done;
+ } else if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Error %d: %s while retrieving %s\n",
+ ret, sss_strerror(ret), name);
goto done;
}
@@ -1841,3 +1876,222 @@ int confdb_ensure_files_domain(struct confdb_ctx *cdb,
return activate_files_domain(cdb, implicit_files_dom_name);
#endif /* ADD_FILES_DOMAIN */
}
+
+static int confdb_get_parent_domain(TALLOC_CTX *mem_ctx,
+ const char *name,
+ struct confdb_ctx *cdb,
+ struct ldb_result *app_dom,
+ struct ldb_result **_parent_dom)
+{
+ const char *inherit_from;
+
+ inherit_from = ldb_msg_find_attr_as_string(app_dom->msgs[0],
+ CONFDB_DOMAIN_INHERIT_FROM, NULL);
+ if (inherit_from == NULL) {
+ DEBUG(SSSDBG_CONF_SETTINGS,
+ "%s does not inherit from any POSIX domain\n", name);
+ *_parent_dom = NULL;
+ return EOK;
+ }
+
+ return confdb_get_domain_section(mem_ctx, cdb,
+ CONFDB_DOMAIN_BASEDN, inherit_from,
+ _parent_dom);
+}
+
+static int confdb_add_app_domain(TALLOC_CTX *mem_ctx,
+ struct confdb_ctx *cdb,
+ const char *name)
+{
+ char *cdb_path = NULL;
+ const char *val[2] = { NULL, NULL };
+ int ret;
+
+ cdb_path = talloc_asprintf(mem_ctx, CONFDB_DOMAIN_PATH_TMPL, name);
+ if (cdb_path == NULL) {
+ return ENOMEM;
+ }
+
+ val[0] = CONFDB_DOMAIN_TYPE_APP;
+ ret = confdb_add_param(cdb, true, cdb_path, CONFDB_DOMAIN_TYPE, val);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add id_provider [%d]: %s\n",
+ ret, sss_strerror(ret));
+ return ret;
+ }
+
+ return EOK;
+}
+
+static int confdb_merge_parent_domain(const char *name,
+ struct confdb_ctx *cdb,
+ struct ldb_result *app_section)
+{
+ int ret;
+ int ldb_flag;
+ struct ldb_result *parent_domain = NULL;
+ struct ldb_message *replace_msg = NULL;
+ struct ldb_message *app_msg = NULL;
+ struct ldb_dn *domain_dn;
+ TALLOC_CTX *tmp_ctx = NULL;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
+ return ENOMEM;
+ }
+
+ domain_dn = ldb_dn_new_fmt(tmp_ctx,
+ cdb->ldb,
+ "%s=%s,%s",
+ CONFDB_DOMAIN_ATTR,
+ name,
+ CONFDB_DOMAIN_BASEDN);
+ if (domain_dn == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ /* Copy the parent domain parameters */
+ ret = confdb_get_parent_domain(tmp_ctx, name, cdb,
+ app_section, &parent_domain);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Cannot retrieve the parent domain [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ if (parent_domain != NULL) {
+ replace_msg = ldb_msg_copy(tmp_ctx, parent_domain->msgs[0]);
+ if (replace_msg == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ replace_msg->dn = domain_dn;
+
+ for (unsigned i = 0; i < replace_msg->num_elements; i++) {
+ replace_msg->elements[i].flags = LDB_FLAG_MOD_ADD;
+ }
+
+ ret = ldb_modify(cdb->ldb, replace_msg);
+ if (ret != LDB_SUCCESS) {
+ ret = sysdb_error_to_errno(ret);
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Inheriting options from parent domain failed [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+ }
+
+ /* Finally, add any app-domain specific overrides */
+ app_msg = ldb_msg_new(tmp_ctx);
+ if (app_msg == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ app_msg->dn = domain_dn;
+
+ for (unsigned i = 0; i < app_section->msgs[0]->num_elements; i++) {
+ struct ldb_message_element *el = NULL;
+
+ if (replace_msg != NULL) {
+ el = ldb_msg_find_element(replace_msg,
+ app_section->msgs[0]->elements[i].name);
+ if (el == NULL) {
+ /* Adding an element */
+ ldb_flag = LDB_FLAG_MOD_ADD;
+ } else {
+ /* Overriding an element */
+ ldb_flag = LDB_FLAG_MOD_REPLACE;
+ }
+ } else {
+ /* If there was no domain to inherit from, just add all */
+ ldb_flag = LDB_FLAG_MOD_ADD;
+ }
+
+ ret = ldb_msg_add(app_msg,
+ &app_section->msgs[0]->elements[i],
+ ldb_flag);
+ if (ret != EOK) {
+ continue;
+ }
+ }
+
+ ret = ldb_modify(cdb->ldb, app_msg);
+ if (ret != LDB_SUCCESS) {
+ ret = sysdb_error_to_errno(ret);
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Adding app-specific options failed [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ DEBUG(SSSDBG_TRACE_LIBS, "Added a domain section for %s\n", name);
+ ret = EOK;
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+int confdb_expand_app_domains(struct confdb_ctx *cdb)
+{
+ int ret;
+ char **domlist;
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_result *app_domain = NULL;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ ret = confdb_get_string_as_list(cdb, tmp_ctx,
+ CONFDB_MONITOR_CONF_ENTRY,
+ CONFDB_MONITOR_ACTIVE_DOMAINS,
+ &domlist);
+ if (ret == ENOENT) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "No domains configured, fatal error!\n");
+ goto done;
+ } else if (ret != EOK ) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Fatal error retrieving domains list!\n");
+ goto done;
+ }
+
+ for (int i = 0; domlist[i]; i++) {
+ ret = confdb_get_domain_section(tmp_ctx, cdb,
+ CONFDB_APP_DOMAIN_BASEDN, domlist[i],
+ &app_domain);
+ if (ret == ENOENT) {
+ DEBUG(SSSDBG_TRACE_INTERNAL,
+ "%s is not an app domain\n", domlist[i]);
+ continue;
+ } else if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Error %d: %s while retrieving %s\n",
+ ret, sss_strerror(ret), domlist[i]);
+ goto done;
+ }
+
+ ret = confdb_add_app_domain(tmp_ctx, cdb, domlist[i]);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Cannot add the app domain section [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ ret = confdb_merge_parent_domain(domlist[i], cdb, app_domain);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Cannot add options into the app domain section [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+ }
+
+ ret = EOK;
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
index a4046610f3cdbdb832de8924bf4397fb0018f2db..5a8d377c312f641f544b1c7cf38826192462ea3c 100644
--- a/src/confdb/confdb.h
+++ b/src/confdb/confdb.h
@@ -164,6 +164,7 @@
/* Domains */
#define CONFDB_DOMAIN_PATH_TMPL "config/domain/%s"
#define CONFDB_DOMAIN_BASEDN "cn=domain,cn=config"
+#define CONFDB_APP_DOMAIN_BASEDN "cn=application,cn=config"
#define CONFDB_DOMAIN_ID_PROVIDER "id_provider"
#define CONFDB_DOMAIN_AUTH_PROVIDER "auth_provider"
#define CONFDB_DOMAIN_ACCESS_PROVIDER "access_provider"
@@ -212,6 +213,7 @@
#define CONFDB_DOMAIN_TYPE "domain_type"
#define CONFDB_DOMAIN_TYPE_POSIX "posix"
#define CONFDB_DOMAIN_TYPE_APP "application"
+#define CONFDB_DOMAIN_INHERIT_FROM "inherit_from"
/* Local Provider */
#define CONFDB_LOCAL_DEFAULT_SHELL "default_shell"
@@ -398,6 +400,8 @@ int confdb_get_domains(struct confdb_ctx *cdb,
int confdb_ensure_files_domain(struct confdb_ctx *cdb,
const char *implicit_files_dom_name);
+int confdb_expand_app_domains(struct confdb_ctx *cdb);
+
/**
* Get a null-terminated linked-list of all domain names
* @param[in] mem_ctx The parent memory context for the value list
diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini
index 3c857236eaa55b313d176bc4bb479918163b60d5..8fd2d2c5236246394353a88c50d1510bd6233f77 100644
--- a/src/config/cfg_rules.ini
+++ b/src/config/cfg_rules.ini
@@ -12,6 +12,7 @@ section = secrets
section = kcm
section_re = ^secrets/users/[0-9]\+$
section_re = ^domain/.*$
+section_re = ^application/.*$
[rule/allowed_sssd_options]
validator = ini_allowed_options
@@ -286,7 +287,7 @@ option = responder_idle_timeout
[rule/allowed_domain_options]
validator = ini_allowed_options
-section_re = ^domain/.*$
+section_re = ^(domain|application)/.*$
option = debug
option = debug_level
@@ -684,3 +685,9 @@ option = ldap_user_ssh_public_key
option = ldap_user_uid_number
option = ldap_user_uuid
option = ldap_use_tokengroups
+
+[rule/allowed_application_options]
+validator = ini_allowed_options
+section_re = ^application/.*$
+
+option = inherit_from
diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
index 9abcff84a95ea1b27e36845e830cc125fdc89f90..8294793c765bfa6bf481693c7d7f206950454681 100644
--- a/src/man/sssd.conf.5.xml
+++ b/src/man/sssd.conf.5.xml
@@ -1539,6 +1539,10 @@ pam_account_locked_message = Account locked, please contact help desk.
<quote>id_provider=ldap</quote> only.
</para>
<para>
+ For an easy way to configure a non-POSIX domains, please
+ see the <quote>Application domains</quote> section.
+ </para>
+ <para>
Default: posix
</para>
</listitem>
@@ -2692,6 +2696,79 @@ subdomain_inherit = ldap_purge_cache_timeout
</variablelist>
</para>
+ <refsect2 id='app_domains'>
+ <title>Application domains</title>
+ <para>
+ SSSD, with its D-Bus interface (see
+ <citerefentry>
+ <refentrytitle>sssd-ifp</refentrytitle>
+ <manvolnum>5</manvolnum>
+ </citerefentry>) is appealing to applications
+ as a gateway to an LDAP directory where users and groups
+ are stored. However, contrary to the traditional SSSD
+ deployment where all users and groups either have POSIX
+ attributes or those attributes can be inferred from the
+ Windows SIDs, in many cases the users and groups in the
+ application support scenario have no POSIX attributes.
+ Instead of setting a
+ <quote>[domain/<replaceable>NAME</replaceable>]</quote>
+ section, the administrator can set up an
+ <quote>[application/<replaceable>NAME</replaceable>]</quote>
+ section that internally represents a domain with type
+ <quote>application</quote> optionally inherits settings
+ from a tradition SSSD domain.
+ </para>
+ <para>
+ Please note that the application domain must still be
+ explicitly enabled in the <quote>domains</quote> parameter
+ so that the lookup order between the application domain
+ and its POSIX sibling domain is set correctly.
+ </para>
+ <variablelist>
+ <title>Application domain parameters</title>
+ <varlistentry>
+ <term>inherit_from (string)</term>
+ <listitem>
+ <para>
+ The SSSD POSIX-type domain the application
+ domain inherits all settings from. The
+ application domain can moreover add its own
+ settings to the application settings that augment
+ or override the <quote>sibling</quote>
+ domain settings.
+ </para>
+ <para>
+ Default: Not set
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>
+ The following example illustrates the use of an application
+ domain. In this setup, the POSIX domain is connected to an LDAP
+ server and is used by the OS through the NSS responder. In addition,
+ the application domains also requests the telephoneNumber attribute,
+ stores it as the phone attribute in the cache and makes the phone
+ attribute reachable through the D-Bus interface.
+ </para>
+<programlisting>
+[sssd]
+domains = appdom, posixdom
+
+[ifp]
+user_attributes = +phone
+
+[domain/posixdom]
+id_provider = ldap
+ldap_uri = ldap://ldap.example.com
+ldap_search_base = dc=example,dc=com
+
+[application/appdom]
+inherit_from = posixdom
+ldap_user_extra_attrs = phone:telephoneNumber
+</programlisting>
+ </refsect2>
+
<refsect2 id='local_domain'>
<title>The local domain section</title>
<para>
diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c
index 7e7b5a07d11aecf1c0b11592213b90d385fd5076..2753b46667f7ae0b022776862c67a327d3356d6d 100644
--- a/src/monitor/monitor.c
+++ b/src/monitor/monitor.c
@@ -1064,6 +1064,14 @@ static int get_monitor_config(struct mt_ctx *ctx)
/* Not fatal */
}
+ ret = confdb_expand_app_domains(ctx->cdb);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Failed to expand application domains\n");
+ /* This must not be fatal so that SSSD keeps running and lets
+ * admin correct the error.
+ */
+ }
+
ret = confdb_get_domains(ctx->cdb, &ctx->domains);
if (ret != EOK) {
DEBUG(SSSDBG_FATAL_FAILURE, "No domains configured.\n");
--
2.12.2

View File

@ -1,976 +0,0 @@
From cee85e8fb9534ec997e5388fce59f392cf029573 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Fri, 24 Mar 2017 10:39:12 +0100
Subject: [PATCH 66/97] CACHE_REQ: Domain type selection in cache_req
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Related to:
https://pagure.io/SSSD/sssd/issue/3310
Adds a new enumeration cache_req_dom_type. It is a tri-state that
allows the caller to select which domains can be contacted - either only
POSIX, only application domains or any type.
Not all plugins of cache_req have the new parameter added -- only those
that are usable/useful in a non-POSIX environment. For example, it makes
no sense to allow the selection for calls by ID because those are
inherently POSIX-specific. Also, services or netgroups are supported
only coming from POSIX domains.
At the moment, the patch should not change any behaviour as all calls
default to contacting POSIX domains only.
Reviewed-by: Pavel Březina <pbrezina@redhat.com>
---
src/responder/common/cache_req/cache_req.c | 80 ++++++++++++++++++++--
src/responder/common/cache_req/cache_req.h | 19 +++++
src/responder/common/cache_req/cache_req_private.h | 3 +
.../cache_req/plugins/cache_req_enum_groups.c | 4 +-
.../common/cache_req/plugins/cache_req_enum_svc.c | 3 +-
.../cache_req/plugins/cache_req_enum_users.c | 4 +-
.../cache_req/plugins/cache_req_group_by_filter.c | 5 +-
.../cache_req/plugins/cache_req_group_by_id.c | 4 +-
.../cache_req/plugins/cache_req_group_by_name.c | 5 +-
.../cache_req/plugins/cache_req_host_by_name.c | 4 +-
.../plugins/cache_req_initgroups_by_name.c | 5 +-
.../cache_req/plugins/cache_req_netgroup_by_name.c | 4 +-
.../cache_req/plugins/cache_req_object_by_id.c | 4 +-
.../cache_req/plugins/cache_req_object_by_name.c | 4 +-
.../cache_req/plugins/cache_req_object_by_sid.c | 4 +-
.../cache_req/plugins/cache_req_svc_by_name.c | 4 +-
.../cache_req/plugins/cache_req_svc_by_port.c | 4 +-
.../cache_req/plugins/cache_req_user_by_cert.c | 4 +-
.../cache_req/plugins/cache_req_user_by_filter.c | 5 +-
.../cache_req/plugins/cache_req_user_by_id.c | 4 +-
.../cache_req/plugins/cache_req_user_by_name.c | 9 ++-
src/responder/ifp/ifp_groups.c | 14 +++-
src/responder/ifp/ifp_users.c | 19 +++--
src/responder/ifp/ifpsrv_cmd.c | 3 +-
src/responder/nss/nss_enum.c | 2 +-
src/responder/nss/nss_get_object.c | 3 +-
src/responder/pam/pamsrv_cmd.c | 5 +-
src/responder/sudo/sudosrv_get_sudorules.c | 3 +-
src/tests/cmocka/test_responder_cache_req.c | 62 ++++++++++++++---
29 files changed, 246 insertions(+), 47 deletions(-)
diff --git a/src/responder/common/cache_req/cache_req.c b/src/responder/common/cache_req/cache_req.c
index 483126396f8addbad744ae03bfc739801cd0c18b..3a5fecf34427437bbf95317e05c5bd8b07b4537d 100644
--- a/src/responder/common/cache_req/cache_req.c
+++ b/src/responder/common/cache_req/cache_req.c
@@ -89,12 +89,31 @@ static errno_t cache_req_set_plugin(struct cache_req *cr,
return EOK;
}
+static const char *
+cache_req_dom_type_as_str(struct cache_req *cr)
+{
+ if (cr == NULL) {
+ return "BUG: Invalid cache_req pointer\n";
+ }
+ switch (cr->req_dom_type) {
+ case CACHE_REQ_POSIX_DOM:
+ return "POSIX-only";
+ case CACHE_REQ_APPLICATION_DOM:
+ return "Application-only";
+ case CACHE_REQ_ANY_DOM:
+ return "Any";
+ }
+
+ return "Unknown";
+}
+
static struct cache_req *
cache_req_create(TALLOC_CTX *mem_ctx,
struct resp_ctx *rctx,
struct cache_req_data *data,
struct sss_nc_ctx *ncache,
- int midpoint)
+ int midpoint,
+ enum cache_req_dom_type req_dom_type)
{
struct cache_req *cr;
errno_t ret;
@@ -108,6 +127,7 @@ cache_req_create(TALLOC_CTX *mem_ctx,
cr->data = data;
cr->ncache = ncache;
cr->midpoint = midpoint;
+ cr->req_dom_type = req_dom_type;
cr->req_start = time(NULL);
/* It is perfectly fine to just overflow here. */
@@ -145,8 +165,8 @@ cache_req_set_name(struct cache_req *cr, const char *name)
}
static bool
-cache_req_validate_domain(struct cache_req *cr,
- struct sss_domain_info *domain)
+cache_req_validate_domain_enumeration(struct cache_req *cr,
+ struct sss_domain_info *domain)
{
if (!cr->plugin->require_enumeration) {
return true;
@@ -164,6 +184,52 @@ cache_req_validate_domain(struct cache_req *cr,
return true;
}
+static bool
+cache_req_validate_domain_type(struct cache_req *cr,
+ struct sss_domain_info *domain)
+{
+ bool valid = false;
+
+ switch (cr->req_dom_type) {
+ case CACHE_REQ_POSIX_DOM:
+ valid = domain->type == DOM_TYPE_POSIX ? true : false;
+ break;
+ case CACHE_REQ_APPLICATION_DOM:
+ valid = domain->type == DOM_TYPE_APPLICATION ? true : false;
+ break;
+ case CACHE_REQ_ANY_DOM:
+ valid = true;
+ break;
+ }
+
+ DEBUG(SSSDBG_TRACE_INTERNAL,
+ "Request type %s for domain %s type %s is %svalid\n",
+ cache_req_dom_type_as_str(cr),
+ domain->name,
+ sss_domain_type_str(domain),
+ valid ? "" : "not ");
+ return valid;
+}
+
+static bool
+cache_req_validate_domain(struct cache_req *cr,
+ struct sss_domain_info *domain)
+{
+ bool ok;
+
+ ok = cache_req_validate_domain_enumeration(cr, domain);
+ if (ok == false) {
+ return false;
+ }
+
+ ok = cache_req_validate_domain_type(cr, domain);
+ if (ok == false) {
+ return false;
+ }
+
+ return true;
+}
+
static errno_t
cache_req_is_well_known_object(TALLOC_CTX *mem_ctx,
struct cache_req *cr,
@@ -651,6 +717,7 @@ struct tevent_req *cache_req_send(TALLOC_CTX *mem_ctx,
struct resp_ctx *rctx,
struct sss_nc_ctx *ncache,
int midpoint,
+ enum cache_req_dom_type req_dom_type,
const char *domain,
struct cache_req_data *data)
{
@@ -667,7 +734,8 @@ struct tevent_req *cache_req_send(TALLOC_CTX *mem_ctx,
}
state->ev = ev;
- state->cr = cr = cache_req_create(state, rctx, data, ncache, midpoint);
+ state->cr = cr = cache_req_create(state, rctx, data,
+ ncache, midpoint, req_dom_type);
if (state->cr == NULL) {
ret = ENOMEM;
goto done;
@@ -952,13 +1020,15 @@ cache_req_steal_data_and_send(TALLOC_CTX *mem_ctx,
struct resp_ctx *rctx,
struct sss_nc_ctx *ncache,
int cache_refresh_percent,
+ enum cache_req_dom_type req_dom_type,
const char *domain,
struct cache_req_data *data)
{
struct tevent_req *req;
req = cache_req_send(mem_ctx, ev, rctx, ncache,
- cache_refresh_percent, domain, data);
+ cache_refresh_percent,
+ req_dom_type, domain, data);
if (req == NULL) {
talloc_zfree(data);
return NULL;
diff --git a/src/responder/common/cache_req/cache_req.h b/src/responder/common/cache_req/cache_req.h
index d0e5ff43921467fc191fd5cc7d5b49cc039b7f67..c04b2fba6f0445dcfcc9cfe1b5963ac975c39118 100644
--- a/src/responder/common/cache_req/cache_req.h
+++ b/src/responder/common/cache_req/cache_req.h
@@ -57,6 +57,18 @@ enum cache_req_type {
CACHE_REQ_SENTINEL
};
+/* Whether to limit the request type to a certain domain type
+ * (POSIX/non-POSIX)
+ */
+enum cache_req_dom_type {
+ /* Only look up data in POSIX domains */
+ CACHE_REQ_POSIX_DOM,
+ /* Only look up data in application domains */
+ CACHE_REQ_APPLICATION_DOM,
+ /* Look up data in any domain type */
+ CACHE_REQ_ANY_DOM
+};
+
/* Input data. */
struct cache_req_data;
@@ -172,6 +184,7 @@ struct tevent_req *cache_req_send(TALLOC_CTX *mem_ctx,
struct resp_ctx *rctx,
struct sss_nc_ctx *ncache,
int midpoint,
+ enum cache_req_dom_type req_dom_type,
const char *domain,
struct cache_req_data *data);
@@ -191,6 +204,7 @@ cache_req_user_by_name_send(TALLOC_CTX *mem_ctx,
struct resp_ctx *rctx,
struct sss_nc_ctx *ncache,
int cache_refresh_percent,
+ enum cache_req_dom_type req_dom_type,
const char *domain,
const char *name);
@@ -228,6 +242,7 @@ cache_req_user_by_cert_send(TALLOC_CTX *mem_ctx,
struct resp_ctx *rctx,
struct sss_nc_ctx *ncache,
int cache_refresh_percent,
+ enum cache_req_dom_type req_dom_type,
const char *domain,
const char *pem_cert);
@@ -240,6 +255,7 @@ cache_req_group_by_name_send(TALLOC_CTX *mem_ctx,
struct resp_ctx *rctx,
struct sss_nc_ctx *ncache,
int cache_refresh_percent,
+ enum cache_req_dom_type req_dom_type,
const char *domain,
const char *name);
@@ -264,6 +280,7 @@ cache_req_initgr_by_name_send(TALLOC_CTX *mem_ctx,
struct resp_ctx *rctx,
struct sss_nc_ctx *ncache,
int cache_refresh_percent,
+ enum cache_req_dom_type req_dom_type,
const char *domain,
const char *name);
@@ -274,6 +291,7 @@ struct tevent_req *
cache_req_user_by_filter_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct resp_ctx *rctx,
+ enum cache_req_dom_type req_dom_type,
const char *domain,
const char *filter);
@@ -284,6 +302,7 @@ struct tevent_req *
cache_req_group_by_filter_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct resp_ctx *rctx,
+ enum cache_req_dom_type req_dom_type,
const char *domain,
const char *filter);
diff --git a/src/responder/common/cache_req/cache_req_private.h b/src/responder/common/cache_req/cache_req_private.h
index 2d3c1870795e4fd5667f603280edcee24f926220..851005c389f994b1bd2d04cda9b68df8b18492cc 100644
--- a/src/responder/common/cache_req/cache_req_private.h
+++ b/src/responder/common/cache_req/cache_req_private.h
@@ -42,6 +42,8 @@ struct cache_req {
struct sss_domain_info *domain;
bool cache_first;
bool bypass_cache;
+ /* Only contact domains with this type */
+ enum cache_req_dom_type req_dom_type;
/* Debug information */
uint32_t reqid;
@@ -108,6 +110,7 @@ cache_req_steal_data_and_send(TALLOC_CTX *mem_ctx,
struct resp_ctx *rctx,
struct sss_nc_ctx *ncache,
int cache_refresh_percent,
+ enum cache_req_dom_type req_dom_type,
const char *domain,
struct cache_req_data *data);
diff --git a/src/responder/common/cache_req/plugins/cache_req_enum_groups.c b/src/responder/common/cache_req/plugins/cache_req_enum_groups.c
index dbb40c98339cc9295e3678e05340396aff51ac78..49ce3508e678862e4389657187b9659ce90fbd1c 100644
--- a/src/responder/common/cache_req/plugins/cache_req_enum_groups.c
+++ b/src/responder/common/cache_req/plugins/cache_req_enum_groups.c
@@ -96,5 +96,7 @@ cache_req_enum_groups_send(TALLOC_CTX *mem_ctx,
}
return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
- cache_refresh_percent, domain, data);
+ cache_refresh_percent,
+ CACHE_REQ_POSIX_DOM, domain,
+ data);
}
diff --git a/src/responder/common/cache_req/plugins/cache_req_enum_svc.c b/src/responder/common/cache_req/plugins/cache_req_enum_svc.c
index 28dea33c601f500b9c7af0de3eb9e1c342f03522..499b994738d62707b4e86d5a8383e3e2b82e8c57 100644
--- a/src/responder/common/cache_req/plugins/cache_req_enum_svc.c
+++ b/src/responder/common/cache_req/plugins/cache_req_enum_svc.c
@@ -97,5 +97,6 @@ cache_req_enum_svc_send(TALLOC_CTX *mem_ctx,
}
return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
- cache_refresh_percent, domain, data);
+ cache_refresh_percent,
+ CACHE_REQ_POSIX_DOM, domain, data);
}
diff --git a/src/responder/common/cache_req/plugins/cache_req_enum_users.c b/src/responder/common/cache_req/plugins/cache_req_enum_users.c
index 3b1a85841e3ed853cd329dfa9d762cb7a05cbd43..b635354be6e9d2e2e2af1a6f867ac68e6cf7f085 100644
--- a/src/responder/common/cache_req/plugins/cache_req_enum_users.c
+++ b/src/responder/common/cache_req/plugins/cache_req_enum_users.c
@@ -96,5 +96,7 @@ cache_req_enum_users_send(TALLOC_CTX *mem_ctx,
}
return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
- cache_refresh_percent, domain, data);
+ cache_refresh_percent,
+ CACHE_REQ_POSIX_DOM, domain,
+ data);
}
diff --git a/src/responder/common/cache_req/plugins/cache_req_group_by_filter.c b/src/responder/common/cache_req/plugins/cache_req_group_by_filter.c
index 6ce6ae0d63967ac50b813a47ac938251619948da..4377a476c36e5e03c8533bc62335b84fa1cee3ff 100644
--- a/src/responder/common/cache_req/plugins/cache_req_group_by_filter.c
+++ b/src/responder/common/cache_req/plugins/cache_req_group_by_filter.c
@@ -140,6 +140,7 @@ struct tevent_req *
cache_req_group_by_filter_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct resp_ctx *rctx,
+ enum cache_req_dom_type req_dom_type,
const char *domain,
const char *filter)
{
@@ -151,5 +152,7 @@ cache_req_group_by_filter_send(TALLOC_CTX *mem_ctx,
}
return cache_req_steal_data_and_send(mem_ctx, ev, rctx, NULL,
- 0, domain, data);
+ 0,
+ req_dom_type, domain,
+ data);
}
diff --git a/src/responder/common/cache_req/plugins/cache_req_group_by_id.c b/src/responder/common/cache_req/plugins/cache_req_group_by_id.c
index e98f76f8cd20742b81ae247df61db159d2584a17..ad5b7d890a42f29b586ab8e0943fef3dfab1162d 100644
--- a/src/responder/common/cache_req/plugins/cache_req_group_by_id.c
+++ b/src/responder/common/cache_req/plugins/cache_req_group_by_id.c
@@ -166,5 +166,7 @@ cache_req_group_by_id_send(TALLOC_CTX *mem_ctx,
}
return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
- cache_refresh_percent, domain, data);
+ cache_refresh_percent,
+ CACHE_REQ_POSIX_DOM, domain,
+ data);
}
diff --git a/src/responder/common/cache_req/plugins/cache_req_group_by_name.c b/src/responder/common/cache_req/plugins/cache_req_group_by_name.c
index af6f23ccfd68f952027462ba3e74ed7219d04651..de1e8f9442273acf386a2278b06f28ee63a7e3c6 100644
--- a/src/responder/common/cache_req/plugins/cache_req_group_by_name.c
+++ b/src/responder/common/cache_req/plugins/cache_req_group_by_name.c
@@ -205,6 +205,7 @@ cache_req_group_by_name_send(TALLOC_CTX *mem_ctx,
struct resp_ctx *rctx,
struct sss_nc_ctx *ncache,
int cache_refresh_percent,
+ enum cache_req_dom_type req_dom_type,
const char *domain,
const char *name)
{
@@ -216,5 +217,7 @@ cache_req_group_by_name_send(TALLOC_CTX *mem_ctx,
}
return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
- cache_refresh_percent, domain, data);
+ cache_refresh_percent,
+ req_dom_type, domain,
+ data);
}
diff --git a/src/responder/common/cache_req/plugins/cache_req_host_by_name.c b/src/responder/common/cache_req/plugins/cache_req_host_by_name.c
index 77b46831fec3abc4126ef9d9be67221469801094..1171cd63fac5cc1d36b31bf8a069f059705cae90 100644
--- a/src/responder/common/cache_req/plugins/cache_req_host_by_name.c
+++ b/src/responder/common/cache_req/plugins/cache_req_host_by_name.c
@@ -117,5 +117,7 @@ cache_req_host_by_name_send(TALLOC_CTX *mem_ctx,
}
return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
- cache_refresh_percent, domain, data);
+ cache_refresh_percent,
+ CACHE_REQ_POSIX_DOM, domain,
+ data);
}
diff --git a/src/responder/common/cache_req/plugins/cache_req_initgroups_by_name.c b/src/responder/common/cache_req/plugins/cache_req_initgroups_by_name.c
index 307b65a24282838b99c472b50a71f06865aed3f0..f100aefe5c92279cde7e3209c7f48f5e2b35f135 100644
--- a/src/responder/common/cache_req/plugins/cache_req_initgroups_by_name.c
+++ b/src/responder/common/cache_req/plugins/cache_req_initgroups_by_name.c
@@ -220,6 +220,7 @@ cache_req_initgr_by_name_send(TALLOC_CTX *mem_ctx,
struct resp_ctx *rctx,
struct sss_nc_ctx *ncache,
int cache_refresh_percent,
+ enum cache_req_dom_type req_dom_type,
const char *domain,
const char *name)
{
@@ -231,5 +232,7 @@ cache_req_initgr_by_name_send(TALLOC_CTX *mem_ctx,
}
return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
- cache_refresh_percent, domain, data);
+ cache_refresh_percent,
+ req_dom_type, domain,
+ data);
}
diff --git a/src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c b/src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c
index e49d6d84a41ce8dabf18c87373826f8e7b684bda..ab3e553d3ecb8ae09094dcfc938ed0ac01925327 100644
--- a/src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c
+++ b/src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c
@@ -150,5 +150,7 @@ cache_req_netgroup_by_name_send(TALLOC_CTX *mem_ctx,
}
return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
- cache_refresh_percent, domain, data);
+ cache_refresh_percent,
+ CACHE_REQ_POSIX_DOM, domain,
+ data);
}
diff --git a/src/responder/common/cache_req/plugins/cache_req_object_by_id.c b/src/responder/common/cache_req/plugins/cache_req_object_by_id.c
index 046e313c83d1d4c75237b047be779201b8a5d3c0..9557bd15270b2eb1a0671f9ef91033efac29c3ac 100644
--- a/src/responder/common/cache_req/plugins/cache_req_object_by_id.c
+++ b/src/responder/common/cache_req/plugins/cache_req_object_by_id.c
@@ -134,5 +134,7 @@ cache_req_object_by_id_send(TALLOC_CTX *mem_ctx,
}
return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
- cache_refresh_percent, domain, data);
+ cache_refresh_percent,
+ CACHE_REQ_POSIX_DOM, domain,
+ data);
}
diff --git a/src/responder/common/cache_req/plugins/cache_req_object_by_name.c b/src/responder/common/cache_req/plugins/cache_req_object_by_name.c
index 74d2b3dea287e890b38e4d5bb176ad2dc6337b7e..e236d1fa4aadcd87b192d34ebaf5f9ad8908b6c2 100644
--- a/src/responder/common/cache_req/plugins/cache_req_object_by_name.c
+++ b/src/responder/common/cache_req/plugins/cache_req_object_by_name.c
@@ -228,5 +228,7 @@ cache_req_object_by_name_send(TALLOC_CTX *mem_ctx,
}
return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
- cache_refresh_percent, domain, data);
+ cache_refresh_percent,
+ CACHE_REQ_POSIX_DOM, domain,
+ data);
}
diff --git a/src/responder/common/cache_req/plugins/cache_req_object_by_sid.c b/src/responder/common/cache_req/plugins/cache_req_object_by_sid.c
index ab577663111cfd424e7f46308b2621af7f1ca264..dfec79da07d669165205a767cab22c2254686134 100644
--- a/src/responder/common/cache_req/plugins/cache_req_object_by_sid.c
+++ b/src/responder/common/cache_req/plugins/cache_req_object_by_sid.c
@@ -143,5 +143,7 @@ cache_req_object_by_sid_send(TALLOC_CTX *mem_ctx,
}
return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
- cache_refresh_percent, domain, data);
+ cache_refresh_percent,
+ CACHE_REQ_POSIX_DOM, domain,
+ data);
}
diff --git a/src/responder/common/cache_req/plugins/cache_req_svc_by_name.c b/src/responder/common/cache_req/plugins/cache_req_svc_by_name.c
index ef13f097a8ae78ec9db5b7f6e14924b511578b34..b2bfb26ffed1a60ed8389fa89b0e728c8c6cf76c 100644
--- a/src/responder/common/cache_req/plugins/cache_req_svc_by_name.c
+++ b/src/responder/common/cache_req/plugins/cache_req_svc_by_name.c
@@ -175,5 +175,7 @@ cache_req_svc_by_name_send(TALLOC_CTX *mem_ctx,
}
return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
- cache_refresh_percent, domain, data);
+ cache_refresh_percent,
+ CACHE_REQ_POSIX_DOM, domain,
+ data);
}
diff --git a/src/responder/common/cache_req/plugins/cache_req_svc_by_port.c b/src/responder/common/cache_req/plugins/cache_req_svc_by_port.c
index afa2eeeda12794de26e798aee4b88900bc87ed93..0e48437f4b64d26112be88af1eebc20f012b70fd 100644
--- a/src/responder/common/cache_req/plugins/cache_req_svc_by_port.c
+++ b/src/responder/common/cache_req/plugins/cache_req_svc_by_port.c
@@ -149,5 +149,7 @@ cache_req_svc_by_port_send(TALLOC_CTX *mem_ctx,
}
return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
- cache_refresh_percent, domain, data);
+ cache_refresh_percent,
+ CACHE_REQ_POSIX_DOM, domain,
+ data);
}
diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_cert.c b/src/responder/common/cache_req/plugins/cache_req_user_by_cert.c
index f237c8d0fe3faf5aea553480f3f92eb279209a20..286a34db276e0098060982c572e2a68ceceebf60 100644
--- a/src/responder/common/cache_req/plugins/cache_req_user_by_cert.c
+++ b/src/responder/common/cache_req/plugins/cache_req_user_by_cert.c
@@ -105,6 +105,7 @@ cache_req_user_by_cert_send(TALLOC_CTX *mem_ctx,
struct resp_ctx *rctx,
struct sss_nc_ctx *ncache,
int cache_refresh_percent,
+ enum cache_req_dom_type req_dom_type,
const char *domain,
const char *pem_cert)
{
@@ -117,5 +118,6 @@ cache_req_user_by_cert_send(TALLOC_CTX *mem_ctx,
return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
cache_refresh_percent,
- domain, data);
+ req_dom_type, domain,
+ data);
}
diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_filter.c b/src/responder/common/cache_req/plugins/cache_req_user_by_filter.c
index eb71b42dad3a805298df0c8425409d571befb31b..c476814373cd784bf8dbbea1da7b010afe5bb4e4 100644
--- a/src/responder/common/cache_req/plugins/cache_req_user_by_filter.c
+++ b/src/responder/common/cache_req/plugins/cache_req_user_by_filter.c
@@ -140,6 +140,7 @@ struct tevent_req *
cache_req_user_by_filter_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct resp_ctx *rctx,
+ enum cache_req_dom_type req_dom_type,
const char *domain,
const char *filter)
{
@@ -151,5 +152,7 @@ cache_req_user_by_filter_send(TALLOC_CTX *mem_ctx,
}
return cache_req_steal_data_and_send(mem_ctx, ev, rctx, NULL,
- 0, domain, data);
+ 0,
+ req_dom_type, domain,
+ data);
}
diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_id.c b/src/responder/common/cache_req/plugins/cache_req_user_by_id.c
index fa783714b7c67ca029d18a223b64a3a69e3e6929..9ba73292e5dc518e86c6e00e7e493d6871f28e70 100644
--- a/src/responder/common/cache_req/plugins/cache_req_user_by_id.c
+++ b/src/responder/common/cache_req/plugins/cache_req_user_by_id.c
@@ -166,5 +166,7 @@ cache_req_user_by_id_send(TALLOC_CTX *mem_ctx,
}
return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
- cache_refresh_percent, domain, data);
+ cache_refresh_percent,
+ CACHE_REQ_POSIX_DOM, domain,
+ data);
}
diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_name.c b/src/responder/common/cache_req/plugins/cache_req_user_by_name.c
index 0670febdce2d51e0373045570dd07f56255db7bc..15da7d0d20b1ac97511a226daecc8ef7e7d2e7e4 100644
--- a/src/responder/common/cache_req/plugins/cache_req_user_by_name.c
+++ b/src/responder/common/cache_req/plugins/cache_req_user_by_name.c
@@ -210,6 +210,7 @@ cache_req_user_by_name_send(TALLOC_CTX *mem_ctx,
struct resp_ctx *rctx,
struct sss_nc_ctx *ncache,
int cache_refresh_percent,
+ enum cache_req_dom_type req_dom_type,
const char *domain,
const char *name)
{
@@ -221,7 +222,9 @@ cache_req_user_by_name_send(TALLOC_CTX *mem_ctx,
}
return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
- cache_refresh_percent, domain, data);
+ cache_refresh_percent,
+ req_dom_type, domain,
+ data);
}
struct tevent_req *
@@ -243,5 +246,7 @@ cache_req_user_by_name_attrs_send(TALLOC_CTX *mem_ctx,
}
return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
- cache_refresh_percent, domain, data);
+ cache_refresh_percent,
+ CACHE_REQ_POSIX_DOM, domain,
+ data);
}
diff --git a/src/responder/ifp/ifp_groups.c b/src/responder/ifp/ifp_groups.c
index 94d1e84cc9de75727d3c47c0a5a24790d21ce132..99908e96bd971bce4b4e9064a77d8413f837d743 100644
--- a/src/responder/ifp/ifp_groups.c
+++ b/src/responder/ifp/ifp_groups.c
@@ -118,7 +118,9 @@ int ifp_groups_find_by_name(struct sbus_request *sbus_req,
}
req = cache_req_group_by_name_send(sbus_req, ctx->rctx->ev, ctx->rctx,
- ctx->rctx->ncache, 0, NULL, name);
+ ctx->rctx->ncache, 0,
+ CACHE_REQ_POSIX_DOM, NULL,
+ name);
if (req == NULL) {
return ENOMEM;
}
@@ -271,6 +273,7 @@ static int ifp_groups_list_by_name_step(struct ifp_list_ctx *list_ctx)
req = cache_req_group_by_filter_send(list_ctx,
list_ctx->ctx->rctx->ev,
list_ctx->ctx->rctx,
+ CACHE_REQ_POSIX_DOM,
list_ctx->dom->name,
list_ctx->filter);
if (req == NULL) {
@@ -355,7 +358,8 @@ int ifp_groups_list_by_domain_and_name(struct sbus_request *sbus_req,
}
req = cache_req_group_by_filter_send(list_ctx, ctx->rctx->ev, ctx->rctx,
- domain, filter);
+ CACHE_REQ_POSIX_DOM,
+ domain, filter);
if (req == NULL) {
return ENOMEM;
}
@@ -522,7 +526,10 @@ static struct tevent_req *resolv_ghosts_send(TALLOC_CTX *mem_ctx,
}
subreq = cache_req_group_by_name_send(state, ev, ctx->rctx,
- ctx->rctx->ncache, 0, domain->name, name);
+ ctx->rctx->ncache, 0,
+ CACHE_REQ_POSIX_DOM,
+ domain->name,
+ name);
if (subreq == NULL) {
ret = ENOMEM;
goto immediately;
@@ -601,6 +608,7 @@ errno_t resolv_ghosts_step(struct tevent_req *req)
subreq = cache_req_user_by_name_send(state, state->ev, state->ctx->rctx,
state->ctx->rctx->ncache, 0,
+ CACHE_REQ_POSIX_DOM,
state->domain->name,
state->ghosts[state->index]);
if (subreq == NULL) {
diff --git a/src/responder/ifp/ifp_users.c b/src/responder/ifp/ifp_users.c
index cc78300f31e863fcb5366e18a14abc597c6f7ddb..436bb268fa9c78d72fb744e0d338aa561a7d8764 100644
--- a/src/responder/ifp/ifp_users.c
+++ b/src/responder/ifp/ifp_users.c
@@ -99,7 +99,9 @@ int ifp_users_find_by_name(struct sbus_request *sbus_req,
}
req = cache_req_user_by_name_send(sbus_req, ctx->rctx->ev, ctx->rctx,
- ctx->rctx->ncache, 0, NULL, name);
+ ctx->rctx->ncache, 0,
+ CACHE_REQ_POSIX_DOM,
+ NULL, name);
if (req == NULL) {
return ENOMEM;
}
@@ -253,7 +255,9 @@ int ifp_users_find_by_cert(struct sbus_request *sbus_req, void *data,
}
req = cache_req_user_by_cert_send(sbus_req, ctx->rctx->ev, ctx->rctx,
- ctx->rctx->ncache, 0, NULL, derb64);
+ ctx->rctx->ncache, 0,
+ CACHE_REQ_POSIX_DOM, NULL,
+ derb64);
if (req == NULL) {
return ENOMEM;
}
@@ -367,6 +371,7 @@ static int ifp_users_list_by_cert_step(struct ifp_list_ctx *list_ctx)
list_ctx->ctx->rctx,
list_ctx->ctx->rctx->ncache,
0,
+ CACHE_REQ_POSIX_DOM,
list_ctx->dom->name,
list_ctx->filter);
if (req == NULL) {
@@ -532,7 +537,9 @@ int ifp_users_find_by_name_and_cert(struct sbus_request *sbus_req, void *data,
if (name_and_cert_ctx->name != NULL) {
req = cache_req_user_by_name_send(sbus_req, ctx->rctx->ev, ctx->rctx,
- ctx->rctx->ncache, 0, NULL,
+ ctx->rctx->ncache, 0,
+ CACHE_REQ_POSIX_DOM,
+ NULL,
name_and_cert_ctx->name);
if (req == NULL) {
return ENOMEM;
@@ -614,6 +621,7 @@ static int ifp_users_find_by_name_and_cert_step(
list_ctx->ctx->rctx,
list_ctx->ctx->rctx->ncache,
0,
+ CACHE_REQ_POSIX_DOM,
list_ctx->dom->name,
list_ctx->filter);
if (req == NULL) {
@@ -774,6 +782,7 @@ static int ifp_users_list_by_name_step(struct ifp_list_ctx *list_ctx)
req = cache_req_user_by_filter_send(list_ctx,
list_ctx->ctx->rctx->ev,
list_ctx->ctx->rctx,
+ CACHE_REQ_POSIX_DOM,
list_ctx->dom->name,
list_ctx->filter);
if (req == NULL) {
@@ -858,6 +867,7 @@ int ifp_users_list_by_domain_and_name(struct sbus_request *sbus_req,
}
req = cache_req_user_by_filter_send(list_ctx, ctx->rctx->ev, ctx->rctx,
+ CACHE_REQ_POSIX_DOM,
domain, filter);
if (req == NULL) {
return ENOMEM;
@@ -1102,7 +1112,8 @@ int ifp_users_user_update_groups_list(struct sbus_request *sbus_req,
}
req = cache_req_initgr_by_name_send(sbus_req, ctx->rctx->ev, ctx->rctx,
- ctx->rctx->ncache, 0, domain->name,
+ ctx->rctx->ncache, 0,
+ CACHE_REQ_POSIX_DOM, domain->name,
username);
if (req == NULL) {
return ENOMEM;
diff --git a/src/responder/ifp/ifpsrv_cmd.c b/src/responder/ifp/ifpsrv_cmd.c
index 07edcddffa1091f8bbcf79a25962aadc791bb890..118b5083b14bf5692c6fdd7ba90668fe514aa89d 100644
--- a/src/responder/ifp/ifpsrv_cmd.c
+++ b/src/responder/ifp/ifpsrv_cmd.c
@@ -509,7 +509,8 @@ ifp_user_get_attr_lookup(struct tevent_req *subreq)
}
subreq = cache_req_send(state, state->rctx->ev, state->rctx,
- state->ncache, 0, state->domname, data);
+ state->ncache, 0, CACHE_REQ_POSIX_DOM,
+ state->domname, data);
if (subreq == NULL) {
tevent_req_error(req, ENOMEM);
return;
diff --git a/src/responder/nss/nss_enum.c b/src/responder/nss/nss_enum.c
index b1cce2cde43ece735285c132d0127c142ee83cb0..aa7d8428f37e943a6b5904495c40ad4b8011b767 100644
--- a/src/responder/nss/nss_enum.c
+++ b/src/responder/nss/nss_enum.c
@@ -93,7 +93,7 @@ nss_setent_internal_send(TALLOC_CTX *mem_ctx,
/* Create new object. */
state->enum_ctx->is_ready = false;
subreq = cache_req_send(req, ev, cli_ctx->rctx, cli_ctx->rctx->ncache,
- 0, NULL, data);
+ 0, CACHE_REQ_POSIX_DOM, NULL, data);
if (subreq == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "Unable to send cache request!\n");
ret = ENOMEM;
diff --git a/src/responder/nss/nss_get_object.c b/src/responder/nss/nss_get_object.c
index f83dd393c0e333d8914802e005672a15a51d5939..9058793ea2d72b57003a7219414af6a0f0c5b89e 100644
--- a/src/responder/nss/nss_get_object.c
+++ b/src/responder/nss/nss_get_object.c
@@ -190,7 +190,8 @@ nss_get_object_send(TALLOC_CTX *mem_ctx,
}
subreq = cache_req_send(req, ev, cli_ctx->rctx, cli_ctx->rctx->ncache,
- state->nss_ctx->cache_refresh_percent, NULL, data);
+ state->nss_ctx->cache_refresh_percent,
+ CACHE_REQ_POSIX_DOM, NULL, data);
if (subreq == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "Unable to send cache request!\n");
ret = ENOMEM;
diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c
index ba2563c11885ff39681c2ef432acaedf26702b64..fa6d2cc10fe1404196f9d9221a469d7a9a768211 100644
--- a/src/responder/pam/pamsrv_cmd.c
+++ b/src/responder/pam/pamsrv_cmd.c
@@ -1315,7 +1315,9 @@ static void pam_forwarder_cert_cb(struct tevent_req *req)
req = cache_req_user_by_cert_send(preq, cctx->ev, cctx->rctx,
- pctx->rctx->ncache, 0, NULL, cert);
+ pctx->rctx->ncache, 0,
+ CACHE_REQ_POSIX_DOM, NULL,
+ cert);
if (req == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "cache_req_user_by_cert_send failed.\n");
ret = ENOMEM;
@@ -1507,6 +1509,7 @@ static int pam_check_user_search(struct pam_auth_req *preq)
preq->cctx->rctx,
preq->cctx->rctx->ncache,
0,
+ CACHE_REQ_POSIX_DOM,
preq->pd->domain,
data);
if (!dpreq) {
diff --git a/src/responder/sudo/sudosrv_get_sudorules.c b/src/responder/sudo/sudosrv_get_sudorules.c
index 52dfd5c709e48f0d4610a4b384962fbc2869312b..cfdbfc9c9c66d96f774822d6a4d4aaaf1327abe3 100644
--- a/src/responder/sudo/sudosrv_get_sudorules.c
+++ b/src/responder/sudo/sudosrv_get_sudorules.c
@@ -644,7 +644,8 @@ struct tevent_req *sudosrv_get_rules_send(TALLOC_CTX *mem_ctx,
DEBUG(SSSDBG_TRACE_FUNC, "Running initgroups for [%s]\n", username);
subreq = cache_req_initgr_by_name_send(state, ev, sudo_ctx->rctx,
- sudo_ctx->rctx->ncache, 0, NULL,
+ sudo_ctx->rctx->ncache, 0,
+ CACHE_REQ_POSIX_DOM, NULL,
username);
if (subreq == NULL) {
ret = ENOMEM;
diff --git a/src/tests/cmocka/test_responder_cache_req.c b/src/tests/cmocka/test_responder_cache_req.c
index 5f1e5350eaf1d85de376c94731f0bd678f884a1d..80086232fd437876c2b190fb972c2ee3194d9efd 100644
--- a/src/tests/cmocka/test_responder_cache_req.c
+++ b/src/tests/cmocka/test_responder_cache_req.c
@@ -84,6 +84,28 @@ struct test_group {
talloc_free(req_mem_ctx); \
} while (0)
+#define run_cache_req_domtype(ctx, send_fn, done_fn, dom, crp, domtype, lookup, expret) do { \
+ TALLOC_CTX *req_mem_ctx; \
+ struct tevent_req *req; \
+ errno_t ret; \
+ \
+ req_mem_ctx = talloc_new(global_talloc_context); \
+ check_leaks_push(req_mem_ctx); \
+ \
+ req = send_fn(req_mem_ctx, ctx->tctx->ev, ctx->rctx, \
+ ctx->ncache, crp, \
+ domtype, \
+ (dom == NULL ? NULL : dom->name), lookup); \
+ assert_non_null(req); \
+ tevent_req_set_callback(req, done_fn, ctx); \
+ \
+ ret = test_ev_loop(ctx->tctx); \
+ assert_int_equal(ret, expret); \
+ assert_true(check_leaks_pop(req_mem_ctx)); \
+ \
+ talloc_free(req_mem_ctx); \
+} while (0)
+
struct cache_req_test_ctx {
struct sss_test_ctx *tctx;
struct resp_ctx *rctx;
@@ -211,9 +233,11 @@ static void run_user_by_name(struct cache_req_test_ctx *test_ctx,
int cache_refresh_percent,
errno_t exp_ret)
{
- run_cache_req(test_ctx, cache_req_user_by_name_send,
- cache_req_user_by_name_test_done, domain,
- cache_refresh_percent, users[0].short_name, exp_ret);
+ run_cache_req_domtype(test_ctx, cache_req_user_by_name_send,
+ cache_req_user_by_name_test_done, domain,
+ cache_refresh_percent,
+ CACHE_REQ_POSIX_DOM,
+ users[0].short_name, exp_ret);
}
static void run_user_by_upn(struct cache_req_test_ctx *test_ctx,
@@ -221,9 +245,11 @@ static void run_user_by_upn(struct cache_req_test_ctx *test_ctx,
int cache_refresh_percent,
errno_t exp_ret)
{
- run_cache_req(test_ctx, cache_req_user_by_name_send,
- cache_req_user_by_name_test_done, domain,
- cache_refresh_percent, users[0].upn, exp_ret);
+ run_cache_req_domtype(test_ctx, cache_req_user_by_name_send,
+ cache_req_user_by_name_test_done, domain,
+ cache_refresh_percent,
+ CACHE_REQ_POSIX_DOM,
+ users[0].upn, exp_ret);
}
static void run_user_by_id(struct cache_req_test_ctx *test_ctx,
@@ -318,9 +344,11 @@ static void run_group_by_name(struct cache_req_test_ctx *test_ctx,
int cache_refresh_percent,
errno_t exp_ret)
{
- run_cache_req(test_ctx, cache_req_group_by_name_send,
- cache_req_group_by_name_test_done, domain,
- cache_refresh_percent, groups[0].short_name, exp_ret);
+ run_cache_req_domtype(test_ctx, cache_req_group_by_name_send,
+ cache_req_group_by_name_test_done, domain,
+ cache_refresh_percent,
+ CACHE_REQ_POSIX_DOM,
+ groups[0].short_name, exp_ret);
}
static void run_group_by_id(struct cache_req_test_ctx *test_ctx,
@@ -605,7 +633,9 @@ void test_user_by_name_multiple_domains_parse(void **state)
check_leaks_push(req_mem_ctx);
req = cache_req_user_by_name_send(req_mem_ctx, test_ctx->tctx->ev,
- test_ctx->rctx, test_ctx->ncache, 0,
+ test_ctx->rctx, test_ctx->ncache,
+ CACHE_REQ_POSIX_DOM,
+ 0,
NULL, input_fqn);
assert_non_null(req);
tevent_req_set_callback(req, cache_req_user_by_name_test_done, test_ctx);
@@ -1119,7 +1149,8 @@ void test_group_by_name_multiple_domains_parse(void **state)
req = cache_req_group_by_name_send(req_mem_ctx, test_ctx->tctx->ev,
test_ctx->rctx, test_ctx->ncache, 0,
- NULL, input_fqn);
+ CACHE_REQ_POSIX_DOM, NULL,
+ input_fqn);
assert_non_null(req);
tevent_req_set_callback(req, cache_req_group_by_name_test_done, test_ctx);
@@ -1421,6 +1452,7 @@ void test_user_by_recent_filter_valid(void **state)
/* User TEST_USER is created with a DP callback. */
req = cache_req_user_by_filter_send(req_mem_ctx, test_ctx->tctx->ev,
test_ctx->rctx,
+ CACHE_REQ_POSIX_DOM,
test_ctx->tctx->dom->name,
TEST_USER_PREFIX);
assert_non_null(req);
@@ -1463,6 +1495,7 @@ void test_users_by_recent_filter_valid(void **state)
/* User TEST_USER1 and TEST_USER2 are created with a DP callback. */
req = cache_req_user_by_filter_send(req_mem_ctx, test_ctx->tctx->ev,
test_ctx->rctx,
+ CACHE_REQ_POSIX_DOM,
test_ctx->tctx->dom->name,
TEST_USER_PREFIX);
assert_non_null(req);
@@ -1524,6 +1557,7 @@ void test_users_by_filter_filter_old(void **state)
req = cache_req_user_by_filter_send(req_mem_ctx, test_ctx->tctx->ev,
test_ctx->rctx,
+ CACHE_REQ_POSIX_DOM,
test_ctx->tctx->dom->name,
TEST_USER_PREFIX);
assert_non_null(req);
@@ -1559,6 +1593,7 @@ void test_users_by_filter_notfound(void **state)
req = cache_req_user_by_filter_send(req_mem_ctx, test_ctx->tctx->ev,
test_ctx->rctx,
+ CACHE_REQ_POSIX_DOM,
test_ctx->tctx->dom->name,
"nosuchuser*");
assert_non_null(req);
@@ -1592,6 +1627,7 @@ static void test_users_by_filter_multiple_domains_notfound(void **state)
req = cache_req_user_by_filter_send(req_mem_ctx, test_ctx->tctx->ev,
test_ctx->rctx,
+ CACHE_REQ_POSIX_DOM,
domain->name,
"nosuchuser*");
assert_non_null(req);
@@ -1636,6 +1672,7 @@ void test_group_by_recent_filter_valid(void **state)
/* Group TEST_GROUP is created with a DP callback. */
req = cache_req_group_by_filter_send(req_mem_ctx, test_ctx->tctx->ev,
test_ctx->rctx,
+ CACHE_REQ_POSIX_DOM,
test_ctx->tctx->dom->name,
TEST_USER_PREFIX);
assert_non_null(req);
@@ -1680,6 +1717,7 @@ void test_groups_by_recent_filter_valid(void **state)
/* Group TEST_GROUP1 and TEST_GROUP2 are created with a DP callback. */
req = cache_req_group_by_filter_send(req_mem_ctx, test_ctx->tctx->ev,
test_ctx->rctx,
+ CACHE_REQ_POSIX_DOM,
test_ctx->tctx->dom->name,
TEST_USER_PREFIX);
assert_non_null(req);
@@ -1738,6 +1776,7 @@ void test_groups_by_filter_notfound(void **state)
req = cache_req_group_by_filter_send(req_mem_ctx, test_ctx->tctx->ev,
test_ctx->rctx,
+ CACHE_REQ_POSIX_DOM,
test_ctx->tctx->dom->name,
"nosuchgroup*");
assert_non_null(req);
@@ -1770,6 +1809,7 @@ void test_groups_by_filter_multiple_domains_notfound(void **state)
req = cache_req_group_by_filter_send(req_mem_ctx, test_ctx->tctx->ev,
test_ctx->rctx,
+ CACHE_REQ_POSIX_DOM,
domain->name,
"nosuchgroup*");
assert_non_null(req);
--
2.12.2

View File

@ -1,705 +0,0 @@
From 35f0f5ff9dac790f6c947190fcdc00d01ae9077c Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Fri, 24 Mar 2017 12:44:09 +0100
Subject: [PATCH 67/97] IFP: Search both POSIX and non-POSIX domains
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Related to:
https://pagure.io/SSSD/sssd/issue/3310
Changes the behaviour of the InfoPipe responder so that both application
and POSIX domains are searched. In general, the IFP responder uses the
CACHE_REQ_ANY_DOM lookup type because we can't presume the intention of
the caller. Therefore, deployments that combine both POSIX and non-POSIX
domains must use fully qualified names or select the right domain order
manually.
There is one change between the POSIX and non-POSIX users or groups -
the object path. For the POSIX users, the object path includes the UID
or GID. Because we don't have that for the non-POSIX objects, the object
name is used in the path instead.
Reviewed-by: Sumit Bose <sbose@redhat.com>
Reviewed-by: Pavel Březina <pbrezina@redhat.com>
---
src/responder/ifp/ifp_groups.c | 135 ++++++++++++++++++++++-------------
src/responder/ifp/ifp_users.c | 158 ++++++++++++++++++++++++++---------------
src/responder/ifp/ifpsrv_cmd.c | 6 +-
3 files changed, 194 insertions(+), 105 deletions(-)
diff --git a/src/responder/ifp/ifp_groups.c b/src/responder/ifp/ifp_groups.c
index 99908e96bd971bce4b4e9064a77d8413f837d743..c568c62009cd4b777919dea048fd381a91bd3460 100644
--- a/src/responder/ifp/ifp_groups.c
+++ b/src/responder/ifp/ifp_groups.c
@@ -35,25 +35,33 @@ char * ifp_groups_build_path_from_msg(TALLOC_CTX *mem_ctx,
struct sss_domain_info *domain,
struct ldb_message *msg)
{
- const char *gid;
+ const char *key = NULL;
- gid = ldb_msg_find_attr_as_string(msg, SYSDB_GIDNUM, NULL);
+ switch (domain->type) {
+ case DOM_TYPE_APPLICATION:
+ key = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
+ break;
+ case DOM_TYPE_POSIX:
+ key = ldb_msg_find_attr_as_string(msg, SYSDB_GIDNUM, NULL);
+ break;
+ }
- if (gid == NULL) {
+
+ if (key == NULL) {
return NULL;
}
- return sbus_opath_compose(mem_ctx, IFP_PATH_GROUPS, domain->name, gid);
+ return sbus_opath_compose(mem_ctx, IFP_PATH_GROUPS, domain->name, key);
}
-static errno_t ifp_groups_decompose_path(struct sss_domain_info *domains,
+static errno_t ifp_groups_decompose_path(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domains,
const char *path,
struct sss_domain_info **_domain,
- gid_t *_gid)
+ char **_key)
{
char **parts = NULL;
struct sss_domain_info *domain;
- gid_t gid;
errno_t ret;
ret = sbus_opath_decompose_exact(NULL, path, IFP_PATH_GROUPS, 2, &parts);
@@ -67,14 +75,8 @@ static errno_t ifp_groups_decompose_path(struct sss_domain_info *domains,
goto done;
}
- gid = strtouint32(parts[1], NULL, 10);
- ret = errno;
- if (ret != EOK) {
- goto done;
- }
-
*_domain = domain;
- *_gid = gid;
+ *_key = talloc_steal(mem_ctx, parts[1]);
done:
talloc_free(parts);
@@ -119,7 +121,7 @@ int ifp_groups_find_by_name(struct sbus_request *sbus_req,
req = cache_req_group_by_name_send(sbus_req, ctx->rctx->ev, ctx->rctx,
ctx->rctx->ncache, 0,
- CACHE_REQ_POSIX_DOM, NULL,
+ CACHE_REQ_ANY_DOM, NULL,
name);
if (req == NULL) {
return ENOMEM;
@@ -273,7 +275,7 @@ static int ifp_groups_list_by_name_step(struct ifp_list_ctx *list_ctx)
req = cache_req_group_by_filter_send(list_ctx,
list_ctx->ctx->rctx->ev,
list_ctx->ctx->rctx,
- CACHE_REQ_POSIX_DOM,
+ CACHE_REQ_ANY_DOM,
list_ctx->dom->name,
list_ctx->filter);
if (req == NULL) {
@@ -358,7 +360,7 @@ int ifp_groups_list_by_domain_and_name(struct sbus_request *sbus_req,
}
req = cache_req_group_by_filter_send(list_ctx, ctx->rctx->ev, ctx->rctx,
- CACHE_REQ_POSIX_DOM,
+ CACHE_REQ_ANY_DOM,
domain, filter);
if (req == NULL) {
return ENOMEM;
@@ -412,16 +414,65 @@ done:
}
static errno_t
+ifp_groups_get_from_cache(struct sbus_request *sbus_req,
+ struct sss_domain_info *domain,
+ const char *key,
+ struct ldb_message **_group)
+{
+ struct ldb_result *group_res;
+ errno_t ret;
+ gid_t gid;
+
+ switch (domain->type) {
+ case DOM_TYPE_POSIX:
+ gid = strtouint32(key, NULL, 10);
+ ret = errno;
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Invalid UID value\n");
+ return ret;
+ }
+
+ ret = sysdb_getgrgid_with_views(sbus_req, domain, gid, &group_res);
+ if (ret == EOK && group_res->count == 0) {
+ *_group = NULL;
+ return ENOENT;
+ } else if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to lookup group %u@%s [%d]: %s\n",
+ gid, domain->name, ret, sss_strerror(ret));
+ return ret;
+ }
+ break;
+ case DOM_TYPE_APPLICATION:
+ ret = sysdb_getgrnam_with_views(sbus_req, domain, key, &group_res);
+ if (ret == EOK && group_res->count == 0) {
+ *_group = NULL;
+ return ENOENT;
+ } else if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to lookup group %s@%s [%d]: %s\n",
+ key, domain->name, ret, sss_strerror(ret));
+ return ret;
+ }
+ break;
+ }
+
+ if (group_res->count > 1) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "More groups matched by the single key\n");
+ return EIO;
+ }
+
+ *_group = group_res->msgs[0];
+ return EOK;
+}
+
+static errno_t
ifp_groups_group_get(struct sbus_request *sbus_req,
void *data,
- gid_t *_gid,
struct sss_domain_info **_domain,
struct ldb_message **_group)
{
struct ifp_ctx *ctx;
struct sss_domain_info *domain;
- struct ldb_result *res;
- uid_t gid;
+ char *key;
errno_t ret;
ctx = talloc_get_type(data, struct ifp_ctx);
@@ -430,8 +481,9 @@ ifp_groups_group_get(struct sbus_request *sbus_req,
return ERR_INTERNAL;
}
- ret = ifp_groups_decompose_path(ctx->rctx->domains, sbus_req->path,
- &domain, &gid);
+ ret = ifp_groups_decompose_path(sbus_req,
+ ctx->rctx->domains, sbus_req->path,
+ &domain, &key);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, "Unable to decompose object path"
"[%s] [%d]: %s\n", sbus_req->path, ret, sss_strerror(ret));
@@ -439,28 +491,15 @@ ifp_groups_group_get(struct sbus_request *sbus_req,
}
if (_group != NULL) {
- ret = sysdb_getgrgid_with_views(sbus_req, domain, gid, &res);
- if (ret == EOK && res->count == 0) {
- *_group = NULL;
- ret = ENOENT;
- }
-
- if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to lookup group %u@%s [%d]: %s\n",
- gid, domain->name, ret, sss_strerror(ret));
- } else {
- *_group = res->msgs[0];
- }
+ ret = ifp_groups_get_from_cache(sbus_req, domain, key, _group);
}
if (ret == EOK || ret == ENOENT) {
- if (_gid != NULL) {
- *_gid = gid;
- }
-
if (_domain != NULL) {
*_domain = domain;
}
+ } else if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "Unable to retrieve group from cache\n");
}
return ret;
@@ -513,7 +552,7 @@ static struct tevent_req *resolv_ghosts_send(TALLOC_CTX *mem_ctx,
state->ctx = ctx;
state->data = data;
- ret = ifp_groups_group_get(sbus_req, data, NULL, &domain, &group);
+ ret = ifp_groups_group_get(sbus_req, data, &domain, &group);
if (ret != EOK) {
goto immediately;
}
@@ -527,7 +566,7 @@ static struct tevent_req *resolv_ghosts_send(TALLOC_CTX *mem_ctx,
subreq = cache_req_group_by_name_send(state, ev, ctx->rctx,
ctx->rctx->ncache, 0,
- CACHE_REQ_POSIX_DOM,
+ CACHE_REQ_ANY_DOM,
domain->name,
name);
if (subreq == NULL) {
@@ -561,7 +600,7 @@ static void resolv_ghosts_group_done(struct tevent_req *subreq)
req = tevent_req_callback_data(subreq, struct tevent_req);
state = tevent_req_data(req, struct resolv_ghosts_state);
- ret = ifp_groups_group_get(state->sbus_req, state->data, NULL,
+ ret = ifp_groups_group_get(state->sbus_req, state->data,
&state->domain, &group);
if (ret != EOK) {
goto done;
@@ -608,7 +647,7 @@ errno_t resolv_ghosts_step(struct tevent_req *req)
subreq = cache_req_user_by_name_send(state, state->ev, state->ctx->rctx,
state->ctx->rctx->ncache, 0,
- CACHE_REQ_POSIX_DOM,
+ CACHE_REQ_ANY_DOM,
state->domain->name,
state->ghosts[state->index]);
if (subreq == NULL) {
@@ -719,7 +758,7 @@ void ifp_groups_group_get_name(struct sbus_request *sbus_req,
return;
}
- ret = ifp_groups_group_get(sbus_req, data, NULL, &domain, &msg);
+ ret = ifp_groups_group_get(sbus_req, data, &domain, &msg);
if (ret != EOK) {
*_out = NULL;
return;
@@ -744,7 +783,7 @@ void ifp_groups_group_get_gid_number(struct sbus_request *sbus_req,
struct sss_domain_info *domain;
errno_t ret;
- ret = ifp_groups_group_get(sbus_req, data, NULL, &domain, &msg);
+ ret = ifp_groups_group_get(sbus_req, data, &domain, &msg);
if (ret != EOK) {
*_out = 0;
return;
@@ -763,7 +802,7 @@ void ifp_groups_group_get_unique_id(struct sbus_request *sbus_req,
struct sss_domain_info *domain;
errno_t ret;
- ret = ifp_groups_group_get(sbus_req, data, NULL, &domain, &msg);
+ ret = ifp_groups_group_get(sbus_req, data, &domain, &msg);
if (ret != EOK) {
*_out = 0;
return;
@@ -803,7 +842,7 @@ ifp_groups_group_get_members(TALLOC_CTX *mem_ctx,
return ENOMEM;
}
- ret = ifp_groups_group_get(sbus_req, data, NULL, &domain, &group);
+ ret = ifp_groups_group_get(sbus_req, data, &domain, &group);
if (ret != EOK) {
goto done;
}
@@ -954,7 +993,7 @@ int ifp_cache_object_store_group(struct sbus_request *sbus_req,
struct ldb_message *group;
errno_t ret;
- ret = ifp_groups_group_get(sbus_req, data, NULL, &domain, &group);
+ ret = ifp_groups_group_get(sbus_req, data, &domain, &group);
if (ret != EOK) {
error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Failed to fetch "
"group [%d]: %s\n", ret, sss_strerror(ret));
@@ -973,7 +1012,7 @@ int ifp_cache_object_remove_group(struct sbus_request *sbus_req,
struct ldb_message *group;
errno_t ret;
- ret = ifp_groups_group_get(sbus_req, data, NULL, &domain, &group);
+ ret = ifp_groups_group_get(sbus_req, data, &domain, &group);
if (ret != EOK) {
error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Failed to fetch "
"group [%d]: %s\n", ret, sss_strerror(ret));
diff --git a/src/responder/ifp/ifp_users.c b/src/responder/ifp/ifp_users.c
index 436bb268fa9c78d72fb744e0d338aa561a7d8764..ce9557f94351b730ee46f3cbce31613cb5901942 100644
--- a/src/responder/ifp/ifp_users.c
+++ b/src/responder/ifp/ifp_users.c
@@ -37,25 +37,33 @@ char * ifp_users_build_path_from_msg(TALLOC_CTX *mem_ctx,
struct sss_domain_info *domain,
struct ldb_message *msg)
{
- const char *uid;
+ const char *key = NULL;
- uid = ldb_msg_find_attr_as_string(msg, SYSDB_UIDNUM, NULL);
+ switch (domain->type) {
+ case DOM_TYPE_APPLICATION:
+ key = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
+ break;
+ case DOM_TYPE_POSIX:
+ key = ldb_msg_find_attr_as_string(msg, SYSDB_UIDNUM, NULL);
+ break;
+ }
- if (uid == NULL) {
+
+ if (key == NULL) {
return NULL;
}
- return sbus_opath_compose(mem_ctx, IFP_PATH_USERS, domain->name, uid);
+ return sbus_opath_compose(mem_ctx, IFP_PATH_USERS, domain->name, key);
}
-static errno_t ifp_users_decompose_path(struct sss_domain_info *domains,
+static errno_t ifp_users_decompose_path(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domains,
const char *path,
struct sss_domain_info **_domain,
- uid_t *_uid)
+ char **_key)
{
char **parts = NULL;
struct sss_domain_info *domain;
- uid_t uid;
errno_t ret;
ret = sbus_opath_decompose_exact(NULL, path, IFP_PATH_USERS, 2, &parts);
@@ -69,14 +77,8 @@ static errno_t ifp_users_decompose_path(struct sss_domain_info *domains,
goto done;
}
- uid = strtouint32(parts[1], NULL, 10);
- ret = errno;
- if (ret != EOK) {
- goto done;
- }
-
*_domain = domain;
- *_uid = uid;
+ *_key = talloc_steal(mem_ctx, parts[1]);
done:
talloc_free(parts);
@@ -100,7 +102,7 @@ int ifp_users_find_by_name(struct sbus_request *sbus_req,
req = cache_req_user_by_name_send(sbus_req, ctx->rctx->ev, ctx->rctx,
ctx->rctx->ncache, 0,
- CACHE_REQ_POSIX_DOM,
+ CACHE_REQ_ANY_DOM,
NULL, name);
if (req == NULL) {
return ENOMEM;
@@ -256,7 +258,7 @@ int ifp_users_find_by_cert(struct sbus_request *sbus_req, void *data,
req = cache_req_user_by_cert_send(sbus_req, ctx->rctx->ev, ctx->rctx,
ctx->rctx->ncache, 0,
- CACHE_REQ_POSIX_DOM, NULL,
+ CACHE_REQ_ANY_DOM, NULL,
derb64);
if (req == NULL) {
return ENOMEM;
@@ -371,7 +373,7 @@ static int ifp_users_list_by_cert_step(struct ifp_list_ctx *list_ctx)
list_ctx->ctx->rctx,
list_ctx->ctx->rctx->ncache,
0,
- CACHE_REQ_POSIX_DOM,
+ CACHE_REQ_ANY_DOM,
list_ctx->dom->name,
list_ctx->filter);
if (req == NULL) {
@@ -538,7 +540,7 @@ int ifp_users_find_by_name_and_cert(struct sbus_request *sbus_req, void *data,
if (name_and_cert_ctx->name != NULL) {
req = cache_req_user_by_name_send(sbus_req, ctx->rctx->ev, ctx->rctx,
ctx->rctx->ncache, 0,
- CACHE_REQ_POSIX_DOM,
+ CACHE_REQ_ANY_DOM,
NULL,
name_and_cert_ctx->name);
if (req == NULL) {
@@ -621,7 +623,7 @@ static int ifp_users_find_by_name_and_cert_step(
list_ctx->ctx->rctx,
list_ctx->ctx->rctx->ncache,
0,
- CACHE_REQ_POSIX_DOM,
+ CACHE_REQ_ANY_DOM,
list_ctx->dom->name,
list_ctx->filter);
if (req == NULL) {
@@ -782,7 +784,7 @@ static int ifp_users_list_by_name_step(struct ifp_list_ctx *list_ctx)
req = cache_req_user_by_filter_send(list_ctx,
list_ctx->ctx->rctx->ev,
list_ctx->ctx->rctx,
- CACHE_REQ_POSIX_DOM,
+ CACHE_REQ_ANY_DOM,
list_ctx->dom->name,
list_ctx->filter);
if (req == NULL) {
@@ -867,7 +869,7 @@ int ifp_users_list_by_domain_and_name(struct sbus_request *sbus_req,
}
req = cache_req_user_by_filter_send(list_ctx, ctx->rctx->ev, ctx->rctx,
- CACHE_REQ_POSIX_DOM,
+ CACHE_REQ_ANY_DOM,
domain, filter);
if (req == NULL) {
return ENOMEM;
@@ -930,19 +932,69 @@ done:
}
static errno_t
+ifp_users_get_from_cache(struct sbus_request *sbus_req,
+ struct sss_domain_info *domain,
+ const char *key,
+ struct ldb_message **_user)
+{
+ struct ldb_result *user_res;
+ errno_t ret;
+ uid_t uid;
+
+ switch (domain->type) {
+ case DOM_TYPE_POSIX:
+ uid = strtouint32(key, NULL, 10);
+ ret = errno;
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Invalid UID value\n");
+ return ret;
+ }
+
+ ret = sysdb_getpwuid_with_views(sbus_req, domain, uid, &user_res);
+ if (ret == EOK && user_res->count == 0) {
+ *_user = NULL;
+ return ENOENT;
+ } else if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to lookup user %u@%s [%d]: %s\n",
+ uid, domain->name, ret, sss_strerror(ret));
+ return ret;
+ }
+ break;
+ case DOM_TYPE_APPLICATION:
+ ret = sysdb_getpwnam_with_views(sbus_req, domain, key, &user_res);
+ if (ret == EOK && user_res->count == 0) {
+ *_user = NULL;
+ return ENOENT;
+ } else if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to lookup user %s@%s [%d]: %s\n",
+ key, domain->name, ret, sss_strerror(ret));
+ return ret;
+ }
+ break;
+ }
+
+ if (user_res->count > 1) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "More users matched by the single key\n");
+ return EIO;
+ }
+
+ *_user = user_res->msgs[0];
+ return EOK;
+}
+
+static errno_t
ifp_users_user_get(struct sbus_request *sbus_req,
struct ifp_ctx *ifp_ctx,
- uid_t *_uid,
struct sss_domain_info **_domain,
struct ldb_message **_user)
{
struct sss_domain_info *domain;
- struct ldb_result *res;
- uid_t uid;
+ char *key;
errno_t ret;
- ret = ifp_users_decompose_path(ifp_ctx->rctx->domains, sbus_req->path,
- &domain, &uid);
+ ret = ifp_users_decompose_path(sbus_req,
+ ifp_ctx->rctx->domains, sbus_req->path,
+ &domain, &key);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, "Unable to decompose object path"
"[%s] [%d]: %s\n", sbus_req->path, ret, sss_strerror(ret));
@@ -950,28 +1002,15 @@ ifp_users_user_get(struct sbus_request *sbus_req,
}
if (_user != NULL) {
- ret = sysdb_getpwuid_with_views(sbus_req, domain, uid, &res);
- if (ret == EOK && res->count == 0) {
- *_user = NULL;
- ret = ENOENT;
- }
-
- if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to lookup user %u@%s [%d]: %s\n",
- uid, domain->name, ret, sss_strerror(ret));
- } else {
- *_user = res->msgs[0];
- }
+ ret = ifp_users_get_from_cache(sbus_req, domain, key, _user);
}
if (ret == EOK || ret == ENOENT) {
- if (_uid != NULL) {
- *_uid = uid;
- }
-
if (_domain != NULL) {
*_domain = domain;
}
+ } else if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "Unable to retrieve user from cache\n");
}
return ret;
@@ -1000,7 +1039,7 @@ static void ifp_users_get_as_string(struct sbus_request *sbus_req,
return;
}
- ret = ifp_users_user_get(sbus_req, ifp_ctx, NULL, &domain, &msg);
+ ret = ifp_users_user_get(sbus_req, ifp_ctx, &domain, &msg);
if (ret != EOK) {
return;
}
@@ -1034,7 +1073,7 @@ static void ifp_users_get_name(struct sbus_request *sbus_req,
return;
}
- ret = ifp_users_user_get(sbus_req, ifp_ctx, NULL, &domain, &msg);
+ ret = ifp_users_user_get(sbus_req, ifp_ctx, &domain, &msg);
if (ret != EOK) {
return;
}
@@ -1072,7 +1111,7 @@ static void ifp_users_get_as_uint32(struct sbus_request *sbus_req,
return;
}
- ret = ifp_users_user_get(sbus_req, ifp_ctx, NULL, &domain, &msg);
+ ret = ifp_users_user_get(sbus_req, ifp_ctx, &domain, &msg);
if (ret != EOK) {
return;
}
@@ -1100,7 +1139,7 @@ int ifp_users_user_update_groups_list(struct sbus_request *sbus_req,
return ERR_INTERNAL;
}
- ret = ifp_users_user_get(sbus_req, data, NULL, &domain, &user);
+ ret = ifp_users_user_get(sbus_req, data, &domain, &user);
if (ret != EOK) {
return ret;
}
@@ -1113,7 +1152,7 @@ int ifp_users_user_update_groups_list(struct sbus_request *sbus_req,
req = cache_req_initgr_by_name_send(sbus_req, ctx->rctx->ev, ctx->rctx,
ctx->rctx->ncache, 0,
- CACHE_REQ_POSIX_DOM, domain->name,
+ CACHE_REQ_ANY_DOM, domain->name,
username);
if (req == NULL) {
return ENOMEM;
@@ -1235,7 +1274,7 @@ void ifp_users_user_get_groups(struct sbus_request *sbus_req,
return;
}
- ret = ifp_users_user_get(sbus_req, ifp_ctx, NULL, &domain, &user);
+ ret = ifp_users_user_get(sbus_req, ifp_ctx, &domain, &user);
if (ret != EOK) {
return;
}
@@ -1268,7 +1307,7 @@ void ifp_users_user_get_groups(struct sbus_request *sbus_req,
for (i = 0; i < res->count; i++) {
gid = sss_view_ldb_msg_find_attr_as_uint64(domain, res->msgs[i],
SYSDB_GIDNUM, 0);
- if (gid == 0) {
+ if (gid == 0 && domain->type == DOM_TYPE_POSIX) {
continue;
}
@@ -1293,11 +1332,12 @@ void ifp_users_user_get_extra_attributes(struct sbus_request *sbus_req,
{
struct ifp_ctx *ifp_ctx;
struct sss_domain_info *domain;
+ struct ldb_message *base_user;
+ const char *name;
struct ldb_message **user;
struct ldb_message_element *el;
struct ldb_dn *basedn;
size_t count;
- uid_t uid;
const char *filter;
const char **extra;
hash_table_t *table;
@@ -1322,7 +1362,7 @@ void ifp_users_user_get_extra_attributes(struct sbus_request *sbus_req,
return;
}
- ret = ifp_users_user_get(sbus_req, data, &uid, &domain, NULL);
+ ret = ifp_users_user_get(sbus_req, data, &domain, &base_user);
if (ret != EOK) {
return;
}
@@ -1333,9 +1373,15 @@ void ifp_users_user_get_extra_attributes(struct sbus_request *sbus_req,
return;
}
- filter = talloc_asprintf(sbus_req, "(&(%s=%s)(%s=%u))",
+ name = ldb_msg_find_attr_as_string(base_user, SYSDB_NAME, NULL);
+ if (name == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "A user with no name\n");
+ return;
+ }
+
+ filter = talloc_asprintf(sbus_req, "(&(%s=%s)(%s=%s))",
SYSDB_OBJECTCLASS, SYSDB_USER_CLASS,
- SYSDB_UIDNUM, uid);
+ SYSDB_NAME, name);
if (filter == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf() failed\n");
return;
@@ -1351,7 +1397,7 @@ void ifp_users_user_get_extra_attributes(struct sbus_request *sbus_req,
}
if (count == 0) {
- DEBUG(SSSDBG_TRACE_FUNC, "User %u not found!\n", uid);
+ DEBUG(SSSDBG_TRACE_FUNC, "User %s not found!\n", name);
return;
} else if (count > 1) {
DEBUG(SSSDBG_CRIT_FAILURE, "More than one entry found!\n");
@@ -1421,7 +1467,7 @@ int ifp_cache_object_store_user(struct sbus_request *sbus_req,
struct ldb_message *user;
errno_t ret;
- ret = ifp_users_user_get(sbus_req, data, NULL, &domain, &user);
+ ret = ifp_users_user_get(sbus_req, data, &domain, &user);
if (ret != EOK) {
error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Failed to fetch "
"user [%d]: %s\n", ret, sss_strerror(ret));
@@ -1440,7 +1486,7 @@ int ifp_cache_object_remove_user(struct sbus_request *sbus_req,
struct ldb_message *user;
errno_t ret;
- ret = ifp_users_user_get(sbus_req, data, NULL, &domain, &user);
+ ret = ifp_users_user_get(sbus_req, data, &domain, &user);
if (ret != EOK) {
error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Failed to fetch "
"user [%d]: %s\n", ret, sss_strerror(ret));
diff --git a/src/responder/ifp/ifpsrv_cmd.c b/src/responder/ifp/ifpsrv_cmd.c
index 118b5083b14bf5692c6fdd7ba90668fe514aa89d..d10f35e41dbb1623a0b9de37a4c43363cbefc1a3 100644
--- a/src/responder/ifp/ifpsrv_cmd.c
+++ b/src/responder/ifp/ifpsrv_cmd.c
@@ -508,8 +508,12 @@ ifp_user_get_attr_lookup(struct tevent_req *subreq)
return;
}
+ /* IFP serves both POSIX and application domains. Requests that need
+ * to differentiate between the two must be qualified
+ */
subreq = cache_req_send(state, state->rctx->ev, state->rctx,
- state->ncache, 0, CACHE_REQ_POSIX_DOM,
+ state->ncache, 0,
+ CACHE_REQ_ANY_DOM,
state->domname, data);
if (subreq == NULL) {
tevent_req_error(req, ENOMEM);
--
2.12.2

View File

@ -1,57 +0,0 @@
From b010f24f4d96d15c5c85021bb4aa83db25cd3df5 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Tue, 28 Mar 2017 14:07:29 +0200
Subject: [PATCH 68/97] IFP: ListByName: Don't crash when no results are found
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
If no results were found using the List command, the results variable
was undefined which resulted in a crash.
Instead, only copy the results of the cache_req lookup returns EOK and
we can presume that the results are valid.
Reviewed-by: Pavel Březina <pbrezina@redhat.com>
Reviewed-by: Sumit Bose <sbose@redhat.com>
---
src/responder/ifp/ifp_users.c | 16 +++++++++-------
1 file changed, 9 insertions(+), 7 deletions(-)
diff --git a/src/responder/ifp/ifp_users.c b/src/responder/ifp/ifp_users.c
index ce9557f94351b730ee46f3cbce31613cb5901942..188194f2ab356d0e67b0f26b003f3a9ce48e6acd 100644
--- a/src/responder/ifp/ifp_users.c
+++ b/src/responder/ifp/ifp_users.c
@@ -801,7 +801,7 @@ static void ifp_users_list_by_name_done(struct tevent_req *req)
DBusError *error;
struct ifp_list_ctx *list_ctx;
struct sbus_request *sbus_req;
- struct cache_req_result *result;
+ struct cache_req_result *result = NULL;
errno_t ret;
list_ctx = tevent_req_callback_data(req, struct ifp_list_ctx);
@@ -816,12 +816,14 @@ static void ifp_users_list_by_name_done(struct tevent_req *req)
return;
}
- ret = ifp_users_list_copy(list_ctx, result->ldb_result);
- if (ret != EOK) {
- error = sbus_error_new(sbus_req, SBUS_ERROR_INTERNAL,
- "Failed to copy domain result");
- sbus_request_fail_and_finish(sbus_req, error);
- return;
+ if (ret == EOK) {
+ ret = ifp_users_list_copy(list_ctx, result->ldb_result);
+ if (ret != EOK) {
+ error = sbus_error_new(sbus_req, SBUS_ERROR_INTERNAL,
+ "Failed to copy domain result");
+ sbus_request_fail_and_finish(sbus_req, error);
+ return;
+ }
}
list_ctx->dom = get_next_domain(list_ctx->dom, SSS_GND_DESCEND);
--
2.12.2

View File

@ -1,58 +0,0 @@
From 57eeec5d735c7a3bbe58299fded97414626d85f1 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Fri, 24 Mar 2017 20:36:06 +0100
Subject: [PATCH 69/97] PAM: Remove unneeded memory context
Since we only store data into pam_ctx in get_public_domains(), it
doesn't make sense to allow passing a separate memory context. It is
always going to be pam_ctx, otherwise the memory hierarchy will cause
issues anyway.
Reviewed-by: Sumit Bose <sbose@redhat.com>
---
src/responder/pam/pamsrv.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/responder/pam/pamsrv.c b/src/responder/pam/pamsrv.c
index 816f2293130ff8761ca94b4a42ca93063c11ea35..ab3f4545520f3fcb2492a6089a039c46f0fb847f 100644
--- a/src/responder/pam/pamsrv.c
+++ b/src/responder/pam/pamsrv.c
@@ -122,7 +122,7 @@ done:
return ret;
}
-static errno_t get_public_domains(TALLOC_CTX *mem_ctx, struct pam_ctx *pctx)
+static errno_t get_public_domains(struct pam_ctx *pctx)
{
char *domains_str = NULL;
errno_t ret;
@@ -137,7 +137,7 @@ static errno_t get_public_domains(TALLOC_CTX *mem_ctx, struct pam_ctx *pctx)
if (strcmp(domains_str, ALL_DOMAIMS_ARE_PUBLIC) == 0) { /* all */
/* copy all domains */
- ret = get_dom_names(mem_ctx,
+ ret = get_dom_names(pctx,
pctx->rctx->domains,
&pctx->public_domains,
&pctx->public_domains_count);
@@ -149,7 +149,7 @@ static errno_t get_public_domains(TALLOC_CTX *mem_ctx, struct pam_ctx *pctx)
pctx->public_domains = NULL;
pctx->public_domains_count = 0;
} else {
- ret = split_on_separator(mem_ctx, domains_str, ',', true, false,
+ ret = split_on_separator(pctx, domains_str, ',', true, false,
&pctx->public_domains,
&pctx->public_domains_count);
if (ret != EOK) {
@@ -212,7 +212,7 @@ static int pam_process_init(TALLOC_CTX *mem_ctx,
goto done;
}
- ret = get_public_domains(pctx, pctx);
+ ret = get_public_domains(pctx);
if (ret != EOK) {
DEBUG(SSSDBG_FATAL_FAILURE, "get_public_domains failed: %d:[%s].\n",
ret, sss_strerror(ret));
--
2.12.2

View File

@ -1,452 +0,0 @@
From 3e789aa0bd6b7bb6e62f91458b76753498030fb5 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Sun, 26 Mar 2017 18:28:41 +0200
Subject: [PATCH 70/97] PAM: Add application services
Related to:
https://pagure.io/SSSD/sssd/issue/3310
Adds a new PAM responder option 'pam_app_services'. This option can hold
a list of PAM services that are allowed to contact the application
non-POSIX domains. These services are NOT allowed to contact any of the
POSIX domains.
Reviewed-by: Sumit Bose <sbose@redhat.com>
---
src/confdb/confdb.h | 1 +
src/config/SSSDConfig/__init__.py.in | 1 +
src/config/cfg_rules.ini | 1 +
src/config/etc/sssd.api.conf | 1 +
src/man/sssd.conf.5.xml | 12 +++
src/responder/pam/pamsrv.c | 33 +++++++
src/responder/pam/pamsrv.h | 5 ++
src/responder/pam/pamsrv_cmd.c | 26 +++++-
src/tests/cmocka/test_pam_srv.c | 167 ++++++++++++++++++++++++++++++++++-
9 files changed, 241 insertions(+), 6 deletions(-)
diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
index 5a8d377c312f641f544b1c7cf38826192462ea3c..8719c239362b371fcdb1b78956bcddde871f141b 100644
--- a/src/confdb/confdb.h
+++ b/src/confdb/confdb.h
@@ -129,6 +129,7 @@
#define CONFDB_PAM_CERT_AUTH "pam_cert_auth"
#define CONFDB_PAM_CERT_DB_PATH "pam_cert_db_path"
#define CONFDB_PAM_P11_CHILD_TIMEOUT "p11_child_timeout"
+#define CONFDB_PAM_APP_SERVICES "pam_app_services"
/* SUDO */
#define CONFDB_SUDO_CONF_ENTRY "config/sudo"
diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in
index 070994bcd04604777019d264d12cb126d6638bfd..a29d51e0ddffc520107a309d862346fb4d4f5f80 100644
--- a/src/config/SSSDConfig/__init__.py.in
+++ b/src/config/SSSDConfig/__init__.py.in
@@ -102,6 +102,7 @@ option_strings = {
'pam_cert_auth' : _('Allow certificate based/Smartcard authentication.'),
'pam_cert_db_path' : _('Path to certificate databse with PKCS#11 modules.'),
'p11_child_timeout' : _('How many seconds will pam_sss wait for p11_child to finish'),
+ 'pam_app_services' : _('Which PAM services are permitted to contact application domains'),
# [sudo]
'sudo_timed' : _('Whether to evaluate the time-based attributes in sudo rules'),
diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini
index 8fd2d2c5236246394353a88c50d1510bd6233f77..1a749db754cedd87f263f7ae596d6f8238bb4357 100644
--- a/src/config/cfg_rules.ini
+++ b/src/config/cfg_rules.ini
@@ -119,6 +119,7 @@ option = pam_account_locked_message
option = pam_cert_auth
option = pam_cert_db_path
option = p11_child_timeout
+option = pam_app_services
[rule/allowed_sudo_options]
validator = ini_allowed_options
diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf
index a38b24208f89e4502e41625c540ea9958d5bbffe..a1a0c2992925a4c7df86832117eec2a0cf7894c9 100644
--- a/src/config/etc/sssd.api.conf
+++ b/src/config/etc/sssd.api.conf
@@ -73,6 +73,7 @@ pam_account_locked_message = str, None, false
pam_cert_auth = bool, None, false
pam_cert_db_path = str, None, false
p11_child_timeout = int, None, false
+pam_app_services = str, None, false
[sudo]
# sudo service
diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
index 8294793c765bfa6bf481693c7d7f206950454681..c4e30396f16c40db37af2f56ac218b6e37201ef7 100644
--- a/src/man/sssd.conf.5.xml
+++ b/src/man/sssd.conf.5.xml
@@ -1325,6 +1325,18 @@ pam_account_locked_message = Account locked, please contact help desk.
</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>pam_app_services (string)</term>
+ <listitem>
+ <para>
+ Which PAM services are permitted to contact
+ domains of type <quote>application</quote>
+ </para>
+ <para>
+ Default: Not set
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect2>
diff --git a/src/responder/pam/pamsrv.c b/src/responder/pam/pamsrv.c
index ab3f4545520f3fcb2492a6089a039c46f0fb847f..79470823d18138da6ef9235e6336a3220ead1797 100644
--- a/src/responder/pam/pamsrv.c
+++ b/src/responder/pam/pamsrv.c
@@ -166,6 +166,32 @@ done:
return ret;
}
+static errno_t get_app_services(struct pam_ctx *pctx)
+{
+ errno_t ret;
+
+ ret = confdb_get_string_as_list(pctx->rctx->cdb, pctx,
+ CONFDB_PAM_CONF_ENTRY,
+ CONFDB_PAM_APP_SERVICES,
+ &pctx->app_services);
+ if (ret == ENOENT) {
+ pctx->app_services = talloc_zero_array(pctx, char *, 1);
+ if (pctx->app_services == NULL) {
+ return ENOMEM;
+ }
+ /* Allocating an empty array makes it easier for the consumer
+ * to iterate over it
+ */
+ } else if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Cannot read "CONFDB_PAM_APP_SERVICES" [%d]: %s\n",
+ ret, sss_strerror(ret));
+ return ret;
+ }
+
+ return EOK;
+}
+
static int pam_process_init(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct confdb_ctx *cdb,
@@ -219,6 +245,13 @@ static int pam_process_init(TALLOC_CTX *mem_ctx,
goto done;
}
+ ret = get_app_services(pctx);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "get_app_services failed: %d:[%s].\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
/* Enable automatic reconnection to the Data Provider */
/* FIXME: "retries" is too generic, either get it from a global config
diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h
index b3eb56441048ecdba82866a95f1d6d6d5e786c60..b569748fe2a2005cee5df34bef55e803175492a9 100644
--- a/src/responder/pam/pamsrv.h
+++ b/src/responder/pam/pamsrv.h
@@ -26,6 +26,7 @@
#include "util/util.h"
#include "sbus/sssd_dbus.h"
#include "responder/common/responder.h"
+#include "responder/common/cache_req/cache_req.h"
struct pam_auth_req;
@@ -42,6 +43,9 @@ struct pam_ctx {
char **public_domains;
int public_domains_count;
+ /* What services are permitted to access application domains */
+ char **app_services;
+
bool cert_auth;
int p11_child_debug_fd;
char *nss_db;
@@ -54,6 +58,7 @@ struct pam_auth_dp_req {
struct pam_auth_req {
struct cli_ctx *cctx;
struct sss_domain_info *domain;
+ enum cache_req_dom_type req_dom_type;
struct pam_data *pd;
diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c
index fa6d2cc10fe1404196f9d9221a469d7a9a768211..f2b3c74b483e527932dda42279d14a9ac184b475 100644
--- a/src/responder/pam/pamsrv_cmd.c
+++ b/src/responder/pam/pamsrv_cmd.c
@@ -1161,6 +1161,25 @@ static bool is_domain_public(char *name,
return false;
}
+static enum cache_req_dom_type
+get_domain_request_type(struct pam_auth_req *preq,
+ struct pam_ctx *pctx)
+{
+ enum cache_req_dom_type req_dom_type;
+
+ /* By default, only POSIX domains are to be contacted */
+ req_dom_type = CACHE_REQ_POSIX_DOM;
+
+ for (int i = 0; pctx->app_services[i]; i++) {
+ if (strcmp(pctx->app_services[i], preq->pd->service) == 0) {
+ req_dom_type = CACHE_REQ_APPLICATION_DOM;
+ break;
+ }
+ }
+
+ return req_dom_type;
+}
+
static errno_t check_cert(TALLOC_CTX *mctx,
struct tevent_context *ev,
struct pam_ctx *pctx,
@@ -1257,6 +1276,9 @@ static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd)
goto done;
}
+ /* Determine what domain type to contact */
+ preq->req_dom_type = get_domain_request_type(preq, pctx);
+
/* try backend first for authentication before doing local Smartcard
* authentication */
if (pd->cmd != SSS_PAM_AUTHENTICATE && may_do_cert_auth(pctx, pd)) {
@@ -1316,7 +1338,7 @@ static void pam_forwarder_cert_cb(struct tevent_req *req)
req = cache_req_user_by_cert_send(preq, cctx->ev, cctx->rctx,
pctx->rctx->ncache, 0,
- CACHE_REQ_POSIX_DOM, NULL,
+ preq->req_dom_type, NULL,
cert);
if (req == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "cache_req_user_by_cert_send failed.\n");
@@ -1509,7 +1531,7 @@ static int pam_check_user_search(struct pam_auth_req *preq)
preq->cctx->rctx,
preq->cctx->rctx->ncache,
0,
- CACHE_REQ_POSIX_DOM,
+ preq->req_dom_type,
preq->pd->domain,
data);
if (!dpreq) {
diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c
index 847419658bb983e6548722d6fa6fb22c63ee86b8..d249b8f1ea48f1c17b461c3add9e8c63774e5f88 100644
--- a/src/tests/cmocka/test_pam_srv.c
+++ b/src/tests/cmocka/test_pam_srv.c
@@ -186,6 +186,15 @@ struct pam_ctx *mock_pctx(TALLOC_CTX *mem_ctx)
ret = sss_hash_create(pctx, 10, &pctx->id_table);
assert_int_equal(ret, EOK);
+ /* Two NULLs so that tests can just assign a const to the first slot
+ * should they need it. The code iterates until first NULL anyway
+ */
+ pctx->app_services = talloc_zero_array(pctx, char *, 2);
+ if (pctx->app_services == NULL) {
+ talloc_free(pctx);
+ return NULL;
+ }
+
return pctx;
}
@@ -495,8 +504,12 @@ int __wrap_pam_dp_send_req(struct pam_auth_req *preq, int timeout)
return EOK;
}
-static void mock_input_pam(TALLOC_CTX *mem_ctx, const char *name,
- const char *pwd, const char *fa2)
+static void mock_input_pam_ex(TALLOC_CTX *mem_ctx,
+ const char *name,
+ const char *pwd,
+ const char *fa2,
+ const char *svc,
+ bool contact_dp)
{
size_t buf_size;
uint8_t *m_buf;
@@ -536,7 +549,10 @@ static void mock_input_pam(TALLOC_CTX *mem_ctx, const char *name,
}
}
- pi.pam_service = "pam_test_service";
+ if (svc == NULL) {
+ svc = "pam_test_service";
+ }
+ pi.pam_service = svc;
pi.pam_service_size = strlen(pi.pam_service) + 1;
pi.pam_tty = "/dev/tty";
pi.pam_tty_size = strlen(pi.pam_tty) + 1;
@@ -559,7 +575,17 @@ static void mock_input_pam(TALLOC_CTX *mem_ctx, const char *name,
will_return(__wrap_sss_packet_get_body, buf_size);
mock_parse_inp(name, NULL, EOK);
- mock_account_recv_simple();
+ if (contact_dp) {
+ mock_account_recv_simple();
+ }
+}
+
+static void mock_input_pam(TALLOC_CTX *mem_ctx,
+ const char *name,
+ const char *pwd,
+ const char *fa2)
+{
+ return mock_input_pam_ex(mem_ctx, name, pwd, fa2, NULL, true);
}
static void mock_input_pam_cert(TALLOC_CTX *mem_ctx, const char *name,
@@ -2097,6 +2123,127 @@ void test_filter_response(void **state)
talloc_free(pd);
}
+static int pam_test_setup_appsvc_posix_dom(void **state)
+{
+ int ret;
+
+ ret = pam_test_setup(state);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ /* This config option is only read on startup, which is not executed
+ * in test, so we can't just pass in a param
+ */
+ pam_test_ctx->pctx->app_services[0] = discard_const("app_svc");
+ return 0;
+}
+
+void test_appsvc_posix_dom(void **state)
+{
+ int ret;
+
+ /* The domain is POSIX, the request will skip over it */
+ mock_input_pam_ex(pam_test_ctx, "pamuser", NULL, NULL, "app_svc", false);
+ pam_test_ctx->exp_pam_status = PAM_USER_UNKNOWN;
+
+ will_return(__wrap_sss_packet_get_cmd, SSS_PAM_AUTHENTICATE);
+ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
+
+ set_cmd_cb(test_pam_user_unknown_check);
+ ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_AUTHENTICATE,
+ pam_test_ctx->pam_cmds);
+ assert_int_equal(ret, EOK);
+
+ ret = test_ev_loop(pam_test_ctx->tctx);
+ assert_int_equal(ret, EOK);
+}
+
+void test_not_appsvc_posix_dom(void **state)
+{
+ int ret;
+
+ /* A different service than the app one can authenticate against a POSIX domain */
+ mock_input_pam_ex(pam_test_ctx, "pamuser", NULL, NULL, "not_app_svc", true);
+
+ will_return(__wrap_sss_packet_get_cmd, SSS_PAM_AUTHENTICATE);
+ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
+
+ set_cmd_cb(test_pam_simple_check);
+ ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_AUTHENTICATE,
+ pam_test_ctx->pam_cmds);
+ assert_int_equal(ret, EOK);
+
+ /* Wait until the test finishes with EOK */
+ ret = test_ev_loop(pam_test_ctx->tctx);
+ assert_int_equal(ret, EOK);
+}
+
+static int pam_test_setup_appsvc_app_dom(void **state)
+{
+ struct sss_test_conf_param dom_params[] = {
+ { "domain_type", "application" },
+ { NULL, NULL }, /* Sentinel */
+ };
+ struct sss_test_conf_param pam_params[] = {
+ { NULL, NULL }, /* Sentinel */
+ };
+ struct sss_test_conf_param monitor_params[] = {
+ { NULL, NULL }, /* Sentinel */
+ };
+
+
+ test_pam_setup(dom_params, pam_params, monitor_params, state);
+ pam_test_setup_common();
+
+ /* This config option is only read on startup, which is not executed
+ * in test, so we can't just pass in a param
+ */
+ pam_test_ctx->pctx->app_services[0] = discard_const("app_svc");
+ return 0;
+}
+
+void test_appsvc_app_dom(void **state)
+{
+ int ret;
+
+ /* The domain is POSIX, the request will skip over it */
+ mock_input_pam_ex(pam_test_ctx, "pamuser", NULL, NULL, "app_svc", true);
+
+ will_return(__wrap_sss_packet_get_cmd, SSS_PAM_AUTHENTICATE);
+ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
+
+ set_cmd_cb(test_pam_simple_check);
+ ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_AUTHENTICATE,
+ pam_test_ctx->pam_cmds);
+ assert_int_equal(ret, EOK);
+
+ /* Wait until the test finishes with EOK */
+ ret = test_ev_loop(pam_test_ctx->tctx);
+ assert_int_equal(ret, EOK);
+}
+
+void test_not_appsvc_app_dom(void **state)
+{
+ int ret;
+
+ /* A different service than the app one can authenticate against a POSIX domain */
+ mock_input_pam_ex(pam_test_ctx, "pamuser", NULL, NULL, "not_app_svc", false);
+
+ pam_test_ctx->exp_pam_status = PAM_USER_UNKNOWN;
+
+ will_return(__wrap_sss_packet_get_cmd, SSS_PAM_AUTHENTICATE);
+ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
+
+ set_cmd_cb(test_pam_user_unknown_check);
+ ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_AUTHENTICATE,
+ pam_test_ctx->pam_cmds);
+ assert_int_equal(ret, EOK);
+
+ ret = test_ev_loop(pam_test_ctx->tctx);
+ assert_int_equal(ret, EOK);
+}
+
int main(int argc, const char *argv[])
{
int rv;
@@ -2216,6 +2363,18 @@ int main(int argc, const char *argv[])
cmocka_unit_test_setup_teardown(test_filter_response,
pam_test_setup, pam_test_teardown),
+ cmocka_unit_test_setup_teardown(test_appsvc_posix_dom,
+ pam_test_setup_appsvc_posix_dom,
+ pam_test_teardown),
+ cmocka_unit_test_setup_teardown(test_not_appsvc_posix_dom,
+ pam_test_setup_appsvc_posix_dom,
+ pam_test_teardown),
+ cmocka_unit_test_setup_teardown(test_appsvc_app_dom,
+ pam_test_setup_appsvc_app_dom,
+ pam_test_teardown),
+ cmocka_unit_test_setup_teardown(test_not_appsvc_app_dom,
+ pam_test_setup_appsvc_posix_dom,
+ pam_test_teardown),
};
/* Set debug level to invalid value so we can deside if -d 0 was used. */
--
2.12.2

View File

@ -1,152 +0,0 @@
From 5f7f249f2a8a1c7284e991aa64dbf850d482b0aa Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Wed, 22 Mar 2017 13:00:31 +0100
Subject: [PATCH 71/97] SYSDB: Allow storing non-POSIX users
Related to:
https://pagure.io/SSSD/sssd/issue/3310
We already do the same for groups. If the user does not have UID number
set but does have the POSIX: false attribute set, then we save the user
with zero UID and the non-POSIX flag.
Reviewed-by: Sumit Bose <sbose@redhat.com>
---
src/db/sysdb_ops.c | 32 ++++++++++++++++++++--------
src/tests/sysdb-tests.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 79 insertions(+), 9 deletions(-)
diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c
index 919f22370ff87eff2bf0bb569ca90f1ee699a61e..3cf9d903f25b9ccd506d7957c94040bdc7d658a3 100644
--- a/src/db/sysdb_ops.c
+++ b/src/db/sysdb_ops.c
@@ -1855,6 +1855,7 @@ int sysdb_add_user(struct sss_domain_info *domain,
struct sysdb_attrs *id_attrs;
uint32_t id;
int ret;
+ bool posix;
if (domain->mpg) {
if (gid != 0) {
@@ -1926,7 +1927,28 @@ int sysdb_add_user(struct sss_domain_info *domain,
/* Not fatal */
}
- if (uid == 0) {
+ if (!attrs) {
+ attrs = sysdb_new_attrs(tmp_ctx);
+ if (!attrs) {
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+
+ ret = sysdb_attrs_get_bool(attrs, SYSDB_POSIX, &posix);
+ if (ret == ENOENT) {
+ posix = true;
+ ret = sysdb_attrs_add_bool(attrs, SYSDB_POSIX, true);
+ if (ret) {
+ DEBUG(SSSDBG_TRACE_LIBS, "Failed to add posix attribute.\n");
+ goto done;
+ }
+ } else if (ret != EOK) {
+ DEBUG(SSSDBG_TRACE_LIBS, "Failed to get posix attribute.\n");
+ goto done;
+ }
+
+ if (uid == 0 && posix == true) {
ret = sysdb_get_new_id(domain, &id);
if (ret) goto done;
@@ -1948,14 +1970,6 @@ int sysdb_add_user(struct sss_domain_info *domain,
if (ret) goto done;
}
- if (!attrs) {
- attrs = sysdb_new_attrs(tmp_ctx);
- if (!attrs) {
- ret = ENOMEM;
- goto done;
- }
- }
-
if (!now) {
now = time(NULL);
}
diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c
index 1767dc3c734c6b2e5f74564debd603e2442f491b..6ec82ce4ca5c4f918bc9f3144c21f33b270ea47e 100644
--- a/src/tests/sysdb-tests.c
+++ b/src/tests/sysdb-tests.c
@@ -1428,6 +1428,59 @@ START_TEST (test_sysdb_get_user_attr_subdomain)
}
END_TEST
+START_TEST (test_sysdb_add_nonposix_user)
+{
+ struct sysdb_test_ctx *test_ctx;
+ const char *get_attrs[] = { SYSDB_GIDNUM,
+ SYSDB_UIDNUM,
+ SYSDB_POSIX,
+ NULL };
+ struct ldb_result *res;
+ const char *attrval;
+ const char *username = "test_sysdb_add_nonposix_user";
+ const char *fq_name;
+ struct sysdb_attrs *user_attrs;
+ int ret;
+ uint64_t id;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ fail_if(ret != EOK, "Could not set up the test");
+
+ /* Create user */
+ fq_name = sss_create_internal_fqname(test_ctx, username, test_ctx->domain->name);
+ fail_if(fq_name == NULL, "Failed to create fq name.");
+
+ user_attrs = sysdb_new_attrs(test_ctx);
+ fail_if(user_attrs == NULL);
+
+ ret = sysdb_attrs_add_bool(user_attrs, SYSDB_POSIX, false);
+ fail_if(ret != EOK, "Could not add attribute");
+
+ ret = sysdb_add_user(test_ctx->domain, fq_name, 0, 0, "Gecos",
+ "/home/userhome", "/bin/bash", NULL, user_attrs, 0, 0);
+ fail_if(ret != EOK, "sysdb_add_user failed.");
+
+ /* Test */
+ ret = sysdb_get_user_attr(test_ctx, test_ctx->domain, fq_name,
+ get_attrs, &res);
+ fail_if(ret != EOK, "Could not get user attributes.");
+ fail_if(res->count != 1, "Invalid number of entries, expected 1, got %d",
+ res->count);
+
+ attrval = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_POSIX, NULL);
+ fail_if(strcasecmp(attrval, "false") != 0, "Got bad attribute value.");
+
+ id = ldb_msg_find_attr_as_uint64(res->msgs[0], SYSDB_UIDNUM, 123);
+ fail_unless(id == 0, "Wrong UID value");
+
+ id = ldb_msg_find_attr_as_uint64(res->msgs[0], SYSDB_GIDNUM, 123);
+ fail_unless(id == 0, "Wrong GID value");
+
+ talloc_free(test_ctx);
+}
+END_TEST
+
START_TEST (test_sysdb_add_group_member)
{
struct sysdb_test_ctx *test_ctx;
@@ -7044,6 +7097,9 @@ Suite *create_sysdb_suite(void)
/* Test GetUserAttr with subdomain user */
tcase_add_test(tc_sysdb, test_sysdb_get_user_attr_subdomain);
+ /* Test adding a non-POSIX user */
+ tcase_add_test(tc_sysdb, test_sysdb_add_nonposix_user);
+
/* ===== NETGROUP TESTS ===== */
/* Create a new netgroup */
--
2.12.2

View File

@ -1,36 +0,0 @@
From 901396366075dc3e3fcc0894345af1b51052ac69 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Tue, 28 Mar 2017 14:49:31 +0200
Subject: [PATCH 72/97] SYSDB: Only generate new UID in local domain
To avoid issues where a user with no UID but without the posix=false
flag was passed to sysdb, we only allow generating the new ID in the
local domain. This might prevent bugs where non-POSIX users would get a
UID created by sysdb which might allow accessing resources owned by that
UID.
Reviewed-by: Sumit Bose <sbose@redhat.com>
---
src/db/sysdb_ops.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c
index 3cf9d903f25b9ccd506d7957c94040bdc7d658a3..4d7b2abd8026c90aaf4e7be687102e459cf3690e 100644
--- a/src/db/sysdb_ops.c
+++ b/src/db/sysdb_ops.c
@@ -1422,6 +1422,12 @@ int sysdb_get_new_id(struct sss_domain_info *domain,
return ENOMEM;
}
+ if (strcasecmp(domain->provider, "local") != 0) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Generating new ID is only supported in the local domain!\n");
+ return ENOTSUP;
+ }
+
base_dn = sysdb_domain_dn(tmp_ctx, domain);
if (!base_dn) {
talloc_zfree(tmp_ctx);
--
2.12.2

View File

@ -1,141 +0,0 @@
From ed0cdfcacc44e4e13e1524e254efa744610a87c2 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Wed, 22 Mar 2017 13:06:08 +0100
Subject: [PATCH 73/97] LDAP: save non-POSIX users in application domains
Related to:
https://pagure.io/SSSD/sssd/issue/3310
If a user being saved by the LDAP provider does not have a UID or GID
and the domain type is application, we save the user entry as non-POSIX.
Reviewed-by: Sumit Bose <sbose@redhat.com>
---
src/providers/ldap/sdap_async_users.c | 72 +++++++++++++++++++++++++++--------
1 file changed, 57 insertions(+), 15 deletions(-)
diff --git a/src/providers/ldap/sdap_async_users.c b/src/providers/ldap/sdap_async_users.c
index 3d957ab584865f74499bc732395388a78965fe5f..265cd7e4f7929c295d5bdcfbd781221b74601f13 100644
--- a/src/providers/ldap/sdap_async_users.c
+++ b/src/providers/ldap/sdap_async_users.c
@@ -112,6 +112,28 @@ done:
return ret;
}
+static errno_t sdap_set_non_posix_flag(struct sysdb_attrs *attrs,
+ const char *pkey)
+{
+ errno_t ret;
+
+ ret = sysdb_attrs_add_uint32(attrs, pkey, 0);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to add a zero ID to a non-posix object!\n");
+ return ret;
+ }
+
+ ret = sysdb_attrs_add_bool(attrs, SYSDB_POSIX, false);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Error: Failed to mark objects as non-posix!\n");
+ return ret;
+ }
+
+ return EOK;
+}
+
/* FIXME: support storing additional attributes */
int sdap_save_user(TALLOC_CTX *memctx,
struct sdap_options *opts,
@@ -130,8 +152,8 @@ int sdap_save_user(TALLOC_CTX *memctx,
const char *homedir;
const char *shell;
const char *orig_dn = NULL;
- uid_t uid;
- gid_t gid;
+ uid_t uid = 0;
+ gid_t gid = 0;
struct sysdb_attrs *user_attrs;
char *upn = NULL;
size_t i;
@@ -146,6 +168,7 @@ int sdap_save_user(TALLOC_CTX *memctx,
size_t c;
char *p1;
char *p2;
+ bool is_posix = true;
DEBUG(SSSDBG_TRACE_FUNC, "Save user\n");
@@ -295,19 +318,29 @@ int sdap_save_user(TALLOC_CTX *memctx,
ret = sysdb_attrs_get_uint32_t(attrs,
opts->user_map[SDAP_AT_USER_UID].sys_name,
&uid);
- if (ret != EOK) {
+ if (ret == ENOENT && dom->type == DOM_TYPE_APPLICATION) {
+ DEBUG(SSSDBG_TRACE_INTERNAL,
+ "Marking object as non-posix and setting ID=0!\n");
+ ret = sdap_set_non_posix_flag(user_attrs,
+ opts->user_map[SDAP_AT_USER_UID].sys_name);
+ if (ret != EOK) {
+ goto done;
+ }
+ is_posix = false;
+ } else if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
- "no uid provided for [%s] in domain [%s].\n",
+ "Cannot retrieve UID for [%s] in domain [%s].\n",
user_name, dom->name);
- ret = EINVAL;
+ ret = ERR_NO_POSIX;
goto done;
}
}
- /* check that the uid is valid for this domain */
- if (OUT_OF_ID_RANGE(uid, dom->id_min, dom->id_max)) {
- DEBUG(SSSDBG_OP_FAILURE,
- "User [%s] filtered out! (uid out of range)\n",
- user_name);
+
+ /* check that the uid is valid for this domain if the user is a POSIX one */
+ if (is_posix == true && OUT_OF_ID_RANGE(uid, dom->id_min, dom->id_max)) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "User [%s] filtered out! (uid out of range)\n",
+ user_name);
ret = EINVAL;
goto done;
}
@@ -349,17 +382,26 @@ int sdap_save_user(TALLOC_CTX *memctx,
ret = sysdb_attrs_get_uint32_t(attrs,
opts->user_map[SDAP_AT_USER_GID].sys_name,
&gid);
- if (ret != EOK) {
+ if (ret == ENOENT && dom->type == DOM_TYPE_APPLICATION) {
+ DEBUG(SSSDBG_TRACE_INTERNAL,
+ "Marking object as non-posix and setting ID=0!\n");
+ ret = sdap_set_non_posix_flag(attrs,
+ opts->user_map[SDAP_AT_USER_GID].sys_name);
+ if (ret != EOK) {
+ goto done;
+ }
+ is_posix = false;
+ } else if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
- "no gid provided for [%s] in domain [%s].\n",
- user_name, dom->name);
- ret = EINVAL;
+ "Cannot retrieve GID for [%s] in domain [%s].\n",
+ user_name, dom->name);
+ ret = ERR_NO_POSIX;
goto done;
}
}
/* check that the gid is valid for this domain */
- if (IS_SUBDOMAIN(dom) == false &&
+ if (is_posix == true && IS_SUBDOMAIN(dom) == false &&
OUT_OF_ID_RANGE(gid, dom->id_min, dom->id_max)) {
DEBUG(SSSDBG_CRIT_FAILURE,
"User [%s] filtered out! (primary gid out of range)\n",
--
2.12.2

View File

@ -1,254 +0,0 @@
From 3e39806177e1cd383743ff596cb96df44a6ce8c9 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Wed, 22 Mar 2017 13:06:14 +0100
Subject: [PATCH 74/97] LDAP: Relax search filters in application domains
Related to:
https://pagure.io/SSSD/sssd/issue/3310
If a request comes towards an application domain, we can drop the part
of the filter that asserts that the object has a valid UID/GID. Instead,
we just search by name.
Reviewed-by: Sumit Bose <sbose@redhat.com>
---
src/providers/ldap/ldap_id.c | 35 ++++++++++++++++++++++++----
src/providers/ldap/sdap_async_enum.c | 7 +++++-
src/providers/ldap/sdap_async_initgroups.c | 37 ++++++++++++++++++++++++------
3 files changed, 66 insertions(+), 13 deletions(-)
diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c
index 0bee0ca8d71abece6749fdb8393b9ceacb64417d..7400dc1f57e30cc6ae5f939ffa628a1e9dd47e06 100644
--- a/src/providers/ldap/ldap_id.c
+++ b/src/providers/ldap/ldap_id.c
@@ -56,6 +56,7 @@ struct users_get_state {
char *filter;
const char **attrs;
bool use_id_mapping;
+ bool non_posix;
int dp_error;
int sdap_ret;
@@ -114,6 +115,10 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx,
state->filter_value = filter_value;
state->filter_type = filter_type;
+ if (state->domain->type == DOM_TYPE_APPLICATION) {
+ state->non_posix = true;
+ }
+
state->use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping(
ctx->opts->idmap_ctx,
sdom->dom->name,
@@ -292,7 +297,13 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx,
}
}
- if (state->use_id_mapping || filter_type == BE_FILTER_SECID) {
+ if (state->non_posix) {
+ state->filter = talloc_asprintf(state,
+ "(&%s(objectclass=%s)(%s=*))",
+ user_filter,
+ ctx->opts->user_map[SDAP_OC_USER].name,
+ ctx->opts->user_map[SDAP_AT_USER_NAME].name);
+ } else if (state->use_id_mapping || filter_type == BE_FILTER_SECID) {
/* When mapping IDs or looking for SIDs, we don't want to limit
* ourselves to users with a UID value. But there must be a SID to map
* from.
@@ -304,7 +315,8 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx,
ctx->opts->user_map[SDAP_AT_USER_NAME].name,
ctx->opts->user_map[SDAP_AT_USER_OBJECTSID].name);
} else {
- /* When not ID-mapping, make sure there is a non-NULL UID */
+ /* When not ID-mapping or looking up POSIX users,
+ * make sure there is a non-NULL UID */
state->filter = talloc_asprintf(state,
"(&%s(objectclass=%s)(%s=*)(&(%s=*)(!(%s=0))))",
user_filter,
@@ -380,6 +392,7 @@ static void users_get_connect_done(struct tevent_req *subreq)
* have no idea about POSIX attributes support, run a one-time check
*/
if (state->use_id_mapping == false &&
+ state->non_posix == false &&
state->ctx->opts->schema_type == SDAP_SCHEMA_AD &&
state->ctx->srv_opts &&
state->ctx->srv_opts->posix_checked == false) {
@@ -650,6 +663,7 @@ struct groups_get_state {
char *filter;
const char **attrs;
bool use_id_mapping;
+ bool non_posix;
int dp_error;
int sdap_ret;
@@ -709,6 +723,10 @@ struct tevent_req *groups_get_send(TALLOC_CTX *memctx,
state->filter_value = filter_value;
state->filter_type = filter_type;
+ if (state->domain->type == DOM_TYPE_APPLICATION) {
+ state->non_posix = true;
+ }
+
state->use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping(
ctx->opts->idmap_ctx,
sdom->dom->name,
@@ -827,9 +845,11 @@ struct tevent_req *groups_get_send(TALLOC_CTX *memctx,
goto done;
}
- if (state->use_id_mapping || filter_type == BE_FILTER_SECID) {
- /* When mapping IDs or looking for SIDs, we don't want to limit
- * ourselves to groups with a GID value
+ if (state->non_posix
+ || state->use_id_mapping
+ || filter_type == BE_FILTER_SECID) {
+ /* When mapping IDs or looking for SIDs, or when in a non-POSIX domain,
+ * we don't want to limit ourselves to groups with a GID value
*/
state->filter = talloc_asprintf(state,
@@ -1123,6 +1143,7 @@ struct groups_by_user_state {
int filter_type;
const char *extra_value;
const char **attrs;
+ bool non_posix;
int dp_error;
int sdap_ret;
@@ -1204,6 +1225,10 @@ static struct tevent_req *groups_by_user_send(TALLOC_CTX *memctx,
state->domain = sdom->dom;
state->sysdb = sdom->dom->sysdb;
+ if (state->domain->type == DOM_TYPE_APPLICATION) {
+ state->non_posix = true;
+ }
+
ret = build_attrs_from_map(state, ctx->opts->group_map, SDAP_OPTS_GROUP,
NULL, &state->attrs, NULL);
if (ret != EOK) goto fail;
diff --git a/src/providers/ldap/sdap_async_enum.c b/src/providers/ldap/sdap_async_enum.c
index 3f65059e18d5c8b548da0babec867d27c3a64198..91e481c4e694126900c729e86d187fba355de0b8 100644
--- a/src/providers/ldap/sdap_async_enum.c
+++ b/src/providers/ldap/sdap_async_enum.c
@@ -717,6 +717,7 @@ static struct tevent_req *enum_groups_send(TALLOC_CTX *memctx,
struct enum_groups_state *state;
int ret;
bool use_mapping;
+ bool non_posix = false;
char *oc_list;
req = tevent_req_create(memctx, &state, struct enum_groups_state);
@@ -727,6 +728,10 @@ static struct tevent_req *enum_groups_send(TALLOC_CTX *memctx,
state->ctx = ctx;
state->op = op;
+ if (sdom->dom->type == DOM_TYPE_APPLICATION) {
+ non_posix = true;
+ }
+
use_mapping = sdap_idmap_domain_has_algorithmic_mapping(
ctx->opts->idmap_ctx,
sdom->dom->name,
@@ -749,7 +754,7 @@ static struct tevent_req *enum_groups_send(TALLOC_CTX *memctx,
goto fail;
}
- if (use_mapping) {
+ if (!non_posix && use_mapping) {
/* If we're ID-mapping, check for the objectSID as well */
state->filter = talloc_asprintf_append_buffer(
state->filter, "(%s=*)",
diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c
index 79af7a3eda3fe8533933535c98c2b4b4698dfda2..c926ddcbefe471daa80505e139c3f19efa33b9ba 100644
--- a/src/providers/ldap/sdap_async_initgroups.c
+++ b/src/providers/ldap/sdap_async_initgroups.c
@@ -376,7 +376,7 @@ struct sdap_initgr_rfc2307_state {
struct sdap_handle *sh;
const char **attrs;
const char *name;
- const char *base_filter;
+ char *base_filter;
const char *orig_dn;
char *filter;
int timeout;
@@ -473,18 +473,32 @@ struct tevent_req *sdap_initgr_rfc2307_send(TALLOC_CTX *memctx,
}
state->base_filter = talloc_asprintf(state,
- "(&(%s=%s)(%s)(%s=*)(&(%s=*)(!(%s=0))))",
+ "(&(%s=%s)(%s)(%s=*)",
opts->group_map[SDAP_AT_GROUP_MEMBER].name,
clean_name, oc_list,
- opts->group_map[SDAP_AT_GROUP_NAME].name,
- opts->group_map[SDAP_AT_GROUP_GID].name,
- opts->group_map[SDAP_AT_GROUP_GID].name);
+ opts->group_map[SDAP_AT_GROUP_NAME].name);
if (!state->base_filter) {
talloc_zfree(req);
return NULL;
}
talloc_zfree(clean_name);
+ switch (domain->type) {
+ case DOM_TYPE_APPLICATION:
+ state->base_filter = talloc_asprintf_append(state->base_filter, ")");
+ break;
+ case DOM_TYPE_POSIX:
+ state->base_filter = talloc_asprintf_append(state->base_filter,
+ "(&(%s=*)(!(%s=0))))",
+ opts->group_map[SDAP_AT_GROUP_GID].name,
+ opts->group_map[SDAP_AT_GROUP_GID].name);
+ break;
+ }
+ if (!state->base_filter) {
+ ret = ENOMEM;
+ goto done;
+ }
+
ret = sdap_initgr_rfc2307_next_base(req);
done:
@@ -2666,6 +2680,7 @@ struct sdap_get_initgr_state {
char *shortname;
char *filter;
int timeout;
+ bool non_posix;
struct sysdb_attrs *orig_user;
@@ -2724,6 +2739,10 @@ struct tevent_req *sdap_get_initgr_send(TALLOC_CTX *memctx,
goto done;
}
+ if (state->dom->type == DOM_TYPE_APPLICATION) {
+ state->non_posix = true;
+ }
+
use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping(
id_ctx->opts->idmap_ctx,
sdom->dom->name,
@@ -2813,7 +2832,10 @@ struct tevent_req *sdap_get_initgr_send(TALLOC_CTX *memctx,
}
}
- if (use_id_mapping) {
+ if (state->non_posix) {
+ state->user_base_filter = talloc_asprintf_append(state->user_base_filter,
+ ")");
+ } else if (use_id_mapping) {
/* When mapping IDs or looking for SIDs, we don't want to limit
* ourselves to users with a UID value. But there must be a SID to map
* from.
@@ -2822,7 +2844,8 @@ struct tevent_req *sdap_get_initgr_send(TALLOC_CTX *memctx,
"(%s=*))",
id_ctx->opts->user_map[SDAP_AT_USER_OBJECTSID].name);
} else {
- /* When not ID-mapping, make sure there is a non-NULL UID */
+ /* When not ID-mapping or looking up app users, make sure there
+ * is a non-NULL UID */
state->user_base_filter = talloc_asprintf_append(state->user_base_filter,
"(&(%s=*)(!(%s=0))))",
id_ctx->opts->user_map[SDAP_AT_USER_UID].name,
--
2.12.2

View File

@ -1,353 +0,0 @@
From 861ab44e8148208425b67c4711bc8fade10fd3ed Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Wed, 22 Mar 2017 13:01:18 +0100
Subject: [PATCH 75/97] KRB5: Authenticate users in a non-POSIX domain using a
MEMORY ccache
Related to:
https://pagure.io/SSSD/sssd/issue/3310
The following changes were done to the Kerberos authentication code
in order to support authentication in a non-POSIX environment:
- delayed authentication is disabled in non-POSIX domains
- when a user logs in in a non-POSIX domain, SSSD uses a
MEMORY:$username ccache and destroys is then krb5_child finishes
so that just the numeric result is used
- krb5_child doesn't drop privileges in this configuration because
there is nothing to drop privileges to
Reviewed-by: Sumit Bose <sbose@redhat.com>
---
src/providers/krb5/krb5_auth.c | 62 ++++++++++++++++------
src/providers/krb5/krb5_auth.h | 2 +
src/providers/krb5/krb5_child.c | 32 +++++++++--
src/providers/krb5/krb5_child_handler.c | 15 +++++-
.../krb5/krb5_delayed_online_authentication.c | 7 +++
src/providers/krb5/krb5_init.c | 3 ++
6 files changed, 99 insertions(+), 22 deletions(-)
diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c
index c2d6d7eeacc1f766024c4d629f25fd0f0be24e5e..2faf18d17a735476c20f9cc27b15be4a39cadc5c 100644
--- a/src/providers/krb5/krb5_auth.c
+++ b/src/providers/krb5/krb5_auth.c
@@ -42,6 +42,8 @@
#include "providers/krb5/krb5_utils.h"
#include "providers/krb5/krb5_ccache.h"
+#define NON_POSIX_CCNAME_FMT "MEMORY:sssd_nonposix_dummy_%u"
+
static int krb5_mod_ccname(TALLOC_CTX *mem_ctx,
struct sysdb_ctx *sysdb,
struct sss_domain_info *domain,
@@ -200,6 +202,7 @@ errno_t krb5_setup(TALLOC_CTX *mem_ctx,
talloc_set_destructor((TALLOC_CTX *) kr, krb5_cleanup);
kr->pd = pd;
+ kr->dom = dom;
kr->krb5_ctx = krb5_ctx;
ret = get_krb_primary(krb5_ctx->name_to_primary,
@@ -275,8 +278,11 @@ static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx,
return;
}
- ret = add_user_to_delayed_online_authentication(krb5_ctx, pd, uid);
- if (ret != EOK) {
+ ret = add_user_to_delayed_online_authentication(krb5_ctx, domain, pd, uid);
+ if (ret == ENOTSUP) {
+ /* This error is not fatal */
+ DEBUG(SSSDBG_MINOR_FAILURE, "Delayed authentication not supported\n");
+ } else if (ret != EOK) {
/* This error is not fatal */
DEBUG(SSSDBG_CRIT_FAILURE,
"add_user_to_delayed_online_authentication failed.\n");
@@ -291,21 +297,43 @@ static errno_t krb5_auth_prepare_ccache_name(struct krb5child_req *kr,
{
const char *ccname_template;
- ccname_template = dp_opt_get_cstring(kr->krb5_ctx->opts, KRB5_CCNAME_TMPL);
+ switch (kr->dom->type) {
+ case DOM_TYPE_POSIX:
+ ccname_template = dp_opt_get_cstring(kr->krb5_ctx->opts, KRB5_CCNAME_TMPL);
- kr->ccname = expand_ccname_template(kr, kr, ccname_template,
- kr->krb5_ctx->illegal_path_re, true,
- be_ctx->domain->case_sensitive);
- if (kr->ccname == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "expand_ccname_template failed.\n");
- return ENOMEM;
- }
+ kr->ccname = expand_ccname_template(kr, kr, ccname_template,
+ kr->krb5_ctx->illegal_path_re, true,
+ be_ctx->domain->case_sensitive);
+ if (kr->ccname == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "expand_ccname_template failed.\n");
+ return ENOMEM;
+ }
- kr->old_ccname = ldb_msg_find_attr_as_string(user_msg,
- SYSDB_CCACHE_FILE, NULL);
- if (kr->old_ccname == NULL) {
- DEBUG(SSSDBG_TRACE_LIBS,
- "No ccache file for user [%s] found.\n", kr->pd->user);
+ kr->old_ccname = ldb_msg_find_attr_as_string(user_msg,
+ SYSDB_CCACHE_FILE, NULL);
+ if (kr->old_ccname == NULL) {
+ DEBUG(SSSDBG_TRACE_LIBS,
+ "No ccache file for user [%s] found.\n", kr->pd->user);
+ }
+ break;
+ case DOM_TYPE_APPLICATION:
+ DEBUG(SSSDBG_TRACE_FUNC,
+ "Domain type application, will use in-memory ccache\n");
+ /* We don't care about using cryptographic randomness, just
+ * a non-predictable ccname, so using rand() here is fine
+ */
+ kr->ccname = talloc_asprintf(kr,
+ NON_POSIX_CCNAME_FMT,
+ rand() % UINT_MAX);
+ if (kr->ccname == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed.\n");
+ return ENOMEM;
+ }
+
+ break;
+ default:
+ DEBUG(SSSDBG_FATAL_FAILURE, "Unsupported domain type\n");
+ return EINVAL;
}
return EOK;
@@ -617,7 +645,7 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx,
kr->uid = sss_view_ldb_msg_find_attr_as_uint64(state->domain,
res->msgs[0],
SYSDB_UIDNUM, 0);
- if (kr->uid == 0) {
+ if (kr->uid == 0 && state->domain->type == DOM_TYPE_POSIX) {
DEBUG(SSSDBG_CONF_SETTINGS,
"UID for user [%s] not known.\n", pd->user);
ret = ENOENT;
@@ -627,7 +655,7 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx,
kr->gid = sss_view_ldb_msg_find_attr_as_uint64(state->domain,
res->msgs[0],
SYSDB_GIDNUM, 0);
- if (kr->gid == 0) {
+ if (kr->gid == 0 && state->domain->type == DOM_TYPE_POSIX) {
DEBUG(SSSDBG_CONF_SETTINGS,
"GID for user [%s] not known.\n", pd->user);
ret = ENOENT;
diff --git a/src/providers/krb5/krb5_auth.h b/src/providers/krb5/krb5_auth.h
index 75ad916e79b29043120543ab3c4c1bd27e09d913..8ad3aeff21e58f9055ae144eaa450992c6391ba6 100644
--- a/src/providers/krb5/krb5_auth.h
+++ b/src/providers/krb5/krb5_auth.h
@@ -50,6 +50,7 @@
struct krb5child_req {
struct pam_data *pd;
struct krb5_ctx *krb5_ctx;
+ struct sss_domain_info *dom;
const char *ccname;
const char *old_ccname;
@@ -118,6 +119,7 @@ parse_krb5_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf, ssize_t len,
struct krb5_child_response **_res);
errno_t add_user_to_delayed_online_authentication(struct krb5_ctx *krb5_ctx,
+ struct sss_domain_info *domain,
struct pam_data *pd,
uid_t uid);
errno_t init_delayed_online_authentication(struct krb5_ctx *krb5_ctx,
diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c
index a4128dda6b0861a95dba223047d66c4158b1afb6..cbbc892bee0365892ac66d3654c974d325166b60 100644
--- a/src/providers/krb5/krb5_child.c
+++ b/src/providers/krb5/krb5_child.c
@@ -80,6 +80,7 @@ struct krb5_req {
char *ccname;
char *keytab;
bool validate;
+ bool posix_domain;
bool send_pac;
bool use_enterprise_princ;
char *fast_ccname;
@@ -102,6 +103,16 @@ struct krb5_req {
static krb5_context krb5_error_ctx;
#define KRB5_CHILD_DEBUG(level, error) KRB5_DEBUG(level, krb5_error_ctx, error)
+static errno_t k5c_become_user(uid_t uid, gid_t gid, bool is_posix)
+{
+ if (is_posix == false) {
+ DEBUG(SSSDBG_TRACE_FUNC,
+ "Will not drop privileges for a non-POSIX user\n");
+ return EOK;
+ }
+ return become_user(uid, gid);
+}
+
static krb5_error_code set_lifetime_options(struct cli_opts *cli_opts,
krb5_get_init_creds_opt *options)
{
@@ -1561,6 +1572,15 @@ static krb5_error_code get_and_save_tgt(struct krb5_req *kr,
DEBUG(SSSDBG_CONF_SETTINGS, "TGT validation is disabled.\n");
}
+ /* In a non-POSIX environment, we only care about the return code from
+ * krb5_child, so let's not even attempt to create the ccache
+ */
+ if (kr->posix_domain == false) {
+ DEBUG(SSSDBG_TRACE_LIBS,
+ "Finished authentication in a non-POSIX domain\n");
+ goto done;
+ }
+
/* If kr->ccname is cache collection (DIR:/...), we want to work
* directly with file ccache (DIR::/...), but cache collection
* should be returned back to back end.
@@ -2146,6 +2166,7 @@ static errno_t unpack_buffer(uint8_t *buf, size_t size,
size_t p = 0;
uint32_t len;
uint32_t validate;
+ uint32_t posix_domain;
uint32_t send_pac;
uint32_t use_enterprise_princ;
struct pam_data *pd;
@@ -2167,6 +2188,8 @@ static errno_t unpack_buffer(uint8_t *buf, size_t size,
SAFEALIGN_COPY_UINT32_CHECK(&kr->gid, buf + p, size, &p);
SAFEALIGN_COPY_UINT32_CHECK(&validate, buf + p, size, &p);
kr->validate = (validate == 0) ? false : true;
+ SAFEALIGN_COPY_UINT32_CHECK(&posix_domain, buf + p, size, &p);
+ kr->posix_domain = (posix_domain == 0) ? false : true;
SAFEALIGN_COPY_UINT32_CHECK(offline, buf + p, size, &p);
SAFEALIGN_COPY_UINT32_CHECK(&send_pac, buf + p, size, &p);
kr->send_pac = (send_pac == 0) ? false : true;
@@ -2331,6 +2354,7 @@ static krb5_error_code check_fast_ccache(TALLOC_CTX *mem_ctx,
krb5_context ctx,
uid_t fast_uid,
gid_t fast_gid,
+ bool posix_domain,
struct cli_opts *cli_opts,
const char *primary,
const char *realm,
@@ -2420,7 +2444,7 @@ static krb5_error_code check_fast_ccache(TALLOC_CTX *mem_ctx,
/* Try to carry on */
}
- kerr = become_user(fast_uid, fast_gid);
+ kerr = k5c_become_user(fast_uid, fast_gid, posix_domain);
if (kerr != 0) {
DEBUG(SSSDBG_CRIT_FAILURE, "become_user failed: %d\n", kerr);
exit(1);
@@ -2572,7 +2596,7 @@ static int k5c_setup_fast(struct krb5_req *kr, bool demand)
}
kerr = check_fast_ccache(kr, kr->ctx, kr->fast_uid, kr->fast_gid,
- kr->cli_opts,
+ kr->posix_domain, kr->cli_opts,
fast_principal, fast_principal_realm,
kr->keytab, &kr->fast_ccname);
if (kerr != 0) {
@@ -2773,7 +2797,7 @@ static int k5c_setup(struct krb5_req *kr, uint32_t offline)
* the user who is logging in. The same applies to the offline case
* the user who is logging in. The same applies to the offline case.
*/
- kerr = become_user(kr->uid, kr->gid);
+ kerr = k5c_become_user(kr->uid, kr->gid, kr->posix_domain);
if (kerr != 0) {
DEBUG(SSSDBG_CRIT_FAILURE, "become_user failed.\n");
return kerr;
@@ -3075,7 +3099,7 @@ int main(int argc, const char *argv[])
if ((sss_authtok_get_type(kr->pd->authtok) != SSS_AUTHTOK_TYPE_SC_PIN
&& sss_authtok_get_type(kr->pd->authtok)
!= SSS_AUTHTOK_TYPE_SC_KEYPAD)) {
- kerr = become_user(kr->uid, kr->gid);
+ kerr = k5c_become_user(kr->uid, kr->gid, kr->posix_domain);
if (kerr != 0) {
DEBUG(SSSDBG_CRIT_FAILURE, "become_user failed.\n");
ret = EFAULT;
diff --git a/src/providers/krb5/krb5_child_handler.c b/src/providers/krb5/krb5_child_handler.c
index 680e67b089fcb32280352af24aae35af133a52f3..87e79a06e917aadb622455bccfc2e9c6769f70c2 100644
--- a/src/providers/krb5/krb5_child_handler.c
+++ b/src/providers/krb5/krb5_child_handler.c
@@ -107,6 +107,7 @@ static errno_t create_send_buffer(struct krb5child_req *kr,
uint32_t validate;
uint32_t send_pac;
uint32_t use_enterprise_principal;
+ uint32_t posix_domain;
size_t username_len = 0;
errno_t ret;
@@ -131,6 +132,17 @@ static errno_t create_send_buffer(struct krb5child_req *kr,
break;
}
+ switch (kr->dom->type) {
+ case DOM_TYPE_POSIX:
+ posix_domain = 1;
+ break;
+ case DOM_TYPE_APPLICATION:
+ posix_domain = 0;
+ break;
+ default:
+ return EINVAL;
+ }
+
if (kr->pd->cmd == SSS_CMD_RENEW || kr->is_offline) {
use_enterprise_principal = false;
} else {
@@ -151,7 +163,7 @@ static errno_t create_send_buffer(struct krb5child_req *kr,
kr->pd->cmd == SSS_CMD_RENEW ||
kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM ||
kr->pd->cmd == SSS_PAM_CHAUTHTOK) {
- buf->size += 4*sizeof(uint32_t) + strlen(kr->ccname) + strlen(keytab) +
+ buf->size += 5*sizeof(uint32_t) + strlen(kr->ccname) + strlen(keytab) +
sss_authtok_get_size(kr->pd->authtok);
buf->size += sizeof(uint32_t);
@@ -182,6 +194,7 @@ static errno_t create_send_buffer(struct krb5child_req *kr,
SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->uid, &rp);
SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->gid, &rp);
SAFEALIGN_COPY_UINT32(&buf->data[rp], &validate, &rp);
+ SAFEALIGN_COPY_UINT32(&buf->data[rp], &posix_domain, &rp);
SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->is_offline, &rp);
SAFEALIGN_COPY_UINT32(&buf->data[rp], &send_pac, &rp);
SAFEALIGN_COPY_UINT32(&buf->data[rp], &use_enterprise_principal, &rp);
diff --git a/src/providers/krb5/krb5_delayed_online_authentication.c b/src/providers/krb5/krb5_delayed_online_authentication.c
index bf2ef775573ba6bad79a99ad43b5d9748516e794..1cb7eade0e4cb9afbc4d031a07b3519ba08456d6 100644
--- a/src/providers/krb5/krb5_delayed_online_authentication.c
+++ b/src/providers/krb5/krb5_delayed_online_authentication.c
@@ -234,6 +234,7 @@ static void delayed_online_authentication_callback(void *private_data)
}
errno_t add_user_to_delayed_online_authentication(struct krb5_ctx *krb5_ctx,
+ struct sss_domain_info *domain,
struct pam_data *pd,
uid_t uid)
{
@@ -242,6 +243,12 @@ errno_t add_user_to_delayed_online_authentication(struct krb5_ctx *krb5_ctx,
hash_value_t value;
struct pam_data *new_pd;
+ if (domain->type != DOM_TYPE_POSIX) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "Domain type does not support delayed authentication\n");
+ return ENOTSUP;
+ }
+
if (krb5_ctx->deferred_auth_ctx == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE,
"Missing context for delayed online authentication.\n");
diff --git a/src/providers/krb5/krb5_init.c b/src/providers/krb5/krb5_init.c
index 12c8dfcc49af75de619ec0858aaff81504698273..66ae68fb4773af3987f2062246bc6493107c74d5 100644
--- a/src/providers/krb5/krb5_init.c
+++ b/src/providers/krb5/krb5_init.c
@@ -136,6 +136,9 @@ errno_t sssm_krb5_init(TALLOC_CTX *mem_ctx,
return ENOMEM;
}
+ /* Only needed to generate random ccache names for non-POSIX domains */
+ srand(time(NULL) * getpid());
+
ret = sss_krb5_get_options(ctx, be_ctx->cdb, be_ctx->conf_path, &ctx->opts);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get krb5 options [%d]: %s\n",
--
2.12.2

View File

@ -1,210 +0,0 @@
From 7d73049884e3a96ca3b00b5bd4104f4edd6287ab Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Wed, 29 Mar 2017 22:49:09 +0200
Subject: [PATCH 76/97] KCM: Fix off-by-one error in secrets key parsing
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
When parsing the secrets key, the code tried to protect against malformed keys
or keys that are too short, but it did an error - the UUID stringified
form is 36 bytes long, so the UUID_STR_SIZE is 37 because UUID_STR_SIZE
accounts for the null terminator.
But the code, that was trying to assert that there are two characters after
the UUID string (separator and at least a single character for the name)
didn't take the NULL terminator (which strlen() doesn't return) into
account and ended up rejecting all ccaches whose name is only a single
character.
Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
---
src/responder/kcm/kcmsrv_ccache_json.c | 43 +++++++++-------
src/tests/cmocka/test_kcm_json_marshalling.c | 75 ++++++++++++++++++++++++++++
2 files changed, 101 insertions(+), 17 deletions(-)
diff --git a/src/responder/kcm/kcmsrv_ccache_json.c b/src/responder/kcm/kcmsrv_ccache_json.c
index 40b64861c209206d6f60ccd0843857edee24a844..8199bc613e4204859438e1cd820f3f4b2123dd7e 100644
--- a/src/responder/kcm/kcmsrv_ccache_json.c
+++ b/src/responder/kcm/kcmsrv_ccache_json.c
@@ -109,6 +109,28 @@ static const char *sec_key_create(TALLOC_CTX *mem_ctx,
"%s%c%s", uuid_str, SEC_KEY_SEPARATOR, name);
}
+static bool sec_key_valid(const char *sec_key)
+{
+ if (sec_key == NULL) {
+ return false;
+ }
+
+ if (strlen(sec_key) < UUID_STR_SIZE + 1) {
+ /* One char for separator (at UUID_STR_SIZE, because strlen doesn't
+ * include the '\0', but UUID_STR_SIZE does) and at least one for
+ * the name */
+ DEBUG(SSSDBG_CRIT_FAILURE, "Key %s is too short\n", sec_key);
+ return false;
+ }
+
+ if (sec_key[UUID_STR_SIZE - 1] != SEC_KEY_SEPARATOR) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Key doesn't contain the separator\n");
+ return false;
+ }
+
+ return true;
+}
+
static errno_t sec_key_parse(TALLOC_CTX *mem_ctx,
const char *sec_key,
const char **_name,
@@ -116,9 +138,7 @@ static errno_t sec_key_parse(TALLOC_CTX *mem_ctx,
{
char uuid_str[UUID_STR_SIZE];
- if (strlen(sec_key) < UUID_STR_SIZE + 2) {
- /* One char for separator and at least one for the name */
- DEBUG(SSSDBG_CRIT_FAILURE, "Key %s is too short\n", sec_key);
+ if (!sec_key_valid(sec_key)) {
return EINVAL;
}
@@ -143,14 +163,7 @@ errno_t sec_key_get_uuid(const char *sec_key,
{
char uuid_str[UUID_STR_SIZE];
- if (strlen(sec_key) < UUID_STR_SIZE + 2) {
- /* One char for separator and at least one for the name */
- DEBUG(SSSDBG_CRIT_FAILURE, "Key %s is too short\n", sec_key);
- return EINVAL;
- }
-
- if (sec_key[UUID_STR_SIZE-1] != SEC_KEY_SEPARATOR) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Key doesn't contain the separator\n");
+ if (!sec_key_valid(sec_key)) {
return EINVAL;
}
@@ -162,9 +175,7 @@ errno_t sec_key_get_uuid(const char *sec_key,
const char *sec_key_get_name(const char *sec_key)
{
- if (strlen(sec_key) < UUID_STR_SIZE + 2) {
- /* One char for separator and at least one for the name */
- DEBUG(SSSDBG_CRIT_FAILURE, "Key %s is too short\n", sec_key);
+ if (!sec_key_valid(sec_key)) {
return NULL;
}
@@ -174,9 +185,7 @@ const char *sec_key_get_name(const char *sec_key)
bool sec_key_match_name(const char *sec_key,
const char *name)
{
- if (strlen(sec_key) < UUID_STR_SIZE + 2) {
- /* One char for separator and at least one for the name */
- DEBUG(SSSDBG_MINOR_FAILURE, "Key %s is too short\n", sec_key);
+ if (!sec_key_valid(sec_key) || name == NULL) {
return false;
}
diff --git a/src/tests/cmocka/test_kcm_json_marshalling.c b/src/tests/cmocka/test_kcm_json_marshalling.c
index 8eff2f501066c70a8730cd3d4dc41b92d7a03e4c..108eaf55628029a6de8c23cd6486bdccc42c0364 100644
--- a/src/tests/cmocka/test_kcm_json_marshalling.c
+++ b/src/tests/cmocka/test_kcm_json_marshalling.c
@@ -32,6 +32,12 @@
#define TEST_CREDS "TESTCREDS"
+#define TEST_UUID_STR "5f8f296b-02be-4e86-9235-500e82354186"
+#define TEST_SEC_KEY_ONEDIGIT TEST_UUID_STR"-0"
+#define TEST_SEC_KEY_MULTIDIGITS TEST_UUID_STR"-123456"
+
+#define TEST_SEC_KEY_NOSEP TEST_UUID_STR"+0"
+
const struct kcm_ccdb_ops ccdb_mem_ops;
const struct kcm_ccdb_ops ccdb_sec_ops;
@@ -188,6 +194,72 @@ static void test_kcm_ccache_marshall_unmarshall(void **state)
assert_int_equal(ret, EOK);
assert_cc_equal(cc, cc2);
+
+ /* This key is exactly one byte shorter than it should be */
+ ret = sec_kv_to_ccache(test_ctx,
+ TEST_UUID_STR"-",
+ (const char *) data,
+ &owner,
+ &cc2);
+ assert_int_equal(ret, EINVAL);
+}
+
+void test_sec_key_get_uuid(void **state)
+{
+ errno_t ret;
+ uuid_t uuid;
+ char str_uuid[UUID_STR_SIZE];
+
+ uuid_clear(uuid);
+ ret = sec_key_get_uuid(TEST_SEC_KEY_ONEDIGIT, uuid);
+ assert_int_equal(ret, EOK);
+ uuid_unparse(uuid, str_uuid);
+ assert_string_equal(TEST_UUID_STR, str_uuid);
+
+ ret = sec_key_get_uuid(TEST_SEC_KEY_NOSEP, uuid);
+ assert_int_equal(ret, EINVAL);
+
+ ret = sec_key_get_uuid(TEST_UUID_STR, uuid);
+ assert_int_equal(ret, EINVAL);
+
+ ret = sec_key_get_uuid(NULL, uuid);
+ assert_int_equal(ret, EINVAL);
+}
+
+void test_sec_key_get_name(void **state)
+{
+ const char *name;
+
+ name = sec_key_get_name(TEST_SEC_KEY_ONEDIGIT);
+ assert_non_null(name);
+ assert_string_equal(name, "0");
+
+ name = sec_key_get_name(TEST_SEC_KEY_MULTIDIGITS);
+ assert_non_null(name);
+ assert_string_equal(name, "123456");
+
+ name = sec_key_get_name(TEST_UUID_STR);
+ assert_null(name);
+
+ name = sec_key_get_name(TEST_SEC_KEY_NOSEP);
+ assert_null(name);
+
+ name = sec_key_get_name(NULL);
+ assert_null(name);
+}
+
+void test_sec_key_match_name(void **state)
+{
+ assert_true(sec_key_match_name(TEST_SEC_KEY_ONEDIGIT, "0"));
+ assert_true(sec_key_match_name(TEST_SEC_KEY_MULTIDIGITS, "123456"));
+
+ assert_false(sec_key_match_name(TEST_SEC_KEY_MULTIDIGITS, "0"));
+ assert_false(sec_key_match_name(TEST_SEC_KEY_ONEDIGIT, "123456"));
+
+ assert_false(sec_key_match_name(TEST_UUID_STR, "0"));
+ assert_false(sec_key_match_name(TEST_SEC_KEY_NOSEP, "0"));
+ assert_false(sec_key_match_name(TEST_SEC_KEY_ONEDIGIT, NULL));
+ assert_false(sec_key_match_name(NULL, "0"));
}
int main(int argc, const char *argv[])
@@ -205,6 +277,9 @@ int main(int argc, const char *argv[])
cmocka_unit_test_setup_teardown(test_kcm_ccache_marshall_unmarshall,
setup_kcm_marshalling,
teardown_kcm_marshalling),
+ cmocka_unit_test(test_sec_key_get_uuid),
+ cmocka_unit_test(test_sec_key_get_name),
+ cmocka_unit_test(test_sec_key_match_name),
};
/* Set debug level to invalid value so we can deside if -d 0 was used. */
--
2.12.2

File diff suppressed because it is too large Load Diff

View File

@ -1,437 +0,0 @@
From b800a6d09244359959404aca81c6796a58cafbcb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Fri, 24 Feb 2017 12:23:01 +0100
Subject: [PATCH 78/97] tcurl test: refactor so new options can be added more
easily
Just to make the tool a little bit nicer and more flexible.
Reviewed-by: Simo Sorce <simo@redhat.com>
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
---
src/tests/tcurl_test_tool.c | 334 +++++++++++++++++++++++++++-----------------
1 file changed, 209 insertions(+), 125 deletions(-)
diff --git a/src/tests/tcurl_test_tool.c b/src/tests/tcurl_test_tool.c
index 9a6266f89131ffd3a561e857af85df9854c44949..e5fc9705db415650d849b89c3d18e41574b7e28b 100644
--- a/src/tests/tcurl_test_tool.c
+++ b/src/tests/tcurl_test_tool.c
@@ -28,26 +28,39 @@
struct tool_ctx {
bool verbose;
-
- errno_t error;
bool done;
size_t nreqs;
};
+struct tool_options {
+ int debug;
+ int verbose;
+
+ enum tcurl_http_method method;
+ const char *socket_path;
+};
+
static void request_done(struct tevent_req *req)
{
- int http_code;
+ struct tool_ctx *tool_ctx;
struct sss_iobuf *outbuf;
- struct tool_ctx *tool_ctx = tevent_req_callback_data(req,
- struct tool_ctx);
+ int http_code;
+ errno_t ret;
- tool_ctx->error = tcurl_request_recv(tool_ctx, req, &outbuf, &http_code);
+ tool_ctx = tevent_req_callback_data(req, struct tool_ctx);
+
+ ret = tcurl_request_recv(tool_ctx, req, &outbuf, &http_code);
talloc_zfree(req);
- if (tool_ctx->error != EOK) {
- DEBUG(SSSDBG_FATAL_FAILURE, "HTTP request failed: %d\n", tool_ctx->error);
+ tool_ctx->nreqs--;
+ if (tool_ctx->nreqs == 0) {
tool_ctx->done = true;
+ }
+
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "HTTP request failed [%d]: %s\n",
+ ret, sss_strerror(ret));
return;
} else if (tool_ctx->verbose) {
printf("Request HTTP code: %d\n", http_code);
@@ -55,167 +68,171 @@ static void request_done(struct tevent_req *req)
(const char *) sss_iobuf_get_data(outbuf));
talloc_zfree(outbuf);
}
-
- tool_ctx->nreqs--;
- if (tool_ctx->nreqs == 0) {
- tool_ctx->done = true;
- }
}
-int main(int argc, const char *argv[])
+static errno_t
+parse_options(poptContext pc, struct tool_options *opts)
{
int opt;
- poptContext pc;
-
- int pc_debug = 0;
- int pc_verbose = 0;
- const char *socket_path = NULL;
- const char *extra_arg_ptr;
-
- static const char *headers[] = {
- "Content-type: application/octet-stream",
- NULL,
- };
-
- struct poptOption long_options[] = {
- POPT_AUTOHELP
- { "debug", '\0', POPT_ARG_INT, &pc_debug, 0,
- "The debug level to run with", NULL },
- { "socket-path", 's', POPT_ARG_STRING, &socket_path, 0,
- "The path to the HTTP server socket", NULL },
- { "get", 'g', POPT_ARG_NONE, NULL, 'g', "Perform a HTTP GET (default)", NULL },
- { "put", 'p', POPT_ARG_NONE, NULL, 'p', "Perform a HTTP PUT", NULL },
- { "post", 'o', POPT_ARG_NONE, NULL, 'o', "Perform a HTTP POST", NULL },
- { "del", 'd', POPT_ARG_NONE, NULL, 'd', "Perform a HTTP DELETE", NULL },
- { "verbose", 'v', POPT_ARG_NONE, NULL, 'v', "Print response code and body", NULL },
- POPT_TABLEEND
- };
-
- struct tevent_req *req;
- struct tevent_context *ev;
- enum tcurl_http_method method = TCURL_HTTP_GET;
- struct tcurl_ctx *ctx;
- struct tcurl_request *tcurl_req;
- struct tool_ctx *tool_ctx;
-
- const char *urls[MAXREQ] = { 0 };
- struct sss_iobuf **inbufs;
-
- size_t n_reqs = 0;
-
- debug_prg_name = argv[0];
- pc = poptGetContext(NULL, argc, argv, long_options, 0);
- poptSetOtherOptionHelp(pc, "HTTPDATA");
while ((opt = poptGetNextOpt(pc)) > 0) {
switch (opt) {
case 'g':
- method = TCURL_HTTP_GET;
+ opts->method = TCURL_HTTP_GET;
break;
case 'p':
- method = TCURL_HTTP_PUT;
+ opts->method = TCURL_HTTP_PUT;
break;
case 'o':
- method = TCURL_HTTP_POST;
+ opts->method = TCURL_HTTP_POST;
break;
case 'd':
- method = TCURL_HTTP_DELETE;
- break;
- case 'v':
- pc_verbose = 1;
+ opts->method = TCURL_HTTP_DELETE;
break;
default:
DEBUG(SSSDBG_FATAL_FAILURE, "Unexpected option\n");
- return 1;
+ return EINVAL;
}
}
- DEBUG_CLI_INIT(pc_debug);
-
- tool_ctx = talloc_zero(NULL, struct tool_ctx);
- if (tool_ctx == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Could not init tool context\n");
- return 1;
+ if (opt != -1) {
+ poptPrintUsage(pc, stderr, 0);
+ fprintf(stderr, "%s", poptStrerror(opt));
+ return EINVAL;
}
- inbufs = talloc_zero_array(tool_ctx, struct sss_iobuf *, MAXREQ);
- if (inbufs == NULL) {
- talloc_zfree(tool_ctx);
- return 1;
+ return EOK;
+}
+
+static errno_t
+prepare_requests(TALLOC_CTX *mem_ctx,
+ poptContext pc,
+ struct tool_options *opts,
+ struct tcurl_request ***_requests,
+ size_t *_num_requests)
+{
+ struct tcurl_request **requests;
+ const char *arg;
+ const char *url;
+ struct sss_iobuf *body;
+ errno_t ret;
+ size_t i;
+
+ static const char *headers[] = {
+ "Content-type: application/octet-stream",
+ NULL,
+ };
+
+ requests = talloc_zero_array(mem_ctx, struct tcurl_request *, MAXREQ + 1);
+ if (requests == NULL) {
+ return ENOMEM;
}
- while ((extra_arg_ptr = poptGetArg(pc)) != NULL) {
- switch(method) {
+ i = 0;
+ while ((arg = poptGetArg(pc)) != NULL) {
+ if (i >= MAXREQ) {
+ fprintf(stderr, _("Too many requests!\n"));
+ ret = EINVAL;
+ goto done;
+ }
+
+ switch (opts->method) {
case TCURL_HTTP_GET:
case TCURL_HTTP_DELETE:
- case TCURL_HTTP_POST:
- urls[n_reqs++] = extra_arg_ptr;
+ url = arg;
+ body = NULL;
break;
case TCURL_HTTP_PUT:
- if (urls[n_reqs] == NULL) {
- urls[n_reqs] = extra_arg_ptr;
- } else {
- inbufs[n_reqs] = sss_iobuf_init_readonly(
- inbufs,
- (uint8_t *) discard_const(extra_arg_ptr),
- strlen(extra_arg_ptr));
- if (inbufs[n_reqs] == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Could not init input buffer\n");
- talloc_zfree(tool_ctx);
- return 1;
- }
- n_reqs++;
+ case TCURL_HTTP_POST:
+ url = arg;
+
+ arg = poptGetArg(pc);
+ if (arg == NULL) {
+ body = NULL;
+ break;
+ }
+
+ body = sss_iobuf_init_readonly(requests,
+ discard_const_p(uint8_t, arg),
+ strlen(arg));
+ if (body == NULL) {
+ ret = ENOMEM;
+ goto done;
}
break;
+ default:
+ DEBUG(SSSDBG_CRIT_FAILURE, "Invalid method!\n");
+ ret = EINVAL;
+ goto done;
}
+
+ requests[i] = tcurl_http(requests, opts->method, opts->socket_path,
+ url, headers, body);
+ if (requests[i] == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ i++;
}
- if (opt != -1) {
- poptPrintUsage(pc, stderr, 0);
- fprintf(stderr, "%s", poptStrerror(opt));
- talloc_zfree(tool_ctx);
- return 1;
+ *_requests = requests;
+ *_num_requests = i;
+
+ ret = EOK;
+
+done:
+ if (ret != EOK) {
+ talloc_free(requests);
}
- if (!socket_path) {
- DEBUG(SSSDBG_FATAL_FAILURE, "Please specify the socket path\n");
- poptPrintUsage(pc, stderr, 0);
- talloc_zfree(tool_ctx);
- return 1;
+ return ret;
+}
+
+static errno_t
+run_requests(struct tool_ctx *tool_ctx,
+ struct tcurl_request **requests)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct tcurl_ctx *tcurl_ctx;
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ errno_t ret;
+ int i;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory!\n");
+ return ENOMEM;
}
- tool_ctx->nreqs = n_reqs;
- tool_ctx->verbose = !!pc_verbose;
+ if (requests == NULL || requests[0] == NULL) {
+ ret = EOK;
+ goto done;
+ }
- ev = tevent_context_init(tool_ctx);
+ ev = tevent_context_init(tmp_ctx);
if (ev == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "Could not init tevent context\n");
- talloc_zfree(tool_ctx);
- return 1;
+ ret = ENOMEM;
+ goto done;
}
- ctx = tcurl_init(tool_ctx, ev);
- if (ctx == NULL) {
+ tcurl_ctx = tcurl_init(tmp_ctx, ev);
+ if (tcurl_ctx == NULL) {
DEBUG(SSSDBG_FATAL_FAILURE, "Could not init tcurl context\n");
- talloc_zfree(tool_ctx);
- return 1;
+ ret = ENOMEM;
+ goto done;
}
- for (size_t i = 0; i < n_reqs; i++) {
- tcurl_req = tcurl_http(tool_ctx, method, socket_path,
- urls[i], headers, inbufs[i]);
- if (tcurl_req == NULL) {
- DEBUG(SSSDBG_FATAL_FAILURE, "Unable to create TCURL request\n");
- talloc_zfree(tool_ctx);
- return 1;
+ for (i = 0; requests[i] != NULL; i++) {
+ req = tcurl_request_send(tmp_ctx, ev, tcurl_ctx, requests[i], 5);
+ if (req == NULL) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Could not create tevent request\n");
+ ret = ENOMEM;
+ goto done;
}
- req = tcurl_request_send(tool_ctx, ev, ctx, tcurl_req, 10);
- if (ctx == NULL) {
- DEBUG(SSSDBG_FATAL_FAILURE, "Could not create request\n");
- talloc_zfree(tool_ctx);
- return 1;
- }
tevent_req_set_callback(req, request_done, tool_ctx);
}
@@ -226,11 +243,78 @@ int main(int argc, const char *argv[])
if (tool_ctx->nreqs > 0) {
DEBUG(SSSDBG_FATAL_FAILURE,
"The tool finished with some pending requests, fail!\n");
- talloc_zfree(tool_ctx);
- return 1;
+ ret = EEXIST;
+ goto done;
}
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+int main(int argc, const char *argv[])
+{
+ struct tool_options opts = { 0 };
+ struct tool_ctx *tool_ctx;
+ struct tcurl_request **requests;
+ poptContext pc;
+ errno_t ret;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ { "debug", '\0', POPT_ARG_INT, &opts.debug, 0, "The debug level to run with", NULL },
+ { "socket-path", 's', POPT_ARG_STRING, &opts.socket_path, 0, "The path to the HTTP server socket", NULL },
+ { "get", 'g', POPT_ARG_NONE, NULL, 'g', "Perform a HTTP GET (default)", NULL },
+ { "put", 'p', POPT_ARG_NONE, NULL, 'p', "Perform a HTTP PUT", NULL },
+ { "post", 'o', POPT_ARG_NONE, NULL, 'o', "Perform a HTTP POST", NULL },
+ { "del", 'd', POPT_ARG_NONE, NULL, 'd', "Perform a HTTP DELETE", NULL },
+ { "verbose", 'v', POPT_ARG_NONE, &opts.verbose, '\0', "Print response code and body", NULL },
+ POPT_TABLEEND
+ };
+
+ pc = poptGetContext(NULL, argc, argv, long_options, 0);
+ poptSetOtherOptionHelp(pc, "[URL HTTPDATA]*");
+
+ tool_ctx = talloc_zero(NULL, struct tool_ctx);
+ if (tool_ctx == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Could not init tool context\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = parse_options(pc, &opts);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Unable to parse options [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ DEBUG_CLI_INIT(opts.debug);
+ tool_ctx->verbose = opts.verbose;
+
+ ret = prepare_requests(tool_ctx, pc, &opts, &requests, &tool_ctx->nreqs);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Unable to prepare requests [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ ret = run_requests(tool_ctx, requests);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Unable to issue requests [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+done:
talloc_free(tool_ctx);
poptFreeContext(pc);
- return 0;
+
+ if (ret != EOK) {
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
}
--
2.12.2

View File

@ -1,48 +0,0 @@
From 36e49a842e257ac9bde71728ee3bef4299b6e6e2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Fri, 24 Feb 2017 12:23:22 +0100
Subject: [PATCH 79/97] tcurl test: add support for raw output
Reviewed-by: Simo Sorce <simo@redhat.com>
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
---
src/tests/tcurl_test_tool.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/src/tests/tcurl_test_tool.c b/src/tests/tcurl_test_tool.c
index e5fc9705db415650d849b89c3d18e41574b7e28b..7d3bc19f0ec7e118e251247536d25c58fe009f54 100644
--- a/src/tests/tcurl_test_tool.c
+++ b/src/tests/tcurl_test_tool.c
@@ -36,6 +36,7 @@ struct tool_ctx {
struct tool_options {
int debug;
int verbose;
+ int raw;
enum tcurl_http_method method;
const char *socket_path;
@@ -173,6 +174,13 @@ prepare_requests(TALLOC_CTX *mem_ctx,
goto done;
}
+ if (opts->raw) {
+ ret = tcurl_req_enable_rawoutput(requests[i]);
+ if (ret != EOK) {
+ goto done;
+ }
+ }
+
i++;
}
@@ -270,6 +278,7 @@ int main(int argc, const char *argv[])
{ "put", 'p', POPT_ARG_NONE, NULL, 'p', "Perform a HTTP PUT", NULL },
{ "post", 'o', POPT_ARG_NONE, NULL, 'o', "Perform a HTTP POST", NULL },
{ "del", 'd', POPT_ARG_NONE, NULL, 'd', "Perform a HTTP DELETE", NULL },
+ { "raw", 'r', POPT_ARG_NONE, &opts.raw, '\0', "Print raw protocol output", NULL },
{ "verbose", 'v', POPT_ARG_NONE, &opts.verbose, '\0', "Print response code and body", NULL },
POPT_TABLEEND
};
--
2.12.2

View File

@ -1,61 +0,0 @@
From 886e0f75e6f4c7877a23a3625f8a20c09109b09d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Mon, 27 Feb 2017 12:58:06 +0100
Subject: [PATCH 80/97] tcurl test: add support for tls settings
Reviewed-by: Simo Sorce <simo@redhat.com>
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
---
src/tests/tcurl_test_tool.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/src/tests/tcurl_test_tool.c b/src/tests/tcurl_test_tool.c
index 7d3bc19f0ec7e118e251247536d25c58fe009f54..9cec000fbf2e4eca2fdc5213c8b3b4cb10f1df1b 100644
--- a/src/tests/tcurl_test_tool.c
+++ b/src/tests/tcurl_test_tool.c
@@ -37,9 +37,14 @@ struct tool_options {
int debug;
int verbose;
int raw;
+ int tls;
+ int verify_peer;
+ int verify_host;
enum tcurl_http_method method;
const char *socket_path;
+ const char *capath;
+ const char *cacert;
};
static void request_done(struct tevent_req *req)
@@ -181,6 +186,14 @@ prepare_requests(TALLOC_CTX *mem_ctx,
}
}
+ if (opts->tls) {
+ ret = tcurl_req_verify_peer(requests[i], opts->capath, opts->cacert,
+ opts->verify_peer, opts->verify_host);
+ if (ret != EOK) {
+ goto done;
+ }
+ }
+
i++;
}
@@ -280,6 +293,12 @@ int main(int argc, const char *argv[])
{ "del", 'd', POPT_ARG_NONE, NULL, 'd', "Perform a HTTP DELETE", NULL },
{ "raw", 'r', POPT_ARG_NONE, &opts.raw, '\0', "Print raw protocol output", NULL },
{ "verbose", 'v', POPT_ARG_NONE, &opts.verbose, '\0', "Print response code and body", NULL },
+ /* TLS */
+ { "tls", '\0', POPT_ARG_NONE, &opts.tls, '\0', "Enable TLS", NULL },
+ { "verify-peer", '\0', POPT_ARG_NONE, &opts.verify_peer, '\0', "Verify peer when TLS is enabled", NULL },
+ { "verify-host", '\0', POPT_ARG_NONE, &opts.verify_host, '\0', "Verify host when TLS is enabled", NULL },
+ { "capath", '\0', POPT_ARG_STRING, &opts.capath, '\0', "Path to CA directory where peer certificate is stored", NULL },
+ { "cacert", '\0', POPT_ARG_STRING, &opts.cacert, '\0', "Path to CA certificate", NULL },
POPT_TABLEEND
};
--
2.12.2

View File

@ -1,111 +0,0 @@
From c2ea75da72b426d98ba489039e220d417bfb4c2a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Tue, 28 Feb 2017 13:32:31 +0100
Subject: [PATCH 81/97] tcurl: add support for http basic auth
Reviewed-by: Simo Sorce <simo@redhat.com>
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
---
src/tests/tcurl_test_tool.c | 14 ++++++++++++++
src/util/tev_curl.c | 24 ++++++++++++++++++++++++
src/util/tev_curl.h | 15 +++++++++++++++
3 files changed, 53 insertions(+)
diff --git a/src/tests/tcurl_test_tool.c b/src/tests/tcurl_test_tool.c
index 9cec000fbf2e4eca2fdc5213c8b3b4cb10f1df1b..4ceef8e06040ea0abd4d112a5b7845f436c69488 100644
--- a/src/tests/tcurl_test_tool.c
+++ b/src/tests/tcurl_test_tool.c
@@ -45,6 +45,9 @@ struct tool_options {
const char *socket_path;
const char *capath;
const char *cacert;
+
+ const char *username;
+ const char *password;
};
static void request_done(struct tevent_req *req)
@@ -194,6 +197,14 @@ prepare_requests(TALLOC_CTX *mem_ctx,
}
}
+ if (opts->username != NULL && opts->password != NULL) {
+ ret = tcurl_req_http_basic_auth(requests[i], opts->username,
+ opts->password);
+ if (ret != EOK) {
+ goto done;
+ }
+ }
+
i++;
}
@@ -299,6 +310,9 @@ int main(int argc, const char *argv[])
{ "verify-host", '\0', POPT_ARG_NONE, &opts.verify_host, '\0', "Verify host when TLS is enabled", NULL },
{ "capath", '\0', POPT_ARG_STRING, &opts.capath, '\0', "Path to CA directory where peer certificate is stored", NULL },
{ "cacert", '\0', POPT_ARG_STRING, &opts.cacert, '\0', "Path to CA certificate", NULL },
+ /* BASIC AUTH */
+ { "username", '\0', POPT_ARG_STRING, &opts.username, '\0', "Username for basic authentication", NULL },
+ { "password", '\0', POPT_ARG_STRING, &opts.password, '\0', "Password for basic authentication", NULL },
POPT_TABLEEND
};
diff --git a/src/util/tev_curl.c b/src/util/tev_curl.c
index c155f4c038d4215933ee30d41c694ad4a14ae132..8faf07c714b636a0351be365597de68d2f68a1be 100644
--- a/src/util/tev_curl.c
+++ b/src/util/tev_curl.c
@@ -1092,3 +1092,27 @@ errno_t tcurl_req_set_client_cert(struct tcurl_request *tcurl_req,
return EOK;
}
+
+errno_t tcurl_req_http_basic_auth(struct tcurl_request *tcurl_req,
+ const char *username,
+ const char *password)
+{
+ errno_t ret;
+
+ ret = tcurl_set_option(tcurl_req, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ ret = tcurl_set_option(tcurl_req, CURLOPT_USERNAME, username);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ ret = tcurl_set_option(tcurl_req, CURLOPT_PASSWORD, password);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ return EOK;
+}
diff --git a/src/util/tev_curl.h b/src/util/tev_curl.h
index 933abcb9b531412737e8fcf391644d828b125cf8..c733127b3686b5665f53cf53ea72674e0d7af64e 100644
--- a/src/util/tev_curl.h
+++ b/src/util/tev_curl.h
@@ -243,4 +243,19 @@ errno_t tcurl_req_set_client_cert(struct tcurl_request *tcurl_req,
const char *cert,
const char *key);
+/**
+ * @brief Force HTTP basic authentication with @username and @password.
+ *
+ * @param[in] tcurl_request
+ * @param[in] username
+ * @param[in] password
+ *
+ * @returns errno code
+ *
+ * @see tcurl_http
+ */
+errno_t tcurl_req_http_basic_auth(struct tcurl_request *tcurl_req,
+ const char *username,
+ const char *password);
+
#endif /* __TEV_CURL_H */
--
2.12.2

View File

@ -1,62 +0,0 @@
From d1ed11fc50922aab2332758a9300f3fbf814f112 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Fri, 10 Mar 2017 12:11:12 +0100
Subject: [PATCH 82/97] tcurl test: allow to set custom headers
Reviewed-by: Simo Sorce <simo@redhat.com>
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
---
src/tests/tcurl_test_tool.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/src/tests/tcurl_test_tool.c b/src/tests/tcurl_test_tool.c
index 4ceef8e06040ea0abd4d112a5b7845f436c69488..63a3e26b561781795873c2a4d72ac071a4da9939 100644
--- a/src/tests/tcurl_test_tool.c
+++ b/src/tests/tcurl_test_tool.c
@@ -40,6 +40,7 @@ struct tool_options {
int tls;
int verify_peer;
int verify_host;
+ const char **headers;
enum tcurl_http_method method;
const char *socket_path;
@@ -121,13 +122,14 @@ prepare_requests(TALLOC_CTX *mem_ctx,
size_t *_num_requests)
{
struct tcurl_request **requests;
+ struct sss_iobuf *body;
+ const char **headers;
const char *arg;
const char *url;
- struct sss_iobuf *body;
errno_t ret;
size_t i;
- static const char *headers[] = {
+ static const char *default_headers[] = {
"Content-type: application/octet-stream",
NULL,
};
@@ -137,6 +139,8 @@ prepare_requests(TALLOC_CTX *mem_ctx,
return ENOMEM;
}
+ headers = opts->headers == NULL ? default_headers : opts->headers;
+
i = 0;
while ((arg = poptGetArg(pc)) != NULL) {
if (i >= MAXREQ) {
@@ -302,6 +306,9 @@ int main(int argc, const char *argv[])
{ "put", 'p', POPT_ARG_NONE, NULL, 'p', "Perform a HTTP PUT", NULL },
{ "post", 'o', POPT_ARG_NONE, NULL, 'o', "Perform a HTTP POST", NULL },
{ "del", 'd', POPT_ARG_NONE, NULL, 'd', "Perform a HTTP DELETE", NULL },
+#ifdef POPT_ARG_ARGV
+ { "header", 'h', POPT_ARG_ARGV, &opts.headers, '\0', "Add HTTP header", NULL },
+#endif
{ "raw", 'r', POPT_ARG_NONE, &opts.raw, '\0', "Print raw protocol output", NULL },
{ "verbose", 'v', POPT_ARG_NONE, &opts.verbose, '\0', "Print response code and body", NULL },
/* TLS */
--
2.12.2

View File

@ -1,52 +0,0 @@
From ae6b11229d9961e26922918183c7c1de7780b8d6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Mon, 13 Mar 2017 13:30:48 +0100
Subject: [PATCH 83/97] tcurl test: add support for client certificate
Reviewed-by: Simo Sorce <simo@redhat.com>
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
---
src/tests/tcurl_test_tool.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/src/tests/tcurl_test_tool.c b/src/tests/tcurl_test_tool.c
index 63a3e26b561781795873c2a4d72ac071a4da9939..fbc2790357b131ebb21b4be041688e5f699d73e7 100644
--- a/src/tests/tcurl_test_tool.c
+++ b/src/tests/tcurl_test_tool.c
@@ -47,6 +47,9 @@ struct tool_options {
const char *capath;
const char *cacert;
+ const char *clientcert;
+ const char *clientkey;
+
const char *username;
const char *password;
};
@@ -201,6 +204,14 @@ prepare_requests(TALLOC_CTX *mem_ctx,
}
}
+ if (opts->clientcert != NULL) {
+ ret = tcurl_req_set_client_cert(requests[i], opts->clientcert,
+ opts->clientkey);
+ if (ret != EOK) {
+ goto done;
+ }
+ }
+
if (opts->username != NULL && opts->password != NULL) {
ret = tcurl_req_http_basic_auth(requests[i], opts->username,
opts->password);
@@ -317,6 +328,8 @@ int main(int argc, const char *argv[])
{ "verify-host", '\0', POPT_ARG_NONE, &opts.verify_host, '\0', "Verify host when TLS is enabled", NULL },
{ "capath", '\0', POPT_ARG_STRING, &opts.capath, '\0', "Path to CA directory where peer certificate is stored", NULL },
{ "cacert", '\0', POPT_ARG_STRING, &opts.cacert, '\0', "Path to CA certificate", NULL },
+ { "clientcert", '\0', POPT_ARG_STRING, &opts.clientcert, '\0', "Path to client's certificate", NULL },
+ { "clientkey", '\0', POPT_ARG_STRING, &opts.clientkey, '\0', "Path to client's private key", NULL },
/* BASIC AUTH */
{ "username", '\0', POPT_ARG_STRING, &opts.username, '\0', "Username for basic authentication", NULL },
{ "password", '\0', POPT_ARG_STRING, &opts.password, '\0', "Password for basic authentication", NULL },
--
2.12.2

View File

@ -1,114 +0,0 @@
From 6698d40512e55e7c2d03e14c227c51b1edc77ffa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Tue, 28 Mar 2017 15:24:01 +0200
Subject: [PATCH 84/97] ci: do not build secrets on rhel6
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
We require newer libcurl version than is available on rhel6. We don't
ship secrets responder in rhel6 so we just disable its build.
Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
---
contrib/ci/configure.sh | 1 +
contrib/sssd.spec.in | 15 +++++++++++++++
src/tests/intg/test_secrets.py | 4 ++++
3 files changed, 20 insertions(+)
diff --git a/contrib/ci/configure.sh b/contrib/ci/configure.sh
index 7590743c2aa5fe31bcdf1a3e92a3f482dbec699b..9d18d0c187561a2dc3bc47d3e8913626e7ff3046 100644
--- a/contrib/ci/configure.sh
+++ b/contrib/ci/configure.sh
@@ -38,6 +38,7 @@ if [[ "$DISTRO_BRANCH" == -redhat-redhatenterprise*-6.*- ||
"--disable-cifs-idmap-plugin"
"--with-syslog=syslog"
"--without-python3-bindings"
+ "--without-secrets"
"--without-kcm"
)
fi
diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in
index af14d4e3d6b9ffeb4696f1517113b8daa575cb99..39a974edebba3dbcd7625d1729b4a7330eaa8a27 100644
--- a/contrib/sssd.spec.in
+++ b/contrib/sssd.spec.in
@@ -112,6 +112,12 @@
%global enable_systemtap_opt --enable-systemtap
%endif
+%if (0%{?fedora} || 0%{?epel} >= 7)
+ %global with_secrets 1
+%else
+ %global with_secret_responder --without-secrets
+%endif
+
%if (0%{?fedora} >= 23 || 0%{?rhel} >= 7)
%global with_kcm 1
%global with_kcm_option --with-kcm
@@ -220,8 +226,10 @@ BuildRequires: libsmbclient-devel
%if (0%{?enable_systemtap} == 1)
BuildRequires: systemtap-sdt-devel
%endif
+%if (0%{?with_secrets} == 1)
BuildRequires: http-parser-devel
BuildRequires: jansson-devel
+%endif
BuildRequires: libuuid-devel
BuildRequires: libcurl-devel
@@ -727,6 +735,7 @@ autoreconf -ivf
%{?with_python3_option} \
%{?enable_polkit_rules_option} \
%{?enable_systemtap_opt} \
+ %{?with_secret_responder} \
%{?with_kcm_option} \
%{?experimental}
@@ -865,7 +874,9 @@ done
%{_libexecdir}/%{servicename}/sssd_nss
%{_libexecdir}/%{servicename}/sssd_pam
%{_libexecdir}/%{servicename}/sssd_autofs
+%if (0%{?with_secrets} == 1)
%{_libexecdir}/%{servicename}/sssd_secrets
+%endif
%{_libexecdir}/%{servicename}/sssd_ssh
%{_libexecdir}/%{servicename}/sssd_sudo
%{_libexecdir}/%{servicename}/p11_child
@@ -900,7 +911,9 @@ done
%dir %{_localstatedir}/cache/krb5rcache
%attr(700,sssd,sssd) %dir %{dbpath}
%attr(755,sssd,sssd) %dir %{mcpath}
+%if (0%{?with_secrets} == 1)
%attr(700,root,root) %dir %{secdbpath}
+%endif
%ghost %attr(0644,sssd,sssd) %verify(not md5 size mtime) %{mcpath}/passwd
%ghost %attr(0644,sssd,sssd) %verify(not md5 size mtime) %{mcpath}/group
%ghost %attr(0644,sssd,sssd) %verify(not md5 size mtime) %{mcpath}/initgroups
@@ -933,7 +946,9 @@ done
%{_mandir}/man5/sssd.conf.5*
%{_mandir}/man5/sssd-simple.5*
%{_mandir}/man5/sssd-sudo.5*
+%if (0%{?with_secrets} == 1)
%{_mandir}/man5/sssd-secrets.5*
+%endif
%{_mandir}/man5/sss_rpcidmapd.5*
%{_mandir}/man8/sssd.8*
%{_mandir}/man8/sss_cache.8*
diff --git a/src/tests/intg/test_secrets.py b/src/tests/intg/test_secrets.py
index d71c1904558cc6f8a6eee36c4049582705bc30ac..202f43e61cb0e4986394ad2b32da5abdcb0be3e9 100644
--- a/src/tests/intg/test_secrets.py
+++ b/src/tests/intg/test_secrets.py
@@ -46,6 +46,10 @@ def create_sssd_secrets_fixture(request):
raise Exception("failed to regenerate confdb")
resp_path = os.path.join(config.LIBEXEC_PATH, "sssd", "sssd_secrets")
+ if not os.access(resp_path, os.X_OK):
+ # It would be cleaner to use pytest.mark.skipif on the package level
+ # but upstream insists on supporting RHEL-6.
+ pytest.skip("No Secrets responder, skipping")
secpid = os.fork()
assert secpid >= 0
--
2.12.2

View File

@ -1,64 +0,0 @@
From 793f2573b2beaf8b48eab850429482acf68ec2b1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Wed, 22 Mar 2017 12:32:31 +0100
Subject: [PATCH 85/97] build: make curl required by secrets
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Also remove --disable-libcurl since it doesn't make sense.
Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
Reviewed-by: Simo Sorce <simo@redhat.com>
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
---
configure.ac | 6 +++++-
src/external/libcurl.m4 | 16 ++--------------
2 files changed, 7 insertions(+), 15 deletions(-)
diff --git a/configure.ac b/configure.ac
index cf5e2557ef0a1bd6374200aa33abea6c509d03aa..80d8ea9ff5785b0d76edbb04f454d0dd8c8a1e6d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -201,9 +201,13 @@ if test x$with_secrets = xyes; then
fi
if test x$with_kcm = xyes; then
- m4_include([src/external/libcurl.m4])
m4_include([src/external/libuuid.m4])
fi
+
+if test x$with_kcm = xyes -o x$with_secrets = xyes; then
+ m4_include([src/external/libcurl.m4])
+fi
+
# This variable is defined by external/libcurl.m4, but conditionals
# must be always evaluated
AM_CONDITIONAL([BUILD_WITH_LIBCURL],
diff --git a/src/external/libcurl.m4 b/src/external/libcurl.m4
index b420b04ad806bd1251f086b773ffe480d39f8bd3..42be308cd1e4b04e736daf887be9b75ea92db80e 100644
--- a/src/external/libcurl.m4
+++ b/src/external/libcurl.m4
@@ -1,17 +1,5 @@
-AC_ARG_ENABLE([curl],
- [AS_HELP_STRING([--disable-curl-support],
- [do not build with libcurl support])],
- [enable_libcurl=$enableval],
- [enable_libcurl=yes])
-
-found_libcurl="no"
-AS_IF([test x$enable_libcurl = xyes],
- [PKG_CHECK_MODULES([CURL],
- [libcurl],
- [found_libcurl=yes],
- [AC_MSG_ERROR([
-The libcurl development library was not found.])
- ])])
+PKG_CHECK_MODULES([CURL], [libcurl], [found_libcurl=yes],
+ [AC_MSG_ERROR([The libcurl development library was not found.])])
AS_IF([test x"$found_libcurl" = xyes],
CFLAGS="$CFLAGS $CURL_CFLAGS"
--
2.12.2

View File

@ -1,458 +0,0 @@
From df99d709c8cbef3c378c111944d83b7345e4c1ea Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Wed, 22 Feb 2017 10:38:56 +0100
Subject: [PATCH 86/97] secrets: use tcurl in proxy provider
We switch from http-parser to libcurl for an http client. This gaves us many
features for free such as tls and http basic authentication support instead
of implementing it on our own.
Resolves:
https://pagure.io/SSSD/sssd/issue/3192
Reviewed-by: Simo Sorce <simo@redhat.com>
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
---
Makefile.am | 3 +
src/responder/secrets/providers.c | 20 +++
src/responder/secrets/proxy.c | 246 ++++++++++++++++++++++-----------
src/responder/secrets/secsrv_private.h | 5 +
4 files changed, 191 insertions(+), 83 deletions(-)
diff --git a/Makefile.am b/Makefile.am
index 573b37c52fdeab1add4ea057e1e1844ea4d348a5..4a414f77df999b8b1d81f663fcc18dbd2d6d2dc4 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1486,6 +1486,8 @@ sssd_secrets_SOURCES = \
src/responder/secrets/local.c \
src/responder/secrets/proxy.c \
src/util/sss_sockets.c \
+ src/util/sss_iobuf.c \
+ src/util/tev_curl.c \
$(SSSD_RESPONDER_OBJ) \
$(SSSD_RESOLV_OBJ) \
$(NULL)
@@ -1497,6 +1499,7 @@ sssd_secrets_LDADD = \
$(SYSTEMD_DAEMON_LIBS) \
$(CARES_LIBS) \
$(SSSD_INTERNAL_LTLIBS) \
+ $(CURL_LIBS) \
$(NULL)
endif
diff --git a/src/responder/secrets/providers.c b/src/responder/secrets/providers.c
index 94831c73036d269addca45c0117811a2c68873fd..80a443d91135447ec8ce8d424b692a6d7e26a907 100644
--- a/src/responder/secrets/providers.c
+++ b/src/responder/secrets/providers.c
@@ -22,6 +22,7 @@
#include "responder/secrets/secsrv_private.h"
#include "responder/secrets/secsrv_local.h"
#include "responder/secrets/secsrv_proxy.h"
+#include "util/sss_iobuf.h"
#include <jansson.h>
typedef int (*url_mapper_fn)(struct sec_req_ctx *secreq,
@@ -387,6 +388,25 @@ int sec_http_reply_with_headers(TALLOC_CTX *mem_ctx, struct sec_data *reply,
return EOK;
}
+errno_t sec_http_reply_iobuf(TALLOC_CTX *mem_ctx,
+ struct sec_data *reply,
+ int response_code,
+ struct sss_iobuf *response)
+{
+ DEBUG(SSSDBG_TRACE_LIBS, "HTTP reply %d\n", response_code);
+
+ reply->data = (char *)sss_iobuf_get_data(response);
+ reply->length = sss_iobuf_get_len(response);
+
+ talloc_steal(mem_ctx, reply->data);
+
+ if (reply->data == NULL) {
+ return EINVAL;
+ }
+
+ return EOK;
+}
+
enum sec_http_status_codes sec_errno_to_http_status(errno_t err)
{
DEBUG(SSSDBG_TRACE_LIBS, "Request errno: %d\n", err);
diff --git a/src/responder/secrets/proxy.c b/src/responder/secrets/proxy.c
index 3ed03e6086d0de0f6f80de227ffc65ef4067db4f..fe2f0134e233d9a98f499fe563abe0af69762514 100644
--- a/src/responder/secrets/proxy.c
+++ b/src/responder/secrets/proxy.c
@@ -23,10 +23,15 @@
#include "util/crypto/sss_crypto.h"
#include "resolv/async_resolv.h"
#include "util/sss_sockets.h"
+#include "util/sss_iobuf.h"
+#include "util/tev_curl.h"
+
+#define SEC_PROXY_TIMEOUT 5
struct proxy_context {
struct resolv_ctx *resctx;
struct confdb_ctx *cdb;
+ struct tcurl_ctx *tcurl;
};
enum proxy_auth_type {
@@ -216,103 +221,177 @@ int proxy_sec_map_url(TALLOC_CTX *mem_ctx, struct sec_req_ctx *secreq,
return EOK;
}
-int proxy_sec_map_headers(TALLOC_CTX *mem_ctx, struct sec_req_ctx *secreq,
- struct proxy_cfg *pcfg, char **req_headers)
+static errno_t proxy_http_append_header(TALLOC_CTX *mem_ctx,
+ const char *name,
+ const char *value,
+ const char ***_headers,
+ size_t *_num_headers)
{
- int ret;
-
- for (int i = 0; i < secreq->num_headers; i++) {
- bool forward = false;
- for (int j = 0; pcfg->fwd_headers[j]; j++) {
- if (strcasecmp(secreq->headers[i].name,
- pcfg->fwd_headers[j]) == 0) {
- forward = true;
+ const char **headers = *_headers;
+ size_t num_headers = *_num_headers;
+
+ num_headers++;
+ headers = talloc_realloc(mem_ctx, headers, const char *,
+ num_headers + 1);
+ if (headers == NULL) {
+ return ENOMEM;
+ }
+
+ headers[num_headers - 1] = talloc_asprintf(headers, "%s: %s", name, value);
+ if (headers[num_headers - 1] == NULL) {
+ return ENOMEM;
+ }
+
+ headers[num_headers] = NULL;
+
+ *_headers = headers;
+ *_num_headers = num_headers;
+
+ return EOK;
+}
+
+static const char **
+proxy_http_create_headers(TALLOC_CTX *mem_ctx,
+ struct sec_req_ctx *secreq,
+ struct proxy_cfg *pcfg)
+{
+ TALLOC_CTX *tmp_ctx;
+ const char **headers;
+ size_t num_headers;
+ errno_t ret;
+ int i, j;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory!\n");
+ return NULL;
+ }
+
+ headers = talloc_zero_array(tmp_ctx, const char *, 1);
+ if (headers == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ num_headers = 0;
+ for (i = 0; i < secreq->num_headers; i++) {
+ for (j = 0; pcfg->fwd_headers[j]; j++) {
+ if (strcasecmp(secreq->headers[i].name, pcfg->fwd_headers[j]) == 0) {
+ DEBUG(SSSDBG_TRACE_LIBS, "Forwarding header %s: %s\n",
+ secreq->headers[i].name, secreq->headers[i].value);
+
+ ret = proxy_http_append_header(tmp_ctx, secreq->headers[i].name,
+ secreq->headers[i].value,
+ &headers, &num_headers);
+ if (ret != EOK) {
+ goto done;
+ }
+
break;
}
}
- if (forward) {
- DEBUG(SSSDBG_TRACE_LIBS, "Forwarding header %s:%s\n",
- secreq->headers[i].name, secreq->headers[i].value);
-
- ret = sec_http_append_header(mem_ctx, req_headers,
- secreq->headers[i].name,
- secreq->headers[i].value);
- if (ret) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- "Couldn't append header %s\n", secreq->headers[i].name);
- return ret;
- }
- }
}
if (pcfg->auth_type == PAT_HEADER) {
- DEBUG(SSSDBG_TRACE_LIBS,
- "Forwarding header %s\n", pcfg->auth.header.name);
+ DEBUG(SSSDBG_TRACE_LIBS, "Forwarding header %s\n",
+ pcfg->auth.header.name);
- ret = sec_http_append_header(mem_ctx, req_headers,
- pcfg->auth.header.name,
- pcfg->auth.header.value);
- if (ret) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- "Couldn't append header %s\n", pcfg->auth.header.name);
- return ret;
+ ret = proxy_http_append_header(tmp_ctx, pcfg->auth.header.name,
+ pcfg->auth.header.value,
+ &headers, &num_headers);
+ if (ret != EOK) {
+ goto done;
}
}
- return EOK;
+ talloc_steal(mem_ctx, headers);
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+
+ if (ret != EOK) {
+ return NULL;
+ }
+
+ return headers;
}
-static int proxy_http_create_request(TALLOC_CTX *mem_ctx,
- struct sec_req_ctx *secreq,
- struct proxy_cfg *pcfg,
- const char *http_uri,
- struct sec_data **http_req)
+static errno_t proxy_http_create_request(TALLOC_CTX *mem_ctx,
+ struct sec_req_ctx *secreq,
+ struct proxy_cfg *pcfg,
+ const char *url,
+ struct tcurl_request **_tcurl_req)
{
- struct sec_data *req;
- int ret;
+ TALLOC_CTX *tmp_ctx;
+ struct tcurl_request *tcurl_req;
+ enum tcurl_http_method method;
+ struct sss_iobuf *body;
+ const char **headers;
+ errno_t ret;
- req = talloc_zero(mem_ctx, struct sec_data);
- if (!req) return ENOMEM;
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory!\n");
+ return ENOMEM;
+ }
- /* Request-Line */
- req->data = talloc_asprintf(req, "%s %s HTTP/1.1\r\n",
- http_method_str(secreq->method), http_uri);
- if (!req->data) {
+ headers = proxy_http_create_headers(tmp_ctx, secreq, pcfg);
+ if (headers == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to construct HTTP headers!\n");
ret = ENOMEM;
goto done;
}
- /* Headers */
- ret = proxy_sec_map_headers(req, secreq, pcfg, &req->data);
- if (ret) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Couldn't map headers\n");
+ body = sss_iobuf_init_readonly(tmp_ctx, (uint8_t *)secreq->body.data,
+ secreq->body.length);
+ if (body == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create HTTP body!\n");
+ ret = ENOMEM;
goto done;
}
- /* CRLF separator before body */
- req->data = talloc_strdup_append_buffer(req->data, "\r\n");
-
- req->length = strlen(req->data);
+ switch (secreq->method) {
+ case HTTP_GET:
+ method = TCURL_HTTP_GET;
+ break;
+ case HTTP_PUT:
+ method = TCURL_HTTP_PUT;
+ break;
+ case HTTP_POST:
+ method = TCURL_HTTP_POST;
+ break;
+ case HTTP_DELETE:
+ method = TCURL_HTTP_DELETE;
+ break;
+ default:
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected HTTP method: %d\n",
+ secreq->method);
+ ret = EINVAL;
+ goto done;
+ }
- /* Message-Body */
- if (secreq->body.length > 0) {
- req->data = talloc_realloc_size(req, req->data,
- req->length + secreq->body.length);
- if (!req->data) {
- ret = ENOMEM;
- goto done;
- }
+ tcurl_req = tcurl_http(tmp_ctx, method, NULL, url, headers, body);
+ if (tcurl_req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create TCURL request!\n");
+ ret = ENOMEM;
+ goto done;
+ }
- memcpy(&req->data[req->length],
- secreq->body.data, secreq->body.length);
- req->length += secreq->body.length;
+ /* TCURL will return response buffer also with headers. */
+ ret = tcurl_req_enable_rawoutput(tcurl_req);
+ if (ret != EOK) {
+ goto done;
}
- *http_req = req;
+ talloc_steal(tcurl_req, body);
+ *_tcurl_req = talloc_steal(mem_ctx, tcurl_req);
+
ret = EOK;
done:
- if (ret) talloc_free(req);
+ talloc_free(tmp_ctx);
return ret;
}
@@ -911,8 +990,8 @@ struct tevent_req *proxy_secret_req(TALLOC_CTX *mem_ctx,
{
struct tevent_req *req, *subreq;
struct proxy_secret_state *state;
+ struct tcurl_request *tcurl_req;
struct proxy_context *pctx;
- struct sec_data *http_req;
char *http_uri;
int ret;
@@ -942,9 +1021,8 @@ struct tevent_req *proxy_secret_req(TALLOC_CTX *mem_ctx,
goto done;
}
-
ret = proxy_http_create_request(state, state->secreq, state->pcfg,
- http_uri, &http_req);
+ http_uri, &tcurl_req);
if (ret) {
DEBUG(SSSDBG_CRIT_FAILURE,
"proxy_http_create_request failed [%d]: %s\n",
@@ -952,10 +1030,9 @@ struct tevent_req *proxy_secret_req(TALLOC_CTX *mem_ctx,
goto done;
}
-
- subreq = proxy_http_req_send(pctx, state, ev, state->secreq,
- http_uri, http_req);
- if (!subreq) {
+ subreq = tcurl_request_send(mem_ctx, ev, pctx->tcurl, tcurl_req,
+ SEC_PROXY_TIMEOUT);
+ if (subreq == NULL) {
ret = ENOMEM;
goto done;
}
@@ -981,32 +1058,30 @@ static void proxy_secret_req_done(struct tevent_req *subreq)
{
struct tevent_req *req;
struct proxy_secret_state *state;
- struct proxy_http_reply *reply = NULL;
+ struct sss_iobuf *response;
+ int http_code;
int ret;
req = tevent_req_callback_data(subreq, struct tevent_req);
state = tevent_req_data(req, struct proxy_secret_state);
- ret = proxy_http_req_recv(subreq, state, &reply);
+ ret = tcurl_request_recv(state, subreq, &response, &http_code);
talloc_zfree(subreq);
if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE,
- "proxy_http request failed [%d]: %s\n",
+ DEBUG(SSSDBG_OP_FAILURE, "proxy_http request failed [%d]: %s\n",
ret, sss_strerror(ret));
tevent_req_error(req, ret);
return;
}
- ret = sec_http_reply_with_headers(state->secreq, &state->secreq->reply,
- reply->status_code, reply->reason_phrase,
- reply->headers, reply->num_headers,
- &reply->body);
+ ret = sec_http_reply_iobuf(state->secreq, &state->secreq->reply,
+ http_code, response);
if (ret == EOK) {
tevent_req_done(req);
} else {
DEBUG(SSSDBG_OP_FAILURE,
- "sec_http_reply_with_headers request failed [%d]: %s\n",
+ "sec_http_reply_iobuf request failed [%d]: %s\n",
ret, sss_strerror(ret));
tevent_req_error(req, ret);
}
@@ -1034,6 +1109,11 @@ int proxy_secrets_provider_handle(struct sec_ctx *sctx,
pctx->resctx = sctx->resctx;
pctx->cdb = sctx->rctx->cdb;
+ pctx->tcurl = tcurl_init(pctx, sctx->rctx->ev);
+ if (pctx->tcurl == NULL) {
+ talloc_free(pctx);
+ return ENOMEM;
+ }
handle->context = pctx;
diff --git a/src/responder/secrets/secsrv_private.h b/src/responder/secrets/secsrv_private.h
index a8544f656517a17fe4576247779bff4850beaf97..2e68628f61a0a8e79cd48fb5a510221e6fc36c70 100644
--- a/src/responder/secrets/secsrv_private.h
+++ b/src/responder/secrets/secsrv_private.h
@@ -25,6 +25,7 @@
#include "config.h"
#include "responder/common/responder.h"
#include "responder/secrets/secsrv.h"
+#include "util/sss_iobuf.h"
#include <http_parser.h>
struct sec_kvp {
@@ -129,6 +130,10 @@ int sec_http_reply_with_headers(TALLOC_CTX *mem_ctx, struct sec_data *reply,
int status_code, const char *reason,
struct sec_kvp *headers, int num_headers,
struct sec_data *body);
+errno_t sec_http_reply_iobuf(TALLOC_CTX *mem_ctx,
+ struct sec_data *reply,
+ int response_code,
+ struct sss_iobuf *response);
enum sec_http_status_codes sec_errno_to_http_status(errno_t err);
int sec_json_to_simple_secret(TALLOC_CTX *mem_ctx,
--
2.12.2

View File

@ -1,611 +0,0 @@
From 06744bf5a47d5971a338281c8243b11cf72dac90 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Tue, 28 Feb 2017 14:14:40 +0100
Subject: [PATCH 87/97] secrets: remove http-parser code in proxy provider
We switche to libcurl in previous patch. This just removes the unused code.
Resolves:
https://pagure.io/SSSD/sssd/issue/3192
Reviewed-by: Simo Sorce <simo@redhat.com>
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
---
src/responder/secrets/proxy.c | 581 ------------------------------------------
1 file changed, 581 deletions(-)
diff --git a/src/responder/secrets/proxy.c b/src/responder/secrets/proxy.c
index fe2f0134e233d9a98f499fe563abe0af69762514..3c495716010ac468c9e2f1fb6356529a8dbdc614 100644
--- a/src/responder/secrets/proxy.c
+++ b/src/responder/secrets/proxy.c
@@ -395,587 +395,6 @@ done:
return ret;
}
-struct proxy_http_request {
- struct sec_data *data;
- size_t written;
-};
-
-struct proxy_http_reply {
- http_parser parser;
- bool complete;
-
- int status_code;
- char *reason_phrase;
- struct sec_kvp *headers;
- int num_headers;
- struct sec_data body;
-
- size_t received;
-};
-
-struct proxy_http_req_state {
- struct tevent_context *ev;
-
- char *proxyname;
- int port;
-
- struct resolv_hostent *hostent;
- int hostidx;
-
- int sd;
- struct tevent_fd *fde;
-
- struct proxy_http_request request;
- struct proxy_http_reply *reply;
-};
-
-static int proxy_http_req_state_destroy(void *data);
-static void proxy_http_req_gethostname_done(struct tevent_req *subreq);
-static void proxy_http_req_connect_step(struct tevent_req *req);
-static void proxy_http_req_connect_done(struct tevent_req *subreq);
-static void proxy_fd_handler(struct tevent_context *ev, struct tevent_fd *fde,
- uint16_t flags, void *ptr);
-
-struct tevent_req *proxy_http_req_send(struct proxy_context *pctx,
- TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- struct sec_req_ctx *secreq,
- const char *http_uri,
- struct sec_data *http_req)
-{
- struct proxy_http_req_state *state;
- struct http_parser_url parsed;
- struct tevent_req *req, *subreq;
- int ret;
-
- req = tevent_req_create(mem_ctx, &state, struct proxy_http_req_state);
- if (!req) return NULL;
-
- state->ev = ev;
- state->request.data = http_req;
- state->sd = -1;
- talloc_set_destructor((TALLOC_CTX *)state,
- proxy_http_req_state_destroy);
-
- /* STEP1: reparse URL to get hostname and port */
- ret = http_parser_parse_url(http_uri, strlen(http_uri), 0, &parsed);
- if (ret) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Failed to parse URL [%s]: %d: %s\n",
- http_uri, ret, sss_strerror(ret));
- goto done;
- }
-
- if (!(parsed.field_set & (1 << UF_HOST))) {
- DEBUG(SSSDBG_CRIT_FAILURE, "No UF_HOST flag found\n");
- ret = EINVAL;
- goto done;
- }
- state->proxyname =
- talloc_strndup(state,
- &http_uri[parsed.field_data[UF_HOST].off],
- parsed.field_data[UF_HOST].len);
- if (!state->proxyname) {
- ret = ENOMEM;
- goto done;
- }
- DEBUG(SSSDBG_TRACE_LIBS, "proxy name: %s\n", state->proxyname);
-
- if (parsed.field_set & (1 << UF_PORT)) {
- state->port = parsed.port;
- } else if (parsed.field_set & (1 << UF_SCHEMA)) {
- uint16_t off = parsed.field_data[UF_SCHEMA].off;
- uint16_t len = parsed.field_data[UF_SCHEMA].len;
-
- if ((len == 5) &&
- (strncmp("https", &http_uri[off], len) == 0)) {
- state->port = 443;
- } else if ((len == 4) &&
- (strncmp("http", &http_uri[off], len) == 0)) {
- state->port = 80;
- }
- }
- DEBUG(SSSDBG_TRACE_LIBS, "proxy port: %d\n", state->port);
-
- /* STEP2: resolve hostname first */
- subreq = resolv_gethostbyname_send(state, ev, pctx->resctx,
- state->proxyname, IPV4_FIRST,
- default_host_dbs);
- if (subreq == NULL) {
- ret = ENOMEM;
- goto done;
- }
-
- tevent_req_set_callback(subreq, proxy_http_req_gethostname_done, req);
-
- return req;
-
-done:
- if (ret == EOK) {
- tevent_req_done(req);
- } else {
- tevent_req_error(req, ret);
- }
- tevent_req_post(req, ev);
-
- return req;
-}
-
-static void proxy_http_req_gethostname_done(struct tevent_req *subreq)
-{
- struct tevent_req *req;
- struct proxy_http_req_state *state;
- int resolv_status;
- int ret;
-
- req = tevent_req_callback_data(subreq, struct tevent_req);
- state = tevent_req_data(req, struct proxy_http_req_state);
-
- ret = resolv_gethostbyname_recv(subreq, state, &resolv_status, NULL,
- &state->hostent);
- talloc_zfree(subreq);
- if (ret != EOK) {
- if (ret == ENOENT) {
- /* Empty result, just quit */
- DEBUG(SSSDBG_TRACE_INTERNAL, "No hostent found\n");
- } else {
- DEBUG(SSSDBG_OP_FAILURE,
- "Could not resolve fqdn for this machine, error [%d]: %s, "
- "resolver returned: [%d]: %s\n", ret, strerror(ret),
- resolv_status, resolv_strerror(resolv_status));
- }
- goto done;
- }
-
- /* EOK */
- DEBUG(SSSDBG_TRACE_INTERNAL, "Found fqdn: %s\n", state->hostent->name);
-
- /* STEP3: connect to one of the servers */
- proxy_http_req_connect_step(req);
- return;
-
-done:
- if (ret == EOK) {
- tevent_req_done(req);
- } else {
- tevent_req_error(req, ret);
- }
-}
-
-static void proxy_http_req_connect_step(struct tevent_req *req)
-{
- struct proxy_http_req_state *state;
- struct sockaddr_storage *sockaddr;
- char *ipaddr;
- struct tevent_req *subreq;
- int ret;
-
- state = tevent_req_data(req, struct proxy_http_req_state);
-
- if (!state->hostent->addr_list[state->hostidx]) {
- DEBUG(SSSDBG_CRIT_FAILURE, "No more addresses to try.\n");
- ret = ERR_SEC_NO_PROXY;
- goto done;
- }
-
- sockaddr = resolv_get_sockaddr_address_index(state, state->hostent,
- state->port, state->hostidx);
- if (sockaddr == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, "resolv_get_sockaddr_address() failed\n");
- ret = EIO;
- goto done;
- }
-
- if (DEBUG_IS_SET(SSSDBG_TRACE_FUNC)) {
- ipaddr = resolv_get_string_address_index(state, state->hostent,
- state->hostidx);
- if (!ipaddr) {
- ret = EFAULT;
- goto done;
- }
- DEBUG(SSSDBG_TRACE_FUNC, "Connecting to %s:%d\n",
- ipaddr, state->port);
- }
-
- /* increase idx for next attempt */
- state->hostidx++;
-
- subreq = sssd_async_socket_init_send(state, state->ev, sockaddr,
- sizeof(struct sockaddr_storage),
- SEC_NET_TIMEOUT);
- if (!subreq) {
- ret = EIO;
- goto done;
- }
- tevent_req_set_callback(subreq, proxy_http_req_connect_done, req);
- return;
-
-done:
- if (ret == EOK) {
- tevent_req_done(req);
- } else {
- tevent_req_error(req, ret);
- }
-}
-
-static void proxy_http_req_connect_done(struct tevent_req *subreq)
-{
- struct tevent_req *req;
- struct proxy_http_req_state *state;
- int ret;
-
- req = tevent_req_callback_data(subreq, struct tevent_req);
- state = tevent_req_data(req, struct proxy_http_req_state);
-
- ret = sssd_async_socket_init_recv(subreq, &state->sd);
- talloc_zfree(subreq);
- if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- "sssd_async_socket_init request failed: [%d]: %s.\n",
- ret, sss_strerror(ret));
-
- /* try next server if any */
- proxy_http_req_connect_step(req);
- return;
- }
-
- /* EOK */
- DEBUG(SSSDBG_TRACE_FUNC, "Connected to %s\n", state->hostent->name);
-
- state->fde = tevent_add_fd(state->ev, state, state->sd,
- TEVENT_FD_WRITE, proxy_fd_handler,
- req);
- if (!state->fde) {
- ret = EIO;
- goto done;
- }
-
- return;
-
-done:
- if (ret == EOK) {
- tevent_req_done(req);
- } else {
- tevent_req_error(req, ret);
- }
-}
-
-
-int proxy_http_req_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
- struct proxy_http_reply **reply)
-{
- struct proxy_http_req_state *state =
- tevent_req_data(req, struct proxy_http_req_state);
-
- TEVENT_REQ_RETURN_ON_ERROR(req);
-
- *reply = talloc_move(mem_ctx, &state->reply);
-
- return EOK;
-}
-
-static int proxy_http_req_state_destroy(void *data)
-{
- struct proxy_http_req_state *state =
- talloc_get_type(data, struct proxy_http_req_state);
-
- if (!state) return 0;
-
- if (state->sd != -1) {
- DEBUG(SSSDBG_TRACE_FUNC, "closing socket [%d]\n", state->sd);
- close(state->sd);
- state->sd = -1;
- }
-
- return 0;
-}
-
-static int proxy_wire_send(int fd, struct proxy_http_request *req)
-{
- struct sec_data data;
- int ret;
-
- data.data = req->data->data + req->written;
- data.length = req->data->length - req->written;
-
- ret = sec_send_data(fd, &data);
- if (ret != EOK && ret != EAGAIN) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- "sec_send_data failed [%d]: %s\n", ret, sss_strerror(ret));
- return ret;
- }
-
- req->written = req->data->length - data.length;
- return ret;
-}
-
-static void proxy_fd_send(void *data)
-{
- struct proxy_http_req_state *state;
- struct tevent_req * req;
- int ret;
-
- req = talloc_get_type(data, struct tevent_req);
- state = tevent_req_data(req, struct proxy_http_req_state);
-
- ret = proxy_wire_send(state->sd, &state->request);
- if (ret == EAGAIN) {
- /* not all data was sent, loop again */
- return;
- }
- if (ret != EOK) {
- DEBUG(SSSDBG_FATAL_FAILURE, "Failed to send data, aborting!\n");
- tevent_req_error(req, ret);
- return;
- }
-
- /* ok all sent, wait for reply now */
- TEVENT_FD_NOT_WRITEABLE(state->fde);
- TEVENT_FD_READABLE(state->fde);
- return;
-}
-
-static bool ph_received_data(struct proxy_http_reply *reply, size_t length)
-{
- reply->received += length;
- if (reply->received > SEC_REQUEST_MAX_SIZE) {
- DEBUG(SSSDBG_FATAL_FAILURE, "Request too big, aborting!\n");
- return true;
- }
- return false;
-}
-
-static void ph_append_string(TALLOC_CTX *memctx, char **dest,
- const char *src, size_t len)
-{
- if (*dest) {
- *dest = talloc_strndup_append_buffer(*dest, src, len);
- } else {
- *dest = talloc_strndup(memctx, src, len);
- }
-}
-
-static int ph_on_message_begin(http_parser *parser)
-{
- DEBUG(SSSDBG_TRACE_INTERNAL, "HTTP Message parsing begins\n");
- return 0;
-}
-
-#if ((HTTP_PARSER_VERSION_MAJOR >= 2) && (HTTP_PARSER_VERSION_MINOR >= 2))
-static int ph_on_status(http_parser *parser, const char *at, size_t length)
-{
- struct proxy_http_reply *reply =
- talloc_get_type(parser->data, struct proxy_http_reply);
-
- if (ph_received_data(reply, length)) return -1;
-
- ph_append_string(reply, &reply->reason_phrase, at, length);
- if (!reply->reason_phrase) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "Failed to store reason phrase, aborting client!\n");
- return -1;
- }
-
- return 0;
-}
-#endif
-
-static int ph_on_header_field(http_parser *parser,
- const char *at, size_t length)
-{
- struct proxy_http_reply *reply =
- talloc_get_type(parser->data, struct proxy_http_reply);
- int n = reply->num_headers;
-
- if (ph_received_data(reply, length)) return -1;
-
- if (!reply->headers) {
- reply->headers = talloc_zero_array(reply, struct sec_kvp, 10);
- } else if ((n % 10 == 0) &&
- (reply->headers[n - 1].value)) {
- reply->headers = talloc_realloc(reply, reply->headers,
- struct sec_kvp, n + 10);
- if (reply->headers) {
- memset(&reply->headers[n], 0, sizeof(struct sec_kvp) * 10);
- }
- }
- if (!reply->headers) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "Failed to store headers, aborting client!\n");
- return -1;
- }
-
- if (!n || reply->headers[n - 1].value) {
- /* new field */
- n++;
- }
- ph_append_string(reply->headers, &reply->headers[n - 1].name, at, length);
- if (!reply->headers[n - 1].name) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "Failed to store header name, aborting client!\n");
- return -1;
- }
-
- return 0;
-}
-
-static int ph_on_header_value(http_parser *parser,
- const char *at, size_t length)
-{
- struct proxy_http_reply *reply =
- talloc_get_type(parser->data, struct proxy_http_reply);
- int n = reply->num_headers;
-
- if (ph_received_data(reply, length)) return -1;
-
- if (!reply->headers) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "Invalid headers pointer, aborting client!\n");
- return -1;
- }
-
- if (reply->headers[n].name && !reply->headers[n].value) {
- /* we increment on new value */
- n = ++reply->num_headers;
- }
-
- ph_append_string(reply->headers, &reply->headers[n - 1].value, at, length);
- if (!reply->headers[n - 1].value) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "Failed to store header value, aborting client!\n");
- return -1;
- }
-
- return 0;
-}
-
-static int ph_on_headers_complete(http_parser *parser)
-{
- /* TODO: if message has no body we should return 1 */
- return 0;
-}
-
-static int ph_on_body(http_parser *parser, const char *at, size_t length)
-{
- struct proxy_http_reply *reply =
- talloc_get_type(parser->data, struct proxy_http_reply);
-
- if (ph_received_data(reply, length)) return -1;
-
- /* FIXME: body may be binary */
- ph_append_string(reply, &reply->body.data, at, length);
- if (!reply->body.data) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "Failed to store body, aborting!\n");
- return -1;
- }
- reply->body.length += length;
-
- return 0;
-}
-
-static int ph_on_message_complete(http_parser *parser)
-{
- struct proxy_http_reply *reply =
- talloc_get_type(parser->data, struct proxy_http_reply);
-
- reply->status_code = parser->status_code;
- reply->complete = true;
-
- return 0;
-}
-
-static http_parser_settings ph_callbacks = {
- .on_message_begin = ph_on_message_begin,
-#if ((HTTP_PARSER_VERSION_MAJOR >= 2) && (HTTP_PARSER_VERSION_MINOR >= 2))
- .on_status = ph_on_status,
-#endif
- .on_header_field = ph_on_header_field,
- .on_header_value = ph_on_header_value,
- .on_headers_complete = ph_on_headers_complete,
- .on_body = ph_on_body,
- .on_message_complete = ph_on_message_complete
-};
-
-static void proxy_fd_recv(void *data)
-{
- char buffer[SEC_PACKET_MAX_RECV_SIZE];
- struct sec_data packet = { buffer,
- SEC_PACKET_MAX_RECV_SIZE };
- struct proxy_http_req_state *state;
- struct tevent_req *req;
- bool must_complete = false;
- int ret;
-
- req = talloc_get_type(data, struct tevent_req);
- state = tevent_req_data(req, struct proxy_http_req_state);
-
- if (!state->reply) {
- /* A new reply */
- state->reply = talloc_zero(state, struct proxy_http_reply);
- if (!state->reply) {
- DEBUG(SSSDBG_FATAL_FAILURE, "Failed to allocate reply, aborting!\n");
- tevent_req_error(req, ENOMEM);
- return;
- }
- http_parser_init(&state->reply->parser, HTTP_RESPONSE);
- state->reply->parser.data = state->reply;
- }
-
- ret = sec_recv_data(state->sd, &packet);
- switch (ret) {
- case ENODATA:
- DEBUG(SSSDBG_TRACE_ALL, "Server closed connection.\n");
- /* if we got no content length and the request is not complete,
- * then 0 length will indicate EOF to the parser, otherwise we
- * have an error */
- must_complete = true;
- break;
- case EAGAIN:
- DEBUG(SSSDBG_TRACE_ALL,
- "Interrupted before any data could be read, retry later\n");
- return;
- case EOK:
- /* all fine */
- break;
- default:
- DEBUG(SSSDBG_FATAL_FAILURE,
- "Failed to receive data (%d, %s), aborting\n",
- ret, sss_strerror(ret));
- tevent_req_error(req, EIO);
- return;
- }
-
- ret = http_parser_execute(&state->reply->parser, &ph_callbacks,
- packet.data, packet.length);
- if (ret != packet.length) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "Failed to parse request, aborting!\n");
- tevent_req_error(req, EIO);
- return;
- }
-
- if (!state->reply->complete) {
- if (must_complete) {
- tevent_req_error(req, EIO);
- }
- return;
- }
-
- /* do not read anymore, server is done sending */
- TEVENT_FD_NOT_READABLE(state->fde);
- tevent_req_done(req);
-}
-
-static void proxy_fd_handler(struct tevent_context *ev, struct tevent_fd *fde,
- uint16_t flags, void *data)
-{
- if (flags & TEVENT_FD_READ) {
- proxy_fd_recv(data);
- } else if (flags & TEVENT_FD_WRITE) {
- proxy_fd_send(data);
- }
-}
-
struct proxy_secret_state {
struct tevent_context *ev;
struct sec_req_ctx *secreq;
--
2.12.2

View File

@ -1,253 +0,0 @@
From 720e1a5b95a953a0f1c8315bbb7c9c1edf9fb417 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Tue, 28 Feb 2017 11:47:32 +0100
Subject: [PATCH 88/97] secrets: allow to configure certificate check
Some users may want to use TLS with unverified peer (for example if
they use self-signed certificate) or if unverified hostname (if
certificate hostname does not match with the real hostname). On the
other side it may be useful to point to a directory containing custom
certificate authorities.
This patch add three new options to secrets responder:
verify_peer => peer's certificate must be valid
verify_host => hostnames must match
capath => path to directory containing CA certs
cacert => ca certificate
cert => client certificate
key => client private key
Resolves:
https://pagure.io/SSSD/sssd/issue/3192
Reviewed-by: Simo Sorce <simo@redhat.com>
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
---
src/config/SSSDConfig/__init__.py.in | 6 +++
src/config/cfg_rules.ini | 6 +++
src/config/etc/sssd.api.conf | 6 +++
src/man/sssd-secrets.5.xml | 76 ++++++++++++++++++++++++++++++++++++
src/responder/secrets/proxy.c | 55 ++++++++++++++++++++++++++
5 files changed, 149 insertions(+)
diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in
index a29d51e0ddffc520107a309d862346fb4d4f5f80..54ad722f07ef91a13a0df278ffd2b1c166bc8d36 100644
--- a/src/config/SSSDConfig/__init__.py.in
+++ b/src/config/SSSDConfig/__init__.py.in
@@ -137,6 +137,12 @@ option_strings = {
'forward_headers': _('The list of the headers to forward to the Custodia server together with the request'),
'username': _('The username to use when authenticating to a Custodia server using basic_auth'),
'password': _('The password to use when authenticating to a Custodia server using basic_auth'),
+ 'verify_peer': _('If true peer\'s certificate is verified if proxy_url uses https protocol'),
+ 'verify_host': _('If false peer\'s certificate may contain different hostname then proxy_url when https protocol is used'),
+ 'capath': _('Path to directory where certificate authority certificates are stored'),
+ 'cacert': _('Path to file containing server\'s CA certificate'),
+ 'cert': _('Path to file containing client\'s certificate'),
+ 'key': _('Path to file containing client\'s private key'),
# [provider]
'id_provider' : _('Identity provider'),
diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini
index 1a749db754cedd87f263f7ae596d6f8238bb4357..e47ff33242d6a9e5979fe0eb8eea14c2af28685a 100644
--- a/src/config/cfg_rules.ini
+++ b/src/config/cfg_rules.ini
@@ -265,6 +265,12 @@ option = auth_header_value
option = forward_headers
option = username
option = password
+option = verify_peer
+option = verify_host
+option = capath
+option = cacert
+option = cert
+option = key
# KCM responder
[rule/allowed_kcm_options]
diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf
index a1a0c2992925a4c7df86832117eec2a0cf7894c9..f86589ecefa0b9e046aba781ded107f8e94395d6 100644
--- a/src/config/etc/sssd.api.conf
+++ b/src/config/etc/sssd.api.conf
@@ -114,6 +114,12 @@ auth_header_value = str, None, false
forward_headers = list, None, false
username = str, None, false
password = str, None, false
+verify_peer = bool, None, false
+verify_host = bool, None, false
+capath = str, None, false
+cacert = str, None, false
+cert = str, None, false
+key = str, None, false
[provider]
#Available provider types
diff --git a/src/man/sssd-secrets.5.xml b/src/man/sssd-secrets.5.xml
index 80e9c405921e1fb46a3d172d9873deebfa5ed2ce..44a86c3fb56a8bdebebd01e9f49ad171986282a4 100644
--- a/src/man/sssd-secrets.5.xml
+++ b/src/man/sssd-secrets.5.xml
@@ -273,6 +273,82 @@ systemctl enable sssd-secrets.service
</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>verify_peer (boolean)</term>
+ <listitem>
+ <para>
+ Whether peer's certificate should be verified and valid
+ if HTTPS protocol is used with the proxy provider.
+ </para>
+ <para>
+ Default: true
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>verify_host (boolean)</term>
+ <listitem>
+ <para>
+ Whether peer's hostname must match with hostname in
+ its certificate if HTTPS protocol is used with the
+ proxy provider.
+ </para>
+ <para>
+ Default: true
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>capath (string)</term>
+ <listitem>
+ <para>
+ Path to directory containing stored certificate authority
+ certificates. System default path is used if this option is
+ not set.
+ </para>
+ <para>
+ Default: not set
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>cacert (string)</term>
+ <listitem>
+ <para>
+ Path to file containing server's certificate authority
+ certificate. If this option is not set then the CA's
+ certificate is looked up in <quote>capath</quote>.
+ </para>
+ <para>
+ Default: not set
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>cert (string)</term>
+ <listitem>
+ <para>
+ Path to file containing client's certificate if required
+ by the server. This file may also contain private key or
+ the private key may be in separate file set with
+ <quote>key</quote>.
+ </para>
+ <para>
+ Default: not set
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>key (string)</term>
+ <listitem>
+ <para>
+ Path to file containing client's private key.
+ </para>
+ <para>
+ Default: not set
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect1>
<refsect1 id='restapi'>
diff --git a/src/responder/secrets/proxy.c b/src/responder/secrets/proxy.c
index 3c495716010ac468c9e2f1fb6356529a8dbdc614..240a1de1e431d511a1eca24d8b463c37ba893e7b 100644
--- a/src/responder/secrets/proxy.c
+++ b/src/responder/secrets/proxy.c
@@ -59,6 +59,13 @@ struct proxy_cfg {
struct pat_basic_auth basic;
struct pat_header header;
} auth;
+
+ char *key;
+ char *cert;
+ char *cacert;
+ char *capath;
+ bool verify_peer;
+ bool verify_host;
};
static int proxy_get_config_string(struct proxy_context *pctx,
@@ -129,6 +136,38 @@ static int proxy_sec_get_cfg(struct proxy_context *pctx,
}
}
+ ret = confdb_get_bool(pctx->cdb, secreq->cfg_section, "verify_peer",
+ true, &cfg->verify_peer);
+ if (ret) goto done;
+ DEBUG(SSSDBG_CONF_SETTINGS, "verify_peer: %s\n",
+ (&cfg->verify_peer ? "true" : "false"));
+
+ ret = confdb_get_bool(pctx->cdb, secreq->cfg_section, "verify_host",
+ true, &cfg->verify_host);
+ if (ret) goto done;
+ DEBUG(SSSDBG_CONF_SETTINGS, "verify_host: %s\n",
+ (&cfg->verify_host ? "true" : "false"));
+
+ ret = proxy_get_config_string(pctx, cfg, false, secreq,
+ "capath", &cfg->capath);
+ if (ret) goto done;
+ DEBUG(SSSDBG_CONF_SETTINGS, "capath: %s\n", cfg->capath);
+
+ ret = proxy_get_config_string(pctx, cfg, false, secreq,
+ "cacert", &cfg->cacert);
+ if (ret) goto done;
+ DEBUG(SSSDBG_CONF_SETTINGS, "cacert: %s\n", cfg->cacert);
+
+ ret = proxy_get_config_string(pctx, cfg, false, secreq,
+ "cert", &cfg->cert);
+ if (ret) goto done;
+ DEBUG(SSSDBG_CONF_SETTINGS, "cert: %s\n", cfg->cert);
+
+ ret = proxy_get_config_string(pctx, cfg, false, secreq,
+ "key", &cfg->key);
+ if (ret) goto done;
+ DEBUG(SSSDBG_CONF_SETTINGS, "key: %s\n", cfg->key);
+
ret = confdb_get_string_as_list(pctx->cdb, cfg, secreq->cfg_section,
"forward_headers", &cfg->fwd_headers);
if ((ret != 0) && (ret != ENOENT)) goto done;
@@ -385,6 +424,22 @@ static errno_t proxy_http_create_request(TALLOC_CTX *mem_ctx,
goto done;
}
+ /* Set TLS settings to verify peer.
+ * This has no effect for HTTP protocol so we can set it anyway. */
+ ret = tcurl_req_verify_peer(tcurl_req, pcfg->capath, pcfg->cacert,
+ pcfg->verify_peer, pcfg->verify_host);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ /* Set client's certificate if required. */
+ if (pcfg->cert != NULL) {
+ ret = tcurl_req_set_client_cert(tcurl_req, pcfg->cert, pcfg->key);
+ if (ret != EOK) {
+ goto done;
+ }
+ }
+
talloc_steal(tcurl_req, body);
*_tcurl_req = talloc_steal(mem_ctx, tcurl_req);
--
2.12.2

View File

@ -1,38 +0,0 @@
From af026ea6a6e812b7d6c5c889dda64ba7b7c433ee Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Tue, 28 Feb 2017 13:58:20 +0100
Subject: [PATCH 89/97] secrets: support HTTP basic authentication with proxy
provider
Even though configuration options auth_type = basic, username and password
are read they were not used anywhere prior this patch.
Reviewed-by: Simo Sorce <simo@redhat.com>
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
---
src/responder/secrets/proxy.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/src/responder/secrets/proxy.c b/src/responder/secrets/proxy.c
index 240a1de1e431d511a1eca24d8b463c37ba893e7b..fd96e985c897e2cb470a9b5d6eecbd34350fb7d2 100644
--- a/src/responder/secrets/proxy.c
+++ b/src/responder/secrets/proxy.c
@@ -440,6 +440,15 @@ static errno_t proxy_http_create_request(TALLOC_CTX *mem_ctx,
}
}
+ /* Set basic authentication if required. */
+ if (pcfg->auth_type == PAT_BASIC_AUTH) {
+ ret = tcurl_req_http_basic_auth(tcurl_req, pcfg->auth.basic.username,
+ pcfg->auth.basic.password);
+ if (ret != EOK) {
+ goto done;
+ }
+ }
+
talloc_steal(tcurl_req, body);
*_tcurl_req = talloc_steal(mem_ctx, tcurl_req);
--
2.12.2

View File

@ -1,28 +0,0 @@
From db826f57b4c2ee814823057cc536386889f7aa1d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Wed, 15 Mar 2017 13:27:59 +0100
Subject: [PATCH 90/97] secrets: fix debug message
Reviewed-by: Simo Sorce <simo@redhat.com>
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
---
src/responder/secrets/secsrv_cmd.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/responder/secrets/secsrv_cmd.c b/src/responder/secrets/secsrv_cmd.c
index 70679ec0398fca25cfb0525772f539526a0eb3ff..b88680c3d7c3105d160de5c78e6d981b852318b9 100644
--- a/src/responder/secrets/secsrv_cmd.c
+++ b/src/responder/secrets/secsrv_cmd.c
@@ -451,7 +451,8 @@ int sec_send_data(int fd, struct sec_data *data)
data->length -= len;
data->data += len;
- DEBUG(SSSDBG_TRACE_INTERNAL, "sent %zu bytes\n", data->length);
+ DEBUG(SSSDBG_TRACE_INTERNAL, "sent %zu bytes, %zu bytes remaining\n",
+ len, data->length);
return EOK;
}
--
2.12.2

View File

@ -1,111 +0,0 @@
From 13d720de13e490850c1139eea865bcd5195a2630 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Wed, 15 Mar 2017 15:15:08 +0100
Subject: [PATCH 91/97] secrets: always add Content-Length header
If custodia server does not reply with Content-Length header, curl may
wait for non-existing body of http reply if such body does not exist
(for example during POST operation when creating a container).
Reviewed-by: Simo Sorce <simo@redhat.com>
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
---
src/responder/secrets/providers.c | 72 ++++++++++++++++++++++++++++++++++++---
1 file changed, 68 insertions(+), 4 deletions(-)
diff --git a/src/responder/secrets/providers.c b/src/responder/secrets/providers.c
index 80a443d91135447ec8ce8d424b692a6d7e26a907..a27fb720b394e7c76d1b65f656146bcd00755449 100644
--- a/src/responder/secrets/providers.c
+++ b/src/responder/secrets/providers.c
@@ -388,20 +388,84 @@ int sec_http_reply_with_headers(TALLOC_CTX *mem_ctx, struct sec_data *reply,
return EOK;
}
+static errno_t
+sec_http_iobuf_split(struct sss_iobuf *response,
+ const char **headers,
+ const char **body)
+{
+ const char *data = (const char *)sss_iobuf_get_data(response);
+ char *delim;
+
+ /* The last header ends with \r\n and then comes \r\n again as a separator
+ * of body from headers. We can use this to find this point. */
+ delim = strstr(data, "\r\n\r\n");
+ if (delim == NULL) {
+ return EINVAL;
+ }
+
+ /* Skip to the body delimiter. */
+ delim = delim + sizeof("\r\n") - 1;
+
+ /* Replace \r\n with zeros turning data into:
+ * from HEADER\r\nBODY into HEADER\0\0BODY format. */
+ delim[0] = '\0';
+ delim[1] = '\0';
+
+ /* Split the buffer. */
+ *headers = data;
+ *body = delim + 2;
+
+ return 0;
+}
+
+static const char *
+sec_http_iobuf_add_content_length(TALLOC_CTX *mem_ctx,
+ const char *headers,
+ size_t body_len)
+{
+ /* If Content-Length is already present we do nothing. */
+ if (strstr(headers, "Content-Length:") != NULL) {
+ return headers;
+ }
+
+ return talloc_asprintf(mem_ctx, "%sContent-Length: %zu\r\n",
+ headers, body_len);
+}
+
errno_t sec_http_reply_iobuf(TALLOC_CTX *mem_ctx,
struct sec_data *reply,
int response_code,
struct sss_iobuf *response)
{
+ const char *headers;
+ const char *body;
+ size_t body_len;
+ errno_t ret;
+
DEBUG(SSSDBG_TRACE_LIBS, "HTTP reply %d\n", response_code);
- reply->data = (char *)sss_iobuf_get_data(response);
- reply->length = sss_iobuf_get_len(response);
+ ret = sec_http_iobuf_split(response, &headers, &body);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Unexpected HTTP reply, returning what we got from server\n");
+ reply->data = (char *)sss_iobuf_get_data(response);
+ reply->length = sss_iobuf_get_len(response);
- talloc_steal(mem_ctx, reply->data);
+ return EOK;
+ }
+ /* Add Content-Length header if not present so client does not await
+ * not-existing incoming data. */
+ body_len = strlen(body);
+ headers = sec_http_iobuf_add_content_length(mem_ctx, headers, body_len);
+ if (headers == NULL) {
+ return ENOMEM;
+ }
+
+ reply->length = strlen(headers) + sizeof("\r\n") - 1 + body_len;
+ reply->data = talloc_asprintf(mem_ctx, "%s\r\n%s", headers, body);
if (reply->data == NULL) {
- return EINVAL;
+ return ENOMEM;
}
return EOK;
--
2.12.2

View File

@ -1,39 +0,0 @@
From 18e4fe9d836e8f7bee52724374ffc0011172329f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Tue, 28 Mar 2017 15:26:52 +0200
Subject: [PATCH 92/97] sss_iobuf: fix 'read' shadows a global declaration
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
---
src/util/sss_iobuf.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/util/sss_iobuf.c b/src/util/sss_iobuf.c
index fc288d2df2bfaaba393dd490d4da8976de804cb5..518713e4cc3dd99627a3a4450f235cbbc69ed3a2 100644
--- a/src/util/sss_iobuf.c
+++ b/src/util/sss_iobuf.c
@@ -188,15 +188,15 @@ errno_t sss_iobuf_read_len(struct sss_iobuf *iobuf,
size_t len,
uint8_t *_buf)
{
- size_t read;
+ size_t read_bytes;
errno_t ret;
- ret = sss_iobuf_read(iobuf, len, _buf, &read);
+ ret = sss_iobuf_read(iobuf, len, _buf, &read_bytes);
if (ret != EOK) {
return ret;
}
- if (read != len) {
+ if (read_bytes != len) {
return ENOBUFS;
}
--
2.12.2

View File

@ -1,28 +0,0 @@
From dc186bfe90665c13d589b3b4efd9009293e62c46 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Wed, 29 Mar 2017 13:28:49 +0200
Subject: [PATCH 93/97] configure: fix typo
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
---
src/external/libhttp_parser.m4 | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/external/libhttp_parser.m4 b/src/external/libhttp_parser.m4
index 504bdf0f66c95b3d224c677a205a46e6f8b44726..3a5ef0dbbc63423ad8e960d72e97ec4fb4481dd1 100644
--- a/src/external/libhttp_parser.m4
+++ b/src/external/libhttp_parser.m4
@@ -17,6 +17,6 @@ AS_IF([test x"$found_http_parser" != xyes],
],
[-L$sss_extra_libdir -lhttp_parser_strict])],
[AC_MSG_ERROR([
-You must have the header file http_parse.h installed to build sssd
+You must have the header file http_parser.h installed to build sssd
with secrets responder. If you want to build sssd without secret responder
then specify --without-secrets when running configure.])])])
--
2.12.2

View File

@ -1,87 +0,0 @@
From 5231ba679402eeb0705a3ecd41f97fdd67d42a69 Mon Sep 17 00:00:00 2001
From: David Kupka <dkupka@redhat.com>
Date: Fri, 31 Mar 2017 21:31:23 +0200
Subject: [PATCH 94/97] libsss_certmap: Accept certificate with data before
header
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
According to RFC 7468 parser must not fail when some data are present
before the encapsulation boundary. sss_cert_pem_to_der didn't respect
this and refused valid input. Changing it's code to first locate
the certificate header fixes the issue.
Resolves:
https://pagure.io/SSSD/sssd/issue/3354
Reviewed-by: Sumit Bose <sbose@redhat.com>
Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
---
src/tests/cmocka/test_cert_utils.c | 16 ++++++++++++++++
src/util/cert/nss/cert.c | 9 +++++----
2 files changed, 21 insertions(+), 4 deletions(-)
diff --git a/src/tests/cmocka/test_cert_utils.c b/src/tests/cmocka/test_cert_utils.c
index 5830131754e4cf318273151b586ef36d6a349829..8003d8daa7063773cf8b37c46ac8759e3a38736f 100644
--- a/src/tests/cmocka/test_cert_utils.c
+++ b/src/tests/cmocka/test_cert_utils.c
@@ -128,6 +128,13 @@ const uint8_t test_cert_der[] = {
"lBPDhfTVcWXQwN385uycW/ARtSzzSME2jKKWSIQ=\n" \
"-----END CERTIFICATE-----\n"
+#define TEST_CERT_PEM_WITH_METADATA "Bag Attributes\n" \
+" friendlyName: ipa-devel\n" \
+" localKeyID: 8E 0D 04 1F BC 13 73 54 00 8F 65 57 D7 A8 AF 34 0C 18 B3 99\n" \
+"subject= /O=IPA.DEVEL/CN=ipa-devel.ipa.devel\n" \
+"issuer= /O=IPA.DEVEL/CN=Certificate Authority\n" \
+TEST_CERT_PEM
+
#define TEST_CERT_DERB64 \
"MIIECTCCAvGgAwIBAgIBCTANBgkqhkiG9w0BAQsFADA0MRIwEAYDVQQKDAlJUEEu" \
"REVWRUwxHjAcBgNVBAMMFUNlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNTA0Mjgx" \
@@ -219,6 +226,15 @@ void test_sss_cert_pem_to_der(void **state)
assert_memory_equal(der, test_cert_der, der_size);
talloc_free(der);
+
+ /* https://pagure.io/SSSD/sssd/issue/3354
+ https://tools.ietf.org/html/rfc7468#section-2 */
+ ret = sss_cert_pem_to_der(ts, TEST_CERT_PEM_WITH_METADATA, &der, &der_size);
+ assert_int_equal(ret, EOK);
+ assert_int_equal(sizeof(test_cert_der), der_size);
+ assert_memory_equal(der, test_cert_der, der_size);
+
+ talloc_free(der);
}
void test_sss_cert_derb64_to_pem(void **state)
diff --git a/src/util/cert/nss/cert.c b/src/util/cert/nss/cert.c
index 9d31cfe9b584aa4f87a60ffec03dcf391fe43067..93d4e04220be71ce5823b077525d9f6676e5b763 100644
--- a/src/util/cert/nss/cert.c
+++ b/src/util/cert/nss/cert.c
@@ -147,16 +147,17 @@ errno_t sss_cert_pem_to_der(TALLOC_CTX *mem_ctx, const char *pem,
return EINVAL;
}
+ if ((pem = strstr(pem, NS_CERT_HEADER)) == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Missing PEM header.");
+ return EINVAL;
+ }
+
pem_len = strlen(pem);
if (pem_len <= NS_CERT_HEADER_LEN + NS_CERT_TRAILER_LEN) {
DEBUG(SSSDBG_CRIT_FAILURE, "PEM data too short.\n");
return EINVAL;
}
- if (strncmp(pem, NS_CERT_HEADER, NS_CERT_HEADER_LEN) != 0) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Wrong PEM header.\n");
- return EINVAL;
- }
if (pem[NS_CERT_HEADER_LEN] != '\n') {
DEBUG(SSSDBG_CRIT_FAILURE, "Missing newline in PEM data.\n");
return EINVAL;
--
2.12.2

View File

@ -1,48 +0,0 @@
From 84fecc2fd535030bc56b5046ba2a1ba95c46bc34 Mon Sep 17 00:00:00 2001
From: Lukas Slebodnik <lslebodn@redhat.com>
Date: Fri, 24 Mar 2017 10:37:50 +0100
Subject: [PATCH 95/97] BUILD: Fix compilation of libsss_certmap with libcrypto
CC src/lib/certmap/libsss_certmap_la-sss_cert_content_nss.lo
src/lib/certmap/sss_cert_content_nss.c:25:18:
fatal error: cert.h: No such file or directory
#include <cert.h>
^
compilation terminated.
Reviewed-by: Sumit Bose <sbose@redhat.com>
---
Makefile.am | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/Makefile.am b/Makefile.am
index 4a414f77df999b8b1d81f663fcc18dbd2d6d2dc4..5264183cd199be464e5e99d2ab31ba4fcd77c5ec 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1787,7 +1787,6 @@ libsss_certmap_la_DEPENDENCIES = src/lib/certmap/sss_certmap.exports
libsss_certmap_la_SOURCES = \
src/lib/certmap/sss_certmap.c \
src/lib/certmap/sss_certmap_attr_names.c \
- src/lib/certmap/sss_cert_content_nss.c \
src/lib/certmap/sss_certmap_krb5_match.c \
src/lib/certmap/sss_certmap_ldap_mapping.c \
src/util/util_ext.c \
@@ -1806,6 +1805,7 @@ libsss_certmap_la_LDFLAGS = \
if HAVE_NSS
libsss_certmap_la_SOURCES += \
+ src/lib/certmap/sss_cert_content_nss.c \
src/util/crypto/nss/nss_base64.c \
src/util/cert/nss/cert.c \
src/util/crypto/nss/nss_util.c \
@@ -1814,6 +1814,7 @@ libsss_certmap_la_CFLAGS += $(NSS_CFLAGS)
libsss_certmap_la_LIBADD += $(NSS_LIBS)
else
libsss_certmap_la_SOURCES += \
+ src/lib/certmap/sss_cert_content_crypto.c \
src/util/crypto/libcrypto/crypto_base64.c \
src/util/cert/libcrypto/cert.c \
$(NULL)
--
2.12.2

View File

@ -1,68 +0,0 @@
From 05c2c3047912fca1c1a35ab1c8d3157b05383495 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Mon, 3 Apr 2017 12:56:01 +0200
Subject: [PATCH 96/97] responders: do not leak selinux context on clients
destruction
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The SELinux context created in get_client_cred is not talloc bound and
we were leaking it if available with each client's destruction.
Resolves:
https://pagure.io/SSSD/sssd/issue/3360
Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
---
src/responder/common/responder_common.c | 20 +++++++++++++++++++-
1 file changed, 19 insertions(+), 1 deletion(-)
diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c
index 154d7dc7718c437d10e152fcba98161e2034fb14..67e1deefdfde19c95a68029b11099579d851513f 100644
--- a/src/responder/common/responder_common.c
+++ b/src/responder/common/responder_common.c
@@ -97,7 +97,7 @@ static errno_t get_client_cred(struct cli_ctx *cctx)
SEC_CTX secctx;
int ret;
- cctx->creds = talloc(cctx, struct cli_creds);
+ cctx->creds = talloc_zero(cctx, struct cli_creds);
if (!cctx->creds) return ENOMEM;
#ifdef HAVE_UCRED
@@ -464,6 +464,22 @@ static void client_fd_handler(struct tevent_context *ev,
static errno_t setup_client_idle_timer(struct cli_ctx *cctx);
+static int cli_ctx_destructor(struct cli_ctx *cctx)
+{
+ if (cctx->creds == NULL) {
+ return 0;
+ }
+
+ if (cctx->creds->selinux_ctx == NULL) {
+ return 0;
+ }
+
+ SELINUX_context_free(cctx->creds->selinux_ctx);
+ cctx->creds->selinux_ctx = NULL;
+
+ return 0;
+}
+
struct accept_fd_ctx {
struct resp_ctx *rctx;
bool is_private;
@@ -520,6 +536,8 @@ static void accept_fd_handler(struct tevent_context *ev,
return;
}
+ talloc_set_destructor(cctx, cli_ctx_destructor);
+
len = sizeof(cctx->addr);
cctx->cfd = accept(fd, (struct sockaddr *)&cctx->addr, &len);
if (cctx->cfd == -1) {
--
2.12.2

View File

@ -1,88 +0,0 @@
From b07bcd8b99590bd404733fa7ff1add37c55126bc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Mon, 3 Apr 2017 12:09:44 +0200
Subject: [PATCH 97/97] ipa_s2n_get_acct_info_send: provide correct req_input
name
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
To avoid crash.
Resolves:
https://pagure.io/SSSD/sssd/issue/3358
Reviewed-by: Sumit Bose <sbose@redhat.com>
Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
---
src/providers/ipa/ipa_s2n_exop.c | 40 ++++++++++++++++++++++++++++++++++++----
1 file changed, 36 insertions(+), 4 deletions(-)
diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
index 8a3391b4093f1547d84fe44a0f24b1d063d1e28c..2173db357700499a6140aa61841e443139981483 100644
--- a/src/providers/ipa/ipa_s2n_exop.c
+++ b/src/providers/ipa/ipa_s2n_exop.c
@@ -1054,6 +1054,33 @@ static const char *ipa_s2n_reqtype2str(enum request_types request_type)
return "Unknown request type";
}
+static const char *ipa_s2n_reqinp2str(TALLOC_CTX *mem_ctx,
+ struct req_input *req_input)
+{
+ const char *str = NULL;
+
+ switch (req_input->type) {
+ case REQ_INP_NAME:
+ str = talloc_strdup(mem_ctx, req_input->inp.name);
+ break;
+ case REQ_INP_SECID:
+ str = talloc_strdup(mem_ctx, req_input->inp.secid);
+ break;
+ case REQ_INP_CERT:
+ str = talloc_strdup(mem_ctx, req_input->inp.cert);
+ break;
+ case REQ_INP_ID:
+ str = talloc_asprintf(mem_ctx, "%u", req_input->inp.id);
+ break;
+ }
+
+ if (str == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory!\n");
+ }
+
+ return str;
+}
+
struct ipa_s2n_get_list_state {
struct tevent_context *ev;
struct ipa_id_ctx *ipa_ctx;
@@ -1410,6 +1437,7 @@ struct tevent_req *ipa_s2n_get_acct_info_send(TALLOC_CTX *mem_ctx,
struct tevent_req *req;
struct tevent_req *subreq;
struct berval *bv_req = NULL;
+ const char *input;
int ret = EFAULT;
bool is_v1 = false;
@@ -1454,10 +1482,14 @@ struct tevent_req *ipa_s2n_get_acct_info_send(TALLOC_CTX *mem_ctx,
goto fail;
}
- DEBUG(SSSDBG_TRACE_FUNC, "Sending request_type: [%s] for trust user [%s] "
- "to IPA server\n",
- ipa_s2n_reqtype2str(state->request_type),
- req_input->inp.name);
+ if (DEBUG_IS_SET(SSSDBG_TRACE_FUNC)) {
+ input = ipa_s2n_reqinp2str(state, req_input);
+ DEBUG(SSSDBG_TRACE_FUNC,
+ "Sending request_type: [%s] for trust user [%s] to IPA server\n",
+ ipa_s2n_reqtype2str(state->request_type),
+ input);
+ talloc_zfree(input);
+ }
subreq = ipa_s2n_exop_send(state, state->ev, state->sh, is_v1,
state->exop_timeout, bv_req);
--
2.12.2

View File

@ -1,210 +0,0 @@
From 78a08d30b5fbf6e1e3b589e0cf67022e0c1faa33 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
Date: Wed, 8 Feb 2017 12:01:37 +0100
Subject: [PATCH] selinux: Do not fail if SELinux is not managed
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Previously we failed if semanage_is_managed returned 0 or -1 (not
managed or error). With this patch we only fail in case of error and
continue normally if selinux is not managed by libsemanage at all.
Resolves:
https://fedorahosted.org/sssd/ticket/3297
Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
---
Makefile.am | 1 +
src/providers/ipa/selinux_child.c | 9 ++++--
src/util/sss_semanage.c | 61 +++++++++++++++++++++++++--------------
src/util/util_errors.c | 1 +
src/util/util_errors.h | 1 +
5 files changed, 49 insertions(+), 24 deletions(-)
diff --git a/Makefile.am b/Makefile.am
index 5264183cd..d45c0ff75 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -4040,6 +4040,7 @@ selinux_child_SOURCES = \
src/util/atomic_io.c \
src/util/util.c \
src/util/util_ext.c \
+ src/util/util_errors.c
$(NULL)
selinux_child_CFLAGS = \
$(AM_CFLAGS) \
diff --git a/src/providers/ipa/selinux_child.c b/src/providers/ipa/selinux_child.c
index 380005c7a..f8dd3954a 100644
--- a/src/providers/ipa/selinux_child.c
+++ b/src/providers/ipa/selinux_child.c
@@ -174,14 +174,19 @@ static bool seuser_needs_update(struct input_buffer *ibuf)
ret = get_seuser(ibuf, ibuf->username, &db_seuser, &db_mls_range);
DEBUG(SSSDBG_TRACE_INTERNAL,
- "get_seuser: ret: %d seuser: %s mls: %s\n",
- ret, db_seuser ? db_seuser : "unknown",
+ "get_seuser: ret: %d msg: [%s] seuser: %s mls: %s\n",
+ ret, sss_strerror(ret),
+ db_seuser ? db_seuser : "unknown",
db_mls_range ? db_mls_range : "unknown");
if (ret == EOK && db_seuser && db_mls_range &&
strcmp(db_seuser, ibuf->seuser) == 0 &&
strcmp(db_mls_range, ibuf->mls_range) == 0) {
needs_update = false;
}
+ /* OR */
+ if (ret == ERR_SELINUX_NOT_MANAGED) {
+ needs_update = false;
+ }
talloc_free(db_seuser);
talloc_free(db_mls_range);
diff --git a/src/util/sss_semanage.c b/src/util/sss_semanage.c
index fe06bee1d..0da97aad4 100644
--- a/src/util/sss_semanage.c
+++ b/src/util/sss_semanage.c
@@ -73,7 +73,7 @@ static void sss_semanage_close(semanage_handle_t *handle)
semanage_handle_destroy(handle);
}
-static semanage_handle_t *sss_semanage_init(void)
+static int sss_semanage_init(semanage_handle_t **_handle)
{
int ret;
semanage_handle_t *handle = NULL;
@@ -81,7 +81,8 @@ static semanage_handle_t *sss_semanage_init(void)
handle = semanage_handle_create();
if (!handle) {
DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create SELinux management handle\n");
- return NULL;
+ ret = EIO;
+ goto done;
}
semanage_msg_set_callback(handle,
@@ -89,28 +90,41 @@ static semanage_handle_t *sss_semanage_init(void)
NULL);
ret = semanage_is_managed(handle);
- if (ret != 1) {
- DEBUG(SSSDBG_CRIT_FAILURE, "SELinux policy not managed\n");
- goto fail;
+ if (ret == 0) {
+ DEBUG(SSSDBG_TRACE_FUNC, "SELinux policy not managed via libsemanage\n");
+ ret = ERR_SELINUX_NOT_MANAGED;
+ goto done;
+ } else if (ret == -1) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Call to semanage_is_managed failed\n");
+ ret = EIO;
+ goto done;
}
ret = semanage_access_check(handle);
if (ret < SEMANAGE_CAN_READ) {
DEBUG(SSSDBG_CRIT_FAILURE, "Cannot read SELinux policy store\n");
- goto fail;
+ ret = EACCES;
+ goto done;
}
ret = semanage_connect(handle);
if (ret != 0) {
DEBUG(SSSDBG_CRIT_FAILURE,
"Cannot estabilish SELinux management connection\n");
- goto fail;
+ ret = EIO;
+ goto done;
}
- return handle;
-fail:
- sss_semanage_close(handle);
- return NULL;
+ ret = EOK;
+
+done:
+ if (ret != EOK) {
+ sss_semanage_close(handle);
+ } else {
+ *_handle = handle;
+ }
+
+ return ret;
}
static int sss_semanage_user_add(semanage_handle_t *handle,
@@ -228,10 +242,11 @@ int set_seuser(const char *login_name, const char *seuser_name,
return EOK;
}
- handle = sss_semanage_init();
- if (!handle) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Cannot init SELinux management\n");
- ret = EIO;
+ ret = sss_semanage_init(&handle);
+ if (ret == ERR_SELINUX_NOT_MANAGED) {
+ goto done;
+ } else if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create SELinux handle\n");
goto done;
}
@@ -295,10 +310,11 @@ int del_seuser(const char *login_name)
int ret;
int exists = 0;
- handle = sss_semanage_init();
- if (!handle) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Cannot init SELinux management\n");
- ret = EIO;
+ ret = sss_semanage_init(&handle);
+ if (ret == ERR_SELINUX_NOT_MANAGED) {
+ goto done;
+ } else if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create SELinux handle\n");
goto done;
}
@@ -377,10 +393,11 @@ int get_seuser(TALLOC_CTX *mem_ctx, const char *login_name,
semanage_seuser_t *sm_user = NULL;
semanage_seuser_key_t *sm_key = NULL;
- sm_handle = sss_semanage_init();
- if (sm_handle == NULL) {
+ ret = sss_semanage_init(&sm_handle);
+ if (ret == ERR_SELINUX_NOT_MANAGED) {
+ goto done;
+ } else if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create SELinux handle\n");
- ret = EIO;
goto done;
}
diff --git a/src/util/util_errors.c b/src/util/util_errors.c
index 466a3b406..97eaf160f 100644
--- a/src/util/util_errors.c
+++ b/src/util/util_errors.c
@@ -75,6 +75,7 @@ struct err_string error_to_str[] = {
{ "Cannot connect to system bus" }, /* ERR_NO_SYSBUS */
{ "LDAP search returned a referral" }, /* ERR_REFERRAL */
{ "Error setting SELinux user context" }, /* ERR_SELINUX_CONTEXT */
+ { "SELinux is not managed by libsemanage" }, /* ERR_SELINUX_NOT_MANAGED */
{ "Username format not allowed by re_expression" }, /* ERR_REGEX_NOMATCH */
{ "Time specification not supported" }, /* ERR_TIMESPEC_NOT_SUPPORTED */
{ "Invalid SSSD configuration detected" }, /* ERR_INVALID_CONFIG */
diff --git a/src/util/util_errors.h b/src/util/util_errors.h
index 2f90c0a5d..4a250bf03 100644
--- a/src/util/util_errors.h
+++ b/src/util/util_errors.h
@@ -97,6 +97,7 @@ enum sssd_errors {
ERR_NO_SYSBUS,
ERR_REFERRAL,
ERR_SELINUX_CONTEXT,
+ ERR_SELINUX_NOT_MANAGED,
ERR_REGEX_NOMATCH,
ERR_TIMESPEC_NOT_SUPPORTED,
ERR_INVALID_CONFIG,
--
2.12.2

View File

@ -1,38 +0,0 @@
From 6a611406e805a1707ca0b9e86b6aa96e02e43ecc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Thu, 6 Apr 2017 11:23:43 +0200
Subject: [PATCH 099/135] DP: Fix typo
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
---
src/providers/data_provider/dp_target_id.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/providers/data_provider/dp_target_id.c b/src/providers/data_provider/dp_target_id.c
index 0bca9bac27b68a8b905a668992cb8f7650023f65..2088f9529cab83794ac793c7fd5a320f479dbf11 100644
--- a/src/providers/data_provider/dp_target_id.c
+++ b/src/providers/data_provider/dp_target_id.c
@@ -210,7 +210,7 @@ static errno_t dp_initgroups(struct sbus_request *sbus_req,
ret = sysdb_initgroups(sbus_req, domain, data->filter_value, &res);
if (ret == ENOENT || (ret == EOK && res->count == 0)) {
- /* There is no point in concacting NSS responder. Proceed as usual. */
+ /* There is no point in contacting NSS responder. Proceed as usual. */
return EAGAIN;
} else if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get initgroups [%d]: %s\n",
@@ -274,7 +274,7 @@ errno_t dp_get_account_info_handler(struct sbus_request *sbus_req,
}
if ((data->entry_type & BE_REQ_TYPE_MASK) == BE_REQ_INITGROUPS) {
- ret = dp_initgroups(sbus_req, dp_cli, key, dp_flags, data);
+ ret = dp_initgroups(sbus_req, dp_cli, key, dp_flags, data);
if (ret != EAGAIN) {
goto done;
}
--
2.12.2

Some files were not shown because too many files have changed in this diff Show More