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 6ae47cc580fbf644c56ace1fe54e40f6f01632a5 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/monitor/monitor.c                     |   6 +-
 src/providers/ipa/ipa_common.h            |   3 +
 src/providers/ipa/ipa_subdomains_server.c |   3 +-
 src/responder/common/responder.h          |   5 +-
 src/responder/common/responder_common.c   |   6 +-
 src/responder/ifp/ifp_private.h           |   4 +
 src/responder/ifp/ifpsrv.c                |   2 +-
 src/responder/nss/nss_private.h           |   4 +
 src/responder/nss/nsssrv.c                |   4 +-
 src/responder/pac/pacsrv.c                |   2 +-
 src/responder/pac/pacsrv.h                |   4 +
 src/responder/pam/pamsrv.c                |   2 +-
 src/responder/pam/pamsrv.h                |   4 +
 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   |  22 ++++-
 src/tests/cwrap/test_usertools.c          |  41 +++++++-
 src/tests/responder_socket_access-tests.c |  11 ++-
 src/util/usertools.c                      |  60 +++++++++--
 src/util/usertools_extra.c                |  53 ++++++++++
 src/util/util.h                           |   6 +-
 23 files changed, 366 insertions(+), 32 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/monitor/monitor.c b/src/monitor/monitor.c
index 55cb0838aa..86ec612600 100644
--- a/src/monitor/monitor.c
+++ b/src/monitor/monitor.c
@@ -173,6 +173,9 @@ struct mt_ctx {
     /* For running unprivileged services */
     uid_t uid;
     gid_t gid;
+
+    /* Dynamic library load */
+    struct sss_nss_ops ops;
 };
 
 static int start_service(struct mt_svc *mt_svc);
@@ -882,7 +885,8 @@ static int get_service_user(struct mt_ctx *ctx)
         return ret;
     }
 
