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