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 7ab4e9d470018fabbceba7ad242e660e5a94a733 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 | 76 +++++++++++++++++++++++ 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/nss_dl_load.c | 13 +++- src/util/nss_dl_load.h | 3 + src/util/nss_dl_load_extra.c | 51 +++++++++++++++ src/util/usertools.c | 32 +++++++--- 10 files changed, 218 insertions(+), 11 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/nss_dl_load_extra.c diff --git a/Makefile.am b/Makefile.am index f6bc9414d0..ebd92afd55 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 \ @@ -1265,6 +1266,8 @@ 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 \ + src/util/nss_dl_load_extra.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..88f8ae792e --- /dev/null +++ b/src/tests/cwrap/common_mock_nss_dl_load.c @@ -0,0 +1,76 @@ +/* + 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 <dlfcn.h> +#include <errno.h> +#include <fcntl.h> +#include <stddef.h> + +#include "common_mock_nss_dl_load.h" + + +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; + + rc = getpwnam_r(name, result, buffer, buflen, (struct passwd **)&pwd_pointer); + if (rc == 0 && pwd_pointer == result) { + return NSS_STATUS_SUCCESS; + } else if (rc == 0 && (result == NULL)) { + 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 = 0; + rc = getpwuid_r(uid, result, buffer, buflen, (struct passwd **)&pwd_pointer); + if (rc == 0 && pwd_pointer == result) { + return NSS_STATUS_SUCCESS; + } else if (rc == 0 && (pwd_pointer == NULL)) { + *errnop = errno; + return NSS_STATUS_NOTFOUND; + } else { + *errnop = errno; + 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..6db4114508 --- /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 "util/nss_dl_load.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/nss_dl_load.c b/src/util/nss_dl_load.c index 4421083077..379ccfa659 100644 --- a/src/util/nss_dl_load.c +++ b/src/util/nss_dl_load.c @@ -48,6 +48,16 @@ static void *proxy_dlsym(void *handle, return funcptr; } +static void sss_close_handle(struct sss_nss_ops *ops, const char *libname) +{ + if (dlclose(ops->dl_handle) != 0) { + DEBUG(SSSDBG_OP_FAILURE, + "Error closing the handle for the '%s' library, error: %s.\n", + libname, dlerror()); + } + + ops->dl_handle = NULL; +} errno_t sss_load_nss_symbols(struct sss_nss_ops *ops, const char *libname, struct sss_nss_symbols *syms, size_t nsyms) @@ -72,7 +82,7 @@ errno_t sss_load_nss_symbols(struct sss_nss_ops *ops, const char *libname, for (i = 0; i < nsyms; i++) { *(syms[i].fptr) = proxy_dlsym(ops->dl_handle, syms[i].fname, - libname); + libname); if (*(syms[i].fptr) == NULL) { if (syms[i].mandatory) { @@ -80,6 +90,7 @@ errno_t sss_load_nss_symbols(struct sss_nss_ops *ops, const char *libname, "mandatory symbol '%s', error: %s.\n", libpath, syms[i].fname, dlerror()); ret = ELIBBAD; + sss_close_handle(ops, libname); goto out; } else { DEBUG(SSSDBG_OP_FAILURE, "Library '%s' did not provide " diff --git a/src/util/nss_dl_load.h b/src/util/nss_dl_load.h index f1e882b969..07c04e0916 100644 --- a/src/util/nss_dl_load.h +++ b/src/util/nss_dl_load.h @@ -23,6 +23,8 @@ #include <pwd.h> #include <grp.h> #include <netdb.h> +#include <stdbool.h> + #include "util/util_errors.h" #include "sss_client/nss_compat.h" @@ -118,5 +120,6 @@ struct sss_nss_symbols { errno_t sss_load_nss_symbols(struct sss_nss_ops *ops, const char *libname, struct sss_nss_symbols *syms, size_t nsyms); +errno_t sss_load_nss_pw_symbols(struct sss_nss_ops *ops); #endif /* __SSSD_NSS_DL_LOAD_H__ */ diff --git a/src/util/nss_dl_load_extra.c b/src/util/nss_dl_load_extra.c new file mode 100644 index 0000000000..49eb24d62f --- /dev/null +++ b/src/util/nss_dl_load_extra.c @@ -0,0 +1,51 @@ +/* + SSSD + + nss_dl_load_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/nss_dl_load.h" +#include "util/safe-format-string.h" +#include "util/strtonum.h" +#include "util/util.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/usertools.c b/src/util/usertools.c index 370a98b417..5c3af08bb0 100644 --- a/src/util/usertools.c +++ b/src/util/usertools.c @@ -27,12 +27,14 @@ #include "db/sysdb.h" #include "confdb/confdb.h" +#include "util/nss_dl_load.h" #include "util/strtonum.h" #include "util/util.h" #include "util/safe-format-string.h" #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 +574,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; + static 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_OP_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,26 +602,27 @@ 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); + "resolved by getpwnam() [%d][%s]. status returned [%d]\n", + input, errnop, strerror(errnop), status); return EINVAL; } if (_uid) { - *_uid = pwd->pw_uid; + *_uid = pwd.pw_uid; } if (_gid) { - *_gid = pwd->pw_gid; + *_gid = pwd.pw_gid; } + return EOK; } From 008d0e466821a2f818ecaa8470c23f327c64e5f0 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..c787ef9d4d 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> + Local user names are required, 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..34bfe8bfcd 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> + Local user names are required, 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