From 03e2f0157c3337fba854c3f1e6df40bd80f91d83 Mon Sep 17 00:00:00 2001
From: Samuel Cabrero <scabrero@suse.com>
Date: Fri, 6 Mar 2026 13:57:05 +0100
Subject: [PATCH 1/3] sssctl: Add missing new line

Signed-off-by: Samuel Cabrero <scabrero@suse.com>
---
 src/tools/sssctl/sssctl_config.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/tools/sssctl/sssctl_config.c b/src/tools/sssctl/sssctl_config.c
index 0a246a6c7..993444a1e 100644
--- a/src/tools/sssctl/sssctl_config.c
+++ b/src/tools/sssctl/sssctl_config.c
@@ -127,7 +127,7 @@ errno_t sssctl_config_check(struct sss_cmdline *cmdline,
                                        SSSDDATADIR"/cfg_rules.ini",
                                        &strs, &num_errors);
     if (ret) {
-        PRINT("Failed to run validators");
+        PRINT("Failed to run validators\n");
         goto done;
     }
 
-- 
2.53.0


From eb0d8484d779ebb01d45d2f3c43901f392b1dd1c Mon Sep 17 00:00:00 2001
From: Samuel Cabrero <scabrero@suse.com>
Date: Fri, 6 Mar 2026 13:53:47 +0100
Subject: [PATCH 2/3] confdb: Add UsrEtc support

Vendor provided configuration is installed in /usr/etc/sssd/sssd.conf.

Users can override it creating /etc/sssd/sssd.conf, or override defaults
dropping config snippets to /etc/sssd/conf.d/

Doc: https://en.opensuse.org/openSUSE:Packaging_UsrEtc
Doc: https://github.com/uapi-group/specifications/blob/main/specs/configuration_files_specification.md

:packaging: New configure option '--with-vendordir' to enable reading
the vendor provided configuration file.

Signed-off-by: Samuel Cabrero <scabrero@suse.com>
---
 Makefile.am                      |  1 +
 configure.ac                     |  1 +
 src/conf_macros.m4               | 13 ++++++++
 src/confdb/confdb.h              |  3 ++
 src/monitor/monitor.c            |  6 ++--
 src/responder/kcm/kcm.c          | 12 +++++--
 src/tools/sssctl/sssctl_config.c | 31 ++++++++++++------
 src/util/sss_config.c            | 55 ++++++++++++++++++++++++++++++++
 src/util/util.h                  |  3 ++
 9 files changed, 111 insertions(+), 14 deletions(-)
 create mode 100644 src/util/sss_config.c

diff --git a/Makefile.am b/Makefile.am
index eb92b4a51..d9da2a5b9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1305,6 +1305,7 @@ libsss_util_la_SOURCES = \
     src/util/sss_chain_id_tevent.c \
     src/util/sss_chain_id.c \
     src/util/sss_time.c \
+    src/util/sss_config.c \
     $(NULL)
 libsss_util_la_CFLAGS = \
     $(AM_CFLAGS) \
diff --git a/configure.ac b/configure.ac
index 90cb1f3ec..1aa3cb6df 100644
--- a/configure.ac
+++ b/configure.ac
@@ -202,6 +202,7 @@ WITH_OIDC_CHILD
 WITH_TMPFILES_DIR
 WITH_UDEV_RULES_DIR
 WITH_SYSTEMD_SYSUSERS_DIR
+WITH_VENDOR_DIR
 
 m4_include([src/external/pkg.m4])
 m4_include([src/external/libpopt.m4])
diff --git a/src/conf_macros.m4 b/src/conf_macros.m4
index ded342213..415028d6b 100644
--- a/src/conf_macros.m4
+++ b/src/conf_macros.m4
@@ -1019,3 +1019,16 @@ AS_IF([test x$enable_gss_spnego_for_zero_maxssf = xyes],
                          [whether to use GSS-SPNEGO if maxssf is 0 (zero)]))
 
 AC_DEFINE_UNQUOTED(KRB5_KDC_RUNDIR, RUNDIR "/krb5kdc", [Path to KRB5 KDC run directory])
