From 76fe5d637c892efa4312078b218b90a9f7ea03c2 Mon Sep 17 00:00:00 2001 From: Alexey Tikhonov Date: Mon, 2 Aug 2021 17:10:36 +0200 Subject: [PATCH] Resolves: rhbz#1803943 - [RFE] support subid ranges managed by FreeIPA --- ...ubid-ranges-support-for-IPA-provider.patch | 1817 +++++++++++++++++ sssd.spec | 11 +- 2 files changed, 1826 insertions(+), 2 deletions(-) create mode 100644 0001-Basics-of-subid-ranges-support-for-IPA-provider.patch diff --git a/0001-Basics-of-subid-ranges-support-for-IPA-provider.patch b/0001-Basics-of-subid-ranges-support-for-IPA-provider.patch new file mode 100644 index 0000000..aac4e4e --- /dev/null +++ b/0001-Basics-of-subid-ranges-support-for-IPA-provider.patch @@ -0,0 +1,1817 @@ +From f546088226872f24722bdd94388816792bd5891a Mon Sep 17 00:00:00 2001 +From: Alexey Tikhonov +Date: Sat, 1 May 2021 22:56:15 +0200 +Subject: [PATCH] Basics of 'subid ranges' support for IPA provider. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +:feature: Basic support of user's 'subuid and subgid ranges' for IPA +provider and corresponding plugin for shadow-utils were introduced. +Limitations: + - single subid interval pair (subuid+subgid) per user + - idviews aren't supported + - only forward lookup (user -> subid ranges) +Take a note, this is MVP of experimental feature. Significant changes +might be required later, after initial feedback. +Corresponding support in shadow-utils was merged upstream, but since there +is no upstream release available yet, SSSD feature isn't built by default. +Build can be enabled with `--with-subid` configure option. +Plugin's install path can be configured with `--with-subid-lib-path=` +("${libdir}" by default) + +For additional details about support in shadow-utils please see discussion +in https://github.com/shadow-maint/shadow/issues/154 and in related PRs. + +:config: New IPA provider's option `ipa_subid_ranges_search_base` allows +configuration of search base for user's subid ranges. +Default: `cn=subids,%basedn` + +Resolves: https://github.com/SSSD/sssd/issues/5197 + +Reviewed-by: Iker Pedrosa +Reviewed-by: Pavel Březina +--- + Makefile.am | 34 +++ + configure.ac | 2 + + src/conf_macros.m4 | 30 +++ + src/config/SSSDConfig/sssdoptions.py | 1 + + src/config/cfg_rules.ini | 1 + + src/config/etc/sssd.api.d/sssd-ipa.conf | 1 + + src/db/sysdb.h | 6 + + src/db/sysdb_subid.c | 163 +++++++++++ + src/db/sysdb_subid.h | 39 +++ + src/man/sssd-ipa.5.xml | 14 + + src/providers/data_provider_req.c | 2 + + src/providers/data_provider_req.h | 1 + + src/providers/ipa/ipa_common.c | 38 +++ + src/providers/ipa/ipa_common.h | 1 + + src/providers/ipa/ipa_id.c | 17 ++ + src/providers/ipa/ipa_opts.c | 12 + + src/providers/ipa/ipa_opts.h | 2 + + src/providers/ldap/ldap_common.h | 14 + + src/providers/ldap/ldap_id.c | 31 +++ + src/providers/ldap/ldap_id_subid.c | 255 ++++++++++++++++++ + src/providers/ldap/sdap.h | 19 ++ + src/responder/common/cache_req/cache_req.c | 4 + + src/responder/common/cache_req/cache_req.h | 4 + + .../common/cache_req/cache_req_data.c | 3 + + .../common/cache_req/cache_req_plugin.h | 3 + + .../plugins/cache_req_subid_ranges_by_name.c | 143 ++++++++++ + src/responder/common/responder.h | 1 + + src/responder/common/responder_dp.c | 4 + + src/responder/nss/nss_cmd.c | 20 ++ + src/responder/nss/nss_protocol.h | 8 + + src/responder/nss/nss_protocol_subid.c | 60 +++++ + src/sss_client/common.c | 2 +- + src/sss_client/sss_cli.h | 11 + + src/sss_client/subid/sss_subid.c | 209 ++++++++++++++ + src/sss_client/subid/sss_subid.exports | 12 + + src/systemtap/sssd_functions.stp | 2 +- + src/tests/cwrap/Makefile.am | 3 + + src/tests/dlopen-tests.c | 3 + + src/util/sss_cli_cmd.c | 5 + + src/util/util_errors.c | 1 + + src/util/util_errors.h | 1 + + 41 files changed, 1180 insertions(+), 2 deletions(-) + create mode 100644 src/db/sysdb_subid.c + create mode 100644 src/db/sysdb_subid.h + create mode 100644 src/providers/ldap/ldap_id_subid.c + create mode 100644 src/responder/common/cache_req/plugins/cache_req_subid_ranges_by_name.c + create mode 100644 src/responder/nss/nss_protocol_subid.c + create mode 100644 src/sss_client/subid/sss_subid.c + create mode 100644 src/sss_client/subid/sss_subid.exports + +diff --git a/Makefile.am b/Makefile.am +index 1dd06d74c..577935e7e 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -65,6 +65,7 @@ localedir = @localedir@ + nsslibdir = @nsslibdir@ + pamlibdir = @pammoddir@ + autofslibdir = @appmodpath@ ++subidlibdir = @subidlibpath@ + nfslibdir = @nfsidmaplibdir@ + + dbpath = @dbpath@ +@@ -596,6 +597,9 @@ SSSD_CACHE_REQ_OBJ = \ + src/responder/common/cache_req/plugins/cache_req_ip_network_by_name.c \ + src/responder/common/cache_req/plugins/cache_req_ip_network_by_addr.c \ + $(NULL) ++if BUILD_SUBID ++ SSSD_CACHE_REQ_OBJ += src/responder/common/cache_req/plugins/cache_req_subid_ranges_by_name.c ++endif + + SSSD_RESPONDER_IFACE_OBJ = \ + src/responder/common/responder_iface.c \ +@@ -810,6 +814,7 @@ dist_noinst_HEADERS = \ + src/db/sysdb_private.h \ + src/db/sysdb_services.h \ + src/db/sysdb_ssh.h \ ++ src/db/sysdb_subid.h \ + src/db/sysdb_domain_resolution_order.h \ + src/db/sysdb_computer.h \ + src/db/sysdb_iphosts.h \ +@@ -1247,6 +1252,7 @@ libsss_util_la_SOURCES = \ + src/db/sysdb_ipnetworks.c \ + src/util/sss_pam_data.c \ + src/db/sysdb_computer.c \ ++ src/db/sysdb_subid.c \ + src/util/util.c \ + src/util/util_ext.c \ + src/util/util_preauth.c \ +@@ -1558,6 +1564,9 @@ sssd_nss_LDADD = \ + libsss_iface.la \ + libsss_sbus.la \ + $(NULL) ++if BUILD_SUBID ++ sssd_nss_SOURCES += src/responder/nss/nss_protocol_subid.c ++endif + + sssd_pam_SOURCES = \ + src/responder/pam/pam_LOCAL_domain.c \ +@@ -2691,6 +2700,9 @@ nss_srv_tests_LDADD = \ + libsss_iface.la \ + libsss_sbus.la \ + $(NULL) ++if BUILD_SUBID ++ nss_srv_tests_SOURCES += src/responder/nss/nss_protocol_subid.c ++endif + + EXTRA_pam_srv_tests_DEPENDENCIES = \ + $(ldblib_LTLIBRARIES) \ +@@ -4217,6 +4229,21 @@ libsss_autofs_la_LDFLAGS = \ + -Wl,--version-script,$(srcdir)/src/sss_client/autofs/sss_autofs.exports + endif + ++if BUILD_SUBID ++subidlib_LTLIBRARIES = libsubid_sss.la ++libsubid_sss_la_SOURCES = \ ++ src/sss_client/common.c \ ++ src/sss_client/sss_cli.h \ ++ src/sss_client/subid/sss_subid.c ++ ++libsubid_sss_la_LIBADD = \ ++ $(CLIENT_LIBS) ++libsubid_sss_la_LDFLAGS = \ ++ -module \ ++ -avoid-version \ ++ -Wl,--version-script,$(srcdir)/src/sss_client/subid/sss_subid.exports ++endif ++ + dist_noinst_DATA += \ + src/sss_client/sss_nss.exports \ + src/sss_client/sss_pam.exports \ +@@ -4231,6 +4258,10 @@ if BUILD_AUTOFS + dist_noinst_DATA += src/sss_client/autofs/sss_autofs.exports + endif + ++if BUILD_SUBID ++dist_noinst_DATA += src/sss_client/subid/sss_subid.exports ++endif ++ + #################### + # Plugin Libraries # + #################### +@@ -4315,6 +4346,9 @@ libsss_ldap_common_la_LDFLAGS = \ + if BUILD_SYSTEMTAP + libsss_ldap_common_la_LIBADD += stap_generated_probes.lo + endif ++if BUILD_SUBID ++libsss_ldap_common_la_SOURCES += src/providers/ldap/ldap_id_subid.c ++endif + + if BUILD_SSH + libsss_ldap_common_la_SOURCES += src/providers/ldap/sdap_hostid.c +diff --git a/configure.ac b/configure.ac +index e98487cae..c14a59eef 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -161,6 +161,8 @@ WITH_APP_LIBS + WITH_SUDO + WITH_SUDO_LIB_PATH + WITH_AUTOFS ++WITH_SUBID ++WITH_SUBID_LIB_PATH + WITH_SSH + WITH_IFP + WITH_SYSLOG +diff --git a/src/conf_macros.m4 b/src/conf_macros.m4 +index cdffba11c..0a1e6dd8f 100644 +--- a/src/conf_macros.m4 ++++ b/src/conf_macros.m4 +@@ -675,6 +675,36 @@ AC_DEFUN([WITH_AUTOFS], + AM_CONDITIONAL([BUILD_AUTOFS], [test x"$with_autofs" = xyes]) + ]) + ++AC_DEFUN([WITH_SUBID], ++ [ AC_ARG_WITH([subid], ++ [AC_HELP_STRING([--with-subid], ++ [Whether to build with subid ranges support [no]] ++ ) ++ ], ++ [with_subid=$withval], ++ with_subid=no ++ ) ++ ++ if test x"$with_subid" = xyes; then ++ AC_DEFINE(BUILD_SUBID, 1, [whether to build with SUBID ranges support]) ++ fi ++ AM_CONDITIONAL([BUILD_SUBID], [test x"$with_subid" = xyes]) ++ ]) ++ ++AC_DEFUN([WITH_SUBID_LIB_PATH], ++ [ AC_ARG_WITH([subid-lib-path], ++ [AC_HELP_STRING([--with-subid-lib-path=], ++ [Path to the subid library] ++ ) ++ ] ++ ) ++ subidlibpath="${libdir}" ++ if test x"$with_subid_lib_path" != x; then ++ subidlibpath=$with_subid_lib_path ++ fi ++ AC_SUBST(subidlibpath) ++ ]) ++ + AC_DEFUN([WITH_SSH], + [ AC_ARG_WITH([ssh], + [AC_HELP_STRING([--with-ssh], +diff --git a/src/config/SSSDConfig/sssdoptions.py b/src/config/SSSDConfig/sssdoptions.py +index c4ce2588b..39380c462 100644 +--- a/src/config/SSSDConfig/sssdoptions.py ++++ b/src/config/SSSDConfig/sssdoptions.py +@@ -265,6 +265,7 @@ class SSSDOptions(object): + 'ipa_deskprofile_request_interval': _("The amount of time in minutes between lookups of Desktop Profiles " + "rules against the IPA server when the last request did not find any " + "rule"), ++ 'ipa_subid_ranges_search_base': _("Search base for SUBID ranges"), + 'ipa_host_fqdn': _('The LDAP attribute that contains FQDN of the host.'), + 'ipa_host_object_class': _('The object class of a host entry in LDAP.'), + 'ipa_host_search_base': _('Use the given string as search base for host objects.'), +diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini +index 0a3c32a97..d8190c2f4 100644 +--- a/src/config/cfg_rules.ini ++++ b/src/config/cfg_rules.ini +@@ -538,6 +538,7 @@ option = ipa_backup_server + option = ipa_deskprofile_refresh + option = ipa_deskprofile_request_interval + option = ipa_deskprofile_search_base ++option = ipa_subid_ranges_search_base + option = ipa_domain + option = ipa_dyndns_iface + option = ipa_dyndns_ttl +diff --git a/src/config/etc/sssd.api.d/sssd-ipa.conf b/src/config/etc/sssd.api.d/sssd-ipa.conf +index 9a81389ca..02c9089fd 100644 +--- a/src/config/etc/sssd.api.d/sssd-ipa.conf ++++ b/src/config/etc/sssd.api.d/sssd-ipa.conf +@@ -4,6 +4,7 @@ ipa_server = str, None, false + ipa_backup_server = str, None, false + ipa_hostname = str, None, false + ipa_deskprofile_search_base = str, None, false ++ipa_subid_ranges_search_base = str, None, false + ipa_dyndns_update = bool, None, false + ipa_dyndns_ttl = int, None, false + ipa_dyndns_iface = str, None, false +diff --git a/src/db/sysdb.h b/src/db/sysdb.h +index a29232f48..b638f4397 100644 +--- a/src/db/sysdb.h ++++ b/src/db/sysdb.h +@@ -143,6 +143,12 @@ + + #define SYSDB_SSH_PUBKEY "sshPublicKey" + ++#define SYSDB_SUBID_UID_COUND "subUidCount" ++#define SYSDB_SUBID_GID_COUNT "subGidCount" ++#define SYSDB_SUBID_UID_NUMBER "subUidNumber" ++#define SYSDB_SUBID_GID_NUMBER "subGidNumber" ++#define SYSDB_SUBID_OWNER "subidOwner" ++ + #define SYSDB_AUTH_TYPE "authType" + #define SYSDB_USER_CERT "userCertificate" + #define SYSDB_USER_MAPPED_CERT "userMappedCertificate" +diff --git a/src/db/sysdb_subid.c b/src/db/sysdb_subid.c +new file mode 100644 +index 000000000..519b0834c +--- /dev/null ++++ b/src/db/sysdb_subid.c +@@ -0,0 +1,163 @@ ++/* ++ Copyright (C) 2021 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 . ++*/ ++ ++#include ++ ++#include "db/sysdb_private.h" ++#include "db/sysdb_subid.h" ++ ++#define SUBID_SUBDIR "subid_ranges" ++ ++ ++errno_t sysdb_store_subid_range(struct sss_domain_info *domain, ++ const char *name, ++ int expiration_period, ++ struct sysdb_attrs *attrs) ++{ ++ TALLOC_CTX *tmp_ctx; ++ errno_t ret, sret; ++ bool in_transaction = false; ++ time_t now = time(NULL); ++ ++ DEBUG(SSSDBG_TRACE_FUNC, "Storing subid ranges for %s, expiration period = %d\n", ++ name, expiration_period); ++ ++ tmp_ctx = talloc_new(NULL); ++ if (!tmp_ctx) { ++ return ENOMEM; ++ } ++ ++ ret = sysdb_transaction_start(domain->sysdb); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n"); ++ goto done; ++ } ++ ++ in_transaction = true; ++ ++ ret = sysdb_attrs_add_string(attrs, SYSDB_OBJECTCLASS, SYSDB_SUBID_RANGE_OC); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Could not set object class [%d]: %s\n", ret, strerror(ret)); ++ goto done; ++ } ++ ++ ret = sysdb_attrs_add_string(attrs, SYSDB_NAME, name); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Could not set name attribute [%d]: %s\n", ret, strerror(ret)); ++ goto done; ++ } ++ ++ ret = sysdb_attrs_add_time_t(attrs, SYSDB_LAST_UPDATE, now); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Could not set sysdb lastUpdate [%d]: %s\n", ++ ret, strerror(ret)); ++ goto done; ++ } ++ ++ ret = sysdb_attrs_add_time_t(attrs, SYSDB_CACHE_EXPIRE, ++ expiration_period ? (now + expiration_period) : 0); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Could not set sysdb cache expire [%d]: %s\n", ++ ret, strerror(ret)); ++ goto done; ++ } ++ ++ ret = sysdb_store_custom(domain, name, SUBID_SUBDIR, attrs); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ ret = sysdb_transaction_commit(domain->sysdb); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n"); ++ goto done; ++ } ++ ++ in_transaction = false; ++ ++ ret = EOK; ++ ++done: ++ if (in_transaction) { ++ sret = sysdb_transaction_cancel(domain->sysdb); ++ if (sret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Could not cancel transaction\n"); ++ } ++ } ++ ++ talloc_free(tmp_ctx); ++ ++ return ret; ++} ++ ++errno_t sysdb_get_subid_ranges(TALLOC_CTX *mem_ctx, ++ struct sss_domain_info *domain, ++ const char *name, ++ const char **attrs, ++ struct ldb_message **_range) ++{ ++ TALLOC_CTX *tmp_ctx; ++ errno_t ret; ++ const char *filter; ++ struct ldb_message **ranges; ++ size_t num_ranges; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (!tmp_ctx) { ++ return ENOMEM; ++ } ++ ++ filter = talloc_asprintf(tmp_ctx, "(&(%s=%s)(%s=%s))", ++ SYSDB_OBJECTCLASS, SYSDB_SUBID_RANGE_OC, ++ SYSDB_NAME, name); ++ if (!filter) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = sysdb_search_custom(tmp_ctx, domain, filter, ++ SUBID_SUBDIR, attrs, ++ &num_ranges, &ranges); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ if (num_ranges > 1) { ++ ret = EINVAL; ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Found more than one range with name %s\n", name); ++ goto done; ++ } ++ ++ *_range = talloc_steal(mem_ctx, ranges[0]); ++ ret = EOK; ++ ++done: ++ talloc_free(tmp_ctx); ++ ++ return ret; ++} ++ ++errno_t sysdb_delete_subid_range(struct sss_domain_info *domain, ++ const char *name) ++{ ++ DEBUG(SSSDBG_TRACE_FUNC, "Deleting subid ranges for %s\n", name); ++ return sysdb_delete_custom(domain, name, SUBID_SUBDIR); ++} +diff --git a/src/db/sysdb_subid.h b/src/db/sysdb_subid.h +new file mode 100644 +index 000000000..4b4a86334 +--- /dev/null ++++ b/src/db/sysdb_subid.h +@@ -0,0 +1,39 @@ ++/* ++ Copyright (C) 2021 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 . ++*/ ++ ++#ifndef _SYSDB_SUBID_H_ ++#define _SYSDB_SUBID_H_ ++ ++#include "db/sysdb.h" ++ ++#define SYSDB_SUBID_RANGE_OC "subordinateid" ++ ++errno_t sysdb_store_subid_range(struct sss_domain_info *domain, ++ const char *name, ++ int expiration_period, ++ struct sysdb_attrs *attrs); ++ ++errno_t sysdb_get_subid_ranges(TALLOC_CTX *mem_ctx, ++ struct sss_domain_info *domain, ++ const char *name, ++ const char **attrs, ++ struct ldb_message **range); ++ ++errno_t sysdb_delete_subid_range(struct sss_domain_info *domain, ++ const char *name); ++ ++#endif /* _SYSDB_SSH_H_ */ +diff --git a/src/man/sssd-ipa.5.xml b/src/man/sssd-ipa.5.xml +index 7b630493d..2bbf67c83 100644 +--- a/src/man/sssd-ipa.5.xml ++++ b/src/man/sssd-ipa.5.xml +@@ -356,6 +356,20 @@ + + + ++ ++ ipa_subid_ranges_search_base (string) ++ ++ ++ Optional. Use the given string as search base for ++ subordinate ranges related objects. ++ ++ ++ Default: the value of ++ cn=subids,%basedn ++ ++ ++ ++ + + ipa_hbac_search_base (string) + +diff --git a/src/providers/data_provider_req.c b/src/providers/data_provider_req.c +index e22cfd71a..b7f4d152e 100644 +--- a/src/providers/data_provider_req.c ++++ b/src/providers/data_provider_req.c +@@ -44,6 +44,8 @@ const char *be_req2str(dbus_uint32_t req_type) + return be_req_to_str(BE_REQ_HOST); + case BE_REQ_IP_NETWORK: + return be_req_to_str(BE_REQ_IP_NETWORK); ++ case BE_REQ_SUBID_RANGES: ++ return be_req_to_str(BE_REQ_SUBID_RANGES); + case BE_REQ_BY_SECID: + return be_req_to_str(BE_REQ_BY_SECID); + case BE_REQ_USER_AND_GROUP: +diff --git a/src/providers/data_provider_req.h b/src/providers/data_provider_req.h +index 75f7f9713..4c6ab5a7e 100644 +--- a/src/providers/data_provider_req.h ++++ b/src/providers/data_provider_req.h +@@ -35,6 +35,7 @@ + #define BE_REQ_SUDO_RULES 0x0007 + #define BE_REQ_HOST 0x0008 + #define BE_REQ_IP_NETWORK 0x0009 ++#define BE_REQ_SUBID_RANGES 0x0010 + #define BE_REQ_BY_SECID 0x0011 + #define BE_REQ_USER_AND_GROUP 0x0012 + #define BE_REQ_BY_UUID 0x0013 +diff --git a/src/providers/ipa/ipa_common.c b/src/providers/ipa/ipa_common.c +index 23b358819..1509cb1ce 100644 +--- a/src/providers/ipa/ipa_common.c ++++ b/src/providers/ipa/ipa_common.c +@@ -152,6 +152,9 @@ static errno_t ipa_parse_search_base(TALLOC_CTX *mem_ctx, + case IPA_DESKPROFILE_SEARCH_BASE: + class_name = "IPA_DESKPROFILE"; + break; ++ case IPA_SUBID_RANGES_SEARCH_BASE: ++ class_name = "IPA_SUBID_RANGES"; ++ break; + default: + DEBUG(SSSDBG_CONF_SETTINGS, + "Unknown search base type: [%d]\n", class); +@@ -481,6 +484,41 @@ int ipa_get_id_options(struct ipa_options *ipa_opts, + &ipa_opts->deskprofile_search_bases); + if (ret != EOK) goto done; + ++#ifdef BUILD_SUBID ++ if (NULL == dp_opt_get_string(ipa_opts->basic, ++ IPA_SUBID_RANGES_SEARCH_BASE)) { ++ value = talloc_asprintf(tmpctx, "cn=subids,%s", ++ ipa_opts->id->sdom->search_bases[0]->basedn); ++ if (!value) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = dp_opt_set_string(ipa_opts->basic, IPA_SUBID_RANGES_SEARCH_BASE, value); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ DEBUG(SSSDBG_TRACE_FUNC, "Option %s set to %s\n", ++ ipa_opts->basic[IPA_SUBID_RANGES_SEARCH_BASE].opt_name, ++ dp_opt_get_string(ipa_opts->basic, ++ IPA_SUBID_RANGES_SEARCH_BASE)); ++ } ++ ret = ipa_parse_search_base(ipa_opts->basic, ipa_opts->basic, ++ IPA_SUBID_RANGES_SEARCH_BASE, ++ &ipa_opts->id->sdom->subid_ranges_search_bases); ++ if (ret != EOK) goto done; ++ ++ ret = sdap_get_map(ipa_opts->id, ++ cdb, conf_path, ++ ipa_subid_map, ++ SDAP_OPTS_SUBID_RANGE, ++ &ipa_opts->id->subid_map); ++ if (ret != EOK) { ++ goto done; ++ } ++#endif ++ + value = dp_opt_get_string(ipa_opts->id->basic, SDAP_DEREF); + if (value != NULL) { + ret = deref_string_to_val(value, &i); +diff --git a/src/providers/ipa/ipa_common.h b/src/providers/ipa/ipa_common.h +index 480f7b664..eb0eda8eb 100644 +--- a/src/providers/ipa/ipa_common.h ++++ b/src/providers/ipa/ipa_common.h +@@ -68,6 +68,7 @@ enum ipa_basic_opt { + IPA_DESKPROFILE_SEARCH_BASE, + IPA_DESKPROFILE_REFRESH, + IPA_DESKPROFILE_REQUEST_INTERVAL, ++ IPA_SUBID_RANGES_SEARCH_BASE, + + IPA_OPTS_BASIC /* opts counter */ + }; +diff --git a/src/providers/ipa/ipa_id.c b/src/providers/ipa/ipa_id.c +index 2cbe0c9c7..636e07965 100644 +--- a/src/providers/ipa/ipa_id.c ++++ b/src/providers/ipa/ipa_id.c +@@ -728,6 +728,22 @@ static errno_t ipa_id_get_account_info_get_original_step(struct tevent_req *req, + struct ipa_id_get_account_info_state); + struct tevent_req *subreq; + ++#ifdef BUILD_SUBID ++ if ((ar->entry_type & BE_REQ_TYPE_MASK) == BE_REQ_SUBID_RANGES) { ++ if (!state->ctx->opts->sdom->subid_ranges_search_bases || ++ !state->ctx->opts->sdom->subid_ranges_search_bases[0] || ++ !state->ctx->opts->sdom->subid_ranges_search_bases[0]->basedn) { ++ DEBUG(SSSDBG_OP_FAILURE, "subid_ranges_search_bases isn't set\n"); ++ return EINVAL; ++ } ++ ar->extra_value = talloc_asprintf(ar, ++ "%s=%s,"SYSDB_USERS_CONTAINER",%s", ++ state->ctx->opts->user_map[SDAP_AT_USER_NAME].name, ++ ar->filter_value, ++ state->ctx->opts->sdom->user_search_bases[0]->basedn); ++ } ++#endif ++ + subreq = sdap_handle_acct_req_send(state, state->ctx->be, ar, + state->ipa_ctx->sdap_id_ctx, + state->ipa_ctx->sdap_id_ctx->opts->sdom, +@@ -769,6 +785,7 @@ static void ipa_id_get_account_info_orig_done(struct tevent_req *subreq) + } + + if (! is_object_overridable(state->ar)) { ++ DEBUG(SSSDBG_FUNC_DATA, "Object not overridable, ending request\n"); + state->dp_error = DP_ERR_OK; + tevent_req_done(req); + return; +diff --git a/src/providers/ipa/ipa_opts.c b/src/providers/ipa/ipa_opts.c +index 09e360a43..dc0a2201b 100644 +--- a/src/providers/ipa/ipa_opts.c ++++ b/src/providers/ipa/ipa_opts.c +@@ -26,6 +26,7 @@ + #include "db/sysdb_autofs.h" + #include "db/sysdb_services.h" + #include "db/sysdb_selinux.h" ++#include "db/sysdb_subid.h" + #include "providers/ldap/ldap_common.h" + + struct dp_option ipa_basic_opts[] = { +@@ -51,6 +52,7 @@ struct dp_option ipa_basic_opts[] = { + { "ipa_deskprofile_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "ipa_deskprofile_refresh", DP_OPT_NUMBER, { .number = 5 }, NULL_NUMBER }, + { "ipa_deskprofile_request_interval", DP_OPT_NUMBER, { .number = 60 }, NULL_NUMBER }, ++ { "ipa_subid_ranges_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + DP_OPTION_TERMINATOR + }; + +@@ -250,6 +252,16 @@ struct sdap_attr_map ipa_netgroup_map[] = { + SDAP_ATTR_MAP_TERMINATOR + }; + ++struct sdap_attr_map ipa_subid_map[] = { ++ { "ipa_subuid_object_class", "ipasubordinateid", SYSDB_SUBID_RANGE_OC, NULL }, ++ { "ipa_subuid_count", "ipaSubUidCount", SYSDB_SUBID_UID_COUND, NULL }, ++ { "ipa_subgid_count", "ipaSubGidCount", SYSDB_SUBID_GID_COUNT, NULL }, ++ { "ipa_subuid_number", "ipaSubUidNumber", SYSDB_SUBID_UID_NUMBER, NULL }, ++ { "ipa_subgid_number", "ipaSubGidNumber", SYSDB_SUBID_GID_NUMBER, NULL }, ++ { "ipa_owner", "ipaOwner", SYSDB_SUBID_OWNER, NULL }, ++ SDAP_ATTR_MAP_TERMINATOR ++}; ++ + struct sdap_attr_map ipa_host_map[] = { + { "ipa_host_object_class", "ipaHost", SYSDB_HOST_CLASS, NULL }, + { "ipa_host_name", "cn", SYSDB_NAME, NULL }, +diff --git a/src/providers/ipa/ipa_opts.h b/src/providers/ipa/ipa_opts.h +index 378a9922c..6f54e57a9 100644 +--- a/src/providers/ipa/ipa_opts.h ++++ b/src/providers/ipa/ipa_opts.h +@@ -40,6 +40,8 @@ extern struct sdap_attr_map ipa_group_map[]; + + extern struct sdap_attr_map ipa_netgroup_map[]; + ++extern struct sdap_attr_map ipa_subid_map[]; ++ + extern struct sdap_attr_map ipa_host_map[]; + + extern struct sdap_attr_map ipa_hostgroup_map[]; +diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h +index 13e6d4871..c78338b5d 100644 +--- a/src/providers/ldap/ldap_common.h ++++ b/src/providers/ldap/ldap_common.h +@@ -446,4 +446,18 @@ errno_t users_get_handle_no_user(TALLOC_CTX *mem_ctx, + errno_t groups_get_handle_no_group(TALLOC_CTX *mem_ctx, + struct sss_domain_info *domain, + int filter_type, const char *filter_value); ++ ++#ifdef BUILD_SUBID ++struct tevent_req *subid_ranges_get_send(TALLOC_CTX *memctx, ++ struct tevent_context *ev, ++ struct sdap_id_ctx *ctx, ++ struct sdap_domain *sdom, ++ struct sdap_id_conn_ctx *conn, ++ const char* filter_value, ++ const char *extra_value); ++ ++int subid_ranges_get_recv(struct tevent_req *req, int *dp_error_out, ++ int *sdap_ret); ++#endif ++ + #endif /* _LDAP_COMMON_H_ */ +diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c +index ebc0ab8e4..9b67773a8 100644 +--- a/src/providers/ldap/ldap_id.c ++++ b/src/providers/ldap/ldap_id.c +@@ -1449,6 +1449,24 @@ sdap_handle_acct_req_send(TALLOC_CTX *mem_ctx, + noexist_delete); + break; + ++ case BE_REQ_SUBID_RANGES: ++#ifdef BUILD_SUBID ++ if (!ar->extra_value) { ++ ret = ERR_GET_ACCT_SUBID_RANGES_NOT_SUPPORTED; ++ state->err = "This id_provider doesn't support subid ranges"; ++ goto done; ++ } ++ subreq = subid_ranges_get_send(state, be_ctx->ev, id_ctx, ++ sdom, conn, ++ ar->filter_value, ++ ar->extra_value); ++#else ++ ret = ERR_GET_ACCT_SUBID_RANGES_NOT_SUPPORTED; ++ state->err = "Subid ranges are not supported"; ++ goto done; ++#endif ++ break; ++ + case BE_REQ_NETGROUP: + if (ar->filter_type != BE_FILTER_NAME) { + ret = EINVAL; +@@ -1533,6 +1551,11 @@ sdap_handle_acct_req_send(TALLOC_CTX *mem_ctx, + default: /*fail*/ + ret = EINVAL; + state->err = "Invalid request type"; ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Unexpected request type: 0x%X [%s:%s] in %s\n", ++ ar->entry_type, ar->filter_value, ++ ar->extra_value?ar->extra_value:"-", ++ ar->domain); + goto done; + } + +@@ -1578,6 +1601,14 @@ sdap_handle_acct_req_done(struct tevent_req *subreq) + err = "Init group lookup failed"; + ret = groups_by_user_recv(subreq, &state->dp_error, &state->sdap_ret); + break; ++ case BE_REQ_SUBID_RANGES: ++ err = "Subid ranges lookup failed"; ++#ifdef BUILD_SUBID ++ ret = subid_ranges_get_recv(subreq, &state->dp_error, &state->sdap_ret); ++#else ++ ret = EINVAL; ++#endif ++ break; + case BE_REQ_NETGROUP: + err = "Netgroup lookup failed"; + ret = ldap_netgroup_get_recv(subreq, &state->dp_error, &state->sdap_ret); +diff --git a/src/providers/ldap/ldap_id_subid.c b/src/providers/ldap/ldap_id_subid.c +new file mode 100644 +index 000000000..d25c6aaac +--- /dev/null ++++ b/src/providers/ldap/ldap_id_subid.c +@@ -0,0 +1,255 @@ ++/* ++ SSSD ++ ++ LDAP Identity Backend Module - subid ranges support ++ ++ Copyright (C) 2021 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 . ++*/ ++ ++#include ++ ++#include "db/sysdb_subid.h" ++#include "providers/ldap/ldap_common.h" ++#include "providers/ldap/sdap_async.h" ++#include "providers/ldap/sdap_ops.h" ++ ++static int subid_ranges_get_retry(struct tevent_req *req); ++static void subid_ranges_get_connect_done(struct tevent_req *subreq); ++static void subid_ranges_get_search(struct tevent_req *req); ++static void subid_ranges_get_done(struct tevent_req *subreq); ++ ++ ++struct subid_ranges_get_state { ++ struct tevent_context *ev; ++ struct sdap_id_ctx *ctx; ++ struct sdap_domain *sdom; ++ struct sdap_id_conn_ctx *conn; ++ struct sdap_id_op *op; ++ struct sss_domain_info *domain; ++ ++ char *filter; ++ char *name; ++ const char **attrs; ++ ++ int dp_error; ++ int sdap_ret; ++}; ++ ++struct tevent_req *subid_ranges_get_send(TALLOC_CTX *memctx, ++ struct tevent_context *ev, ++ struct sdap_id_ctx *ctx, ++ struct sdap_domain *sdom, ++ struct sdap_id_conn_ctx *conn, ++ const char *filter_value, ++ const char *extra_value) ++{ ++ struct tevent_req *req; ++ struct subid_ranges_get_state *state; ++ int ret; ++ ++ req = tevent_req_create(memctx, &state, struct subid_ranges_get_state); ++ if (!req) return NULL; ++ ++ state->ev = ev; ++ state->ctx = ctx; ++ state->sdom = sdom; ++ state->conn = conn; ++ state->dp_error = DP_ERR_FATAL; ++ state->name = talloc_strdup(state, filter_value); ++ if (!state->name) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ state->op = sdap_id_op_create(state, state->conn->conn_cache); ++ if (!state->op) { ++ DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ state->domain = sdom->dom; ++ ++ state->filter = talloc_asprintf(state, ++ "(&(%s=%s)(%s=%s))", ++ SYSDB_OBJECTCLASS, ++ ctx->opts->subid_map[SDAP_OC_SUBID_RANGE].name, ++ ctx->opts->subid_map[SDAP_AT_SUBID_RANGE_OWNER].name, ++ extra_value); ++ ++ ret = subid_ranges_get_retry(req); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ return req; ++ ++done: ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ } else { ++ tevent_req_done(req); ++ } ++ return tevent_req_post(req, ev); ++} ++ ++static int subid_ranges_get_retry(struct tevent_req *req) ++{ ++ struct subid_ranges_get_state *state = tevent_req_data(req, ++ struct subid_ranges_get_state); ++ struct tevent_req *subreq; ++ int ret = EOK; ++ ++ subreq = sdap_id_op_connect_send(state->op, state, &ret); ++ if (!subreq) { ++ return ret; ++ } ++ ++ tevent_req_set_callback(subreq, subid_ranges_get_connect_done, req); ++ return EOK; ++} ++ ++static void subid_ranges_get_connect_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct subid_ranges_get_state *state = tevent_req_data(req, ++ struct subid_ranges_get_state); ++ int dp_error = DP_ERR_FATAL; ++ int ret; ++ ++ ret = sdap_id_op_connect_recv(subreq, &dp_error); ++ talloc_zfree(subreq); ++ ++ if (ret != EOK) { ++ state->dp_error = dp_error; ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ subid_ranges_get_search(req); ++} ++ ++static void subid_ranges_get_search(struct tevent_req *req) ++{ ++ struct subid_ranges_get_state *state = tevent_req_data(req, ++ struct subid_ranges_get_state); ++ struct tevent_req *subreq = NULL; ++ const char **attrs; ++ int ret; ++ ++ ret = build_attrs_from_map(state, state->ctx->opts->subid_map, ++ SDAP_OPTS_SUBID_RANGE, NULL, &attrs, NULL); ++ if (ret != EOK) { ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ ++ subreq = sdap_search_bases_send(state, state->ev, state->ctx->opts, ++ sdap_id_op_handle(state->op), ++ state->sdom->subid_ranges_search_bases, ++ state->ctx->opts->subid_map, ++ false, /* allow_paging */ ++ dp_opt_get_int(state->ctx->opts->basic, ++ SDAP_SEARCH_TIMEOUT), ++ state->filter, ++ attrs, ++ NULL); ++ talloc_free(attrs); ++ if (!subreq) { ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ tevent_req_set_callback(subreq, subid_ranges_get_done, req); ++} ++ ++static void subid_ranges_get_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct subid_ranges_get_state *state = tevent_req_data(req, ++ struct subid_ranges_get_state); ++ int dp_error = DP_ERR_FATAL; ++ int ret; ++ struct sysdb_attrs **results; ++ size_t num_results; ++ ++ ret = sdap_search_bases_recv(subreq, state, &num_results, &results); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ ret = sdap_id_op_done(state->op, ret, &dp_error); ++ if (dp_error == DP_ERR_OK && ret != EOK) { ++ /* retry */ ++ ret = subid_ranges_get_retry(req); ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ return; ++ } ++ state->sdap_ret = ret; ++ ++ if (ret && ret != ENOENT) { ++ DEBUG(SSSDBG_OP_FAILURE, "Failed to retrieve subid ranges.\n"); ++ state->dp_error = dp_error; ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ if (num_results == 0 || !results) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "No such user '%s' or user doesn't have subid range\n", ++ state->name); ++ sysdb_delete_subid_range(state->domain, state->name); ++ } else { ++ if (num_results > 1) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Multiple subid ranges, only first will be processed\n"); ++ } ++ ++ /* store range */ ++ sysdb_store_subid_range(state->domain, state->name, ++ state->domain->user_timeout, ++ results[0]); ++ } ++ ++ state->dp_error = DP_ERR_OK; ++ tevent_req_done(req); ++} ++ ++int subid_ranges_get_recv(struct tevent_req *req, int *dp_error_out, ++ int *sdap_ret) ++{ ++ struct subid_ranges_get_state *state = tevent_req_data(req, ++ struct subid_ranges_get_state); ++ ++ if (dp_error_out) { ++ *dp_error_out = state->dp_error; ++ } ++ ++ if (sdap_ret) { ++ *sdap_ret = state->sdap_ret; ++ } ++ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ ++ return EOK; ++} +diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h +index ffcbee8a5..6382bec25 100644 +--- a/src/providers/ldap/sdap.h ++++ b/src/providers/ldap/sdap.h +@@ -389,6 +389,19 @@ enum sdap_ipnetwork_entry_attrs { + SDAP_OPTS_IPNETWORK /* attrs counter */ + }; + ++#ifdef BUILD_SUBID ++enum sdap_subid_range_attrs { ++ SDAP_OC_SUBID_RANGE = 0, ++ SDAP_AT_SUBID_RANGE_UID_COUNT, ++ SDAP_AT_SUBID_RANGE_GID_COUNT, ++ SDAP_AT_SUBID_RANGE_UID_NUMBER, ++ SDAP_AT_SUBID_RANGE_GID_NUMBER, ++ SDAP_AT_SUBID_RANGE_OWNER, ++ ++ SDAP_OPTS_SUBID_RANGE /* attrs counter */ ++}; ++#endif ++ + enum sdap_autofs_map_attrs { + SDAP_OC_AUTOFS_MAP, + SDAP_AT_AUTOFS_MAP_NAME, +@@ -453,6 +466,9 @@ struct sdap_domain { + struct sdap_search_base **iphost_search_bases; + struct sdap_search_base **ipnetwork_search_bases; + struct sdap_search_base **autofs_search_bases; ++#ifdef BUILD_SUBID ++ struct sdap_search_base **subid_ranges_search_bases; ++#endif + + struct sdap_domain *next, *prev; + /* Need to modify the list from a talloc destructor */ +@@ -495,6 +511,9 @@ struct sdap_options { + struct sdap_attr_map *service_map; + struct sdap_attr_map *iphost_map; + struct sdap_attr_map *ipnetwork_map; ++#ifdef BUILD_SUBID ++ struct sdap_attr_map *subid_map; ++#endif + + /* ID-mapping support */ + struct sdap_idmap_ctx *idmap_ctx; +diff --git a/src/responder/common/cache_req/cache_req.c b/src/responder/common/cache_req/cache_req.c +index 889547ba7..750d655c1 100644 +--- a/src/responder/common/cache_req/cache_req.c ++++ b/src/responder/common/cache_req/cache_req.c +@@ -45,6 +45,10 @@ cache_req_get_plugin(enum cache_req_type type) + &cache_req_initgroups_by_name, + &cache_req_initgroups_by_upn, + ++#ifdef BUILD_SUBID ++ &cache_req_subid_ranges_by_name, ++#endif ++ + &cache_req_object_by_sid, + &cache_req_object_by_name, + &cache_req_object_by_id, +diff --git a/src/responder/common/cache_req/cache_req.h b/src/responder/common/cache_req/cache_req.h +index d5c25ccf0..055fb405b 100644 +--- a/src/responder/common/cache_req/cache_req.h ++++ b/src/responder/common/cache_req/cache_req.h +@@ -39,6 +39,10 @@ enum cache_req_type { + CACHE_REQ_INITGROUPS, + CACHE_REQ_INITGROUPS_BY_UPN, + ++#ifdef BUILD_SUBID ++ CACHE_REQ_SUBID_RANGES_BY_NAME, ++#endif ++ + CACHE_REQ_OBJECT_BY_SID, + CACHE_REQ_OBJECT_BY_NAME, + CACHE_REQ_OBJECT_BY_ID, +diff --git a/src/responder/common/cache_req/cache_req_data.c b/src/responder/common/cache_req/cache_req_data.c +index e82dc8ab6..3c60eb484 100644 +--- a/src/responder/common/cache_req/cache_req_data.c ++++ b/src/responder/common/cache_req/cache_req_data.c +@@ -90,6 +90,9 @@ cache_req_data_create(TALLOC_CTX *mem_ctx, + case CACHE_REQ_GROUP_BY_FILTER: + case CACHE_REQ_INITGROUPS: + case CACHE_REQ_INITGROUPS_BY_UPN: ++#ifdef BUILD_SUBID ++ case CACHE_REQ_SUBID_RANGES_BY_NAME: ++#endif + case CACHE_REQ_NETGROUP_BY_NAME: + case CACHE_REQ_OBJECT_BY_NAME: + case CACHE_REQ_AUTOFS_MAP_ENTRIES: +diff --git a/src/responder/common/cache_req/cache_req_plugin.h b/src/responder/common/cache_req/cache_req_plugin.h +index 9e4986f93..f86a02042 100644 +--- a/src/responder/common/cache_req/cache_req_plugin.h ++++ b/src/responder/common/cache_req/cache_req_plugin.h +@@ -302,6 +302,9 @@ extern const struct cache_req_plugin cache_req_group_by_name; + extern const struct cache_req_plugin cache_req_group_by_id; + extern const struct cache_req_plugin cache_req_initgroups_by_name; + extern const struct cache_req_plugin cache_req_initgroups_by_upn; ++#ifdef BUILD_SUBID ++extern const struct cache_req_plugin cache_req_subid_ranges_by_name; ++#endif + extern const struct cache_req_plugin cache_req_user_by_cert; + extern const struct cache_req_plugin cache_req_user_by_filter; + extern const struct cache_req_plugin cache_req_group_by_filter; +diff --git a/src/responder/common/cache_req/plugins/cache_req_subid_ranges_by_name.c b/src/responder/common/cache_req/plugins/cache_req_subid_ranges_by_name.c +new file mode 100644 +index 000000000..54852711f +--- /dev/null ++++ b/src/responder/common/cache_req/plugins/cache_req_subid_ranges_by_name.c +@@ -0,0 +1,143 @@ ++/* ++ Copyright (C) 2021 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 . ++*/ ++ ++#include ++#include ++ ++#include "db/sysdb.h" ++#include "db/sysdb_subid.h" ++#include "util/util.h" ++#include "providers/data_provider.h" ++#include "responder/common/cache_req/cache_req_plugin.h" ++ ++static errno_t ++cache_req_subid_ranges_by_name_prepare_domain_data(struct cache_req *cr, ++ struct cache_req_data *data, ++ struct sss_domain_info *domain) ++{ ++ TALLOC_CTX *tmp_ctx; ++ const char *name; ++ errno_t ret; ++ ++ if (cr->data->name.name == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Bug: parsed name is NULL?\n"); ++ return ERR_INTERNAL; ++ } ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ name = sss_get_cased_name(tmp_ctx, cr->data->name.name, ++ domain->case_sensitive); ++ if (name == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ name = sss_reverse_replace_space(tmp_ctx, name, cr->rctx->override_space); ++ if (name == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ talloc_zfree(data->name.lookup); ++ data->name.lookup = talloc_steal(data, name); ++ ++ ret = EOK; ++ ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ ++static const char * ++cache_req_subid_ranges_by_name_create_debug_name(TALLOC_CTX *mem_ctx, ++ struct cache_req_data *data, ++ struct sss_domain_info *domain) ++{ ++ return talloc_strdup(mem_ctx, data->name.lookup); ++} ++ ++static errno_t ++cache_req_subid_ranges_by_name_lookup(TALLOC_CTX *mem_ctx, ++ struct cache_req *cr, ++ struct cache_req_data *data, ++ struct sss_domain_info *domain, ++ struct ldb_result **_result) ++{ ++ struct ldb_result *result; ++ struct ldb_message *msg; ++ errno_t ret; ++ ++ ret = sysdb_get_subid_ranges(mem_ctx, domain, data->name.name, ++ data->attrs, &msg); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ result = cache_req_create_ldb_result_from_msg(mem_ctx, msg); ++ if (result == NULL) { ++ return ENOMEM; ++ } ++ ++ *_result = result; ++ ++ return EOK; ++} ++ ++static struct tevent_req * ++cache_req_subid_ranges_by_name_dp_send(TALLOC_CTX *mem_ctx, ++ struct cache_req *cr, ++ struct cache_req_data *data, ++ struct sss_domain_info *domain, ++ struct ldb_result *result) ++{ ++ /* Views aren't yet supported */ ++ return sss_dp_get_account_send(mem_ctx, cr->rctx, domain, true, ++ SSS_DP_SUBID_RANGES, cr->data->name.lookup, 0, NULL); ++} ++ ++const struct cache_req_plugin cache_req_subid_ranges_by_name = { ++ .name = "SubID ranges by name", ++ .attr_expiration = SYSDB_CACHE_EXPIRE, ++ .parse_name = true, ++ .ignore_default_domain = false, ++ .bypass_cache = false, ++ .only_one_result = false, ++ .search_all_domains = false, ++ .require_enumeration = false, ++ .allow_missing_fqn = false, ++ .allow_switch_to_upn = false, ++ .upn_equivalent = CACHE_REQ_SENTINEL, ++ .get_next_domain_flags = SSS_GND_DESCEND, ++ ++ .is_well_known_fn = NULL, ++ .prepare_domain_data_fn = cache_req_subid_ranges_by_name_prepare_domain_data, ++ .create_debug_name_fn = cache_req_subid_ranges_by_name_create_debug_name, ++ .global_ncache_add_fn = NULL, ++ .ncache_check_fn = NULL, ++ .ncache_add_fn = NULL, ++ .ncache_filter_fn = NULL, ++ .lookup_fn = cache_req_subid_ranges_by_name_lookup, ++ .dp_send_fn = cache_req_subid_ranges_by_name_dp_send, ++ .dp_recv_fn = cache_req_common_dp_recv, ++ .dp_get_domain_check_fn = NULL, ++ .dp_get_domain_send_fn = NULL, ++ .dp_get_domain_recv_fn = NULL, ++}; +diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h +index a5d6359a0..fbe46f335 100644 +--- a/src/responder/common/responder.h ++++ b/src/responder/common/responder.h +@@ -273,6 +273,7 @@ enum sss_dp_acct_type { + SSS_DP_USER = 1, + SSS_DP_GROUP, + SSS_DP_INITGROUPS, ++ SSS_DP_SUBID_RANGES, + SSS_DP_NETGR, + SSS_DP_SERVICES, + SSS_DP_SECID, +diff --git a/src/responder/common/responder_dp.c b/src/responder/common/responder_dp.c +index 8076e1e43..1b016dba1 100644 +--- a/src/responder/common/responder_dp.c ++++ b/src/responder/common/responder_dp.c +@@ -70,6 +70,7 @@ sss_dp_account_files_params(struct sss_domain_info *dom, + *_opt_name_out = opt_name_in; + return EAGAIN; + /* These are not handled by the files provider, just fall back */ ++ case SSS_DP_SUBID_RANGES: + case SSS_DP_NETGR: + case SSS_DP_SERVICES: + case SSS_DP_SECID: +@@ -109,6 +110,9 @@ sss_dp_get_account_filter(TALLOC_CTX *mem_ctx, + case SSS_DP_INITGROUPS: + entry_type = BE_REQ_INITGROUPS; + break; ++ case SSS_DP_SUBID_RANGES: ++ entry_type = BE_REQ_SUBID_RANGES; ++ break; + case SSS_DP_NETGR: + entry_type = BE_REQ_NETGROUP; + break; +diff --git a/src/responder/nss/nss_cmd.c b/src/responder/nss/nss_cmd.c +index a487e1c24..ef59daea8 100644 +--- a/src/responder/nss/nss_cmd.c ++++ b/src/responder/nss/nss_cmd.c +@@ -1041,6 +1041,25 @@ static errno_t nss_cmd_initgroups_ex(struct cli_ctx *cli_ctx) + SSS_MC_INITGROUPS, nss_protocol_fill_initgr); + } + ++static errno_t nss_cmd_subid_ranges(struct cli_ctx *cli_ctx) ++{ ++#ifdef BUILD_SUBID ++ const char *attrs[] = ++ { ++ SYSDB_SUBID_UID_COUND, ++ SYSDB_SUBID_GID_COUNT, ++ SYSDB_SUBID_UID_NUMBER, ++ SYSDB_SUBID_GID_NUMBER, ++ NULL ++ }; ++ ++ return nss_getby_name(cli_ctx, false, CACHE_REQ_SUBID_RANGES_BY_NAME, attrs, ++ SSS_MC_NONE, nss_protocol_fill_subid_ranges); ++#else ++ return ENOTSUP; ++#endif ++} ++ + static errno_t nss_cmd_setnetgrent(struct cli_ctx *cli_ctx) + { + struct nss_state_ctx *state_ctx; +@@ -1332,6 +1351,7 @@ struct sss_cmd_table *get_nss_cmds(void) + { SSS_NSS_GETGRENT, nss_cmd_getgrent }, + { SSS_NSS_ENDGRENT, nss_cmd_endgrent }, + { SSS_NSS_INITGR, nss_cmd_initgroups }, ++ { SSS_NSS_GET_SUBID_RANGES, nss_cmd_subid_ranges }, + { SSS_NSS_SETNETGRENT, nss_cmd_setnetgrent }, + /* { SSS_NSS_GETNETGRENT, "not needed" }, */ + /* { SSS_NSS_ENDNETGRENT, "not needed" }, */ +diff --git a/src/responder/nss/nss_protocol.h b/src/responder/nss/nss_protocol.h +index 364f19c83..949b6291a 100644 +--- a/src/responder/nss/nss_protocol.h ++++ b/src/responder/nss/nss_protocol.h +@@ -147,6 +147,14 @@ nss_protocol_fill_initgr(struct nss_ctx *nss_ctx, + struct sss_packet *packet, + struct cache_req_result *result); + ++#ifdef BUILD_SUBID ++errno_t ++nss_protocol_fill_subid_ranges(struct nss_ctx *nss_ctx, ++ struct nss_cmd_ctx *cmd_ctx, ++ struct sss_packet *packet, ++ struct cache_req_result *result); ++#endif ++ + errno_t + nss_protocol_fill_netgrent(struct nss_ctx *nss_ctx, + struct nss_cmd_ctx *cmd_ctx, +diff --git a/src/responder/nss/nss_protocol_subid.c b/src/responder/nss/nss_protocol_subid.c +new file mode 100644 +index 000000000..29a957762 +--- /dev/null ++++ b/src/responder/nss/nss_protocol_subid.c +@@ -0,0 +1,60 @@ ++/* ++ Copyright (C) 2021 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 . ++*/ ++ ++#include "responder/nss/nss_protocol.h" ++ ++errno_t ++nss_protocol_fill_subid_ranges(struct nss_ctx *nss_ctx, ++ struct nss_cmd_ctx *cmd_ctx, ++ struct sss_packet *packet, ++ struct cache_req_result *result) ++{ ++ static const uint32_t one = 1; ++ errno_t ret; ++ uint8_t *body; ++ size_t body_len; ++ size_t rp = 0; ++ uint32_t gid, uid, gidCount, uidCount; ++ ++ if (!result->count || !result->msgs) { ++ return ENOENT; ++ } ++ ++ uid = ldb_msg_find_attr_as_uint(result->msgs[0], SYSDB_SUBID_UID_NUMBER, 0); ++ uidCount = ldb_msg_find_attr_as_uint(result->msgs[0], SYSDB_SUBID_UID_COUND, 0); ++ gid = ldb_msg_find_attr_as_uint(result->msgs[0], SYSDB_SUBID_GID_NUMBER, 0); ++ gidCount = ldb_msg_find_attr_as_uint(result->msgs[0], SYSDB_SUBID_GID_COUNT, 0); ++ if (!uid || !gid || !gidCount || !uidCount) { ++ return ENOENT; ++ } ++ ++ /* only single uid & gid range is expected currently */ ++ ret = sss_packet_grow(packet, (2 + 2*2) * sizeof(uint32_t)); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ sss_packet_get_body(packet, &body, &body_len); ++ SAFEALIGN_COPY_UINT32(&body[rp], &one, &rp); ++ SAFEALIGN_COPY_UINT32(&body[rp], &one, &rp); ++ SAFEALIGN_COPY_UINT32(&body[rp], &uid, &rp); ++ SAFEALIGN_COPY_UINT32(&body[rp], &uidCount, &rp); ++ SAFEALIGN_COPY_UINT32(&body[rp], &gid, &rp); ++ SAFEALIGN_COPY_UINT32(&body[rp], &gidCount, &rp); ++ ++ return EOK; ++} +diff --git a/src/sss_client/common.c b/src/sss_client/common.c +index d29332939..9416e21d1 100644 +--- a/src/sss_client/common.c ++++ b/src/sss_client/common.c +@@ -1008,7 +1008,7 @@ void sss_pam_close_fd(void) + sss_pam_unlock(); + } + +-static enum sss_status ++enum sss_status + sss_cli_make_request_with_checks(enum sss_cli_command cmd, + struct sss_cli_req_data *rd, + int timeout, +diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h +index 2c3c71bc4..1347ce71d 100644 +--- a/src/sss_client/sss_cli.h ++++ b/src/sss_client/sss_cli.h +@@ -284,6 +284,10 @@ SSS_NSS_GETSIDBYGID = 0x0119, /**< Takes an unsigned 32bit integer (POSIX GID) + and return the zero terminated string + representation of the SID of the object + with the given UID. */ ++ ++/* subid */ ++ SSS_NSS_GET_SUBID_RANGES = 0x0130, /**< Requests both subuid and subgid ranges ++ defined for a user. */ + }; + + /** +@@ -631,6 +635,13 @@ enum sss_cli_error_codes { + + const char *ssscli_err2string(int err); + ++enum sss_status sss_cli_make_request_with_checks(enum sss_cli_command cmd, ++ struct sss_cli_req_data *rd, ++ int timeout, ++ uint8_t **repbuf, size_t *replen, ++ int *errnop, ++ const char *socket_name); ++ + enum nss_status sss_nss_make_request(enum sss_cli_command cmd, + struct sss_cli_req_data *rd, + uint8_t **repbuf, size_t *replen, +diff --git a/src/sss_client/subid/sss_subid.c b/src/sss_client/subid/sss_subid.c +new file mode 100644 +index 000000000..ae74ece3c +--- /dev/null ++++ b/src/sss_client/subid/sss_subid.c +@@ -0,0 +1,209 @@ ++/* ++ Copyright (C) 2021 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 . ++*/ ++ ++#include ++#include ++#include ++#include "sss_cli.h" ++ ++/* This shadow-utils plugin contains partial SSSD implementation ++ * of `subid_nss_ops` API as described in ++ * https://github.com/shadow-maint/shadow/blob/d4b6d1549b2af48ce3cb6ff78d9892095fb8fdd9/lib/prototypes.h#L271 ++ */ ++ ++/* Find all subid ranges delegated to a user. ++ * ++ * Usage in shadow-utils: ++ * libsubid: get_sub?id_ranges() -> list_owner_ranges() ++ * ++ * SUBID_RANGES Reply: ++ * ++ * 0-3: 32bit unsigned number of UID results ++ * 4-7: 32bit unsigned number of GID results ++ * For each result (sub-uid ranges first): ++ * 0-3: 32bit number with "start" id ++ * 4-7: 32bit number with "count" (range size) ++ */ ++enum subid_status shadow_subid_list_owner_ranges(const char *user, ++ enum subid_type id_type, ++ struct subid_range **ranges, ++ int *count) ++{ ++ size_t user_len; ++ enum sss_status ret; ++ uint8_t *repbuf = NULL; ++ size_t index = 0; ++ size_t replen; ++ int errnop; ++ struct sss_cli_req_data rd; ++ uint32_t num_results = 0; ++ uint32_t val; ++ ++ if ( !user || !ranges || !count || ++ ((id_type != ID_TYPE_UID) && (id_type != ID_TYPE_GID)) ) { ++ return SUBID_STATUS_ERROR; ++ } ++ ++ ret = sss_strnlen(user, SSS_NAME_MAX, &user_len); ++ if (ret != 0) { ++ return SUBID_STATUS_UNKNOWN_USER; ++ } ++ rd.len = user_len + 1; ++ rd.data = user; ++ ++ sss_nss_lock(); ++ /* Anticipated workflow will always request both ++ * sub-uid and sub-gid ranges anyway. ++ * So don't bother with dedicated commands - ++ * just request everything in one shot. ++ * The second request will get data from the cache. ++ */ ++ ret = sss_cli_make_request_with_checks(SSS_NSS_GET_SUBID_RANGES, &rd, ++ SSS_CLI_SOCKET_TIMEOUT, ++ &repbuf, &replen, &errnop, ++ SSS_NSS_SOCKET_NAME); ++ sss_nss_unlock(); ++ ++ if ((ret != SSS_STATUS_SUCCESS) || (errnop != EOK)) { ++ free(repbuf); ++ if (ret == SSS_STATUS_UNAVAIL) { ++ return SUBID_STATUS_ERROR_CONN; ++ } ++ return SUBID_STATUS_ERROR; ++ } ++ ++ SAFEALIGN_COPY_UINT32(&num_results, repbuf, NULL); ++ if (id_type == ID_TYPE_UID) { ++ index = 2 * sizeof(uint32_t); ++ } else { ++ index = (2 + 2*num_results) * sizeof(uint32_t); ++ SAFEALIGN_COPY_UINT32(&num_results, repbuf + sizeof(uint32_t), NULL); ++ } ++ if (num_results == 0) { ++ /* TODO: how to distinguish "user not found" vs "user doesn't have ranges defined" here? ++ * Options: ++ * - special "fake" entry in the cache ++ * - provide 'nss_protocol_done_fn' to 'nss_getby_name' to avoid "ENOENT -> "empty packet" logic ++ * - add custom error code for this case and handle in generic 'nss_protocol_done' ++ * ++ * Note: at the moment this is not important, since shadow-utils doesn't use return code internally ++ * and returns -1 from libsubid on any error anyway. ++ */ ++ free(repbuf); ++ return SUBID_STATUS_UNKNOWN_USER; ++ } ++ ++ *count = num_results; ++ if (*count < 0) { ++ free(repbuf); ++ return SUBID_STATUS_ERROR; ++ } ++ ++ *ranges = malloc(num_results * sizeof(struct subid_range)); ++ if (!*ranges) { ++ free(repbuf); ++ return SUBID_STATUS_ERROR; ++ } ++ ++ for (uint32_t c = 0; c < num_results; ++c) { ++ SAFEALIGN_COPY_UINT32(&val, repbuf + index, &index); ++ (*ranges)[c].start = val; ++ SAFEALIGN_COPY_UINT32(&val, repbuf + index, &index); ++ (*ranges)[c].count = val; ++ } ++ free(repbuf); ++ ++ return SUBID_STATUS_SUCCESS; ++} ++ ++/* Does a user own a given subid range? ++ * ++ * Usage in shadow-utils: ++ * newuidmap/user busy : have_sub_uids() -> has_range() ++ */ ++enum subid_status shadow_subid_has_range(const char *owner, ++ unsigned long start, ++ unsigned long count, ++ enum subid_type id_type, ++ bool *result) ++{ ++ enum subid_status ret; ++ struct subid_range *range; ++ int amount; ++ unsigned long end = start + count; ++ ++ if (!result || (end < start)) { ++ return SUBID_STATUS_ERROR; ++ } ++ ++ if (count == 0) { ++ *result = true; ++ return SUBID_STATUS_SUCCESS; ++ } ++ ++ /* Anticipated workflow is the following: ++ * ++ * 1) Podman figures out ranges available for a user: ++ * libsubid::get_subid_ranges() -> ... -> list_owner_ranges() ++ * ++ * 2) Podman maps available ranges: ++ * newuidmap -> have_sub_uids() -> has_range() ++ * At this point all ranges are available in a cache from step (1) ++ * so it doesn't make sense to try "smart" LDAP searches (even if possible) ++ * Let's just reuse list_owner_ranges() and do a check. ++ * ++ * It might have some sense to do a check at responder's side (i.e. without ++ * fetching all ranges), but range is just a couple of numbers (and FreeIPA ++ * only supports a single range per user anyway), so this optimization ++ * wouldn't save much traffic anyway, but would introduce new ++ * `sss_cli_command`/responder handler. ++ */ ++ ++ ret = shadow_subid_list_owner_ranges(owner, id_type, &range, &amount); ++ if (ret != SUBID_STATUS_SUCCESS) { ++ return ret; ++ } ++ ++ *result = false; ++ ++ for (int i = 0; i < amount; ++i) { ++ if ((range[i].start <= start) && ++ (range[i].start + range[i].count >= end)) { ++ *result = true; ++ } ++ /* TODO: handle coverage via multiple ranges (once IPA supports this) */ ++ } ++ ++ free(range); ++ return ret; ++} ++ ++/* Find uids who own a given subid. ++ * ++ * Usage in shadow-utils: ++ * libsubid: get_sub?id_owners() -> find_subid_owners() ++ */ ++enum subid_status shadow_subid_find_subid_owners(unsigned long subid, ++ enum subid_type id_type, ++ uid_t **uids, ++ int *count) ++{ ++ /* Not yet implemented. ++ * Currently there are no users of this function. ++ */ ++ return SUBID_STATUS_ERROR; ++} +diff --git a/src/sss_client/subid/sss_subid.exports b/src/sss_client/subid/sss_subid.exports +new file mode 100644 +index 000000000..87c073b48 +--- /dev/null ++++ b/src/sss_client/subid/sss_subid.exports +@@ -0,0 +1,12 @@ ++EXPORTED { ++ ++ # public functions ++ global: ++ shadow_subid_has_range; ++ shadow_subid_list_owner_ranges; ++ shadow_subid_find_subid_owners; ++ ++ # everything else is local ++ local: ++ *; ++}; +diff --git a/src/systemtap/sssd_functions.stp b/src/systemtap/sssd_functions.stp +index 01f553177..513029046 100644 +--- a/src/systemtap/sssd_functions.stp ++++ b/src/systemtap/sssd_functions.stp +@@ -29,8 +29,8 @@ function acct_req_desc(entry_type) + str_entry_type = "host" + } else if (entry_type == 0x0009) { + str_entry_type = "ip_network" +- # See src/providers/data_provider_req.h, no 0x0010 there.. + } else if (entry_type == 0x0010) { ++ str_entry_type = "subid_ranges" + } else if (entry_type == 0x0011) { + str_entry_type = "by_secid" + } else if (entry_type == 0x0012) { +diff --git a/src/tests/cwrap/Makefile.am b/src/tests/cwrap/Makefile.am +index 60f71036e..6d3dc45e5 100644 +--- a/src/tests/cwrap/Makefile.am ++++ b/src/tests/cwrap/Makefile.am +@@ -74,6 +74,9 @@ SSSD_CACHE_REQ_OBJ = \ + ../../../src/responder/common/cache_req/plugins/cache_req_ip_network_by_name.c \ + ../../../src/responder/common/cache_req/plugins/cache_req_ip_network_by_addr.c \ + $(NULL) ++if BUILD_SUBID ++ SSSD_CACHE_REQ_OBJ += ../../../src/responder/common/cache_req/plugins/cache_req_subid_ranges_by_name.c ++endif + + SSSD_RESPONDER_IFACE_OBJ = \ + ../../../src/responder/common/responder_iface.c \ +diff --git a/src/tests/dlopen-tests.c b/src/tests/dlopen-tests.c +index ab44c213c..6d3345cbe 100644 +--- a/src/tests/dlopen-tests.c ++++ b/src/tests/dlopen-tests.c +@@ -60,6 +60,9 @@ struct so { + #ifdef BUILD_AUTOFS + { "libsss_autofs.so", { LIBPFX"libsss_autofs.so", NULL } }, + #endif ++#ifdef BUILD_SUBID ++ { "libsubid_sss.so", { LIBPFX"libsubid_sss.so", NULL } }, ++#endif + #ifdef HAVE_KRB5_LOCATOR_PLUGIN + { "sssd_krb5_locator_plugin.so", { LIBPFX"sssd_krb5_locator_plugin.so", + NULL } }, +diff --git a/src/util/sss_cli_cmd.c b/src/util/sss_cli_cmd.c +index 82dc33b33..bc9332aaa 100644 +--- a/src/util/sss_cli_cmd.c ++++ b/src/util/sss_cli_cmd.c +@@ -230,6 +230,11 @@ const char *sss_cmd2str(enum sss_cli_command cmd) + return "SSS_NSS_GETIDBYSID"; + case SSS_NSS_GETORIGBYNAME: + return "SSS_NSS_GETORIGBYNAME"; ++ ++ /* SUBID ranges */ ++ case SSS_NSS_GET_SUBID_RANGES: ++ return "SSS_NSS_GET_SUBID_RANGES"; ++ + default: + DEBUG(SSSDBG_MINOR_FAILURE, + "Translation's string is missing for command [%#x].\n", cmd); +diff --git a/src/util/util_errors.c b/src/util/util_errors.c +index 7ba2621d1..f2d1d5dfc 100644 +--- a/src/util/util_errors.c ++++ b/src/util/util_errors.c +@@ -120,6 +120,7 @@ struct err_string error_to_str[] = { + { "Unable to verify peer" }, /* ERR_UNABLE_TO_VERIFY_PEER */ + { "Unable to resolve host" }, /* ERR_UNABLE_TO_RESOLVE_HOST */ + { "GetAccountDomain() not supported" }, /* ERR_GET_ACCT_DOM_NOT_SUPPORTED */ ++ { "Subid ranges are not supported by this provider" }, /* ERR_GET_ACCT_SUBID_RANGES_NOT_SUPPORTED */ + { "The last GetAccountDomain() result is still valid" }, /* ERR_GET_ACCT_DOM_CACHED */ + { "ID is outside the allowed range" }, /* ERR_ID_OUTSIDE_RANGE */ + { "Group ID is duplicated" }, /* ERR_GID_DUPLICATED */ +diff --git a/src/util/util_errors.h b/src/util/util_errors.h +index 37ce2de23..4098e818d 100644 +--- a/src/util/util_errors.h ++++ b/src/util/util_errors.h +@@ -141,6 +141,7 @@ enum sssd_errors { + ERR_UNABLE_TO_VERIFY_PEER, + ERR_UNABLE_TO_RESOLVE_HOST, + ERR_GET_ACCT_DOM_NOT_SUPPORTED, ++ ERR_GET_ACCT_SUBID_RANGES_NOT_SUPPORTED, + ERR_GET_ACCT_DOM_CACHED, + ERR_ID_OUTSIDE_RANGE, + ERR_GID_DUPLICATED, +-- +2.26.3 + diff --git a/sssd.spec b/sssd.spec index cff843e..3cb5f16 100644 --- a/sssd.spec +++ b/sssd.spec @@ -27,13 +27,14 @@ Name: sssd Version: 2.5.2 -Release: 1%{?dist} +Release: 2%{?dist} Summary: System Security Services Daemon License: GPLv3+ URL: https://github.com/SSSD/sssd/ Source0: https://github.com/SSSD/sssd/releases/download/2.5.2/sssd-2.5.2.tar.gz ### Patches ### +Patch0001: 0001-Basics-of-subid-ranges-support-for-IPA-provider.patch ### Dependencies ### @@ -119,6 +120,7 @@ BuildRequires: systemd-devel BuildRequires: systemtap-sdt-devel BuildRequires: uid_wrapper BuildRequires: po4a +BuildRequires: shadow-utils-subid-devel %description Provides a set of daemons to manage access to remote directories and @@ -500,6 +502,7 @@ autoreconf -ivf --with-sssd-user=%{sssd_user} \ --with-syslog=journald \ --with-test-dir=/dev/shm \ + --with-subid \ %if 0%{?fedora} --enable-files-domain \ --disable-polkit-rules-path \ @@ -806,6 +809,7 @@ done %files client -f sssd_client.lang %license src/sss_client/COPYING src/sss_client/COPYING.LESSER %{_libdir}/libnss_sss.so.2 +%{_libdir}/libsubid_sss.so %{_libdir}/security/pam_sss.so %{_libdir}/security/pam_sss_gss.so %{_libdir}/krb5/plugins/libkrb5/sssd_krb5_locator_plugin.so @@ -1013,7 +1017,10 @@ fi %systemd_postun_with_restart sssd.service %changelog -* Fri Jul 16 2021 Alexey Tikhonov - 2.5.2-1 +* Mon Aug 02 2021 Alexey Tikhonov - 2.5.2-2 +- Resolves: rhbz#1803943 - [RFE] support subid ranges managed by FreeIPA + +* Fri Jul 16 2021 Alexey Tikhonov - 2.5.2-1 - Resolves: rhbz#1952922 - Rebase SSSD for RHEL 9-Beta - Resolves: rhbz#1975691 - covscan NULL pointer dereference cache_req_data_create()