diff options
Diffstat (limited to 'lib/nss_wrapper/nss_wrapper.c')
-rw-r--r-- | lib/nss_wrapper/nss_wrapper.c | 2744 |
1 files changed, 2360 insertions, 384 deletions
diff --git a/lib/nss_wrapper/nss_wrapper.c b/lib/nss_wrapper/nss_wrapper.c index 8767fbfd892..7c5a413ee78 100644 --- a/lib/nss_wrapper/nss_wrapper.c +++ b/lib/nss_wrapper/nss_wrapper.c @@ -1,6 +1,7 @@ /* * Copyright (C) Stefan Metzmacher 2007 <metze@samba.org> * Copyright (C) Guenther Deschner 2009 <gd@samba.org> + * Copyright (C) Andreas Schneider 2013 <asn@samba.org> * * All rights reserved. * @@ -32,120 +33,229 @@ * SUCH DAMAGE. */ -#ifdef _SAMBA_BUILD_ +#include "config.h" + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <errno.h> +#include <fcntl.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <ctype.h> -/* defining this gives us the posix getpwnam_r() calls on solaris - Thanks to heimdal for this */ +/* + * Defining _POSIX_PTHREAD_SEMANTICS before including pwd.h and grp.h gives us + * the posix getpwnam_r(), getpwuid_r(), getgrnam_r and getgrgid_r calls on + * Solaris + */ #ifndef _POSIX_PTHREAD_SEMANTICS #define _POSIX_PTHREAD_SEMANTICS #endif -#define NSS_WRAPPER_NOT_REPLACE -#include "../replace/replace.h" -#include "system/passwd.h" -#include "system/filesys.h" -#include "../nsswitch/nsstest.h" +#include <pwd.h> +#include <grp.h> + +#include <netdb.h> +#include <arpa/inet.h> +#include <netinet/in.h> + +#include <dlfcn.h> -#else /* _SAMBA_BUILD_ */ +#if defined(HAVE_NSS_H) +/* Linux and BSD */ +#include <nss.h> -#error nss_wrapper_only_supported_in_samba_yet +typedef enum nss_status NSS_STATUS; +#elif defined(HAVE_NSS_COMMON_H) +/* Solaris */ +#include <nss_common.h> +#include <nss_dbdefs.h> +#include <nsswitch.h> + +typedef nss_status_t NSS_STATUS; + +# define NSS_STATUS_SUCCESS NSS_SUCCESS +# define NSS_STATUS_NOTFOUND NSS_NOTFOUND +# define NSS_STATUS_UNAVAIL NSS_UNAVAIL +# define NSS_STATUS_TRYAGAIN NSS_TRYAGAIN +#else +# error "No nsswitch support detected" +#endif +#ifndef PTR_DIFF +#define PTR_DIFF(p1, p2) ((ptrdiff_t)(((const char *)(p1)) - (const char *)(p2))) #endif #ifndef _PUBLIC_ #define _PUBLIC_ #endif -/* not all systems have _r functions... */ -#ifndef HAVE_GETPWNAM_R -#define getpwnam_r(name, pwdst, buf, buflen, pwdstp) ENOSYS -#endif -#ifndef HAVE_GETPWUID_R -#define getpwuid_r(uid, pwdst, buf, buflen, pwdstp) ENOSYS +#ifndef EAI_NODATA +#define EAI_NODATA EAI_NONAME #endif -#ifndef HAVE_GETPWENT_R -#define getpwent_r(pwdst, buf, buflen, pwdstp) ENOSYS + +#ifndef EAI_ADDRFAMILY +#define EAI_ADDRFAMILY EAI_FAMILY #endif -#ifndef HAVE_GETGRNAM_R -#define getgrnam_r(name, grdst, buf, buflen, grdstp) ENOSYS + +#ifndef __STRING +#define __STRING(x) #x #endif -#ifndef HAVE_GETGRGID_R -#define getgrgid_r(gid, grdst, buf, buflen, grdstp) ENOSYS + +#ifndef __STRINGSTRING +#define __STRINGSTRING(x) __STRING(x) #endif -#ifndef HAVE_GETGRENT_R -#define getgrent_r(grdst, buf, buflen, grdstp) ENOSYS + +#ifndef __LINESTR__ +#define __LINESTR__ __STRINGSTRING(__LINE__) #endif -/* not all systems have getgrouplist */ -#ifndef HAVE_GETGROUPLIST -#define getgrouplist(user, group, groups, ngroups) 0 +#ifndef __location__ +#define __location__ __FILE__ ":" __LINESTR__ #endif -/* LD_PRELOAD doesn't work yet, so REWRITE_CALLS is all we support - * for now */ -#define REWRITE_CALLS +/* GCC have printf type attribute check. */ +#ifdef HAVE_ATTRIBUTE_PRINTF_FORMAT +#define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b))) +#else +#define PRINTF_ATTRIBUTE(a,b) +#endif /* HAVE_ATTRIBUTE_PRINTF_FORMAT */ -#ifdef REWRITE_CALLS +#ifdef HAVE_DESTRUCTOR_ATTRIBUTE +#define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor)) +#else +#define DESTRUCTOR_ATTRIBUTE +#endif /* HAVE_DESTRUCTOR_ATTRIBUTE */ -#define real_getpwnam getpwnam -#define real_getpwnam_r getpwnam_r -#define real_getpwuid getpwuid -#define real_getpwuid_r getpwuid_r +#define ZERO_STRUCTP(x) do { if ((x) != NULL) memset((char *)(x), 0, sizeof(*(x))); } while(0) -#define real_setpwent setpwent -#define real_getpwent getpwent -#define real_getpwent_r getpwent_r -#define real_endpwent endpwent +enum nwrap_dbglvl_e { + NWRAP_LOG_ERROR = 0, + NWRAP_LOG_WARN, + NWRAP_LOG_DEBUG, + NWRAP_LOG_TRACE +}; -/* -#define real_getgrlst getgrlst -#define real_getgrlst_r getgrlst_r -#define real_initgroups_dyn initgroups_dyn -*/ -#define real_initgroups initgroups -#define real_getgrouplist getgrouplist - -#define real_getgrnam getgrnam -#define real_getgrnam_r getgrnam_r -#define real_getgrgid getgrgid -#define real_getgrgid_r getgrgid_r - -#define real_setgrent setgrent -#define real_getgrent getgrent -#define real_getgrent_r getgrent_r -#define real_endgrent endgrent +#ifdef NDEBUG +# define NWRAP_LOG(...) +#else -#endif +static void nwrap_log(enum nwrap_dbglvl_e dbglvl, const char *func, const char *format, ...) PRINTF_ATTRIBUTE(3, 4); +# define NWRAP_LOG(dbglvl, ...) nwrap_log((dbglvl), __func__, __VA_ARGS__) -#if 0 -# ifdef DEBUG -# define NWRAP_ERROR(args) DEBUG(0, args) -# else -# define NWRAP_ERROR(args) printf args -# endif +static void nwrap_log(enum nwrap_dbglvl_e dbglvl, + const char *func, + const char *format, ...) +{ + char buffer[1024]; + va_list va; + const char *d; + unsigned int lvl = 0; + int pid = getpid(); + + d = getenv("NSS_WRAPPER_DEBUGLEVEL"); + if (d != NULL) { + lvl = atoi(d); + } + + va_start(va, format); + vsnprintf(buffer, sizeof(buffer), format, va); + va_end(va); + + if (lvl >= dbglvl) { + switch (dbglvl) { + case NWRAP_LOG_ERROR: + fprintf(stderr, + "NWRAP_ERROR(%d) - %s: %s\n", + pid, func, buffer); + break; + case NWRAP_LOG_WARN: + fprintf(stderr, + "NWRAP_WARN(%d) - %s: %s\n", + pid, func, buffer); + break; + case NWRAP_LOG_DEBUG: + fprintf(stderr, + "NWRAP_DEBUG(%d) - %s: %s\n", + pid, func, buffer); + break; + case NWRAP_LOG_TRACE: + fprintf(stderr, + "NWRAP_TRACE(%d) - %s: %s\n", + pid, func, buffer); + break; + } + } +} +#endif /* NDEBUG NWRAP_LOG */ + +struct nwrap_libc_fns { + struct passwd *(*_libc_getpwnam)(const char *name); + int (*_libc_getpwnam_r)(const char *name, struct passwd *pwd, + char *buf, size_t buflen, struct passwd **result); + struct passwd *(*_libc_getpwuid)(uid_t uid); + int (*_libc_getpwuid_r)(uid_t uid, struct passwd *pwd, char *buf, size_t buflen, struct passwd **result); + void (*_libc_setpwent)(void); + struct passwd *(*_libc_getpwent)(void); +#ifdef HAVE_SOLARIS_GETPWENT_R + struct passwd *(*_libc_getpwent_r)(struct passwd *pwbuf, char *buf, size_t buflen); #else -#define NWRAP_ERROR(args) + int (*_libc_getpwent_r)(struct passwd *pwbuf, char *buf, size_t buflen, struct passwd **pwbufp); #endif - -#if 0 -# ifdef DEBUG -# define NWRAP_DEBUG(args) DEBUG(0, args) -# else -# define NWRAP_DEBUG(args) printf args -# endif + void (*_libc_endpwent)(void); + int (*_libc_initgroups)(const char *user, gid_t gid); + struct group *(*_libc_getgrnam)(const char *name); + int (*_libc_getgrnam_r)(const char *name, struct group *grp, char *buf, size_t buflen, struct group **result); + struct group *(*_libc_getgrgid)(gid_t gid); + int (*_libc_getgrgid_r)(gid_t gid, struct group *grp, char *buf, size_t buflen, struct group **result); + void (*_libc_setgrent)(void); + struct group *(*_libc_getgrent)(void); +#ifdef HAVE_SOLARIS_GETGRENT_R + struct group *(*_libc_getgrent_r)(struct group *group, char *buf, size_t buflen); #else -#define NWRAP_DEBUG(args) + int (*_libc_getgrent_r)(struct group *group, char *buf, size_t buflen, struct group **result); #endif + void (*_libc_endgrent)(void); + int (*_libc_getgrouplist)(const char *user, gid_t group, gid_t *groups, int *ngroups); -#if 0 -# ifdef DEBUG -# define NWRAP_VERBOSE(args) DEBUG(0, args) -# else -# define NWRAP_VERBOSE(args) printf args -# endif -#else -#define NWRAP_VERBOSE(args) + void (*_libc_sethostent)(int stayopen); + struct hostent *(*_libc_gethostent)(void); + void (*_libc_endhostent)(void); + + struct hostent *(*_libc_gethostbyname)(const char *name); +#ifdef HAVE_GETHOSTBYNAME2 /* GNU extension */ + struct hostent *(*_libc_gethostbyname2)(const char *name, int af); +#endif + struct hostent *(*_libc_gethostbyaddr)(const void *addr, socklen_t len, int type); + + int (*_libc_getaddrinfo)(const char *node, const char *service, + const struct addrinfo *hints, + struct addrinfo **res); + int (*_libc_getnameinfo)(const struct sockaddr *sa, socklen_t salen, + char *host, size_t hostlen, + char *serv, size_t servlen, + int flags); + int (*_libc_gethostname)(char *name, size_t len); +#ifdef HAVE_GETHOSTBYNAME_R + int (*_libc_gethostbyname_r)(const char *name, + struct hostent *ret, + char *buf, size_t buflen, + struct hostent **result, int *h_errnop); +#endif +#ifdef HAVE_GETHOSTBYADDR_R + int (*_libc_gethostbyaddr_r)(const void *addr, socklen_t len, int type, + struct hostent *ret, + char *buf, size_t buflen, + struct hostent **result, int *h_errnop); #endif +}; struct nwrap_module_nss_fns { NSS_STATUS (*_nss_getpwnam_r)(const char *name, struct passwd *result, char *buffer, @@ -213,6 +323,11 @@ struct nwrap_ops { void (*nw_endgrent)(struct nwrap_backend *b); }; +/* Public prototypes */ + +bool nss_wrapper_enabled(void); +bool nss_wrapper_hosts_enabled(void); + /* prototypes for files backend */ @@ -328,10 +443,18 @@ struct nwrap_ops nwrap_module_ops = { .nw_endgrent = nwrap_module_endgrent, }; +struct nwrap_libc { + void *handle; + void *nsl_handle; + void *sock_handle; + struct nwrap_libc_fns *fns; +}; + struct nwrap_main { const char *nwrap_switch; int num_backends; struct nwrap_backend *backends; + struct nwrap_libc *libc; }; struct nwrap_main *nwrap_main_global; @@ -372,8 +495,550 @@ struct nwrap_gr { struct nwrap_cache __nwrap_cache_gr; struct nwrap_gr nwrap_gr_global; +static bool nwrap_he_parse_line(struct nwrap_cache *nwrap, char *line); +static void nwrap_he_unload(struct nwrap_cache *nwrap); + +struct nwrap_addrdata { + unsigned char host_addr[16]; /* IPv4 or IPv6 address */ + char *h_addr_ptrs[2]; /* host_addr pointer + NULL */ +}; + +struct nwrap_entdata { + struct nwrap_addrdata *addr; + struct hostent ht; +}; + +struct nwrap_he { + struct nwrap_cache *cache; + + struct nwrap_entdata *list; + int num; + int idx; +}; + +struct nwrap_cache __nwrap_cache_he; +struct nwrap_he nwrap_he_global; + + +/********************************************************* + * NWRAP PROTOTYPES + *********************************************************/ + +static void nwrap_init(void); static bool nwrap_gr_parse_line(struct nwrap_cache *nwrap, char *line); static void nwrap_gr_unload(struct nwrap_cache *nwrap); +void nwrap_destructor(void) DESTRUCTOR_ATTRIBUTE; + +/********************************************************* + * NWRAP LIBC LOADER FUNCTIONS + *********************************************************/ + +enum nwrap_lib { + NWRAP_LIBC, + NWRAP_LIBNSL, + NWRAP_LIBSOCKET, +}; + +#ifndef NDEBUG +static const char *nwrap_str_lib(enum nwrap_lib lib) +{ + switch (lib) { + case NWRAP_LIBC: + return "libc"; + case NWRAP_LIBNSL: + return "libnsl"; + case NWRAP_LIBSOCKET: + return "libsocket"; + } + + /* Compiler would warn us about unhandled enum value if we get here */ + return "unknown"; +} +#endif + +static void *nwrap_load_lib_handle(enum nwrap_lib lib) +{ + int flags = RTLD_LAZY; + void *handle = NULL; + int i; + +#ifdef HAVE_APPLE + return RTLD_NEXT; +#endif + +#ifdef RTLD_DEEPBIND + flags |= RTLD_DEEPBIND; +#endif + + switch (lib) { + case NWRAP_LIBNSL: +#ifdef HAVE_LIBNSL + handle = nwrap_main_global->libc->nsl_handle; + if (handle == NULL) { + for (handle = NULL, i = 10; handle == NULL && i >= 0; i--) { + char soname[256] = {0}; + + snprintf(soname, sizeof(soname), "libnsl.so.%d", i); + handle = dlopen(soname, flags); + } + + nwrap_main_global->libc->nsl_handle = handle; + } + break; +#endif + /* FALL TROUGH */ + case NWRAP_LIBSOCKET: +#ifdef HAVE_LIBSOCKET + handle = nwrap_main_global->libc->sock_handle; + if (handle == NULL) { + for (handle = NULL, i = 10; handle == NULL && i >= 0; i--) { + char soname[256] = {0}; + + snprintf(soname, sizeof(soname), "libsocket.so.%d", i); + handle = dlopen(soname, flags); + } + + nwrap_main_global->libc->sock_handle = handle; + } + break; +#endif + /* FALL TROUGH */ + case NWRAP_LIBC: + handle = nwrap_main_global->libc->handle; + if (handle == NULL) { + for (handle = NULL, i = 10; handle == NULL && i >= 0; i--) { + char soname[256] = {0}; + + snprintf(soname, sizeof(soname), "libc.so.%d", i); + handle = dlopen(soname, flags); + } + + nwrap_main_global->libc->handle = handle; + } + break; + } + + if (handle == NULL) { + NWRAP_LOG(NWRAP_LOG_ERROR, + "Failed to dlopen library: %s\n", + dlerror()); + exit(-1); + } + + return handle; +} + +static void *_nwrap_load_lib_function(enum nwrap_lib lib, const char *fn_name) +{ + void *handle; + void *func; + + nwrap_init(); + + handle = nwrap_load_lib_handle(lib); + + func = dlsym(handle, fn_name); + if (func == NULL) { + NWRAP_LOG(NWRAP_LOG_ERROR, + "Failed to find %s: %s\n", + fn_name, dlerror()); + exit(-1); + } + + NWRAP_LOG(NWRAP_LOG_TRACE, + "Loaded %s from %s", + fn_name, nwrap_str_lib(lib)); + return func; +} + +#define nwrap_load_lib_function(lib, fn_name) \ + if (nwrap_main_global->libc->fns->_libc_##fn_name == NULL) { \ + *(void **) (&nwrap_main_global->libc->fns->_libc_##fn_name) = \ + _nwrap_load_lib_function(lib, #fn_name); \ + } + +/* + * IMPORTANT + * + * Functions expeciall from libc need to be loaded individually, you can't load + * all at once or gdb will segfault at startup. The same applies to valgrind and + * has probably something todo with with the linker. + * So we need load each function at the point it is called the first time. + */ +static struct passwd *libc_getpwnam(const char *name) +{ + nwrap_load_lib_function(NWRAP_LIBC, getpwnam); + + return nwrap_main_global->libc->fns->_libc_getpwnam(name); +} + +#ifdef HAVE_GETPWNAM_R +static int libc_getpwnam_r(const char *name, + struct passwd *pwd, + char *buf, + size_t buflen, + struct passwd **result) +{ +#ifdef HAVE___POSIX_GETPWNAM_R + if (nwrap_main_global->libc->fns->_libc_getpwnam_r == NULL) { + *(void **) (&nwrap_main_global->libc->fns->_libc_getpwnam_r) = + _nwrap_load_lib_function(NWRAP_LIBC, "__posix_getpwnam_r"); + } +#else + nwrap_load_lib_function(NWRAP_LIBC, getpwnam_r); +#endif + + return nwrap_main_global->libc->fns->_libc_getpwnam_r(name, + pwd, + buf, + buflen, + result); +} +#endif + +static struct passwd *libc_getpwuid(uid_t uid) +{ + nwrap_load_lib_function(NWRAP_LIBC, getpwuid); + + return nwrap_main_global->libc->fns->_libc_getpwuid(uid); +} + +#ifdef HAVE_GETPWUID_R +static int libc_getpwuid_r(uid_t uid, + struct passwd *pwd, + char *buf, + size_t buflen, + struct passwd **result) +{ +#ifdef HAVE___POSIX_GETPWUID_R + if (nwrap_main_global->libc->fns->_libc_getpwuid_r == NULL) { + *(void **) (&nwrap_main_global->libc->fns->_libc_getpwuid_r) = + _nwrap_load_lib_function(NWRAP_LIBC, "__posix_getpwuid_r"); + } +#else + nwrap_load_lib_function(NWRAP_LIBC, getpwuid_r); +#endif + + return nwrap_main_global->libc->fns->_libc_getpwuid_r(uid, + pwd, + buf, + buflen, + result); +} +#endif + +static void libc_setpwent(void) +{ + nwrap_load_lib_function(NWRAP_LIBC, setpwent); + + nwrap_main_global->libc->fns->_libc_setpwent(); +} + +static struct passwd *libc_getpwent(void) +{ + nwrap_load_lib_function(NWRAP_LIBC, getpwent); + + return nwrap_main_global->libc->fns->_libc_getpwent(); +} + +#ifdef HAVE_SOLARIS_GETPWENT_R +static struct passwd *libc_getpwent_r(struct passwd *pwdst, + char *buf, + int buflen) +{ + nwrap_load_lib_function(NWRAP_LIBC, getpwent_r); + + return nwrap_main_global->libc->fns->_libc_getpwent_r(pwdst, + buf, + buflen); +} +#else /* HAVE_SOLARIS_GETPWENT_R */ +static int libc_getpwent_r(struct passwd *pwdst, + char *buf, + size_t buflen, + struct passwd **pwdstp) +{ + nwrap_load_lib_function(NWRAP_LIBC, getpwent_r); + + return nwrap_main_global->libc->fns->_libc_getpwent_r(pwdst, + buf, + buflen, + pwdstp); +} +#endif /* HAVE_SOLARIS_GETPWENT_R */ + +static void libc_endpwent(void) +{ + nwrap_load_lib_function(NWRAP_LIBC, endpwent); + + nwrap_main_global->libc->fns->_libc_endpwent(); +} + +static int libc_initgroups(const char *user, gid_t gid) +{ + nwrap_load_lib_function(NWRAP_LIBC, initgroups); + + return nwrap_main_global->libc->fns->_libc_initgroups(user, gid); +} + +static struct group *libc_getgrnam(const char *name) +{ + nwrap_load_lib_function(NWRAP_LIBC, getgrnam); + + return nwrap_main_global->libc->fns->_libc_getgrnam(name); +} + +#ifdef HAVE_GETGRNAM_R +static int libc_getgrnam_r(const char *name, + struct group *grp, + char *buf, + size_t buflen, + struct group **result) +{ +#ifdef HAVE___POSIX_GETGRNAM_R + if (nwrap_main_global->libc->fns->_libc_getgrnam_r == NULL) { + *(void **) (&nwrap_main_global->libc->fns->_libc_getgrnam_r) = + _nwrap_load_lib_function(NWRAP_LIBC, "__posix_getgrnam_r"); + } +#else + nwrap_load_lib_function(NWRAP_LIBC, getgrnam_r); +#endif + + return nwrap_main_global->libc->fns->_libc_getgrnam_r(name, + grp, + buf, + buflen, + result); +} +#endif + +static struct group *libc_getgrgid(gid_t gid) +{ + nwrap_load_lib_function(NWRAP_LIBC, getgrgid); + + return nwrap_main_global->libc->fns->_libc_getgrgid(gid); +} + +#ifdef HAVE_GETGRGID_R +static int libc_getgrgid_r(gid_t gid, + struct group *grp, + char *buf, + size_t buflen, + struct group **result) +{ +#ifdef HAVE___POSIX_GETGRGID_R + if (nwrap_main_global->libc->fns->_libc_getgrgid_r == NULL) { + *(void **) (&nwrap_main_global->libc->fns->_libc_getgrgid_r) = + _nwrap_load_lib_function(NWRAP_LIBC, "__posix_getgrgid_r"); + } +#else + nwrap_load_lib_function(NWRAP_LIBC, getgrgid_r); +#endif + + return nwrap_main_global->libc->fns->_libc_getgrgid_r(gid, + grp, + buf, + buflen, + result); +} +#endif + +static void libc_setgrent(void) +{ + nwrap_load_lib_function(NWRAP_LIBC, setgrent); + + nwrap_main_global->libc->fns->_libc_setgrent(); +} + +static struct group *libc_getgrent(void) +{ + nwrap_load_lib_function(NWRAP_LIBC, getgrent); + + return nwrap_main_global->libc->fns->_libc_getgrent(); +} + +#ifdef HAVE_GETGRENT_R +#ifdef HAVE_SOLARIS_GETGRENT_R +static struct group *libc_getgrent_r(struct group *group, + char *buf, + size_t buflen) +{ + nwrap_load_lib_function(NWRAP_LIBC, getgrent_r); + + return nwrap_main_global->libc->fns->_libc_getgrent_r(group, + buf, + buflen); +} +#else /* !HAVE_SOLARIS_GETGRENT_R */ +static int libc_getgrent_r(struct group *group, + char *buf, + size_t buflen, + struct group **result) +{ + nwrap_load_lib_function(NWRAP_LIBC, getgrent_r); + + return nwrap_main_global->libc->fns->_libc_getgrent_r(group, + buf, + buflen, + result); +} +#endif /* HAVE_SOLARIS_GETGRENT_R */ +#endif /* HAVE_GETGRENT_R */ + +static void libc_endgrent(void) +{ + nwrap_load_lib_function(NWRAP_LIBC, endgrent); + + nwrap_main_global->libc->fns->_libc_endgrent(); +} + +#ifdef HAVE_GETGROUPLIST +static int libc_getgrouplist(const char *user, + gid_t group, + gid_t *groups, + int *ngroups) +{ + nwrap_load_lib_function(NWRAP_LIBC, getgrouplist); + + return nwrap_main_global->libc->fns->_libc_getgrouplist(user, + group, + groups, + ngroups); +} +#endif + +static void libc_sethostent(int stayopen) +{ + nwrap_load_lib_function(NWRAP_LIBNSL, sethostent); + + nwrap_main_global->libc->fns->_libc_sethostent(stayopen); +} + +static struct hostent *libc_gethostent(void) +{ + nwrap_load_lib_function(NWRAP_LIBNSL, gethostent); + + return nwrap_main_global->libc->fns->_libc_gethostent(); +} + +static void libc_endhostent(void) +{ + nwrap_load_lib_function(NWRAP_LIBNSL, endhostent); + + nwrap_main_global->libc->fns->_libc_endhostent(); +} + +static struct hostent *libc_gethostbyname(const char *name) +{ + nwrap_load_lib_function(NWRAP_LIBNSL, gethostbyname); + + return nwrap_main_global->libc->fns->_libc_gethostbyname(name); +} + +#ifdef HAVE_GETHOSTBYNAME2 /* GNU extension */ +static struct hostent *libc_gethostbyname2(const char *name, int af) +{ + nwrap_load_lib_function(NWRAP_LIBNSL, gethostbyname2); + + return nwrap_main_global->libc->fns->_libc_gethostbyname2(name, af); +} +#endif + +static struct hostent *libc_gethostbyaddr(const void *addr, + socklen_t len, + int type) +{ + nwrap_load_lib_function(NWRAP_LIBNSL, gethostbyaddr); + + return nwrap_main_global->libc->fns->_libc_gethostbyaddr(addr, + len, + type); +} + +static int libc_gethostname(char *name, size_t len) +{ + nwrap_load_lib_function(NWRAP_LIBNSL, gethostname); + + return nwrap_main_global->libc->fns->_libc_gethostname(name, len); +} + +#ifdef HAVE_GETHOSTBYNAME_R +static int libc_gethostbyname_r(const char *name, + struct hostent *ret, + char *buf, + size_t buflen, + struct hostent **result, + int *h_errnop) +{ + nwrap_load_lib_function(NWRAP_LIBNSL, gethostbyname_r); + + return nwrap_main_global->libc->fns->_libc_gethostbyname_r(name, + ret, + buf, + buflen, + result, + h_errnop); +} +#endif + +#ifdef HAVE_GETHOSTBYADDR_R +static int libc_gethostbyaddr_r(const void *addr, + socklen_t len, + int type, + struct hostent *ret, + char *buf, + size_t buflen, + struct hostent **result, + int *h_errnop) +{ + nwrap_load_lib_function(NWRAP_LIBNSL, gethostbyaddr_r); + + return nwrap_main_global->libc->fns->_libc_gethostbyaddr_r(addr, + len, + type, + ret, + buf, + buflen, + result, + h_errnop); +} +#endif + +static int libc_getaddrinfo(const char *node, + const char *service, + const struct addrinfo *hints, + struct addrinfo **res) +{ + nwrap_load_lib_function(NWRAP_LIBSOCKET, getaddrinfo); + + return nwrap_main_global->libc->fns->_libc_getaddrinfo(node, + service, + hints, + res); +} + +static int libc_getnameinfo(const struct sockaddr *sa, + socklen_t salen, + char *host, + size_t hostlen, + char *serv, + size_t servlen, + int flags) +{ + nwrap_load_lib_function(NWRAP_LIBSOCKET, getnameinfo); + + return nwrap_main_global->libc->fns->_libc_getnameinfo(sa, + salen, + host, + hostlen, + serv, + servlen, + flags); +} + +/********************************************************* + * NWRAP NSS MODULE LOADER FUNCTIONS + *********************************************************/ static void *nwrap_load_module_fn(struct nwrap_backend *b, const char *fn_name) @@ -382,21 +1047,20 @@ static void *nwrap_load_module_fn(struct nwrap_backend *b, char *s; if (!b->so_handle) { - NWRAP_ERROR(("%s: no handle\n", - __location__)); + NWRAP_LOG(NWRAP_LOG_ERROR, "No handle"); return NULL; } if (asprintf(&s, "_nss_%s_%s", b->name, fn_name) == -1) { - NWRAP_ERROR(("%s: out of memory\n", - __location__)); + NWRAP_LOG(NWRAP_LOG_ERROR, "Out of memory"); return NULL; } res = dlsym(b->so_handle, s); if (!res) { - NWRAP_ERROR(("%s: cannot find function %s in %s\n", - __location__, s, b->so_path)); + NWRAP_LOG(NWRAP_LOG_ERROR, + "Cannot find function %s in %s", + s, b->so_path); } free(s); s = NULL; @@ -416,28 +1080,28 @@ static struct nwrap_module_nss_fns *nwrap_load_module_fns(struct nwrap_backend * return NULL; } - fns->_nss_getpwnam_r = (NSS_STATUS (*)(const char *, struct passwd *, char *, size_t, int *)) - nwrap_load_module_fn(b, "getpwnam_r"); - fns->_nss_getpwuid_r = (NSS_STATUS (*)(uid_t, struct passwd *, char *, size_t, int *)) - nwrap_load_module_fn(b, "getpwuid_r"); - fns->_nss_setpwent = (NSS_STATUS(*)(void)) - nwrap_load_module_fn(b, "setpwent"); - fns->_nss_getpwent_r = (NSS_STATUS (*)(struct passwd *, char *, size_t, int *)) - nwrap_load_module_fn(b, "getpwent_r"); - fns->_nss_endpwent = (NSS_STATUS(*)(void)) - nwrap_load_module_fn(b, "endpwent"); - fns->_nss_initgroups = (NSS_STATUS (*)(const char *, gid_t, long int *, long int *, gid_t **, long int, int *)) - nwrap_load_module_fn(b, "initgroups_dyn"); - fns->_nss_getgrnam_r = (NSS_STATUS (*)(const char *, struct group *, char *, size_t, int *)) - nwrap_load_module_fn(b, "getgrnam_r"); - fns->_nss_getgrgid_r = (NSS_STATUS (*)(gid_t, struct group *, char *, size_t, int *)) - nwrap_load_module_fn(b, "getgrgid_r"); - fns->_nss_setgrent = (NSS_STATUS(*)(void)) - nwrap_load_module_fn(b, "setgrent"); - fns->_nss_getgrent_r = (NSS_STATUS (*)(struct group *, char *, size_t, int *)) - nwrap_load_module_fn(b, "getgrent_r"); - fns->_nss_endgrent = (NSS_STATUS(*)(void)) - nwrap_load_module_fn(b, "endgrent"); + *(void **)(&fns->_nss_getpwnam_r) = + nwrap_load_module_fn(b, "getpwnam_r"); + *(void **)(&fns->_nss_getpwuid_r) = + nwrap_load_module_fn(b, "getpwuid_r"); + *(void **)(&fns->_nss_setpwent) = + nwrap_load_module_fn(b, "setpwent"); + *(void **)(&fns->_nss_getpwent_r) = + nwrap_load_module_fn(b, "getpwent_r"); + *(void **)(&fns->_nss_endpwent) = + nwrap_load_module_fn(b, "endpwent"); + *(void **)(&fns->_nss_initgroups) = + nwrap_load_module_fn(b, "initgroups_dyn"); + *(void **)(&fns->_nss_getgrnam_r) = + nwrap_load_module_fn(b, "getgrnam_r"); + *(void **)(&fns->_nss_getgrgid_r)= + nwrap_load_module_fn(b, "getgrgid_r"); + *(void **)(&fns->_nss_setgrent) = + nwrap_load_module_fn(b, "setgrent"); + *(void **)(&fns->_nss_getgrent_r) = + nwrap_load_module_fn(b, "getgrent_r"); + *(void **)(&fns->_nss_endgrent) = + nwrap_load_module_fn(b, "endgrent"); return fns; } @@ -452,8 +1116,9 @@ static void *nwrap_load_module(const char *so_path) h = dlopen(so_path, RTLD_LAZY); if (!h) { - NWRAP_ERROR(("%s: cannot open shared library %s\n", - __location__, so_path)); + NWRAP_LOG(NWRAP_LOG_ERROR, + "Cannot open shared library %s", + so_path); return NULL; } @@ -471,8 +1136,7 @@ static bool nwrap_module_init(const char *name, *backends = (struct nwrap_backend *)realloc(*backends, sizeof(struct nwrap_backend) * ((*num_backends) + 1)); if (!*backends) { - NWRAP_ERROR(("%s: out of memory\n", - __location__)); + NWRAP_LOG(NWRAP_LOG_ERROR, "Out of memory"); return false; } @@ -498,9 +1162,27 @@ static bool nwrap_module_init(const char *name, return true; } +static void nwrap_libc_init(struct nwrap_main *r) +{ + r->libc = malloc(sizeof(struct nwrap_libc)); + if (r->libc == NULL) { + printf("Failed to allocate memory for libc"); + exit(-1); + } + ZERO_STRUCTP(r->libc); + + r->libc->fns = malloc(sizeof(struct nwrap_libc_fns)); + if (r->libc->fns == NULL) { + printf("Failed to allocate memory for libc functions"); + exit(-1); + } + ZERO_STRUCTP(r->libc->fns); +} + static void nwrap_backend_init(struct nwrap_main *r) { - const char *winbind_so_path = getenv("NSS_WRAPPER_WINBIND_SO_PATH"); + const char *module_so_path = getenv("NSS_WRAPPER_MODULE_SO_PATH"); + const char *module_fn_name = getenv("NSS_WRAPPER_MODULE_FN_PREFIX"); r->num_backends = 0; r->backends = NULL; @@ -508,17 +1190,23 @@ static void nwrap_backend_init(struct nwrap_main *r) if (!nwrap_module_init("files", &nwrap_files_ops, NULL, &r->num_backends, &r->backends)) { - NWRAP_ERROR(("%s: failed to initialize 'files' backend\n", - __location__)); + NWRAP_LOG(NWRAP_LOG_ERROR, + "Failed to initialize 'files' backend"); return; } - if (winbind_so_path && strlen(winbind_so_path)) { - if (!nwrap_module_init("winbind", &nwrap_module_ops, winbind_so_path, + if (module_so_path != NULL && + module_so_path[0] != '\0' && + module_fn_name != NULL && + module_fn_name[0] != '\0') { + if (!nwrap_module_init(module_fn_name, + &nwrap_module_ops, + module_so_path, &r->num_backends, &r->backends)) { - NWRAP_ERROR(("%s: failed to initialize 'winbind' backend\n", - __location__)); + NWRAP_LOG(NWRAP_LOG_ERROR, + "Failed to initialize '%s' backend", + module_fn_name); return; } } @@ -533,6 +1221,8 @@ static void nwrap_init(void) nwrap_main_global = &__nwrap_main_global; + nwrap_libc_init(nwrap_main_global); + nwrap_backend_init(nwrap_main_global); nwrap_pw_global.cache = &__nwrap_cache_pw; @@ -550,22 +1240,49 @@ static void nwrap_init(void) nwrap_gr_global.cache->private_data = &nwrap_gr_global; nwrap_gr_global.cache->parse_line = nwrap_gr_parse_line; nwrap_gr_global.cache->unload = nwrap_gr_unload; + + nwrap_he_global.cache = &__nwrap_cache_he; + + nwrap_he_global.cache->path = getenv("NSS_WRAPPER_HOSTS"); + nwrap_he_global.cache->fd = -1; + nwrap_he_global.cache->private_data = &nwrap_he_global; + nwrap_he_global.cache->parse_line = nwrap_he_parse_line; + nwrap_he_global.cache->unload = nwrap_he_unload; } -static bool nwrap_enabled(void) +bool nss_wrapper_enabled(void) { nwrap_init(); - if (!nwrap_pw_global.cache->path) { + if (nwrap_pw_global.cache->path == NULL || + nwrap_pw_global.cache->path[0] == '\0') { return false; } - if (nwrap_pw_global.cache->path[0] == '\0') { + if (nwrap_gr_global.cache->path == NULL || + nwrap_gr_global.cache->path[0] == '\0') { return false; } - if (!nwrap_gr_global.cache->path) { + + return true; +} + +bool nss_wrapper_hosts_enabled(void) +{ + nwrap_init(); + + if (nwrap_he_global.cache->path == NULL || + nwrap_he_global.cache->path[0] == '\0') { return false; } - if (nwrap_gr_global.cache->path[0] == '\0') { + + return true; +} + +static bool nwrap_hostname_enabled(void) +{ + nwrap_init(); + + if (getenv("NSS_WRAPPER_HOSTNAME") == NULL) { return false; } @@ -579,40 +1296,41 @@ static bool nwrap_parse_file(struct nwrap_cache *nwrap) char *nline; if (nwrap->st.st_size == 0) { - NWRAP_DEBUG(("%s: size == 0\n", - __location__)); + NWRAP_LOG(NWRAP_LOG_DEBUG, "size == 0"); goto done; } if (nwrap->st.st_size > INT32_MAX) { - NWRAP_ERROR(("%s: size[%u] larger than INT32_MAX\n", - __location__, (unsigned)nwrap->st.st_size)); + NWRAP_LOG(NWRAP_LOG_ERROR, + "Size[%u] larger than INT32_MAX", + (unsigned)nwrap->st.st_size); goto failed; } ret = lseek(nwrap->fd, 0, SEEK_SET); if (ret != 0) { - NWRAP_ERROR(("%s: lseek - %d\n",__location__,ret)); + NWRAP_LOG(NWRAP_LOG_ERROR, "lseek - rc=%d\n", ret); goto failed; } buf = (uint8_t *)malloc(nwrap->st.st_size + 1); if (!buf) { - NWRAP_ERROR(("%s: malloc failed\n",__location__)); + NWRAP_LOG(NWRAP_LOG_ERROR, "Out of memory"); goto failed; } ret = read(nwrap->fd, buf, nwrap->st.st_size); if (ret != nwrap->st.st_size) { - NWRAP_ERROR(("%s: read(%u) gave %d\n", - __location__, (unsigned)nwrap->st.st_size, ret)); + NWRAP_LOG(NWRAP_LOG_ERROR, + "read(%u) rc=%d\n", + (unsigned)nwrap->st.st_size, ret); goto failed; } buf[nwrap->st.st_size] = '\0'; nline = (char *)buf; - while (nline && nline[0]) { + while (nline != NULL && nline[0] != '\0') { char *line; char *e; bool ok; @@ -631,8 +1349,6 @@ static bool nwrap_parse_file(struct nwrap_cache *nwrap) nline = e; } - NWRAP_VERBOSE(("%s:'%s'\n",__location__, line)); - if (strlen(line) == 0) { continue; } @@ -672,28 +1388,30 @@ reopen: if (nwrap->fd < 0) { nwrap->fd = open(nwrap->path, O_RDONLY); if (nwrap->fd < 0) { - NWRAP_ERROR(("%s: unable to open '%s' readonly %d:%s\n", - __location__, - nwrap->path, nwrap->fd, - strerror(errno))); + NWRAP_LOG(NWRAP_LOG_ERROR, + "Unable to open '%s' readonly %d:%s", + nwrap->path, nwrap->fd, + strerror(errno)); return; } - NWRAP_VERBOSE(("%s: open '%s'\n", __location__, nwrap->path)); + NWRAP_LOG(NWRAP_LOG_DEBUG, "Open '%s'", nwrap->path); } ret = fstat(nwrap->fd, &st); if (ret != 0) { - NWRAP_ERROR(("%s: fstat(%s) - %d:%s\n", - __location__, - nwrap->path, - ret, strerror(errno))); + NWRAP_LOG(NWRAP_LOG_ERROR, + "fstat(%s) - %d:%s", + nwrap->path, + ret, + strerror(errno)); return; } if (retried == false && st.st_nlink == 0) { /* maybe someone has replaced the file... */ - NWRAP_DEBUG(("%s: st_nlink == 0, reopen %s\n", - __location__, nwrap->path)); + NWRAP_LOG(NWRAP_LOG_TRACE, + "st_nlink == 0, reopen %s", + nwrap->path); retried = true; memset(&nwrap->st, 0, sizeof(nwrap->st)); close(nwrap->fd); @@ -702,13 +1420,16 @@ reopen: } if (st.st_mtime == nwrap->st.st_mtime) { - NWRAP_VERBOSE(("%s: st_mtime[%u] hasn't changed, skip reload\n", - __location__, (unsigned)st.st_mtime)); + NWRAP_LOG(NWRAP_LOG_TRACE, + "st_mtime[%u] hasn't changed, skip reload", + (unsigned)st.st_mtime); return; } - NWRAP_DEBUG(("%s: st_mtime has changed [%u] => [%u], start reload\n", - __location__, (unsigned)st.st_mtime, - (unsigned)nwrap->st.st_mtime)); + + NWRAP_LOG(NWRAP_LOG_TRACE, + "st_mtime has changed [%u] => [%u], start reload", + (unsigned)st.st_mtime, + (unsigned)nwrap->st.st_mtime); nwrap->st = st; @@ -716,12 +1437,11 @@ reopen: ok = nwrap_parse_file(nwrap); if (!ok) { - NWRAP_ERROR(("%s: failed to reload %s\n", - __location__, nwrap->path)); + NWRAP_LOG(NWRAP_LOG_ERROR, "Failed to reload %s", nwrap->path); nwrap_files_cache_unload(nwrap); } - NWRAP_DEBUG(("%s: reloaded %s\n", - __location__, nwrap->path)); + + NWRAP_LOG(NWRAP_LOG_TRACE, "Reloaded %s", nwrap->path); } /* @@ -741,8 +1461,9 @@ static bool nwrap_pw_parse_line(struct nwrap_cache *nwrap, char *line) list_size = sizeof(*nwrap_pw->list) * (nwrap_pw->num+1); pw = (struct passwd *)realloc(nwrap_pw->list, list_size); if (!pw) { - NWRAP_ERROR(("%s:realloc(%u) failed\n", - __location__, list_size)); + NWRAP_LOG(NWRAP_LOG_ERROR, + "realloc(%u) failed", + (unsigned)list_size); return false; } nwrap_pw->list = pw; @@ -754,8 +1475,10 @@ static bool nwrap_pw_parse_line(struct nwrap_cache *nwrap, char *line) /* name */ p = strchr(c, ':'); if (!p) { - NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n", - __location__, line, c)); + NWRAP_LOG(NWRAP_LOG_ERROR, + "Invalid line[%s]: '%s'", + line, + c); return false; } *p = '\0'; @@ -763,13 +1486,12 @@ static bool nwrap_pw_parse_line(struct nwrap_cache *nwrap, char *line) pw->pw_name = c; c = p; - NWRAP_VERBOSE(("name[%s]\n", pw->pw_name)); + NWRAP_LOG(NWRAP_LOG_TRACE, "name[%s]\n", pw->pw_name); /* password */ p = strchr(c, ':'); if (!p) { - NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n", - __location__, line, c)); + NWRAP_LOG(NWRAP_LOG_ERROR, "Invalid line[%s]: '%s'", line, c); return false; } *p = '\0'; @@ -777,13 +1499,12 @@ static bool nwrap_pw_parse_line(struct nwrap_cache *nwrap, char *line) pw->pw_passwd = c; c = p; - NWRAP_VERBOSE(("password[%s]\n", pw->pw_passwd)); + NWRAP_LOG(NWRAP_LOG_TRACE, "password[%s]\n", pw->pw_passwd); /* uid */ p = strchr(c, ':'); if (!p) { - NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n", - __location__, line, c)); + NWRAP_LOG(NWRAP_LOG_ERROR, "Invalid line[%s]: '%s'", line, c); return false; } *p = '\0'; @@ -791,29 +1512,31 @@ static bool nwrap_pw_parse_line(struct nwrap_cache *nwrap, char *line) e = NULL; pw->pw_uid = (uid_t)strtoul(c, &e, 10); if (c == e) { - NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n", - __location__, line, c, strerror(errno))); + NWRAP_LOG(NWRAP_LOG_ERROR, + "Invalid line[%s]: '%s' - %s", + line, c, strerror(errno)); return false; } if (e == NULL) { - NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n", - __location__, line, c, strerror(errno))); + NWRAP_LOG(NWRAP_LOG_ERROR, + "Invalid line[%s]: '%s' - %s", + line, c, strerror(errno)); return false; } if (e[0] != '\0') { - NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n", - __location__, line, c, strerror(errno))); + NWRAP_LOG(NWRAP_LOG_ERROR, + "Invalid line[%s]: '%s' - %s", + line, c, strerror(errno)); return false; } c = p; - NWRAP_VERBOSE(("uid[%u]\n", pw->pw_uid)); + NWRAP_LOG(NWRAP_LOG_TRACE, "uid[%u]", pw->pw_uid); /* gid */ p = strchr(c, ':'); if (!p) { - NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n", - __location__, line, c)); + NWRAP_LOG(NWRAP_LOG_ERROR, "Invalid line[%s]: '%s'", line, c); return false; } *p = '\0'; @@ -821,29 +1544,31 @@ static bool nwrap_pw_parse_line(struct nwrap_cache *nwrap, char *line) e = NULL; pw->pw_gid = (gid_t)strtoul(c, &e, 10); if (c == e) { - NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n", - __location__, line, c, strerror(errno))); + NWRAP_LOG(NWRAP_LOG_ERROR, + "Invalid line[%s]: '%s' - %s", + line, c, strerror(errno)); return false; } if (e == NULL) { - NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n", - __location__, line, c, strerror(errno))); + NWRAP_LOG(NWRAP_LOG_ERROR, + "Invalid line[%s]: '%s' - %s", + line, c, strerror(errno)); return false; } if (e[0] != '\0') { - NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n", - __location__, line, c, strerror(errno))); + NWRAP_LOG(NWRAP_LOG_ERROR, + "Invalid line[%s]: '%s' - %s", + line, c, strerror(errno)); return false; } c = p; - NWRAP_VERBOSE(("gid[%u]\n", pw->pw_gid)); + NWRAP_LOG(NWRAP_LOG_TRACE, "gid[%u]\n", pw->pw_gid); /* gecos */ p = strchr(c, ':'); if (!p) { - NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n", - __location__, line, c)); + NWRAP_LOG(NWRAP_LOG_ERROR, "invalid line[%s]: '%s'", line, c); return false; } *p = '\0'; @@ -851,12 +1576,12 @@ static bool nwrap_pw_parse_line(struct nwrap_cache *nwrap, char *line) pw->pw_gecos = c; c = p; - NWRAP_VERBOSE(("gecos[%s]\n", pw->pw_gecos)); + NWRAP_LOG(NWRAP_LOG_TRACE, "gecos[%s]", pw->pw_gecos); /* dir */ p = strchr(c, ':'); if (!p) { - NWRAP_ERROR(("%s:'%s'\n",__location__,c)); + NWRAP_LOG(NWRAP_LOG_ERROR, "'%s'", c); return false; } *p = '\0'; @@ -864,16 +1589,17 @@ static bool nwrap_pw_parse_line(struct nwrap_cache *nwrap, char *line) pw->pw_dir = c; c = p; - NWRAP_VERBOSE(("dir[%s]\n", pw->pw_dir)); + NWRAP_LOG(NWRAP_LOG_TRACE, "dir[%s]", pw->pw_dir); /* shell */ pw->pw_shell = c; - NWRAP_VERBOSE(("shell[%s]\n", pw->pw_shell)); + NWRAP_LOG(NWRAP_LOG_TRACE, "shell[%s]", pw->pw_shell); - NWRAP_DEBUG(("add user[%s:%s:%u:%u:%s:%s:%s]\n", - pw->pw_name, pw->pw_passwd, - pw->pw_uid, pw->pw_gid, - pw->pw_gecos, pw->pw_dir, pw->pw_shell)); + NWRAP_LOG(NWRAP_LOG_DEBUG, + "Added user[%s:%s:%u:%u:%s:%s:%s]", + pw->pw_name, pw->pw_passwd, + pw->pw_uid, pw->pw_gid, + pw->pw_gecos, pw->pw_dir, pw->pw_shell); nwrap_pw->num++; return true; @@ -905,7 +1631,7 @@ static int nwrap_pw_copy_r(const struct passwd *src, struct passwd *dst, ofs = PTR_DIFF(last + 1, first); - if (ofs > buflen) { + if (ofs > (off_t) buflen) { return ERANGE; } @@ -949,7 +1675,7 @@ static bool nwrap_gr_parse_line(struct nwrap_cache *nwrap, char *line) list_size = sizeof(*nwrap_gr->list) * (nwrap_gr->num+1); gr = (struct group *)realloc(nwrap_gr->list, list_size); if (!gr) { - NWRAP_ERROR(("%s:realloc failed\n",__location__)); + NWRAP_LOG(NWRAP_LOG_ERROR, "realloc failed"); return false; } nwrap_gr->list = gr; @@ -961,8 +1687,7 @@ static bool nwrap_gr_parse_line(struct nwrap_cache *nwrap, char *line) /* name */ p = strchr(c, ':'); if (!p) { - NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n", - __location__, line, c)); + NWRAP_LOG(NWRAP_LOG_ERROR, "Invalid line[%s]: '%s'", line, c); return false; } *p = '\0'; @@ -970,13 +1695,12 @@ static bool nwrap_gr_parse_line(struct nwrap_cache *nwrap, char *line) gr->gr_name = c; c = p; - NWRAP_VERBOSE(("name[%s]\n", gr->gr_name)); + NWRAP_LOG(NWRAP_LOG_TRACE, "name[%s]", gr->gr_name); /* password */ p = strchr(c, ':'); if (!p) { - NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n", - __location__, line, c)); + NWRAP_LOG(NWRAP_LOG_ERROR, "Invalid line[%s]: '%s'", line, c); return false; } *p = '\0'; @@ -984,13 +1708,12 @@ static bool nwrap_gr_parse_line(struct nwrap_cache *nwrap, char *line) gr->gr_passwd = c; c = p; - NWRAP_VERBOSE(("password[%s]\n", gr->gr_passwd)); + NWRAP_LOG(NWRAP_LOG_TRACE, "password[%s]", gr->gr_passwd); /* gid */ p = strchr(c, ':'); if (!p) { - NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n", - __location__, line, c)); + NWRAP_LOG(NWRAP_LOG_ERROR, "Invalid line[%s]: '%s'", line, c); return false; } *p = '\0'; @@ -998,28 +1721,31 @@ static bool nwrap_gr_parse_line(struct nwrap_cache *nwrap, char *line) e = NULL; gr->gr_gid = (gid_t)strtoul(c, &e, 10); if (c == e) { - NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n", - __location__, line, c, strerror(errno))); + NWRAP_LOG(NWRAP_LOG_ERROR, + "Invalid line[%s]: '%s' - %s", + line, c, strerror(errno)); return false; } if (e == NULL) { - NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n", - __location__, line, c, strerror(errno))); + NWRAP_LOG(NWRAP_LOG_ERROR, + "Invalid line[%s]: '%s' - %s", + line, c, strerror(errno)); return false; } if (e[0] != '\0') { - NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n", - __location__, line, c, strerror(errno))); + NWRAP_LOG(NWRAP_LOG_ERROR, + "Invalid line[%s]: '%s' - %s", + line, c, strerror(errno)); return false; } c = p; - NWRAP_VERBOSE(("gid[%u]\n", gr->gr_gid)); + NWRAP_LOG(NWRAP_LOG_TRACE, "gid[%u]", gr->gr_gid); /* members */ gr->gr_mem = (char **)malloc(sizeof(char *)); if (!gr->gr_mem) { - NWRAP_ERROR(("%s:calloc failed\n",__location__)); + NWRAP_LOG(NWRAP_LOG_ERROR, "Out of memory"); return false; } gr->gr_mem[0] = NULL; @@ -1041,19 +1767,23 @@ static bool nwrap_gr_parse_line(struct nwrap_cache *nwrap, char *line) m_size = sizeof(char *) * (nummem+2); m = (char **)realloc(gr->gr_mem, m_size); if (!m) { - NWRAP_ERROR(("%s:realloc(%u) failed\n", - __location__, m_size)); + NWRAP_LOG(NWRAP_LOG_ERROR, + "realloc(%zd) failed", + m_size); return false; } gr->gr_mem = m; gr->gr_mem[nummem] = c; gr->gr_mem[nummem+1] = NULL; - NWRAP_VERBOSE(("member[%u]: '%s'\n", nummem, gr->gr_mem[nummem])); + NWRAP_LOG(NWRAP_LOG_TRACE, + "member[%u]: '%s'", + nummem, gr->gr_mem[nummem]); } - NWRAP_DEBUG(("add group[%s:%s:%u:] with %u members\n", - gr->gr_name, gr->gr_passwd, gr->gr_gid, nummem)); + NWRAP_LOG(NWRAP_LOG_DEBUG, + "Added group[%s:%s:%u:] with %u members", + gr->gr_name, gr->gr_passwd, gr->gr_gid, nummem); nwrap_gr->num++; return true; @@ -1106,7 +1836,7 @@ static int nwrap_gr_copy_r(const struct group *src, struct group *dst, ofsb = PTR_DIFF(last + 1, first); ofsm = PTR_DIFF(lastm + 1, src->gr_mem); - if ((ofsb + ofsm) > buflen) { + if ((ofsb + ofsm) > (off_t) buflen) { return ERANGE; } @@ -1132,26 +1862,212 @@ static int nwrap_gr_copy_r(const struct group *src, struct group *dst, return 0; } +static bool nwrap_he_parse_line(struct nwrap_cache *nwrap, char *line) +{ + struct nwrap_he *nwrap_he = (struct nwrap_he *)nwrap->private_data; + struct nwrap_entdata *ed; + size_t list_size; + bool do_aliases = true; + int aliases_count = 0; + char *p; + char *i; + char *n; + + list_size = sizeof(struct nwrap_entdata) * (nwrap_he->num + 1); + + ed = (struct nwrap_entdata *)realloc(nwrap_he->list, list_size); + if (ed == NULL) { + NWRAP_LOG(NWRAP_LOG_ERROR, "realloc[%zd] failed", list_size); + return false; + } + nwrap_he->list = ed; + + /* set it to the last element */ + ed = &(nwrap_he->list[nwrap_he->num]); + + ed->addr = malloc(sizeof(struct nwrap_addrdata)); + if (ed->addr == NULL) { + NWRAP_LOG(NWRAP_LOG_ERROR, "realloc[%zd] failed", list_size); + return false; + } + + i = line; + + /* + * IP + */ + + /* Walk to first char */ + for (p = i; *p != '.' && *p != ':' && !isxdigit((int) *p); p++) { + if (*p == '\0') { + NWRAP_LOG(NWRAP_LOG_ERROR, + "Invalid line[%s]: '%s'", + line, i); + return false; + } + } + + for (i = p; !isspace((int)*p); p++) { + if (*p == '\0') { + NWRAP_LOG(NWRAP_LOG_ERROR, + "Invalid line[%s]: '%s'", + line, i); + return false; + } + } + + *p = '\0'; + + if (inet_pton(AF_INET, i, ed->addr->host_addr)) { + ed->ht.h_addrtype = AF_INET; + ed->ht.h_length = 4; +#ifdef HAVE_IPV6 + } else if (inet_pton(AF_INET6, i, ed->addr->host_addr)) { + ed->ht.h_addrtype = AF_INET6; + ed->ht.h_length = 16; +#endif + } else { + NWRAP_LOG(NWRAP_LOG_ERROR, + "Invalid line[%s]: '%s'", + line, i); + + return false; + } + + ed->addr->h_addr_ptrs[0] = (char *)ed->addr->host_addr; + ed->addr->h_addr_ptrs[1] = NULL; + + ed->ht.h_addr_list = ed->addr->h_addr_ptrs; + + p++; + + /* + * FQDN + */ + + /* Walk to first char */ + for (n = p; *p != '_' && !isalnum((int) *p); p++) { + if (*p == '\0') { + NWRAP_LOG(NWRAP_LOG_ERROR, + "Invalid line[%s]: '%s'", + line, n); + + return false; + } + } + + for (n = p; !isspace((int)*p); p++) { + if (*p == '\0') { + do_aliases = false; + break; + } + } + + *p = '\0'; + + ed->ht.h_name = n; + + /* glib's getent always dereferences he->h_aliases */ + ed->ht.h_aliases = malloc(sizeof(char *)); + if (ed->ht.h_aliases == NULL) { + return false; + } + ed->ht.h_aliases[0] = NULL; + + /* + * Aliases + */ + while (do_aliases) { + char **aliases; + char *a; + + p++; + + /* Walk to first char */ + for (a = p; *p != '_' && !isalnum((int) *p); p++) { + if (*p == '\0') { + do_aliases = false; + break; + } + } + /* Only trailing spaces are left */ + if (!do_aliases) { + break; + } + + for (a = p; !isspace((int)*p); p++) { + if (*p == '\0') { + do_aliases = false; + break; + } + } + + *p = '\0'; + + aliases = realloc(ed->ht.h_aliases, sizeof(char *) * (aliases_count + 2)); + if (aliases == NULL) { + return false; + } + ed->ht.h_aliases = aliases; + + aliases[aliases_count] = a; + aliases[aliases_count + 1] = NULL; + + aliases_count++; + } + + nwrap_he->num++; + return true; +} + +static void nwrap_he_unload(struct nwrap_cache *nwrap) +{ + struct nwrap_he *nwrap_he = + (struct nwrap_he *)nwrap->private_data; + int i; + + if (nwrap_he->list != NULL) { + for (i = 0; i < nwrap_he->num; i++) { + if (nwrap_he->list[i].ht.h_aliases != NULL) { + free(nwrap_he->list[i].ht.h_aliases); + } + if (nwrap_he->list[i].addr != NULL) { + free(nwrap_he->list[i].addr); + } + } + free(nwrap_he->list); + } + + nwrap_he->list = NULL; + nwrap_he->num = 0; + nwrap_he->idx = 0; +} + + /* user functions */ static struct passwd *nwrap_files_getpwnam(struct nwrap_backend *b, const char *name) { int i; + (void) b; /* unused */ + + NWRAP_LOG(NWRAP_LOG_DEBUG, "Lookup user %s in files", name); + nwrap_files_cache_reload(nwrap_pw_global.cache); for (i=0; i<nwrap_pw_global.num; i++) { if (strcmp(nwrap_pw_global.list[i].pw_name, name) == 0) { - NWRAP_DEBUG(("%s: user[%s] found\n", - __location__, name)); + NWRAP_LOG(NWRAP_LOG_DEBUG, "user[%s] found", name); return &nwrap_pw_global.list[i]; } - NWRAP_VERBOSE(("%s: user[%s] does not match [%s]\n", - __location__, name, - nwrap_pw_global.list[i].pw_name)); + NWRAP_LOG(NWRAP_LOG_DEBUG, + "user[%s] does not match [%s]", + name, + nwrap_pw_global.list[i].pw_name); } - NWRAP_DEBUG(("%s: user[%s] not found\n", __location__, name)); + NWRAP_LOG(NWRAP_LOG_DEBUG, "user[%s] not found\n", name); errno = ENOENT; return NULL; @@ -1179,20 +2095,22 @@ static struct passwd *nwrap_files_getpwuid(struct nwrap_backend *b, { int i; + (void) b; /* unused */ + nwrap_files_cache_reload(nwrap_pw_global.cache); for (i=0; i<nwrap_pw_global.num; i++) { if (nwrap_pw_global.list[i].pw_uid == uid) { - NWRAP_DEBUG(("%s: uid[%u] found\n", - __location__, uid)); + NWRAP_LOG(NWRAP_LOG_DEBUG, "uid[%u] found", uid); return &nwrap_pw_global.list[i]; } - NWRAP_VERBOSE(("%s: uid[%u] does not match [%u]\n", - __location__, uid, - nwrap_pw_global.list[i].pw_uid)); + NWRAP_LOG(NWRAP_LOG_DEBUG, + "uid[%u] does not match [%u]", + uid, + nwrap_pw_global.list[i].pw_uid); } - NWRAP_DEBUG(("%s: uid[%u] not found\n", __location__, uid)); + NWRAP_LOG(NWRAP_LOG_DEBUG, "uid[%u] not found\n", uid); errno = ENOENT; return NULL; @@ -1218,6 +2136,8 @@ static int nwrap_files_getpwuid_r(struct nwrap_backend *b, /* user enum functions */ static void nwrap_files_setpwent(struct nwrap_backend *b) { + (void) b; /* unused */ + nwrap_pw_global.idx = 0; } @@ -1225,6 +2145,8 @@ static struct passwd *nwrap_files_getpwent(struct nwrap_backend *b) { struct passwd *pw; + (void) b; /* unused */ + if (nwrap_pw_global.idx == 0) { nwrap_files_cache_reload(nwrap_pw_global.cache); } @@ -1236,8 +2158,9 @@ static struct passwd *nwrap_files_getpwent(struct nwrap_backend *b) pw = &nwrap_pw_global.list[nwrap_pw_global.idx++]; - NWRAP_VERBOSE(("%s: return user[%s] uid[%u]\n", - __location__, pw->pw_name, pw->pw_uid)); + NWRAP_LOG(NWRAP_LOG_DEBUG, + "return user[%s] uid[%u]", + pw->pw_name, pw->pw_uid); return pw; } @@ -1261,6 +2184,8 @@ static int nwrap_files_getpwent_r(struct nwrap_backend *b, static void nwrap_files_endpwent(struct nwrap_backend *b) { + (void) b; /* unused */ + nwrap_pw_global.idx = 0; } @@ -1268,6 +2193,10 @@ static void nwrap_files_endpwent(struct nwrap_backend *b) static int nwrap_files_initgroups(struct nwrap_backend *b, const char *user, gid_t group) { + (void) b; /* unused */ + (void) user; /* unused */ + (void) group; /* used */ + /* TODO: maybe we should also fake this... */ return EPERM; } @@ -1278,20 +2207,22 @@ static struct group *nwrap_files_getgrnam(struct nwrap_backend *b, { int i; + (void) b; /* unused */ + nwrap_files_cache_reload(nwrap_gr_global.cache); for (i=0; i<nwrap_gr_global.num; i++) { if (strcmp(nwrap_gr_global.list[i].gr_name, name) == 0) { - NWRAP_DEBUG(("%s: group[%s] found\n", - __location__, name)); + NWRAP_LOG(NWRAP_LOG_DEBUG, "group[%s] found", name); return &nwrap_gr_global.list[i]; } - NWRAP_VERBOSE(("%s: group[%s] does not match [%s]\n", - __location__, name, - nwrap_gr_global.list[i].gr_name)); + NWRAP_LOG(NWRAP_LOG_DEBUG, + "group[%s] does not match [%s]", + name, + nwrap_gr_global.list[i].gr_name); } - NWRAP_DEBUG(("%s: group[%s] not found\n", __location__, name)); + NWRAP_LOG(NWRAP_LOG_DEBUG, "group[%s] not found", name); errno = ENOENT; return NULL; @@ -1319,20 +2250,22 @@ static struct group *nwrap_files_getgrgid(struct nwrap_backend *b, { int i; + (void) b; /* unused */ + nwrap_files_cache_reload(nwrap_gr_global.cache); for (i=0; i<nwrap_gr_global.num; i++) { if (nwrap_gr_global.list[i].gr_gid == gid) { - NWRAP_DEBUG(("%s: gid[%u] found\n", - __location__, gid)); + NWRAP_LOG(NWRAP_LOG_DEBUG, "gid[%u] found", gid); return &nwrap_gr_global.list[i]; } - NWRAP_VERBOSE(("%s: gid[%u] does not match [%u]\n", - __location__, gid, - nwrap_gr_global.list[i].gr_gid)); + NWRAP_LOG(NWRAP_LOG_DEBUG, + "gid[%u] does not match [%u]", + gid, + nwrap_gr_global.list[i].gr_gid); } - NWRAP_DEBUG(("%s: gid[%u] not found\n", __location__, gid)); + NWRAP_LOG(NWRAP_LOG_DEBUG, "gid[%u] not found", gid); errno = ENOENT; return NULL; @@ -1358,6 +2291,8 @@ static int nwrap_files_getgrgid_r(struct nwrap_backend *b, /* group enum functions */ static void nwrap_files_setgrent(struct nwrap_backend *b) { + (void) b; /* unused */ + nwrap_gr_global.idx = 0; } @@ -1365,6 +2300,8 @@ static struct group *nwrap_files_getgrent(struct nwrap_backend *b) { struct group *gr; + (void) b; /* unused */ + if (nwrap_gr_global.idx == 0) { nwrap_files_cache_reload(nwrap_gr_global.cache); } @@ -1376,8 +2313,9 @@ static struct group *nwrap_files_getgrent(struct nwrap_backend *b) gr = &nwrap_gr_global.list[nwrap_gr_global.idx++]; - NWRAP_VERBOSE(("%s: return group[%s] gid[%u]\n", - __location__, gr->gr_name, gr->gr_gid)); + NWRAP_LOG(NWRAP_LOG_DEBUG, + "return group[%s] gid[%u]", + gr->gr_name, gr->gr_gid); return gr; } @@ -1401,9 +2339,189 @@ static int nwrap_files_getgrent_r(struct nwrap_backend *b, static void nwrap_files_endgrent(struct nwrap_backend *b) { + (void) b; /* unused */ + nwrap_gr_global.idx = 0; } +/* hosts functions */ +static struct hostent *nwrap_files_gethostbyname(const char *name, int af) +{ + struct hostent *he; + int i; + + nwrap_files_cache_reload(nwrap_he_global.cache); + + for (i = 0; i < nwrap_he_global.num; i++) { + int j; + + he = &nwrap_he_global.list[i].ht; + + /* Filter by address familiy if provided */ + if (af != AF_UNSPEC && he->h_addrtype != af) { + continue; + } + + if (strcasecmp(he->h_name, name) == 0) { + NWRAP_LOG(NWRAP_LOG_DEBUG, "name[%s] found", name); + return he; + } + + if (he->h_aliases == NULL) { + continue; + } + + for (j = 0; he->h_aliases[j] != NULL; j++) { + if (strcasecmp(he->h_aliases[j], name) == 0) { + NWRAP_LOG(NWRAP_LOG_DEBUG, + "name[%s] found", + name); + return he; + } + } + } + + errno = ENOENT; + return NULL; +} + +#ifdef HAVE_GETHOSTBYNAME_R +static int nwrap_gethostbyname_r(const char *name, + struct hostent *ret, + char *buf, size_t buflen, + struct hostent **result, int *h_errnop) +{ + *result = nwrap_files_gethostbyname(name, AF_UNSPEC); + if (*result != NULL) { + memset(buf, '\0', buflen); + *ret = **result; + return 0; + } else { + *h_errnop = h_errno; + return -1; + } +} + +int gethostbyname_r(const char *name, + struct hostent *ret, + char *buf, size_t buflen, + struct hostent **result, int *h_errnop) +{ + if (!nss_wrapper_hosts_enabled()) { + return libc_gethostbyname_r(name, + ret, + buf, + buflen, + result, + h_errnop); + } + + return nwrap_gethostbyname_r(name, ret, buf, buflen, result, h_errnop); +} +#endif + +static struct hostent *nwrap_files_gethostbyaddr(const void *addr, + socklen_t len, int type) +{ + struct hostent *he; + char ip[INET6_ADDRSTRLEN] = {0}; + const char *a; + int i; + + (void) len; /* unused */ + + nwrap_files_cache_reload(nwrap_he_global.cache); + + a = inet_ntop(type, addr, ip, sizeof(ip)); + if (a == NULL) { + errno = EINVAL; + return NULL; + } + + for (i = 0; i < nwrap_he_global.num; i++) { + he = &nwrap_he_global.list[i].ht; + + if (he->h_addrtype != type) { + continue; + } + + if (memcmp(addr, he->h_addr_list[0], he->h_length) == 0) { + return he; + } + } + + errno = ENOENT; + return NULL; +} + +#ifdef HAVE_GETHOSTBYADDR_R +static int nwrap_gethostbyaddr_r(const void *addr, socklen_t len, int type, + struct hostent *ret, + char *buf, size_t buflen, + struct hostent **result, int *h_errnop) +{ + *result = nwrap_files_gethostbyaddr(addr, len, type); + if (*result != NULL) { + memset(buf, '\0', buflen); + *ret = **result; + return 0; + } else { + *h_errnop = h_errno; + return -1; + } +} + +int gethostbyaddr_r(const void *addr, socklen_t len, int type, + struct hostent *ret, + char *buf, size_t buflen, + struct hostent **result, int *h_errnop) +{ + if (!nss_wrapper_hosts_enabled()) { + return libc_gethostbyaddr_r(addr, + len, + type, + ret, + buf, + buflen, + result, + h_errnop); + } + + return nwrap_gethostbyaddr_r(addr, len, type, ret, buf, buflen, result, h_errnop); +} +#endif + +/* hosts enum functions */ +static void nwrap_files_sethostent(void) +{ + nwrap_he_global.idx = 0; +} + +static struct hostent *nwrap_files_gethostent(void) +{ + struct hostent *he; + + if (nwrap_he_global.idx == 0) { + nwrap_files_cache_reload(nwrap_he_global.cache); + } + + if (nwrap_he_global.idx >= nwrap_he_global.num) { + errno = ENOENT; + return NULL; + } + + he = &nwrap_he_global.list[nwrap_he_global.idx++].ht; + + NWRAP_LOG(NWRAP_LOG_DEBUG, "return hosts[%s]", he->h_name); + + return he; +} + +static void nwrap_files_endhostent(void) +{ + nwrap_he_global.idx = 0; +} + /* * module backend */ @@ -1430,6 +2548,7 @@ static struct passwd *nwrap_module_getpwnam(struct nwrap_backend *b, if (status != NSS_STATUS_SUCCESS) { return NULL; } + return &pwd; } @@ -1439,6 +2558,10 @@ static int nwrap_module_getpwnam_r(struct nwrap_backend *b, { int ret; + (void) b; /* unused */ + (void) pwdst; /* unused */ + (void) pwdstp; /* unused */ + if (!b->fns->_nss_getpwnam_r) { return NSS_STATUS_NOTFOUND; } @@ -1492,6 +2615,8 @@ static int nwrap_module_getpwuid_r(struct nwrap_backend *b, { int ret; + (void) pwdstp; /* unused */ + if (!b->fns->_nss_getpwuid_r) { return ENOENT; } @@ -1553,6 +2678,8 @@ static int nwrap_module_getpwent_r(struct nwrap_backend *b, { int ret; + (void) pwdstp; /* unused */ + if (!b->fns->_nss_getpwent_r) { return ENOENT; } @@ -1644,6 +2771,8 @@ static int nwrap_module_getgrnam_r(struct nwrap_backend *b, { int ret; + (void) grdstp; /* unused */ + if (!b->fns->_nss_getgrnam_r) { return ENOENT; } @@ -1713,6 +2842,8 @@ static int nwrap_module_getgrgid_r(struct nwrap_backend *b, { int ret; + (void) grdstp; /* unused */ + if (!b->fns->_nss_getgrgid_r) { return ENOENT; } @@ -1790,6 +2921,8 @@ static int nwrap_module_getgrent_r(struct nwrap_backend *b, { int ret; + (void) grdstp; /* unused */ + if (!b->fns->_nss_getgrent_r) { return ENOENT; } @@ -1825,19 +2958,15 @@ static void nwrap_module_endgrent(struct nwrap_backend *b) b->fns->_nss_endgrent(); } -/* - * PUBLIC interface - */ +/**************************************************************************** + * GETPWNAM + ***************************************************************************/ -_PUBLIC_ struct passwd *nwrap_getpwnam(const char *name) +static struct passwd *nwrap_getpwnam(const char *name) { int i; struct passwd *pwd; - if (!nwrap_enabled()) { - return real_getpwnam(name); - } - for (i=0; i < nwrap_main_global->num_backends; i++) { struct nwrap_backend *b = &nwrap_main_global->backends[i]; pwd = b->ops->nw_getpwnam(b, name); @@ -1849,15 +2978,24 @@ _PUBLIC_ struct passwd *nwrap_getpwnam(const char *name) return NULL; } -_PUBLIC_ int nwrap_getpwnam_r(const char *name, struct passwd *pwdst, - char *buf, size_t buflen, struct passwd **pwdstp) +struct passwd *getpwnam(const char *name) { - int i,ret; - - if (!nwrap_enabled()) { - return real_getpwnam_r(name, pwdst, buf, buflen, pwdstp); + if (!nss_wrapper_enabled()) { + return libc_getpwnam(name); } + return nwrap_getpwnam(name); +} + +/**************************************************************************** + * GETPWNAM_R + ***************************************************************************/ + +static int nwrap_getpwnam_r(const char *name, struct passwd *pwdst, + char *buf, size_t buflen, struct passwd **pwdstp) +{ + int i,ret; + for (i=0; i < nwrap_main_global->num_backends; i++) { struct nwrap_backend *b = &nwrap_main_global->backends[i]; ret = b->ops->nw_getpwnam_r(b, name, pwdst, buf, buflen, pwdstp); @@ -1870,15 +3008,32 @@ _PUBLIC_ int nwrap_getpwnam_r(const char *name, struct passwd *pwdst, return ENOENT; } -_PUBLIC_ struct passwd *nwrap_getpwuid(uid_t uid) +#ifdef HAVE_GETPWNAM_R +# ifdef HAVE_SOLARIS_GETPWNAM_R +int getpwnam_r(const char *name, struct passwd *pwdst, + char *buf, int buflen, struct passwd **pwdstp) +# else /* HAVE_SOLARIS_GETPWNAM_R */ +int getpwnam_r(const char *name, struct passwd *pwdst, + char *buf, size_t buflen, struct passwd **pwdstp) +# endif /* HAVE_SOLARIS_GETPWNAM_R */ +{ + if (!nss_wrapper_enabled()) { + return libc_getpwnam_r(name, pwdst, buf, buflen, pwdstp); + } + + return nwrap_getpwnam_r(name, pwdst, buf, buflen, pwdstp); +} +#endif + +/**************************************************************************** + * GETPWUID + ***************************************************************************/ + +static struct passwd *nwrap_getpwuid(uid_t uid) { int i; struct passwd *pwd; - if (!nwrap_enabled()) { - return real_getpwuid(uid); - } - for (i=0; i < nwrap_main_global->num_backends; i++) { struct nwrap_backend *b = &nwrap_main_global->backends[i]; pwd = b->ops->nw_getpwuid(b, uid); @@ -1890,15 +3045,24 @@ _PUBLIC_ struct passwd *nwrap_getpwuid(uid_t uid) return NULL; } -_PUBLIC_ int nwrap_getpwuid_r(uid_t uid, struct passwd *pwdst, - char *buf, size_t buflen, struct passwd **pwdstp) +struct passwd *getpwuid(uid_t uid) { - int i,ret; - - if (!nwrap_enabled()) { - return real_getpwuid_r(uid, pwdst, buf, buflen, pwdstp); + if (!nss_wrapper_enabled()) { + return libc_getpwuid(uid); } + return nwrap_getpwuid(uid); +} + +/**************************************************************************** + * GETPWUID_R + ***************************************************************************/ + +static int nwrap_getpwuid_r(uid_t uid, struct passwd *pwdst, + char *buf, size_t buflen, struct passwd **pwdstp) +{ + int i,ret; + for (i=0; i < nwrap_main_global->num_backends; i++) { struct nwrap_backend *b = &nwrap_main_global->backends[i]; ret = b->ops->nw_getpwuid_r(b, uid, pwdst, buf, buflen, pwdstp); @@ -1911,30 +3075,54 @@ _PUBLIC_ int nwrap_getpwuid_r(uid_t uid, struct passwd *pwdst, return ENOENT; } -_PUBLIC_ void nwrap_setpwent(void) +#ifdef HAVE_SOLARIS_GETPWUID_R +int getpwuid_r(uid_t uid, struct passwd *pwdst, + char *buf, int buflen, struct passwd **pwdstp) +#else +int getpwuid_r(uid_t uid, struct passwd *pwdst, + char *buf, size_t buflen, struct passwd **pwdstp) +#endif { - int i; - - if (!nwrap_enabled()) { - real_setpwent(); - return; + if (!nss_wrapper_enabled()) { + return libc_getpwuid_r(uid, pwdst, buf, buflen, pwdstp); } + return nwrap_getpwuid_r(uid, pwdst, buf, buflen, pwdstp); +} + +/**************************************************************************** + * SETPWENT + ***************************************************************************/ + +static void nwrap_setpwent(void) +{ + int i; + for (i=0; i < nwrap_main_global->num_backends; i++) { struct nwrap_backend *b = &nwrap_main_global->backends[i]; b->ops->nw_setpwent(b); } } -_PUBLIC_ struct passwd *nwrap_getpwent(void) +void setpwent(void) +{ + if (!nss_wrapper_enabled()) { + libc_setpwent(); + return; + } + + nwrap_setpwent(); +} + +/**************************************************************************** + * GETPWENT + ***************************************************************************/ + +static struct passwd *nwrap_getpwent(void) { int i; struct passwd *pwd; - if (!nwrap_enabled()) { - return real_getpwent(); - } - for (i=0; i < nwrap_main_global->num_backends; i++) { struct nwrap_backend *b = &nwrap_main_global->backends[i]; pwd = b->ops->nw_getpwent(b); @@ -1946,30 +3134,24 @@ _PUBLIC_ struct passwd *nwrap_getpwent(void) return NULL; } -_PUBLIC_ int nwrap_getpwent_r(struct passwd *pwdst, char *buf, - size_t buflen, struct passwd **pwdstp) +struct passwd *getpwent(void) { - int i,ret; - - if (!nwrap_enabled()) { -#ifdef SOLARIS_GETPWENT_R - struct passwd *pw; - pw = real_getpwent_r(pwdst, buf, buflen); - if (!pw) { - if (errno == 0) { - return ENOENT; - } - return errno; - } - if (pwdstp) { - *pwdstp = pw; - } - return 0; -#else - return real_getpwent_r(pwdst, buf, buflen, pwdstp); -#endif + if (!nss_wrapper_enabled()) { + return libc_getpwent(); } + return nwrap_getpwent(); +} + +/**************************************************************************** + * GETPWENT_R + ***************************************************************************/ + +static int nwrap_getpwent_r(struct passwd *pwdst, char *buf, + size_t buflen, struct passwd **pwdstp) +{ + int i,ret; + for (i=0; i < nwrap_main_global->num_backends; i++) { struct nwrap_backend *b = &nwrap_main_global->backends[i]; ret = b->ops->nw_getpwent_r(b, pwdst, buf, buflen, pwdstp); @@ -1982,14 +3164,41 @@ _PUBLIC_ int nwrap_getpwent_r(struct passwd *pwdst, char *buf, return ENOENT; } -_PUBLIC_ void nwrap_endpwent(void) +#ifdef HAVE_SOLARIS_GETPWENT_R +struct passwd *getpwent_r(struct passwd *pwdst, char *buf, int buflen) { - int i; + struct passwd *pwdstp = NULL; + int rc; - if (!nwrap_enabled()) { - real_endpwent(); - return; + if (!nss_wrapper_enabled()) { + return libc_getpwent_r(pwdst, buf, buflen); } + rc = nwrap_getpwent_r(pwdst, buf, buflen, &pwdstp); + if (rc < 0) { + return NULL; + } + + return pwdstp; +} +#else /* HAVE_SOLARIS_GETPWENT_R */ +int getpwent_r(struct passwd *pwdst, char *buf, + size_t buflen, struct passwd **pwdstp) +{ + if (!nss_wrapper_enabled()) { + return libc_getpwent_r(pwdst, buf, buflen, pwdstp); + } + + return nwrap_getpwent_r(pwdst, buf, buflen, pwdstp); +} +#endif /* HAVE_SOLARIS_GETPWENT_R */ + +/**************************************************************************** + * ENDPWENT + ***************************************************************************/ + +static void nwrap_endpwent(void) +{ + int i; for (i=0; i < nwrap_main_global->num_backends; i++) { struct nwrap_backend *b = &nwrap_main_global->backends[i]; @@ -1997,32 +3206,56 @@ _PUBLIC_ void nwrap_endpwent(void) } } -_PUBLIC_ int nwrap_initgroups(const char *user, gid_t group) +void endpwent(void) { - int i; - - if (!nwrap_enabled()) { - return real_initgroups(user, group); + if (!nss_wrapper_enabled()) { + libc_endpwent(); + return; } + nwrap_endpwent(); +} + +/**************************************************************************** + * INITGROUPS + ***************************************************************************/ + +static int nwrap_initgroups(const char *user, gid_t group) +{ + int i; + for (i=0; i < nwrap_main_global->num_backends; i++) { struct nwrap_backend *b = &nwrap_main_global->backends[i]; - return b->ops->nw_initgroups(b, user, group); + int rc; + + rc = b->ops->nw_initgroups(b, user, group); + if (rc == 0) { + return 0; + } } errno = ENOENT; return -1; } -_PUBLIC_ struct group *nwrap_getgrnam(const char *name) +int initgroups(const char *user, gid_t group) +{ + if (!nss_wrapper_enabled()) { + return libc_initgroups(user, group); + } + + return nwrap_initgroups(user, group); +} + +/**************************************************************************** + * GETGRNAM + ***************************************************************************/ + +static struct group *nwrap_getgrnam(const char *name) { int i; struct group *grp; - if (!nwrap_enabled()) { - return real_getgrnam(name); - } - for (i=0; i < nwrap_main_global->num_backends; i++) { struct nwrap_backend *b = &nwrap_main_global->backends[i]; grp = b->ops->nw_getgrnam(b, name); @@ -2034,15 +3267,24 @@ _PUBLIC_ struct group *nwrap_getgrnam(const char *name) return NULL; } -_PUBLIC_ int nwrap_getgrnam_r(const char *name, struct group *grdst, - char *buf, size_t buflen, struct group **grdstp) +struct group *getgrnam(const char *name) { - int i,ret; - - if (!nwrap_enabled()) { - return real_getgrnam_r(name, grdst, buf, buflen, grdstp); + if (!nss_wrapper_enabled()) { + return libc_getgrnam(name); } + return nwrap_getgrnam(name); +} + +/**************************************************************************** + * GETGRNAM_R + ***************************************************************************/ + +static int nwrap_getgrnam_r(const char *name, struct group *grdst, + char *buf, size_t buflen, struct group **grdstp) +{ + int i, ret; + for (i=0; i < nwrap_main_global->num_backends; i++) { struct nwrap_backend *b = &nwrap_main_global->backends[i]; ret = b->ops->nw_getgrnam_r(b, name, grdst, buf, buflen, grdstp); @@ -2055,15 +3297,36 @@ _PUBLIC_ int nwrap_getgrnam_r(const char *name, struct group *grdst, return ENOENT; } -_PUBLIC_ struct group *nwrap_getgrgid(gid_t gid) +#ifdef HAVE_GETGRNAM_R +# ifdef HAVE_SOLARIS_GETGRNAM_R +int getgrnam_r(const char *name, struct group *grp, + char *buf, int buflen, struct group **pgrp) +# else /* HAVE_SOLARIS_GETGRNAM_R */ +int getgrnam_r(const char *name, struct group *grp, + char *buf, size_t buflen, struct group **pgrp) +# endif /* HAVE_SOLARIS_GETGRNAM_R */ +{ + if (!nss_wrapper_enabled()) { + return libc_getgrnam_r(name, + grp, + buf, + buflen, + pgrp); + } + + return nwrap_getgrnam_r(name, grp, buf, buflen, pgrp); +} +#endif /* HAVE_GETGRNAM_R */ + +/**************************************************************************** + * GETGRGID + ***************************************************************************/ + +static struct group *nwrap_getgrgid(gid_t gid) { int i; struct group *grp; - if (!nwrap_enabled()) { - return real_getgrgid(gid); - } - for (i=0; i < nwrap_main_global->num_backends; i++) { struct nwrap_backend *b = &nwrap_main_global->backends[i]; grp = b->ops->nw_getgrgid(b, gid); @@ -2075,15 +3338,24 @@ _PUBLIC_ struct group *nwrap_getgrgid(gid_t gid) return NULL; } -_PUBLIC_ int nwrap_getgrgid_r(gid_t gid, struct group *grdst, - char *buf, size_t buflen, struct group **grdstp) +struct group *getgrgid(gid_t gid) { - int i,ret; - - if (!nwrap_enabled()) { - return real_getgrgid_r(gid, grdst, buf, buflen, grdstp); + if (!nss_wrapper_enabled()) { + return libc_getgrgid(gid); } + return nwrap_getgrgid(gid); +} + +/**************************************************************************** + * GETGRGID_R + ***************************************************************************/ + +static int nwrap_getgrgid_r(gid_t gid, struct group *grdst, + char *buf, size_t buflen, struct group **grdstp) +{ + int i,ret; + for (i=0; i < nwrap_main_global->num_backends; i++) { struct nwrap_backend *b = &nwrap_main_global->backends[i]; ret = b->ops->nw_getgrgid_r(b, gid, grdst, buf, buflen, grdstp); @@ -2096,30 +3368,67 @@ _PUBLIC_ int nwrap_getgrgid_r(gid_t gid, struct group *grdst, return ENOENT; } -_PUBLIC_ void nwrap_setgrent(void) +#ifdef HAVE_GETGRGID_R +# ifdef HAVE_SOLARIS_GETGRGID_R +int getgrgid_r(gid_t gid, struct group *grdst, + char *buf, int buflen, struct group **grdstp) +# else /* HAVE_SOLARIS_GETGRGID_R */ +int getgrgid_r(gid_t gid, struct group *grdst, + char *buf, size_t buflen, struct group **grdstp) +# endif /* HAVE_SOLARIS_GETGRGID_R */ { - int i; - - if (!nwrap_enabled()) { - real_setgrent(); - return; + if (!nss_wrapper_enabled()) { + return libc_getgrgid_r(gid, grdst, buf, buflen, grdstp); } + return nwrap_getgrgid_r(gid, grdst, buf, buflen, grdstp); +} +#endif + +/**************************************************************************** + * SETGRENT + ***************************************************************************/ + +static void nwrap_setgrent(void) +{ + int i; + for (i=0; i < nwrap_main_global->num_backends; i++) { struct nwrap_backend *b = &nwrap_main_global->backends[i]; b->ops->nw_setgrent(b); } } -_PUBLIC_ struct group *nwrap_getgrent(void) +#ifdef HAVE_BSD_SETGRENT +int setgrent(void) +#else +void setgrent(void) +#endif +{ + if (!nss_wrapper_enabled()) { + libc_setgrent(); + goto out; + } + + nwrap_setgrent(); + +out: +#ifdef HAVE_BSD_SETGRENT + return 0; +#else + return; +#endif +} + +/**************************************************************************** + * GETGRENT + ***************************************************************************/ + +static struct group *nwrap_getgrent(void) { int i; struct group *grp; - if (!nwrap_enabled()) { - return real_getgrent(); - } - for (i=0; i < nwrap_main_global->num_backends; i++) { struct nwrap_backend *b = &nwrap_main_global->backends[i]; grp = b->ops->nw_getgrent(b); @@ -2131,30 +3440,24 @@ _PUBLIC_ struct group *nwrap_getgrent(void) return NULL; } -_PUBLIC_ int nwrap_getgrent_r(struct group *grdst, char *buf, - size_t buflen, struct group **grdstp) +struct group *getgrent(void) { - int i,ret; - - if (!nwrap_enabled()) { -#ifdef SOLARIS_GETGRENT_R - struct group *gr; - gr = real_getgrent_r(grdst, buf, buflen); - if (!gr) { - if (errno == 0) { - return ENOENT; - } - return errno; - } - if (grdstp) { - *grdstp = gr; - } - return 0; -#else - return real_getgrent_r(grdst, buf, buflen, grdstp); -#endif + if (!nss_wrapper_enabled()) { + return libc_getgrent(); } + return nwrap_getgrent(); +} + +/**************************************************************************** + * GETGRENT_R + ***************************************************************************/ + +static int nwrap_getgrent_r(struct group *grdst, char *buf, + size_t buflen, struct group **grdstp) +{ + int i,ret; + for (i=0; i < nwrap_main_global->num_backends; i++) { struct nwrap_backend *b = &nwrap_main_global->backends[i]; ret = b->ops->nw_getgrent_r(b, grdst, buf, buflen, grdstp); @@ -2167,37 +3470,77 @@ _PUBLIC_ int nwrap_getgrent_r(struct group *grdst, char *buf, return ENOENT; } -_PUBLIC_ void nwrap_endgrent(void) +#ifdef HAVE_SOLARIS_GETGRENT_R +struct group *getgrent_r(struct group *src, char *buf, int buflen) { - int i; + struct group *grdstp = NULL; + int rc; - if (!nwrap_enabled()) { - real_endgrent(); - return; + if (!nss_wrapper_enabled()) { + return libc_getgrent_r(src, buf, buflen); + } + + rc = nwrap_getgrent_r(src, buf, buflen, &grdstp); + if (rc < 0) { + return NULL; + } + + return grdstp; +} +#else /* HAVE_SOLARIS_GETGRENT_R */ +int getgrent_r(struct group *src, char *buf, + size_t buflen, struct group **grdstp) +{ + if (!nss_wrapper_enabled()) { + return libc_getgrent_r(src, buf, buflen, grdstp); } + return nwrap_getgrent_r(src, buf, buflen, grdstp); +} +#endif /* HAVE_SOLARIS_GETGRENT_R */ + +/**************************************************************************** + * ENDGRENT + ***************************************************************************/ + +static void nwrap_endgrent(void) +{ + int i; + for (i=0; i < nwrap_main_global->num_backends; i++) { struct nwrap_backend *b = &nwrap_main_global->backends[i]; b->ops->nw_endgrent(b); } } -_PUBLIC_ int nwrap_getgrouplist(const char *user, gid_t group, gid_t *groups, int *ngroups) +void endgrent(void) +{ + if (!nss_wrapper_enabled()) { + libc_endgrent(); + return; + } + + nwrap_endgrent(); +} + +/**************************************************************************** + * GETGROUPLIST + ***************************************************************************/ + +#ifdef HAVE_GETGROUPLIST +static int nwrap_getgrouplist(const char *user, gid_t group, + gid_t *groups, int *ngroups) { struct group *grp; gid_t *groups_tmp; int count = 1; const char *name_of_group = ""; - if (!nwrap_enabled()) { - return real_getgrouplist(user, group, groups, ngroups); - } - - NWRAP_DEBUG(("%s: getgrouplist called for %s\n", __location__, user)); + NWRAP_LOG(NWRAP_LOG_DEBUG, "getgrouplist called for %s", user); groups_tmp = (gid_t *)malloc(count * sizeof(gid_t)); if (!groups_tmp) { - NWRAP_ERROR(("%s:calloc failed\n",__location__)); + NWRAP_LOG(NWRAP_LOG_ERROR, "Out of memory"); errno = ENOMEM; return -1; } @@ -2213,20 +3556,24 @@ _PUBLIC_ int nwrap_getgrouplist(const char *user, gid_t group, gid_t *groups, in while ((grp = nwrap_getgrent()) != NULL) { int i = 0; - NWRAP_VERBOSE(("%s: inspecting %s for group membership\n", - __location__, grp->gr_name)); + NWRAP_LOG(NWRAP_LOG_DEBUG, + "Inspecting %s for group membership", + grp->gr_name); for (i=0; grp->gr_mem && grp->gr_mem[i] != NULL; i++) { if ((strcmp(user, grp->gr_mem[i]) == 0) && (strcmp(name_of_group, grp->gr_name) != 0)) { - NWRAP_DEBUG(("%s: %s is member of %s\n", - __location__, user, grp->gr_name)); + NWRAP_LOG(NWRAP_LOG_DEBUG, + "%s is member of %s", + user, + grp->gr_name); groups_tmp = (gid_t *)realloc(groups_tmp, (count + 1) * sizeof(gid_t)); if (!groups_tmp) { - NWRAP_ERROR(("%s:calloc failed\n",__location__)); + NWRAP_LOG(NWRAP_LOG_ERROR, + "Out of memory"); errno = ENOMEM; return -1; } @@ -2239,8 +3586,9 @@ _PUBLIC_ int nwrap_getgrouplist(const char *user, gid_t group, gid_t *groups, in nwrap_endgrent(); - NWRAP_VERBOSE(("%s: %s is member of %d groups: %d\n", - __location__, user, *ngroups)); + NWRAP_LOG(NWRAP_LOG_DEBUG, + "%s is member of %d groups", + user, *ngroups); if (*ngroups < count) { *ngroups = count; @@ -2254,3 +3602,631 @@ _PUBLIC_ int nwrap_getgrouplist(const char *user, gid_t group, gid_t *groups, in return count; } + +int getgrouplist(const char *user, gid_t group, gid_t *groups, int *ngroups) +{ + if (!nss_wrapper_enabled()) { + return libc_getgrouplist(user, group, groups, ngroups); + } + + return nwrap_getgrouplist(user, group, groups, ngroups); +} +#endif + +/********************************************************** + * NETDB + **********************************************************/ + +static void nwrap_sethostent(int stayopen) { + (void) stayopen; /* ignored */ + + nwrap_files_sethostent(); +} + +#ifdef HAVE_SOLARIS_SETHOSTENT +int sethostent(int stayopen) +{ + if (!nss_wrapper_hosts_enabled()) { + libc_sethostent(stayopen); + return 0; + } + + nwrap_sethostent(stayopen); + + return 0; +} +#else /* HAVE_SOLARIS_SETHOSTENT */ +void sethostent(int stayopen) +{ + if (!nss_wrapper_hosts_enabled()) { + libc_sethostent(stayopen); + return; + } + + nwrap_sethostent(stayopen); +} +#endif /* HAVE_SOLARIS_SETHOSTENT */ + +static struct hostent *nwrap_gethostent(void) +{ + return nwrap_files_gethostent(); +} + +struct hostent *gethostent(void) { + if (!nss_wrapper_hosts_enabled()) { + return libc_gethostent(); + } + + return nwrap_gethostent(); +} + +static void nwrap_endhostent(void) { + nwrap_files_endhostent(); +} + +#ifdef HAVE_SOLARIS_ENDHOSTENT +int endhostent(void) +{ + if (!nss_wrapper_hosts_enabled()) { + libc_endhostent(); + return 0; + } + + nwrap_endhostent(); + + return 0; +} +#else /* HAVE_SOLARIS_ENDHOSTENT */ +void endhostent(void) +{ + if (!nss_wrapper_hosts_enabled()) { + libc_endhostent(); + return; + } + + nwrap_endhostent(); +} +#endif /* HAVE_SOLARIS_ENDHOSTENT */ + +static struct hostent *nwrap_gethostbyname(const char *name) +{ + return nwrap_files_gethostbyname(name, AF_UNSPEC); +} + +struct hostent *gethostbyname(const char *name) +{ + if (!nss_wrapper_hosts_enabled()) { + return libc_gethostbyname(name); + } + + return nwrap_gethostbyname(name); +} + +/* This is a GNU extension */ +#ifdef HAVE_GETHOSTBYNAME2 +static struct hostent *nwrap_gethostbyname2(const char *name, int af) +{ + return nwrap_files_gethostbyname(name, af); +} + +struct hostent *gethostbyname2(const char *name, int af) +{ + if (!nss_wrapper_hosts_enabled()) { + return libc_gethostbyname2(name, af); + } + + return nwrap_gethostbyname2(name, af); +} +#endif + +static struct hostent *nwrap_gethostbyaddr(const void *addr, + socklen_t len, int type) +{ + return nwrap_files_gethostbyaddr(addr, len, type); +} + +struct hostent *gethostbyaddr(const void *addr, + socklen_t len, int type) +{ + if (!nss_wrapper_hosts_enabled()) { + return libc_gethostbyaddr(addr, len, type); + } + + return nwrap_gethostbyaddr(addr, len, type); +} + +static const struct addrinfo default_hints = +{ + .ai_flags = AI_ADDRCONFIG|AI_V4MAPPED, + .ai_family = AF_UNSPEC, + .ai_socktype = 0, + .ai_protocol = 0, + .ai_addrlen = 0, + .ai_addr = NULL, + .ai_canonname = NULL, + .ai_next = NULL +}; + +static int nwrap_convert_he_ai(const struct hostent *he, + unsigned short port, + const struct addrinfo *hints, + struct addrinfo **pai) +{ + struct addrinfo *ai; + socklen_t socklen; + + switch (he->h_addrtype) { + case AF_INET: + socklen = sizeof(struct sockaddr_in); + break; +#ifdef HAVE_IPV6 + case AF_INET6: + socklen = sizeof(struct sockaddr_in6); + break; +#endif + default: + return EAI_FAMILY; + } + + ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) + socklen); + if (ai == NULL) { + return EAI_MEMORY; + } + + ai->ai_flags = 0; + ai->ai_family = he->h_addrtype; + ai->ai_socktype = hints->ai_socktype; + ai->ai_protocol = hints->ai_protocol; + + ai->ai_addrlen = socklen; + ai->ai_addr = (void *)(ai + 1); + +#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN + ai->ai_addr->sa_len = socklen; +#endif + ai->ai_addr->sa_family = he->h_addrtype; + + switch (he->h_addrtype) { + case AF_INET: + { + struct sockaddr_in *sinp = + (struct sockaddr_in *) ai->ai_addr; + + memset(sinp, 0, sizeof(struct sockaddr_in)); + + sinp->sin_port = htons(port); + sinp->sin_family = AF_INET; + + memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero)); + memcpy(&sinp->sin_addr, he->h_addr_list[0], he->h_length); + + } + break; +#ifdef HAVE_IPV6 + case AF_INET6: + { + struct sockaddr_in6 *sin6p = + (struct sockaddr_in6 *) ai->ai_addr; + + memset(sin6p, 0, sizeof(struct sockaddr_in6)); + + sin6p->sin6_port = htons(port); + sin6p->sin6_family = AF_INET6; + + memcpy(&sin6p->sin6_addr, he->h_addr_list[0], he->h_length); + } + break; +#endif + } + + ai->ai_next = NULL; + + if (he->h_name) { + ai->ai_canonname = strdup(he->h_name); + if (ai->ai_canonname == NULL) { + freeaddrinfo(ai); + return EAI_MEMORY; + } + } + + *pai = ai; + return 0; +} + +static int nwrap_getaddrinfo(const char *node, + const char *service, + const struct addrinfo *hints, + struct addrinfo **res) +{ + struct addrinfo *ai = NULL; + struct addrinfo *p = NULL; + unsigned short port = 0; + struct hostent *he; + struct in_addr in; + bool is_addr_ipv4 = false; + bool is_addr_ipv6 = false; + int eai = EAI_SYSTEM; + int ret; + int rc; + int af; + + if (node == NULL && service == NULL) { + return EAI_NONAME; + } + + ret = libc_getaddrinfo(node, service, hints, &p); + if (ret == 0) { + *res = p; + } + + /* If no node has been specified, let glibc deal with it */ + if (node == NULL) { + return ret; + } + + if (hints == NULL) { + hints = &default_hints; + } + + if ((hints->ai_flags & AI_CANONNAME) && node == NULL) { + return EAI_BADFLAGS; + } + + if (service != NULL && service[0] != '\0') { + if (isdigit((int)service[0])) { + port = (unsigned short)atoi(service); + } else { + const char *proto = NULL; + struct servent *s; + + if (hints->ai_protocol != 0) { + struct protoent *pent; + + pent = getprotobynumber(hints->ai_protocol); + if (pent != NULL) { + proto = pent->p_name; + } + } + + s = getservbyname(service, proto); + if (s != NULL) { + port = ntohs(s->s_port); + } else { + if (p != NULL) { + freeaddrinfo(p); + } + return EAI_SERVICE; + } + } + } + + af = hints->ai_family; + if (af == AF_UNSPEC) { + af = AF_INET; + } + + rc = inet_pton(af, node, &in); + if (rc == 1) { + is_addr_ipv4 = true; + if (af == AF_UNSPEC) { + af = AF_INET; + } +#ifdef HAVE_IPV6 + } else { + struct in6_addr in6; + + af = AF_INET6; + + rc = inet_pton(af, node, &in6); + if (rc == 1) { + is_addr_ipv6 = true; + } +#endif + } + + if (is_addr_ipv4) { + he = nwrap_files_gethostbyaddr(&in, sizeof(struct in_addr), af); + if (he != NULL) { + rc = nwrap_convert_he_ai(he, port, hints, &ai); + } else { + eai = EAI_NODATA; + rc = -1; + } +#ifdef HAVE_IPV6 + } else if (is_addr_ipv6) { + struct in6_addr in6; + + rc = inet_pton(af, node, &in6); + if (rc <= 0) { + eai = EAI_ADDRFAMILY; + return ret == 0 ? 0 : eai; + } + + he = nwrap_files_gethostbyaddr(&in6, + sizeof(struct in6_addr), + af); + if (he != NULL) { + rc = nwrap_convert_he_ai(he, port, hints, &ai); + eai = rc; + } else { + eai = EAI_NODATA; + rc = -1; + } +#endif + } else { + he = nwrap_files_gethostbyname(node, hints->ai_family); + if (he != NULL) { + rc = nwrap_convert_he_ai(he, port, hints, &ai); + eai = rc; + } else { + eai = EAI_NODATA; + rc = -1; + } + } + + if (rc < 0) { + return ret == 0 ? 0 : eai; + } + + if (ret == 0) { + freeaddrinfo(p); + } + + if (ai->ai_flags == 0) { + ai->ai_flags = hints->ai_flags; + } + if (ai->ai_socktype == 0) { + ai->ai_socktype = SOCK_DGRAM; + } + if (ai->ai_protocol == 0 && ai->ai_socktype == SOCK_DGRAM) { + ai->ai_protocol = 17; /* UDP */ + } else if (ai->ai_protocol == 0 && ai->ai_socktype == SOCK_STREAM) { + ai->ai_protocol = 6; /* TCP */ + } + + if (hints->ai_socktype == 0) { + /* Add second ai */ + rc = nwrap_convert_he_ai(he, port, hints, &ai->ai_next); + if (rc < 0) { + freeaddrinfo(ai); + return rc; + } + + if (ai->ai_next->ai_flags == 0) { + ai->ai_next->ai_flags = hints->ai_flags; + } + if (ai->ai_socktype == SOCK_DGRAM) { + ai->ai_next->ai_socktype = SOCK_STREAM; + } else if (ai->ai_socktype == SOCK_STREAM) { + ai->ai_next->ai_socktype = SOCK_DGRAM; + } + if (ai->ai_next->ai_socktype == SOCK_DGRAM) { + ai->ai_next->ai_protocol = 17; /* UDP */ + } else if (ai->ai_next->ai_socktype == SOCK_STREAM) { + ai->ai_next->ai_protocol = 6; /* TCP */ + } + } + + *res = ai; + + return 0; +} + +int getaddrinfo(const char *node, const char *service, + const struct addrinfo *hints, + struct addrinfo **res) +{ + if (!nss_wrapper_hosts_enabled()) { + return libc_getaddrinfo(node, service, hints, res); + } + + return nwrap_getaddrinfo(node, service, hints, res); +} + +static int nwrap_getnameinfo(const struct sockaddr *sa, socklen_t salen, + char *host, size_t hostlen, + char *serv, size_t servlen, + int flags) +{ + struct hostent *he; + struct servent *service; + const char *proto; + const void *addr; + socklen_t addrlen; + uint16_t port; + sa_family_t type; + + if (sa == NULL || salen < sizeof(sa_family_t)) { + return EAI_FAMILY; + } + + if ((flags & NI_NAMEREQD) && host == NULL && serv == NULL) { + return EAI_NONAME; + } + + type = sa->sa_family; + switch (type) { + case AF_INET: + if (salen < sizeof(struct sockaddr_in)) + return EAI_FAMILY; + addr = &((struct sockaddr_in *)sa)->sin_addr; + addrlen = sizeof(((struct sockaddr_in *)sa)->sin_addr); + port = ntohs(((struct sockaddr_in *)sa)->sin_port); + break; +#ifdef HAVE_IPV6 + case AF_INET6: + if (salen < sizeof(struct sockaddr_in6)) + return EAI_FAMILY; + addr = &((struct sockaddr_in6 *)sa)->sin6_addr; + addrlen = sizeof(((struct sockaddr_in6 *)sa)->sin6_addr); + port = ntohs(((struct sockaddr_in6 *)sa)->sin6_port); + break; +#endif + default: + return EAI_FAMILY; + } + + if (host != NULL) { + he = NULL; + if ((flags & NI_NUMERICHOST) == 0) { + he = nwrap_files_gethostbyaddr(addr, addrlen, type); + if ((flags & NI_NAMEREQD) && (he == NULL || he->h_name == NULL)) + return EAI_NONAME; + } + if (he != NULL && he->h_name != NULL) { + if (strlen(he->h_name) >= hostlen) + return EAI_OVERFLOW; + strcpy(host, he->h_name); + if (flags & NI_NOFQDN) + host[strcspn(host, ".")] = '\0'; + } else { + if (inet_ntop(type, addr, host, hostlen) == NULL) + return (errno == ENOSPC) ? EAI_OVERFLOW : EAI_FAIL; + } + } + + if (serv != NULL) { + service = NULL; + if ((flags & NI_NUMERICSERV) == 0) { + proto = (flags & NI_DGRAM) ? "udp" : "tcp"; + service = getservbyport(htons(port), proto); + } + if (service != NULL) { + if (strlen(service->s_name) >= servlen) + return EAI_OVERFLOW; + strcpy(serv, service->s_name); + } else { + if (snprintf(serv, servlen, "%u", port) >= (int) servlen) + return EAI_OVERFLOW; + } + } + + return 0; +} + +#ifdef HAVE_LINUX_GETNAMEINFO +int getnameinfo(const struct sockaddr *sa, socklen_t salen, + char *host, socklen_t hostlen, + char *serv, socklen_t servlen, + int flags) +#elif defined(HAVE_LINUX_GETNAMEINFO_UNSIGNED) +int getnameinfo(const struct sockaddr *sa, socklen_t salen, + char *host, socklen_t hostlen, + char *serv, socklen_t servlen, + unsigned int flags) +#else +int getnameinfo(const struct sockaddr *sa, socklen_t salen, + char *host, size_t hostlen, + char *serv, size_t servlen, + int flags) +#endif +{ + if (!nss_wrapper_hosts_enabled()) { + return libc_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags); + } + + return nwrap_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags); +} + +static int nwrap_gethostname(char *name, size_t len) +{ + const char *hostname = getenv("NSS_WRAPPER_HOSTNAME"); + + if (strlen(hostname) >= len) { + errno = ENAMETOOLONG; + return -1; + } + snprintf(name, len, "%s", hostname); + + return 0; +} + +#ifdef HAVE_SOLARIS_GETHOSTNAME +int gethostname(char *name, int len) +#else /* HAVE_SOLARIS_GETHOSTNAME */ +int gethostname(char *name, size_t len) +#endif /* HAVE_SOLARIS_GETHOSTNAME */ +{ + if (!nwrap_hostname_enabled()) { + return libc_gethostname(name, len); + } + + return nwrap_gethostname(name, len); +} + +/**************************** + * DESTRUCTOR + ***************************/ + +/* + * This function is called when the library is unloaded and makes sure that + * sockets get closed and the unix file for the socket are unlinked. + */ +void nwrap_destructor(void) +{ + int i; + + if (nwrap_main_global != NULL) { + struct nwrap_main *m = nwrap_main_global; + + /* libc */ + SAFE_FREE(m->libc->fns); + if (m->libc->handle != NULL) { + dlclose(m->libc->handle); + } + if (m->libc->nsl_handle != NULL) { + dlclose(m->libc->nsl_handle); + } + if (m->libc->sock_handle != NULL) { + dlclose(m->libc->sock_handle); + } + SAFE_FREE(m->libc); + + /* backends */ + for (i = 0; i < m->num_backends; i++) { + struct nwrap_backend *b = &(m->backends[i]); + + if (b->so_handle != NULL) { + dlclose(b->so_handle); + } + SAFE_FREE(b->fns); + } + SAFE_FREE(m->backends); + } + + if (nwrap_pw_global.cache != NULL) { + struct nwrap_cache *c = nwrap_pw_global.cache; + + nwrap_files_cache_unload(c); + if (c->fd >= 0) { + close(c->fd); + } + + SAFE_FREE(nwrap_pw_global.list); + nwrap_pw_global.num = 0; + } + + if (nwrap_gr_global.cache != NULL) { + struct nwrap_cache *c = nwrap_gr_global.cache; + + nwrap_files_cache_unload(c); + if (c->fd >= 0) { + close(c->fd); + } + + SAFE_FREE(nwrap_gr_global.list); + nwrap_pw_global.num = 0; + } + + if (nwrap_he_global.cache != NULL) { + struct nwrap_cache *c = nwrap_he_global.cache; + + nwrap_files_cache_unload(c); + if (c->fd >= 0) { + close(c->fd); + } + + SAFE_FREE(nwrap_he_global.list); + nwrap_he_global.num = 0; + } +} |