Blob Blame History Raw
From ac1c193a3d8d2e0be39fc647e9a4b616b7513a45 Mon Sep 17 00:00:00 2001
From: Alexey Tikhonov <atikhono@redhat.com>
Date: Fri, 22 Mar 2019 15:33:22 +0100
Subject: [PATCH 11/15] Util: added facility to load nss lib syms

Factored out (from proxy provider code) utility to load NSS symbols
from shared library.

Related: https://pagure.io/SSSD/sssd/issue/3964

Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
(cherry picked from commit 6a6aad282e56a5f0bf52f20b98c1764d43abbbaf)

Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
---
 Makefile.am                      |   2 +
 src/providers/proxy/proxy.h      |  54 +---------
 src/providers/proxy/proxy_init.c | 163 ++++++++++++-------------------
 src/util/nss_dl_load.c           | 106 ++++++++++++++++++++
 src/util/nss_dl_load.h           |  81 +++++++++++++++
 5 files changed, 255 insertions(+), 151 deletions(-)
 create mode 100644 src/util/nss_dl_load.c
 create mode 100644 src/util/nss_dl_load.h

diff --git a/Makefile.am b/Makefile.am
index 4475b3d12..05f5f4e26 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -677,6 +677,7 @@ dist_noinst_HEADERS = \
     src/util/inotify.h \
     src/util/sss_iobuf.h \
     src/util/tev_curl.h \
+    src/util/nss_dl_load.h \
     src/monitor/monitor.h \
     src/monitor/monitor_interfaces.h \
     src/monitor/monitor_iface_generated.h \
@@ -3996,6 +3997,7 @@ libsss_proxy_la_SOURCES = \
     src/providers/proxy/proxy_services.c \
     src/providers/proxy/proxy_auth.c \
     src/providers/proxy/proxy_iface_generated.c \
+    src//util/nss_dl_load.c \
     $(NULL)
 libsss_proxy_la_CFLAGS = \
     $(AM_CFLAGS)
diff --git a/src/providers/proxy/proxy.h b/src/providers/proxy/proxy.h
index 3b0475d08..6debd4953 100644
--- a/src/providers/proxy/proxy.h
+++ b/src/providers/proxy/proxy.h
@@ -25,11 +25,7 @@
 #ifndef __PROXY_H__
 #define __PROXY_H__
 
-#include <nss.h>
 #include <errno.h>
-#include <pwd.h>
-#include <grp.h>
-#include <dlfcn.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 
@@ -37,58 +33,13 @@
 #include <security/pam_modules.h>
 
 #include "util/util.h"
+#include "util/nss_dl_load.h"
 #include "providers/backend.h"
 #include "db/sysdb.h"
-#include "sss_client/nss_compat.h"
 #include <dhash.h>
 
 #define PROXY_CHILD_PATH "/org/freedesktop/sssd/proxychild"
 
