Compare commits

...

No commits in common. "c8" and "c9-beta" have entirely different histories.
c8 ... c9-beta

17 changed files with 1456 additions and 1923 deletions

2
.gitignore vendored
View File

@ -1 +1 @@
SOURCES/sssd-2.9.4.tar.gz SOURCES/sssd-2.9.5.tar.gz

View File

@ -1 +1 @@
574f6cec9ee12dd943e4305286845343ab7bb891 SOURCES/sssd-2.9.4.tar.gz f6704a9df1303e154ef8526f9f21e2b72879c046 SOURCES/sssd-2.9.5.tar.gz

View File

@ -0,0 +1,34 @@
From ee8de7e404ba65062e0b373f2badc0475835bbde Mon Sep 17 00:00:00 2001
From: Iker Pedrosa <ipedrosa@redhat.com>
Date: Tue, 11 Jun 2024 15:57:23 +0200
Subject: [PATCH] spec: change passkey_child owner
passkey_child owner was incorrectly set to $sssd_user:$sssd_user, when
it should be root:root. Correcting it.
Fixes: 30daa0ccdae5 ("spec: update to include passkey")
Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
Reviewed-by: Alexey Tikhonov <atikhono@redhat.com>
(cherry picked from commit bb72b53d3a222f016d882853a619bd74c237edf9)
---
contrib/sssd.spec.in | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in
index 03171a872..3735d4f06 100644
--- a/contrib/sssd.spec.in
+++ b/contrib/sssd.spec.in
@@ -998,7 +998,7 @@ done
%if %{build_passkey}
%files passkey
-%attr(755,%{sssd_user},%{sssd_user}) %{_libexecdir}/%{servicename}/passkey_child
+%{_libexecdir}/%{servicename}/passkey_child
%{_libdir}/%{name}/modules/sssd_krb5_passkey_plugin.so
%{_datadir}/sssd/krb5-snippets/sssd_enable_passkey
%config(noreplace) %{_sysconfdir}/krb5.conf.d/sssd_enable_passkey
--
2.44.0

View File

