From ac1c193a3d8d2e0be39fc647e9a4b616b7513a45 Mon Sep 17 00:00:00 2001 From: Alexey Tikhonov 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 (cherry picked from commit 6a6aad282e56a5f0bf52f20b98c1764d43abbbaf) Reviewed-by: Jakub Hrozek --- 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 #include -#include -#include -#include #include #include @@ -37,58 +33,13 @@ #include #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 #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 . +*/ + + +#include +#include +#include +#include + +#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 . +*/ + +#ifndef __SSSD_NSS_DL_LOAD_H__ +#define __SSSD_NSS_DL_LOAD_H__ + + +#include +#include +#include +#include +#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