+
+AC_DEFUN([WITH_VENDOR_DIR],
+  [ AC_ARG_WITH([vendordir],
+                  [AS_HELP_STRING([--with-vendordir=DIR],
+                                  [Directory for distribution provided configuration files])],
+                  [vendordir=$withval],
+                  [with_vendordir=no])
+    AS_IF([test x"$with_vendordir" != xno],
+          [
+            AC_DEFINE([USE_VENDORDIR], 1, [whether to use distribution provided configuration files]),
+            AC_DEFINE_UNQUOTED([SSSD_VENDOR_DIR], "$with_vendordir", [Directory for distribution provided configuration files])
+          ])
+  ])
diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
index 633e0bcbc..64375d6b8 100644
--- a/src/confdb/confdb.h
+++ b/src/confdb/confdb.h
@@ -47,6 +47,9 @@
 #define CONFDB_DEFAULT_CONFIG_DIR SSSD_CONF_DIR"/"CONFDB_DEFAULT_CONFIG_DIR_NAME
 #define SSSD_MIN_ID 1
 #define CONFDB_DEFAULT_SHELL_FALLBACK "/bin/sh"
+#if defined(USE_VENDORDIR)
+#define SSSD_VENDOR_CONFIG_FILE SSSD_VENDOR_DIR"/"SSSD_CONFIG_FILE_NAME
+#endif
 
 /* Configuration options */
 
diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c
index 55db00069..f58f1435c 100644
--- a/src/monitor/monitor.c
+++ b/src/monitor/monitor.c
@@ -1794,7 +1794,7 @@ int main(int argc, const char *argv[])
     int opt_version = 0;
     char *opt_config_file = NULL;
     const char *opt_logger = NULL;
-    char *config_file = NULL;
+    const char *config_file = NULL;
     int flags = FLAGS_NO_WATCHDOG;
     struct main_context *main_ctx;
     TALLOC_CTX *tmp_ctx;
@@ -1882,9 +1882,11 @@ int main(int argc, const char *argv[])
     if (opt_config_file) {
         config_file = talloc_strdup(tmp_ctx, opt_config_file);
     } else {
-        config_file = talloc_strdup(tmp_ctx, SSSD_CONFIG_FILE);
+        config_file = sss_get_default_config_file(tmp_ctx);
     }
     if (config_file == NULL) {
+        DEBUG(SSSDBG_FATAL_FAILURE,
+              "Failed to get the configuration file name\n");
         ret = 2;
         goto out;
     }
diff --git a/src/responder/kcm/kcm.c b/src/responder/kcm/kcm.c
index 1085437b6..4bfefec9e 100644
--- a/src/responder/kcm/kcm.c
+++ b/src/responder/kcm/kcm.c
@@ -395,10 +395,16 @@ int main(int argc, const char *argv[])
     debug_log_file = "sssd_kcm";
     DEBUG_INIT(debug_level, opt_logger);
 