@ -1,144 +0,0 @@
From dd0f63246aa75d5f53b44cbc185e88833e79976e Mon Sep 17 00:00:00 2001
From: Andre Boscatto <andreboscatto@gmail.com>
Date: Wed, 7 Feb 2024 12:28:28 +0100
Subject: [PATCH] sssd: adding mail as case insensitive
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Resolves: https://github.com/SSSD/sssd/issues/7173
Reviewed-by: Iker Pedrosa <ipedrosa@redhat.com>
Reviewed-by: Tomáš Halman <thalman@redhat.com>
(cherry picked from commit 945cebcf72ef53ea0368f19c09e710f7fff11b51)
---
src/db/sysdb_init.c | 7 ++++++
src/db/sysdb_private.h | 5 +++-
src/db/sysdb_upgrade.c | 56 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 67 insertions(+), 1 deletion(-)
diff --git a/src/db/sysdb_init.c b/src/db/sysdb_init.c
index c2ea6c369..38a9cd64a 100644
--- a/src/db/sysdb_init.c
+++ b/src/db/sysdb_init.c
@@ -603,6 +603,13 @@ static errno_t sysdb_domain_cache_upgrade(TALLOC_CTX *mem_ctx,
}
}
+ if (strcmp(version, SYSDB_VERSION_0_23) == 0) {
+ ret = sysdb_upgrade_23(sysdb, &version);
+ if (ret != EOK) {
+ goto done;
+ }
+ }
+
ret = EOK;
done:
sysdb->ldb = save_ldb;
diff --git a/src/db/sysdb_private.h b/src/db/sysdb_private.h
index 1f55007bc..63f7b5601 100644
--- a/src/db/sysdb_private.h
+++ b/src/db/sysdb_private.h
@@ -23,6 +23,7 @@
#ifndef __INT_SYS_DB_H__
#define __INT_SYS_DB_H__
+#define SYSDB_VERSION_0_24 "0.24"
#define SYSDB_VERSION_0_23 "0.23"
#define SYSDB_VERSION_0_22 "0.22"
#define SYSDB_VERSION_0_21 "0.21"
@@ -47,7 +48,7 @@
#define SYSDB_VERSION_0_2 "0.2"
#define SYSDB_VERSION_0_1 "0.1"
-#define SYSDB_VERSION SYSDB_VERSION_0_23
+#define SYSDB_VERSION SYSDB_VERSION_0_24
#define SYSDB_BASE_LDIF \
"dn: @ATTRIBUTES\n" \
@@ -60,6 +61,7 @@
"objectclass: CASE_INSENSITIVE\n" \
"ipHostNumber: CASE_INSENSITIVE\n" \
"ipNetworkNumber: CASE_INSENSITIVE\n" \
+ "mail: CASE_INSENSITIVE\n" \
"\n" \
"dn: @INDEXLIST\n" \
"@IDXATTR: cn\n" \
@@ -191,6 +193,7 @@ int sysdb_upgrade_19(struct sysdb_ctx *sysdb, const char **ver);
int sysdb_upgrade_20(struct sysdb_ctx *sysdb, const char **ver);
int sysdb_upgrade_21(struct sysdb_ctx *sysdb, const char **ver);
int sysdb_upgrade_22(struct sysdb_ctx *sysdb, const char **ver);
+int sysdb_upgrade_23(struct sysdb_ctx *sysdb, const char **ver);
int sysdb_ts_upgrade_01(struct sysdb_ctx *sysdb, const char **ver);
diff --git a/src/db/sysdb_upgrade.c b/src/db/sysdb_upgrade.c
index 346a1cb0b..56083e6be 100644
--- a/src/db/sysdb_upgrade.c
+++ b/src/db/sysdb_upgrade.c
@@ -2718,6 +2718,62 @@ done:
return ret;
}
+int sysdb_upgrade_23(struct sysdb_ctx *sysdb, const char **ver)
+{
+ TALLOC_CTX *tmp_ctx;
+ int ret;
+ struct ldb_message *msg;
+ struct upgrade_ctx *ctx;
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) {
+ return ENOMEM;
+ }
+
+ ret = commence_upgrade(sysdb, sysdb->ldb, SYSDB_VERSION_0_24, &ctx);
+ if (ret) {
+ return ret;
+ }
+
+ /* Add new indexes */
+ msg = ldb_msg_new(tmp_ctx);
+ if (!msg) {
+ ret = ENOMEM;
+ goto done;
+ }
+ msg->dn = ldb_dn_new(tmp_ctx, sysdb->ldb, "@ATTRIBUTES");
+ if (!msg->dn) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ /* Case insensitive search for mail */
+ ret = ldb_msg_add_empty(msg, SYSDB_USER_EMAIL, LDB_FLAG_MOD_ADD, NULL);
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+ ret = ldb_msg_add_string(msg, SYSDB_USER_EMAIL, "CASE_INSENSITIVE");
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_modify(sysdb->ldb, msg);
+ if (ret != LDB_SUCCESS) {
+ ret = sysdb_error_to_errno(ret);
+ goto done;
+ }
+
+ /* conversion done, update version number */
+ ret = update_version(ctx);
+
+done:
+ ret = finish_upgrade(ret, &ctx, ver);
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
int sysdb_ts_upgrade_01(struct sysdb_ctx *sysdb, const char **ver)
{
struct upgrade_ctx *ctx;
--
2.41.0

View File

@ -1,154 +0,0 @@
From a7621a5b464af7a3c8409dcbde038b35fee2c895 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Tue, 23 Jan 2024 13:47:53 +0100
Subject: [PATCH 2/3] sdap: add search_bases option to groups_by_user_send()
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
AD handles users and computer objects very similar and so does SSSD's
GPO code when lookup up the host's group-memberships. But users and
computers might be stored in different sub-tree of the AD LDAP tree and
if a dedicated user search base is given with the ldap_user_search_base
option in sssd.conf the host object might be in a different sub-tree. To
make sure the host can still be found this patch uses the base DN of
the LDAP tree when searching for hosts in the GPO code.
Resolves: https://github.com/SSSD/sssd/issues/5708
Reviewed-by: Alejandro López <allopez@redhat.com>
Reviewed-by: Tomáš Halman <thalman@redhat.com>
(cherry picked from commit 29a77c6e79020d7e8cb474b4d3b394d390eba196)
---
src/providers/ad/ad_gpo.c | 10 ++++++++++
src/providers/ldap/ldap_common.h | 1 +
src/providers/ldap/ldap_id.c | 6 +++++-
src/providers/ldap/sdap_async.h | 1 +
src/providers/ldap/sdap_async_initgroups.c | 4 +++-
5 files changed, 20 insertions(+), 2 deletions(-)
diff --git a/src/providers/ad/ad_gpo.c b/src/providers/ad/ad_gpo.c
index 94959c36b..b0ee3e616 100644
--- a/src/providers/ad/ad_gpo.c
+++ b/src/providers/ad/ad_gpo.c
@@ -2091,6 +2091,7 @@ ad_gpo_connect_done(struct tevent_req *subreq)
char *server_uri;
LDAPURLDesc *lud;
struct sdap_domain *sdom;
+ struct sdap_search_base **search_bases;
req = tevent_req_callback_data(subreq, struct tevent_req);
state = tevent_req_data(req, struct ad_gpo_access_state);
@@ -2184,9 +2185,18 @@ ad_gpo_connect_done(struct tevent_req *subreq)
goto done;
}
+ ret = common_parse_search_base(state, sdom->basedn, state->ldb_ctx,
+ "AD_HOSTS", NULL, &search_bases);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Failed to create dedicated search base for host lookups, "
+ "trying with user search base.");
+ }
+
subreq = groups_by_user_send(state, state->ev,
state->access_ctx->ad_id_ctx->sdap_id_ctx,
sdom, state->conn,
+ search_bases,
state->host_fqdn,
BE_FILTER_NAME,
NULL,
diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h
index 7159d6356..2c984ef50 100644
--- a/src/providers/ldap/ldap_common.h
+++ b/src/providers/ldap/ldap_common.h
@@ -304,6 +304,7 @@ struct tevent_req *groups_by_user_send(TALLOC_CTX *memctx,
struct sdap_id_ctx *ctx,
struct sdap_domain *sdom,
struct sdap_id_conn_ctx *conn,
+ struct sdap_search_base **search_bases,
const char *filter_value,
int filter_type,
const char *extra_value,
diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c
index da54816bd..b3ea2333f 100644
--- a/src/providers/ldap/ldap_id.c
+++ b/src/providers/ldap/ldap_id.c
@@ -1139,6 +1139,7 @@ struct groups_by_user_state {
struct sdap_id_op *op;
struct sysdb_ctx *sysdb;
struct sss_domain_info *domain;
+ struct sdap_search_base **search_bases;
const char *filter_value;
int filter_type;
@@ -1160,6 +1161,7 @@ struct tevent_req *groups_by_user_send(TALLOC_CTX *memctx,
struct sdap_id_ctx *ctx,
struct sdap_domain *sdom,
struct sdap_id_conn_ctx *conn,
+ struct sdap_search_base **search_bases,
const char *filter_value,
int filter_type,
const char *extra_value,
@@ -1192,6 +1194,7 @@ struct tevent_req *groups_by_user_send(TALLOC_CTX *memctx,
state->extra_value = extra_value;
state->domain = sdom->dom;
state->sysdb = sdom->dom->sysdb;
+ state->search_bases = search_bases;
if (state->domain->type == DOM_TYPE_APPLICATION || set_non_posix) {
state->non_posix = true;
@@ -1254,6 +1257,7 @@ static void groups_by_user_connect_done(struct tevent_req *subreq)
sdap_id_op_handle(state->op),
state->ctx,
state->conn,
+ state->search_bases,
state->filter_value,
state->filter_type,
state->extra_value,
@@ -1449,7 +1453,7 @@ sdap_handle_acct_req_send(TALLOC_CTX *mem_ctx,
}
subreq = groups_by_user_send(state, be_ctx->ev, id_ctx,
- sdom, conn,
+ sdom, conn, NULL,
ar->filter_value,
ar->filter_type,
ar->extra_value,
diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h
index 5458d21f1..89245f41f 100644
--- a/src/providers/ldap/sdap_async.h
+++ b/src/providers/ldap/sdap_async.h
@@ -158,6 +158,7 @@ struct tevent_req *sdap_get_initgr_send(TALLOC_CTX *memctx,
struct sdap_handle *sh,
struct sdap_id_ctx *id_ctx,
struct sdap_id_conn_ctx *conn,
+ struct sdap_search_base **search_bases,
const char *name,
int filter_type,
const char *extra_value,
diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c
index 97be594a3..fb3d8fe24 100644
--- a/src/providers/ldap/sdap_async_initgroups.c
+++ b/src/providers/ldap/sdap_async_initgroups.c
@@ -2732,6 +2732,7 @@ struct tevent_req *sdap_get_initgr_send(TALLOC_CTX *memctx,
struct sdap_handle *sh,
struct sdap_id_ctx *id_ctx,
struct sdap_id_conn_ctx *conn,
+ struct sdap_search_base **search_bases,
const char *filter_value,
int filter_type,
const char *extra_value,
@@ -2764,7 +2765,8 @@ struct tevent_req *sdap_get_initgr_send(TALLOC_CTX *memctx,
state->orig_user = NULL;
state->timeout = dp_opt_get_int(state->opts->basic, SDAP_SEARCH_TIMEOUT);
state->user_base_iter = 0;
- state->user_search_bases = sdom->user_search_bases;
+ state->user_search_bases = (search_bases == NULL) ? sdom->user_search_bases
+ : search_bases;
if (!state->user_search_bases) {
DEBUG(SSSDBG_CRIT_FAILURE,
"Initgroups lookup request without a user search base\n");
--
2.41.0

View File

@ -0,0 +1,58 @@
From d234cf5d6e793daf2c96856887acb641c4dff407 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Fri, 14 Jun 2024 16:10:34 +0200
Subject: [PATCH] sysdb: do not fail to add non-posix user to MPG domain
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
SSSD does not handle the root user (UID==0) and treats all accounts with
UID 0 as non-Posix accounts. The primary GID of those accounts is 0 as
well and as a result for those accounts in MPG domains the check for a
collisions of the primary GID should be skipped. The current code might
e.g. cause issues during GPO evaluation when adding a host account into
the cache which does not have any UID or GID set in AD and SSSD is
configured to read UID and GID from AD.
Resolves: https://github.com/SSSD/sssd/issues/7451
Reviewed-by: Alejandro López <allopez@redhat.com>
Reviewed-by: Tomáš Halman <thalman@redhat.com>
(cherry picked from commit 986bb726202e69b05f861c14c3a220379baf9bd1)
---
src/db/sysdb_ops.c | 18 ++++++++++--------
1 file changed, 10 insertions(+), 8 deletions(-)
diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c
index 0f62e3b1a..76f4580aa 100644
--- a/src/db/sysdb_ops.c
+++ b/src/db/sysdb_ops.c
@@ -1914,15 +1914,17 @@ int sysdb_add_user(struct sss_domain_info *domain,
goto done;
}
- ret = sysdb_search_group_by_gid(tmp_ctx, domain, uid, NULL, &msg);
- if (ret != ENOENT) {
- if (ret == EOK) {
- DEBUG(SSSDBG_OP_FAILURE,
- "Group with GID [%"SPRIgid"] already exists in an "
- "MPG domain\n", gid);
- ret = EEXIST;
+ if (uid != 0) { /* uid == 0 means non-POSIX object */
+ ret = sysdb_search_group_by_gid(tmp_ctx, domain, uid, NULL, &msg);
+ if (ret != ENOENT) {
+ if (ret == EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Group with GID [%"SPRIgid"] already exists in an "
+ "MPG domain\n", uid);
+ ret = EEXIST;
+ }
+ goto done;
}
- goto done;
}
}
--
2.44.0

View File

@ -0,0 +1,37 @@
From 723a30b45ba4cbd9a4913fd37d68e392dcfc16ba Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Fri, 7 Jun 2024 18:04:00 +0200
Subject: [PATCH] ad: use right memory context in GPO code
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The original primary SID is allocated on a temporary context and must be
move to be longer living one to still be available when the SID is
evaluated later in the code.
Resolves: https://github.com/SSSD/sssd/issues/7411
Reviewed-by: Alexey Tikhonov <atikhono@redhat.com>
Reviewed-by: Tomáš Halman <thalman@redhat.com>
(cherry picked from commit b25e510ad60f6ce0b57063cce648c3aa48b21241)
---
src/providers/ad/ad_gpo.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/providers/ad/ad_gpo.c b/src/providers/ad/ad_gpo.c
index b879b0a08..ed664ec83 100644
--- a/src/providers/ad/ad_gpo.c
+++ b/src/providers/ad/ad_gpo.c
@@ -711,7 +711,7 @@ ad_gpo_get_sids(TALLOC_CTX *mem_ctx,
}
group_sids[i++] = talloc_strdup(group_sids, AD_AUTHENTICATED_USERS_SID);
if (orig_gid_sid != NULL) {
- group_sids[i++] = orig_gid_sid;
+ group_sids[i++] = talloc_steal(group_sids, orig_gid_sid);
}
group_sids[i] = NULL;
--
2.44.0

View File

@ -1,194 +0,0 @@
From 6a8e60df84d5d2565bec36be19c2def25a6ece1f Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Wed, 24 Jan 2024 14:21:12 +0100
Subject: [PATCH 3/3] sdap: add naming_context as new member of struct
sdap_domain
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The naming_context could be a more reliable source than basedn for the
actual base DN because basedn is set very early from the domain name
given in sssd.conf. Although it is recommended to use the fully
qualified DNS domain name here it is not required. As a result basedn
might not reflect the actual based DN of the LDAP server. Also pure LDAP
server (i.e. not AD or FreeIPA) might use different schemes to set the
base DN which will not be based on the DNS domain of the LDAP server.
Resolves: https://github.com/SSSD/sssd/issues/5708
Reviewed-by: Alejandro López <allopez@redhat.com>
Reviewed-by: Tomáš Halman <thalman@redhat.com>
(cherry picked from commit a153f13f296401247a862df2b99048bb1bbb8e2e)
---
src/providers/ad/ad_gpo.c | 6 ++++--
src/providers/ldap/sdap.c | 36 +++++++++++++-----------------------
src/providers/ldap/sdap.h | 11 +++++++++++
3 files changed, 28 insertions(+), 25 deletions(-)
diff --git a/src/providers/ad/ad_gpo.c b/src/providers/ad/ad_gpo.c
index b0ee3e616..3d1ad39c7 100644
--- a/src/providers/ad/ad_gpo.c
+++ b/src/providers/ad/ad_gpo.c
@@ -2185,8 +2185,10 @@ ad_gpo_connect_done(struct tevent_req *subreq)
goto done;
}
- ret = common_parse_search_base(state, sdom->basedn, state->ldb_ctx,
- "AD_HOSTS", NULL, &search_bases);
+ ret = common_parse_search_base(state,
+ sdom->naming_context == NULL ? sdom->basedn
+ : sdom->naming_context,
+ state->ldb_ctx, "AD_HOSTS", NULL, &search_bases);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"Failed to create dedicated search base for host lookups, "
diff --git a/src/providers/ldap/sdap.c b/src/providers/ldap/sdap.c
index f5637c5fb..956eba93a 100644
--- a/src/providers/ldap/sdap.c
+++ b/src/providers/ldap/sdap.c
@@ -1252,19 +1252,10 @@ errno_t sdap_set_config_options_with_rootdse(struct sysdb_attrs *rootdse,
struct sdap_domain *sdom)
{
int ret;
- char *naming_context = NULL;
- if (!sdom->search_bases
- || !sdom->user_search_bases
- || !sdom->group_search_bases
- || !sdom->netgroup_search_bases
- || !sdom->host_search_bases
- || !sdom->sudo_search_bases
- || !sdom->iphost_search_bases
- || !sdom->ipnetwork_search_bases
- || !sdom->autofs_search_bases) {
- naming_context = get_naming_context(opts->basic, rootdse);
- if (naming_context == NULL) {
+ if (!sdom->naming_context) {
+ sdom->naming_context = get_naming_context(sdom, rootdse);
+ if (sdom->naming_context == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "get_naming_context failed.\n");
/* This has to be non-fatal, since some servers offer
@@ -1280,7 +1271,7 @@ errno_t sdap_set_config_options_with_rootdse(struct sysdb_attrs *rootdse,
if (!sdom->search_bases) {
ret = sdap_set_search_base(opts, sdom,
SDAP_SEARCH_BASE,
- naming_context);
+ sdom->naming_context);
if (ret != EOK) goto done;
}
@@ -1288,7 +1279,7 @@ errno_t sdap_set_config_options_with_rootdse(struct sysdb_attrs *rootdse,
if (!sdom->user_search_bases) {
ret = sdap_set_search_base(opts, sdom,
SDAP_USER_SEARCH_BASE,
- naming_context);
+ sdom->naming_context);
if (ret != EOK) goto done;
}
@@ -1296,7 +1287,7 @@ errno_t sdap_set_config_options_with_rootdse(struct sysdb_attrs *rootdse,
if (!sdom->group_search_bases) {
ret = sdap_set_search_base(opts, sdom,
SDAP_GROUP_SEARCH_BASE,
- naming_context);
+ sdom->naming_context);
if (ret != EOK) goto done;
}
@@ -1304,7 +1295,7 @@ errno_t sdap_set_config_options_with_rootdse(struct sysdb_attrs *rootdse,
if (!sdom->netgroup_search_bases) {
ret = sdap_set_search_base(opts, sdom,
SDAP_NETGROUP_SEARCH_BASE,
- naming_context);
+ sdom->naming_context);
if (ret != EOK) goto done;
}
@@ -1312,7 +1303,7 @@ errno_t sdap_set_config_options_with_rootdse(struct sysdb_attrs *rootdse,
if (!sdom->host_search_bases) {
ret = sdap_set_search_base(opts, sdom,
SDAP_HOST_SEARCH_BASE,
- naming_context);
+ sdom->naming_context);
if (ret != EOK) goto done;
}
@@ -1320,7 +1311,7 @@ errno_t sdap_set_config_options_with_rootdse(struct sysdb_attrs *rootdse,
if (!sdom->sudo_search_bases) {
ret = sdap_set_search_base(opts, sdom,
SDAP_SUDO_SEARCH_BASE,
- naming_context);
+ sdom->naming_context);
if (ret != EOK) goto done;
}
@@ -1328,7 +1319,7 @@ errno_t sdap_set_config_options_with_rootdse(struct sysdb_attrs *rootdse,
if (!sdom->service_search_bases) {
ret = sdap_set_search_base(opts, sdom,
SDAP_SERVICE_SEARCH_BASE,
- naming_context);
+ sdom->naming_context);
if (ret != EOK) goto done;
}
@@ -1336,7 +1327,7 @@ errno_t sdap_set_config_options_with_rootdse(struct sysdb_attrs *rootdse,
if (!sdom->autofs_search_bases) {
ret = sdap_set_search_base(opts, sdom,
SDAP_AUTOFS_SEARCH_BASE,
- naming_context);
+ sdom->naming_context);
if (ret != EOK) goto done;
}
@@ -1344,7 +1335,7 @@ errno_t sdap_set_config_options_with_rootdse(struct sysdb_attrs *rootdse,
if (!sdom->iphost_search_bases) {
ret = sdap_set_search_base(opts, sdom,
SDAP_IPHOST_SEARCH_BASE,
- naming_context);
+ sdom->naming_context);
if (ret != EOK) goto done;
}
@@ -1352,14 +1343,13 @@ errno_t sdap_set_config_options_with_rootdse(struct sysdb_attrs *rootdse,
if (!sdom->ipnetwork_search_bases) {
ret = sdap_set_search_base(opts, sdom,
SDAP_IPNETWORK_SEARCH_BASE,
- naming_context);
+ sdom->naming_context);
if (ret != EOK) goto done;
}
ret = EOK;
done:
- talloc_free(naming_context);
return ret;
}
diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
index 161bc5c26..103d50ed4 100644
--- a/src/providers/ldap/sdap.h
+++ b/src/providers/ldap/sdap.h
@@ -454,6 +454,17 @@ struct sdap_domain {
char *basedn;
+ /* The naming_context could be a more reliable source than basedn for the
+ * actual base DN because basedn is set very early from the domain name
+ * given in sssd.conf. Although it is recommended to use the fully
+ * qualified DNS domain name here it is not required. As a result basedn
+ * might not reflect the actual based DN of the LDAP server. Also pure
+ * LDAP server (i.e. not AD or FreeIPA) might use different schemes to set
+ * the base DN which will not be based on the DNS domain of the LDAP
+ * server. naming_context might be NULL even after connection to an LDAP
+ * server. */
+ char *naming_context;
+
struct sdap_search_base **search_bases;
struct sdap_search_base **user_search_bases;
struct sdap_search_base **group_search_bases;
--
2.41.0

View File

@ -0,0 +1,208 @@
From 09b23e78806d8930c3f1b9e411dc8cf464c18998 Mon Sep 17 00:00:00 2001
From: Alexey Tikhonov <atikhono@redhat.com>
Date: Tue, 16 Jul 2024 13:08:02 +0200
Subject: [PATCH 4/5] TS_CACHE: never try to upgrade timestamps cache
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
It's easier and more consistent to recreate it instead.
This is a natural extension of 3b67fc6488ac10ca13561d9032f59951f82203e6
Reviewed-by: Alejandro López <allopez@redhat.com>
Reviewed-by: Sumit Bose <sbose@redhat.com>
Reviewed-by: Tomáš Halman <thalman@redhat.com>
(cherry picked from commit fc2a26c306e51b66680aef85aa0d2c41d8049a7f)
---
src/db/sysdb_init.c | 103 +----------------------------------------
src/db/sysdb_upgrade.c | 45 ------------------
2 files changed, 1 insertion(+), 147 deletions(-)
diff --git a/src/db/sysdb_init.c b/src/db/sysdb_init.c
index 38a9cd64a..a1d02d49c 100644
--- a/src/db/sysdb_init.c
+++ b/src/db/sysdb_init.c
@@ -376,57 +376,6 @@ static errno_t sysdb_cache_create_empty(struct ldb_context *ldb,
return EOK;
}
-static errno_t sysdb_ts_cache_upgrade(TALLOC_CTX *mem_ctx,
- struct sysdb_ctx *sysdb,
- struct ldb_context *ldb,
- struct sss_domain_info *domain,
- const char *cur_version,
- const char **_new_version)
-{
- errno_t ret;
- TALLOC_CTX *tmp_ctx;
- const char *version;
- struct ldb_context *save_ldb;
-
- tmp_ctx = talloc_new(NULL);
- if (tmp_ctx == NULL) {
- return ENOMEM;
- }
-
- /* The upgrade process depends on having ldb around, yet the upgrade
- * function shouldn't set the ldb pointer, only the connect function
- * should after it's successful. To avoid hard refactoring, save the
- * ldb pointer here and restore in the 'done' handler
- */
- save_ldb = sysdb->ldb;
- sysdb->ldb = ldb;
-
- version = talloc_strdup(tmp_ctx, cur_version);
- if (version == NULL) {
- ret = ENOMEM;
- goto done;
- }
-
- DEBUG(SSSDBG_CONF_SETTINGS,
- "Upgrading timstamp cache of DB [%s] from version: %s\n",
- domain->name, version);
-
- if (strcmp(version, SYSDB_TS_VERSION_0_1) == 0) {
- ret = sysdb_ts_upgrade_01(sysdb, &version);
- if (ret != EOK) {
- goto done;
- }
- }
-
- ret = EOK;
-
-done:
- sysdb->ldb = save_ldb;
- *_new_version = version;
- talloc_free(tmp_ctx);
- return ret;
-}
-
static errno_t sysdb_domain_cache_upgrade(TALLOC_CTX *mem_ctx,
struct sysdb_ctx *sysdb,
struct sysdb_dom_upgrade_ctx *upgrade_ctx,
@@ -884,56 +833,6 @@ static int sysdb_timestamp_cache_connect(struct sysdb_ctx *sysdb,
}
ret = sysdb_ts_cache_connect(tmp_ctx, sysdb, domain, &ldb, &version);
- switch (ret) {
- case ERR_SYSDB_VERSION_TOO_OLD:
- if (upgrade_ctx == NULL) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "DB version too old [%s], expected [%s] for domain %s!\n",
- version, SYSDB_VERSION, domain->name);
- break;
- }
-
- ret = sysdb_ts_cache_upgrade(tmp_ctx, sysdb, ldb, domain, version,
- &version);
- if (ret != EOK) {
- DEBUG(SSSDBG_MINOR_FAILURE,
- "Could not upgrade the timestamp ldb file (%d) (%s)\n",
- ret, sss_strerror(ret));
- break;
- }
-
- /* The version should now match SYSDB_VERSION.
- * If not, it means we didn't match any of the
- * known older versions. The DB might be
- * corrupt or generated by a newer version of
- * SSSD.
- */
- ret = sysdb_version_check(SYSDB_TS_VERSION, version);
- if (ret == EOK) {
- /* The cache has been upgraded.
- * We need to reopen the LDB to ensure that
- * any changes made above take effect.
- */
- ret = sysdb_ldb_reconnect(tmp_ctx,
- sysdb->ldb_ts_file,
- LDB_FLG_NOSYNC,
- &ldb);
- if (ret != EOK) {
- DEBUG(SSSDBG_MINOR_FAILURE,
- "Could not reopen the timestamp ldb file (%d) (%s)\n",
- ret, sss_strerror(ret));
- }
- }
- break;
- case ERR_SYSDB_VERSION_TOO_NEW:
- DEBUG(SSSDBG_MINOR_FAILURE,
- "DB version too new [%s], expected [%s] for domain %s!\n",
- version, SYSDB_TS_VERSION, domain->name);
- break;
- default:
- break;
- }
-
if (ret != EOK) {
DEBUG(SSSDBG_MINOR_FAILURE,
"The timestamps cache could not be opened. "
@@ -953,7 +852,7 @@ static int sysdb_timestamp_cache_connect(struct sysdb_ctx *sysdb,
ret = sysdb_ts_cache_connect(tmp_ctx, sysdb, domain, &ldb, &version);
if (ret != EOK) {
DEBUG(SSSDBG_MINOR_FAILURE,
- "Could not delete the timestamp ldb file (%d) (%s)\n",
+ "sysdb_ts_cache_connect() failed after cache deletion [%d]: %s\n",
ret, sss_strerror(ret));
}
}
diff --git a/src/db/sysdb_upgrade.c b/src/db/sysdb_upgrade.c
index 328bd2962..37c0007cb 100644
--- a/src/db/sysdb_upgrade.c
+++ b/src/db/sysdb_upgrade.c
@@ -2774,51 +2774,6 @@ done:
return ret;
}
-int sysdb_ts_upgrade_01(struct sysdb_ctx *sysdb, const char **ver)
-{
- struct upgrade_ctx *ctx;
- errno_t ret;
- struct ldb_message *msg = NULL;
-
- ret = commence_upgrade(sysdb, sysdb->ldb, SYSDB_TS_VERSION_0_2, &ctx);
- if (ret) {
- return ret;
- }
-
- /* Remove @IDXONE from index */
- talloc_free(msg);
- msg = ldb_msg_new(ctx);
- if (msg == NULL) {
- ret = ENOMEM;
- goto done;
- }
-
- msg->dn = ldb_dn_new(msg, sysdb->ldb, "@INDEXLIST");
- if (msg->dn == NULL) {
- ret = ENOMEM;
- goto done;
- }
-
- ret = ldb_msg_add_empty(msg, "@IDXONE", LDB_FLAG_MOD_DELETE, NULL);
- if (ret != LDB_SUCCESS) {
- ret = ENOMEM;
- goto done;
- }
-
- ret = ldb_modify(sysdb->ldb, msg);
- if (ret != LDB_SUCCESS) {
- ret = sysdb_error_to_errno(ret);
- goto done;
- }
-
- /* conversion done, update version number */
- ret = update_version(ctx);
-
-done:
- ret = finish_upgrade(ret, &ctx, ver);
- return ret;
-}
-
/*
* Example template for future upgrades.
* Copy and change version numbers as appropriate.
--
2.45.2

View File

@ -1,233 +0,0 @@
From 50077c3255177fe1b01837fbe31a7f8fd47dee74 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Thu, 18 Jan 2024 13:08:17 +0100
Subject: [PATCH] pam: fix SC auth with multiple certs and missing login name
While introducing the local_auth_policy option a quite specific use-case
was not covered correctly. If there are multiple matching certificates
on the Smartcard, 'local_auth_policy = only' is set and GDM's Smartcard
mode was used for login, i.e. there is no user name given and the user
has to be derived from the certificate used for login, authentication
failed. The main reason for the failure is that in this case the
Smartcard interaction and the user mapping has to be done first to
determine the user before local_auth_policy is evaluated. As a result
when checking if the authentication can be finished the request was in
an unexpected state because the indicator for local Smartcard
authentication was not enabled.
Resolves: https://github.com/SSSD/sssd/issues/7109
Reviewed-by: Justin Stephenson <jstephen@redhat.com>
Reviewed-by: Scott Poore <spoore@redhat.com>
(cherry picked from commit 44ec3e4638b0c6f7f45a3390a28c2e8745d52bc3)
---
src/responder/pam/pamsrv.h | 10 ++++
src/responder/pam/pamsrv_cmd.c | 17 +++++--
src/tests/intg/Makefile.am | 2 +
src/tests/intg/test_pam_responder.py | 74 +++++++++++++++++++++++++++-
4 files changed, 96 insertions(+), 7 deletions(-)
diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h
index 7013a8edd..618836189 100644
--- a/src/responder/pam/pamsrv.h
+++ b/src/responder/pam/pamsrv.h
@@ -93,7 +93,17 @@ struct pam_auth_req {
struct ldb_message *user_obj;
struct cert_auth_info *cert_list;
struct cert_auth_info *current_cert;
+ /* Switched to 'true' if the backend indicates that it cannot handle
+ * Smartcard authentication, but Smartcard authentication is
+ * possible and local Smartcard authentication is allowed. */
bool cert_auth_local;
+ /* Switched to 'true' if authentication (not pre-authentication) was
+ * started without a login name and the name had to be lookup up with the
+ * certificate used for authentication. Since reading the certificate from
+ * the Smartcard already involves the PIN validation in this case there
+ * would be no need for an additional Smartcard interaction if only local
+ * Smartcard authentication is possible. */
+ bool initial_cert_auth_successful;
bool passkey_data_exists;
uint32_t client_id_num;
diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c
index c23ea7ba4..a7c181733 100644
--- a/src/responder/pam/pamsrv_cmd.c
+++ b/src/responder/pam/pamsrv_cmd.c
@@ -2200,8 +2200,8 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req)
ret = ENOENT;
goto done;
}
-
- if (cert_count > 1) {
+ /* Multiple certificates are only expected during pre-auth */
+ if (cert_count > 1 && preq->pd->cmd == SSS_PAM_PREAUTH) {
for (preq->current_cert = preq->cert_list;
preq->current_cert != NULL;
preq->current_cert = sss_cai_get_next(preq->current_cert)) {
@@ -2285,7 +2285,9 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req)
}
/* If logon_name was not given during authentication add a
- * SSS_PAM_CERT_INFO message to send the name to the caller. */
+ * SSS_PAM_CERT_INFO message to send the name to the caller.
+ * Additionally initial_cert_auth_successful is set to
+ * indicate that the user is already authenticated. */
if (preq->pd->cmd == SSS_PAM_AUTHENTICATE
&& preq->pd->logon_name == NULL) {
ret = add_pam_cert_response(preq->pd,
@@ -2297,6 +2299,8 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req)
preq->pd->pam_status = PAM_AUTHINFO_UNAVAIL;
goto done;
}
+
+ preq->initial_cert_auth_successful = true;
}
/* cert_user will be returned to the PAM client as user name, so
@@ -2851,12 +2855,15 @@ static void pam_dom_forwarder(struct pam_auth_req *preq)
if (found) {
if (local_policy != NULL && strcasecmp(local_policy, "only") == 0) {
talloc_free(tmp_ctx);
- DEBUG(SSSDBG_IMPORTANT_INFO, "Local auth only set, skipping online auth\n");
+ DEBUG(SSSDBG_IMPORTANT_INFO,
+ "Local auth only set and matching certificate was found, "
+ "skipping online auth\n");
if (preq->pd->cmd == SSS_PAM_PREAUTH) {
preq->pd->pam_status = PAM_SUCCESS;
} else if (preq->pd->cmd == SSS_PAM_AUTHENTICATE
&& IS_SC_AUTHTOK(preq->pd->authtok)
- && preq->cert_auth_local) {
+ && (preq->cert_auth_local
+ || preq->initial_cert_auth_successful)) {
preq->pd->pam_status = PAM_SUCCESS;
preq->callback = pam_reply;
}
diff --git a/src/tests/intg/Makefile.am b/src/tests/intg/Makefile.am
index 3866d3ca6..0cfd268dc 100644
--- a/src/tests/intg/Makefile.am
+++ b/src/tests/intg/Makefile.am
@@ -199,6 +199,7 @@ clean-local:
PAM_CERT_DB_PATH="$(abs_builddir)/../test_CA/SSSD_test_CA.pem"
SOFTHSM2_CONF="$(abs_builddir)/../test_CA/softhsm2_one.conf"
+SOFTHSM2_TWO_CONF="$(abs_builddir)/../test_CA/softhsm2_two.conf"
intgcheck-installed: config.py passwd group pam_sss_service pam_sss_alt_service pam_sss_sc_required pam_sss_try_sc pam_sss_allow_missing_name pam_sss_domains sss_netgroup_thread_test
pipepath="$(DESTDIR)$(pipepath)"; \
@@ -233,6 +234,7 @@ intgcheck-installed: config.py passwd group pam_sss_service pam_sss_alt_service
PAM_CERT_DB_PATH=$(PAM_CERT_DB_PATH) \
ABS_SRCDIR=$(abs_srcdir) \
SOFTHSM2_CONF=$(SOFTHSM2_CONF) \
+ SOFTHSM2_TWO_CONF=$(SOFTHSM2_TWO_CONF) \
KCM_RENEW=$(KCM_RENEW) \
FILES_PROVIDER=$(FILES_PROVIDER) \
DBUS_SOCK_DIR="$(DESTDIR)$(runstatedir)/dbus/" \
diff --git a/src/tests/intg/test_pam_responder.py b/src/tests/intg/test_pam_responder.py
index 1fc3937e6..0fbf8065e 100644
--- a/src/tests/intg/test_pam_responder.py
+++ b/src/tests/intg/test_pam_responder.py
@@ -168,7 +168,7 @@ def format_pam_cert_auth_conf(config, provider):
{provider.p}
[certmap/auth_only/user1]
- matchrule = <SUBJECT>.*CN=SSSD test cert 0001.*
+ matchrule = <SUBJECT>.*CN=SSSD test cert 000[12].*
""").format(**locals())
@@ -201,7 +201,7 @@ def format_pam_cert_auth_conf_name_format(config, provider):
{provider.p}
[certmap/auth_only/user1]
- matchrule = <SUBJECT>.*CN=SSSD test cert 0001.*
+ matchrule = <SUBJECT>.*CN=SSSD test cert 000[12].*
""").format(**locals())
@@ -380,6 +380,28 @@ def simple_pam_cert_auth_no_cert(request, passwd_ops_setup):
return None
+@pytest.fixture
+def simple_pam_cert_auth_two_certs(request, passwd_ops_setup):
+ """Setup SSSD with pam_cert_auth=True"""
+ config.PAM_CERT_DB_PATH = os.environ['PAM_CERT_DB_PATH']
+
+ old_softhsm2_conf = os.environ['SOFTHSM2_CONF']
+ softhsm2_two_conf = os.environ['SOFTHSM2_TWO_CONF']
+ os.environ['SOFTHSM2_CONF'] = softhsm2_two_conf
+
+ conf = format_pam_cert_auth_conf(config, provider_switch(request.param))
+ create_conf_fixture(request, conf)
+ create_sssd_fixture(request)
+
+ os.environ['SOFTHSM2_CONF'] = old_softhsm2_conf
+
+ passwd_ops_setup.useradd(**USER1)
+ passwd_ops_setup.useradd(**USER2)
+ sync_files_provider(USER2['name'])
+
+ return None
+
+
@pytest.fixture
def simple_pam_cert_auth_name_format(request, passwd_ops_setup):
"""Setup SSSD with pam_cert_auth=True and full_name_format"""
@@ -522,6 +544,54 @@ def test_sc_auth(simple_pam_cert_auth, env_for_sssctl):
assert err.find("pam_authenticate for user [user1]: Success") != -1
+@pytest.mark.parametrize('simple_pam_cert_auth_two_certs', provider_list(), indirect=True)
+def test_sc_auth_two(simple_pam_cert_auth_two_certs, env_for_sssctl):
+
+ sssctl = subprocess.Popen(["sssctl", "user-checks", "user1",
+ "--action=auth", "--service=pam_sss_service"],
+ universal_newlines=True,
+ env=env_for_sssctl, stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+
+ try:
+ out, err = sssctl.communicate(input="2\n123456")
+ except Exception:
+ sssctl.kill()
+ out, err = sssctl.communicate()
+
+ sssctl.stdin.close()
+ sssctl.stdout.close()
+
+ if sssctl.wait() != 0:
+ raise Exception("sssctl failed")
+
+ assert err.find("pam_authenticate for user [user1]: Success") != -1
+
+
+@pytest.mark.parametrize('simple_pam_cert_auth_two_certs', provider_list(), indirect=True)
+def test_sc_auth_two_missing_name(simple_pam_cert_auth_two_certs, env_for_sssctl):
+
+ sssctl = subprocess.Popen(["sssctl", "user-checks", "",
+ "--action=auth", "--service=pam_sss_allow_missing_name"],
+ universal_newlines=True,
+ env=env_for_sssctl, stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+
+ try:
+ out, err = sssctl.communicate(input="2\n123456")
+ except Exception:
+ sssctl.kill()
+ out, err = sssctl.communicate()
+
+ sssctl.stdin.close()
+ sssctl.stdout.close()
+
+ if sssctl.wait() != 0:
+ raise Exception("sssctl failed")
+
+ assert err.find("pam_authenticate for user [user1]: Success") != -1
+
+
@pytest.mark.parametrize('simple_pam_cert_auth', ['proxy_password'], indirect=True)
def test_sc_proxy_password_fallback(simple_pam_cert_auth, env_for_sssctl):
"""
--
2.41.0

View File

@ -0,0 +1,147 @@
From 13e3d0390b9aaf72a855b857857c3cdd6eb6252a Mon Sep 17 00:00:00 2001
From: Alexey Tikhonov <atikhono@redhat.com>
Date: Fri, 21 Jun 2024 19:09:29 +0200
Subject: [PATCH 5/5] SYSDB: remove index on `dataExpireTimestamp`
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This index was only used in cleanup tasks that don't run often.
On the other hand, this index is huge and degrades performance of libldb
in general.
Reviewed-by: Alejandro López <allopez@redhat.com>
Reviewed-by: Sumit Bose <sbose@redhat.com>
Reviewed-by: Tomáš Halman <thalman@redhat.com>
(cherry picked from commit f0d45464cee1d2a6a2719dbffe5bbf6189d0554a)
---
src/db/sysdb_init.c | 8 ++++++++
src/db/sysdb_private.h | 9 +++++----
src/db/sysdb_upgrade.c | 27 +++++++++++++++++++++++++++
3 files changed, 40 insertions(+), 4 deletions(-)
diff --git a/src/db/sysdb_init.c b/src/db/sysdb_init.c
index a1d02d49c..68b9744dd 100644
--- a/src/db/sysdb_init.c
+++ b/src/db/sysdb_init.c
@@ -559,6 +559,13 @@ static errno_t sysdb_domain_cache_upgrade(TALLOC_CTX *mem_ctx,
}
}
+ if (strcmp(version, SYSDB_VERSION_0_24) == 0) {
+ ret = sysdb_upgrade_24(sysdb, &version);
+ if (ret != EOK) {
+ goto done;
+ }
+ }
+
ret = EOK;
done:
sysdb->ldb = save_ldb;
@@ -765,6 +772,7 @@ static int sysdb_domain_cache_connect(struct sysdb_ctx *sysdb,
ret = sysdb_domain_cache_upgrade(tmp_ctx, sysdb, upgrade_ctx,
ldb, domain, version, &version);
if (ret != EOK) {
+ DEBUG(SSSDBG_TRACE_FUNC, "sysdb_domain_cache_upgrade() failed\n");
goto done;
}
diff --git a/src/db/sysdb_private.h b/src/db/sysdb_private.h
index 63f7b5601..b814f97a5 100644
--- a/src/db/sysdb_private.h
+++ b/src/db/sysdb_private.h
@@ -23,6 +23,7 @@
#ifndef __INT_SYS_DB_H__
#define __INT_SYS_DB_H__
+#define SYSDB_VERSION_0_25 "0.25"
#define SYSDB_VERSION_0_24 "0.24"
#define SYSDB_VERSION_0_23 "0.23"
#define SYSDB_VERSION_0_22 "0.22"
@@ -48,7 +49,7 @@
#define SYSDB_VERSION_0_2 "0.2"
#define SYSDB_VERSION_0_1 "0.1"
-#define SYSDB_VERSION SYSDB_VERSION_0_24
+#define SYSDB_VERSION SYSDB_VERSION_0_25
#define SYSDB_BASE_LDIF \
"dn: @ATTRIBUTES\n" \
@@ -72,7 +73,6 @@
"@IDXATTR: uidNumber\n" \
"@IDXATTR: gidNumber\n" \
"@IDXATTR: lastUpdate\n" \
- "@IDXATTR: dataExpireTimestamp\n" \
"@IDXATTR: originalDN\n" \
"@IDXATTR: nameAlias\n" \
"@IDXATTR: servicePort\n" \
@@ -104,10 +104,11 @@
"\n"
/* The timestamp cache has its own versioning */
+#define SYSDB_TS_VERSION_0_3 "0.3"
#define SYSDB_TS_VERSION_0_2 "0.2"
#define SYSDB_TS_VERSION_0_1 "0.1"
-#define SYSDB_TS_VERSION SYSDB_TS_VERSION_0_2
+#define SYSDB_TS_VERSION SYSDB_TS_VERSION_0_3
#define SYSDB_TS_BASE_LDIF \
"dn: @ATTRIBUTES\n" \
@@ -115,7 +116,6 @@
"\n" \
"dn: @INDEXLIST\n" \
"@IDXATTR: lastUpdate\n" \
- "@IDXATTR: dataExpireTimestamp\n" \
"\n" \
"dn: cn=sysdb\n" \
"cn: sysdb\n" \
@@ -194,6 +194,7 @@ int sysdb_upgrade_20(struct sysdb_ctx *sysdb, const char **ver);
int sysdb_upgrade_21(struct sysdb_ctx *sysdb, const char **ver);
int sysdb_upgrade_22(struct sysdb_ctx *sysdb, const char **ver);
int sysdb_upgrade_23(struct sysdb_ctx *sysdb, const char **ver);
+int sysdb_upgrade_24(struct sysdb_ctx *sysdb, const char **ver);
int sysdb_ts_upgrade_01(struct sysdb_ctx *sysdb, const char **ver);
diff --git a/src/db/sysdb_upgrade.c b/src/db/sysdb_upgrade.c
index 37c0007cb..b010488ca 100644
--- a/src/db/sysdb_upgrade.c
+++ b/src/db/sysdb_upgrade.c
@@ -2774,6 +2774,33 @@ done:
return ret;
}
+int sysdb_upgrade_24(struct sysdb_ctx *sysdb, const char **ver)
+{
+ struct upgrade_ctx *ctx;
+ errno_t ret;
+
+ ret = commence_upgrade(sysdb, sysdb->ldb, SYSDB_VERSION_0_25, &ctx);
+ if (ret) {
+ return ret;
+ }
+
+ ret = sysdb_ldb_mod_index(sysdb, SYSDB_IDX_DELETE, sysdb->ldb, "dataExpireTimestamp");
+ if (ret == ENOENT) { /*nothing to delete */
+ ret = EOK;
+ }
+ if (ret != EOK) {
+ DEBUG(SSSDBG_TRACE_FUNC, "sysdb_ldb_mod_index() failed [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ ret = update_version(ctx);
+
+done:
+ ret = finish_upgrade(ret, &ctx, ver);
+ return ret;
+}
+
/*
* Example template for future upgrades.
* Copy and change version numbers as appropriate.
--
2.45.2

View File

@ -1,218 +0,0 @@
From e1bfbc2493c4194988acc3b2413df3dde0735ae3 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Wed, 8 Nov 2023 14:50:24 +0100
Subject: [PATCH] ad-gpo: use hash to store intermediate results
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Currently after the evaluation of a single GPO file the intermediate
results are stored in the cache and this cache entry is updated until
all applicable GPO files are evaluated. Finally the data in the cache is
used to make the decision of access is granted or rejected.
If there are two or more access-control request running in parallel one
request might overwrite the cache object with intermediate data while
another request reads the cached data for the access decision and as a
result will do this decision based on intermediate data.
To avoid this the intermediate results are not stored in the cache
anymore but in hash tables which are specific to the request. Only the
final result is written to the cache to have it available for offline
authentication.
Reviewed-by: Alexey Tikhonov <atikhono@redhat.com>
Reviewed-by: Tomáš Halman <thalman@redhat.com>
(cherry picked from commit d7db7971682da2dbf7642ac94940d6b0577ec35a)
---
src/providers/ad/ad_gpo.c | 116 +++++++++++++++++++++++++++++++++-----
1 file changed, 102 insertions(+), 14 deletions(-)
diff --git a/src/providers/ad/ad_gpo.c b/src/providers/ad/ad_gpo.c
index 3d1ad39c7..b879b0a08 100644
--- a/src/providers/ad/ad_gpo.c
+++ b/src/providers/ad/ad_gpo.c
@@ -1431,6 +1431,33 @@ ad_gpo_extract_policy_setting(TALLOC_CTX *mem_ctx,
return ret;
}
+static errno_t
+add_result_to_hash(hash_table_t *hash, const char *key, char *value)
+{
+ int hret;
+ hash_key_t k;
+ hash_value_t v;
+
+ if (hash == NULL || key == NULL || value == NULL) {
+ return EINVAL;
+ }
+
+ k.type = HASH_KEY_CONST_STRING;
+ k.c_str = key;
+
+ v.type = HASH_VALUE_PTR;
+ v.ptr = value;
+
+ hret = hash_enter(hash, &k, &v);
+ if (hret != HASH_SUCCESS) {
+ DEBUG(SSSDBG_OP_FAILURE, "Failed to add [%s][%s] to hash: [%s].\n",
+ key, value, hash_error_string(hret));
+ return EIO;
+ }
+
+ return EOK;
+}
+
/*
* This function parses the cse-specific (GP_EXT_GUID_SECURITY) filename,
* and stores the allow_key and deny_key of all of the gpo_map_types present
@@ -1438,6 +1465,7 @@ ad_gpo_extract_policy_setting(TALLOC_CTX *mem_ctx,
*/
static errno_t
ad_gpo_store_policy_settings(struct sss_domain_info *domain,
+ hash_table_t *allow_maps, hash_table_t *deny_maps,
const char *filename)
{
struct ini_cfgfile *file_ctx = NULL;
@@ -1571,14 +1599,14 @@ ad_gpo_store_policy_settings(struct sss_domain_info *domain,
goto done;
} else if (ret != ENOENT) {
const char *value = allow_value ? allow_value : empty_val;
- ret = sysdb_gpo_store_gpo_result_setting(domain,
- allow_key,
- value);
+ ret = add_result_to_hash(allow_maps, allow_key,
+ talloc_strdup(allow_maps, value));
if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- "sysdb_gpo_store_gpo_result_setting failed for key:"
- "'%s' value:'%s' [%d][%s]\n", allow_key, allow_value,
- ret, sss_strerror(ret));
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to add key: [%s] "
+ "value: [%s] to allow maps "
+ "[%d][%s].\n",
+ allow_key, value, ret,
+ sss_strerror(ret));
goto done;
}
}
@@ -1598,14 +1626,14 @@ ad_gpo_store_policy_settings(struct sss_domain_info *domain,
goto done;
} else if (ret != ENOENT) {
const char *value = deny_value ? deny_value : empty_val;
- ret = sysdb_gpo_store_gpo_result_setting(domain,
- deny_key,
- value);
+ ret = add_result_to_hash(deny_maps, deny_key,
+ talloc_strdup(deny_maps, value));
if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- "sysdb_gpo_store_gpo_result_setting failed for key:"
- "'%s' value:'%s' [%d][%s]\n", deny_key, deny_value,
- ret, sss_strerror(ret));
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to add key: [%s] "
+ "value: [%s] to deny maps "
+ "[%d][%s].\n",
+ deny_key, value, ret,
+ sss_strerror(ret));
goto done;
}
}
@@ -1902,6 +1930,8 @@ struct ad_gpo_access_state {
int num_cse_filtered_gpos;
int cse_gpo_index;
const char *ad_domain;
+ hash_table_t *allow_maps;
+ hash_table_t *deny_maps;
};
static void ad_gpo_connect_done(struct tevent_req *subreq);
@@ -2023,6 +2053,19 @@ ad_gpo_access_send(TALLOC_CTX *mem_ctx,
goto immediately;
}
+ ret = sss_hash_create(state, 0, &state->allow_maps);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Could not create allow maps "
+ "hash table [%d]: %s\n", ret, sss_strerror(ret));
+ goto immediately;
+ }
+
+ ret = sss_hash_create(state, 0, &state->deny_maps);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Could not create deny maps "
+ "hash table [%d]: %s\n", ret, sss_strerror(ret));
+ goto immediately;
+ }
subreq = sdap_id_op_connect_send(state->sdap_op, state, &ret);
if (subreq == NULL) {
@@ -2713,6 +2756,43 @@ ad_gpo_cse_step(struct tevent_req *req)
return EAGAIN;
}
+static errno_t
+store_hash_maps_in_cache(struct sss_domain_info *domain,
+ hash_table_t *allow_maps, hash_table_t *deny_maps)
+{
+ int ret;
+ struct hash_iter_context_t *iter;
+ hash_entry_t *entry;
+ size_t c;
+ hash_table_t *hash_list[] = { allow_maps, deny_maps, NULL};
+
+
+ for (c = 0; hash_list[c] != NULL; c++) {
+ iter = new_hash_iter_context(hash_list[c]);
+ if (iter == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "Failed to create hash iterator.\n");
+ return EINVAL;
+ }
+
+ while ((entry = iter->next(iter)) != NULL) {
+ ret = sysdb_gpo_store_gpo_result_setting(domain,
+ entry->key.c_str,
+ entry->value.ptr);
+ if (ret != EOK) {
+ free(iter);
+ DEBUG(SSSDBG_OP_FAILURE,
+ "sysdb_gpo_store_gpo_result_setting failed for key:"
+ "[%s] value:[%s] [%d][%s]\n", entry->key.c_str,
+ (char *) entry->value.ptr, ret, sss_strerror(ret));
+ return ret;
+ }
+ }
+ talloc_free(iter);
+ }
+
+ return EOK;
+}
+
/*
* This cse-specific function (GP_EXT_GUID_SECURITY) increments the
* cse_gpo_index until the policy settings for all applicable GPOs have been
@@ -2754,6 +2834,7 @@ ad_gpo_cse_done(struct tevent_req *subreq)
* (as part of the GPO Result object in the sysdb cache).
*/
ret = ad_gpo_store_policy_settings(state->host_domain,
+ state->allow_maps, state->deny_maps,
cse_filtered_gpo->policy_filename);
if (ret != EOK && ret != ENOENT) {
DEBUG(SSSDBG_OP_FAILURE,
@@ -2767,6 +2848,13 @@ ad_gpo_cse_done(struct tevent_req *subreq)
if (ret == EOK) {
/* ret is EOK only after all GPO policy files have been downloaded */
+ ret = store_hash_maps_in_cache(state->host_domain,
+ state->allow_maps, state->deny_maps);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "Failed to store evaluated GPO maps "
+ "[%d][%s].\n", ret, sss_strerror(ret));
+ goto done;
+ }
ret = ad_gpo_perform_hbac_processing(state,
state->gpo_mode,
state->gpo_map_type,
--
2.44.0

View File

@ -1,81 +0,0 @@
From db27a51f274640e1aa2f13476c80955a3ec9e91c Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Fri, 1 Mar 2024 10:50:07 +0100
Subject: [PATCH] ad: refresh root domain when read directly
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
If the domain object of the forest root domain cannot be found in the
LDAP tree of the local AD domain SSSD tries to read the request data
from an LDAP server of the forest root domain directly. After reading
this data the information is stored in the cache but currently the
information about the domain store in memory is not updated with the
additional data. As a result e.g. the domain SID is missing in this data
and only becomes available after a restart where it is read from the
cache.
With this patch an unconditional refresh is triggered at the end of the
fallback code path.
Resolves: https://github.com/SSSD/sssd/issues/7250
Reviewed-by: Dan Lavu <dlavu@redhat.com>
Reviewed-by: Tomáš Halman <thalman@redhat.com>
(cherry picked from commit 0de6c33047ac7a2b5316ec5ec936d6b675671c53)
---
src/providers/ad/ad_subdomains.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
index a8d1892cc..d8f3738ce 100644
--- a/src/providers/ad/ad_subdomains.c
+++ b/src/providers/ad/ad_subdomains.c
@@ -1395,7 +1395,7 @@ struct ad_get_root_domain_state {
static void ad_get_root_domain_done(struct tevent_req *subreq);
static void ad_check_root_domain_done(struct tevent_req *subreq);
static errno_t
-ad_get_root_domain_refresh(struct ad_get_root_domain_state *state);
+ad_get_root_domain_refresh(struct ad_get_root_domain_state *state, bool refresh);
struct tevent_req *
ad_check_domain_send(TALLOC_CTX *mem_ctx,
@@ -1582,7 +1582,7 @@ static void ad_get_root_domain_done(struct tevent_req *subreq)
return;
}
- ret = ad_get_root_domain_refresh(state);
+ ret = ad_get_root_domain_refresh(state, false);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "ad_get_root_domain_refresh() failed.\n");
}
@@ -1682,7 +1682,7 @@ static void ad_check_root_domain_done(struct tevent_req *subreq)
state->reply_count = 1;
- ret = ad_get_root_domain_refresh(state);
+ ret = ad_get_root_domain_refresh(state, true);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "ad_get_root_domain_refresh() failed.\n");
}
@@ -1697,7 +1697,7 @@ done:
}
static errno_t
-ad_get_root_domain_refresh(struct ad_get_root_domain_state *state)
+ad_get_root_domain_refresh(struct ad_get_root_domain_state *state, bool refresh)
{
struct sss_domain_info *root_domain;
bool has_changes;
@@ -1713,7 +1713,7 @@ ad_get_root_domain_refresh(struct ad_get_root_domain_state *state)
goto done;
}
- if (has_changes) {
+ if (has_changes || refresh) {
ret = ad_subdom_reinit(state->sd_ctx);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "Could not reinitialize subdomains\n");
--
2.45.0

View File

@ -0,0 +1,115 @@
From 39cbb8df402f59b4df2442eb291600773e7062cc Mon Sep 17 00:00:00 2001
From: Petr Mikhalicin <pmikhalicin@rutoken.ru>
Date: Fri, 10 Nov 2023 15:24:48 +0600
Subject: [PATCH 6/8] pam_sss: fix passthrow of old authtok from another pam
modules at PAM_PRELIM_CHECK
pam_sss ignored old authtoks passed from another pam modules
Resolves: https://github.com/SSSD/sssd/issues/7007
Resolves: https://github.com/SSSD/sssd/issues/5418
Reviewed-by: Iker Pedrosa <ipedrosa@redhat.com>
Reviewed-by: Sumit Bose <sbose@redhat.com>
(cherry picked from commit ae6b9163be0a5a8846e8dbf2e0da2c29221781b9)
Reviewed-by: Sumit Bose <sbose@redhat.com>
---
src/sss_client/pam_sss.c | 75 ++++++++++++++++++++++++----------------
1 file changed, 45 insertions(+), 30 deletions(-)
diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c
index 41a528dda..5171e58ec 100644
--- a/src/sss_client/pam_sss.c
+++ b/src/sss_client/pam_sss.c
@@ -2728,42 +2728,57 @@ static int get_authtok_for_password_change(pam_handle_t *pamh,
exp_data = NULL;
}
- /* we query for the old password during PAM_PRELIM_CHECK to make
- * pam_sss work e.g. with pam_cracklib */
if (pam_flags & PAM_PRELIM_CHECK) {
- if ( (getuid() != 0 || exp_data ) && !(flags & PAM_CLI_FLAGS_USE_FIRST_PASS)) {
- if (flags & PAM_CLI_FLAGS_USE_2FA
- || (pi->otp_vendor != NULL && pi->otp_token_id != NULL
- && pi->otp_challenge != NULL)) {
- if (pi->password_prompting) {
- ret = prompt_2fa(pamh, pi, _("First Factor (Current Password): "),
- _("Second Factor (optional): "));
- } else {
- ret = prompt_2fa(pamh, pi, _("First Factor (Current Password): "),
- _("Second Factor: "));
- }
+ if (getuid() == 0 && !exp_data )
+ return PAM_SUCCESS;
+
+ if (flags & PAM_CLI_FLAGS_USE_2FA
+ || (pi->otp_vendor != NULL && pi->otp_token_id != NULL
+ && pi->otp_challenge != NULL)) {
+ if (pi->password_prompting) {
+ ret = prompt_2fa(pamh, pi, _("First Factor (Current Password): "),
+ _("Second Factor (optional): "));
} else {
- ret = prompt_password(pamh, pi, _("Current Password: "));
+ ret = prompt_2fa(pamh, pi, _("First Factor (Current Password): "),
+ _("Second Factor: "));
}
- if (ret != PAM_SUCCESS) {
- D(("failed to get credentials from user"));
- return ret;
+ } else if ((flags & PAM_CLI_FLAGS_USE_FIRST_PASS)
+ && check_authtok_data(pamh, pi) != 0) {
+ if (pi->pamstack_oldauthtok == NULL) {
+ pi->pam_authtok_type = SSS_AUTHTOK_TYPE_EMPTY;
+ pi->pam_authtok = NULL;
+ pi->pam_authtok_size = 0;
+ } else {
+ pi->pam_authtok = strdup(pi->pamstack_oldauthtok);
+ if (pi->pam_authtok == NULL) {
+ D(("strdup failed"));
+ return PAM_BUF_ERR;
+ }
+ pi->pam_authtok_type = SSS_AUTHTOK_TYPE_PASSWORD;
+ pi->pam_authtok_size = strlen(pi->pam_authtok);
}
+ ret = PAM_SUCCESS;
+ } else {
+ ret = prompt_password(pamh, pi, _("Current Password: "));
+ }
+ if (ret != PAM_SUCCESS) {
+ D(("failed to get credentials from user"));
+ return ret;
+ }
- ret = pam_set_item(pamh, PAM_OLDAUTHTOK, pi->pam_authtok);
- if (ret != PAM_SUCCESS) {
- D(("Failed to set PAM_OLDAUTHTOK [%s], "
- "oldauthtok may not be available",
- pam_strerror(pamh,ret)));
- return ret;
- }
+ ret = pam_set_item(pamh, PAM_OLDAUTHTOK, pi->pam_authtok);
+ if (ret != PAM_SUCCESS) {
+ D(("Failed to set PAM_OLDAUTHTOK [%s], "
+ "oldauthtok may not be available",
+ pam_strerror(pamh,ret)));
+ return ret;
+ }
- if (pi->pam_authtok_type == SSS_AUTHTOK_TYPE_2FA) {
- ret = keep_authtok_data(pamh, pi);
- if (ret != 0) {
- D(("Failed to store authtok data to pam handle. Password "
- "change might fail."));
- }
+ if (pi->pam_authtok_type == SSS_AUTHTOK_TYPE_2FA) {
+ ret = keep_authtok_data(pamh, pi);
+ if (ret != 0) {
+ D(("Failed to store authtok data to pam handle. Password "
+ "change might fail."));
}
}
--
2.45.2

View File

@ -0,0 +1,178 @@
From ef375cdd67b51d8fb63cae4d3cd40f3a5c2bc173 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Mon, 1 Jul 2024 20:40:30 +0200
Subject: [PATCH 7/8] krb5_child: do not try passwords with OTP
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
During two-factor authentication (OTP) krb5_child should use use the
dedicated OTP auth types SSS_AUTHTOK_TYPE_2FA and
SSS_AUTHTOK_TYPE_2FA_SINGLE exclusively and should not try password or
other types.
The special handling needed of ssh under certain conditions are
documented in the code and the man page.
Resolves: https://github.com/SSSD/sssd/issues/7456
Reviewed-by: Justin Stephenson <jstephen@redhat.com>
Reviewed-by: Tomáš Halman <thalman@redhat.com>
(cherry picked from commit af799964e5fa1264467b49988021c054586eff27)
Reviewed-by: Sumit Bose <sbose@redhat.com>
---
src/man/sssd.conf.5.xml | 11 +++++++++
src/providers/krb5/krb5_child.c | 11 +--------
src/sss_client/pam_sss.c | 44 ++++++++++++++++++++++++---------
3 files changed, 44 insertions(+), 22 deletions(-)
diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
index fb86a4e41..8ac1a4418 100644
--- a/src/man/sssd.conf.5.xml
+++ b/src/man/sssd.conf.5.xml
@@ -4559,6 +4559,17 @@ ldap_user_extra_attrs = phone:telephoneNumber
to log in either only with the password or with both factors
two-step prompting has to be used.
</para>
+ <para>
+ Some clients, such as SSH with
+ 'PasswordAuthentication yes', generate their own prompts
+ and do not use prompts provided by SSSD or other PAM
+ modules. Additionally, for SSH with
+ PasswordAuthentication, if two-factor authentication is
+ available, SSSD expects that the
+ credentials entered by the user at the SSH password prompt
+ will always be the two factors in a single string, even if
+ two-factor authentication is optional.
+ </para>
</listitem>
</varlistentry>
</variablelist>
diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c
index 494711de9..cb9a9ce73 100644
--- a/src/providers/krb5/krb5_child.c
+++ b/src/providers/krb5/krb5_child.c
@@ -536,15 +536,6 @@ static krb5_error_code tokeninfo_matches(TALLOC_CTX *mem_ctx,
size_t fa2_len;
switch (sss_authtok_get_type(auth_tok)) {
- case SSS_AUTHTOK_TYPE_PASSWORD:
- ret = sss_authtok_get_password(auth_tok, &pwd, &len);
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "sss_authtok_get_password failed.\n");
- return ret;
- }
-
- return tokeninfo_matches_pwd(mem_ctx, ti, pwd, len, out_token, out_pin);
- break;
case SSS_AUTHTOK_TYPE_2FA_SINGLE:
ret = sss_authtok_get_2fa_single(auth_tok, &pwd, &len);
if (ret != EOK) {
@@ -569,7 +560,7 @@ static krb5_error_code tokeninfo_matches(TALLOC_CTX *mem_ctx,
"Unsupported authtok type %d\n", sss_authtok_get_type(auth_tok));
}
- return EINVAL;
+ return EAGAIN;
}
static krb5_error_code answer_otp(krb5_context ctx,
diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c
index 5171e58ec..d43bd0f55 100644
--- a/src/sss_client/pam_sss.c
+++ b/src/sss_client/pam_sss.c
@@ -1656,6 +1656,7 @@ static int prompt_password(pam_handle_t *pamh, struct pam_items *pi,
}
static int prompt_2fa(pam_handle_t *pamh, struct pam_items *pi,
+ bool second_factor_optional,
const char *prompt_fa1, const char *prompt_fa2)
{
int ret;
@@ -1706,13 +1707,30 @@ static int prompt_2fa(pam_handle_t *pamh, struct pam_items *pi,
goto done;
}
- if (resp[1].resp == NULL || *(resp[1].resp) == '\0'
- || (pi->pam_service != NULL && strcmp(pi->pam_service, "sshd") == 0
- && strcmp(resp[0].resp, resp[1].resp) == 0)) {
+ if (resp[1].resp == NULL || *(resp[1].resp) == '\0') {
/* Missing second factor, assume first factor contains combined 2FA
- * credentials.
- * Special handling for SSH with password authentication. Combined
- * 2FA credentials are used but SSH puts them in both responses. */
+ * credentials if the second factor is not optional. If it is optional
+ * then it is assumed that the first factor contain the password. */
+ pi->pam_authtok = strndup(resp[0].resp, MAX_AUTHTOK_SIZE);
+ if (pi->pam_authtok == NULL) {
+ D(("strndup failed."));
+ ret = PAM_BUF_ERR;
+ goto done;
+ }
+ pi->pam_authtok_size = strlen(pi->pam_authtok) + 1;
+ pi->pam_authtok_type = second_factor_optional
+ ? SSS_AUTHTOK_TYPE_PASSWORD
+ : SSS_AUTHTOK_TYPE_2FA_SINGLE;
+ } else if (pi->pam_service != NULL && strcmp(pi->pam_service, "sshd") == 0
+ && strcmp(resp[0].resp, resp[1].resp) == 0) {
+ /* Special handling for SSH with password authentication (ssh's
+ * 'PasswordAuthentication' option. In this mode the ssh client
+ * directly prompts the user for a password and the prompts we are
+ * sending are ignored. Since we send two prompts ssh * will create two
+ * response as well with the same content. We assume that the combined
+ * 2FA credentials are used even if the second factor is optional
+ * because there is no indication about the intention of the user. As a
+ * result we prefer the more secure variant. */
pi->pam_authtok = strndup(resp[0].resp, MAX_AUTHTOK_SIZE);
if (pi->pam_authtok == NULL) {
@@ -1721,7 +1739,7 @@ static int prompt_2fa(pam_handle_t *pamh, struct pam_items *pi,
goto done;
}
pi->pam_authtok_size = strlen(pi->pam_authtok) + 1;
- pi->pam_authtok_type = SSS_AUTHTOK_TYPE_PASSWORD;
+ pi->pam_authtok_type = SSS_AUTHTOK_TYPE_2FA_SINGLE;
} else {
ret = sss_auth_pack_2fa_blob(resp[0].resp, 0, resp[1].resp, 0, NULL, 0,
@@ -2487,7 +2505,7 @@ static int prompt_by_config(pam_handle_t *pamh, struct pam_items *pi)
ret = prompt_password(pamh, pi, pc_get_password_prompt(pi->pc[c]));
break;
case PC_TYPE_2FA:
- ret = prompt_2fa(pamh, pi, pc_get_2fa_1st_prompt(pi->pc[c]),
+ ret = prompt_2fa(pamh, pi, false, pc_get_2fa_1st_prompt(pi->pc[c]),
pc_get_2fa_2nd_prompt(pi->pc[c]));
break;
case PC_TYPE_2FA_SINGLE:
@@ -2564,10 +2582,10 @@ static int get_authtok_for_authentication(pam_handle_t *pamh,
|| (pi->otp_vendor != NULL && pi->otp_token_id != NULL
&& pi->otp_challenge != NULL)) {
if (pi->password_prompting) {
- ret = prompt_2fa(pamh, pi, _("First Factor: "),
+ ret = prompt_2fa(pamh, pi, true, _("First Factor: "),
_("Second Factor (optional): "));
} else {
- ret = prompt_2fa(pamh, pi, _("First Factor: "),
+ ret = prompt_2fa(pamh, pi, false, _("First Factor: "),
_("Second Factor: "));
}
} else if (pi->passkey_prompt_pin) {
@@ -2736,10 +2754,12 @@ static int get_authtok_for_password_change(pam_handle_t *pamh,
|| (pi->otp_vendor != NULL && pi->otp_token_id != NULL
&& pi->otp_challenge != NULL)) {
if (pi->password_prompting) {
- ret = prompt_2fa(pamh, pi, _("First Factor (Current Password): "),
+ ret = prompt_2fa(pamh, pi, true,
+ _("First Factor (Current Password): "),
_("Second Factor (optional): "));
} else {
- ret = prompt_2fa(pamh, pi, _("First Factor (Current Password): "),
+ ret = prompt_2fa(pamh, pi, false,
+ _("First Factor (Current Password): "),
_("Second Factor: "));
}
} else if ((flags & PAM_CLI_FLAGS_USE_FIRST_PASS)
--
2.45.2

View File

@ -0,0 +1,45 @@
From 7e76396a891b4c704f1db8c71a217f869bef0ec3 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Fri, 12 Jul 2024 13:46:00 +0200
Subject: [PATCH 8/8] pam_sss: add missing optional 2nd factor handling
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This is a follow up to pull-request #7462 and adds the proper handling of
an optional second factor in case the prompting is configured.
Resolves: https://github.com/SSSD/sssd/issues/7456
Reviewed-by: Justin Stephenson <jstephen@redhat.com>
Reviewed-by: Tomáš Halman <thalman@redhat.com>
(cherry picked from commit 077d2993a1b306e7cfe61618cbd5d03c602572f8)
Reviewed-by: Sumit Bose <sbose@redhat.com>
---
src/sss_client/pam_sss.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c
index d43bd0f55..d1101e16c 100644
--- a/src/sss_client/pam_sss.c
+++ b/src/sss_client/pam_sss.c
@@ -2505,8 +2505,13 @@ static int prompt_by_config(pam_handle_t *pamh, struct pam_items *pi)
ret = prompt_password(pamh, pi, pc_get_password_prompt(pi->pc[c]));
break;
case PC_TYPE_2FA:
- ret = prompt_2fa(pamh, pi, false, pc_get_2fa_1st_prompt(pi->pc[c]),
- pc_get_2fa_2nd_prompt(pi->pc[c]));
+ if (pi->password_prompting) {
+ ret = prompt_2fa(pamh, pi, true, pc_get_2fa_1st_prompt(pi->pc[c]),
+ pc_get_2fa_2nd_prompt(pi->pc[c]));
+ } else {
+ ret = prompt_2fa(pamh, pi, false, pc_get_2fa_1st_prompt(pi->pc[c]),
+ pc_get_2fa_2nd_prompt(pi->pc[c]));
+ }
break;
case PC_TYPE_2FA_SINGLE:
ret = prompt_2fa_single(pamh, pi,
--
2.45.2

File diff suppressed because it is too large Load Diff