/*
* 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.
*
* SUCH DAMAGE.
*/
-#ifdef _SAMBA_BUILD_
+#include "config.h"
-/* defining this gives us the posix getpwnam_r() calls on solaris
- Thanks to heimdal for this */
+#include <pthread.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>
+
+#include <search.h>
+#include <assert.h>
+
+/*
+ * 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>
+#ifdef HAVE_SHADOW_H
+#include <shadow.h>
+#endif /* HAVE_SHADOW_H */
+
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#include <dlfcn.h>
+
+#if defined(HAVE_NSS_H)
+/* Linux and BSD */
+#include <nss.h>
-#else /* _SAMBA_BUILD_ */
+typedef enum nss_status NSS_STATUS;
+#elif defined(HAVE_NSS_COMMON_H)
+/* Solaris */
+#include <nss_common.h>
+#include <nss_dbdefs.h>
+#include <nsswitch.h>
-#error nss_wrapper_only_supported_in_samba_yet
+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
-#endif
-#ifndef HAVE_GETGRNAM_R
-#define getgrnam_r(name, grdst, buf, buflen, grdstp) ENOSYS
+
+#ifndef EAI_ADDRFAMILY
+#define EAI_ADDRFAMILY EAI_FAMILY
#endif
-#ifndef HAVE_GETGRGID_R
-#define getgrgid_r(gid, grdst, buf, buflen, grdstp) ENOSYS
+
+#ifndef __STRING
+#define __STRING(x) #x
#endif
-#ifndef HAVE_GETGRENT_R
-#define getgrent_r(grdst, buf, buflen, grdstp) ENOSYS
+
+#ifndef __STRINGSTRING
+#define __STRINGSTRING(x) __STRING(x)
#endif
-/* not all systems have getgrouplist */
-#ifndef HAVE_GETGROUPLIST
-#define getgrouplist(user, group, groups, ngroups) 0
+#ifndef __LINESTR__
+#define __LINESTR__ __STRINGSTRING(__LINE__)
#endif
-/* LD_PRELOAD doesn't work yet, so REWRITE_CALLS is all we support
- * for now */
-#define REWRITE_CALLS
+#ifndef __location__
+#define __location__ __FILE__ ":" __LINESTR__
+#endif
-#ifdef REWRITE_CALLS
+#ifndef DNS_NAME_MAX
+#define DNS_NAME_MAX 255
+#endif
-#define real_getpwnam getpwnam
-#define real_getpwnam_r getpwnam_r
-#define real_getpwuid getpwuid
-#define real_getpwuid_r getpwuid_r
+/* 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 */
-#define real_setpwent setpwent
-#define real_getpwent getpwent
-#define real_getpwent_r getpwent_r
-#define real_endpwent endpwent
+#ifdef HAVE_DESTRUCTOR_ATTRIBUTE
+#define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor))
+#else
+#define DESTRUCTOR_ATTRIBUTE
+#endif /* HAVE_DESTRUCTOR_ATTRIBUTE */
-/*
-#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
+#define ZERO_STRUCTP(x) do { if ((x) != NULL) memset((char *)(x), 0, sizeof(*(x))); } while(0)
+#ifndef SAFE_FREE
+#define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
#endif
-#if 0
-# ifdef DEBUG
-# define NWRAP_ERROR(args) DEBUG(0, args)
-# else
-# define NWRAP_ERROR(args) printf args
-# endif
+#ifdef HAVE_IPV6
+#define NWRAP_INET_ADDRSTRLEN INET6_ADDRSTRLEN
#else
-#define NWRAP_ERROR(args)
+#define NWRAP_INET_ADDRSTRLEN INET_ADDRSTRLEN
#endif
-#if 0
-# ifdef DEBUG
-# define NWRAP_DEBUG(args) DEBUG(0, args)
-# else
-# define NWRAP_DEBUG(args) printf args
-# endif
+#define NWRAP_LOCK(m) do { \
+ pthread_mutex_lock(&( m ## _mutex)); \
+} while(0)
+
+#define NWRAP_UNLOCK(m) do { \
+ pthread_mutex_unlock(&( m ## _mutex)); \
+} while(0)
+
+
+static bool nwrap_initialized = false;
+static pthread_mutex_t nwrap_initialized_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* The mutex or accessing the id */
+static pthread_mutex_t nwrap_global_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t nwrap_gr_global_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t nwrap_he_global_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t nwrap_pw_global_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t nwrap_sp_global_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* Add new global locks here please */
+/* Also don't forget to add locks to
+ * nwrap_init() function.
+ */
+# define NWRAP_LOCK_ALL do { \
+ NWRAP_LOCK(nwrap_initialized); \
+ NWRAP_LOCK(nwrap_global); \
+ NWRAP_LOCK(nwrap_gr_global); \
+ NWRAP_LOCK(nwrap_he_global); \
+ NWRAP_LOCK(nwrap_pw_global); \
+ NWRAP_LOCK(nwrap_sp_global); \
+} while (0);
+
+# define NWRAP_UNLOCK_ALL do {\
+ NWRAP_UNLOCK(nwrap_sp_global); \
+ NWRAP_UNLOCK(nwrap_pw_global); \
+ NWRAP_UNLOCK(nwrap_he_global); \
+ NWRAP_UNLOCK(nwrap_gr_global); \
+ NWRAP_UNLOCK(nwrap_global); \
+ NWRAP_UNLOCK(nwrap_initialized); \
+} while (0);
+
+static void nwrap_thread_prepare(void)
+{
+ NWRAP_LOCK_ALL;
+}
+
+static void nwrap_thread_parent(void)
+{
+ NWRAP_UNLOCK_ALL;
+}
+
+static void nwrap_thread_child(void)
+{
+ NWRAP_UNLOCK_ALL;
+}
+
+enum nwrap_dbglvl_e {
+ NWRAP_LOG_ERROR = 0,
+ NWRAP_LOG_WARN,
+ NWRAP_LOG_DEBUG,
+ NWRAP_LOG_TRACE
+};
+
+#ifdef NDEBUG
+# define NWRAP_LOG(...)
#else
-#define NWRAP_DEBUG(args)
-#endif
-#if 0
-# ifdef DEBUG
-# define NWRAP_VERBOSE(args) DEBUG(0, args)
-# else
-# define NWRAP_VERBOSE(args) printf args
-# 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__)
+
+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
+ int (*_libc_getpwent_r)(struct passwd *pwbuf, char *buf, size_t buflen, struct passwd **pwbufp);
+#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_VERBOSE(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);
+
+ 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,
void (*nw_endgrent)(struct nwrap_backend *b);
};
+/* Public prototypes */
+
+bool nss_wrapper_enabled(void);
+bool nss_wrapper_shadow_enabled(void);
+bool nss_wrapper_hosts_enabled(void);
+
/* prototypes for files backend */
.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;
+};
+
+static struct nwrap_main *nwrap_main_global;
+static struct nwrap_main __nwrap_main_global;
+
+/*
+ * PROTOTYPES
+ */
+static int nwrap_convert_he_ai(const struct hostent *he,
+ unsigned short port,
+ const struct addrinfo *hints,
+ struct addrinfo **pai,
+ bool skip_canonname);
+
+/*
+ * VECTORS
+ */
+
+#define DEFAULT_VECTOR_CAPACITY 16
+
+struct nwrap_vector {
+ void **items;
+ size_t count;
+ size_t capacity;
};
-struct nwrap_main *nwrap_main_global;
-struct nwrap_main __nwrap_main_global;
+/* Macro returns pointer to first element of vector->items array.
+ *
+ * nwrap_vector is used as a memory backend which take care of
+ * memory allocations and other stuff like memory growing.
+ * nwrap_vectors should not be considered as some abstract structures.
+ * On this level, vectors are more handy than direct realloc/malloc
+ * calls.
+ *
+ * nwrap_vector->items is array inside nwrap_vector which can be
+ * directly pointed by libc structure assembled by cwrap itself.
+ *
+ * EXAMPLE:
+ *
+ * 1) struct hostent contains char **h_addr_list element.
+ * 2) nwrap_vector holds array of pointers to addresses.
+ * It's easier to use vector to store results of
+ * file parsing etc.
+ *
+ * Now, pretend that cwrap assembled struct hostent and
+ * we need to set h_addr_list to point to nwrap_vector.
+ * Idea behind is to shield users from internal nwrap_vector
+ * implementation.
+ * (Yes, not fully - array terminated by NULL is needed because
+ * it's result expected by libc function caller.)
+ *
+ *
+ * CODE EXAMPLE:
+ *
+ * struct hostent he;
+ * struct nwrap_vector *vector = malloc(sizeof(struct nwrap_vector));
+ * ... don't care about failed allocation now ...
+ *
+ * ... fill nwrap vector ...
+ *
+ * struct hostent he;
+ * he.h_addr_list = nwrap_vector_head(vector);
+ *
+ */
+#define nwrap_vector_head(vect) ((void *)((vect)->items))
+
+#define nwrap_vector_foreach(item, vect, iter) \
+ for (iter = 0, (item) = (vect).items == NULL ? NULL : (vect).items[0]; \
+ item != NULL; \
+ (item) = (vect).items[++iter])
+
+#define nwrap_vector_is_initialized(vector) ((vector)->items != NULL)
+
+static inline bool nwrap_vector_init(struct nwrap_vector *const vector)
+{
+ if (vector == NULL) {
+ return false;
+ }
+
+ /* count is initialized by ZERO_STRUCTP */
+ ZERO_STRUCTP(vector);
+ vector->items = malloc(sizeof(void *) * (DEFAULT_VECTOR_CAPACITY + 1));
+ if (vector->items == NULL) {
+ return false;
+ }
+ vector->capacity = DEFAULT_VECTOR_CAPACITY;
+ memset(vector->items, '\0', sizeof(void *) * (DEFAULT_VECTOR_CAPACITY + 1));
+
+ return true;
+}
+
+static bool nwrap_vector_add_item(struct nwrap_vector *vector, void *const item)
+{
+ assert (vector != NULL);
+
+ if (vector->items == NULL) {
+ nwrap_vector_init(vector);
+ }
+
+ if (vector->count == vector->capacity) {
+ /* Items array _MUST_ be NULL terminated because it's passed
+ * as result to caller which expect NULL terminated array from libc.
+ */
+ void **items = realloc(vector->items, sizeof(void *) * ((vector->capacity * 2) + 1));
+ if (items == NULL) {
+ return false;
+ }
+ vector->items = items;
+
+ /* Don't count ending NULL to capacity */
+ vector->capacity *= 2;
+ }
+
+ vector->items[vector->count] = item;
+
+ vector->count += 1;
+ vector->items[vector->count] = NULL;
+
+ return true;
+}
+
+static bool nwrap_vector_merge(struct nwrap_vector *dst,
+ struct nwrap_vector *src)
+{
+ void **dst_items = NULL;
+ size_t count;
+
+ if (src->count == 0) {
+ return true;
+ }
+
+ count = dst->count + src->count;
+
+ /* We don't need reallocation if we have enough capacity. */
+ if (src->count > (dst->capacity - dst->count)) {
+ dst_items = (void **)realloc(dst->items, (count + 1) * sizeof(void *));
+ if (dst_items == NULL) {
+ return false;
+ }
+ dst->items = dst_items;
+ dst->capacity = count;
+ }
+
+ memcpy((void *)(((long *)dst->items) + dst->count),
+ src->items,
+ src->count * sizeof(void *));
+ dst->count = count;
+
+ return true;
+}
struct nwrap_cache {
const char *path;
int fd;
+ FILE *fp;
struct stat st;
- uint8_t *buf;
void *private_data;
+
+ struct nwrap_vector lines;
+
bool (*parse_line)(struct nwrap_cache *, char *line);
void (*unload)(struct nwrap_cache *);
};
+/* passwd */
struct nwrap_pw {
struct nwrap_cache *cache;
static bool nwrap_pw_parse_line(struct nwrap_cache *nwrap, char *line);
static void nwrap_pw_unload(struct nwrap_cache *nwrap);
+/* shadow */
+#if defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM)
+struct nwrap_sp {
+ struct nwrap_cache *cache;
+
+ struct spwd *list;
+ int num;
+ int idx;
+};
+
+struct nwrap_cache __nwrap_cache_sp;
+struct nwrap_sp nwrap_sp_global;
+
+static bool nwrap_sp_parse_line(struct nwrap_cache *nwrap, char *line);
+static void nwrap_sp_unload(struct nwrap_cache *nwrap);
+#endif /* defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM) */
+
+/* group */
struct nwrap_gr {
struct nwrap_cache *cache;
struct nwrap_cache __nwrap_cache_gr;
struct nwrap_gr nwrap_gr_global;
-static bool nwrap_gr_parse_line(struct nwrap_cache *nwrap, char *line);
-static void nwrap_gr_unload(struct nwrap_cache *nwrap);
+/* hosts */
+static bool nwrap_he_parse_line(struct nwrap_cache *nwrap, char *line);
+static void nwrap_he_unload(struct nwrap_cache *nwrap);
-static void *nwrap_load_module_fn(struct nwrap_backend *b,
- const char *fn_name)
-{
- void *res;
- char *s;
+struct nwrap_addrdata {
+ unsigned char host_addr[16]; /* IPv4 or IPv6 address */
+};
- if (!b->so_handle) {
- NWRAP_ERROR(("%s: no handle\n",
- __location__));
- return NULL;
- }
+static size_t max_hostents = 100;
- if (asprintf(&s, "_nss_%s_%s", b->name, fn_name) == -1) {
- NWRAP_ERROR(("%s: out of memory\n",
- __location__));
- return NULL;
- }
+struct nwrap_entdata {
+ struct nwrap_addrdata addr;
+ struct hostent ht;
- res = dlsym(b->so_handle, s);
- if (!res) {
- NWRAP_ERROR(("%s: cannot find function %s in %s\n",
- __location__, s, b->so_path));
- }
- free(s);
- s = NULL;
- return res;
-}
+ struct nwrap_vector nwrap_addrdata;
-static struct nwrap_module_nss_fns *nwrap_load_module_fns(struct nwrap_backend *b)
-{
- struct nwrap_module_nss_fns *fns;
+ ssize_t aliases_count;
+};
- if (!b->so_handle) {
- return NULL;
- }
+struct nwrap_entlist {
+ struct nwrap_entlist *next;
+ struct nwrap_entdata *ed;
+};
- fns = (struct nwrap_module_nss_fns *)malloc(sizeof(struct nwrap_module_nss_fns));
- if (!fns) {
- return NULL;
- }
+struct nwrap_he {
+ struct nwrap_cache *cache;
- 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");
+ struct nwrap_entdata *list;
+ struct nwrap_vector entdata;
- return fns;
-}
+ int num;
+ int idx;
+};
-static void *nwrap_load_module(const char *so_path)
-{
- void *h;
+static struct nwrap_cache __nwrap_cache_he;
+static struct nwrap_he nwrap_he_global;
- if (!so_path || !strlen(so_path)) {
- return NULL;
- }
- h = dlopen(so_path, RTLD_LAZY);
- if (!h) {
- NWRAP_ERROR(("%s: cannot open shared library %s\n",
- __location__, so_path));
- return NULL;
+/*********************************************************
+ * 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";
}
- return h;
+ /* Compiler would warn us about unhandled enum value if we get here */
+ return "unknown";
}
+#endif
-static bool nwrap_module_init(const char *name,
- struct nwrap_ops *ops,
- const char *so_path,
- int *num_backends,
- struct nwrap_backend **backends)
+static void *nwrap_load_lib_handle(enum nwrap_lib lib)
{
- struct nwrap_backend *b;
+ int flags = RTLD_LAZY;
+ void *handle = NULL;
+ int i;
- *backends = (struct nwrap_backend *)realloc(*backends,
- sizeof(struct nwrap_backend) * ((*num_backends) + 1));
- if (!*backends) {
- NWRAP_ERROR(("%s: out of memory\n",
- __location__));
- return false;
- }
+#ifdef RTLD_DEEPBIND
+ flags |= RTLD_DEEPBIND;
+#endif
- b = &((*backends)[*num_backends]);
+ switch (lib) {
+ case NWRAP_LIBNSL:
+#ifdef HAVE_LIBNSL
+ handle = nwrap_main_global->libc->nsl_handle;
+ if (handle == NULL) {
+ for (i = 10; i >= 0; i--) {
+ char soname[256] = {0};
+
+ snprintf(soname, sizeof(soname), "libnsl.so.%d", i);
+ handle = dlopen(soname, flags);
+ if (handle != NULL) {
+ break;
+ }
+ }
- b->name = name;
- b->ops = ops;
- b->so_path = so_path;
+ 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 (i = 10; i >= 0; i--) {
+ char soname[256] = {0};
+
+ snprintf(soname, sizeof(soname), "libsocket.so.%d", i);
+ handle = dlopen(soname, flags);
+ if (handle != NULL) {
+ break;
+ }
+ }
- if (so_path != NULL) {
- b->so_handle = nwrap_load_module(so_path);
- b->fns = nwrap_load_module_fns(b);
- if (b->fns == NULL) {
- return false;
+ nwrap_main_global->libc->sock_handle = handle;
}
- } else {
- b->so_handle = NULL;
- b->fns = NULL;
+ break;
+#endif
+ /* FALL TROUGH */
+ case NWRAP_LIBC:
+ handle = nwrap_main_global->libc->handle;
+ if (handle == NULL) {
+ for (i = 10; i >= 0; i--) {
+ char soname[256] = {0};
+
+ snprintf(soname, sizeof(soname), "libc.so.%d", i);
+ handle = dlopen(soname, flags);
+ if (handle != NULL) {
+ break;
+ }
+ }
+
+ nwrap_main_global->libc->handle = handle;
+ }
+ break;
}
- (*num_backends)++;
+ if (handle == NULL) {
+#ifdef RTLD_NEXT
+ handle = nwrap_main_global->libc->handle
+ = nwrap_main_global->libc->sock_handle
+ = nwrap_main_global->libc->nsl_handle
+ = RTLD_NEXT;
+#else
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "Failed to dlopen library: %s\n",
+ dlerror());
+ exit(-1);
+#endif
+ }
- return true;
+ return handle;
}
-static void nwrap_backend_init(struct nwrap_main *r)
+static void *_nwrap_load_lib_function(enum nwrap_lib lib, const char *fn_name)
{
- const char *winbind_so_path = getenv("NSS_WRAPPER_WINBIND_SO_PATH");
+ void *handle;
+ void *func;
- r->num_backends = 0;
- r->backends = NULL;
+ nwrap_init();
- if (!nwrap_module_init("files", &nwrap_files_ops, NULL,
- &r->num_backends,
- &r->backends)) {
- NWRAP_ERROR(("%s: failed to initialize 'files' backend\n",
- __location__));
- return;
+ 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);
}
- if (winbind_so_path && strlen(winbind_so_path)) {
- if (!nwrap_module_init("winbind", &nwrap_module_ops, winbind_so_path,
- &r->num_backends,
- &r->backends)) {
- NWRAP_ERROR(("%s: failed to initialize 'winbind' backend\n",
- __location__));
- return;
- }
+ 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); \
}
+
+/* INTERNAL HELPER FUNCTIONS */
+static void nwrap_lines_unload(struct nwrap_cache *const nwrap)
+{
+ size_t p;
+ void *item;
+ nwrap_vector_foreach(item, nwrap->lines, p) {
+ /* Maybe some vectors were merged ... */
+ SAFE_FREE(item);
+ }
+ SAFE_FREE(nwrap->lines.items);
+ ZERO_STRUCTP(&nwrap->lines);
}
-static void nwrap_init(void)
+/*
+ * 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)
{
- static bool initialized;
+ nwrap_load_lib_function(NWRAP_LIBC, getpwnam);
- if (initialized) return;
- initialized = true;
+ return nwrap_main_global->libc->fns->_libc_getpwnam(name);
+}
- nwrap_main_global = &__nwrap_main_global;
+#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
- nwrap_backend_init(nwrap_main_global);
+ return nwrap_main_global->libc->fns->_libc_getpwnam_r(name,
+ pwd,
+ buf,
+ buflen,
+ result);
+}
+#endif
- nwrap_pw_global.cache = &__nwrap_cache_pw;
+static struct passwd *libc_getpwuid(uid_t uid)
+{
+ nwrap_load_lib_function(NWRAP_LIBC, getpwuid);
- nwrap_pw_global.cache->path = getenv("NSS_WRAPPER_PASSWD");
- nwrap_pw_global.cache->fd = -1;
- nwrap_pw_global.cache->private_data = &nwrap_pw_global;
- nwrap_pw_global.cache->parse_line = nwrap_pw_parse_line;
- nwrap_pw_global.cache->unload = nwrap_pw_unload;
+ return nwrap_main_global->libc->fns->_libc_getpwuid(uid);
+}
- nwrap_gr_global.cache = &__nwrap_cache_gr;
+#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
- nwrap_gr_global.cache->path = getenv("NSS_WRAPPER_GROUP");
- nwrap_gr_global.cache->fd = -1;
- 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;
+ return nwrap_main_global->libc->fns->_libc_getpwuid_r(uid,
+ pwd,
+ buf,
+ buflen,
+ result);
}
+#endif
-static bool nwrap_enabled(void)
+static inline void str_tolower(char *dst, char *src)
{
- nwrap_init();
+ register char *src_tmp = src;
+ register char *dst_tmp = dst;
- if (!nwrap_pw_global.cache->path) {
- return false;
- }
- if (nwrap_pw_global.cache->path[0] == '\0') {
- return false;
+ while (*src_tmp != '\0') {
+ *dst_tmp = tolower(*src_tmp);
+ ++src_tmp;
+ ++dst_tmp;
}
- if (!nwrap_gr_global.cache->path) {
+}
+
+static bool str_tolower_copy(char **dst_name, const char *const src_name)
+{
+ char *h_name_lower;
+
+ if ((dst_name == NULL) || (src_name == NULL)) {
return false;
}
- if (nwrap_gr_global.cache->path[0] == '\0') {
+
+ h_name_lower = strdup(src_name);
+ if (h_name_lower == NULL) {
+ NWRAP_LOG(NWRAP_LOG_DEBUG, "Out of memory while strdup");
return false;
}
+ str_tolower(h_name_lower, h_name_lower);
+ *dst_name = h_name_lower;
return true;
}
-static bool nwrap_parse_file(struct nwrap_cache *nwrap)
+static void libc_setpwent(void)
{
- int ret;
- uint8_t *buf = NULL;
- char *nline;
-
- if (nwrap->st.st_size == 0) {
- NWRAP_DEBUG(("%s: size == 0\n",
- __location__));
- 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));
- goto failed;
- }
+ nwrap_load_lib_function(NWRAP_LIBC, setpwent);
- ret = lseek(nwrap->fd, 0, SEEK_SET);
- if (ret != 0) {
- NWRAP_ERROR(("%s: lseek - %d\n",__location__,ret));
- goto failed;
- }
+ nwrap_main_global->libc->fns->_libc_setpwent();
+}
- buf = (uint8_t *)malloc(nwrap->st.st_size + 1);
- if (!buf) {
- NWRAP_ERROR(("%s: malloc failed\n",__location__));
- goto failed;
- }
+static struct passwd *libc_getpwent(void)
+{
+ nwrap_load_lib_function(NWRAP_LIBC, getpwent);
- 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));
- goto failed;
- }
+ return nwrap_main_global->libc->fns->_libc_getpwent();
+}
- buf[nwrap->st.st_size] = '\0';
+#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);
- nline = (char *)buf;
- while (nline && nline[0]) {
- char *line;
- char *e;
- bool ok;
+ 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);
- line = nline;
- nline = NULL;
+ return nwrap_main_global->libc->fns->_libc_getpwent_r(pwdst,
+ buf,
+ buflen,
+ pwdstp);
+}
+#endif /* HAVE_SOLARIS_GETPWENT_R */
- e = strchr(line, '\n');
- if (e) {
- e[0] = '\0';
- e++;
- if (e[0] == '\r') {
- e[0] = '\0';
- e++;
- }
- nline = e;
- }
+static void libc_endpwent(void)
+{
+ nwrap_load_lib_function(NWRAP_LIBC, endpwent);
- NWRAP_VERBOSE(("%s:'%s'\n",__location__, line));
+ nwrap_main_global->libc->fns->_libc_endpwent();
+}
- if (strlen(line) == 0) {
- continue;
- }
+static int libc_initgroups(const char *user, gid_t gid)
+{
+ nwrap_load_lib_function(NWRAP_LIBC, initgroups);
- ok = nwrap->parse_line(nwrap, line);
- if (!ok) {
- goto failed;
- }
- }
+ return nwrap_main_global->libc->fns->_libc_initgroups(user, gid);
+}
-done:
- nwrap->buf = buf;
- return true;
+static struct group *libc_getgrnam(const char *name)
+{
+ nwrap_load_lib_function(NWRAP_LIBC, getgrnam);
-failed:
- if (buf) free(buf);
- return false;
+ return nwrap_main_global->libc->fns->_libc_getgrnam(name);
}
-static void nwrap_files_cache_unload(struct nwrap_cache *nwrap)
+#ifdef HAVE_GETGRNAM_R
+static int libc_getgrnam_r(const char *name,
+ struct group *grp,
+ char *buf,
+ size_t buflen,
+ struct group **result)
{
- nwrap->unload(nwrap);
-
- if (nwrap->buf) free(nwrap->buf);
+#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
- nwrap->buf = NULL;
+ return nwrap_main_global->libc->fns->_libc_getgrnam_r(name,
+ grp,
+ buf,
+ buflen,
+ result);
}
+#endif
-static void nwrap_files_cache_reload(struct nwrap_cache *nwrap)
+static struct group *libc_getgrgid(gid_t gid)
{
- struct stat st;
- int ret;
- bool ok;
- bool retried = false;
+ nwrap_load_lib_function(NWRAP_LIBC, getgrgid);
-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)));
- return;
- }
- NWRAP_VERBOSE(("%s: open '%s'\n", __location__, nwrap->path));
- }
+ return nwrap_main_global->libc->fns->_libc_getgrgid(gid);
+}
- ret = fstat(nwrap->fd, &st);
- if (ret != 0) {
- NWRAP_ERROR(("%s: fstat(%s) - %d:%s\n",
- __location__,
- nwrap->path,
- ret, strerror(errno)));
- return;
+#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
- 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));
- retried = true;
- memset(&nwrap->st, 0, sizeof(nwrap->st));
- close(nwrap->fd);
- nwrap->fd = -1;
- goto reopen;
- }
+ return nwrap_main_global->libc->fns->_libc_getgrgid_r(gid,
+ grp,
+ buf,
+ buflen,
+ result);
+}
+#endif
- 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));
- return;
- }
- NWRAP_DEBUG(("%s: st_mtime has changed [%u] => [%u], start reload\n",
- __location__, (unsigned)st.st_mtime,
- (unsigned)nwrap->st.st_mtime));
+static void libc_setgrent(void)
+{
+ nwrap_load_lib_function(NWRAP_LIBC, setgrent);
- nwrap->st = st;
+ nwrap_main_global->libc->fns->_libc_setgrent();
+}
- nwrap_files_cache_unload(nwrap);
+static struct group *libc_getgrent(void)
+{
+ nwrap_load_lib_function(NWRAP_LIBC, getgrent);
- ok = nwrap_parse_file(nwrap);
- if (!ok) {
- NWRAP_ERROR(("%s: failed to reload %s\n",
- __location__, nwrap->path));
- nwrap_files_cache_unload(nwrap);
- }
- NWRAP_DEBUG(("%s: reloaded %s\n",
- __location__, nwrap->path));
+ return nwrap_main_global->libc->fns->_libc_getgrent();
}
-/*
- * the caller has to call nwrap_unload() on failure
- */
-static bool nwrap_pw_parse_line(struct nwrap_cache *nwrap, char *line)
+#ifdef HAVE_GETGRENT_R
+#ifdef HAVE_SOLARIS_GETGRENT_R
+static struct group *libc_getgrent_r(struct group *group,
+ char *buf,
+ size_t buflen)
{
- struct nwrap_pw *nwrap_pw;
- char *c;
- char *p;
- char *e;
- struct passwd *pw;
- size_t list_size;
-
- nwrap_pw = (struct nwrap_pw *)nwrap->private_data;
+ nwrap_load_lib_function(NWRAP_LIBC, getgrent_r);
- 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));
- return false;
- }
- nwrap_pw->list = pw;
+ 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);
- pw = &nwrap_pw->list[nwrap_pw->num];
+ return nwrap_main_global->libc->fns->_libc_getgrent_r(group,
+ buf,
+ buflen,
+ result);
+}
+#endif /* HAVE_SOLARIS_GETGRENT_R */
+#endif /* HAVE_GETGRENT_R */
- c = line;
+static void libc_endgrent(void)
+{
+ nwrap_load_lib_function(NWRAP_LIBC, endgrent);
- /* name */
- p = strchr(c, ':');
- if (!p) {
- NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
- __location__, line, c));
- return false;
- }
- *p = '\0';
- p++;
- pw->pw_name = c;
- c = p;
+ nwrap_main_global->libc->fns->_libc_endgrent();
+}
- NWRAP_VERBOSE(("name[%s]\n", pw->pw_name));
+#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);
- /* password */
- p = strchr(c, ':');
- if (!p) {
- NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
- __location__, line, c));
- return false;
- }
- *p = '\0';
- p++;
- pw->pw_passwd = c;
- c = p;
+ return nwrap_main_global->libc->fns->_libc_getgrouplist(user,
+ group,
+ groups,
+ ngroups);
+}
+#endif
- NWRAP_VERBOSE(("password[%s]\n", pw->pw_passwd));
+static void libc_sethostent(int stayopen)
+{
+ nwrap_load_lib_function(NWRAP_LIBNSL, sethostent);
- /* uid */
- p = strchr(c, ':');
- if (!p) {
- NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
- __location__, line, c));
- return false;
- }
- *p = '\0';
- p++;
- 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)));
- return false;
- }
- if (e == NULL) {
- NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
- __location__, line, c, strerror(errno)));
- return false;
- }
- if (e[0] != '\0') {
- NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
- __location__, line, c, strerror(errno)));
- return false;
- }
- c = p;
+ nwrap_main_global->libc->fns->_libc_sethostent(stayopen);
+}
- NWRAP_VERBOSE(("uid[%u]\n", pw->pw_uid));
+static struct hostent *libc_gethostent(void)
+{
+ nwrap_load_lib_function(NWRAP_LIBNSL, gethostent);
- /* gid */
- p = strchr(c, ':');
- if (!p) {
- NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
- __location__, line, c));
- return false;
- }
- *p = '\0';
- p++;
- 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)));
- return false;
- }
- if (e == NULL) {
- NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
- __location__, line, c, strerror(errno)));
- return false;
- }
- if (e[0] != '\0') {
- NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
- __location__, line, c, strerror(errno)));
- return false;
- }
- c = p;
+ return nwrap_main_global->libc->fns->_libc_gethostent();
+}
- NWRAP_VERBOSE(("gid[%u]\n", pw->pw_gid));
+static void libc_endhostent(void)
+{
+ nwrap_load_lib_function(NWRAP_LIBNSL, endhostent);
- /* gecos */
- p = strchr(c, ':');
- if (!p) {
- NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
- __location__, line, c));
- return false;
- }
- *p = '\0';
- p++;
- pw->pw_gecos = c;
- c = p;
+ nwrap_main_global->libc->fns->_libc_endhostent();
+}
- NWRAP_VERBOSE(("gecos[%s]\n", pw->pw_gecos));
+static struct hostent *libc_gethostbyname(const char *name)
+{
+ nwrap_load_lib_function(NWRAP_LIBNSL, gethostbyname);
- /* dir */
- p = strchr(c, ':');
- if (!p) {
- NWRAP_ERROR(("%s:'%s'\n",__location__,c));
- return false;
- }
- *p = '\0';
- p++;
- pw->pw_dir = c;
- c = p;
+ return nwrap_main_global->libc->fns->_libc_gethostbyname(name);
+}
- NWRAP_VERBOSE(("dir[%s]\n", pw->pw_dir));
+#ifdef HAVE_GETHOSTBYNAME2 /* GNU extension */
+static struct hostent *libc_gethostbyname2(const char *name, int af)
+{
+ nwrap_load_lib_function(NWRAP_LIBNSL, gethostbyname2);
- /* shell */
- pw->pw_shell = c;
- NWRAP_VERBOSE(("shell[%s]\n", pw->pw_shell));
+ return nwrap_main_global->libc->fns->_libc_gethostbyname2(name, af);
+}
+#endif
- 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));
+static struct hostent *libc_gethostbyaddr(const void *addr,
+ socklen_t len,
+ int type)
+{
+ nwrap_load_lib_function(NWRAP_LIBNSL, gethostbyaddr);
- nwrap_pw->num++;
- return true;
+ return nwrap_main_global->libc->fns->_libc_gethostbyaddr(addr,
+ len,
+ type);
}
-static void nwrap_pw_unload(struct nwrap_cache *nwrap)
+static int libc_gethostname(char *name, size_t len)
{
- struct nwrap_pw *nwrap_pw;
- nwrap_pw = (struct nwrap_pw *)nwrap->private_data;
+ nwrap_load_lib_function(NWRAP_LIBNSL, gethostname);
- if (nwrap_pw->list) free(nwrap_pw->list);
-
- nwrap_pw->list = NULL;
- nwrap_pw->num = 0;
- nwrap_pw->idx = 0;
+ return nwrap_main_global->libc->fns->_libc_gethostname(name, len);
}
-static int nwrap_pw_copy_r(const struct passwd *src, struct passwd *dst,
- char *buf, size_t buflen, struct passwd **dstp)
+#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)
{
- char *first;
- char *last;
- off_t ofs;
+ 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
- first = src->pw_name;
+#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
- last = src->pw_shell;
- while (*last) last++;
+static int libc_getaddrinfo(const char *node,
+ const char *service,
+ const struct addrinfo *hints,
+ struct addrinfo **res)
+{
+ nwrap_load_lib_function(NWRAP_LIBSOCKET, getaddrinfo);
- ofs = PTR_DIFF(last + 1, first);
+ return nwrap_main_global->libc->fns->_libc_getaddrinfo(node,
+ service,
+ hints,
+ res);
+}
- if (ofs > buflen) {
- return ERANGE;
- }
+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);
+}
- memcpy(buf, first, ofs);
+/*********************************************************
+ * NWRAP NSS MODULE LOADER FUNCTIONS
+ *********************************************************/
- ofs = PTR_DIFF(src->pw_name, first);
- dst->pw_name = buf + ofs;
- ofs = PTR_DIFF(src->pw_passwd, first);
- dst->pw_passwd = buf + ofs;
- dst->pw_uid = src->pw_uid;
- dst->pw_gid = src->pw_gid;
- ofs = PTR_DIFF(src->pw_gecos, first);
- dst->pw_gecos = buf + ofs;
- ofs = PTR_DIFF(src->pw_dir, first);
- dst->pw_dir = buf + ofs;
- ofs = PTR_DIFF(src->pw_shell, first);
- dst->pw_shell = buf + ofs;
+static void *nwrap_load_module_fn(struct nwrap_backend *b,
+ const char *fn_name)
+{
+ void *res;
+ char *s;
- if (dstp) {
- *dstp = dst;
+ if (!b->so_handle) {
+ NWRAP_LOG(NWRAP_LOG_ERROR, "No handle");
+ return NULL;
}
- return 0;
+ if (asprintf(&s, "_nss_%s_%s", b->name, fn_name) == -1) {
+ NWRAP_LOG(NWRAP_LOG_ERROR, "Out of memory");
+ return NULL;
+ }
+
+ res = dlsym(b->so_handle, s);
+ if (!res) {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "Cannot find function %s in %s",
+ s, b->so_path);
+ }
+ SAFE_FREE(s);
+ return res;
}
-/*
- * the caller has to call nwrap_unload() on failure
- */
-static bool nwrap_gr_parse_line(struct nwrap_cache *nwrap, char *line)
+static struct nwrap_module_nss_fns *nwrap_load_module_fns(struct nwrap_backend *b)
{
- struct nwrap_gr *nwrap_gr;
- char *c;
- char *p;
- char *e;
- struct group *gr;
- size_t list_size;
- unsigned nummem;
-
- nwrap_gr = (struct nwrap_gr *)nwrap->private_data;
+ struct nwrap_module_nss_fns *fns;
- 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__));
- return false;
+ if (!b->so_handle) {
+ return NULL;
}
- nwrap_gr->list = gr;
-
- gr = &nwrap_gr->list[nwrap_gr->num];
- c = line;
-
- /* name */
- p = strchr(c, ':');
- if (!p) {
- NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
- __location__, line, c));
- return false;
+ fns = (struct nwrap_module_nss_fns *)malloc(sizeof(struct nwrap_module_nss_fns));
+ if (!fns) {
+ return NULL;
}
- *p = '\0';
- p++;
- gr->gr_name = c;
- c = p;
- NWRAP_VERBOSE(("name[%s]\n", gr->gr_name));
+ *(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");
- /* password */
- p = strchr(c, ':');
- if (!p) {
- NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
- __location__, line, c));
- return false;
- }
- *p = '\0';
- p++;
- gr->gr_passwd = c;
- c = p;
+ return fns;
+}
- NWRAP_VERBOSE(("password[%s]\n", gr->gr_passwd));
+static void *nwrap_load_module(const char *so_path)
+{
+ void *h;
- /* gid */
- p = strchr(c, ':');
- if (!p) {
- NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
- __location__, line, c));
- return false;
- }
- *p = '\0';
- p++;
- 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)));
- return false;
- }
- if (e == NULL) {
- NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
- __location__, line, c, strerror(errno)));
- return false;
+ if (!so_path || !strlen(so_path)) {
+ return NULL;
}
- if (e[0] != '\0') {
- NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
- __location__, line, c, strerror(errno)));
- return false;
+
+ h = dlopen(so_path, RTLD_LAZY);
+ if (!h) {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "Cannot open shared library %s",
+ so_path);
+ return NULL;
}
- c = p;
- NWRAP_VERBOSE(("gid[%u]\n", gr->gr_gid));
+ return h;
+}
- /* members */
- gr->gr_mem = (char **)malloc(sizeof(char *));
- if (!gr->gr_mem) {
- NWRAP_ERROR(("%s:calloc failed\n",__location__));
+static bool nwrap_module_init(const char *name,
+ struct nwrap_ops *ops,
+ const char *so_path,
+ int *num_backends,
+ struct nwrap_backend **backends)
+{
+ struct nwrap_backend *b;
+
+ *backends = (struct nwrap_backend *)realloc(*backends,
+ sizeof(struct nwrap_backend) * ((*num_backends) + 1));
+ if (!*backends) {
+ NWRAP_LOG(NWRAP_LOG_ERROR, "Out of memory");
return false;
}
- gr->gr_mem[0] = NULL;
- for(nummem=0; p; nummem++) {
- char **m;
- size_t m_size;
- c = p;
- p = strchr(c, ',');
- if (p) {
- *p = '\0';
- p++;
- }
+ b = &((*backends)[*num_backends]);
- if (strlen(c) == 0) {
- break;
- }
+ b->name = name;
+ b->ops = ops;
+ b->so_path = so_path;
- 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));
+ if (so_path != NULL) {
+ b->so_handle = nwrap_load_module(so_path);
+ b->fns = nwrap_load_module_fns(b);
+ if (b->fns == NULL) {
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]));
+ } else {
+ b->so_handle = NULL;
+ b->fns = NULL;
}
- NWRAP_DEBUG(("add group[%s:%s:%u:] with %u members\n",
- gr->gr_name, gr->gr_passwd, gr->gr_gid, nummem));
+ (*num_backends)++;
- nwrap_gr->num++;
return true;
}
-static void nwrap_gr_unload(struct nwrap_cache *nwrap)
+static void nwrap_libc_init(struct nwrap_main *r)
{
- int i;
- struct nwrap_gr *nwrap_gr;
- nwrap_gr = (struct nwrap_gr *)nwrap->private_data;
-
- if (nwrap_gr->list) {
- for (i=0; i < nwrap_gr->num; i++) {
- if (nwrap_gr->list[i].gr_mem) {
- free(nwrap_gr->list[i].gr_mem);
- }
- }
- free(nwrap_gr->list);
+ r->libc = malloc(sizeof(struct nwrap_libc));
+ if (r->libc == NULL) {
+ printf("Failed to allocate memory for libc");
+ exit(-1);
}
+ ZERO_STRUCTP(r->libc);
- nwrap_gr->list = NULL;
- nwrap_gr->num = 0;
- nwrap_gr->idx = 0;
+ 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 int nwrap_gr_copy_r(const struct group *src, struct group *dst,
- char *buf, size_t buflen, struct group **dstp)
+static void nwrap_backend_init(struct nwrap_main *r)
{
- char *first;
- char **lastm;
- char *last = NULL;
- off_t ofsb;
- off_t ofsm;
- off_t ofs;
- unsigned i;
+ const char *module_so_path = getenv("NSS_WRAPPER_MODULE_SO_PATH");
+ const char *module_fn_name = getenv("NSS_WRAPPER_MODULE_FN_PREFIX");
- first = src->gr_name;
+ r->num_backends = 0;
+ r->backends = NULL;
- lastm = src->gr_mem;
- while (*lastm) {
- last = *lastm;
- lastm++;
+ if (!nwrap_module_init("files", &nwrap_files_ops, NULL,
+ &r->num_backends,
+ &r->backends)) {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "Failed to initialize 'files' backend");
+ return;
}
- if (last == NULL) {
- last = src->gr_passwd;
+ 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_LOG(NWRAP_LOG_ERROR,
+ "Failed to initialize '%s' backend",
+ module_fn_name);
+ return;
+ }
}
- while (*last) last++;
+}
- ofsb = PTR_DIFF(last + 1, first);
- ofsm = PTR_DIFF(lastm + 1, src->gr_mem);
+static void nwrap_init(void)
+{
+ const char *env;
+ char *endptr;
+ size_t max_hostents_tmp;
- if ((ofsb + ofsm) > buflen) {
- return ERANGE;
+ NWRAP_LOCK(nwrap_initialized);
+ if (nwrap_initialized) {
+ NWRAP_UNLOCK(nwrap_initialized);
+ return;
}
- memcpy(buf, first, ofsb);
- memcpy(buf + ofsb, src->gr_mem, ofsm);
+ /*
+ * Still holding nwrap_initialized lock here.
+ * We don't use NWRAP_(UN)LOCK_ALL macros here because we
+ * want to avoid overhead when other threads do their job.
+ */
+ NWRAP_LOCK(nwrap_global);
+ NWRAP_LOCK(nwrap_gr_global);
+ NWRAP_LOCK(nwrap_he_global);
+ NWRAP_LOCK(nwrap_pw_global);
+ NWRAP_LOCK(nwrap_sp_global);
+
+ nwrap_initialized = true;
+
+ /* Initialize pthread_atfork handlers */
+ pthread_atfork(&nwrap_thread_prepare, &nwrap_thread_parent,
+ &nwrap_thread_child);
+
+ env = getenv("NSS_WRAPPER_MAX_HOSTENTS");
+ if (env != NULL) {
+ max_hostents_tmp = (size_t)strtol(env, &endptr, 10);
+ if (((env != '\0') && (endptr == '\0')) ||
+ (max_hostents_tmp == 0)) {
+ NWRAP_LOG(NWRAP_LOG_DEBUG,
+ "Error parsing NSS_WRAPPER_MAX_HOSTENTS "
+ "value or value is too small. "
+ "Using default value: %lu.",
+ max_hostents);
+ } else {
+ max_hostents = max_hostents_tmp;
+ }
+ }
+ /* Initialize hash table */
+ NWRAP_LOG(NWRAP_LOG_DEBUG,
+ "Initializing hash table of size %lu items.", max_hostents);
+ if (hcreate(max_hostents) == 0) {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "Failed to initialize hash table");
+ goto done;
+ }
- ofs = PTR_DIFF(src->gr_name, first);
- dst->gr_name = buf + ofs;
- ofs = PTR_DIFF(src->gr_passwd, first);
- dst->gr_passwd = buf + ofs;
- dst->gr_gid = src->gr_gid;
+ nwrap_main_global = &__nwrap_main_global;
- dst->gr_mem = (char **)(buf + ofsb);
- for (i=0; src->gr_mem[i]; i++) {
- ofs = PTR_DIFF(src->gr_mem[i], first);
- dst->gr_mem[i] = buf + ofs;
- }
+ nwrap_libc_init(nwrap_main_global);
- if (dstp) {
- *dstp = dst;
- }
+ nwrap_backend_init(nwrap_main_global);
- return 0;
+ /* passwd */
+ nwrap_pw_global.cache = &__nwrap_cache_pw;
+
+ nwrap_pw_global.cache->path = getenv("NSS_WRAPPER_PASSWD");
+ nwrap_pw_global.cache->fp = NULL;
+ nwrap_pw_global.cache->fd = -1;
+ nwrap_pw_global.cache->private_data = &nwrap_pw_global;
+ nwrap_pw_global.cache->parse_line = nwrap_pw_parse_line;
+ nwrap_pw_global.cache->unload = nwrap_pw_unload;
+
+ /* shadow */
+#if defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM)
+ nwrap_sp_global.cache = &__nwrap_cache_sp;
+
+ nwrap_sp_global.cache->path = getenv("NSS_WRAPPER_SHADOW");
+ nwrap_sp_global.cache->fp = NULL;
+ nwrap_sp_global.cache->fd = -1;
+ nwrap_sp_global.cache->private_data = &nwrap_sp_global;
+ nwrap_sp_global.cache->parse_line = nwrap_sp_parse_line;
+ nwrap_sp_global.cache->unload = nwrap_sp_unload;
+#endif /* defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM) */
+
+ /* group */
+ nwrap_gr_global.cache = &__nwrap_cache_gr;
+
+ nwrap_gr_global.cache->path = getenv("NSS_WRAPPER_GROUP");
+ nwrap_gr_global.cache->fp = NULL;
+ nwrap_gr_global.cache->fd = -1;
+ 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;
+
+ /* hosts */
+ nwrap_he_global.cache = &__nwrap_cache_he;
+
+ nwrap_he_global.cache->path = getenv("NSS_WRAPPER_HOSTS");
+ nwrap_he_global.cache->fp = NULL;
+ 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;
+
+done:
+ /* We hold all locks here so we can use NWRAP_UNLOCK_ALL. */
+ NWRAP_UNLOCK_ALL;
}
-/* user functions */
-static struct passwd *nwrap_files_getpwnam(struct nwrap_backend *b,
- const char *name)
+bool nss_wrapper_enabled(void)
{
- int i;
+ nwrap_init();
+
+ if (nwrap_pw_global.cache->path == NULL ||
+ nwrap_pw_global.cache->path[0] == '\0') {
+ return false;
+ }
+ if (nwrap_gr_global.cache->path == NULL ||
+ nwrap_gr_global.cache->path[0] == '\0') {
+ return false;
+ }
- nwrap_files_cache_reload(nwrap_pw_global.cache);
+ return true;
+}
- 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));
- return &nwrap_pw_global.list[i];
+#if defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM)
+bool nss_wrapper_shadow_enabled(void)
+{
+ nwrap_init();
+
+ if (nwrap_sp_global.cache->path == NULL ||
+ nwrap_sp_global.cache->path[0] == '\0') {
+ return false;
+ }
+
+ return true;
+}
+#endif /* defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM) */
+
+bool nss_wrapper_hosts_enabled(void)
+{
+ nwrap_init();
+
+ if (nwrap_he_global.cache->path == NULL ||
+ nwrap_he_global.cache->path[0] == '\0') {
+ return false;
+ }
+
+ return true;
+}
+
+static bool nwrap_hostname_enabled(void)
+{
+ nwrap_init();
+
+ if (getenv("NSS_WRAPPER_HOSTNAME") == NULL) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool nwrap_parse_file(struct nwrap_cache *nwrap)
+{
+ char *line = NULL;
+ ssize_t n;
+ /* Unused but getline needs it */
+ size_t len;
+ bool ok;
+
+ if (nwrap->st.st_size == 0) {
+ NWRAP_LOG(NWRAP_LOG_DEBUG, "size == 0");
+ return true;
+ }
+
+ /* Support for 32-bit system I guess */
+ if (nwrap->st.st_size > INT32_MAX) {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "Size[%u] larger than INT32_MAX",
+ (unsigned)nwrap->st.st_size);
+ return false;
+ }
+
+ rewind(nwrap->fp);
+
+ do {
+ n = getline(&line, &len, nwrap->fp);
+ if (n < 0) {
+ SAFE_FREE(line);
+ if (feof(nwrap->fp)) {
+ break;
+ }
+
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "Unable to read line from file: %s",
+ nwrap->path);
+ return false;
+ }
+
+ if (line[n - 1] == '\n') {
+ line[n - 1] = '\0';
+ }
+
+ if (line[0] == '\0') {
+ SAFE_FREE(line);
+ continue;
+ }
+
+ ok = nwrap->parse_line(nwrap, line);
+ if (!ok) {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "Unable to parse line file: %s",
+ line);
+ SAFE_FREE(line);
+ return false;
+ }
+
+ /* Line is parsed without issues so add it to list */
+ ok = nwrap_vector_add_item(&(nwrap->lines), (void *const) line);
+ if (!ok) {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "Unable to add line to vector");
+ return false;
+ }
+
+ /* This forces getline to allocate new memory for line. */
+ line = NULL;
+ } while (!feof(nwrap->fp));
+
+ return true;
+}
+
+static void nwrap_files_cache_unload(struct nwrap_cache *nwrap)
+{
+ nwrap->unload(nwrap);
+
+ nwrap_lines_unload(nwrap);
+}
+
+static bool nwrap_files_cache_reload(struct nwrap_cache *nwrap)
+{
+ struct stat st;
+ int ret;
+ bool ok;
+ bool retried = false;
+
+ assert(nwrap != NULL);
+
+reopen:
+ if (nwrap->fd < 0) {
+ nwrap->fp = fopen(nwrap->path, "re");
+ if (nwrap->fp == NULL) {
+ nwrap->fd = -1;
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "Unable to open '%s' readonly %d:%s",
+ nwrap->path, nwrap->fd,
+ strerror(errno));
+ return false;
+
+ }
+ nwrap->fd = fileno(nwrap->fp);
+ NWRAP_LOG(NWRAP_LOG_DEBUG, "Open '%s'", nwrap->path);
+ }
+
+ ret = fstat(nwrap->fd, &st);
+ if (ret != 0) {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "fstat(%s) - %d:%s",
+ nwrap->path,
+ ret,
+ strerror(errno));
+ fclose(nwrap->fp);
+ nwrap->fp = NULL;
+ nwrap->fd = -1;
+ return false;
+ }
+
+ if (retried == false && st.st_nlink == 0) {
+ /* maybe someone has replaced the file... */
+ NWRAP_LOG(NWRAP_LOG_TRACE,
+ "st_nlink == 0, reopen %s",
+ nwrap->path);
+ retried = true;
+ memset(&nwrap->st, 0, sizeof(nwrap->st));
+ fclose(nwrap->fp);
+ nwrap->fp = NULL;
+ nwrap->fd = -1;
+ goto reopen;
+ }
+
+ if (st.st_mtime == nwrap->st.st_mtime) {
+ NWRAP_LOG(NWRAP_LOG_TRACE,
+ "st_mtime[%u] hasn't changed, skip reload",
+ (unsigned)st.st_mtime);
+ return true;
+ }
+
+ 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;
+
+ nwrap_files_cache_unload(nwrap);
+
+ ok = nwrap_parse_file(nwrap);
+ if (!ok) {
+ NWRAP_LOG(NWRAP_LOG_ERROR, "Failed to reload %s", nwrap->path);
+ nwrap_files_cache_unload(nwrap);
+ return false;
+ }
+
+ NWRAP_LOG(NWRAP_LOG_TRACE, "Reloaded %s", nwrap->path);
+ return true;
+}
+
+/*
+ * the caller has to call nwrap_unload() on failure
+ */
+static bool nwrap_pw_parse_line(struct nwrap_cache *nwrap, char *line)
+{
+ struct nwrap_pw *nwrap_pw;
+ char *c;
+ char *p;
+ char *e;
+ struct passwd *pw;
+ size_t list_size;
+
+ nwrap_pw = (struct nwrap_pw *)nwrap->private_data;
+
+ list_size = sizeof(*nwrap_pw->list) * (nwrap_pw->num+1);
+ pw = (struct passwd *)realloc(nwrap_pw->list, list_size);
+ if (!pw) {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "realloc(%u) failed",
+ (unsigned)list_size);
+ return false;
+ }
+ nwrap_pw->list = pw;
+
+ pw = &nwrap_pw->list[nwrap_pw->num];
+
+ c = line;
+
+ /* name */
+ p = strchr(c, ':');
+ if (!p) {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "Invalid line[%s]: '%s'",
+ line,
+ c);
+ return false;
+ }
+ *p = '\0';
+ p++;
+ pw->pw_name = c;
+ c = p;
+
+ NWRAP_LOG(NWRAP_LOG_TRACE, "name[%s]\n", pw->pw_name);
+
+ /* password */
+ p = strchr(c, ':');
+ if (!p) {
+ NWRAP_LOG(NWRAP_LOG_ERROR, "Invalid line[%s]: '%s'", line, c);
+ return false;
+ }
+ *p = '\0';
+ p++;
+ pw->pw_passwd = c;
+ c = p;
+
+ NWRAP_LOG(NWRAP_LOG_TRACE, "password[%s]\n", pw->pw_passwd);
+
+ /* uid */
+ p = strchr(c, ':');
+ if (!p) {
+ NWRAP_LOG(NWRAP_LOG_ERROR, "Invalid line[%s]: '%s'", line, c);
+ return false;
+ }
+ *p = '\0';
+ p++;
+ e = NULL;
+ pw->pw_uid = (uid_t)strtoul(c, &e, 10);
+ if (c == e) {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "Invalid line[%s]: '%s' - %s",
+ line, c, strerror(errno));
+ return false;
+ }
+ if (e == NULL) {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "Invalid line[%s]: '%s' - %s",
+ line, c, strerror(errno));
+ return false;
+ }
+ if (e[0] != '\0') {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "Invalid line[%s]: '%s' - %s",
+ line, c, strerror(errno));
+ return false;
+ }
+ c = p;
+
+ NWRAP_LOG(NWRAP_LOG_TRACE, "uid[%u]", pw->pw_uid);
+
+ /* gid */
+ p = strchr(c, ':');
+ if (!p) {
+ NWRAP_LOG(NWRAP_LOG_ERROR, "Invalid line[%s]: '%s'", line, c);
+ return false;
+ }
+ *p = '\0';
+ p++;
+ e = NULL;
+ pw->pw_gid = (gid_t)strtoul(c, &e, 10);
+ if (c == e) {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "Invalid line[%s]: '%s' - %s",
+ line, c, strerror(errno));
+ return false;
+ }
+ if (e == NULL) {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "Invalid line[%s]: '%s' - %s",
+ line, c, strerror(errno));
+ return false;
+ }
+ if (e[0] != '\0') {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "Invalid line[%s]: '%s' - %s",
+ line, c, strerror(errno));
+ return false;
+ }
+ c = p;
+
+ NWRAP_LOG(NWRAP_LOG_TRACE, "gid[%u]\n", pw->pw_gid);
+
+ /* gecos */
+ p = strchr(c, ':');
+ if (!p) {
+ NWRAP_LOG(NWRAP_LOG_ERROR, "invalid line[%s]: '%s'", line, c);
+ return false;
+ }
+ *p = '\0';
+ p++;
+ pw->pw_gecos = c;
+ c = p;
+
+ NWRAP_LOG(NWRAP_LOG_TRACE, "gecos[%s]", pw->pw_gecos);
+
+ /* dir */
+ p = strchr(c, ':');
+ if (!p) {
+ NWRAP_LOG(NWRAP_LOG_ERROR, "'%s'", c);
+ return false;
+ }
+ *p = '\0';
+ p++;
+ pw->pw_dir = c;
+ c = p;
+
+ NWRAP_LOG(NWRAP_LOG_TRACE, "dir[%s]", pw->pw_dir);
+
+ /* shell */
+ pw->pw_shell = c;
+ NWRAP_LOG(NWRAP_LOG_TRACE, "shell[%s]", 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;
+}
+
+static void nwrap_pw_unload(struct nwrap_cache *nwrap)
+{
+ struct nwrap_pw *nwrap_pw;
+ nwrap_pw = (struct nwrap_pw *)nwrap->private_data;
+
+ SAFE_FREE(nwrap_pw->list);
+ nwrap_pw->num = 0;
+ nwrap_pw->idx = 0;
+}
+
+static int nwrap_pw_copy_r(const struct passwd *src, struct passwd *dst,
+ char *buf, size_t buflen, struct passwd **dstp)
+{
+ char *first;
+ char *last;
+ off_t ofs;
+
+ first = src->pw_name;
+
+ last = src->pw_shell;
+ while (*last) last++;
+
+ ofs = PTR_DIFF(last + 1, first);
+
+ if (ofs > (off_t) buflen) {
+ return ERANGE;
+ }
+
+ memcpy(buf, first, ofs);
+
+ ofs = PTR_DIFF(src->pw_name, first);
+ dst->pw_name = buf + ofs;
+ ofs = PTR_DIFF(src->pw_passwd, first);
+ dst->pw_passwd = buf + ofs;
+ dst->pw_uid = src->pw_uid;
+ dst->pw_gid = src->pw_gid;
+ ofs = PTR_DIFF(src->pw_gecos, first);
+ dst->pw_gecos = buf + ofs;
+ ofs = PTR_DIFF(src->pw_dir, first);
+ dst->pw_dir = buf + ofs;
+ ofs = PTR_DIFF(src->pw_shell, first);
+ dst->pw_shell = buf + ofs;
+
+ if (dstp) {
+ *dstp = dst;
+ }
+
+ return 0;
+}
+
+#if defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM)
+static bool nwrap_sp_parse_line(struct nwrap_cache *nwrap, char *line)
+{
+ struct nwrap_sp *nwrap_sp;
+ struct spwd *sp;
+ size_t list_size;
+ char *c;
+ char *e;
+ char *p;
+
+ nwrap_sp = (struct nwrap_sp *)nwrap->private_data;
+
+ list_size = sizeof(*nwrap_sp->list) * (nwrap_sp->num+1);
+ sp = (struct spwd *)realloc(nwrap_sp->list, list_size);
+ if (sp == NULL) {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "realloc(%u) failed",
+ (unsigned)list_size);
+ return false;
+ }
+ nwrap_sp->list = sp;
+
+ sp = &nwrap_sp->list[nwrap_sp->num];
+
+ c = line;
+
+ /* name */
+ p = strchr(c, ':');
+ if (p == NULL) {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "name -- Invalid line[%s]: '%s'",
+ line,
+ c);
+ return false;
+ }
+ *p = '\0';
+ p++;
+ sp->sp_namp = c;
+ c = p;
+
+ NWRAP_LOG(NWRAP_LOG_TRACE, "name[%s]\n", sp->sp_namp);
+
+ /* pwd */
+ p = strchr(c, ':');
+ if (p == NULL) {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "pwd -- Invalid line[%s]: '%s'",
+ line,
+ c);
+ return false;
+ }
+ *p = '\0';
+ p++;
+ sp->sp_pwdp = c;
+ c = p;
+
+ /* lstchg (long) */
+ if (c[0] == ':') {
+ sp->sp_lstchg = -1;
+ p++;
+ } else {
+ p = strchr(c, ':');
+ if (p == NULL) {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "lstchg -- Invalid line[%s]: '%s'",
+ line,
+ c);
+ return false;
+ }
+ *p = '\0';
+ p++;
+ sp->sp_lstchg = strtol(c, &e, 10);
+ if (c == e) {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "lstchg -- Invalid line[%s]: '%s' - %s",
+ line, c, strerror(errno));
+ return false;
+ }
+ if (e == NULL) {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "lstchg -- Invalid line[%s]: '%s' - %s",
+ line, c, strerror(errno));
+ return false;
+ }
+ if (e[0] != '\0') {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "lstchg -- Invalid line[%s]: '%s' - %s",
+ line, c, strerror(errno));
+ return false;
+ }
+ }
+ c = p;
+
+ /* min (long) */
+ if (c[0] == ':') {
+ sp->sp_min = -1;
+ p++;
+ } else {
+ p = strchr(c, ':');
+ if (p == NULL) {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "min -- Invalid line[%s]: '%s'",
+ line,
+ c);
+ return false;
+ }
+ *p = '\0';
+ p++;
+ sp->sp_min = strtol(c, &e, 10);
+ if (c == e) {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "min -- Invalid line[%s]: '%s' - %s",
+ line, c, strerror(errno));
+ return false;
+ }
+ if (e == NULL) {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "min -- Invalid line[%s]: '%s' - %s",
+ line, c, strerror(errno));
+ return false;
+ }
+ if (e[0] != '\0') {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "min -- Invalid line[%s]: '%s' - %s",
+ line, c, strerror(errno));
+ return false;
+ }
+ }
+ c = p;
+
+ /* max (long) */
+ if (c[0] == ':') {
+ sp->sp_max = -1;
+ p++;
+ } else {
+ p = strchr(c, ':');
+ if (p == NULL) {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "max -- Invalid line[%s]: '%s'",
+ line,
+ c);
+ return false;
+ }
+ *p = '\0';
+ p++;
+ sp->sp_max = strtol(c, &e, 10);
+ if (c == e) {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "max -- Invalid line[%s]: '%s' - %s",
+ line, c, strerror(errno));
+ return false;
+ }
+ if (e == NULL) {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "max -- Invalid line[%s]: '%s' - %s",
+ line, c, strerror(errno));
+ return false;
+ }
+ if (e[0] != '\0') {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "max -- Invalid line[%s]: '%s' - %s",
+ line, c, strerror(errno));
+ return false;
+ }
+ }
+ c = p;
+
+ /* warn (long) */
+ if (c[0] == ':') {
+ sp->sp_warn = -1;
+ p++;
+ } else {
+ p = strchr(c, ':');
+ if (p == NULL) {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "warn -- Invalid line[%s]: '%s'",
+ line,
+ c);
+ return false;
+ }
+ *p = '\0';
+ p++;
+ sp->sp_warn = strtol(c, &e, 10);
+ if (c == e) {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "warn -- Invalid line[%s]: '%s' - %s",
+ line, c, strerror(errno));
+ return false;
+ }
+ if (e == NULL) {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "warn -- Invalid line[%s]: '%s' - %s",
+ line, c, strerror(errno));
+ return false;
+ }
+ if (e[0] != '\0') {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "warn -- Invalid line[%s]: '%s' - %s",
+ line, c, strerror(errno));
+ return false;
+ }
+ }
+ c = p;
+
+ /* inact (long) */
+ if (c[0] == ':') {
+ sp->sp_inact = -1;
+ p++;
+ } else {
+ p = strchr(c, ':');
+ if (p == NULL) {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "inact -- Invalid line[%s]: '%s'",
+ line,
+ c);
+ return false;
+ }
+ *p = '\0';
+ p++;
+ sp->sp_inact = strtol(c, &e, 10);
+ if (c == e) {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "inact -- Invalid line[%s]: '%s' - %s",
+ line, c, strerror(errno));
+ return false;
+ }
+ if (e == NULL) {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "inact -- Invalid line[%s]: '%s' - %s",
+ line, c, strerror(errno));
+ return false;
+ }
+ if (e[0] != '\0') {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "inact -- Invalid line[%s]: '%s' - %s",
+ line, c, strerror(errno));
+ return false;
+ }
+ }
+ c = p;
+
+ /* expire (long) */
+ if (c[0] == ':') {
+ sp->sp_expire = -1;
+ p++;
+ } else {
+ p = strchr(c, ':');
+ if (p == NULL) {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "expire -- Invalid line[%s]: '%s'",
+ line,
+ c);
+ return false;
+ }
+ *p = '\0';
+ p++;
+ sp->sp_expire = strtol(c, &e, 10);
+ if (c == e) {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "expire -- Invalid line[%s]: '%s' - %s",
+ line, c, strerror(errno));
+ return false;
+ }
+ if (e == NULL) {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "expire -- Invalid line[%s]: '%s' - %s",
+ line, c, strerror(errno));
+ return false;
+ }
+ if (e[0] != '\0') {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "expire -- Invalid line[%s]: '%s' - %s",
+ line, c, strerror(errno));
+ return false;
+ }
+ }
+ c = p;
+
+ nwrap_sp->num++;
+ return true;
+}
+
+static void nwrap_sp_unload(struct nwrap_cache *nwrap)
+{
+ struct nwrap_sp *nwrap_sp;
+ nwrap_sp = (struct nwrap_sp *)nwrap->private_data;
+
+ SAFE_FREE(nwrap_sp->list);
+ nwrap_sp->num = 0;
+ nwrap_sp->idx = 0;
+}
+#endif /* defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM) */
+
+/*
+ * the caller has to call nwrap_unload() on failure
+ */
+static bool nwrap_gr_parse_line(struct nwrap_cache *nwrap, char *line)
+{
+ struct nwrap_gr *nwrap_gr;
+ char *c;
+ char *p;
+ char *e;
+ struct group *gr;
+ size_t list_size;
+ unsigned nummem;
+
+ nwrap_gr = (struct nwrap_gr *)nwrap->private_data;
+
+ list_size = sizeof(*nwrap_gr->list) * (nwrap_gr->num+1);
+ gr = (struct group *)realloc(nwrap_gr->list, list_size);
+ if (!gr) {
+ NWRAP_LOG(NWRAP_LOG_ERROR, "realloc failed");
+ return false;
+ }
+ nwrap_gr->list = gr;
+
+ gr = &nwrap_gr->list[nwrap_gr->num];
+
+ c = line;
+
+ /* name */
+ p = strchr(c, ':');
+ if (!p) {
+ NWRAP_LOG(NWRAP_LOG_ERROR, "Invalid line[%s]: '%s'", line, c);
+ return false;
+ }
+ *p = '\0';
+ p++;
+ gr->gr_name = c;
+ c = p;
+
+ NWRAP_LOG(NWRAP_LOG_TRACE, "name[%s]", gr->gr_name);
+
+ /* password */
+ p = strchr(c, ':');
+ if (!p) {
+ NWRAP_LOG(NWRAP_LOG_ERROR, "Invalid line[%s]: '%s'", line, c);
+ return false;
+ }
+ *p = '\0';
+ p++;
+ gr->gr_passwd = c;
+ c = p;
+
+ NWRAP_LOG(NWRAP_LOG_TRACE, "password[%s]", gr->gr_passwd);
+
+ /* gid */
+ p = strchr(c, ':');
+ if (!p) {
+ NWRAP_LOG(NWRAP_LOG_ERROR, "Invalid line[%s]: '%s'", line, c);
+ return false;
+ }
+ *p = '\0';
+ p++;
+ e = NULL;
+ gr->gr_gid = (gid_t)strtoul(c, &e, 10);
+ if (c == e) {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "Invalid line[%s]: '%s' - %s",
+ line, c, strerror(errno));
+ return false;
+ }
+ if (e == NULL) {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "Invalid line[%s]: '%s' - %s",
+ line, c, strerror(errno));
+ return false;
+ }
+ if (e[0] != '\0') {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "Invalid line[%s]: '%s' - %s",
+ line, c, strerror(errno));
+ return false;
+ }
+ c = p;
+
+ NWRAP_LOG(NWRAP_LOG_TRACE, "gid[%u]", gr->gr_gid);
+
+ /* members */
+ gr->gr_mem = (char **)malloc(sizeof(char *));
+ if (!gr->gr_mem) {
+ NWRAP_LOG(NWRAP_LOG_ERROR, "Out of memory");
+ return false;
+ }
+ gr->gr_mem[0] = NULL;
+
+ for(nummem=0; p; nummem++) {
+ char **m;
+ size_t m_size;
+ c = p;
+ p = strchr(c, ',');
+ if (p) {
+ *p = '\0';
+ p++;
+ }
+
+ if (strlen(c) == 0) {
+ break;
+ }
+
+ m_size = sizeof(char *) * (nummem+2);
+ m = (char **)realloc(gr->gr_mem, m_size);
+ if (!m) {
+ 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_LOG(NWRAP_LOG_TRACE,
+ "member[%u]: '%s'",
+ nummem, gr->gr_mem[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;
+}
+
+static void nwrap_gr_unload(struct nwrap_cache *nwrap)
+{
+ int i;
+ struct nwrap_gr *nwrap_gr;
+ nwrap_gr = (struct nwrap_gr *)nwrap->private_data;
+
+ if (nwrap_gr->list) {
+ for (i=0; i < nwrap_gr->num; i++) {
+ SAFE_FREE(nwrap_gr->list[i].gr_mem);
+ }
+ SAFE_FREE(nwrap_gr->list);
+ }
+
+ nwrap_gr->num = 0;
+ nwrap_gr->idx = 0;
+}
+
+static int nwrap_gr_copy_r(const struct group *src, struct group *dst,
+ char *buf, size_t buflen, struct group **dstp)
+{
+ char *first;
+ char **lastm;
+ char *last = NULL;
+ off_t ofsb;
+ off_t ofsm;
+ off_t ofs;
+ unsigned i;
+
+ first = src->gr_name;
+
+ lastm = src->gr_mem;
+ while (*lastm) {
+ last = *lastm;
+ lastm++;
+ }
+
+ if (last == NULL) {
+ last = src->gr_passwd;
+ }
+ while (*last) last++;
+
+ ofsb = PTR_DIFF(last + 1, first);
+ ofsm = PTR_DIFF(lastm + 1, src->gr_mem);
+
+ if ((ofsb + ofsm) > (off_t) buflen) {
+ return ERANGE;
+ }
+
+ memcpy(buf, first, ofsb);
+ memcpy(buf + ofsb, src->gr_mem, ofsm);
+
+ ofs = PTR_DIFF(src->gr_name, first);
+ dst->gr_name = buf + ofs;
+ ofs = PTR_DIFF(src->gr_passwd, first);
+ dst->gr_passwd = buf + ofs;
+ dst->gr_gid = src->gr_gid;
+
+ dst->gr_mem = (char **)(buf + ofsb);
+ for (i=0; src->gr_mem[i]; i++) {
+ ofs = PTR_DIFF(src->gr_mem[i], first);
+ dst->gr_mem[i] = buf + ofs;
+ }
+
+ if (dstp) {
+ *dstp = dst;
+ }
+
+ return 0;
+}
+
+static struct nwrap_entlist *nwrap_entlist_init(struct nwrap_entdata *ed)
+{
+ struct nwrap_entlist *el;
+
+ if (ed == NULL) {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "entry is NULL, can't create list item");
+ return NULL;
+ }
+
+ el = (struct nwrap_entlist *)malloc(sizeof(struct nwrap_entlist));
+ if (el == NULL) {
+ NWRAP_LOG(NWRAP_LOG_ERROR, "malloc failed");
+ return NULL;
+ }
+
+ el->next = NULL;
+ el->ed = ed;
+
+ return el;
+}
+
+static bool nwrap_add_ai(char *const ip_addr, struct nwrap_entdata *const ed)
+{
+ ENTRY e;
+ ENTRY *p;
+ struct nwrap_entlist *el;
+
+ if (ip_addr == NULL) {
+ NWRAP_LOG(NWRAP_LOG_ERROR, "ip_addr NULL - can't add");
+ return false;
+ }
+
+ el = nwrap_entlist_init(ed);
+ if (el == NULL) {
+ return false;
+ }
+
+ e.key = ip_addr;
+ e.data = el;
+
+ p = hsearch(e, ENTER);
+ if (p == NULL) {
+ NWRAP_LOG(NWRAP_LOG_ERROR, "Hash table is full");
+ return false;
+ }
+
+ return true;
+}
+
+
+static bool nwrap_add_hname_add_new(char *const h_name,
+ struct nwrap_entdata *const ed)
+{
+ ENTRY e;
+ ENTRY *p;
+ struct nwrap_entlist *el;
+
+ if (h_name == NULL) {
+ NWRAP_LOG(NWRAP_LOG_ERROR, "h_name NULL - can't add");
+ return false;
+ }
+
+ el = nwrap_entlist_init(ed);
+ if (el == NULL) {
+ return false;
+ }
+
+ e.key = h_name;
+ e.data = (void *)el;
+
+ p = hsearch(e, ENTER);
+ if (p == NULL) {
+ NWRAP_LOG(NWRAP_LOG_ERROR, "Hash table is full!");
+ return false;
+ }
+
+ return true;
+}
+
+static bool nwrap_add_hname_add_to_existing(struct nwrap_entdata *const ed,
+ struct nwrap_entlist *const el)
+{
+ struct nwrap_entlist *cursor;
+ struct nwrap_entlist *el_new;
+
+ if (el == NULL) {
+ NWRAP_LOG(NWRAP_LOG_ERROR, "list is NULL, can not add");
+ return false;
+ }
+
+ el_new = nwrap_entlist_init(ed);
+ if (el_new == NULL) {
+ return false;
+ }
+
+ for (cursor = el; cursor->next != NULL; cursor = cursor->next)
+ {
+ if (cursor->ed == ed) {
+ free(el_new);
+ return false;
+ }
+ }
+
+ if (cursor->ed == ed) {
+ free(el_new);
+ return false;
+ }
+
+ cursor->next = el_new;
+ return true;
+}
+
+static bool nwrap_add_hname_alias(char *const h_name_a,
+ struct nwrap_entdata *const ed)
+{
+ ENTRY e;
+ ENTRY *p;
+ bool ok;
+
+ e.key = h_name_a;
+ e.data = NULL;
+ NWRAP_LOG(NWRAP_LOG_DEBUG, "Searching name: %s", e.key);
+ p = hsearch(e, FIND);
+ if (p == NULL) {
+ NWRAP_LOG(NWRAP_LOG_DEBUG, "Name %s not found. Adding...", h_name_a);
+ ok = nwrap_add_hname_add_new(h_name_a, ed);
+ } else {
+ struct nwrap_entlist *el = (struct nwrap_entlist *)p->data;
+
+ NWRAP_LOG(NWRAP_LOG_DEBUG, "Name %s found. Add record to list.", h_name_a);
+ ok = nwrap_add_hname_add_to_existing(ed, el);
+ }
+
+ return ok;
+}
+
+static bool nwrap_add_hname(struct nwrap_entdata *const ed)
+{
+ char *const h_name = (char *const)(ed->ht.h_name);
+ ENTRY e;
+ ENTRY *p;
+ unsigned i;
+ bool ok;
+
+ e.key = h_name;
+ e.data = NULL;
+ NWRAP_LOG(NWRAP_LOG_DEBUG, "Searching name: %s", e.key);
+ p = hsearch(e, FIND);
+ if (p == NULL) {
+ NWRAP_LOG(NWRAP_LOG_DEBUG, "Name %s not found. Adding...", h_name);
+ ok = nwrap_add_hname_add_new(h_name, ed);
+ } else {
+ struct nwrap_entlist *el = (struct nwrap_entlist *)p->data;
+
+ NWRAP_LOG(NWRAP_LOG_DEBUG, "Name %s found. Add record to list.", h_name);
+ ok = nwrap_add_hname_add_to_existing(ed, el);
+ }
+
+ if (!ok) {
+ return false;
+ }
+
+ if (ed->ht.h_aliases == NULL) {
+ return true;
+ }
+
+ /* Itemize aliases */
+ for (i = 0; ed->ht.h_aliases[i] != NULL; ++i) {
+ char *h_name_alias;
+
+ h_name_alias = ed->ht.h_aliases[i];
+
+ NWRAP_LOG(NWRAP_LOG_DEBUG, "Add alias: %s", h_name_alias);
+
+ if (!nwrap_add_hname_alias(h_name_alias, ed)) {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "Unable to add alias: %s", h_name_alias);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool nwrap_he_parse_line(struct nwrap_cache *nwrap, char *line)
+{
+ struct nwrap_he *nwrap_he = (struct nwrap_he *)nwrap->private_data;
+ bool do_aliases = true;
+ ssize_t aliases_count = 0;
+ char *p;
+ char *i;
+ char *n;
+
+ char *ip;
+ bool ok;
+
+ struct nwrap_entdata *ed = (struct nwrap_entdata *)
+ malloc(sizeof(struct nwrap_entdata));
+ if (ed == NULL) {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "Unable to allocate memory for nwrap_entdata");
+ return false;
+ }
+ ZERO_STRUCTP(ed);
+
+ 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);
+ free(ed);
+ return false;
+ }
+ }
+
+ for (i = p; !isspace((int)*p); p++) {
+ if (*p == '\0') {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "Invalid line[%s]: '%s'",
+ line, i);
+ free(ed);
+ 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);
+
+ free(ed);
+ return false;
+ }
+ ip = i;
+
+ nwrap_vector_add_item(&(ed->nwrap_addrdata),
+ (void *const)ed->addr.host_addr);
+ ed->ht.h_addr_list = nwrap_vector_head(&ed->nwrap_addrdata);
+
+ 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);
+
+ free(ed);
+ return false;
+ }
+ }
+
+ for (n = p; !isspace((int)*p); p++) {
+ if (*p == '\0') {
+ do_aliases = false;
+ break;
+ }
+ }
+
+ *p = '\0';
+
+ /* Convert to lowercase. This operate on same memory region */
+ str_tolower(n, n);
+ 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) {
+ free(ed);
+ 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) {
+ free(ed);
+ return false;
+ }
+ ed->ht.h_aliases = aliases;
+
+ str_tolower(a, a);
+ aliases[aliases_count] = a;
+ aliases[aliases_count + 1] = NULL;
+
+ aliases_count += 1;
+ }
+
+ nwrap_vector_add_item(&(nwrap_he->entdata), (void *const)ed);
+
+ ed->aliases_count = aliases_count;
+ /* Inventarize item */
+ ok = nwrap_add_hname(ed);
+ if (!ok) {
+ return false;
+ }
+
+ ok = nwrap_add_ai(ip, ed);
+ if (!ok) {
+ return false;
+ }
+
+ 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;
+ struct nwrap_entdata *ed;
+ size_t i;
+
+ nwrap_vector_foreach (ed, nwrap_he->entdata, i)
+ {
+ SAFE_FREE(ed->nwrap_addrdata.items);
+ SAFE_FREE(ed->ht.h_aliases);
+ SAFE_FREE(ed);
+ }
+ SAFE_FREE(nwrap_he->entdata.items);
+ nwrap_he->entdata.count = nwrap_he->entdata.capacity = 0;
+
+ 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;
+ bool ok;
+
+ (void) b; /* unused */
+
+ NWRAP_LOG(NWRAP_LOG_DEBUG, "Lookup user %s in files", name);
+
+ ok = nwrap_files_cache_reload(nwrap_pw_global.cache);
+ if (!ok) {
+ NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading passwd file");
+ return NULL;
+ }
+
+ for (i=0; i<nwrap_pw_global.num; i++) {
+ if (strcmp(nwrap_pw_global.list[i].pw_name, name) == 0) {
+ NWRAP_LOG(NWRAP_LOG_DEBUG, "user[%s] found", name);
+ return &nwrap_pw_global.list[i];
+ }
+ NWRAP_LOG(NWRAP_LOG_DEBUG,
+ "user[%s] does not match [%s]",
+ name,
+ nwrap_pw_global.list[i].pw_name);
+ }
+
+ NWRAP_LOG(NWRAP_LOG_DEBUG, "user[%s] not found\n", name);
+
+ errno = ENOENT;
+ return NULL;
+}
+
+static int nwrap_files_getpwnam_r(struct nwrap_backend *b,
+ const char *name, struct passwd *pwdst,
+ char *buf, size_t buflen, struct passwd **pwdstp)
+{
+ struct passwd *pw;
+
+ pw = nwrap_files_getpwnam(b, name);
+ if (!pw) {
+ if (errno == 0) {
+ return ENOENT;
+ }
+ return errno;
+ }
+
+ return nwrap_pw_copy_r(pw, pwdst, buf, buflen, pwdstp);
+}
+
+static struct passwd *nwrap_files_getpwuid(struct nwrap_backend *b,
+ uid_t uid)
+{
+ int i;
+ bool ok;
+
+ (void) b; /* unused */
+
+ ok = nwrap_files_cache_reload(nwrap_pw_global.cache);
+ if (!ok) {
+ NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading passwd file");
+ return NULL;
+ }
+
+ for (i=0; i<nwrap_pw_global.num; i++) {
+ if (nwrap_pw_global.list[i].pw_uid == uid) {
+ NWRAP_LOG(NWRAP_LOG_DEBUG, "uid[%u] found", uid);
+ return &nwrap_pw_global.list[i];
+ }
+ NWRAP_LOG(NWRAP_LOG_DEBUG,
+ "uid[%u] does not match [%u]",
+ uid,
+ nwrap_pw_global.list[i].pw_uid);
+ }
+
+ NWRAP_LOG(NWRAP_LOG_DEBUG, "uid[%u] not found\n", uid);
+
+ errno = ENOENT;
+ return NULL;
+}
+
+static int nwrap_files_getpwuid_r(struct nwrap_backend *b,
+ uid_t uid, struct passwd *pwdst,
+ char *buf, size_t buflen, struct passwd **pwdstp)
+{
+ struct passwd *pw;
+
+ pw = nwrap_files_getpwuid(b, uid);
+ if (!pw) {
+ if (errno == 0) {
+ return ENOENT;
+ }
+ return errno;
+ }
+
+ return nwrap_pw_copy_r(pw, pwdst, buf, buflen, pwdstp);
+}
+
+/* user enum functions */
+static void nwrap_files_setpwent(struct nwrap_backend *b)
+{
+ (void) b; /* unused */
+
+ nwrap_pw_global.idx = 0;
+}
+
+static struct passwd *nwrap_files_getpwent(struct nwrap_backend *b)
+{
+ struct passwd *pw;
+
+ (void) b; /* unused */
+
+ if (nwrap_pw_global.idx == 0) {
+ bool ok;
+ ok = nwrap_files_cache_reload(nwrap_pw_global.cache);
+ if (!ok) {
+ NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading passwd file");
+ return NULL;
+ }
+ }
+
+ if (nwrap_pw_global.idx >= nwrap_pw_global.num) {
+ errno = ENOENT;
+ return NULL;
+ }
+
+ pw = &nwrap_pw_global.list[nwrap_pw_global.idx++];
+
+ NWRAP_LOG(NWRAP_LOG_DEBUG,
+ "return user[%s] uid[%u]",
+ pw->pw_name, pw->pw_uid);
+
+ return pw;
+}
+
+static int nwrap_files_getpwent_r(struct nwrap_backend *b,
+ struct passwd *pwdst, char *buf,
+ size_t buflen, struct passwd **pwdstp)
+{
+ struct passwd *pw;
+
+ pw = nwrap_files_getpwent(b);
+ if (!pw) {
+ if (errno == 0) {
+ return ENOENT;
+ }
+ return errno;
+ }
+
+ return nwrap_pw_copy_r(pw, pwdst, buf, buflen, pwdstp);
+}
+
+static void nwrap_files_endpwent(struct nwrap_backend *b)
+{
+ (void) b; /* unused */
+
+ nwrap_pw_global.idx = 0;
+}
+
+/* shadow */
+
+#if defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM)
+
+#ifdef HAVE_SETSPENT
+static void nwrap_files_setspent(void)
+{
+ nwrap_sp_global.idx = 0;
+}
+
+static struct spwd *nwrap_files_getspent(void)
+{
+ struct spwd *sp;
+
+ if (nwrap_sp_global.idx == 0) {
+ bool ok;
+
+ ok = nwrap_files_cache_reload(nwrap_sp_global.cache);
+ if (!ok) {
+ NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading shadow file");
+ return NULL;
+ }
+ }
+
+ if (nwrap_sp_global.idx >= nwrap_sp_global.num) {
+ errno = ENOENT;
+ return NULL;
+ }
+
+ sp = &nwrap_sp_global.list[nwrap_sp_global.idx++];
+
+ NWRAP_LOG(NWRAP_LOG_DEBUG,
+ "return user[%s]",
+ sp->sp_namp);
+
+ return sp;
+}
+
+static void nwrap_files_endspent(void)
+{
+ nwrap_sp_global.idx = 0;
+}
+#endif /* HAVE_SETSPENT */
+
+static struct spwd *nwrap_files_getspnam(const char *name)
+{
+ int i;
+ bool ok;
+
+ NWRAP_LOG(NWRAP_LOG_DEBUG, "Lookup user %s in files", name);
+
+ ok = nwrap_files_cache_reload(nwrap_sp_global.cache);
+ if (!ok) {
+ NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading shadow file");
+ return NULL;
+ }
+
+ for (i=0; i<nwrap_sp_global.num; i++) {
+ if (strcmp(nwrap_sp_global.list[i].sp_namp, name) == 0) {
+ NWRAP_LOG(NWRAP_LOG_DEBUG, "user[%s] found", name);
+ return &nwrap_sp_global.list[i];
+ }
+ NWRAP_LOG(NWRAP_LOG_DEBUG,
+ "user[%s] does not match [%s]",
+ name,
+ nwrap_sp_global.list[i].sp_namp);
+ }
+
+ NWRAP_LOG(NWRAP_LOG_DEBUG, "user[%s] not found\n", name);
+
+ errno = ENOENT;
+ return NULL;
+}
+#endif /* defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM) */
+
+/* misc functions */
+static int nwrap_files_initgroups(struct nwrap_backend *b,
+ const char *user,
+ gid_t group)
+{
+ struct group *grp;
+ gid_t *groups;
+ int size = 1;
+ int rc;
+
+ groups = (gid_t *)malloc(size * sizeof(gid_t));
+ if (groups == NULL) {
+ NWRAP_LOG(NWRAP_LOG_ERROR, "Out of memory");
+ errno = ENOMEM;
+ return -1;
+ }
+ groups[0] = group;
+
+ nwrap_files_setgrent(b);
+ while ((grp = nwrap_files_getgrent(b)) != NULL) {
+ int i = 0;
+
+ 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 (group != grp->gr_gid &&
+ (strcmp(user, grp->gr_mem[i]) == 0)) {
+ NWRAP_LOG(NWRAP_LOG_DEBUG,
+ "%s is member of %s",
+ user,
+ grp->gr_name);
+
+ groups = (gid_t *)realloc(groups,
+ (size + 1) * sizeof(gid_t));
+ if (groups == NULL) {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "Out of memory");
+ errno = ENOMEM;
+ return -1;
+ }
+
+ groups[size] = grp->gr_gid;
+ size++;
+ }
+ }
+ }
+
+ nwrap_files_endgrent(b);
+
+ NWRAP_LOG(NWRAP_LOG_DEBUG,
+ "%s is member of %d groups",
+ user, size);
+
+ /* This really only works if uid_wrapper is loaded */
+ rc = setgroups(size, groups);
+
+ free(groups);
+
+ return rc;
+}
+
+/* group functions */
+static struct group *nwrap_files_getgrnam(struct nwrap_backend *b,
+ const char *name)
+{
+ int i;
+ bool ok;
+
+ (void) b; /* unused */
+
+ ok = nwrap_files_cache_reload(nwrap_gr_global.cache);
+ if (!ok) {
+ NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading group file");
+ return NULL;
+ }
+
+ for (i=0; i<nwrap_gr_global.num; i++) {
+ if (strcmp(nwrap_gr_global.list[i].gr_name, name) == 0) {
+ NWRAP_LOG(NWRAP_LOG_DEBUG, "group[%s] found", name);
+ return &nwrap_gr_global.list[i];
+ }
+ NWRAP_LOG(NWRAP_LOG_DEBUG,
+ "group[%s] does not match [%s]",
+ name,
+ nwrap_gr_global.list[i].gr_name);
+ }
+
+ NWRAP_LOG(NWRAP_LOG_DEBUG, "group[%s] not found", name);
+
+ errno = ENOENT;
+ return NULL;
+}
+
+static int nwrap_files_getgrnam_r(struct nwrap_backend *b,
+ const char *name, struct group *grdst,
+ char *buf, size_t buflen, struct group **grdstp)
+{
+ struct group *gr;
+
+ gr = nwrap_files_getgrnam(b, name);
+ if (!gr) {
+ if (errno == 0) {
+ return ENOENT;
+ }
+ return errno;
+ }
+
+ return nwrap_gr_copy_r(gr, grdst, buf, buflen, grdstp);
+}
+
+static struct group *nwrap_files_getgrgid(struct nwrap_backend *b,
+ gid_t gid)
+{
+ int i;
+ bool ok;
+
+ (void) b; /* unused */
+
+ ok = nwrap_files_cache_reload(nwrap_gr_global.cache);
+ if (!ok) {
+ NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading group file");
+ return NULL;
+ }
+
+ for (i=0; i<nwrap_gr_global.num; i++) {
+ if (nwrap_gr_global.list[i].gr_gid == gid) {
+ NWRAP_LOG(NWRAP_LOG_DEBUG, "gid[%u] found", gid);
+ return &nwrap_gr_global.list[i];
+ }
+ NWRAP_LOG(NWRAP_LOG_DEBUG,
+ "gid[%u] does not match [%u]",
+ gid,
+ nwrap_gr_global.list[i].gr_gid);
+ }
+
+ NWRAP_LOG(NWRAP_LOG_DEBUG, "gid[%u] not found", gid);
+
+ errno = ENOENT;
+ return NULL;
+}
+
+static int nwrap_files_getgrgid_r(struct nwrap_backend *b,
+ gid_t gid, struct group *grdst,
+ char *buf, size_t buflen, struct group **grdstp)
+{
+ struct group *gr;
+
+ gr = nwrap_files_getgrgid(b, gid);
+ if (!gr) {
+ if (errno == 0) {
+ return ENOENT;
+ }
+ return errno;
+ }
+
+ return nwrap_gr_copy_r(gr, grdst, buf, buflen, grdstp);
+}
+
+/* group enum functions */
+static void nwrap_files_setgrent(struct nwrap_backend *b)
+{
+ (void) b; /* unused */
+
+ nwrap_gr_global.idx = 0;
+}
+
+static struct group *nwrap_files_getgrent(struct nwrap_backend *b)
+{
+ struct group *gr;
+
+ (void) b; /* unused */
+
+ if (nwrap_gr_global.idx == 0) {
+ bool ok;
+
+ ok = nwrap_files_cache_reload(nwrap_gr_global.cache);
+ if (!ok) {
+ NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading group file");
+ return NULL;
+ }
+ }
+
+ if (nwrap_gr_global.idx >= nwrap_gr_global.num) {
+ errno = ENOENT;
+ return NULL;
+ }
+
+ gr = &nwrap_gr_global.list[nwrap_gr_global.idx++];
+
+ NWRAP_LOG(NWRAP_LOG_DEBUG,
+ "return group[%s] gid[%u]",
+ gr->gr_name, gr->gr_gid);
+
+ return gr;
+}
+
+static int nwrap_files_getgrent_r(struct nwrap_backend *b,
+ struct group *grdst, char *buf,
+ size_t buflen, struct group **grdstp)
+{
+ struct group *gr;
+
+ gr = nwrap_files_getgrent(b);
+ if (!gr) {
+ if (errno == 0) {
+ return ENOENT;
+ }
+ return errno;
+ }
+
+ return nwrap_gr_copy_r(gr, grdst, buf, buflen, grdstp);
+}
+
+static void nwrap_files_endgrent(struct nwrap_backend *b)
+{
+ (void) b; /* unused */
+
+ nwrap_gr_global.idx = 0;
+}
+
+/* hosts functions */
+static int nwrap_files_gethostbyname(const char *name, int af,
+ struct hostent *result,
+ struct nwrap_vector *addr_list)
+{
+ struct nwrap_entlist *el;
+ struct hostent *he;
+ char *h_name_lower;
+ ENTRY e;
+ ENTRY *e_p;
+ char canon_name[DNS_NAME_MAX] = { 0 };
+ size_t name_len;
+ bool he_found = false;
+ bool ok;
+
+ ok = nwrap_files_cache_reload(nwrap_he_global.cache);
+ if (!ok) {
+ NWRAP_LOG(NWRAP_LOG_ERROR, "error loading hosts file");
+ goto no_ent;
+ }
+
+ name_len = strlen(name);
+ if (name_len < sizeof(canon_name) && name[name_len - 1] == '.') {
+ strncpy(canon_name, name, name_len - 1);
+ name = canon_name;
+ }
+
+ if (!str_tolower_copy(&h_name_lower, name)) {
+ NWRAP_LOG(NWRAP_LOG_DEBUG,
+ "Out of memory while converting to lower case");
+ goto no_ent;
+ }
+
+ /* Look at hash table for element */
+ NWRAP_LOG(NWRAP_LOG_DEBUG, "Searching for name: %s", h_name_lower);
+ e.key = h_name_lower;
+ e.data = NULL;
+ e_p = hsearch(e, FIND);
+ if (e_p == NULL) {
+ NWRAP_LOG(NWRAP_LOG_DEBUG, "Name %s not found.", h_name_lower);
+ SAFE_FREE(h_name_lower);
+ goto no_ent;
+ }
+ SAFE_FREE(h_name_lower);
+
+ /* Always cleanup vector and results */
+ if (!nwrap_vector_is_initialized(addr_list)) {
+ if (!nwrap_vector_init(addr_list)) {
+ NWRAP_LOG(NWRAP_LOG_DEBUG,
+ "Unable to initialize memory for addr_list vector");
+ goto no_ent;
+ }
+ } else {
+ /* When vector is initialized data are valid no more.
+ * Quick way how to free vector is: */
+ addr_list->count = 0;
+ }
+
+ /* Iterate through results */
+ for (el = (struct nwrap_entlist *)e_p->data; el != NULL; el = el->next)
+ {
+ he = &(el->ed->ht);
+
+ /* Filter by address familiy if provided */
+ if (af != AF_UNSPEC && he->h_addrtype != af) {
+ continue;
+ }
+
+ /*
+ * GLIBC HACK?
+ * glibc doesn't return ipv6 addresses when AF_UNSPEC is used
+ */
+ if (af == AF_UNSPEC && he->h_addrtype != AF_INET) {
+ continue;
+ }
+
+ if (!he_found) {
+ memcpy(result, he, sizeof(struct hostent));
+ NWRAP_LOG(NWRAP_LOG_DEBUG,
+ "Name found. Returning record for %s",
+ he->h_name);
+ he_found = true;
+ }
+ nwrap_vector_merge(addr_list, &el->ed->nwrap_addrdata);
+ result->h_addr_list = nwrap_vector_head(addr_list);
+ }
+
+ if (he_found) {
+ return 0;
+ }
+ NWRAP_LOG(NWRAP_LOG_DEBUG,
+ "Name found in database. No records matches type.");
+
+no_ent:
+ errno = ENOENT;
+ return -1;
+}
+
+#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)
+{
+ struct nwrap_vector *addr_list = malloc(sizeof(struct nwrap_vector));
+ int rc;
+
+ if (addr_list == NULL) {
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "Unable to allocate memory for address list");
+ errno = ENOENT;
+ return -1;
+ }
+
+ ZERO_STRUCTP(addr_list);
+
+ rc = nwrap_files_gethostbyname(name, AF_UNSPEC, ret, addr_list);
+ if (rc == -1) {
+ *h_errnop = h_errno;
+ if (addr_list->items != NULL) {
+ free(addr_list->items);
+ }
+ SAFE_FREE(addr_list);
+ errno = ENOENT;
+ return -1;
+ }
+
+ if (buflen < (addr_list->count * sizeof(void *))) {
+ SAFE_FREE(addr_list->items);
+ SAFE_FREE(addr_list);
+ return ERANGE;
+ }
+
+ /* Copy all to user provided buffer and change
+ * pointers in returned structure.
+ * +1 is for ending NULL pointer. */
+ memcpy(buf, addr_list->items, (addr_list->count + 1) * sizeof(void *));
+
+ free(addr_list->items);
+ free(addr_list);
+
+ ret->h_addr_list = (char **)buf;
+ *result = ret;
+ return 0;
+}
+
+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 int nwrap_files_getaddrinfo(const char *name,
+ unsigned short port,
+ const struct addrinfo *hints,
+ struct addrinfo **ai,
+ struct addrinfo **ai_tail)
+{
+ struct nwrap_entlist *el;
+ struct hostent *he;
+ struct addrinfo *_ai = NULL;
+ struct addrinfo *ai_head = NULL;
+ struct addrinfo *ai_prev = NULL;
+ char *h_name_lower;
+ size_t name_len;
+ char canon_name[DNS_NAME_MAX] = { 0 };
+ bool skip_canonname = false;
+ ENTRY e = { 0 };
+ ENTRY *e_p = NULL;
+ int rc;
+ bool ok;
+
+ ok = nwrap_files_cache_reload(nwrap_he_global.cache);
+ if (!ok) {
+ NWRAP_LOG(NWRAP_LOG_ERROR, "error loading hosts file");
+ return EAI_SYSTEM;
+ }
+
+ name_len = strlen(name);
+ if (name_len < DNS_NAME_MAX && name[name_len - 1] == '.') {
+ strncpy(canon_name, name, name_len - 1);
+ name = canon_name;
+ }
+
+ if (!str_tolower_copy(&h_name_lower, name)) {
+ NWRAP_LOG(NWRAP_LOG_DEBUG,
+ "Out of memory while converting to lower case");
+ return EAI_MEMORY;
+ }
+
+ NWRAP_LOG(NWRAP_LOG_DEBUG, "Searching for name: %s", h_name_lower);
+ e.key = h_name_lower;
+ e.data = NULL;
+ e_p = hsearch(e, FIND);
+ if (e_p == NULL) {
+ NWRAP_LOG(NWRAP_LOG_DEBUG, "Name %s not found.", h_name_lower);
+ SAFE_FREE(h_name_lower);
+ errno = ENOENT;
+ return EAI_NONAME;
+ }
+ NWRAP_LOG(NWRAP_LOG_DEBUG, "Name: %s found.", h_name_lower);
+ SAFE_FREE(h_name_lower);
+
+ rc = EAI_NONAME;
+ for (el = (struct nwrap_entlist *)e_p->data; el != NULL; el = el->next)
+ {
+ int rc2;
+
+ he = &(el->ed->ht);
+
+ if (hints->ai_family != AF_UNSPEC &&
+ he->h_addrtype != hints->ai_family)
+ {
+ NWRAP_LOG(NWRAP_LOG_DEBUG,
+ "Entry found but with wrong AF - "
+ "remembering EAI_ADDRINFO.");
+ rc = EAI_ADDRFAMILY;
+ continue;
+ }
+
+ /* Function allocates memory and returns it in ai. */
+ rc2 = nwrap_convert_he_ai(he,
+ port,
+ hints,
+ &_ai,
+ skip_canonname);
+ if (rc2 != 0) {
+ NWRAP_LOG(NWRAP_LOG_ERROR, "Error converting he to ai");
+ return rc2;
+ }
+ skip_canonname = true;
+
+ if (ai_head == NULL) {
+ ai_head = _ai;
+ }
+ if (ai_prev != NULL) {
+ ai_prev->ai_next = _ai;
+ }
+ ai_prev = _ai;
+ }
+
+ if (ai_head != NULL) {
+ rc = 0;
+ }
+
+ *ai = ai_head;
+ *ai_tail = _ai;
+
+ return rc;
+}
+
+static struct hostent *nwrap_files_gethostbyaddr(const void *addr,
+ socklen_t len, int type)
+{
+ struct hostent *he;
+ char ip[NWRAP_INET_ADDRSTRLEN] = {0};
+ struct nwrap_entdata *ed;
+ const char *a;
+ size_t i;
+ bool ok;
+
+ (void) len; /* unused */
+
+ ok = nwrap_files_cache_reload(nwrap_he_global.cache);
+ if (!ok) {
+ NWRAP_LOG(NWRAP_LOG_ERROR, "error loading hosts file");
+ return NULL;
+ }
+
+ a = inet_ntop(type, addr, ip, sizeof(ip));
+ if (a == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ nwrap_vector_foreach(ed, nwrap_he_global.entdata, i)
+ {
+ he = &(ed->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) {
+ bool ok;
+
+ ok = nwrap_files_cache_reload(nwrap_he_global.cache);
+ if (!ok) {
+ NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading hosts file");
+ return NULL;
+ }
+ }
+
+ if (nwrap_he_global.idx >= nwrap_he_global.num) {
+ errno = ENOENT;
+ return NULL;
+ }
+
+ he = &((struct nwrap_entdata *)nwrap_he_global.entdata.items[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
+ */
+
+
+static struct passwd *nwrap_module_getpwnam(struct nwrap_backend *b,
+ const char *name)
+{
+ static struct passwd pwd;
+ static char buf[1000];
+ NSS_STATUS status;
+
+ if (!b->fns->_nss_getpwnam_r) {
+ return NULL;
+ }
+
+ status = b->fns->_nss_getpwnam_r(name, &pwd, buf, sizeof(buf), &errno);
+ if (status == NSS_STATUS_NOTFOUND) {
+ return NULL;
+ }
+ if (status != NSS_STATUS_SUCCESS) {
+ return NULL;
+ }
+
+ return &pwd;
+}
+
+static int nwrap_module_getpwnam_r(struct nwrap_backend *b,
+ const char *name, struct passwd *pwdst,
+ char *buf, size_t buflen, struct passwd **pwdstp)
+{
+ int ret;
+
+ (void) b; /* unused */
+ (void) pwdst; /* unused */
+ (void) pwdstp; /* unused */
+
+ if (!b->fns->_nss_getpwnam_r) {
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ ret = b->fns->_nss_getpwnam_r(name, pwdst, buf, buflen, &errno);
+ switch (ret) {
+ case NSS_STATUS_SUCCESS:
+ return 0;
+ case NSS_STATUS_NOTFOUND:
+ if (errno != 0) {
+ return errno;
+ }
+ return ENOENT;
+ case NSS_STATUS_TRYAGAIN:
+ if (errno != 0) {
+ return errno;
+ }
+ return ERANGE;
+ default:
+ if (errno != 0) {
+ return errno;
+ }
+ return ret;
+ }
+}
+
+static struct passwd *nwrap_module_getpwuid(struct nwrap_backend *b,
+ uid_t uid)
+{
+ static struct passwd pwd;
+ static char buf[1000];
+ NSS_STATUS status;
+
+ if (!b->fns->_nss_getpwuid_r) {
+ return NULL;
+ }
+
+ status = b->fns->_nss_getpwuid_r(uid, &pwd, buf, sizeof(buf), &errno);
+ if (status == NSS_STATUS_NOTFOUND) {
+ return NULL;
+ }
+ if (status != NSS_STATUS_SUCCESS) {
+ return NULL;
+ }
+ return &pwd;
+}
+
+static int nwrap_module_getpwuid_r(struct nwrap_backend *b,
+ uid_t uid, struct passwd *pwdst,
+ char *buf, size_t buflen, struct passwd **pwdstp)
+{
+ int ret;
+
+ (void) pwdstp; /* unused */
+
+ if (!b->fns->_nss_getpwuid_r) {
+ return ENOENT;
+ }
+
+ ret = b->fns->_nss_getpwuid_r(uid, pwdst, buf, buflen, &errno);
+ switch (ret) {
+ case NSS_STATUS_SUCCESS:
+ return 0;
+ case NSS_STATUS_NOTFOUND:
+ if (errno != 0) {
+ return errno;
+ }
+ return ENOENT;
+ case NSS_STATUS_TRYAGAIN:
+ if (errno != 0) {
+ return errno;
+ }
+ return ERANGE;
+ default:
+ if (errno != 0) {
+ return errno;
+ }
+ return ret;
+ }
+}
+
+static void nwrap_module_setpwent(struct nwrap_backend *b)
+{
+ if (!b->fns->_nss_setpwent) {
+ return;
+ }
+
+ b->fns->_nss_setpwent();
+}
+
+static struct passwd *nwrap_module_getpwent(struct nwrap_backend *b)
+{
+ static struct passwd pwd;
+ static char buf[1000];
+ NSS_STATUS status;
+
+ if (!b->fns->_nss_getpwent_r) {
+ return NULL;
+ }
+
+ status = b->fns->_nss_getpwent_r(&pwd, buf, sizeof(buf), &errno);
+ if (status == NSS_STATUS_NOTFOUND) {
+ return NULL;
+ }
+ if (status != NSS_STATUS_SUCCESS) {
+ return NULL;
+ }
+ return &pwd;
+}
+
+static int nwrap_module_getpwent_r(struct nwrap_backend *b,
+ struct passwd *pwdst, char *buf,
+ size_t buflen, struct passwd **pwdstp)
+{
+ int ret;
+
+ (void) pwdstp; /* unused */
+
+ if (!b->fns->_nss_getpwent_r) {
+ return ENOENT;
+ }
+
+ ret = b->fns->_nss_getpwent_r(pwdst, buf, buflen, &errno);
+ switch (ret) {
+ case NSS_STATUS_SUCCESS:
+ return 0;
+ case NSS_STATUS_NOTFOUND:
+ if (errno != 0) {
+ return errno;
+ }
+ return ENOENT;
+ case NSS_STATUS_TRYAGAIN:
+ if (errno != 0) {
+ return errno;
+ }
+ return ERANGE;
+ default:
+ if (errno != 0) {
+ return errno;
+ }
+ return ret;
+ }
+}
+
+static void nwrap_module_endpwent(struct nwrap_backend *b)
+{
+ if (!b->fns->_nss_endpwent) {
+ return;
+ }
+
+ b->fns->_nss_endpwent();
+}
+
+static int nwrap_module_initgroups(struct nwrap_backend *b,
+ const char *user, gid_t group)
+{
+ gid_t *groups;
+ long int start;
+ long int size;
+
+ if (!b->fns->_nss_initgroups) {
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ return b->fns->_nss_initgroups(user, group, &start, &size, &groups, 0, &errno);
+}
+
+static struct group *nwrap_module_getgrnam(struct nwrap_backend *b,
+ const char *name)
+{
+ static struct group grp;
+ static char *buf;
+ static int buflen = 1000;
+ NSS_STATUS status;
+
+ if (!b->fns->_nss_getgrnam_r) {
+ return NULL;
+ }
+
+ if (!buf) {
+ buf = (char *)malloc(buflen);
+ }
+again:
+ status = b->fns->_nss_getgrnam_r(name, &grp, buf, buflen, &errno);
+ if (status == NSS_STATUS_TRYAGAIN) {
+ buflen *= 2;
+ buf = (char *)realloc(buf, buflen);
+ if (!buf) {
+ return NULL;
+ }
+ goto again;
+ }
+ if (status == NSS_STATUS_NOTFOUND) {
+ SAFE_FREE(buf);
+ return NULL;
+ }
+ if (status != NSS_STATUS_SUCCESS) {
+ SAFE_FREE(buf);
+ return NULL;
+ }
+ return &grp;
+}
+
+static int nwrap_module_getgrnam_r(struct nwrap_backend *b,
+ const char *name, struct group *grdst,
+ char *buf, size_t buflen, struct group **grdstp)
+{
+ int ret;
+
+ (void) grdstp; /* unused */
+
+ if (!b->fns->_nss_getgrnam_r) {
+ return ENOENT;
+ }
+
+ ret = b->fns->_nss_getgrnam_r(name, grdst, buf, buflen, &errno);
+ switch (ret) {
+ case NSS_STATUS_SUCCESS:
+ return 0;
+ case NSS_STATUS_NOTFOUND:
+ if (errno != 0) {
+ return errno;
+ }
+ return ENOENT;
+ case NSS_STATUS_TRYAGAIN:
+ if (errno != 0) {
+ return errno;
+ }
+ return ERANGE;
+ default:
+ if (errno != 0) {
+ return errno;
+ }
+ return ret;
+ }
+}
+
+static struct group *nwrap_module_getgrgid(struct nwrap_backend *b,
+ gid_t gid)
+{
+ static struct group grp;
+ static char *buf;
+ static int buflen = 1000;
+ NSS_STATUS status;
+
+ if (!b->fns->_nss_getgrgid_r) {
+ return NULL;
+ }
+
+ if (!buf) {
+ buf = (char *)malloc(buflen);
+ }
+
+again:
+ status = b->fns->_nss_getgrgid_r(gid, &grp, buf, buflen, &errno);
+ if (status == NSS_STATUS_TRYAGAIN) {
+ buflen *= 2;
+ buf = (char *)realloc(buf, buflen);
+ if (!buf) {
+ return NULL;
+ }
+ goto again;
+ }
+ if (status == NSS_STATUS_NOTFOUND) {
+ SAFE_FREE(buf);
+ return NULL;
+ }
+ if (status != NSS_STATUS_SUCCESS) {
+ SAFE_FREE(buf);
+ return NULL;
+ }
+ return &grp;
+}
+
+static int nwrap_module_getgrgid_r(struct nwrap_backend *b,
+ gid_t gid, struct group *grdst,
+ char *buf, size_t buflen, struct group **grdstp)
+{
+ int ret;
+
+ (void) grdstp; /* unused */
+
+ if (!b->fns->_nss_getgrgid_r) {
+ return ENOENT;
+ }
+
+ ret = b->fns->_nss_getgrgid_r(gid, grdst, buf, buflen, &errno);
+ switch (ret) {
+ case NSS_STATUS_SUCCESS:
+ return 0;
+ case NSS_STATUS_NOTFOUND:
+ if (errno != 0) {
+ return errno;
+ }
+ return ENOENT;
+ case NSS_STATUS_TRYAGAIN:
+ if (errno != 0) {
+ return errno;
+ }
+ return ERANGE;
+ default:
+ if (errno != 0) {
+ return errno;
+ }
+ return ret;
+ }
+}
+
+static void nwrap_module_setgrent(struct nwrap_backend *b)
+{
+ if (!b->fns->_nss_setgrent) {
+ return;
+ }
+
+ b->fns->_nss_setgrent();
+}
+
+static struct group *nwrap_module_getgrent(struct nwrap_backend *b)
+{
+ static struct group grp;
+ static char *buf;
+ static int buflen = 1024;
+ NSS_STATUS status;
+
+ if (!b->fns->_nss_getgrent_r) {
+ return NULL;
+ }
+
+ if (!buf) {
+ buf = (char *)malloc(buflen);
+ }
+
+again:
+ status = b->fns->_nss_getgrent_r(&grp, buf, buflen, &errno);
+ if (status == NSS_STATUS_TRYAGAIN) {
+ buflen *= 2;
+ buf = (char *)realloc(buf, buflen);
+ if (!buf) {
+ return NULL;
+ }
+ goto again;
+ }
+ if (status == NSS_STATUS_NOTFOUND) {
+ SAFE_FREE(buf);
+ return NULL;
+ }
+ if (status != NSS_STATUS_SUCCESS) {
+ SAFE_FREE(buf);
+ return NULL;
+ }
+ return &grp;
+}
+
+static int nwrap_module_getgrent_r(struct nwrap_backend *b,
+ struct group *grdst, char *buf,
+ size_t buflen, struct group **grdstp)
+{
+ int ret;
+
+ (void) grdstp; /* unused */
+
+ if (!b->fns->_nss_getgrent_r) {
+ return ENOENT;
+ }
+
+ ret = b->fns->_nss_getgrent_r(grdst, buf, buflen, &errno);
+ switch (ret) {
+ case NSS_STATUS_SUCCESS:
+ return 0;
+ case NSS_STATUS_NOTFOUND:
+ if (errno != 0) {
+ return errno;
+ }
+ return ENOENT;
+ case NSS_STATUS_TRYAGAIN:
+ if (errno != 0) {
+ return errno;
}
- NWRAP_VERBOSE(("%s: user[%s] does not match [%s]\n",
- __location__, name,
- nwrap_pw_global.list[i].pw_name));
+ return ERANGE;
+ default:
+ if (errno != 0) {
+ return errno;
+ }
+ return ret;
}
-
- NWRAP_DEBUG(("%s: user[%s] not found\n", __location__, name));
-
- errno = ENOENT;
- return NULL;
}
-static int nwrap_files_getpwnam_r(struct nwrap_backend *b,
- const char *name, struct passwd *pwdst,
- char *buf, size_t buflen, struct passwd **pwdstp)
+static void nwrap_module_endgrent(struct nwrap_backend *b)
{
- struct passwd *pw;
-
- pw = nwrap_files_getpwnam(b, name);
- if (!pw) {
- if (errno == 0) {
- return ENOENT;
- }
- return errno;
+ if (!b->fns->_nss_endgrent) {
+ return;
}
- return nwrap_pw_copy_r(pw, pwdst, buf, buflen, pwdstp);
+ b->fns->_nss_endgrent();
}
-static struct passwd *nwrap_files_getpwuid(struct nwrap_backend *b,
- uid_t uid)
+/****************************************************************************
+ * GETPWNAM
+ ***************************************************************************/
+
+static struct passwd *nwrap_getpwnam(const char *name)
{
int i;
+ struct passwd *pwd;
- 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));
- return &nwrap_pw_global.list[i];
+ 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);
+ if (pwd) {
+ return pwd;
}
- NWRAP_VERBOSE(("%s: uid[%u] does not match [%u]\n",
- __location__, uid,
- nwrap_pw_global.list[i].pw_uid));
}
- NWRAP_DEBUG(("%s: uid[%u] not found\n", __location__, uid));
-
- errno = ENOENT;
return NULL;
}
-static int nwrap_files_getpwuid_r(struct nwrap_backend *b,
- uid_t uid, struct passwd *pwdst,
- char *buf, size_t buflen, struct passwd **pwdstp)
+struct passwd *getpwnam(const char *name)
{
- struct passwd *pw;
-
- pw = nwrap_files_getpwuid(b, uid);
- if (!pw) {
- if (errno == 0) {
- return ENOENT;
- }
- return errno;
+ if (!nss_wrapper_enabled()) {
+ return libc_getpwnam(name);
}
- return nwrap_pw_copy_r(pw, pwdst, buf, buflen, pwdstp);
+ return nwrap_getpwnam(name);
}
-/* user enum functions */
-static void nwrap_files_setpwent(struct nwrap_backend *b)
-{
- nwrap_pw_global.idx = 0;
-}
+/****************************************************************************
+ * GETPWNAM_R
+ ***************************************************************************/
-static struct passwd *nwrap_files_getpwent(struct nwrap_backend *b)
+static int nwrap_getpwnam_r(const char *name, struct passwd *pwdst,
+ char *buf, size_t buflen, struct passwd **pwdstp)
{
- struct passwd *pw;
-
- if (nwrap_pw_global.idx == 0) {
- nwrap_files_cache_reload(nwrap_pw_global.cache);
- }
+ int i,ret;
- if (nwrap_pw_global.idx >= nwrap_pw_global.num) {
- errno = ENOENT;
- return NULL;
+ 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);
+ if (ret == ENOENT) {
+ continue;
+ }
+ return ret;
}
- 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));
-
- return pw;
+ return ENOENT;
}
-static int nwrap_files_getpwent_r(struct nwrap_backend *b,
- struct passwd *pwdst, char *buf,
- size_t buflen, struct passwd **pwdstp)
+#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 */
{
- struct passwd *pw;
-
- pw = nwrap_files_getpwent(b);
- if (!pw) {
- if (errno == 0) {
- return ENOENT;
- }
- return errno;
+ if (!nss_wrapper_enabled()) {
+ return libc_getpwnam_r(name, pwdst, buf, buflen, pwdstp);
}
- return nwrap_pw_copy_r(pw, pwdst, buf, buflen, pwdstp);
-}
-
-static void nwrap_files_endpwent(struct nwrap_backend *b)
-{
- nwrap_pw_global.idx = 0;
+ return nwrap_getpwnam_r(name, pwdst, buf, buflen, pwdstp);
}
+#endif
-/* misc functions */
-static int nwrap_files_initgroups(struct nwrap_backend *b,
- const char *user, gid_t group)
-{
- /* TODO: maybe we should also fake this... */
- return EPERM;
-}
+/****************************************************************************
+ * GETPWUID
+ ***************************************************************************/
-/* group functions */
-static struct group *nwrap_files_getgrnam(struct nwrap_backend *b,
- const char *name)
+static struct passwd *nwrap_getpwuid(uid_t uid)
{
int i;
+ struct passwd *pwd;
- 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));
- return &nwrap_gr_global.list[i];
+ 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);
+ if (pwd) {
+ return pwd;
}
- NWRAP_VERBOSE(("%s: group[%s] does not match [%s]\n",
- __location__, name,
- nwrap_gr_global.list[i].gr_name));
}
- NWRAP_DEBUG(("%s: group[%s] not found\n", __location__, name));
-
- errno = ENOENT;
return NULL;
}
-static int nwrap_files_getgrnam_r(struct nwrap_backend *b,
- const char *name, struct group *grdst,
- char *buf, size_t buflen, struct group **grdstp)
+struct passwd *getpwuid(uid_t uid)
{
- struct group *gr;
-
- gr = nwrap_files_getgrnam(b, name);
- if (!gr) {
- if (errno == 0) {
- return ENOENT;
- }
- return errno;
+ if (!nss_wrapper_enabled()) {
+ return libc_getpwuid(uid);
}
- return nwrap_gr_copy_r(gr, grdst, buf, buflen, grdstp);
+ return nwrap_getpwuid(uid);
}
-static struct group *nwrap_files_getgrgid(struct nwrap_backend *b,
- gid_t gid)
-{
- int i;
+/****************************************************************************
+ * GETPWUID_R
+ ***************************************************************************/
- nwrap_files_cache_reload(nwrap_gr_global.cache);
+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_gr_global.num; i++) {
- if (nwrap_gr_global.list[i].gr_gid == gid) {
- NWRAP_DEBUG(("%s: gid[%u] found\n",
- __location__, gid));
- return &nwrap_gr_global.list[i];
+ 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);
+ if (ret == ENOENT) {
+ continue;
}
- NWRAP_VERBOSE(("%s: gid[%u] does not match [%u]\n",
- __location__, gid,
- nwrap_gr_global.list[i].gr_gid));
+ return ret;
}
- NWRAP_DEBUG(("%s: gid[%u] not found\n", __location__, gid));
-
- errno = ENOENT;
- return NULL;
+ return ENOENT;
}
-static int nwrap_files_getgrgid_r(struct nwrap_backend *b,
- gid_t gid, struct group *grdst,
- char *buf, size_t buflen, struct group **grdstp)
+#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
{
- struct group *gr;
-
- gr = nwrap_files_getgrgid(b, gid);
- if (!gr) {
- if (errno == 0) {
- return ENOENT;
- }
- return errno;
+ if (!nss_wrapper_enabled()) {
+ return libc_getpwuid_r(uid, pwdst, buf, buflen, pwdstp);
}
- return nwrap_gr_copy_r(gr, grdst, buf, buflen, grdstp);
+ return nwrap_getpwuid_r(uid, pwdst, buf, buflen, pwdstp);
}
-/* group enum functions */
-static void nwrap_files_setgrent(struct nwrap_backend *b)
-{
- nwrap_gr_global.idx = 0;
-}
+/****************************************************************************
+ * SETPWENT
+ ***************************************************************************/
-static struct group *nwrap_files_getgrent(struct nwrap_backend *b)
+static void nwrap_setpwent(void)
{
- struct group *gr;
-
- if (nwrap_gr_global.idx == 0) {
- nwrap_files_cache_reload(nwrap_gr_global.cache);
- }
+ int i;
- if (nwrap_gr_global.idx >= nwrap_gr_global.num) {
- errno = ENOENT;
- return NULL;
+ for (i=0; i < nwrap_main_global->num_backends; i++) {
+ struct nwrap_backend *b = &nwrap_main_global->backends[i];
+ b->ops->nw_setpwent(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));
-
- return gr;
}
-static int nwrap_files_getgrent_r(struct nwrap_backend *b,
- struct group *grdst, char *buf,
- size_t buflen, struct group **grdstp)
+void setpwent(void)
{
- struct group *gr;
-
- gr = nwrap_files_getgrent(b);
- if (!gr) {
- if (errno == 0) {
- return ENOENT;
- }
- return errno;
+ if (!nss_wrapper_enabled()) {
+ libc_setpwent();
+ return;
}
- return nwrap_gr_copy_r(gr, grdst, buf, buflen, grdstp);
-}
-
-static void nwrap_files_endgrent(struct nwrap_backend *b)
-{
- nwrap_gr_global.idx = 0;
+ nwrap_setpwent();
}
-/*
- * module backend
- */
-
-#ifndef SAFE_FREE
-#define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
-#endif
+/****************************************************************************
+ * GETPWENT
+ ***************************************************************************/
-static struct passwd *nwrap_module_getpwnam(struct nwrap_backend *b,
- const char *name)
+static struct passwd *nwrap_getpwent(void)
{
- static struct passwd pwd;
- static char buf[1000];
- NSS_STATUS status;
+ int i;
+ struct passwd *pwd;
- if (!b->fns->_nss_getpwnam_r) {
- return NULL;
+ 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);
+ if (pwd) {
+ return pwd;
+ }
}
- status = b->fns->_nss_getpwnam_r(name, &pwd, buf, sizeof(buf), &errno);
- if (status == NSS_STATUS_NOTFOUND) {
- return NULL;
- }
- if (status != NSS_STATUS_SUCCESS) {
- return NULL;
- }
- return &pwd;
+ return NULL;
}
-static int nwrap_module_getpwnam_r(struct nwrap_backend *b,
- const char *name, struct passwd *pwdst,
- char *buf, size_t buflen, struct passwd **pwdstp)
+struct passwd *getpwent(void)
{
- int ret;
-
- if (!b->fns->_nss_getpwnam_r) {
- return NSS_STATUS_NOTFOUND;
+ if (!nss_wrapper_enabled()) {
+ return libc_getpwent();
}
- ret = b->fns->_nss_getpwnam_r(name, pwdst, buf, buflen, &errno);
- switch (ret) {
- case NSS_STATUS_SUCCESS:
- return 0;
- case NSS_STATUS_NOTFOUND:
- if (errno != 0) {
- return errno;
- }
- return ENOENT;
- case NSS_STATUS_TRYAGAIN:
- if (errno != 0) {
- return errno;
- }
- return ERANGE;
- default:
- if (errno != 0) {
- return errno;
+ 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);
+ if (ret == ENOENT) {
+ continue;
}
return ret;
}
+
+ return ENOENT;
}
-static struct passwd *nwrap_module_getpwuid(struct nwrap_backend *b,
- uid_t uid)
+#ifdef HAVE_SOLARIS_GETPWENT_R
+struct passwd *getpwent_r(struct passwd *pwdst, char *buf, int buflen)
{
- static struct passwd pwd;
- static char buf[1000];
- NSS_STATUS status;
+ struct passwd *pwdstp = NULL;
+ int rc;
- if (!b->fns->_nss_getpwuid_r) {
- return NULL;
+ if (!nss_wrapper_enabled()) {
+ return libc_getpwent_r(pwdst, buf, buflen);
}
-
- status = b->fns->_nss_getpwuid_r(uid, &pwd, buf, sizeof(buf), &errno);
- if (status == NSS_STATUS_NOTFOUND) {
+ rc = nwrap_getpwent_r(pwdst, buf, buflen, &pwdstp);
+ if (rc < 0) {
return NULL;
}
- if (status != NSS_STATUS_SUCCESS) {
- 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 &pwd;
+
+ return nwrap_getpwent_r(pwdst, buf, buflen, pwdstp);
}
+#endif /* HAVE_SOLARIS_GETPWENT_R */
-static int nwrap_module_getpwuid_r(struct nwrap_backend *b,
- uid_t uid, struct passwd *pwdst,
- char *buf, size_t buflen, struct passwd **pwdstp)
-{
- int ret;
+/****************************************************************************
+ * ENDPWENT
+ ***************************************************************************/
- if (!b->fns->_nss_getpwuid_r) {
- return ENOENT;
- }
+static void nwrap_endpwent(void)
+{
+ int i;
- ret = b->fns->_nss_getpwuid_r(uid, pwdst, buf, buflen, &errno);
- switch (ret) {
- case NSS_STATUS_SUCCESS:
- return 0;
- case NSS_STATUS_NOTFOUND:
- if (errno != 0) {
- return errno;
- }
- return ENOENT;
- case NSS_STATUS_TRYAGAIN:
- if (errno != 0) {
- return errno;
- }
- return ERANGE;
- default:
- if (errno != 0) {
- return errno;
- }
- return ret;
+ for (i=0; i < nwrap_main_global->num_backends; i++) {
+ struct nwrap_backend *b = &nwrap_main_global->backends[i];
+ b->ops->nw_endpwent(b);
}
}
-static void nwrap_module_setpwent(struct nwrap_backend *b)
+void endpwent(void)
{
- if (!b->fns->_nss_setpwent) {
+ if (!nss_wrapper_enabled()) {
+ libc_endpwent();
return;
}
- b->fns->_nss_setpwent();
+ nwrap_endpwent();
}
-static struct passwd *nwrap_module_getpwent(struct nwrap_backend *b)
+/****************************************************************************
+ * INITGROUPS
+ ***************************************************************************/
+
+static int nwrap_initgroups(const char *user, gid_t group)
{
- static struct passwd pwd;
- static char buf[1000];
- NSS_STATUS status;
+ int i;
- if (!b->fns->_nss_getpwent_r) {
- return NULL;
- }
+ for (i=0; i < nwrap_main_global->num_backends; i++) {
+ struct nwrap_backend *b = &nwrap_main_global->backends[i];
+ int rc;
- status = b->fns->_nss_getpwent_r(&pwd, buf, sizeof(buf), &errno);
- if (status == NSS_STATUS_NOTFOUND) {
- return NULL;
+ rc = b->ops->nw_initgroups(b, user, group);
+ if (rc == 0) {
+ return 0;
+ }
}
- if (status != NSS_STATUS_SUCCESS) {
- return NULL;
+
+ errno = ENOENT;
+ return -1;
+}
+
+int initgroups(const char *user, gid_t group)
+{
+ if (!nss_wrapper_enabled()) {
+ return libc_initgroups(user, group);
}
- return &pwd;
+
+ return nwrap_initgroups(user, group);
}
-static int nwrap_module_getpwent_r(struct nwrap_backend *b,
- struct passwd *pwdst, char *buf,
- size_t buflen, struct passwd **pwdstp)
+/****************************************************************************
+ * GETGRNAM
+ ***************************************************************************/
+
+static struct group *nwrap_getgrnam(const char *name)
{
- int ret;
+ int i;
+ struct group *grp;
- if (!b->fns->_nss_getpwent_r) {
- return ENOENT;
+ 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);
+ if (grp) {
+ return grp;
+ }
}
- ret = b->fns->_nss_getpwent_r(pwdst, buf, buflen, &errno);
- switch (ret) {
- case NSS_STATUS_SUCCESS:
- return 0;
- case NSS_STATUS_NOTFOUND:
- if (errno != 0) {
- return errno;
- }
- return ENOENT;
- case NSS_STATUS_TRYAGAIN:
- if (errno != 0) {
- return errno;
- }
- return ERANGE;
- default:
- if (errno != 0) {
- return errno;
+ return NULL;
+}
+
+struct group *getgrnam(const char *name)
+{
+ 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);
+ if (ret == ENOENT) {
+ continue;
}
return ret;
}
+
+ return ENOENT;
}
-static void nwrap_module_endpwent(struct nwrap_backend *b)
+#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 (!b->fns->_nss_endpwent) {
- return;
+ if (!nss_wrapper_enabled()) {
+ return libc_getgrnam_r(name,
+ grp,
+ buf,
+ buflen,
+ pgrp);
}
- b->fns->_nss_endpwent();
+ return nwrap_getgrnam_r(name, grp, buf, buflen, pgrp);
}
+#endif /* HAVE_GETGRNAM_R */
-static int nwrap_module_initgroups(struct nwrap_backend *b,
- const char *user, gid_t group)
+/****************************************************************************
+ * GETGRGID
+ ***************************************************************************/
+
+static struct group *nwrap_getgrgid(gid_t gid)
{
- gid_t *groups;
- long int start;
- long int size;
+ int i;
+ struct group *grp;
- if (!b->fns->_nss_initgroups) {
- return NSS_STATUS_UNAVAIL;
+ 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);
+ if (grp) {
+ return grp;
+ }
}
- return b->fns->_nss_initgroups(user, group, &start, &size, &groups, 0, &errno);
+ return NULL;
}
-static struct group *nwrap_module_getgrnam(struct nwrap_backend *b,
- const char *name)
+struct group *getgrgid(gid_t gid)
{
- static struct group grp;
- static char *buf;
- static int buflen = 1000;
- NSS_STATUS status;
-
- if (!b->fns->_nss_getgrnam_r) {
- return NULL;
+ if (!nss_wrapper_enabled()) {
+ return libc_getgrgid(gid);
}
- if (!buf) {
- buf = (char *)malloc(buflen);
- }
-again:
- status = b->fns->_nss_getgrnam_r(name, &grp, buf, buflen, &errno);
- if (status == NSS_STATUS_TRYAGAIN) {
- buflen *= 2;
- buf = (char *)realloc(buf, buflen);
- if (!buf) {
- return NULL;
+ 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);
+ if (ret == ENOENT) {
+ continue;
}
- goto again;
- }
- if (status == NSS_STATUS_NOTFOUND) {
- SAFE_FREE(buf);
- return NULL;
+ return ret;
}
- if (status != NSS_STATUS_SUCCESS) {
- SAFE_FREE(buf);
- return NULL;
+
+ return ENOENT;
+}
+
+#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 */
+{
+ if (!nss_wrapper_enabled()) {
+ return libc_getgrgid_r(gid, grdst, buf, buflen, grdstp);
}
- return &grp;
+
+ return nwrap_getgrgid_r(gid, grdst, buf, buflen, grdstp);
}
+#endif
-static int nwrap_module_getgrnam_r(struct nwrap_backend *b,
- const char *name, struct group *grdst,
- char *buf, size_t buflen, struct group **grdstp)
+/****************************************************************************
+ * SETGRENT
+ ***************************************************************************/
+
+static void nwrap_setgrent(void)
{
- int ret;
+ int i;
- if (!b->fns->_nss_getgrnam_r) {
- return ENOENT;
+ for (i=0; i < nwrap_main_global->num_backends; i++) {
+ struct nwrap_backend *b = &nwrap_main_global->backends[i];
+ b->ops->nw_setgrent(b);
}
+}
- ret = b->fns->_nss_getgrnam_r(name, grdst, buf, buflen, &errno);
- switch (ret) {
- case NSS_STATUS_SUCCESS:
- return 0;
- case NSS_STATUS_NOTFOUND:
- if (errno != 0) {
- return errno;
- }
- return ENOENT;
- case NSS_STATUS_TRYAGAIN:
- if (errno != 0) {
- return errno;
- }
- return ERANGE;
- default:
- if (errno != 0) {
- return errno;
+#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;
+
+ 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);
+ if (grp) {
+ return grp;
}
- return ret;
}
+
+ return NULL;
}
-static struct group *nwrap_module_getgrgid(struct nwrap_backend *b,
- gid_t gid)
+struct group *getgrent(void)
{
- static struct group grp;
- static char *buf;
- static int buflen = 1000;
- NSS_STATUS status;
-
- if (!b->fns->_nss_getgrgid_r) {
- return NULL;
+ if (!nss_wrapper_enabled()) {
+ return libc_getgrent();
}
- if (!buf) {
- buf = (char *)malloc(buflen);
- }
+ return nwrap_getgrent();
+}
-again:
- status = b->fns->_nss_getgrgid_r(gid, &grp, buf, buflen, &errno);
- if (status == NSS_STATUS_TRYAGAIN) {
- buflen *= 2;
- buf = (char *)realloc(buf, buflen);
- if (!buf) {
- return NULL;
+/****************************************************************************
+ * 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);
+ if (ret == ENOENT) {
+ continue;
}
- goto again;
- }
- if (status == NSS_STATUS_NOTFOUND) {
- SAFE_FREE(buf);
- return NULL;
- }
- if (status != NSS_STATUS_SUCCESS) {
- SAFE_FREE(buf);
- return NULL;
+ return ret;
}
- return &grp;
+
+ return ENOENT;
}
-static int nwrap_module_getgrgid_r(struct nwrap_backend *b,
- gid_t gid, struct group *grdst,
- char *buf, size_t buflen, struct group **grdstp)
+#ifdef HAVE_SOLARIS_GETGRENT_R
+struct group *getgrent_r(struct group *src, char *buf, int buflen)
{
- int ret;
+ struct group *grdstp = NULL;
+ int rc;
- if (!b->fns->_nss_getgrgid_r) {
- return ENOENT;
+ if (!nss_wrapper_enabled()) {
+ return libc_getgrent_r(src, buf, buflen);
}
- ret = b->fns->_nss_getgrgid_r(gid, grdst, buf, buflen, &errno);
- switch (ret) {
- case NSS_STATUS_SUCCESS:
- return 0;
- case NSS_STATUS_NOTFOUND:
- if (errno != 0) {
- return errno;
- }
- return ENOENT;
- case NSS_STATUS_TRYAGAIN:
- if (errno != 0) {
- return errno;
- }
- return ERANGE;
- default:
- if (errno != 0) {
- return errno;
- }
- return ret;
+ rc = nwrap_getgrent_r(src, buf, buflen, &grdstp);
+ if (rc < 0) {
+ return NULL;
}
-}
-static void nwrap_module_setgrent(struct nwrap_backend *b)
+ return grdstp;
+}
+#else /* HAVE_SOLARIS_GETGRENT_R */
+int getgrent_r(struct group *src, char *buf,
+ size_t buflen, struct group **grdstp)
{
- if (!b->fns->_nss_setgrent) {
- return;
+ if (!nss_wrapper_enabled()) {
+ return libc_getgrent_r(src, buf, buflen, grdstp);
}
- b->fns->_nss_setgrent();
+ return nwrap_getgrent_r(src, buf, buflen, grdstp);
}
+#endif /* HAVE_SOLARIS_GETGRENT_R */
-static struct group *nwrap_module_getgrent(struct nwrap_backend *b)
+/****************************************************************************
+ * ENDGRENT
+ ***************************************************************************/
+
+static void nwrap_endgrent(void)
{
- static struct group grp;
- static char *buf;
- static int buflen = 1024;
- NSS_STATUS status;
+ int i;
- if (!b->fns->_nss_getgrent_r) {
- return NULL;
+ for (i=0; i < nwrap_main_global->num_backends; i++) {
+ struct nwrap_backend *b = &nwrap_main_global->backends[i];
+ b->ops->nw_endgrent(b);
}
+}
- if (!buf) {
- buf = (char *)malloc(buflen);
+void endgrent(void)
+{
+ if (!nss_wrapper_enabled()) {
+ libc_endgrent();
+ return;
}
-again:
- status = b->fns->_nss_getgrent_r(&grp, buf, buflen, &errno);
- if (status == NSS_STATUS_TRYAGAIN) {
- buflen *= 2;
- buf = (char *)realloc(buf, buflen);
- if (!buf) {
- return NULL;
- }
- goto again;
- }
- if (status == NSS_STATUS_NOTFOUND) {
- SAFE_FREE(buf);
- return NULL;
- }
- if (status != NSS_STATUS_SUCCESS) {
- SAFE_FREE(buf);
- return NULL;
- }
- return &grp;
+ nwrap_endgrent();
}
-static int nwrap_module_getgrent_r(struct nwrap_backend *b,
- struct group *grdst, char *buf,
- size_t buflen, struct group **grdstp)
+/****************************************************************************
+ * GETGROUPLIST
+ ***************************************************************************/
+
+#ifdef HAVE_GETGROUPLIST
+static int nwrap_getgrouplist(const char *user, gid_t group,
+ gid_t *groups, int *ngroups)
{
- int ret;
+ struct group *grp;
+ gid_t *groups_tmp;
+ int count = 1;
- if (!b->fns->_nss_getgrent_r) {
- return ENOENT;
+ NWRAP_LOG(NWRAP_LOG_DEBUG, "getgrouplist called for %s", user);
+
+ groups_tmp = (gid_t *)malloc(count * sizeof(gid_t));
+ if (!groups_tmp) {
+ NWRAP_LOG(NWRAP_LOG_ERROR, "Out of memory");
+ errno = ENOMEM;
+ return -1;
}
+ groups_tmp[0] = group;
- ret = b->fns->_nss_getgrent_r(grdst, buf, buflen, &errno);
- switch (ret) {
- case NSS_STATUS_SUCCESS:
- return 0;
- case NSS_STATUS_NOTFOUND:
- if (errno != 0) {
- return errno;
- }
- return ENOENT;
- case NSS_STATUS_TRYAGAIN:
- if (errno != 0) {
- return errno;
- }
- return ERANGE;
- default:
- if (errno != 0) {
- return errno;
+ nwrap_setgrent();
+ while ((grp = nwrap_getgrent()) != NULL) {
+ int i = 0;
+
+ 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 (group != grp->gr_gid &&
+ (strcmp(user, grp->gr_mem[i]) == 0)) {
+
+ 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_LOG(NWRAP_LOG_ERROR,
+ "Out of memory");
+ errno = ENOMEM;
+ return -1;
+ }
+ groups_tmp[count] = grp->gr_gid;
+
+ count++;
+ }
}
- return ret;
}
+
+ nwrap_endgrent();
+
+ NWRAP_LOG(NWRAP_LOG_DEBUG,
+ "%s is member of %d groups",
+ user, *ngroups);
+
+ if (*ngroups < count) {
+ *ngroups = count;
+ free(groups_tmp);
+ return -1;
+ }
+
+ *ngroups = count;
+ memcpy(groups, groups_tmp, count * sizeof(gid_t));
+ free(groups_tmp);
+
+ return count;
}
-static void nwrap_module_endgrent(struct nwrap_backend *b)
+int getgrouplist(const char *user, gid_t group, gid_t *groups, int *ngroups)
{
- if (!b->fns->_nss_endgrent) {
- return;
+ if (!nss_wrapper_enabled()) {
+ return libc_getgrouplist(user, group, groups, ngroups);
}
- b->fns->_nss_endgrent();
+ return nwrap_getgrouplist(user, group, groups, ngroups);
}
+#endif
-/*
- * PUBLIC interface
- */
+/**********************************************************
+ * SHADOW
+ **********************************************************/
-_PUBLIC_ struct passwd *nwrap_getpwnam(const char *name)
-{
- int i;
- struct passwd *pwd;
+#if defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM)
- if (!nwrap_enabled()) {
- return real_getpwnam(name);
- }
+#ifdef HAVE_SETSPENT
+static void nwrap_setspent(void)
+{
+ nwrap_files_setspent();
+}
- 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);
- if (pwd) {
- return pwd;
- }
+void setspent(void)
+{
+ if (!nss_wrapper_shadow_enabled()) {
+ return;
}
- return NULL;
+ nwrap_setspent();
}
-_PUBLIC_ int nwrap_getpwnam_r(const char *name, struct passwd *pwdst,
- char *buf, size_t buflen, struct passwd **pwdstp)
+static struct spwd *nwrap_getspent(void)
{
- int i,ret;
+ return nwrap_files_getspent();
+}
- if (!nwrap_enabled()) {
- return real_getpwnam_r(name, pwdst, buf, buflen, pwdstp);
+struct spwd *getspent(void)
+{
+ if (!nss_wrapper_shadow_enabled()) {
+ return NULL;
}
- 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);
- if (ret == ENOENT) {
- continue;
- }
- return ret;
+ return nwrap_getspent();
+}
+
+static void nwrap_endspent(void)
+{
+ nwrap_files_endspent();
+}
+
+void endspent(void)
+{
+ if (!nss_wrapper_shadow_enabled()) {
+ return;
}
- return ENOENT;
+ nwrap_endspent();
}
+#endif /* HAVE_SETSPENT */
-_PUBLIC_ struct passwd *nwrap_getpwuid(uid_t uid)
+static struct spwd *nwrap_getspnam(const char *name)
{
- int i;
- struct passwd *pwd;
+ return nwrap_files_getspnam(name);
+}
- if (!nwrap_enabled()) {
- return real_getpwuid(uid);
+struct spwd *getspnam(const char *name)
+{
+ if (!nss_wrapper_shadow_enabled()) {
+ return NULL;
}
- 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);
- if (pwd) {
- return pwd;
- }
- }
+ return nwrap_getspnam(name);
+}
- return NULL;
+#endif /* defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM) */
+
+/**********************************************************
+ * NETDB
+ **********************************************************/
+
+static void nwrap_sethostent(int stayopen) {
+ (void) stayopen; /* ignored */
+
+ nwrap_files_sethostent();
}
-_PUBLIC_ int nwrap_getpwuid_r(uid_t uid, struct passwd *pwdst,
- char *buf, size_t buflen, struct passwd **pwdstp)
+#ifdef HAVE_SOLARIS_SETHOSTENT
+int sethostent(int stayopen)
{
- int i,ret;
-
- if (!nwrap_enabled()) {
- return real_getpwuid_r(uid, pwdst, buf, buflen, pwdstp);
+ if (!nss_wrapper_hosts_enabled()) {
+ libc_sethostent(stayopen);
+ return 0;
}
- 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);
- if (ret == ENOENT) {
- continue;
- }
- return ret;
+ nwrap_sethostent(stayopen);
+
+ return 0;
+}
+#else /* HAVE_SOLARIS_SETHOSTENT */
+void sethostent(int stayopen)
+{
+ if (!nss_wrapper_hosts_enabled()) {
+ libc_sethostent(stayopen);
+ return;
}
- return ENOENT;
+ nwrap_sethostent(stayopen);
}
+#endif /* HAVE_SOLARIS_SETHOSTENT */
-_PUBLIC_ void nwrap_setpwent(void)
+static struct hostent *nwrap_gethostent(void)
{
- int i;
+ return nwrap_files_gethostent();
+}
- if (!nwrap_enabled()) {
- real_setpwent();
- return;
+struct hostent *gethostent(void) {
+ if (!nss_wrapper_hosts_enabled()) {
+ return libc_gethostent();
}
- for (i=0; i < nwrap_main_global->num_backends; i++) {
- struct nwrap_backend *b = &nwrap_main_global->backends[i];
- b->ops->nw_setpwent(b);
- }
+ return nwrap_gethostent();
}
-_PUBLIC_ struct passwd *nwrap_getpwent(void)
-{
- int i;
- struct passwd *pwd;
+static void nwrap_endhostent(void) {
+ nwrap_files_endhostent();
+}
- if (!nwrap_enabled()) {
- return real_getpwent();
+#ifdef HAVE_SOLARIS_ENDHOSTENT
+int endhostent(void)
+{
+ if (!nss_wrapper_hosts_enabled()) {
+ libc_endhostent();
+ return 0;
}
- 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);
- if (pwd) {
- return pwd;
- }
+ nwrap_endhostent();
+
+ return 0;
+}
+#else /* HAVE_SOLARIS_ENDHOSTENT */
+void endhostent(void)
+{
+ if (!nss_wrapper_hosts_enabled()) {
+ libc_endhostent();
+ return;
}
- return NULL;
+ nwrap_endhostent();
}
+#endif /* HAVE_SOLARIS_ENDHOSTENT */
-_PUBLIC_ int nwrap_getpwent_r(struct passwd *pwdst, char *buf,
- size_t buflen, struct passwd **pwdstp)
+#ifdef BSD
+/* BSD implementation stores data in thread local storage but GLIBC does not */
+static __thread struct hostent user_he;
+static __thread struct nwrap_vector user_addrlist;
+#else
+static struct hostent user_he;
+static struct nwrap_vector user_addrlist;
+#endif /* BSD */
+static struct hostent *nwrap_gethostbyname(const char *name)
{
- int i,ret;
+ if (nwrap_files_gethostbyname(name, AF_UNSPEC, &user_he, &user_addrlist) == -1) {
+ return NULL;
+ }
+ return &user_he;
+}
- 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;
+struct hostent *gethostbyname(const char *name)
+{
+ if (!nss_wrapper_hosts_enabled()) {
+ return libc_gethostbyname(name);
+ }
+
+ return nwrap_gethostbyname(name);
+}
+
+/* This is a GNU extension - Also can be found on BSD systems */
+#ifdef HAVE_GETHOSTBYNAME2
+#ifdef BSD
+/* BSD implementation stores data in thread local storage but GLIBC not */
+static __thread struct hostent user_he2;
+static __thread struct nwrap_vector user_addrlist2;
#else
- return real_getpwent_r(pwdst, buf, buflen, pwdstp);
-#endif
+static struct hostent user_he2;
+static struct nwrap_vector user_addrlist2;
+#endif /* BSD */
+static struct hostent *nwrap_gethostbyname2(const char *name, int af)
+{
+ if (nwrap_files_gethostbyname(name, af, &user_he2, &user_addrlist2) == -1) {
+ return NULL;
}
+ return &user_he2;
+}
- 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);
- if (ret == ENOENT) {
- continue;
- }
- return ret;
+struct hostent *gethostbyname2(const char *name, int af)
+{
+ if (!nss_wrapper_hosts_enabled()) {
+ return libc_gethostbyname2(name, af);
}
- return ENOENT;
+ return nwrap_gethostbyname2(name, af);
}
+#endif
-_PUBLIC_ void nwrap_endpwent(void)
+static struct hostent *nwrap_gethostbyaddr(const void *addr,
+ socklen_t len, int type)
{
- int i;
+ return nwrap_files_gethostbyaddr(addr, len, type);
+}
- if (!nwrap_enabled()) {
- real_endpwent();
- return;
+struct hostent *gethostbyaddr(const void *addr,
+ socklen_t len, int type)
+{
+ if (!nss_wrapper_hosts_enabled()) {
+ return libc_gethostbyaddr(addr, len, type);
}
- for (i=0; i < nwrap_main_global->num_backends; i++) {
- struct nwrap_backend *b = &nwrap_main_global->backends[i];
- b->ops->nw_endpwent(b);
- }
+ return nwrap_gethostbyaddr(addr, len, type);
}
-_PUBLIC_ int nwrap_initgroups(const char *user, gid_t group)
+static const struct addrinfo default_hints =
{
- int i;
+ .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,
+ bool skip_canonname)
+{
+ struct addrinfo *ai;
+ socklen_t socklen;
- if (!nwrap_enabled()) {
- return real_initgroups(user, group);
+ if (he == NULL) {
+ return EAI_MEMORY;
}
- 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);
+ 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;
}
- errno = ENOENT;
- return -1;
-}
+ ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) + socklen);
+ if (ai == NULL) {
+ return EAI_MEMORY;
+ }
-_PUBLIC_ struct group *nwrap_getgrnam(const char *name)
-{
- int i;
- struct group *grp;
+ ai->ai_flags = 0;
+ ai->ai_family = he->h_addrtype;
+ ai->ai_socktype = hints->ai_socktype;
+ ai->ai_protocol = hints->ai_protocol;
+ ai->ai_canonname = NULL;
- if (!nwrap_enabled()) {
- return real_getgrnam(name);
- }
+ 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);
- 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);
- if (grp) {
- return grp;
}
- }
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ {
+ struct sockaddr_in6 *sin6p =
+ (struct sockaddr_in6 *) ai->ai_addr;
- return NULL;
-}
+ memset(sin6p, 0, sizeof(struct sockaddr_in6));
-_PUBLIC_ int nwrap_getgrnam_r(const char *name, struct group *grdst,
- char *buf, size_t buflen, struct group **grdstp)
-{
- int i,ret;
+ sin6p->sin6_port = htons(port);
+ sin6p->sin6_family = AF_INET6;
- if (!nwrap_enabled()) {
- return real_getgrnam_r(name, grdst, buf, buflen, grdstp);
+ memcpy(&sin6p->sin6_addr,
+ he->h_addr_list[0],
+ he->h_length);
+ }
+ break;
+#endif
}
- 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);
- if (ret == ENOENT) {
- continue;
+ ai->ai_next = NULL;
+
+ if (he->h_name && !skip_canonname) {
+ ai->ai_canonname = strdup(he->h_name);
+ if (ai->ai_canonname == NULL) {
+ freeaddrinfo(ai);
+ return EAI_MEMORY;
}
- return ret;
}
- return ENOENT;
+ *pai = ai;
+ return 0;
}
-_PUBLIC_ struct group *nwrap_getgrgid(gid_t gid)
+static int nwrap_getaddrinfo(const char *node,
+ const char *service,
+ const struct addrinfo *hints,
+ struct addrinfo **res)
{
- int i;
- struct group *grp;
+ struct addrinfo *ai = NULL;
+ struct addrinfo *ai_tail;
+ unsigned short port = 0;
+ struct {
+ int family;
+ union {
+ struct in_addr v4;
+#ifdef HAVE_IPV6
+ struct in6_addr v6;
+ } in;
+#endif
+ } addr = {
+ .family = AF_UNSPEC,
+ };
+ int rc;
- if (!nwrap_enabled()) {
- return real_getgrgid(gid);
+ if (node == NULL && service == NULL) {
+ return EAI_NONAME;
}
- 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);
- if (grp) {
- return grp;
+ if (hints == NULL) {
+ hints = &default_hints;
+ }
+
+ /* EAI_BADFLAGS
+ hints.ai_flags contains invalid flags; or, hints.ai_flags
+ included AI_CANONNAME and name was NULL.
+ */
+ if ((hints->ai_flags & AI_CANONNAME) && (node == NULL)) {
+ return EAI_BADFLAGS;
+ }
+
+ /* If no node has been specified, let glibc deal with it */
+ if (node == NULL) {
+ int ret;
+ struct addrinfo *p = NULL;
+
+ ret = libc_getaddrinfo(node, service, hints, &p);
+
+ if (ret == 0) {
+ *res = p;
}
+ return ret;
}
- return NULL;
-}
+ if (service != NULL && service[0] != '\0') {
+ const char *proto = NULL;
+ struct servent *s;
+ char *end_ptr;
+ long sl;
-_PUBLIC_ int nwrap_getgrgid_r(gid_t gid, struct group *grdst,
- char *buf, size_t buflen, struct group **grdstp)
-{
- int i,ret;
+ errno = 0;
+ sl = strtol(service, &end_ptr, 10);
+
+ if (*end_ptr == '\0') {
+ port = sl;
+ goto valid_port;
+ } else if (hints->ai_flags & AI_NUMERICSERV) {
+ return EAI_NONAME;
+ }
- if (!nwrap_enabled()) {
- return real_getgrgid_r(gid, grdst, buf, buflen, grdstp);
+ 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) {
+ return EAI_NONAME;
+ }
+ port = ntohs(s->s_port);
}
- 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);
- if (ret == ENOENT) {
- continue;
+valid_port:
+
+ rc = inet_pton(AF_INET, node, &addr.in.v4);
+ if (rc == 1) {
+ addr.family = AF_INET;
+ }
+#ifdef HAVE_IPV6
+ if (addr.family == AF_UNSPEC) {
+ rc = inet_pton(AF_INET6, node, &addr.in.v6);
+ if (rc == 1) {
+ addr.family = AF_INET6;
}
- return ret;
}
+#endif
- return ENOENT;
-}
+ if ((addr.family != AF_UNSPEC) &&
+ (hints->ai_family != AF_UNSPEC) &&
+ (hints->ai_family != addr.family))
+ {
+ return EAI_ADDRFAMILY;
+ }
-_PUBLIC_ void nwrap_setgrent(void)
-{
- int i;
+ rc = nwrap_files_getaddrinfo(node, port, hints, &ai, &ai_tail);
+ if (rc != 0) {
+ int ret;
+ struct addrinfo *p = NULL;
- if (!nwrap_enabled()) {
- real_setgrent();
- return;
+ ret = libc_getaddrinfo(node, service, hints, &p);
+
+ if (ret == 0) {
+ /*
+ * nwrap_files_getaddrinfo failed, but libc was
+ * successful -- use the result from libc.
+ */
+ *res = p;
+ return 0;
+ }
+
+ return rc;
}
- for (i=0; i < nwrap_main_global->num_backends; i++) {
- struct nwrap_backend *b = &nwrap_main_global->backends[i];
- b->ops->nw_setgrent(b);
+ 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 */
}
-}
-_PUBLIC_ struct group *nwrap_getgrent(void)
-{
- int i;
- struct group *grp;
+ if (hints->ai_socktype == 0) {
+ /* Add second ai */
+ struct addrinfo *ai_head = ai;
+ struct addrinfo *ai_tmp;
+ struct addrinfo *ai_new_tail = ai_tail;
- if (!nwrap_enabled()) {
- return real_getgrent();
+ /* Add at least one more struct */
+ do {
+ /* CHECKS! */
+ ai_tmp = malloc(sizeof(struct addrinfo));
+ memcpy(ai_tmp, ai_head, sizeof(struct addrinfo));
+ ai_tmp->ai_next = NULL;
+
+ /* We need a deep copy or freeaddrinfo() will blow up */
+ if (ai_head->ai_canonname != NULL) {
+ ai_tmp->ai_canonname =
+ strdup(ai_head->ai_canonname);
+ }
+ /* ai_head should point inside hints. */
+ ai_tmp->ai_addr = ai_head->ai_addr;
+
+ if (ai_head->ai_flags == 0) {
+ ai_tmp->ai_flags = hints->ai_flags;
+ }
+ if (ai_head->ai_socktype == SOCK_DGRAM) {
+ ai_tmp->ai_socktype = SOCK_STREAM;
+ } else if (ai_head->ai_socktype == SOCK_STREAM) {
+ ai_tmp->ai_socktype = SOCK_DGRAM;
+ }
+ if (ai_head->ai_socktype == SOCK_DGRAM) {
+ ai_tmp->ai_protocol = 17; /* UDP */
+ } else if (ai_head->ai_socktype == SOCK_STREAM) {
+ ai_tmp->ai_protocol = 6; /* TCP */
+ }
+ ai_new_tail->ai_next = ai_tmp;
+ ai_new_tail = ai_tmp;
+
+ if (ai_head == ai_tail) {
+ break;
+ }
+ ai_head = ai_head->ai_next;
+ } while (1);
}
- 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);
- if (grp) {
- return grp;
- }
+ *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 NULL;
+ return nwrap_getaddrinfo(node, service, hints, res);
}
-_PUBLIC_ int nwrap_getgrent_r(struct group *grdst, char *buf,
- size_t buflen, struct group **grdstp)
+static int nwrap_getnameinfo(const struct sockaddr *sa, socklen_t salen,
+ char *host, size_t hostlen,
+ char *serv, size_t servlen,
+ int flags)
{
- int i,ret;
+ 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 = &((const struct sockaddr_in *)sa)->sin_addr;
+ addrlen = sizeof(((const struct sockaddr_in *)sa)->sin_addr);
+ port = ntohs(((const struct sockaddr_in *)sa)->sin_port);
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ if (salen < sizeof(struct sockaddr_in6))
+ return EAI_FAMILY;
+ addr = &((const struct sockaddr_in6 *)sa)->sin6_addr;
+ addrlen = sizeof(((const struct sockaddr_in6 *)sa)->sin6_addr);
+ port = ntohs(((const struct sockaddr_in6 *)sa)->sin6_port);
+ break;
+#endif
+ default:
+ return EAI_FAMILY;
+ }
- 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 (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 (grdstp) {
- *grdstp = gr;
+ 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;
}
- return 0;
-#else
- return real_getgrent_r(grdst, buf, buflen, grdstp);
-#endif
}
- 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);
- if (ret == ENOENT) {
- continue;
+ 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 ret;
}
- return ENOENT;
+ return 0;
}
-_PUBLIC_ void nwrap_endgrent(void)
+#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
{
- int i;
-
- if (!nwrap_enabled()) {
- real_endgrent();
- return;
+ if (!nss_wrapper_hosts_enabled()) {
+ return libc_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
}
- for (i=0; i < nwrap_main_global->num_backends; i++) {
- struct nwrap_backend *b = &nwrap_main_global->backends[i];
- b->ops->nw_endgrent(b);
- }
+ return nwrap_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
}
-_PUBLIC_ int nwrap_getgrouplist(const char *user, gid_t group, gid_t *groups, int *ngroups)
+static int nwrap_gethostname(char *name, size_t len)
{
- 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);
- }
+ const char *hostname = getenv("NSS_WRAPPER_HOSTNAME");
- NWRAP_DEBUG(("%s: getgrouplist called for %s\n", __location__, user));
-
- groups_tmp = (gid_t *)malloc(count * sizeof(gid_t));
- if (!groups_tmp) {
- NWRAP_ERROR(("%s:calloc failed\n",__location__));
- errno = ENOMEM;
+ if (strlen(hostname) >= len) {
+ errno = ENAMETOOLONG;
return -1;
}
+ snprintf(name, len, "%s", hostname);
- memcpy(groups_tmp, &group, sizeof(gid_t));
+ return 0;
+}
- grp = nwrap_getgrgid(group);
- if (grp) {
- name_of_group = grp->gr_name;
+#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);
}
- nwrap_setgrent();
- while ((grp = nwrap_getgrent()) != NULL) {
- int i = 0;
+ return nwrap_gethostname(name, len);
+}
- NWRAP_VERBOSE(("%s: inspecting %s for group membership\n",
- __location__, grp->gr_name));
+/****************************
+ * DESTRUCTOR
+ ***************************/
- for (i=0; grp->gr_mem && grp->gr_mem[i] != NULL; i++) {
+/*
+ * 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 ((strcmp(user, grp->gr_mem[i]) == 0) &&
- (strcmp(name_of_group, grp->gr_name) != 0)) {
+ NWRAP_LOCK_ALL;
+ if (nwrap_main_global != NULL) {
+ struct nwrap_main *m = nwrap_main_global;
- NWRAP_DEBUG(("%s: %s is member of %s\n",
- __location__, user, grp->gr_name));
+ /* 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);
- groups_tmp = (gid_t *)realloc(groups_tmp, (count + 1) * sizeof(gid_t));
- if (!groups_tmp) {
- NWRAP_ERROR(("%s:calloc failed\n",__location__));
- errno = ENOMEM;
- return -1;
- }
+ /* backends */
+ for (i = 0; i < m->num_backends; i++) {
+ struct nwrap_backend *b = &(m->backends[i]);
- memcpy(&groups_tmp[count], &grp->gr_gid, sizeof(gid_t));
- count++;
+ if (b->so_handle != NULL) {
+ dlclose(b->so_handle);
}
+ SAFE_FREE(b->fns);
}
+ SAFE_FREE(m->backends);
}
- nwrap_endgrent();
+ if (nwrap_pw_global.cache != NULL) {
+ struct nwrap_cache *c = nwrap_pw_global.cache;
- NWRAP_VERBOSE(("%s: %s is member of %d groups: %d\n",
- __location__, user, *ngroups));
+ nwrap_files_cache_unload(c);
+ if (c->fd >= 0) {
+ fclose(c->fp);
+ c->fd = -1;
+ }
- if (*ngroups < count) {
- *ngroups = count;
- free(groups_tmp);
- return -1;
+ SAFE_FREE(nwrap_pw_global.list);
+ nwrap_pw_global.num = 0;
}
- *ngroups = count;
- memcpy(groups, groups_tmp, count * sizeof(gid_t));
- free(groups_tmp);
+ if (nwrap_gr_global.cache != NULL) {
+ struct nwrap_cache *c = nwrap_gr_global.cache;
- return count;
+ nwrap_files_cache_unload(c);
+ if (c->fd >= 0) {
+ fclose(c->fp);
+ c->fd = -1;
+ }
+
+ 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) {
+ fclose(c->fp);
+ c->fd = -1;
+ }
+
+ nwrap_he_global.num = 0;
+ }
+
+ hdestroy();
+ NWRAP_UNLOCK_ALL;
}