-     if (opt_config_file == NULL) {
-        config_file = SSSD_CONFIG_FILE;
+    if (opt_config_file) {
+        config_file = talloc_strdup(tmp_ctx, opt_config_file);
     } else {
-        config_file = opt_config_file;
+        config_file = sss_get_default_config_file(tmp_ctx);
+    }
+    if (config_file == NULL) {
+        TALLOC_FREE(tmp_ctx);
+        DEBUG(SSSDBG_FATAL_FAILURE,
+              "Failed to get the configuration file name\n");
+        return 2;
     }
 
    /* Parse config file, fail if cannot be done */
diff --git a/src/tools/sssctl/sssctl_config.c b/src/tools/sssctl/sssctl_config.c
index 993444a1e..a261bff15 100644
--- a/src/tools/sssctl/sssctl_config.c
+++ b/src/tools/sssctl/sssctl_config.c
@@ -69,6 +69,7 @@ errno_t sssctl_config_check(struct sss_cmdline *cmdline,
     TALLOC_CTX *tmp_ctx = NULL;
     const char *config_path = NULL;
     const char *config_snippet_path = NULL;
+    const char *config_file = NULL;
     struct poptOption long_options[] = {
         SSSD_CONFIG_OPTS(config_path)
         {"snippet", 's', POPT_ARG_STRING, &config_snippet_path,
@@ -93,25 +94,37 @@ errno_t sssctl_config_check(struct sss_cmdline *cmdline,
         goto done;
     }
 
-    if (config_path == NULL) {
-        config_path = SSSD_CONFIG_FILE;
+    if (config_path) {
+        config_file = talloc_strdup(tmp_ctx, config_path);
+    } else {
+        config_file = sss_get_default_config_file(tmp_ctx);
+    }
+    if (config_file == NULL) {
+        DEBUG(SSSDBG_FATAL_FAILURE,
+              "Failed to get the configuration file name\n");
+        ret = ENOMEM;
+        goto done;
     }
 
     if (config_snippet_path == NULL) {
-        config_snippet_path = sssctl_config_snippet_path(tmp_ctx, config_path);
-        if (config_snippet_path == NULL) {
-            DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create snippet path\n");
-            ret = ENOMEM;
-            goto done;
+        if (config_path) {
+            config_snippet_path = sssctl_config_snippet_path(tmp_ctx, config_path);
+        } else {
+            config_snippet_path = talloc_strdup(tmp_ctx, CONFDB_DEFAULT_CONFIG_DIR);
         }
     }
+    if (config_snippet_path == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create snippet path\n");
+        ret = ENOMEM;
+        goto done;
+    }
 
     ret = sss_ini_read_sssd_conf(init_data,
-                                 config_path,
+                                 config_file,
                                  config_snippet_path);
 
     if (ret == ERR_INI_EMPTY_CONFIG) {
-        PRINT("File %1$s does not exist.\n", config_path);
+        PRINT("File %1$s does not exist.\n", config_file);
         PRINT("There is no configuration.\n");
         ret = ERR_INI_OPEN_FAILED;
         goto done;
diff --git a/src/util/sss_config.c b/src/util/sss_config.c
new file mode 100644
index 000000000..dc144f373
--- /dev/null
+++ b/src/util/sss_config.c
@@ -0,0 +1,55 @@
+/*
+    SSSD
+
+    sss_config.c
+
+    Authors:
+        Samuel Cabrero <scabrero@suse.com>
+
+    Copyright (C) 2026 SUSE LINUX GmbH, Nuernberg, Germany.
+
+    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"
+
+#ifdef USE_VENDORDIR
+#include <sys/stat.h>
+#endif
+
+const char *sss_get_default_config_file(TALLOC_CTX *mem_ctx)
+{
+    char *config_file = NULL;
+
+    config_file = talloc_strdup(mem_ctx, SSSD_CONFIG_FILE);
+    if (config_file == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory.\n");
+        return NULL;
+    }
+
+#if defined(USE_VENDORDIR)
+    struct stat stats = {0};
+    if (stat(config_file, &stats) < 0 && errno == ENOENT) {
+        TALLOC_FREE(config_file);
+        config_file = talloc_strdup(mem_ctx, SSSD_VENDOR_CONFIG_FILE);
+        if (config_file == NULL) {
+            DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory.\n");
+            return NULL;
+        }
+        DEBUG(SSSDBG_CONF_SETTINGS, "Using vendor config file %s\n", config_file);
+    }
+#endif /* USE_VENDORDIR */
+
+    return config_file;
+}
diff --git a/src/util/util.h b/src/util/util.h
index 1045fc04d..cfccd1036 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -875,4 +875,7 @@ errno_t sss_parse_dns_uri(TALLOC_CTX *ctx,
                           const char *uri,
                           struct sss_parsed_dns_uri **_parsed_uri);
 
+/* from sss_config.c */
+const char *sss_get_default_config_file(TALLOC_CTX *mem_ctx);
+
 #endif /* __SSSD_UTIL_H__ */
-- 
2.53.0


From 643c5a760eb0fddacd445cd2906426526ce00fa6 Mon Sep 17 00:00:00 2001
From: Samuel Cabrero <scabrero@suse.com>
Date: Tue, 14 Apr 2026 17:14:23 +0200
Subject: [PATCH 3/3] doc: Document the config file hierarchy when vendor dir
 is enabled

Adds a section in sssd.conf manpage to explain how the vendor
provided configuration can be masked or overriden.

Signed-off-by: Samuel Cabrero <scabrero@suse.com>
---
 src/conf_macros.m4      |  2 ++
 src/man/Makefile.am     | 20 ++++++++++++++++++--
 src/man/sssd.conf.5.xml | 35 +++++++++++++++++++++++++++++++++++
 4 files changed, 57 insertions(+), 2 deletions(-)

diff --git a/src/conf_macros.m4 b/src/conf_macros.m4
index 415028d6b..22adfe8e2 100644
--- a/src/conf_macros.m4
+++ b/src/conf_macros.m4
@@ -1031,4 +1031,6 @@ AC_DEFUN([WITH_VENDOR_DIR],
             AC_DEFINE([USE_VENDORDIR], 1, [whether to use distribution provided configuration files]),
             AC_DEFINE_UNQUOTED([SSSD_VENDOR_DIR], "$with_vendordir", [Directory for distribution provided configuration files])
           ])
+    AC_SUBST(SSSD_VENDOR_DIR, [$vendordir])
+    AM_CONDITIONAL([HAVE_VENDORDIR], [test x"$with_vendordir" != xno])
   ])
diff --git a/src/man/Makefile.am b/src/man/Makefile.am
index 2a15254af..0f2518e96 100644
--- a/src/man/Makefile.am
+++ b/src/man/Makefile.am
@@ -74,9 +74,13 @@ endif
 if HAVE_LIBNL
 LIBNL_CONDS = ;have_libnl
 endif
+if HAVE_VENDORDIR
+VENDORDIR_CONDS = ;have_vendordir
+endif
 
+sssdconfdir = $(sysconfdir)/sssd
 
-CONDS = with_false$(SUDO_CONDS)$(AUTOFS_CONDS)$(SSH_CONDS)$(SSH_KNOWN_HOSTS_PROXY_CONDS)$(PAC_RESPONDER_CONDS)$(GPO_CONDS)$(SYSTEMD_CONDS)$(KCM_CONDS)$(STAP_CONDS)$(KCM_RENEWAL_CONDS)$(LOCKFREE_CLIENT_CONDS)$(HAVE_INOTIFY_CONDS)$(PASSKEY_CONDS)$(FILES_PROVIDER_CONDS)$(SSSD_NON_ROOT_USER_CONDS)$(SSSD_CONF_SERVICE_USER_CONDS)$(ENUM_CONDS)$(LIBNL_CONDS)$(AD_CONDS)
+CONDS = with_false$(SUDO_CONDS)$(AUTOFS_CONDS)$(SSH_CONDS)$(SSH_KNOWN_HOSTS_PROXY_CONDS)$(PAC_RESPONDER_CONDS)$(GPO_CONDS)$(SYSTEMD_CONDS)$(KCM_CONDS)$(STAP_CONDS)$(KCM_RENEWAL_CONDS)$(LOCKFREE_CLIENT_CONDS)$(HAVE_INOTIFY_CONDS)$(PASSKEY_CONDS)$(FILES_PROVIDER_CONDS)$(SSSD_NON_ROOT_USER_CONDS)$(SSSD_CONF_SERVICE_USER_CONDS)$(ENUM_CONDS)$(LIBNL_CONDS)$(AD_CONDS)$(VENDORDIR_CONDS)
 
 
 #Special Rules:
@@ -137,6 +141,14 @@ $(builddir)/src/man/sssd_user_name.include:
 	@mkdir -p $(builddir)/src/man
 	@echo -n $(SSSD_USER) > $(builddir)/src/man/sssd_user_name.include
 
+$(builddir)/src/man/sssd_vendor_dir.include:
+	@mkdir -p $(builddir)/src/man
+	@echo -n $(SSSD_VENDOR_DIR) > $(builddir)/src/man/sssd_vendor_dir.include
+
+$(builddir)/src/man/sssd_conf_dir.include:
+	@mkdir -p $(builddir)/src/man
+	@echo -n $(sssdconfdir) > $(builddir)/src/man/sssd_conf_dir.include
+
 %.1: %.1.xml
 	$(XMLLINT) $(XMLLINT_FLAGS) $<
 	$(XSLTPROC) -o $@  $(XSLTPROC_FLAGS) $(DOCBOOK_XSLT) $<
@@ -145,7 +157,7 @@ $(builddir)/src/man/sssd_user_name.include:
 	$(XMLLINT) $(XMLLINT_FLAGS) $<
 	$(XSLTPROC) -o $@  $(XSLTPROC_FLAGS) $(DOCBOOK_XSLT) $<
 
-%.5: %.5.xml $(builddir)/src/man/sssd_user_name.include
+%.5: %.5.xml $(builddir)/src/man/sssd_user_name.include $(builddir)/src/man/sssd_vendor_dir.include $(builddir)/src/man/sssd_conf_dir.include
 	$(XMLLINT) --path "$(srcdir)/src/man:$(builddir)/src/man" $(XMLLINT_FLAGS) $<
 	$(XSLTPROC) --path "$(srcdir)/src/man:$(builddir)/src/man" -o $@  $(XSLTPROC_FLAGS) $(DOCBOOK_XSLT) $<
 
@@ -232,6 +244,8 @@ clean-local:
 	rm -f $(man_MANS)
 	rm -f man.stamp
 	rm -f $(builddir)/src/man/sssd_user_name.include
+	rm -f $(builddir)/src/man/sssd_conf_dir.include
+	rm -f $(builddir)/src/man/sssd_vendor_dir.include
 
 else
 
@@ -242,6 +256,8 @@ clean-local:
 	rm -f $(man_MANS)
 	rm -f man.stamp
 	rm -f $(builddir)/src/man/sssd_user_name.include
+	rm -f $(builddir)/src/man/sssd_conf_dir.include
+	rm -f $(builddir)/src/man/sssd_vendor_dir.include
 
 endif
 
diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
index d37aa6e5f..63cd741b7 100644
--- a/src/man/sssd.conf.5.xml
+++ b/src/man/sssd.conf.5.xml
@@ -3,6 +3,8 @@
 "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd"
 [
 <!ENTITY sssd_user_name SYSTEM "sssd_user_name.include">
+<!ENTITY sssd_conf_dir SYSTEM "sssd_conf_dir.include">
+<!ENTITY sssd_vendor_dir SYSTEM "sssd_vendor_dir.include">
 ]>
 <reference>
 <title>SSSD Manual pages</title>
@@ -99,6 +101,39 @@
         </para>
     </refsect1>
 
+    <refsect1 id='vendor-dir' condition="have_vendordir">
+        <title>VENDOR PROVIDED CONFIGURATION</title>
+
+        <para>
+          The vendor provided configuraiton file is installed in
+          <filename>&sssd_vendor_dir;/sssd.conf</filename>, but this file must
+          not be directly edited. It can be completely masked by creating the
+          system specific configurtion file
+          <filename>&sssd_conf_dir;/sssd.conf</filename>, or partly overriden
+          by creating config snippets in
+          <filename>&sssd_conf_dir;/conf.d</filename> directory.
+        </para>
+        <refsect2 id='vendor-dir-conf-hierarchy'>
+          <title>CONFIGURATION FILE HIERARCHY</title>
+        <para>
+          When sssd reads the configuration it first tries to open the system
+          specific configuration file in
+          <filename>&sssd_conf_dir;/sssd.conf</filename>. If it exists, it is
+          loaded and snippets from <filename>&sssd_conf_dir;/conf.d</filename>
+          are applied. The vendor provided configuration file
+          <filename>&sssd_vendor_dir;/sssd.conf</filename> is completely ignored
+          in this case.
+        </para>
+        <para>
+          If the system specific configuration file
+          <filename>&sssd_conf_dir;/sssd.conf</filename> does not exist, then
+          the vendor configuration file
+          <filename>&sssd_vendor_dir;/sssd.conf</filename> is loaded and
+          snippets from <filename>&sssd_conf_dir;/conf.d</filename> are applied.
+        </para>
+      </refsect2>
+    </refsect1>
+
     <refsect1 id='general-options'>
         <title>GENERAL OPTIONS</title>
         <para>
-- 
2.53.0


From db99e524b5b044dc9709a578bd3b9347cee23b9d Mon Sep 17 00:00:00 2001
From: Samuel Cabrero <scabrero@suse.com>
Date: Wed, 29 Apr 2026 18:14:54 +0200
Subject: [PATCH] SYSTEMD: Add vendor provided configuration file as a
 triggering condition

If vendor directory is enabled (--with-vendordir=<dir>) then add the
vendor provided configuration file as a triggering condition to start
the service.

Signed-off-by: Samuel Cabrero <scabrero@suse.com>
---
 Makefile.am | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/Makefile.am b/Makefile.am
index d9da2a5b9..b478df9cd 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -97,7 +97,11 @@ ifp_dbus_exec_cmd = $(sssdlibexecdir)/sssd_ifp --socket-activated
 ifp_systemdservice = SystemdService=sssd-ifp.service
 # SSSD requires a configuration file (either /etc/sssd/sssd.conf,
 # or some snippet under /etc/sssd/sssd.conf.d/) to be present.
+if HAVE_VENDORDIR
+condconfigexists = ConditionPathExists=\|@SSSD_VENDOR_DIR@/sssd.conf\nConditionPathExists=\|/etc/sssd/sssd.conf\nConditionDirectoryNotEmpty=\|/etc/sssd/conf.d/
+else
 condconfigexists = ConditionPathExists=\|/etc/sssd/sssd.conf\nConditionDirectoryNotEmpty=\|/etc/sssd/conf.d/
+endif
 
 # Bounding set needs to list capabilities required by ldap/krb5/selinux_childs and sssd_pam, otherwise they can't gain it.
 # Capabilities usage by binaries:
-- 
2.53.0

