sssd-2.6.0-2: pull latest upstream code

This commit is contained in:
Pavel Březina 2021-11-01 11:59:58 +01:00
parent c0c482c21d
commit 306f2f008c
15 changed files with 1537 additions and 1 deletions

View File

@ -0,0 +1,43 @@
From 625274738b5f68418608be99b68d35c43079e2a1 Mon Sep 17 00:00:00 2001
From: Alexey Tikhonov <atikhono@redhat.com>
Date: Thu, 14 Oct 2021 18:48:09 +0200
Subject: [PATCH 01/17] DEBUG: fix missing "va_end"
Fixes following warning:
```
Error: VARARGS (CWE-237):
sssd-2.6.0/src/util/debug.c:294: va_init: Initializing va_list "ap_fallback".
sssd-2.6.0/src/util/debug.c:305: missing_va_end: "va_end" was not called for "ap_fallback".
# 303| debug_chain_id, format);
# 304| if (ret < 0) {
# 305|-> return;
# 306| }
# 307| result_fmt = chain_id_fmt_dyn;
```
Reviewed-by: Sumit Bose <sbose@redhat.com>
---
src/util/debug.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/util/debug.c b/src/util/debug.c
index 51fb42d3cf454ab8a83aa82329725bd250ce271c..7c03fb7dfff1bd6b9510ecd3c2e0948a83e7622e 100644
--- a/src/util/debug.c
+++ b/src/util/debug.c
@@ -297,11 +297,13 @@ void sss_vdebug_fn(const char *file,
ret = snprintf(chain_id_fmt_fixed, sizeof(chain_id_fmt_fixed),
DEBUG_CHAIN_ID_FMT"%s", debug_chain_id, format);
if (ret < 0) {
+ va_end(ap_fallback);
return;
} else if (ret >= sizeof(chain_id_fmt_fixed)) {
ret = asprintf(&chain_id_fmt_dyn, DEBUG_CHAIN_ID_FMT"%s",
debug_chain_id, format);
if (ret < 0) {
+ va_end(ap_fallback);
return;
}
result_fmt = chain_id_fmt_dyn;
--
2.31.1

View File

@ -0,0 +1,143 @@
From 92e1679943fd2a2a50c9e0e176a10a875cb3ac56 Mon Sep 17 00:00:00 2001
From: Tomas Halman <thalman@redhat.com>
Date: Fri, 15 Oct 2021 11:03:19 +0200
Subject: [PATCH 03/17] CONFDB: Change ownership of config.ldb
Config database is owned by root. This prevents our socket
activated services to start because they are started under
the sssd user. Changing the ownership to sssd fixes the issue.
Resolves: https://github.com/SSSD/sssd/issues/5781
Reviewed-by: Iker Pedrosa <ipedrosa@redhat.com>
---
src/confdb/confdb.c | 3 +++
src/monitor/monitor.c | 5 ++++-
src/tests/cwrap/group | 1 +
src/tests/cwrap/passwd | 1 +
src/util/usertools.c | 42 ++++++++++++++++++++++++++++++++++++++++++
src/util/util.h | 3 +++
6 files changed, 54 insertions(+), 1 deletion(-)
diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c
index b7a73d97b34bfa60aa59855c1eec2a17ed0a4ec0..7a718cc628343570d484135da639250ad83e8b01 100644
--- a/src/confdb/confdb.c
+++ b/src/confdb/confdb.c
@@ -673,8 +673,11 @@ int confdb_init(TALLOC_CTX *mem_ctx,
}
old_umask = umask(SSS_DFL_UMASK);
+ sss_set_sssd_user_eid();
ret = ldb_connect(cdb->ldb, confdb_location, 0, NULL);
+
+ sss_restore_sssd_user_eid();
umask(old_umask);
if (ret != LDB_SUCCESS) {
DEBUG(SSSDBG_FATAL_FAILURE, "Unable to open config database [%s]\n",
diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c
index b5fee7e7a78cb75ee267279f5a97725d8dedca52..c7610cb69b77899103d99bf44bb3b9f426482e65 100644
--- a/src/monitor/monitor.c
+++ b/src/monitor/monitor.c
@@ -1551,6 +1551,8 @@ errno_t load_configuration(TALLOC_CTX *mem_ctx,
errno_t ret;
struct mt_ctx *ctx;
char *cdb_file = NULL;
+ uid_t sssd_uid;
+ gid_t sssd_gid;
ctx = talloc_zero(mem_ctx, struct mt_ctx);
if(!ctx) {
@@ -1591,7 +1593,8 @@ errno_t load_configuration(TALLOC_CTX *mem_ctx,
/* Allow configuration database to be accessible
* when SSSD runs as nonroot */
- ret = chown(cdb_file, ctx->uid, ctx->gid);
+ sss_sssd_user_uid_and_gid(&sssd_uid, &sssd_gid);
+ ret = chown(cdb_file, sssd_uid, sssd_gid);
if (ret != 0) {
ret = errno;
DEBUG(SSSDBG_FATAL_FAILURE,
diff --git a/src/tests/cwrap/group b/src/tests/cwrap/group
index d0cea659ea030d14a293f5d941f473f8f3786886..1a3766e6307274b2935737d5060e3d8531d0bed2 100644
--- a/src/tests/cwrap/group
+++ b/src/tests/cwrap/group
@@ -1,2 +1,3 @@
+root:x:0:
sssd:x:123:
foogroup:x:10001:
diff --git a/src/tests/cwrap/passwd b/src/tests/cwrap/passwd
index 862ccfe03e40d43c60c56b0c50f328f494d7e6b9..0511a91bcb2ee3e12d582c98ca0bc6bb358816d3 100644
--- a/src/tests/cwrap/passwd
+++ b/src/tests/cwrap/passwd
@@ -1,2 +1,3 @@
+root:x:0:0:root:/root:/bin/bash
sssd:x:123:456:sssd unprivileged user:/:/sbin/nologin
foobar:x:10001:10001:User for SSSD testing:/home/foobar:/bin/bash
diff --git a/src/util/usertools.c b/src/util/usertools.c
index 8c2ed4e2de764edcb0549eac02a524e7e9975c4f..6f93a4cef288a245a95c2e510a62233f904034fb 100644
--- a/src/util/usertools.c
+++ b/src/util/usertools.c
@@ -835,3 +835,45 @@ done:
talloc_zfree(tmp_ctx);
return ret;
}
+
+void sss_sssd_user_uid_and_gid(uid_t *_uid, gid_t *_gid)
+{
+ uid_t sssd_uid;
+ gid_t sssd_gid;
+ errno_t ret;
+
+ ret = sss_user_by_name_or_uid(SSSD_USER, &sssd_uid, &sssd_gid);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "failed to get sssd user (" SSSD_USER ") uid/gid, using root\n");
+ sssd_uid = 0;
+ sssd_gid = 0;
+ }
+
+ if (_uid != NULL) {
+ *_uid = sssd_uid;
+ }
+
+ if (_gid != NULL) {
+ *_gid = sssd_gid;
+ }
+}
+
+void sss_set_sssd_user_eid(void)
+{
+ uid_t uid;
+ gid_t gid;
+
+ if (geteuid() == 0) {
+ sss_sssd_user_uid_and_gid(&uid, &gid);
+ seteuid(uid);
+ setegid(gid);
+ }
+}
+
+void sss_restore_sssd_user_eid(void)
+{
+ if (getuid() == 0) {
+ seteuid(getuid());
+ setegid(getgid());
+ }
+}
diff --git a/src/util/util.h b/src/util/util.h
index e85cd12022c4ef39c8dd6859bc9adf28e0314129..6dfd2540cc209a728f385273082221b65d05249f 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -383,6 +383,9 @@ errno_t sss_canonicalize_ip_address(TALLOC_CTX *mem_ctx,
const char * const * get_known_services(void);
errno_t sss_user_by_name_or_uid(const char *input, uid_t *_uid, gid_t *_gid);
+void sss_sssd_user_uid_and_gid(uid_t *_uid, gid_t *_gid);
+void sss_set_sssd_user_eid(void);
+void sss_restore_sssd_user_eid(void);
int split_on_separator(TALLOC_CTX *mem_ctx, const char *str,
const char sep, bool trim, bool skip_empty,
--
2.31.1

View File

@ -0,0 +1,44 @@
From 7db6cfd0674d45a4e769b0beeb551c89cc89f92f Mon Sep 17 00:00:00 2001
From: Tomas Halman <thalman@redhat.com>
Date: Fri, 15 Oct 2021 11:04:05 +0200
Subject: [PATCH 04/17] CONFDB: Change ownership before dropping privileges
From previous SSSD version, config file can exist and can be
owned by root. To allow smooth transition we can change
the ownership.
This commit can be reverted later.
Resolves: https://github.com/SSSD/sssd/issues/5781
Reviewed-by: Iker Pedrosa <ipedrosa@redhat.com>
---
src/confdb/confdb.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c
index 7a718cc628343570d484135da639250ad83e8b01..80203c0f640975471df31c522ca91f94099cbcf9 100644
--- a/src/confdb/confdb.c
+++ b/src/confdb/confdb.c
@@ -641,6 +641,8 @@ int confdb_init(TALLOC_CTX *mem_ctx,
struct confdb_ctx *cdb;
int ret = EOK;
mode_t old_umask;
+ uid_t sssd_uid;
+ gid_t sssd_gid;
cdb = talloc_zero(mem_ctx, struct confdb_ctx);
if (!cdb)
@@ -673,6 +675,9 @@ int confdb_init(TALLOC_CTX *mem_ctx,
}
old_umask = umask(SSS_DFL_UMASK);
+ /* file may exists and could be owned by root from previous version */
+ sss_sssd_user_uid_and_gid(&sssd_uid, &sssd_gid);
+ chown(confdb_location, sssd_uid, sssd_gid);
sss_set_sssd_user_eid();
ret = ldb_connect(cdb->ldb, confdb_location, 0, NULL);
--
2.31.1

View File

@ -0,0 +1,53 @@
From 766fe6235083d38bc25ae5562cd67113262af015 Mon Sep 17 00:00:00 2001
From: Alexey Tikhonov <atikhono@redhat.com>
Date: Mon, 18 Oct 2021 22:25:31 +0200
Subject: [PATCH 05/17] GPO: fixed compilation warning
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Fixes following compilation warning:
```
../src/providers/ad/ad_gpo.c: In function ad_gpo_access_send:
../src/util/debug.h:138:5: warning: %s directive argument is null [-Wformat-overflow=]
138 | sss_debug_fn(__FILE__, __LINE__, __FUNCTION__, \
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
139 | level, \
| ~~~~~~~~
140 | format, ##__VA_ARGS__); \
| ~~~~~~~~~~~~~~~~~~~~~~
../src/providers/ad/ad_gpo.c:1847:5: note: in expansion of macro DEBUG
1847 | DEBUG(SSSDBG_TRACE_FUNC, "service %s maps to %s\n", service,
| ^~~~~
```
Reviewed-by: Pavel Březina <pbrezina@redhat.com>
---
src/providers/ad/ad_gpo.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/providers/ad/ad_gpo.c b/src/providers/ad/ad_gpo.c
index 219f3984912086a61bf79525e6740ed4c9bc247b..f3452176af1275ea393957a8e8c667c1376bf314 100644
--- a/src/providers/ad/ad_gpo.c
+++ b/src/providers/ad/ad_gpo.c
@@ -250,7 +250,7 @@ struct gpo_map_option_entry gpo_map_option_entries[] = {
{GPO_MAP_DENY, AD_GPO_MAP_DENY, gpo_map_deny_defaults, NULL, NULL},
};
-const char* gpo_map_type_string(int gpo_map_type)
+static const char* gpo_map_type_string(int gpo_map_type)
{
switch(gpo_map_type) {
case GPO_MAP_INTERACTIVE: return "Interactive";
@@ -261,7 +261,7 @@ const char* gpo_map_type_string(int gpo_map_type)
case GPO_MAP_PERMIT: return "Permitted";
case GPO_MAP_DENY: return "Denied";
}
- return NULL;
+ return "-unknown-"; /* this helper is only used in logs */
}
static inline bool
--
2.31.1

View File

@ -0,0 +1,56 @@
From 84a4230b195f578c43d6e221b4a04f546fd998f9 Mon Sep 17 00:00:00 2001
From: Alexey Tikhonov <atikhono@redhat.com>
Date: Mon, 18 Oct 2021 22:35:13 +0200
Subject: [PATCH 06/17] KCM: fixed uninitialized value
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Fixes following warnings:
```
Error: UNINIT (CWE-457):
sssd-2.6.0/src/responder/kcm/kcmsrv_ccache.c:285: var_decl: Declaring variable "ret" without initializer.
sssd-2.6.0/src/responder/kcm/kcmsrv_ccache.c:323: uninit_use: Using uninitialized value "ret".
# 321| krb5_free_context(kctx);
# 322|
# 323|-> return ret;
# 324| #else
# 325| return EOK;
Error: CLANG_WARNING:
sssd-2.6.0/src/responder/kcm/kcmsrv_ccache.c:323:5: warning[core.uninitialized.UndefReturn]: Undefined or garbage value returned to caller
# 321| krb5_free_context(kctx);
# 322|
# 323|-> return ret;
# 324| #else
# 325| return EOK;
```
Reviewed-by: Pavel Březina <pbrezina@redhat.com>
---
src/responder/kcm/kcmsrv_ccache.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/responder/kcm/kcmsrv_ccache.c b/src/responder/kcm/kcmsrv_ccache.c
index ef174e0a090c54b72d488f6d68041d2ac117990d..b63fc70afa35d52e79771d7a5c9f679bdead9f39 100644
--- a/src/responder/kcm/kcmsrv_ccache.c
+++ b/src/responder/kcm/kcmsrv_ccache.c
@@ -294,6 +294,7 @@ kcm_cc_remove_duplicates(struct kcm_ccache *cc,
kcrd = kcm_cred_to_krb5(kctx, kcm_crd);
if (kcrd == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "Failed to convert kcm cred to krb5\n");
+ ret = ERR_INTERNAL;
goto done;
}
@@ -301,6 +302,7 @@ kcm_cc_remove_duplicates(struct kcm_ccache *cc,
kcrd_cc = kcm_cred_to_krb5(kctx, p);
if (kcrd_cc == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "Failed to convert kcm cred to krb5\n");
+ ret = ERR_INTERNAL;
goto done;
}
--
2.31.1

View File

@ -0,0 +1,62 @@
From bb94a18f0f0cba1e9fb5abf78b995d69e5f3c559 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Mon, 18 Oct 2021 12:29:06 +0200
Subject: [PATCH 07/17] cache_req: return success for autofs when ENOENT is
returned from provider
The receive function should return true if data provider lookup was
successfull and false if there was an error. "Not found" result is
considered a successful lookup, only failure to perform a search
should result in false return code.
Resolves: https://github.com/SSSD/sssd/issues/5832
Reviewed-by: Pawel Polawski <ppolawsk@redhat.com>
---
.../common/cache_req/plugins/cache_req_autofs_entry_by_name.c | 2 +-
.../common/cache_req/plugins/cache_req_autofs_map_by_name.c | 2 +-
.../common/cache_req/plugins/cache_req_autofs_map_entries.c | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/responder/common/cache_req/plugins/cache_req_autofs_entry_by_name.c b/src/responder/common/cache_req/plugins/cache_req_autofs_entry_by_name.c
index 0dc6a585ab8b90ebf8bc43a061172a6d8e3bc3ad..788b6708ce343f7acdf4a9a8388c4eb8732129f8 100644
--- a/src/responder/common/cache_req/plugins/cache_req_autofs_entry_by_name.c
+++ b/src/responder/common/cache_req/plugins/cache_req_autofs_entry_by_name.c
@@ -97,7 +97,7 @@ cache_req_autofs_entry_by_name_dp_recv(struct tevent_req *subreq,
ret = sbus_call_dp_autofs_GetEntry_recv(subreq);
- if (ret == ERR_MISSING_DP_TARGET) {
+ if (ret == ERR_MISSING_DP_TARGET || ret == ENOENT) {
ret = EOK;
}
diff --git a/src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c b/src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c
index 6a665c58ec83eb2471d8be823eef9e61ab6d443a..5d82641ccab1f42e4596102d95f64ed166857d56 100644
--- a/src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c
+++ b/src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c
@@ -93,7 +93,7 @@ cache_req_autofs_map_by_name_dp_recv(struct tevent_req *subreq,
ret = sbus_call_dp_autofs_GetMap_recv(subreq);
- if (ret == ERR_MISSING_DP_TARGET) {
+ if (ret == ERR_MISSING_DP_TARGET || ret == ENOENT) {
ret = EOK;
}
diff --git a/src/responder/common/cache_req/plugins/cache_req_autofs_map_entries.c b/src/responder/common/cache_req/plugins/cache_req_autofs_map_entries.c
index 46776b980804ace3188f14375256d205b2610037..29f289723f233c1b357eefcb6d1fd75c493b950e 100644
--- a/src/responder/common/cache_req/plugins/cache_req_autofs_map_entries.c
+++ b/src/responder/common/cache_req/plugins/cache_req_autofs_map_entries.c
@@ -125,7 +125,7 @@ cache_req_autofs_map_entries_dp_recv(struct tevent_req *subreq,
ret = sbus_call_dp_autofs_Enumerate_recv(subreq);
- if (ret == ERR_MISSING_DP_TARGET) {
+ if (ret == ERR_MISSING_DP_TARGET || ret == ENOENT) {
ret = EOK;
}
--
2.31.1

View File

@ -0,0 +1,48 @@
From 8db2485cd28e0af74bd008251ba49b6d6e3a73a6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Wed, 29 Sep 2021 12:11:08 +0200
Subject: [PATCH 08/17] sbus: maintain correct refcount before sending a reply
sbus_reply decreases the refcount of @reply. This usuall means that
refcount drops to zero and the message is freed. However, under
special circumstances the refcount is increased inside libdbus,
the refcount will be 1 when we leave the function and we drop it
to zero in talloc_free(state) later in this function. This will
leave an invalid message to be send inside dbus connection and
eventually crash.
Increasing the refcount here makes sure that the refcount is always
correct.
Resolves: https://github.com/SSSD/sssd/issues/5672
Reviewed-by: Pawel Polawski <ppolawsk@redhat.com>
---
src/sbus/router/sbus_router_handler.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/src/sbus/router/sbus_router_handler.c b/src/sbus/router/sbus_router_handler.c
index d9a374b41411d7e4451c2d84d3ab1589e256a29a..7b6c2441f16af20b6d4fa27ae17225756a9d387a 100644
--- a/src/sbus/router/sbus_router_handler.c
+++ b/src/sbus/router/sbus_router_handler.c
@@ -160,6 +160,17 @@ static void sbus_issue_request_done(struct tevent_req *subreq)
}
if (ret == EOK) {
+ /* sbus_reply decreases the refcount of @reply. This usuall means that
+ * refcount drops to zero and the message is freed. However, under
+ * special circumstances the refcount is increased inside libdbus,
+ * the refcount will be 1 when we leave the function and we drop it
+ * to zero in talloc_free(state) later in this function. This will
+ * leave an invalid message to be send inside dbus connection and
+ * eventually crash.
+ *
+ * Increasing the refcount here makes sure that the refcount is always
+ * correct. */
+ dbus_message_ref(reply);
sbus_reply(state->conn, reply);
} else {
sbus_errno_to_error(state, ret, &error_name, &error_msg);
--
2.31.1

View File

@ -0,0 +1,101 @@
From de6eba31eaf19e7d8c87cc84aee140e29438336f Mon Sep 17 00:00:00 2001
From: Alexey Tikhonov <atikhono@redhat.com>
Date: Fri, 15 Oct 2021 18:23:55 +0200
Subject: [PATCH 09/17] Removed excessive includes around 'strtonum'
Reviewed-by: Pawel Polawski <ppolawsk@redhat.com>
---
src/providers/ad/ad_gpo.c | 1 +
src/util/strtonum.c | 6 ------
src/util/strtonum.h | 2 --
src/util/usertools.c | 1 +
src/util/well_known_sids.c | 1 +
5 files changed, 3 insertions(+), 8 deletions(-)
diff --git a/src/providers/ad/ad_gpo.c b/src/providers/ad/ad_gpo.c
index f3452176af1275ea393957a8e8c667c1376bf314..8f2fe277e14fe4f430184c03d9913fbbaa3428e9 100644
--- a/src/providers/ad/ad_gpo.c
+++ b/src/providers/ad/ad_gpo.c
@@ -31,6 +31,7 @@
* ad_gpo_process_cse_send/recv: retrieve policy file data
*/
+#include <ctype.h>
#include <security/pam_modules.h>
#include <syslog.h>
#include <fcntl.h>
diff --git a/src/util/strtonum.c b/src/util/strtonum.c
index 22e682b4b22d1de056c578a05a5f81dfdd17df24..8eda8ea25e8896358e13fef7ed4aeeef0df6cdfe 100644
--- a/src/util/strtonum.c
+++ b/src/util/strtonum.c
@@ -19,14 +19,10 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <ctype.h>
#include <stdlib.h>
#include <errno.h>
-#include "config.h"
-#include "util/util.h"
#include "util/strtonum.h"
-/* strtoint32 */
int32_t strtoint32(const char *nptr, char **endptr, int base)
{
long long ret = 0;
@@ -48,7 +44,6 @@ int32_t strtoint32(const char *nptr, char **endptr, int base)
}
-/* strtouint32 */
uint32_t strtouint32(const char *nptr, char **endptr, int base)
{
unsigned long long ret = 0;
@@ -65,7 +60,6 @@ uint32_t strtouint32(const char *nptr, char **endptr, int base)
}
-/* strtouint16 */
uint16_t strtouint16(const char *nptr, char **endptr, int base)
{
unsigned long long ret = 0;
diff --git a/src/util/strtonum.h b/src/util/strtonum.h
index d9c31e9cde87c3af06ab08fbbcadadaf57b593e5..ae493b5f512e31459372bd806e2accccdd827af1 100644
--- a/src/util/strtonum.h
+++ b/src/util/strtonum.h
@@ -22,8 +22,6 @@
#ifndef _STRTONUM_H_
#define _STRTONUM_H_
-#include <ctype.h>
-#include <stdlib.h>
#include <stdint.h>
int32_t strtoint32(const char *nptr, char **endptr, int base);
diff --git a/src/util/usertools.c b/src/util/usertools.c
index 6f93a4cef288a245a95c2e510a62233f904034fb..1fbde2eb43b1cc4c6dead346a1dafc632a6ec78b 100644
--- a/src/util/usertools.c
+++ b/src/util/usertools.c
@@ -21,6 +21,7 @@
#include <pwd.h>
#include <errno.h>
+#include <ctype.h>
#include <talloc.h>
#include <grp.h>
diff --git a/src/util/well_known_sids.c b/src/util/well_known_sids.c
index 38fe2646faa884f3e14d2b0379b9d9eb7641772c..1f9a7beea8086c6aa34a132e4df85edbf37aca55 100644
--- a/src/util/well_known_sids.c
+++ b/src/util/well_known_sids.c
@@ -20,6 +20,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <ctype.h>
#include "util/util.h"
#include "util/strtonum.h"
--
2.31.1

View File

@ -0,0 +1,403 @@
From a2cc7daef2a1378aa12a21cd37a6369946e27bfc Mon Sep 17 00:00:00 2001
From: Alexey Tikhonov <atikhono@redhat.com>
Date: Fri, 15 Oct 2021 21:12:32 +0200
Subject: [PATCH 10/17] 'strtonum' helpers: usage sanitization
To properly check for an error during string to number conversion
one needs to:
- check `errno`
- check that something was really converted (i.e. start != end)
- (if this is expected) check that entire string was consumed
Some of those error conditions weren't checked in various locations
over the code.
Reviewed-by: Pawel Polawski <ppolawsk@redhat.com>
---
src/db/sysdb.c | 3 ---
src/providers/ad/ad_id.c | 8 ++++----
src/providers/ad/ad_machine_pw_renewal.c | 2 --
src/providers/ipa/ipa_s2n_exop.c | 1 -
src/providers/ipa/ipa_subdomains_id.c | 8 ++++----
src/providers/ipa/ipa_views.c | 1 -
src/providers/ldap/ldap_id.c | 4 ++--
src/providers/ldap/ldap_id_services.c | 7 ++++---
src/providers/ldap/sdap_access.c | 8 ++++----
src/providers/ldap/sdap_range.c | 2 +-
src/providers/proxy/proxy_services.c | 1 -
src/responder/common/responder_common.c | 3 +--
src/responder/ifp/ifp_groups.c | 9 +++++----
src/responder/ifp/ifp_users.c | 7 ++++---
src/responder/ifp/ifpsrv.c | 7 ++++---
src/tools/common/sss_colondb.c | 7 ++++---
src/util/usertools.c | 3 +--
src/util/well_known_sids.c | 1 -
18 files changed, 38 insertions(+), 44 deletions(-)
diff --git a/src/db/sysdb.c b/src/db/sysdb.c
index 3fe0ebf6c21a408228b572b2268d159eed6cfafc..3ba79ab3603d802c71dad24e994779019a0ced2f 100644
--- a/src/db/sysdb.c
+++ b/src/db/sysdb.c
@@ -359,7 +359,6 @@ int sysdb_attrs_get_int32_t(struct sysdb_attrs *attrs, const char *name,
return ERANGE;
}
- errno = 0;
val = strtoint32((const char *) el->values[0].data, &endptr, 10);
if (errno != 0) return errno;
if (*endptr) return EINVAL;
@@ -385,7 +384,6 @@ int sysdb_attrs_get_uint32_t(struct sysdb_attrs *attrs, const char *name,
return ERANGE;
}
- errno = 0;
val = strtouint32((const char *) el->values[0].data, &endptr, 10);
if (errno != 0) return errno;
if (*endptr) return EINVAL;
@@ -411,7 +409,6 @@ int sysdb_attrs_get_uint16_t(struct sysdb_attrs *attrs, const char *name,
return ERANGE;
}
- errno = 0;
val = strtouint16((const char *) el->values[0].data, &endptr, 10);
if (errno != 0) return errno;
if (*endptr) return EINVAL;
diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c
index 8e4a0a50946296bf8281b5d80913a3a9fd7855d7..3d12472432708de8df0a872decbcea3dea6cbd99 100644
--- a/src/providers/ad/ad_id.c
+++ b/src/providers/ad/ad_id.c
@@ -42,6 +42,7 @@ static bool ad_account_can_shortcut(struct sdap_idmap_ctx *idmap_ctx,
uint32_t id;
bool shortcut = false;
errno_t ret;
+ char *endptr;
if (!sdap_idmap_domain_has_algorithmic_mapping(idmap_ctx, domain->name,
domain->domain_id)) {
@@ -51,10 +52,9 @@ static bool ad_account_can_shortcut(struct sdap_idmap_ctx *idmap_ctx,
switch (filter_type) {
case BE_FILTER_IDNUM:
/* convert value to ID */
- errno = 0;
- id = strtouint32(filter_value, NULL, 10);
- if (errno != 0) {
- ret = errno;
+ id = strtouint32(filter_value, &endptr, 10);
+ if ((errno != 0) || *endptr || (filter_value == endptr)) {
+ ret = errno ? errno : EINVAL;
DEBUG(SSSDBG_MINOR_FAILURE, "Unable to convert filter value to "
"number [%d]: %s\n", ret, strerror(ret));
goto done;
diff --git a/src/providers/ad/ad_machine_pw_renewal.c b/src/providers/ad/ad_machine_pw_renewal.c
index 6e7137a86a2edcebdc2d1f105cabdf9410a42db7..b5c6cfec9454ad4472f79ed8918b2d4d85640fb7 100644
--- a/src/providers/ad/ad_machine_pw_renewal.c
+++ b/src/providers/ad/ad_machine_pw_renewal.c
@@ -360,7 +360,6 @@ errno_t ad_machine_account_password_renewal_init(struct be_ctx *be_ctx,
goto done;
}
- errno = 0;
period = strtouint32(opt_list[0], &endptr, 10);
if (errno != 0 || *endptr != '\0' || opt_list[0] == endptr) {
DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse first renewal option.\n");
@@ -368,7 +367,6 @@ errno_t ad_machine_account_password_renewal_init(struct be_ctx *be_ctx,
goto done;
}
- errno = 0;
initial_delay = strtouint32(opt_list[1], &endptr, 10);
if (errno != 0 || *endptr != '\0' || opt_list[0] == endptr) {
DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse second renewal option.\n");
diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
index b0baf0e67ce5499aab8a2d87964d7ab1d45d3a55..56105ac2bdad22f20e8885dbc881d43e568530a9 100644
--- a/src/providers/ipa/ipa_s2n_exop.c
+++ b/src/providers/ipa/ipa_s2n_exop.c
@@ -1340,7 +1340,6 @@ static errno_t ipa_s2n_get_list_step(struct tevent_req *req)
break;
case REQ_INP_ID:
- errno = 0;
id = strtouint32(state->list[state->list_idx], &endptr, 10);
if (errno != 0 || *endptr != '\0'
|| (state->list[state->list_idx] == endptr)) {
diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c
index 46d4962585caca7d30df41d1dcf728360ca0a176..445b9ba2ff2ee2116409316a97f9783700af505b 100644
--- a/src/providers/ipa/ipa_subdomains_id.c
+++ b/src/providers/ipa/ipa_subdomains_id.c
@@ -1125,6 +1125,7 @@ errno_t get_object_from_cache(TALLOC_CTX *mem_ctx,
uint32_t id;
struct ldb_message *msg = NULL;
struct ldb_result *res = NULL;
+ char *endptr;
const char *attrs[] = { SYSDB_NAME,
SYSDB_UIDNUM,
SYSDB_SID_STR,
@@ -1183,10 +1184,9 @@ errno_t get_object_from_cache(TALLOC_CTX *mem_ctx,
ret = EOK;
goto done;
} else if (ar->filter_type == BE_FILTER_IDNUM) {
- errno = 0;
- id = strtouint32(ar->filter_value, NULL, 10);
- if (errno != 0) {
- ret = errno;
+ id = strtouint32(ar->filter_value, &endptr, 10);
+ if ((errno != 0) || *endptr || (ar->filter_value == endptr)) {
+ ret = errno ? errno : EINVAL;
DEBUG(SSSDBG_OP_FAILURE, "strtouint32 failed.\n");
goto done;
}
diff --git a/src/providers/ipa/ipa_views.c b/src/providers/ipa/ipa_views.c
index e1090d03b32747ded0cfafa64571646db83103b1..50243098ae591f55e98c70cd7aa9248b973d6477 100644
--- a/src/providers/ipa/ipa_views.c
+++ b/src/providers/ipa/ipa_views.c
@@ -90,7 +90,6 @@ static errno_t dp_id_data_to_override_filter(TALLOC_CTX *mem_ctx,
break;
case BE_FILTER_IDNUM:
- errno = 0;
id = strtouint32(ar->filter_value, &endptr, 10);
if (errno != 0|| *endptr != '\0' || (ar->filter_value == endptr)) {
DEBUG(SSSDBG_CRIT_FAILURE, "Invalid id value [%s].\n",
diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c
index 9b67773a8d2dd96e084eca8e091e36eba56bfa2f..51cebc8c9b176d37d08908ad3d53b22b373f55d6 100644
--- a/src/providers/ldap/ldap_id.c
+++ b/src/providers/ldap/ldap_id.c
@@ -264,7 +264,7 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx,
* in the search filter.
*/
uid = strtouint32(filter_value, &endptr, 10);
- if (errno != EOK) {
+ if ((errno != EOK) || *endptr || (filter_value == endptr)) {
ret = EINVAL;
goto done;
}
@@ -742,7 +742,7 @@ struct tevent_req *groups_get_send(TALLOC_CTX *memctx,
* in the search filter.
*/
gid = strtouint32(filter_value, &endptr, 10);
- if (errno != EOK) {
+ if ((errno != EOK) || *endptr || (filter_value == endptr)) {
ret = EINVAL;
goto done;
}
diff --git a/src/providers/ldap/ldap_id_services.c b/src/providers/ldap/ldap_id_services.c
index 638cb619b39f135307090dcf0f2c6ab2cc4119d0..52a15631842cb4f93c2d73cf6b72aca9c097a26b 100644
--- a/src/providers/ldap/ldap_id_services.c
+++ b/src/providers/ldap/ldap_id_services.c
@@ -217,6 +217,7 @@ services_get_done(struct tevent_req *subreq)
{
errno_t ret;
uint16_t port;
+ char *endptr;
struct tevent_req *req =
tevent_req_callback_data(subreq, struct tevent_req);
struct sdap_services_get_state *state =
@@ -263,9 +264,9 @@ services_get_done(struct tevent_req *subreq)
break;
case BE_FILTER_IDNUM:
- port = strtouint16(state->name, NULL, 10);
- if (errno) {
- tevent_req_error(req, errno);
+ port = strtouint16(state->name, &endptr, 10);
+ if (errno || *endptr || (state->name == endptr)) {
+ tevent_req_error(req, (errno ? errno : EINVAL));
return;
}
diff --git a/src/providers/ldap/sdap_access.c b/src/providers/ldap/sdap_access.c
index 8add97ba88c09f16e833aa145c57d9fbbff54f95..1b898d24488fb1d7decdf5c2488009a02116b0fd 100644
--- a/src/providers/ldap/sdap_access.c
+++ b/src/providers/ldap/sdap_access.c
@@ -1812,6 +1812,7 @@ is_account_locked(const char *pwdAccountLockedTime,
time_t duration;
time_t now;
bool locked;
+ char *endptr;
/* Default action is to consider account to be locked. */
locked = true;
@@ -1855,10 +1856,9 @@ is_account_locked(const char *pwdAccountLockedTime,
if (difftime(lock_time, now) > 0.0) {
locked = false;
} else if (pwdAccountLockedDurationTime != NULL) {
- errno = 0;
- duration = strtouint32(pwdAccountLockedDurationTime, NULL, 0);
- if (errno) {
- ret = errno;
+ duration = strtouint32(pwdAccountLockedDurationTime, &endptr, 0);
+ if (errno || *endptr) {
+ ret = errno ? errno : EINVAL;
goto done;
}
/* Lockout has expired */
diff --git a/src/providers/ldap/sdap_range.c b/src/providers/ldap/sdap_range.c
index d88def6fa91789fb023909535c3f81e32adf6144..44c3350db1e19f6bcaece3e91652c2d0dd6e843e 100644
--- a/src/providers/ldap/sdap_range.c
+++ b/src/providers/ldap/sdap_range.c
@@ -120,7 +120,7 @@ errno_t sdap_parse_range(TALLOC_CTX *mem_ctx,
}
*range_offset = strtouint32(end_range, &endptr, 10);
- if (*endptr != '\0') {
+ if ((errno != 0) || (*endptr != '\0') || (end_range == endptr)) {
*range_offset = 0;
ret = errno;
DEBUG(SSSDBG_MINOR_FAILURE,
diff --git a/src/providers/proxy/proxy_services.c b/src/providers/proxy/proxy_services.c
index 2f7bbeb06d8f063466db55121c7005b04116d4f7..856da09be970741b015ebfabf06cff3f15ab5ce4 100644
--- a/src/providers/proxy/proxy_services.c
+++ b/src/providers/proxy/proxy_services.c
@@ -171,7 +171,6 @@ get_serv_byport(struct proxy_id_ctx *ctx,
goto done;
}
- errno = 0;
port = htons(strtouint16(be_filter, NULL, 0));
if (errno) {
ret = errno;
diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c
index 7e145aa9b26a3298e572484a6998b579f50dd4f2..913dbcd8002e77ba48157c44671218a5042289d8 100644
--- a/src/responder/common/responder_common.c
+++ b/src/responder/common/responder_common.c
@@ -224,7 +224,6 @@ errno_t csv_string_to_uid_array(TALLOC_CTX *mem_ctx, const char *csv_string,
}
for (c = 0; c < list_size; c++) {
- errno = 0;
if (*list[c] == '\0') {
DEBUG(SSSDBG_OP_FAILURE, "Empty list item.\n");
ret = EINVAL;
@@ -232,7 +231,7 @@ errno_t csv_string_to_uid_array(TALLOC_CTX *mem_ctx, const char *csv_string,
}
uids[c] = strtouint32(list[c], &endptr, 10);
- if (errno != 0 || *endptr != '\0') {
+ if ((errno != 0) || (*endptr != '\0') || (list[c] == endptr)) {
ret = errno;
if (ret == ERANGE) {
DEBUG(SSSDBG_OP_FAILURE, "List item [%s] is out of range.\n",
diff --git a/src/responder/ifp/ifp_groups.c b/src/responder/ifp/ifp_groups.c
index 353f3a79f31517fe6daa1c2158ed463d2d4d9a81..14c58c74c34ff31e792b5c0d85644956e082cd42 100644
--- a/src/responder/ifp/ifp_groups.c
+++ b/src/responder/ifp/ifp_groups.c
@@ -530,13 +530,14 @@ ifp_groups_get_from_cache(TALLOC_CTX *mem_ctx,
struct ldb_result *group_res = NULL;
errno_t ret;
gid_t gid;
+ char *endptr;
switch (domain->type) {
case DOM_TYPE_POSIX:
- gid = strtouint32(key, NULL, 10);
- ret = errno;
- if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Invalid UID value\n");
+ gid = strtouint32(key, &endptr, 10);
+ if ((errno != 0) || *endptr || (key == endptr)) {
+ ret = errno ? errno : EINVAL;
+ DEBUG(SSSDBG_CRIT_FAILURE, "Invalid GID value\n");
return ret;
}
diff --git a/src/responder/ifp/ifp_users.c b/src/responder/ifp/ifp_users.c
index ac9330858f0247ce0236d029b5d8678921c9061b..714f7ef78d4e3215b5dd80becaecb063caed860c 100644
--- a/src/responder/ifp/ifp_users.c
+++ b/src/responder/ifp/ifp_users.c
@@ -1038,12 +1038,13 @@ ifp_users_get_from_cache(TALLOC_CTX *mem_ctx,
struct ldb_result *user_res = NULL;
errno_t ret;
uid_t uid;
+ char *endptr;
switch (domain->type) {
case DOM_TYPE_POSIX:
- uid = strtouint32(key, NULL, 10);
- ret = errno;
- if (ret != EOK) {
+ uid = strtouint32(key, &endptr, 10);
+ if ((errno != 0) || *endptr || (key == endptr)) {
+ ret = errno ? errno : EINVAL;
DEBUG(SSSDBG_CRIT_FAILURE, "Invalid UID value\n");
goto done;
}
diff --git a/src/responder/ifp/ifpsrv.c b/src/responder/ifp/ifpsrv.c
index 6de2e00a0194a3d62807a7754d6b7a55ae491acf..d27c2dfccde04401501fa4b37f22a3c96e6f6578 100644
--- a/src/responder/ifp/ifpsrv.c
+++ b/src/responder/ifp/ifpsrv.c
@@ -166,6 +166,7 @@ int ifp_process_init(TALLOC_CTX *mem_ctx,
char *uid_str;
char *attr_list_str;
char *wildcard_limit_str;
+ char *endptr;
ifp_cmds = get_ifp_cmds();
ret = sss_process_init(mem_ctx, ev, cdb,
@@ -245,9 +246,9 @@ int ifp_process_init(TALLOC_CTX *mem_ctx,
}
if (wildcard_limit_str) {
- ifp_ctx->wildcard_limit = strtouint32(wildcard_limit_str, NULL, 10);
- ret = errno;
- if (ret != EOK) {
+ ifp_ctx->wildcard_limit = strtouint32(wildcard_limit_str, &endptr, 10);
+ if ((errno != 0) || *endptr || (wildcard_limit_str == endptr)) {
+ ret = errno ? errno : EINVAL;
goto fail;
}
}
diff --git a/src/tools/common/sss_colondb.c b/src/tools/common/sss_colondb.c
index e8aeb315c9ed0efde15553e2d741d04c5d895b1a..41e6c3a51d0ff84ca9322d443eeccad1aa764ac0 100644
--- a/src/tools/common/sss_colondb.c
+++ b/src/tools/common/sss_colondb.c
@@ -78,6 +78,7 @@ static char *read_field_as_uint32(char *line,
const char *str;
char *rest;
errno_t ret;
+ char *endptr;
rest = read_field_as_string(line, &str);
if (str == NULL) {
@@ -85,9 +86,9 @@ static char *read_field_as_uint32(char *line,
return rest;
}
- *_value = strtouint32(str, NULL, 10);
- if (errno != 0) {
- ret = errno;
+ *_value = strtouint32(str, &endptr, 10);
+ if ((errno != 0) || *endptr || (str == endptr)) {
+ ret = errno ? errno : EINVAL;
DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse number [%d]: %s\n",
ret, sss_strerror(ret));
diff --git a/src/util/usertools.c b/src/util/usertools.c
index 1fbde2eb43b1cc4c6dead346a1dafc632a6ec78b..370a98b41740bb5494a10f93752daa40c6e445ff 100644
--- a/src/util/usertools.c
+++ b/src/util/usertools.c
@@ -578,9 +578,8 @@ errno_t sss_user_by_name_or_uid(const char *input, uid_t *_uid, gid_t *_gid)
struct passwd *pwd;
/* Try if it's an ID first */
- errno = 0;
uid = strtouint32(input, &endptr, 10);
- if (errno != 0 || *endptr != '\0') {
+ if ((errno != 0) || (*endptr != '\0') || (input == endptr)) {
ret = errno;
if (ret == ERANGE) {
DEBUG(SSSDBG_OP_FAILURE,
diff --git a/src/util/well_known_sids.c b/src/util/well_known_sids.c
index 1f9a7beea8086c6aa34a132e4df85edbf37aca55..0b51667a2a62702105c44ab2ba7594c7dbb18c91 100644
--- a/src/util/well_known_sids.c
+++ b/src/util/well_known_sids.c
@@ -189,7 +189,6 @@ static errno_t handle_rid_to_name_map(const char *sid, size_t prefix_len,
char *endptr;
size_t c;
- errno = 0;
rid = (uint32_t) strtouint32(sid + prefix_len, &endptr, 10);
if (errno != 0 || *endptr != '\0') {
return EINVAL;
--
2.31.1

View File

@ -0,0 +1,200 @@
From 3c17a57e7cb30263b73e7b9456b896503be6bd45 Mon Sep 17 00:00:00 2001
From: Alexey Tikhonov <atikhono@redhat.com>
Date: Fri, 15 Oct 2021 22:29:12 +0200
Subject: [PATCH 11/17] 'strto*()': usage sanitization
To properly check for an error during string to number conversion
one needs to:
- check `errno`
- check that something was really converted (i.e. start != end)
- (if this is expected) check that entire string was consumed
Some of those error conditions weren't checked in various locations
over the code.
Reviewed-by: Pawel Polawski <ppolawsk@redhat.com>
---
src/confdb/confdb.c | 16 ++++++++++++----
src/providers/ldap/sdap.c | 6 ++++--
src/providers/ldap/sdap_async_enum.c | 7 ++++---
src/providers/ldap/sdap_async_iphost.c | 4 ++--
src/providers/ldap/sdap_async_ipnetwork.c | 4 ++--
src/providers/ldap/sdap_async_services.c | 4 ++--
src/util/crypto/libcrypto/crypto_sha512crypt.c | 3 ++-
7 files changed, 28 insertions(+), 16 deletions(-)
diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c
index 80203c0f640975471df31c522ca91f94099cbcf9..6a6fac916e5f45b64c7402da3f35bb46e2bf4906 100644
--- a/src/confdb/confdb.c
+++ b/src/confdb/confdb.c
@@ -439,6 +439,7 @@ int confdb_get_int(struct confdb_ctx *cdb,
char **values = NULL;
long val;
int ret;
+ char *endptr;
TALLOC_CTX *tmp_ctx;
tmp_ctx = talloc_new(NULL);
@@ -460,12 +461,15 @@ int confdb_get_int(struct confdb_ctx *cdb,
}
errno = 0;
- val = strtol(values[0], NULL, 0);
+ val = strtol(values[0], &endptr, 0);
ret = errno;
if (ret != 0) {
goto failed;
}
-
+ if (*endptr || (values[0] == endptr)) {
+ ret = EINVAL;
+ goto failed;
+ }
if (val < INT_MIN || val > INT_MAX) {
ret = ERANGE;
goto failed;
@@ -495,6 +499,7 @@ long confdb_get_long(struct confdb_ctx *cdb,
char **values = NULL;
long val;
int ret;
+ char *endptr;
TALLOC_CTX *tmp_ctx;
tmp_ctx = talloc_new(NULL);
@@ -516,12 +521,15 @@ long confdb_get_long(struct confdb_ctx *cdb,
}
errno = 0;
- val = strtol(values[0], NULL, 0);
+ val = strtol(values[0], &endptr, 0);
ret = errno;
if (ret != 0) {
goto failed;
}
-
+ if (*endptr || (values[0] == endptr)) {
+ ret = EINVAL;
+ goto failed;
+ }
} else {
val = defval;
}
diff --git a/src/providers/ldap/sdap.c b/src/providers/ldap/sdap.c
index 32c0144b929b702a2a3ba70b6f477d80a59eb083..72d6a7281291581341f9df878729a38ff3da04fa 100644
--- a/src/providers/ldap/sdap.c
+++ b/src/providers/ldap/sdap.c
@@ -1418,8 +1418,9 @@ int sdap_get_server_opts_from_rootdse(TALLOC_CTX *memctx,
opts->gen_map[SDAP_AT_ENTRY_USN].opt_name);
} else {
so->supports_usn = true;
+ errno = 0;
so->last_usn = strtoul(last_usn_value, &endptr, 10);
- if (endptr != NULL && (*endptr != '\0' || endptr == last_usn_value)) {
+ if (errno || !endptr || *endptr || (endptr == last_usn_value)) {
DEBUG(SSSDBG_MINOR_FAILURE,
"USN is not valid (value: %s)\n", last_usn_value);
so->last_usn = 0;
@@ -1442,8 +1443,9 @@ int sdap_get_server_opts_from_rootdse(TALLOC_CTX *memctx,
opts->gen_map[SDAP_AT_ENTRY_USN].name =
talloc_strdup(opts->gen_map, usn_attrs[i].entry_name);
so->supports_usn = true;
+ errno = 0;
so->last_usn = strtoul(last_usn_value, &endptr, 10);
- if (endptr != NULL && (*endptr != '\0' || endptr == last_usn_value)) {
+ if (errno || !endptr || *endptr || (endptr == last_usn_value)) {
DEBUG(SSSDBG_MINOR_FAILURE,
"USN is not valid (value: %s)\n", last_usn_value);
so->last_usn = 0;
diff --git a/src/providers/ldap/sdap_async_enum.c b/src/providers/ldap/sdap_async_enum.c
index 2a12e59b749ded0c486b16fc5af58ef968dbfb2c..44cec84adb7b078696ed8744e050b738c0963eea 100644
--- a/src/providers/ldap/sdap_async_enum.c
+++ b/src/providers/ldap/sdap_async_enum.c
@@ -571,9 +571,9 @@ static void enum_users_done(struct tevent_req *subreq)
talloc_zfree(state->ctx->srv_opts->max_user_value);
state->ctx->srv_opts->max_user_value =
talloc_steal(state->ctx, usn_value);
-
+ errno = 0;
usn_number = strtoul(usn_value, &endptr, 10);
- if ((endptr == NULL || (*endptr == '\0' && endptr != usn_value))
+ if (!errno && endptr && (*endptr == '\0') && (endptr != usn_value)
&& (usn_number > state->ctx->srv_opts->last_usn)) {
state->ctx->srv_opts->last_usn = usn_number;
}
@@ -751,8 +751,9 @@ static void enum_groups_done(struct tevent_req *subreq)
talloc_zfree(state->ctx->srv_opts->max_group_value);
state->ctx->srv_opts->max_group_value =
talloc_steal(state->ctx, usn_value);
+ errno = 0;
usn_number = strtoul(usn_value, &endptr, 10);
- if ((endptr == NULL || (*endptr == '\0' && endptr != usn_value))
+ if (!errno && endptr && (*endptr == '\0') && (endptr != usn_value)
&& (usn_number > state->ctx->srv_opts->last_usn)) {
state->ctx->srv_opts->last_usn = usn_number;
}
diff --git a/src/providers/ldap/sdap_async_iphost.c b/src/providers/ldap/sdap_async_iphost.c
index e798a32c26ef97c3081d8a33ac9ab74b1b7d0f5d..33b8e21672c81714bfce612a5726e153baba0fd7 100644
--- a/src/providers/ldap/sdap_async_iphost.c
+++ b/src/providers/ldap/sdap_async_iphost.c
@@ -618,9 +618,9 @@ enum_iphosts_op_done(struct tevent_req *subreq)
talloc_zfree(state->id_ctx->srv_opts->max_iphost_value);
state->id_ctx->srv_opts->max_iphost_value =
talloc_steal(state->id_ctx, usn_value);
-
+ errno = 0;
usn_number = strtoul(usn_value, &endptr, 10);
- if ((endptr == NULL || (*endptr == '\0' && endptr != usn_value))
+ if (!errno && endptr && (*endptr == '\0') && (endptr != usn_value)
&& (usn_number > state->id_ctx->srv_opts->last_usn)) {
state->id_ctx->srv_opts->last_usn = usn_number;
}
diff --git a/src/providers/ldap/sdap_async_ipnetwork.c b/src/providers/ldap/sdap_async_ipnetwork.c
index e34bf58d4a8eb2610f76fd3f6543b5f59538286a..e057566c1609a9277a66992ed5270cf4556f2ef7 100644
--- a/src/providers/ldap/sdap_async_ipnetwork.c
+++ b/src/providers/ldap/sdap_async_ipnetwork.c
@@ -603,9 +603,9 @@ enum_ipnetworks_op_done(struct tevent_req *subreq)
talloc_zfree(state->id_ctx->srv_opts->max_ipnetwork_value);
state->id_ctx->srv_opts->max_ipnetwork_value =
talloc_steal(state->id_ctx, usn_value);
-
+ errno = 0;
usn_number = strtoul(usn_value, &endptr, 10);
- if ((endptr == NULL || (*endptr == '\0' && endptr != usn_value))
+ if (!errno && endptr && (*endptr == '\0') && (endptr != usn_value)
&& (usn_number > state->id_ctx->srv_opts->last_usn)) {
state->id_ctx->srv_opts->last_usn = usn_number;
}
diff --git a/src/providers/ldap/sdap_async_services.c b/src/providers/ldap/sdap_async_services.c
index eebe23913399bd0c3c451f4009d7ddb3a172838d..cccc4f94c29e83aed767d2afecf80df94d1c2f69 100644
--- a/src/providers/ldap/sdap_async_services.c
+++ b/src/providers/ldap/sdap_async_services.c
@@ -623,9 +623,9 @@ enum_services_op_done(struct tevent_req *subreq)
talloc_zfree(state->id_ctx->srv_opts->max_service_value);
state->id_ctx->srv_opts->max_service_value =
talloc_steal(state->id_ctx, usn_value);
-
+ errno = 0;
usn_number = strtoul(usn_value, &endptr, 10);
- if ((endptr == NULL || (*endptr == '\0' && endptr != usn_value))
+ if (!errno && endptr && (*endptr == '\0') && (endptr != usn_value)
&& (usn_number > state->id_ctx->srv_opts->last_usn)) {
state->id_ctx->srv_opts->last_usn = usn_number;
}
diff --git a/src/util/crypto/libcrypto/crypto_sha512crypt.c b/src/util/crypto/libcrypto/crypto_sha512crypt.c
index 1e57b04d131b9224fc0ef7947095cfa21e0d4f31..c816d26f184bda62811723c36ba4a009f6473e21 100644
--- a/src/util/crypto/libcrypto/crypto_sha512crypt.c
+++ b/src/util/crypto/libcrypto/crypto_sha512crypt.c
@@ -101,8 +101,9 @@ static int sha512_crypt_r(const char *key,
char *endp;
num = salt + ROUNDS_SIZE;
+ errno = 0;
srounds = strtoul(num, &endp, 10);
- if (*endp == '$') {
+ if (!errno && (*endp == '$')) {
salt = endp + 1;
if (srounds < ROUNDS_MIN) srounds = ROUNDS_MIN;
if (srounds > ROUNDS_MAX) srounds = ROUNDS_MAX;
--
2.31.1

View File

@ -0,0 +1,32 @@
From 86413e5f01339ce54bcece2d1d8b1b88d8823c1e Mon Sep 17 00:00:00 2001
From: Alexey Tikhonov <atikhono@redhat.com>
Date: Tue, 26 Oct 2021 16:02:43 +0200
Subject: [PATCH 14/17] SUDO: decrease log level in case object wasn't found
It is expected sudo responder can be requested to lookup unknown entry.
One of typical examples is lookup for a local user.
Resolves: https://github.com/SSSD/sssd/issues/5839
Reviewed-by: Pawel Polawski <ppolawsk@redhat.com>
---
src/responder/sudo/sudosrv_cmd.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/responder/sudo/sudosrv_cmd.c b/src/responder/sudo/sudosrv_cmd.c
index 3bed22b6fc8b476686269d68e49def6a5af9383b..63b548fe8d5c76aa2fb6eec7f1b174fa7f47f90b 100644
--- a/src/responder/sudo/sudosrv_cmd.c
+++ b/src/responder/sudo/sudosrv_cmd.c
@@ -261,7 +261,8 @@ static void sudosrv_cmd_done(struct tevent_req *req)
&cmd_ctx->num_rules);
talloc_zfree(req);
if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to obtain cached rules [%d]: %s\n",
+ DEBUG((ret == ENOENT) ? SSSDBG_MINOR_FAILURE : SSSDBG_OP_FAILURE,
+ "Unable to obtain cached rules [%d]: %s\n",
ret, sss_strerror(ret));
goto done;
}
--
2.31.1

View File

@ -0,0 +1,67 @@
From 7cba8ed6ae965ffcae9c14269cde02ddc24eaa53 Mon Sep 17 00:00:00 2001
From: Alexey Tikhonov <atikhono@redhat.com>
Date: Tue, 26 Oct 2021 22:16:49 +0200
Subject: [PATCH 16/17] KCM: delete malformed 'cn=default' entries
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This is needed to cleanup outdated entries in old (encrypted)
format that are no longer supported.
Steps to reproduce:
With an old SSSD version that still writes encrypted content in secrets db:
- obtain any ticket (even one ticket is enough)
- `kswitch -c ...` to any cache (any successful execution of `kswitch`
will use `SET_DEFAULT_CACHE` KCM op and create
'cn=default,cn=$uid,cn=persistent,cn=kcm' entry)
Then update SSSD and try `klist`:
- 2.6.0 version will fail with "[ccdb_secdb_get_default_send] (0x0040): Unexpected UUID size ..."
- 2.6.0 + this patch will remove this entry:
```
[ccdb_secdb_get_default_send] (0x0040): Unexpected UUID size 152, deleting this entry
[sss_sec_delete] (0x0400): Removing a secret from [persistent/1000/default]
```
and continue as if default isn't set (since all encrypted entries will be purged,
cache will appear empty)
Reviewed-by: Pavel Březina <pbrezina@redhat.com>
Reviewed-by: Pawel Polawski <ppolawsk@redhat.com>
---
src/responder/kcm/kcmsrv_ccache_secdb.c | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/src/responder/kcm/kcmsrv_ccache_secdb.c b/src/responder/kcm/kcmsrv_ccache_secdb.c
index 05146b1553ad514934f709959036c5335f8c7adc..875eb3c900e5d894591810ff117d1601910e030f 100644
--- a/src/responder/kcm/kcmsrv_ccache_secdb.c
+++ b/src/responder/kcm/kcmsrv_ccache_secdb.c
@@ -764,8 +764,22 @@ static struct tevent_req *ccdb_secdb_get_default_send(TALLOC_CTX *mem_ctx,
uuid_size = sss_iobuf_get_size(dfl_iobuf);
if (uuid_size != UUID_STR_SIZE) {
- DEBUG(SSSDBG_OP_FAILURE, "Unexpected UUID size %zu\n", uuid_size);
- ret = EIO;
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Unexpected UUID size %zu, deleting this entry\n", uuid_size);
+ ret = sss_sec_delete(sreq);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to delete entry: [%d]: %s, "
+ "consider manual removal of "SECRETS_DB_PATH"/secrets.ldb\n",
+ ret, sss_strerror(ret));
+ sss_log(SSS_LOG_CRIT,
+ "Can't delete an entry from "SECRETS_DB_PATH"/secrets.ldb, "
+ "content seems to be corrupted. Consider file removal. "
+ "(Take a note, this will delete all credentials managed "
+ "via sssd_kcm)");
+ }
+ uuid_clear(state->uuid);
+ ret = EOK;
goto immediate;
}
--
2.31.1

View File

@ -0,0 +1,231 @@
From 301659a662a7a7aac11096fd0409f83b45cb41d1 Mon Sep 17 00:00:00 2001
From: Iker Pedrosa <ipedrosa@redhat.com>
Date: Tue, 14 Sep 2021 12:35:09 +0200
Subject: [PATCH 17/17] proxy: allow removing group members
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The proxy provider doesn't allow to remove group members once they have
been added. This patch allows to do it by looping the member list from
the cache and comparing it with the actual membership list. If a member
is missing then it's removed from the cache.
Resolves: https://github.com/SSSD/sssd/issues/5783
Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
Reviewed-by: Alexey Tikhonov <atikhono@redhat.com>
Reviewed-by: Pavel Březina <pbrezina@redhat.com>
---
src/providers/proxy/proxy_id.c | 159 ++++++++++++++++++++++++++++++++-
1 file changed, 157 insertions(+), 2 deletions(-)
diff --git a/src/providers/proxy/proxy_id.c b/src/providers/proxy/proxy_id.c
index 25daea585dfc0df2b568ee3175765a6d64be334b..db6bbb2f0f0a02b31aafd63480613ab82b9d6792 100644
--- a/src/providers/proxy/proxy_id.c
+++ b/src/providers/proxy/proxy_id.c
@@ -908,6 +908,10 @@ handle_getgr_result(enum nss_status status, struct group *grp,
struct sss_domain_info *dom,
bool *delete_group)
{
+ if (delete_group) {
+ *delete_group = false;
+ }
+
switch (status) {
case NSS_STATUS_TRYAGAIN:
DEBUG(SSSDBG_MINOR_FAILURE, "Buffer too small\n");
@@ -915,7 +919,9 @@ handle_getgr_result(enum nss_status status, struct group *grp,
case NSS_STATUS_NOTFOUND:
DEBUG(SSSDBG_MINOR_FAILURE, "Group not found.\n");
- *delete_group = true;
+ if (delete_group) {
+ *delete_group = true;
+ }
break;
case NSS_STATUS_SUCCESS:
@@ -927,7 +933,9 @@ handle_getgr_result(enum nss_status status, struct group *grp,
if (OUT_OF_ID_RANGE(grp->gr_gid, dom->id_min, dom->id_max)) {
DEBUG(SSSDBG_MINOR_FAILURE,
"Group filtered out! (id out of range)\n");
- *delete_group = true;
+ if (delete_group) {
+ *delete_group = true;
+ }
break;
}
break;
@@ -1488,6 +1496,141 @@ fail:
return ret;
}
+static int remove_group_members(struct proxy_id_ctx *ctx,
+ struct sss_domain_info *dom,
+ const struct passwd *pwd,
+ long int num_gids,
+ const gid_t *gids,
+ long int num_cached_gids,
+ const gid_t *cached_gids)
+{
+ TALLOC_CTX *tmp_ctx = NULL;
+ int i = 0, j = 0;
+ int ret = EOK;
+ const char *groupname = NULL;
+ const char *username = NULL;
+ bool group_found = false;
+ struct ldb_result *res = NULL;
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
+ return ENOMEM;
+ }
+
+ username = sss_create_internal_fqname(tmp_ctx, pwd->pw_name, dom->name);
+ if (username == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "Failed to create fqdn '%s'\n", pwd->pw_name);
+ ret = ENOMEM;
+ goto done;
+ }
+
+ for (i = 0; i < num_cached_gids; i++) {
+ group_found = false;
+ /* group 0 is the primary group so it can be skipped */
+ for (j = 1; j < num_gids; j++) {
+ if (cached_gids[i] == gids[j]) {
+ group_found = true;
+ break;
+ }
+ }
+
+ if (!group_found) {
+ ret = sysdb_getgrgid(tmp_ctx, dom, cached_gids[i], &res);
+ if (ret != EOK || res->count != 1) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "sysdb_getgrgid failed for GID [%d].\n", cached_gids[i]);
+ continue;
+ }
+
+ groupname = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_NAME, NULL);
+ if (groupname == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Attribute is missing but this should never happen!\n");
+ continue;
+ }
+
+ ret = sysdb_remove_group_member(dom, groupname,
+ username,
+ SYSDB_MEMBER_USER, false);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Could not remove member [%s] from group [%s]\n",
+ username, groupname);
+ continue;
+ }
+ }
+ }
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+static int get_cached_user_groups(struct sysdb_ctx *sysdb,
+ struct sss_domain_info *dom,
+ const struct passwd *pwd,
+ unsigned int *_num_cached_gids,
+ gid_t **_cached_gids)
+{
+ TALLOC_CTX *tmp_ctx = NULL;
+ int ret = EOK;
+ int i = 0, j = 0;
+ gid_t gid = 0;
+ gid_t *cached_gids = NULL;
+ const char *username = NULL;
+ struct ldb_result *res = NULL;
+
+ if (_num_cached_gids == NULL || _cached_gids == NULL) {
+ return EINVAL;
+ }
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) {
+ ret = ENOMEM;
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
+ goto done;
+ }
+
+ username = sss_create_internal_fqname(tmp_ctx, pwd->pw_name, dom->name);
+ if (username == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "Failed to create fqdn '%s'\n", pwd->pw_name);
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = sysdb_initgroups(tmp_ctx, dom, username, &res);
+ /* the first element is the user itself so it can be skipped */
+ if (ret == EOK && res->count > 1) {
+ cached_gids = talloc_array(tmp_ctx, gid_t, res->count - 1);
+
+ for (i = 1; i < res->count; i++) {
+ gid = ldb_msg_find_attr_as_uint(res->msgs[i], SYSDB_GIDNUM, 0);
+ if (gid != 0) {
+ cached_gids[j] = gid;
+ j++;
+ }
+ }
+
+ *_num_cached_gids = j;
+ *_cached_gids = talloc_steal(sysdb, cached_gids);
+ } else if (ret == EOK) {
+ *_num_cached_gids = 0;
+ *_cached_gids = NULL;
+ } else {
+ goto done;
+ }
+
+ ret = EOK;
+
+done:
+ talloc_zfree(tmp_ctx);
+
+ return ret;
+}
+
static int get_initgr_groups_process(TALLOC_CTX *memctx,
struct proxy_id_ctx *ctx,
struct sysdb_ctx *sysdb,
@@ -1503,6 +1646,8 @@ static int get_initgr_groups_process(TALLOC_CTX *memctx,
int ret;
int i;
time_t now;
+ gid_t *cached_gids = NULL;
+ unsigned int num_cached_gids = 0;
num_gids = 0;
limit = 4096;
@@ -1553,6 +1698,16 @@ static int get_initgr_groups_process(TALLOC_CTX *memctx,
DEBUG(SSSDBG_CONF_SETTINGS, "User [%s] appears to be member of %lu "
"groups\n", pwd->pw_name, num_gids);
+ ret = get_cached_user_groups(sysdb, dom, pwd, &num_cached_gids, &cached_gids);
+ if (ret) {
+ return ret;
+ }
+ ret = remove_group_members(ctx, dom, pwd, num_gids, gids, num_cached_gids, cached_gids);
+ talloc_free(cached_gids);
+ if (ret) {
+ return ret;
+ }
+
now = time(NULL);
for (i = 0; i < num_gids; i++) {
ret = get_gr_gid(memctx, ctx, sysdb, dom, gids[i], now);
--
2.31.1

View File

@ -0,0 +1,30 @@
From a664e9ce08ca6c0f9eb2e260b25463eea9c7829b Mon Sep 17 00:00:00 2001
From: Alexey Tikhonov <atikhono@redhat.com>
Date: Fri, 15 Oct 2021 22:30:21 +0200
Subject: [PATCH] TESTS: fixed a bug in define->string conversion
Previously result of `AS_STR(OFFLINE_TIMEOUT)` was "OFFLINE_TIMEOUT"
instead of expected integer value.
Reviewed-by: Pawel Polawski <ppolawsk@redhat.com>
---
src/tests/cmocka/test_data_provider_be.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/tests/cmocka/test_data_provider_be.c b/src/tests/cmocka/test_data_provider_be.c
index a6d6ec8802dd0c592c22bec08ac8c6eb154a58e6..49f04ddfb043909559bb8724995c2c8c35e1aac6 100644
--- a/src/tests/cmocka/test_data_provider_be.c
+++ b/src/tests/cmocka/test_data_provider_be.c
@@ -32,7 +32,8 @@
#define TEST_ID_PROVIDER "ldap"
#define OFFLINE_TIMEOUT 2
-#define AS_STR(param) (#param)
+#define STR_HELPER(x) #x
+#define AS_STR(param) STR_HELPER(param)
static TALLOC_CTX *global_mock_context = NULL;
static bool global_timer_added;
--
2.31.1

View File

@ -37,7 +37,7 @@
Name: sssd Name: sssd
Version: 2.6.0 Version: 2.6.0
Release: 1%{?dist} Release: 2%{?dist}
Summary: System Security Services Daemon Summary: System Security Services Daemon
License: GPLv3+ License: GPLv3+
URL: https://github.com/SSSD/sssd/ URL: https://github.com/SSSD/sssd/
@ -45,6 +45,21 @@ Source0: https://github.com/SSSD/sssd/releases/download/2.6.0/sssd-2.6.0.tar.gz
### Patches ### ### Patches ###
Patch0001: 0001-DEBUG-fix-missing-va_end.patch
Patch0002: 0002-CONFDB-Change-ownership-of-config.ldb.patch
Patch0003: 0003-CONFDB-Change-ownership-before-dropping-privileges.patch
Patch0004: 0004-GPO-fixed-compilation-warning.patch
Patch0005: 0005-KCM-fixed-uninitialized-value.patch
Patch0006: 0006-cache_req-return-success-for-autofs-when-ENOENT-is-r.patch
Patch0007: 0007-sbus-maintain-correct-refcount-before-sending-a-repl.patch
Patch0008: 0008-Removed-excessive-includes-around-strtonum.patch
Patch0009: 0009-strtonum-helpers-usage-sanitization.patch
Patch0010: 0010-strto-usage-sanitization.patch
Patch0011: 0011-SUDO-decrease-log-level-in-case-object-wasn-t-found.patch
Patch0012: 0012-KCM-delete-malformed-cn-default-entries.patch
Patch0013: 0013-proxy-allow-removing-group-members.patch
Patch0014: 0014-TESTS-fixed-a-bug-in-define-string-conversion.patch
### Dependencies ### ### Dependencies ###
Requires: sssd-ad = %{version}-%{release} Requires: sssd-ad = %{version}-%{release}
@ -124,6 +139,7 @@ BuildRequires: samba-devel
# required for idmap_sss.so # required for idmap_sss.so
BuildRequires: samba-winbind BuildRequires: samba-winbind
BuildRequires: selinux-policy-targeted BuildRequires: selinux-policy-targeted
BuildRequires: shadow-utils-subid-devel
# required for p11_child smartcard tests # required for p11_child smartcard tests
BuildRequires: softhsm >= 2.1.0 BuildRequires: softhsm >= 2.1.0
BuildRequires: systemd-devel BuildRequires: systemd-devel
@ -514,6 +530,7 @@ autoreconf -ivf
--with-sssd-user=%{sssd_user} \ --with-sssd-user=%{sssd_user} \
--with-syslog=journald \ --with-syslog=journald \
--with-test-dir=/dev/shm \ --with-test-dir=/dev/shm \
--with-subid \
%if 0%{?fedora} %if 0%{?fedora}
--disable-polkit-rules-path \ --disable-polkit-rules-path \
%endif %endif
@ -820,6 +837,7 @@ done
%files client -f sssd_client.lang %files client -f sssd_client.lang
%license src/sss_client/COPYING src/sss_client/COPYING.LESSER %license src/sss_client/COPYING src/sss_client/COPYING.LESSER
%{_libdir}/libnss_sss.so.2 %{_libdir}/libnss_sss.so.2
%{_libdir}/libsubid_sss.so
%{_libdir}/security/pam_sss.so %{_libdir}/security/pam_sss.so
%{_libdir}/security/pam_sss_gss.so %{_libdir}/security/pam_sss_gss.so
%{_libdir}/krb5/plugins/libkrb5/sssd_krb5_locator_plugin.so %{_libdir}/krb5/plugins/libkrb5/sssd_krb5_locator_plugin.so
@ -1012,6 +1030,11 @@ fi
%systemd_postun_with_restart sssd.service %systemd_postun_with_restart sssd.service
%changelog %changelog
* Mon Nov 01 2021 Pavel Březina <pbrezina@redhat.com> - 2.6.0-2
- Add additional patches on top of 2.6.0
- Fix KCM upgrade from older releases
- Enable subid ranges
* Thu Oct 14 2021 Pavel Březina <pbrezina@redhat.com> - 2.6.0-1 * Thu Oct 14 2021 Pavel Březina <pbrezina@redhat.com> - 2.6.0-1
- Rebase to SSSD 2.6.0 - Rebase to SSSD 2.6.0