-struct proxy_nss_ops {
-    enum nss_status (*getpwnam_r)(const char *name, struct passwd *result,
-                                  char *buffer, size_t buflen, int *errnop);
-    enum nss_status (*getpwuid_r)(uid_t uid, struct passwd *result,
-                                  char *buffer, size_t buflen, int *errnop);
-    enum nss_status (*setpwent)(void);
-    enum nss_status (*getpwent_r)(struct passwd *result,
-                                  char *buffer, size_t buflen, int *errnop);
-    enum nss_status (*endpwent)(void);
-
-    enum nss_status (*getgrnam_r)(const char *name, struct group *result,
-                                  char *buffer, size_t buflen, int *errnop);
-    enum nss_status (*getgrgid_r)(gid_t gid, struct group *result,
-                                  char *buffer, size_t buflen, int *errnop);
-    enum nss_status (*setgrent)(void);
-    enum nss_status (*getgrent_r)(struct group *result,
-                                  char *buffer, size_t buflen, int *errnop);
-    enum nss_status (*endgrent)(void);
-    enum nss_status (*initgroups_dyn)(const char *user, gid_t group,
-                                      long int *start, long int *size,
-                                      gid_t **groups, long int limit,
-                                      int *errnop);
-    enum nss_status (*setnetgrent)(const char *netgroup,
-                                   struct __netgrent *result);
-    enum nss_status (*getnetgrent_r)(struct __netgrent *result, char *buffer,
-                                     size_t buflen, int *errnop);
-    enum nss_status (*endnetgrent)(struct __netgrent *result);
-
-    /* Services */
-    enum nss_status (*getservbyname_r)(const char *name,
-                                        const char *protocol,
-                                        struct servent *result,
-                                        char *buffer, size_t buflen,
-                                        int *errnop);
-    enum nss_status (*getservbyport_r)(int port, const char *protocol,
-                                        struct servent *result,
-                                        char *buffer, size_t buflen,
-                                        int *errnop);
-    enum nss_status (*setservent)(void);
-    enum nss_status (*getservent_r)(struct servent *result,
-                                    char *buffer, size_t buflen,
-                                    int *errnop);
-    enum nss_status (*endservent)(void);
-};
-
 struct authtok_conv {
     struct sss_auth_token *authtok;
     struct sss_auth_token *newauthtok;
@@ -99,8 +50,7 @@ struct authtok_conv {
 struct proxy_id_ctx {
     struct be_ctx *be;
     bool fast_alias;
-    struct proxy_nss_ops ops;
-    void *handle;
+    struct sss_nss_ops ops;
 };
 
 struct proxy_auth_ctx {
diff --git a/src/providers/proxy/proxy_init.c b/src/providers/proxy/proxy_init.c
index 7d997cb16..e3273d9a7 100644
--- a/src/providers/proxy/proxy_init.c
+++ b/src/providers/proxy/proxy_init.c
@@ -27,44 +27,15 @@
 #include "util/sss_format.h"
 #include "providers/proxy/proxy.h"
 
-#define NSS_FN_NAME "_nss_%s_%s"
-
 #define OPT_MAX_CHILDREN_DEFAULT 10
 
-#define ERROR_INITGR "The '%s' library does not provides the " \
-                         "_nss_XXX_initgroups_dyn function!\n" \
-                         "initgroups will be slow as it will require " \
-                         "full groups enumeration!\n"
-#define ERROR_NETGR "The '%s' library does not support netgroups.\n"
-#define ERROR_SERV "The '%s' library does not support services.\n"
-
-static void *proxy_dlsym(void *handle,
-                         const char *name,
-                         const char *libname)
-{
-    char *funcname;
-    void *funcptr;
-
-    funcname = talloc_asprintf(NULL, NSS_FN_NAME, libname, name);
-    if (funcname == NULL) {
-        return NULL;
-    }
-
-    funcptr = dlsym(handle, funcname);
-    talloc_free(funcname);
-
-    return funcptr;
-}
-
 static errno_t proxy_id_conf(TALLOC_CTX *mem_ctx,
                              struct be_ctx *be_ctx,
                              char **_libname,
-                             char **_libpath,
                              bool *_fast_alias)
 {
     TALLOC_CTX *tmp_ctx;
     char *libname;
-    char *libpath;
     bool fast_alias;
     errno_t ret;
 
@@ -94,15 +65,7 @@ static errno_t proxy_id_conf(TALLOC_CTX *mem_ctx,
         goto done;
     }
 
-    libpath = talloc_asprintf(tmp_ctx, "libnss_%s.so.2", libname);
-    if (libpath == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf() failed\n");
-        ret = ENOMEM;
-        goto done;
-    }
-
     *_libname = talloc_steal(mem_ctx, libname);
-    *_libpath = talloc_steal(mem_ctx, libpath);
     *_fast_alias = fast_alias;
 
     ret = EOK;
@@ -113,57 +76,6 @@ done:
     return ret;
 }
 
-static errno_t proxy_id_load_symbols(struct proxy_nss_ops *ops,
-                                     const char *libname,
-                                     void *handle)
-{
-    int i;
-    struct {void **dest;
-            const char *name;
-            const char *custom_error;
-            bool is_fatal;
-    } symbols[] = {
-        {(void**)&ops->getpwnam_r, "getpwnam_r", NULL, true},
-        {(void**)&ops->getpwuid_r, "getpwuid_r", NULL, true},
-        {(void**)&ops->setpwent, "setpwent", NULL, true},
-        {(void**)&ops->getpwent_r, "getpwent_r", NULL, true},
-        {(void**)&ops->endpwent, "endpwent", NULL, true},
-        {(void**)&ops->getgrnam_r, "getgrnam_r", NULL, true},
-        {(void**)&ops->getgrgid_r, "getgrgid_r", NULL, true},
-        {(void**)&ops->setgrent, "setgrent", NULL, true},
-        {(void**)&ops->getgrent_r, "getgrent_r", NULL, true},
-        {(void**)&ops->endgrent, "endgrent", NULL, true},
-        {(void**)&ops->initgroups_dyn, "initgroups_dyn", ERROR_INITGR, false},
-        {(void**)&ops->setnetgrent, "setnetgrent", ERROR_NETGR, false},
-        {(void**)&ops->getnetgrent_r, "getnetgrent_r", ERROR_NETGR, false},
-        {(void**)&ops->endnetgrent, "endnetgrent", ERROR_NETGR, false},
-        {(void**)&ops->getservbyname_r, "getservbyname_r", ERROR_SERV, false},
-        {(void**)&ops->getservbyport_r, "getservbyport_r", ERROR_SERV, false},
-        {(void**)&ops->setservent, "setservent", ERROR_SERV, false},
-        {(void**)&ops->getservent_r, "getservent_r", ERROR_SERV, false},
-        {(void**)&ops->endservent, "endservent", ERROR_SERV, false},
-        {NULL, NULL, NULL, false}
-    };
-
-    for (i = 0; symbols[i].dest != NULL; i++) {
-        *symbols[i].dest = proxy_dlsym(handle, symbols[i].name, libname);
-        if (*symbols[i].dest == NULL) {
-            DEBUG(SSSDBG_FATAL_FAILURE, "Failed to load _nss_%s_%s, "
-                  "error: %s.\n", libname, symbols[i].name, dlerror());
-
-            if (symbols[i].custom_error != NULL) {
-                DEBUG(SSSDBG_CRIT_FAILURE, symbols[i].custom_error, libname);
-            }
-
-            if (symbols[i].is_fatal) {
-                return ELIBBAD;
-            }
-        }
-    }
-
-    return EOK;
-}
-
 static errno_t proxy_setup_sbus(TALLOC_CTX *mem_ctx,
                                 struct proxy_auth_ctx *ctx,
                                 struct be_ctx *be_ctx)
@@ -310,6 +222,68 @@ errno_t sssm_proxy_init(TALLOC_CTX *mem_ctx,
     return EOK;
 }
 
+
+#define ERROR_INITGR "The '%s' library does not provides the " \
+                         "_nss_XXX_initgroups_dyn function!\n" \
+                         "initgroups will be slow as it will require " \
+                         "full groups enumeration!\n"
+#define ERROR_NETGR "The '%s' library does not support netgroups.\n"
+#define ERROR_SERV "The '%s' library does not support services.\n"
+
+static errno_t proxy_load_nss_symbols(struct sss_nss_ops *ops,
+                                      const char *libname)
+{
+    errno_t ret;
+    size_t i;
+
+    ret = sss_load_nss_symbols(ops, libname);
+    if (ret != EOK) {
+        return ret;
+    }
+
+    struct {
+        void *fptr;
+        const char* custom_error;
+    } optional_syms[] = {
+        {(void*)ops->initgroups_dyn,  ERROR_INITGR},
+        {(void*)ops->setnetgrent,     ERROR_NETGR},
+        {(void*)ops->getnetgrent_r,   ERROR_NETGR},
+        {(void*)ops->endnetgrent,     ERROR_NETGR},
+        {(void*)ops->getservbyname_r, ERROR_SERV},
+        {(void*)ops->getservbyport_r, ERROR_SERV},
+        {(void*)ops->setservent,      ERROR_SERV},
+        {(void*)ops->getservent_r,    ERROR_SERV},
+        {(void*)ops->endservent,      ERROR_SERV},
+    };
+    for (i = 0; i < sizeof(optional_syms) / sizeof(optional_syms[0]); ++i) {
+        if (!optional_syms[i].fptr) {
+            DEBUG(SSSDBG_CRIT_FAILURE, optional_syms[i].custom_error, libname);
+        }
+    }
+
+    void *mandatory_syms[] = {
+        (void*)ops->getpwnam_r,
+        (void*)ops->getpwuid_r,
+        (void*)ops->setpwent,
+        (void*)ops->getpwent_r,
+        (void*)ops->endpwent,
+        (void*)ops->getgrnam_r,
+        (void*)ops->getgrgid_r,
+        (void*)ops->setgrent,
+        (void*)ops->getgrent_r,
+        (void*)ops->endgrent,
+    };
+    for (i = 0; i < sizeof(mandatory_syms)/sizeof(mandatory_syms[0]); ++i) {
+        if (!mandatory_syms[i]) {
+            DEBUG(SSSDBG_CRIT_FAILURE, "The '%s' library does not provide mandatory function", libname);
+            return ELIBBAD;
+        }
+    }
+
+    return EOK;
+}
+
+
 errno_t sssm_proxy_id_init(TALLOC_CTX *mem_ctx,
                            struct be_ctx *be_ctx,
                            void *module_data,
@@ -317,7 +291,6 @@ errno_t sssm_proxy_id_init(TALLOC_CTX *mem_ctx,
 {
     struct proxy_id_ctx *ctx;
     char *libname;
-    char *libpath;
     errno_t ret;
 
     ctx = talloc_zero(mem_ctx, struct proxy_id_ctx);
@@ -327,20 +300,12 @@ errno_t sssm_proxy_id_init(TALLOC_CTX *mem_ctx,
 
     ctx->be = be_ctx;
 
-    ret = proxy_id_conf(ctx, be_ctx, &libname, &libpath, &ctx->fast_alias);
+    ret = proxy_id_conf(ctx, be_ctx, &libname, &ctx->fast_alias);
     if (ret != EOK) {
         goto done;
     }
 
-    ctx->handle = dlopen(libpath, RTLD_NOW);
-    if (ctx->handle == NULL) {
-        DEBUG(SSSDBG_FATAL_FAILURE, "Unable to load %s module, "
-              "error: %s\n", libpath, dlerror());
-        ret = ELIBACC;
-        goto done;
-    }
-
-    ret = proxy_id_load_symbols(&ctx->ops, libname, ctx->handle);
+    ret = proxy_load_nss_symbols(&ctx->ops, libname);
     if (ret != EOK) {
         DEBUG(SSSDBG_FATAL_FAILURE, "Unable to load NSS symbols [%d]: %s\n",
               ret, sss_strerror(ret));
diff --git a/src/util/nss_dl_load.c b/src/util/nss_dl_load.c
new file mode 100644
index 000000000..60df33376
--- /dev/null
+++ b/src/util/nss_dl_load.c
@@ -0,0 +1,106 @@
+/*
+    Copyright (C) 2019 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 <dlfcn.h>
+#include <talloc.h>
+#include <stdbool.h>
+#include <errno.h>
+
+#include "util/util_errors.h"
+#include "util/debug.h"
+#include "nss_dl_load.h"
+
+
+#define NSS_FN_NAME "_nss_%s_%s"
+
+
+static void *proxy_dlsym(void *handle,
+                         const char *name,
+                         const char *libname)
+{
+    char *funcname;
+    void *funcptr;
+
+    funcname = talloc_asprintf(NULL, NSS_FN_NAME, libname, name);
+    if (funcname == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf() failed\n");
+        return NULL;
+    }
+
+    funcptr = dlsym(handle, funcname);
+    talloc_free(funcname);
+
+    return funcptr;
+}
+
+
+errno_t sss_load_nss_symbols(struct sss_nss_ops *ops, const char *libname)
+{
+    char *libpath;
+    size_t i;
+    struct {
+        void **dest;
+        const char *name;
+    } symbols[] = {
+        {(void**)&ops->getpwnam_r,      "getpwnam_r"},
+        {(void**)&ops->getpwuid_r,      "getpwuid_r"},
+        {(void**)&ops->setpwent,        "setpwent"},
+        {(void**)&ops->getpwent_r,      "getpwent_r"},
+        {(void**)&ops->endpwent,        "endpwent"},
+        {(void**)&ops->getgrnam_r,      "getgrnam_r"},
+        {(void**)&ops->getgrgid_r,      "getgrgid_r"},
+        {(void**)&ops->setgrent,        "setgrent"},
+        {(void**)&ops->getgrent_r,      "getgrent_r"},
+        {(void**)&ops->endgrent,        "endgrent"},
+        {(void**)&ops->initgroups_dyn,  "initgroups_dyn"},
+        {(void**)&ops->setnetgrent,     "setnetgrent"},
+        {(void**)&ops->getnetgrent_r,   "getnetgrent_r"},
+        {(void**)&ops->endnetgrent,     "endnetgrent"},
+        {(void**)&ops->getservbyname_r, "getservbyname_r"},
+        {(void**)&ops->getservbyport_r, "getservbyport_r"},
+        {(void**)&ops->setservent,      "setservent"},
+        {(void**)&ops->getservent_r,    "getservent_r"},
+        {(void**)&ops->endservent,      "endservent"}
+    };
+
+    libpath = talloc_asprintf(NULL, "libnss_%s.so.2", libname);
+    if (libpath == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf() failed\n");
+        return ENOMEM;
+    }
+
+    ops->dl_handle = dlopen(libpath, RTLD_NOW);
+    if (ops->dl_handle == NULL) {
+        DEBUG(SSSDBG_FATAL_FAILURE, "Unable to load %s module, "
+              "error: %s\n", libpath, dlerror());
+        talloc_free(libpath);
+        return ELIBACC;
+    }
+    talloc_free(libpath);
+
+    for (i = 0; i < sizeof(symbols)/sizeof(symbols[0]); ++i) {
+        *symbols[i].dest = proxy_dlsym(ops->dl_handle, symbols[i].name,
+                                       libname);
+        if (*symbols[i].dest == NULL) {
+            DEBUG(SSSDBG_FATAL_FAILURE, "Failed to load "NSS_FN_NAME", "
+                  "error: %s.\n", libname, symbols[i].name, dlerror());
+        }
+    }
+
+    return EOK;
+}
diff --git a/src/util/nss_dl_load.h b/src/util/nss_dl_load.h
new file mode 100644
index 000000000..5097acacd
--- /dev/null
+++ b/src/util/nss_dl_load.h
@@ -0,0 +1,81 @@
+/*
+    Copyright (C) 2019 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/>.
+*/
+
+#ifndef __SSSD_NSS_DL_LOAD_H__
+#define __SSSD_NSS_DL_LOAD_H__
+
+
+#include <nss.h>
+#include <pwd.h>
+#include <grp.h>
+#include <netdb.h>
+#include "util/util_errors.h"
+#include "sss_client/nss_compat.h"
+
+
+struct sss_nss_ops {
+    enum nss_status (*getpwnam_r)(const char *name, struct passwd *result,
+                                  char *buffer, size_t buflen, int *errnop);
+    enum nss_status (*getpwuid_r)(uid_t uid, struct passwd *result,
+                                  char *buffer, size_t buflen, int *errnop);
+    enum nss_status (*setpwent)(void);
+    enum nss_status (*getpwent_r)(struct passwd *result,
+                                  char *buffer, size_t buflen, int *errnop);
+    enum nss_status (*endpwent)(void);
+
+    enum nss_status (*getgrnam_r)(const char *name, struct group *result,
+                                  char *buffer, size_t buflen, int *errnop);
+    enum nss_status (*getgrgid_r)(gid_t gid, struct group *result,
+                                  char *buffer, size_t buflen, int *errnop);
+    enum nss_status (*setgrent)(void);
+    enum nss_status (*getgrent_r)(struct group *result,
+                                  char *buffer, size_t buflen, int *errnop);
+    enum nss_status (*endgrent)(void);
+    enum nss_status (*initgroups_dyn)(const char *user, gid_t group,
+                                      long int *start, long int *size,
+                                      gid_t **groups, long int limit,
+                                      int *errnop);
+    enum nss_status (*setnetgrent)(const char *netgroup,
+                                   struct __netgrent *result);
+    enum nss_status (*getnetgrent_r)(struct __netgrent *result, char *buffer,
+                                     size_t buflen, int *errnop);
+    enum nss_status (*endnetgrent)(struct __netgrent *result);
+
+    /* Services */
+    enum nss_status (*getservbyname_r)(const char *name,
+                                        const char *protocol,
+                                        struct servent *result,
+                                        char *buffer, size_t buflen,
+                                        int *errnop);
+    enum nss_status (*getservbyport_r)(int port, const char *protocol,
+                                        struct servent *result,
+                                        char *buffer, size_t buflen,
+                                        int *errnop);
+    enum nss_status (*setservent)(void);
+    enum nss_status (*getservent_r)(struct servent *result,
+                                    char *buffer, size_t buflen,
+                                    int *errnop);
+    enum nss_status (*endservent)(void);
+
+    void *dl_handle;
+};
+
+
+errno_t sss_load_nss_symbols(struct sss_nss_ops *ops, const char *libname);
+
+
+#endif /* __SSSD_NSS_DL_LOAD_H__ */
-- 
2.19.1