URL: https://github.com/SSSD/sssd/pull/5867 Author: ikerexxe Title: #5867: usertools: force local user for sssd process user Action: synchronized
To pull the PR as Git branch: git remote add ghsssd https://github.com/SSSD/sssd git fetch ghsssd pull/5867/head:pr5867 git checkout pr5867
From bf6b2409da7857f079cf0a9250df10f1bc71ed23 Mon Sep 17 00:00:00 2001 From: Iker Pedrosa <ipedr...@redhat.com> Date: Mon, 23 Aug 2021 12:04:42 +0200 Subject: [PATCH 1/2] usertools: force local user for sssd process user System hardening by forcing the sssd user to be loaded from a local database (/etc/passwd) instead of using any remote user. This could happen in very special conditions and might change the owner of the sssd databases and generate a denial of service. Signed-off-by: Iker Pedrosa <ipedr...@redhat.com> --- Makefile.am | 3 + src/tests/cwrap/Makefile.am | 8 +- src/tests/cwrap/common_mock_nss_dl_load.c | 115 ++++++++++++++++++++++ src/tests/cwrap/common_mock_nss_dl_load.h | 30 ++++++ src/tests/cwrap/test_responder_common.c | 7 ++ src/tests/cwrap/test_usertools.c | 6 ++ src/util/usertools.c | 28 ++++-- src/util/usertools_extra.c | 50 ++++++++++ src/util/util.h | 3 + 9 files changed, 241 insertions(+), 9 deletions(-) create mode 100644 src/tests/cwrap/common_mock_nss_dl_load.c create mode 100644 src/tests/cwrap/common_mock_nss_dl_load.h create mode 100644 src/util/usertools_extra.c diff --git a/Makefile.am b/Makefile.am index f6bc9414d0..301f6b5800 100644 --- a/Makefile.am +++ b/Makefile.am @@ -884,6 +884,7 @@ dist_noinst_HEADERS = \ src/tests/cmocka/test_expire_common.h \ src/tests/cmocka/test_sdap_access.h \ src/tests/cmocka/data_provider/mock_dp.h \ + src/tests/cwrap/common_mock_nss_dl_load.h \ src/sss_client/pam_message.h \ src/sss_client/ssh/sss_ssh_client.h \ src/sss_client/sudo/sss_sudo.h \ @@ -1237,6 +1238,7 @@ libsss_util_la_SOURCES = \ src/util/server.c \ src/util/signal.c \ src/util/usertools.c \ + src/util/usertools_extra.c \ src/util/backup_file.c \ src/util/strtonum.c \ src/util/check_and_open.c \ @@ -1265,6 +1267,7 @@ libsss_util_la_SOURCES = \ src/util/selinux.c \ src/util/sss_regexp.c \ src/util/sss_chain_id.c \ + src/util/nss_dl_load.c \ $(NULL) libsss_util_la_CFLAGS = \ $(AM_CFLAGS) \ diff --git a/src/tests/cwrap/Makefile.am b/src/tests/cwrap/Makefile.am index 6d3dc45e57..24e6c4a7c1 100644 --- a/src/tests/cwrap/Makefile.am +++ b/src/tests/cwrap/Makefile.am @@ -141,15 +141,18 @@ endif usertools_tests_SOURCES = \ test_usertools.c \ + common_mock_nss_dl_load.c \ + ../../../src/util/usertools.c \ + ../../../src/util/nss_dl_load.c \ $(NULL) usertools_tests_CFLAGS = \ $(AM_CFLAGS) \ $(NULL) usertools_tests_LDADD = \ + $(LIBADD_DL) \ $(CMOCKA_LIBS) \ $(POPT_LIBS) \ $(TALLOC_LIBS) \ - $(abs_top_builddir)/libsss_util.la \ $(abs_top_builddir)/libsss_debug.la \ $(abs_top_builddir)/libsss_test_common.la \ $(NULL) @@ -159,9 +162,11 @@ endif responder_common_tests_SOURCES =\ test_responder_common.c \ + common_mock_nss_dl_load.c \ $(SSSD_RESPONDER_IFACE_OBJ) \ ../../../src/responder/common/negcache_files.c \ ../../../src/util/nss_dl_load.c \ + ../../../src/util/usertools.c \ ../../../src/responder/common/negcache.c \ ../../../src/responder/common/responder_common.c \ ../../../src/responder/common/responder_packet.c \ @@ -179,7 +184,6 @@ responder_common_tests_LDADD = \ $(SSSD_LIBS) \ $(SELINUX_LIBS) \ $(SYSTEMD_DAEMON_LIBS) \ - $(abs_top_builddir)/libsss_util.la \ $(abs_top_builddir)/libsss_debug.la \ $(abs_top_builddir)/libsss_test_common.la \ $(abs_top_builddir)/libsss_iface.la \ diff --git a/src/tests/cwrap/common_mock_nss_dl_load.c b/src/tests/cwrap/common_mock_nss_dl_load.c new file mode 100644 index 0000000000..ebe006b591 --- /dev/null +++ b/src/tests/cwrap/common_mock_nss_dl_load.c @@ -0,0 +1,115 @@ +/* + Authors: + Iker Pedrosa <ipedr...@redhat.com> + + Copyright (C) 2021 Red Hat + + SSSD tests: Fake nss dl load + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <dlfcn.h> + +#include "common_mock_nss_dl_load.h" + +#define LIB_PATH "libnss_wrapper.so" + + +static errno_t load_function(const char *fname, void **fptr) +{ + void *dl_handle = NULL; + errno_t ret; + + dl_handle = dlopen(LIB_PATH, RTLD_NOW); + if (dl_handle == NULL) { + DEBUG(SSSDBG_FATAL_FAILURE, "Unable to load %s module, " + "error: %s\n", LIB_PATH, dlerror()); + ret = ELIBACC; + goto done; + } + + *fptr = dlsym(dl_handle, fname); + if (*fptr == NULL) { + DEBUG(SSSDBG_FATAL_FAILURE, "Library '%s' did not provide " + "mandatory symbol '%s', error: %s.\n", + LIB_PATH, fname, dlerror()); + ret = ELIBBAD; + goto done; + } + + ret = EOK; + +done: + return ret; +} + +static enum nss_status +mock_getpwnam_r(const char *name, struct passwd *result, + char *buffer, size_t buflen, int *errnop) +{ + void *pwd_pointer = NULL; + int rc; + errno_t (*fptr)(const char *, struct passwd *, char *, + size_t, struct passwd **) = NULL; + + rc = load_function("getpwnam_r", (void *)&fptr); + if (rc) { + return NSS_STATUS_UNAVAIL; + } + + rc = (*fptr)(name, result, buffer, buflen, (struct passwd **)&pwd_pointer); + if (rc == 0 && pwd_pointer == result) { + return NSS_STATUS_SUCCESS; + } else if (rc == 0 && (pwd_pointer == result)) { + return NSS_STATUS_NOTFOUND; + } else { + return NSS_STATUS_UNAVAIL; + } +} + +static enum nss_status +mock_getpwuid_r(uid_t uid, struct passwd *result, + char *buffer, size_t buflen, int *errnop) +{ + void *pwd_pointer = NULL; + int rc; + errno_t (*fptr)(uid_t, struct passwd *, char *, + size_t, struct passwd **) = NULL; + + rc = load_function("getpwuid_r", (void *)&fptr); + if (rc) { + return NSS_STATUS_UNAVAIL; + } + + rc = (*fptr)(uid, result, buffer, buflen, (struct passwd **)&pwd_pointer); + if (rc == 0 && pwd_pointer == result) { + return NSS_STATUS_SUCCESS; + } else if (rc == 0 && (pwd_pointer == result)) { + return NSS_STATUS_NOTFOUND; + } else { + return NSS_STATUS_UNAVAIL; + } +} + +errno_t mock_sss_load_nss_pw_symbols(struct sss_nss_ops *ops) +{ + ops->getpwnam_r = mock_getpwnam_r; + ops->getpwuid_r = mock_getpwuid_r; + + return EOK; +} diff --git a/src/tests/cwrap/common_mock_nss_dl_load.h b/src/tests/cwrap/common_mock_nss_dl_load.h new file mode 100644 index 0000000000..fead14dbf3 --- /dev/null +++ b/src/tests/cwrap/common_mock_nss_dl_load.h @@ -0,0 +1,30 @@ +/* + Authors: + Iker Pedrosa <ipedr...@redhat.com> + + Copyright (C) 2021 Red Hat + + SSSD tests: Fake nss dl load + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef __COMMON_MOCK_NSS_DL_LOAD_H_ +#define __COMMON_MOCK_NSS_DL_LOAD_H_ + +#include "tests/cmocka/common_mock.h" + +errno_t mock_sss_load_nss_pw_symbols(struct sss_nss_ops *ops); + +#endif /* __COMMON_MOCK_NSS_DL_LOAD_H_ */ diff --git a/src/tests/cwrap/test_responder_common.c b/src/tests/cwrap/test_responder_common.c index 11cc3abd8d..571e95d36c 100644 --- a/src/tests/cwrap/test_responder_common.c +++ b/src/tests/cwrap/test_responder_common.c @@ -29,6 +29,13 @@ #include "util/util.h" #include "responder/common/responder.h" #include "tests/cmocka/common_mock.h" +#include "tests/cwrap/common_mock_nss_dl_load.h" + + +errno_t sss_load_nss_pw_symbols(struct sss_nss_ops *ops) +{ + return mock_sss_load_nss_pw_symbols(ops); +} /* Just to satisfy dependencies */ struct cli_protocol_version *register_cli_protocol_version(void) diff --git a/src/tests/cwrap/test_usertools.c b/src/tests/cwrap/test_usertools.c index f61ae83e20..eb30a540cb 100644 --- a/src/tests/cwrap/test_usertools.c +++ b/src/tests/cwrap/test_usertools.c @@ -27,6 +27,12 @@ #include <popt.h> #include "util/util.h" #include "tests/cmocka/common_mock.h" +#include "tests/cwrap/common_mock_nss_dl_load.h" + +errno_t sss_load_nss_pw_symbols(struct sss_nss_ops *ops) +{ + return mock_sss_load_nss_pw_symbols(ops); +} void test_get_user_num(void **state) { diff --git a/src/util/usertools.c b/src/util/usertools.c index 370a98b417..9786609a1a 100644 --- a/src/util/usertools.c +++ b/src/util/usertools.c @@ -33,6 +33,7 @@ #include "responder/common/responder.h" #define NAME_DOMAIN_PATTERN_OPTIONS (SSS_REGEXP_DUPNAMES | SSS_REGEXP_EXTENDED) +#define NSS_BUFFER_SIZE 16384 /* Function returns given realm name as new uppercase string */ char *get_uppercase_realm(TALLOC_CTX *memctx, const char *name) @@ -572,10 +573,23 @@ sss_fqname(char *str, size_t size, struct sss_names_ctx *nctx, errno_t sss_user_by_name_or_uid(const char *input, uid_t *_uid, gid_t *_gid) { + static struct sss_nss_ops nss_ops; uid_t uid; errno_t ret; char *endptr; - struct passwd *pwd; + struct passwd pwd = { 0 }; + int errnop = 0; + enum nss_status status; + char s_nss_buffer[NSS_BUFFER_SIZE]; + + if (!nss_ops.dl_handle) { + ret = sss_load_nss_pw_symbols(&nss_ops); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, "Unable to load NSS symbols [%d]: %s\n", + ret, sss_strerror(ret)); + return ret; + } + } /* Try if it's an ID first */ uid = strtouint32(input, &endptr, 10); @@ -587,13 +601,12 @@ errno_t sss_user_by_name_or_uid(const char *input, uid_t *_uid, gid_t *_gid) return ret; } - /* Nope, maybe a username? */ - pwd = getpwnam(input); + status = nss_ops.getpwnam_r(input, &pwd, s_nss_buffer, NSS_BUFFER_SIZE, &errnop); } else { - pwd = getpwuid(uid); + status = nss_ops.getpwuid_r(uid, &pwd, s_nss_buffer, NSS_BUFFER_SIZE, &errnop); } - if (pwd == NULL) { + if (status != NSS_STATUS_SUCCESS) { DEBUG(SSSDBG_OP_FAILURE, "[%s] is neither a valid UID nor a user name which could be " "resolved by getpwnam().\n", input); @@ -601,12 +614,13 @@ errno_t sss_user_by_name_or_uid(const char *input, uid_t *_uid, gid_t *_gid) } if (_uid) { - *_uid = pwd->pw_uid; + *_uid = pwd.pw_uid; } if (_gid) { - *_gid = pwd->pw_gid; + *_gid = pwd.pw_gid; } + return EOK; } diff --git a/src/util/usertools_extra.c b/src/util/usertools_extra.c new file mode 100644 index 0000000000..a7f93a11f1 --- /dev/null +++ b/src/util/usertools_extra.c @@ -0,0 +1,50 @@ +/* + SSSD + + usertools_extra.c + + Authors: + Sumit Bose <sb...@redhat.com> + Iker Pedrosa <ipedr...@redhat.com> + + Copyright (C) 2021 Red Hat + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <pwd.h> +#include <errno.h> +#include <talloc.h> +#include <grp.h> + +#include "db/sysdb.h" +#include "confdb/confdb.h" +#include "util/strtonum.h" +#include "util/util.h" +#include "util/safe-format-string.h" +#include "responder/common/responder.h" + +errno_t sss_load_nss_pw_symbols(struct sss_nss_ops *ops) +{ + errno_t ret; + struct sss_nss_symbols syms[] = { + {(void*)&ops->getpwnam_r, true, "getpwnam_r" }, + {(void*)&ops->getpwuid_r, true, "getpwuid_r" } + }; + size_t nsyms = sizeof(syms) / sizeof(struct sss_nss_symbols); + + ret = sss_load_nss_symbols(ops, "files", syms, nsyms); + + return ret; +} diff --git a/src/util/util.h b/src/util/util.h index 6dfd2540cc..ca1b0e1950 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -41,6 +41,7 @@ #include "shared/io.h" #include "shared/safealign.h" #include "util/atomic_io.h" +#include "util/nss_dl_load.h" #include "util/util_errors.h" #include "util/sss_format.h" #include "util/sss_regexp.h" @@ -324,6 +325,8 @@ int sss_output_fqname(TALLOC_CTX *mem_ctx, const char *sss_get_name_from_msg(struct sss_domain_info *domain, struct ldb_message *msg); +errno_t sss_load_nss_pw_symbols(struct sss_nss_ops *ops); + /* from backup-file.c */ int backup_file(const char *src, int dbglvl); From 9f9bcab9b79743bcf50650c4fea164fd5665156b Mon Sep 17 00:00:00 2001 From: Iker Pedrosa <ipedr...@redhat.com> Date: Wed, 1 Sep 2021 09:55:12 +0200 Subject: [PATCH 2/2] man: sssd.conf and sssd-ifp clarify user option user and allowed_uids options should be accessible via the files service of nsswitch.conf. Signed-off-by: Iker Pedrosa <ipedr...@redhat.com> --- src/man/sssd-ifp.5.xml | 5 +++++ src/man/sssd.conf.5.xml | 11 +++++++++++ 2 files changed, 16 insertions(+) diff --git a/src/man/sssd-ifp.5.xml b/src/man/sssd-ifp.5.xml index acb3e341eb..cc1a6c835d 100644 --- a/src/man/sssd-ifp.5.xml +++ b/src/man/sssd-ifp.5.xml @@ -55,6 +55,11 @@ responder. User names are resolved to UIDs at startup. </para> + <para> + The user should be a local one, i.e. accessible via + <quote>files</quote> service of + <filename>nsswitch.conf</filename>. + </para> <para> Default: 0 (only the root user is allowed to access the InfoPipe responder) diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml index 8ca267b253..297569d278 100644 --- a/src/man/sssd.conf.5.xml +++ b/src/man/sssd.conf.5.xml @@ -423,6 +423,12 @@ responder. </phrase> </para> + <para> + Both a user name and a uid can be used but the + user should be a local one, i.e. accessible via + <quote>files</quote> service of + <filename>nsswitch.conf</filename>. + </para> <para> Default: not set, process will run as root </para> @@ -2162,6 +2168,11 @@ pam_gssapi_indicators_map = sudo:pkinit, sudo-i:pkinit responder. User names are resolved to UIDs at startup. </para> + <para> + The user should be a local one, i.e. accessible via + <quote>files</quote> service of + <filename>nsswitch.conf</filename>. + </para> <para> Default: 0 (only the root user is allowed to access the PAC responder)
_______________________________________________ sssd-devel mailing list -- sssd-devel@lists.fedorahosted.org To unsubscribe send an email to sssd-devel-le...@lists.fedorahosted.org Fedora Code of Conduct: https://docs.fedoraproject.org/en-US/project/code-of-conduct/ List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines List Archives: https://lists.fedorahosted.org/archives/list/sssd-devel@lists.fedorahosted.org Do not reply to spam on the list, report it: https://pagure.io/fedora-infrastructure