-    ret = sss_user_by_name_or_uid(user_str, &ctx->uid, &ctx->gid);
+
+    ret = sss_user_by_name_or_uid(&ctx->ops, user_str, &ctx->uid, &ctx->gid);
     talloc_free(user_str);
     if (ret != EOK) {
         DEBUG(SSSDBG_FATAL_FAILURE, "Failed to set allowed UIDs.\n");
diff --git a/src/providers/ipa/ipa_common.h b/src/providers/ipa/ipa_common.h
index eb0eda8eb1..034af39efc 100644
--- a/src/providers/ipa/ipa_common.h
+++ b/src/providers/ipa/ipa_common.h
@@ -208,6 +208,9 @@ struct ipa_id_ctx {
     char *view_name;
     /* Only used with server mode */
     struct ipa_server_mode_ctx *server_mode;
+
+    /* Dynamic library load */
+    struct sss_nss_ops ops;
 };
 
 struct ipa_options {
diff --git a/src/providers/ipa/ipa_subdomains_server.c b/src/providers/ipa/ipa_subdomains_server.c
index deb2c2ceec..d355ccf25a 100644
--- a/src/providers/ipa/ipa_subdomains_server.c
+++ b/src/providers/ipa/ipa_subdomains_server.c
@@ -1195,7 +1195,8 @@ int ipa_ad_subdom_init(struct be_ctx *be_ctx,
         /* We need to handle keytabs created by IPA oddjob script gracefully
          * even if we're running as root and IPA creates them as the SSSD user
          */
-        ret = sss_user_by_name_or_uid(SSSD_USER,
+        ret = sss_user_by_name_or_uid(&id_ctx->ops,
+                                      SSSD_USER,
                                       &id_ctx->server_mode->kt_owner_uid,
                                       &id_ctx->server_mode->kt_owner_gid);
         if (ret != EOK) {
diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h
index 90575b89e7..fdc4da2cbd 100644
--- a/src/responder/common/responder.h
+++ b/src/responder/common/responder.h
@@ -38,6 +38,7 @@
 #include "sss_client/sss_cli.h"
 #include "responder/common/cache_req/cache_req_domain.h"
 #include "util/session_recording.h"
+#include "util/nss_dl_load.h"
 
 extern hash_table_t *dp_requests;
 
@@ -370,8 +371,8 @@ errno_t schedule_get_domains_task(TALLOC_CTX *mem_ctx,
                                   get_domains_callback_fn_t *callback,
                                   void *callback_pvt);
 
-errno_t csv_string_to_uid_array(TALLOC_CTX *mem_ctx, const char *csv_string,
-                                bool allow_sss_loop,
+errno_t csv_string_to_uid_array(TALLOC_CTX *mem_ctx, struct sss_nss_ops *ops,
+                                const char *csv_string, bool allow_sss_loop,
                                 size_t *_uid_count, uid_t **_uids);
 
 uid_t client_euid(struct cli_creds *creds);
diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c
index 913dbcd800..59401c69cc 100644
--- a/src/responder/common/responder_common.c
+++ b/src/responder/common/responder_common.c
@@ -189,8 +189,8 @@ errno_t check_allowed_uids(uid_t uid, size_t allowed_uids_count,
     return EACCES;
 }
 
-errno_t csv_string_to_uid_array(TALLOC_CTX *mem_ctx, const char *csv_string,
-                                bool allow_sss_loop,
+errno_t csv_string_to_uid_array(TALLOC_CTX *mem_ctx, struct sss_nss_ops *ops,
+                                const char *csv_string, bool allow_sss_loop,
                                 size_t *_uid_count, uid_t **_uids)
 {
     int ret;
@@ -239,7 +239,7 @@ errno_t csv_string_to_uid_array(TALLOC_CTX *mem_ctx, const char *csv_string,
                 goto done;
             }
 
-            ret = sss_user_by_name_or_uid(list[c], &uids[c], NULL);
+            ret = sss_user_by_name_or_uid(ops, list[c], &uids[c], NULL);
             if (ret != EOK) {
                 DEBUG(SSSDBG_OP_FAILURE, "List item [%s] is neither a valid "
                                          "UID nor a user name which could be "
diff --git a/src/responder/ifp/ifp_private.h b/src/responder/ifp/ifp_private.h
index 3cd986f179..4c48d1e21d 100644
--- a/src/responder/ifp/ifp_private.h
+++ b/src/responder/ifp/ifp_private.h
@@ -30,6 +30,7 @@
 #include <ldb.h>
 
 #include "util/util.h"
+#include "util/nss_dl_load.h"
 #include "confdb/confdb.h"
 #include "responder/common/responder.h"
 #include "responder/common/negcache.h"
@@ -42,6 +43,9 @@ struct ifp_ctx {
     struct sbus_connection *sysbus;
     const char **user_whitelist;
     uint32_t wildcard_limit;
+
+    /* Dynamic library load */
+    struct sss_nss_ops ops;
 };
 
 errno_t
diff --git a/src/responder/ifp/ifpsrv.c b/src/responder/ifp/ifpsrv.c
index d27c2dfccd..5d8691b727 100644
--- a/src/responder/ifp/ifpsrv.c
+++ b/src/responder/ifp/ifpsrv.c
@@ -207,7 +207,7 @@ int ifp_process_init(TALLOC_CTX *mem_ctx,
         goto fail;
     }
 
-    ret = csv_string_to_uid_array(ifp_ctx->rctx, uid_str, true,
+    ret = csv_string_to_uid_array(ifp_ctx->rctx, &ifp_ctx->ops, uid_str, true,
                                   &ifp_ctx->rctx->allowed_uids_count,
                                   &ifp_ctx->rctx->allowed_uids);
     talloc_free(uid_str);
diff --git a/src/responder/nss/nss_private.h b/src/responder/nss/nss_private.h
index dded160f9d..02e75788f4 100644
--- a/src/responder/nss/nss_private.h
+++ b/src/responder/nss/nss_private.h
@@ -27,6 +27,7 @@
 #include <ldb.h>
 
 #include "util/util.h"
+#include "util/nss_dl_load.h"
 #include "db/sysdb.h"
 #include "responder/common/responder.h"
 #include "responder/common/cache_req/cache_req.h"
@@ -93,6 +94,9 @@ struct nss_ctx {
     struct sss_mc_ctx *initgr_mc_ctx;
     uid_t mc_uid;
     gid_t mc_gid;
+
+    /* Dynamic library load */
+    struct sss_nss_ops ops;
 };
 
 struct sss_cmd_table *get_nss_cmds(void);
diff --git a/src/responder/nss/nsssrv.c b/src/responder/nss/nsssrv.c
index 526d97b087..b91857d198 100644
--- a/src/responder/nss/nsssrv.c
+++ b/src/responder/nss/nsssrv.c
@@ -44,6 +44,7 @@
 #include "responder/common/responder_packet.h"
 #include "responder/common/responder.h"
 #include "providers/data_provider.h"
+#include "util/nss_dl_load.h"
 #include "util/util_sss_idmap.h"
 #include "sss_iface/sss_iface_async.h"
 
@@ -401,7 +402,8 @@ static int sssd_supplementary_group(struct nss_ctx *nss_ctx)
      * the SSSD is compiled --with-sssd-user=sssd but the default of the
      * user option is root (this is what RHEL does)
      */
-    ret = sss_user_by_name_or_uid(SSSD_USER,
+    ret = sss_user_by_name_or_uid(&nss_ctx->ops,
+                                  SSSD_USER,
                                   &nss_ctx->mc_uid,
                                   &nss_ctx->mc_gid);
     if (ret != EOK) {
diff --git a/src/responder/pac/pacsrv.c b/src/responder/pac/pacsrv.c
index e77641ec01..a1c45bc0e5 100644
--- a/src/responder/pac/pacsrv.c
+++ b/src/responder/pac/pacsrv.c
@@ -90,7 +90,7 @@ int pac_process_init(TALLOC_CTX *mem_ctx,
         goto fail;
     }
 
-    ret = csv_string_to_uid_array(pac_ctx->rctx, uid_str, true,
+    ret = csv_string_to_uid_array(pac_ctx->rctx, &pac_ctx->ops, uid_str, true,
                                   &pac_ctx->rctx->allowed_uids_count,
                                   &pac_ctx->rctx->allowed_uids);
     talloc_free(uid_str);
diff --git a/src/responder/pac/pacsrv.h b/src/responder/pac/pacsrv.h
index aea16f39ff..8b143b69d5 100644
--- a/src/responder/pac/pacsrv.h
+++ b/src/responder/pac/pacsrv.h
@@ -28,6 +28,7 @@
 #include "responder/common/responder.h"
 #include "responder/common/responder_sbus.h"
 #include "lib/idmap/sss_idmap.h"
+#include "util/nss_dl_load.h"
 
 struct pac_ctx {
     struct resp_ctx *rctx;
@@ -35,6 +36,9 @@ struct pac_ctx {
     struct dom_sid *my_dom_sid;
     struct local_mapping_ranges *range_map;
     int pac_lifetime;
+
+    /* Dynamic library load */
+    struct sss_nss_ops ops;
 };
 
 struct sss_cmd_table *get_pac_cmds(void);
diff --git a/src/responder/pam/pamsrv.c b/src/responder/pam/pamsrv.c
index 14aa094360..62d7d78c1b 100644
--- a/src/responder/pam/pamsrv.c
+++ b/src/responder/pam/pamsrv.c
@@ -69,7 +69,7 @@ static errno_t get_trusted_uids(struct pam_ctx *pctx)
          DEBUG(SSSDBG_TRACE_FUNC, "All UIDs are allowed.\n");
          pctx->trusted_uids_count = 0;
     } else {
-        ret = csv_string_to_uid_array(pctx->rctx, uid_str, true,
+        ret = csv_string_to_uid_array(pctx->rctx, &pctx->ops, uid_str, true,
                                       &pctx->trusted_uids_count,
                                       &pctx->trusted_uids);
     }
diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h
index 85af2f8876..c2694f20f2 100644
--- a/src/responder/pam/pamsrv.h
+++ b/src/responder/pam/pamsrv.h
@@ -24,6 +24,7 @@
 
 #include <security/pam_appl.h>
 #include "util/util.h"
+#include "util/nss_dl_load.h"
 #include "responder/common/responder.h"
 #include "responder/common/cache_req/cache_req.h"
 #include "lib/certmap/sss_certmap.h"
@@ -71,6 +72,9 @@ struct pam_ctx {
     /* List of authentication indicators associated with a PAM service */
     char **gssapi_indicators_map;
     bool gssapi_check_upn;
+
+    /* Dynamic library load */
+    struct sss_nss_ops ops;
 };
 
 struct pam_auth_req {
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..d7c7528339
--- /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.0"
+
+
+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..44951c8d57 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)
@@ -43,16 +50,19 @@ struct cli_protocol_version *register_cli_protocol_version(void)
 void test_uid_csv_to_uid_list(void **state)
 {
     TALLOC_CTX *tmp_ctx;
+    struct sss_nss_ops *ops;
     errno_t ret;
     size_t count;
     uid_t *list;
 
     tmp_ctx = talloc_new(global_talloc_context);
     assert_non_null(tmp_ctx);
+    ops = talloc_zero(tmp_ctx, struct sss_nss_ops);
+    assert_non_null(ops);
 
     check_leaks_push(tmp_ctx);
 
-    ret = csv_string_to_uid_array(tmp_ctx, "1, 2, 3", false, &count, &list);
+    ret = csv_string_to_uid_array(tmp_ctx, ops, "1, 2, 3", false, &count, &list);
     assert_int_equal(ret, EOK);
     assert_int_equal(count, 3);
     assert_int_equal(list[0], 1);
@@ -67,16 +77,19 @@ void test_uid_csv_to_uid_list(void **state)
 void test_name_csv_to_uid_list(void **state)
 {
     TALLOC_CTX *tmp_ctx;
+    struct sss_nss_ops *ops;
     errno_t ret;
     size_t count;
     uid_t *list;
 
     tmp_ctx = talloc_new(global_talloc_context);
     assert_non_null(tmp_ctx);
+    ops = talloc_zero(tmp_ctx, struct sss_nss_ops);
+    assert_non_null(ops);
 
     check_leaks_push(tmp_ctx);
 
-    ret = csv_string_to_uid_array(tmp_ctx, "sssd, foobar", true, &count, &list);
+    ret = csv_string_to_uid_array(tmp_ctx, ops, "sssd, foobar", true, &count, &list);
     assert_int_equal(ret, EOK);
     assert_int_equal(count, 2);
     assert_int_equal(list[0], 123);
@@ -90,16 +103,19 @@ void test_name_csv_to_uid_list(void **state)
 void test_csv_to_uid_list_neg(void **state)
 {
     TALLOC_CTX *tmp_ctx;
+    struct sss_nss_ops *ops;
     errno_t ret;
     size_t count;
     uid_t *list = NULL;
 
     tmp_ctx = talloc_new(global_talloc_context);
     assert_non_null(tmp_ctx);
+    ops = talloc_zero(tmp_ctx, struct sss_nss_ops);
+    assert_non_null(ops);
 
     check_leaks_push(tmp_ctx);
 
-    ret = csv_string_to_uid_array(tmp_ctx, "nosuchuser", true, &count, &list);
+    ret = csv_string_to_uid_array(tmp_ctx, ops, "nosuchuser", true, &count, &list);
     assert_int_not_equal(ret, EOK);
 
     assert_true(check_leaks_pop(tmp_ctx));
diff --git a/src/tests/cwrap/test_usertools.c b/src/tests/cwrap/test_usertools.c
index f61ae83e20..04653ccc03 100644
--- a/src/tests/cwrap/test_usertools.c
+++ b/src/tests/cwrap/test_usertools.c
@@ -27,44 +27,77 @@
 #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)
 {
+    TALLOC_CTX *tmp_ctx;
+    struct sss_nss_ops *ops;
     uid_t uid;
     gid_t gid;
     errno_t ret;
 
-    ret = sss_user_by_name_or_uid("123", &uid, &gid);
+    tmp_ctx = talloc_new(NULL);
+    assert_non_null(tmp_ctx);
+    ops = talloc_zero(tmp_ctx, struct sss_nss_ops);
+    assert_non_null(ops);
+
+    ret = sss_user_by_name_or_uid(ops, "123", &uid, &gid);
     assert_int_equal(ret, EOK);
     assert_int_equal(uid, 123);
     assert_int_equal(gid, 456);
+
+    talloc_zfree(tmp_ctx);
 }
 
 void test_get_user_str(void **state)
 {
+    TALLOC_CTX *tmp_ctx;
+    struct sss_nss_ops *ops;
     uid_t uid;
     gid_t gid;
     errno_t ret;
 
-    ret = sss_user_by_name_or_uid("sssd", &uid, &gid);
+    tmp_ctx = talloc_new(NULL);
+    assert_non_null(tmp_ctx);
+    ops = talloc_zero(tmp_ctx, struct sss_nss_ops);
+    assert_non_null(ops);
+
+    ret = sss_user_by_name_or_uid(ops, "sssd", &uid, &gid);
     assert_int_equal(ret, EOK);
     assert_int_equal(uid, 123);
     assert_int_equal(gid, 456);
+
+    talloc_zfree(tmp_ctx);
 }
 
 void test_get_user_nullparm(void **state)
 {
+    TALLOC_CTX *tmp_ctx;
+    struct sss_nss_ops *ops;
     uid_t uid;
     gid_t gid;
     errno_t ret;
 
-    ret = sss_user_by_name_or_uid("sssd", &uid, NULL);
+    tmp_ctx = talloc_new(NULL);
+    assert_non_null(tmp_ctx);
+    ops = talloc_zero(tmp_ctx, struct sss_nss_ops);
+    assert_non_null(ops);
+
+    ret = sss_user_by_name_or_uid(ops, "sssd", &uid, NULL);
     assert_int_equal(ret, EOK);
     assert_int_equal(uid, 123);
 
-    ret = sss_user_by_name_or_uid("sssd", NULL, &gid);
+    ret = sss_user_by_name_or_uid(ops, "sssd", NULL, &gid);
     assert_int_equal(ret, EOK);
     assert_int_equal(gid, 456);
+
+    talloc_zfree(tmp_ctx);
 }
 
 int main(int argc, const char *argv[])
diff --git a/src/tests/responder_socket_access-tests.c b/src/tests/responder_socket_access-tests.c
index 5218555f47..4685bee8ae 100644
--- a/src/tests/responder_socket_access-tests.c
+++ b/src/tests/responder_socket_access-tests.c
@@ -25,6 +25,7 @@
 #include <string.h>
 
 #include "tests/common.h"
+#include "tests/common_check.h"
 #include "responder/common/responder.h"
 
 struct cli_protocol_version *register_cli_protocol_version(void)
@@ -66,10 +67,16 @@ START_TEST(resp_str_to_array_test)
     uid_t *uids = NULL;
     size_t c;
     size_t d;
+    struct sss_nss_ops *ops;
+
+    ops = talloc_zero(global_talloc_context, struct sss_nss_ops);
+    ck_assert_ptr_nonnull(ops);
+    sss_ck_fail_if_msg(ops == NULL, "Failed to allocate memory");
 
     for (c = 0; s2a_data[c].exp_ret != -1; c++) {
-        ret = csv_string_to_uid_array(global_talloc_context, s2a_data[c].inp,
-                                      true, &uid_count, &uids);
+        ret = csv_string_to_uid_array(global_talloc_context, ops,
+                                      s2a_data[c].inp, true,
+                                      &uid_count, &uids);
         ck_assert_msg(ret == s2a_data[c].exp_ret,
                     "csv_string_to_uid_array failed [%d][%s].", ret,
                                                                 strerror(ret));
diff --git a/src/util/usertools.c b/src/util/usertools.c
index 370a98b417..e3108b54dd 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)
@@ -570,12 +571,32 @@ sss_fqname(char *str, size_t size, struct sss_names_ctx *nctx,
                               name, domain->name, calc_flat_name (domain), NULL);
 }
 
-errno_t sss_user_by_name_or_uid(const char *input, uid_t *_uid, gid_t *_gid)
+errno_t sss_user_by_name_or_uid(struct sss_nss_ops *ops, const char *input,
+                                uid_t *_uid, gid_t *_gid)
 {
     uid_t uid;
     errno_t ret;
     char *endptr;
-    struct passwd *pwd;
+    struct passwd pwd = { 0 };
+    TALLOC_CTX *tmp_ctx;
+    int errnop = 0;
+    enum nss_status status;
+    char s_nss_buffer[NSS_BUFFER_SIZE];
+
+    tmp_ctx = talloc_new(NULL);
+    if (!tmp_ctx) {
+        DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed");
+        return ENOMEM;
+    }
+
+    if (!ops->dl_handle) {
+        ret = sss_load_nss_pw_symbols(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);
@@ -584,29 +605,33 @@ errno_t sss_user_by_name_or_uid(const char *input, uid_t *_uid, gid_t *_gid)
         if (ret == ERANGE) {
             DEBUG(SSSDBG_OP_FAILURE,
                   "UID [%s] is out of range.\n", input);
+            talloc_free(tmp_ctx);
             return ret;
         }
 
-        /* Nope, maybe a username? */
-        pwd = getpwnam(input);
+        status = ops->getpwnam_r(input, &pwd, s_nss_buffer, NSS_BUFFER_SIZE, &errnop);
     } else {
-        pwd = getpwuid(uid);
+        status = 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);
+        talloc_free(tmp_ctx);
         return EINVAL;
     }
 
     if (_uid) {
-        *_uid = pwd->pw_uid;
+        *_uid = pwd.pw_uid;
     }
 
     if (_gid) {
-        *_gid = pwd->pw_gid;
+        *_gid = pwd.pw_gid;
     }
+
+    talloc_free(tmp_ctx);
+
     return EOK;
 }
 
@@ -838,11 +863,25 @@ int sss_output_fqname(TALLOC_CTX *mem_ctx,
 
 void sss_sssd_user_uid_and_gid(uid_t *_uid, gid_t *_gid)
 {
+    TALLOC_CTX *tmp_ctx;
+    struct sss_nss_ops *ops;
     uid_t sssd_uid;
     gid_t sssd_gid;
     errno_t ret;
 
-    ret = sss_user_by_name_or_uid(SSSD_USER, &sssd_uid, &sssd_gid);
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed");
+        goto done;
+    }
+
+    ops = talloc_zero(tmp_ctx, struct sss_nss_ops);
+    if (ops == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed");
+        goto done;
+    }
+
+    ret = sss_user_by_name_or_uid(ops, 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;
@@ -856,6 +895,9 @@ void sss_sssd_user_uid_and_gid(uid_t *_uid, gid_t *_gid)
     if (_gid != NULL) {
         *_gid = sssd_gid;
     }
+
+done:
+    talloc_zfree(tmp_ctx);
 }
 
 void sss_set_sssd_user_eid(void)
diff --git a/src/util/usertools_extra.c b/src/util/usertools_extra.c
new file mode 100644
index 0000000000..1f6677f033
--- /dev/null
+++ b/src/util/usertools_extra.c
@@ -0,0 +1,53 @@
+/*
+    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);
+    if (ret != EOK) {
+        return ret;
+    }
+
+    return ret;
+}
diff --git a/src/util/util.h b/src/util/util.h
index 6dfd2540cc..04eb1b79fa 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);
 
@@ -382,7 +385,8 @@ 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);
+errno_t sss_user_by_name_or_uid(struct sss_nss_ops *ops, 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);

From aab9d32a7af9ab75c296226f82098044924eb967 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 clarify user option

user option in sssd.conf accepts both the user name and the id as input.
The only constraint is that the user should be present in the local
database (/etc/passwd).

Signed-off-by: Iker Pedrosa <ipedr...@redhat.com>
---
 src/man/sssd.conf.5.xml | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
index 8ca267b253..43c19ba479 100644
--- a/src/man/sssd.conf.5.xml
+++ b/src/man/sssd.conf.5.xml
@@ -423,6 +423,11 @@
                                     responder.
                                 </phrase>
                             </para>
+                            <para>
+                                Both a user name and a uid can be used but the
+                                user should be present in
+                                <filename>/etc/passwd</filename>.
+                            </para>
                             <para>
                                 Default: not set, process will run as root
                             </para>
_______________________________________________
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

Reply via email to