/*
- * Copyright (C) Stefan Metzmacher 2007 <metze@samba.org>
- * Copyright (C) Guenther Deschner 2009 <gd@samba.org>
- * Copyright (C) Andreas Schneider 2013 <asn@samba.org>
+ * BSD 3-Clause License
*
+ * Copyright (c) 2007, Stefan Metzmacher <metze@samba.org>
+ * Copyright (c) 2009, Guenther Deschner <gd@samba.org>
+ * Copyright (c) 2014-2015, Michael Adam <obnox@samba.org>
+ * Copyright (c) 2015, Robin Hack <hack.robin@gmail.com>
+ * Copyright (c) 2013-2018, Andreas Schneider <asn@samba.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
#define PRINTF_ATTRIBUTE(a,b)
#endif /* HAVE_ATTRIBUTE_PRINTF_FORMAT */
+#ifdef HAVE_CONSTRUCTOR_ATTRIBUTE
+#define CONSTRUCTOR_ATTRIBUTE __attribute__ ((constructor))
+#else
+#define CONSTRUCTOR_ATTRIBUTE
+#endif /* HAVE_CONSTRUCTOR_ATTRIBUTE */
+
#ifdef HAVE_DESTRUCTOR_ATTRIBUTE
#define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor))
#else
NWRAP_UNLOCK(nwrap_initialized); \
} while (0);
+static void nwrap_init(void);
+
static void nwrap_thread_prepare(void)
{
+ nwrap_init();
NWRAP_LOCK_ALL;
}
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
+#ifdef HAVE_GETPWENT_R
+# ifdef HAVE_SOLARIS_GETPWENT_R
struct passwd *(*_libc_getpwent_r)(struct passwd *pwbuf, char *buf, size_t buflen);
-#else
+# else /* HAVE_SOLARIS_GETPWENT_R */
int (*_libc_getpwent_r)(struct passwd *pwbuf, char *buf, size_t buflen, struct passwd **pwbufp);
-#endif
+# endif /* HAVE_SOLARIS_GETPWENT_R */
+#endif /* HAVE_GETPWENT_R */
void (*_libc_endpwent)(void);
int (*_libc_initgroups)(const char *user, gid_t gid);
struct group *(*_libc_getgrnam)(const char *name);
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
+#ifdef HAVE_GETGRENT_R
+# ifdef HAVE_SOLARIS_GETGRENT_R
struct group *(*_libc_getgrent_r)(struct group *group, char *buf, size_t buflen);
-#else
+# else /* HAVE_SOLARIS_GETGRENT_R */
int (*_libc_getgrent_r)(struct group *group, char *buf, size_t buflen, struct group **result);
-#endif
+# endif /* HAVE_SOLARIS_GETGRENT_R */
+#endif /* HAVE_GETGRENT_R */
void (*_libc_endgrent)(void);
int (*_libc_getgrouplist)(const char *user, gid_t group, gid_t *groups, int *ngroups);
* 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_constructor(void) CONSTRUCTOR_ATTRIBUTE;
void nwrap_destructor(void) DESTRUCTOR_ATTRIBUTE;
/*********************************************************
int i;
#ifdef RTLD_DEEPBIND
- flags |= RTLD_DEEPBIND;
+ const char *env = getenv("LD_PRELOAD");
+
+ /* Don't do a deepbind if we run with libasan */
+ if (env != NULL && strlen(env) < 1024) {
+ const char *p = strstr(env, "libasan.so");
+ if (p == NULL) {
+ flags |= RTLD_DEEPBIND;
+ }
+ }
#endif
switch (lib) {
return nwrap_main_global->libc->fns->_libc_getpwent();
}
-#ifdef HAVE_SOLARIS_GETPWENT_R
+#ifdef HAVE_GETPWENT_R
+# ifdef HAVE_SOLARIS_GETPWENT_R
static struct passwd *libc_getpwent_r(struct passwd *pwdst,
char *buf,
int buflen)
buf,
buflen);
}
-#else /* HAVE_SOLARIS_GETPWENT_R */
+# else /* HAVE_SOLARIS_GETPWENT_R */
static int libc_getpwent_r(struct passwd *pwdst,
char *buf,
size_t buflen,
buflen,
pwdstp);
}
-#endif /* HAVE_SOLARIS_GETPWENT_R */
+# endif /* HAVE_SOLARIS_GETPWENT_R */
+#endif /* HAVE_GETPWENT_R */
static void libc_endpwent(void)
{
}
#ifdef HAVE_GETGRENT_R
-#ifdef HAVE_SOLARIS_GETGRENT_R
+# ifdef HAVE_SOLARIS_GETGRENT_R
static struct group *libc_getgrent_r(struct group *group,
char *buf,
size_t buflen)
buf,
buflen);
}
-#else /* !HAVE_SOLARIS_GETGRENT_R */
+# else /* HAVE_SOLARIS_GETGRENT_R */
static int libc_getgrent_r(struct group *group,
char *buf,
size_t buflen,
buflen,
result);
}
-#endif /* HAVE_SOLARIS_GETGRENT_R */
+# endif /* HAVE_SOLARIS_GETGRENT_R */
#endif /* HAVE_GETGRENT_R */
static void libc_endgrent(void)
static void nwrap_libc_init(struct nwrap_main *r)
{
- r->libc = malloc(sizeof(struct nwrap_libc));
+ r->libc = calloc(1, sizeof(struct nwrap_libc));
if (r->libc == NULL) {
printf("Failed to allocate memory for libc");
exit(-1);
}
- ZERO_STRUCTP(r->libc);
- r->libc->fns = malloc(sizeof(struct nwrap_libc_fns));
+ r->libc->fns = calloc(1, sizeof(struct nwrap_libc_fns));
if (r->libc->fns == NULL) {
printf("Failed to allocate memory for libc functions");
exit(-1);
}
- ZERO_STRUCTP(r->libc->fns);
}
static void nwrap_backend_init(struct nwrap_main *r)
const char *env;
char *endptr;
size_t max_hostents_tmp;
+ int ok;
NWRAP_LOCK(nwrap_initialized);
if (nwrap_initialized) {
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)strtoul(env, &endptr, 10);
NWRAP_LOG(NWRAP_LOG_DEBUG,
"Initializing hash table of size %lu items.",
(unsigned long)max_hostents);
- if (hcreate(max_hostents) == 0) {
+ ok = hcreate(max_hostents);
+ if (!ok) {
NWRAP_LOG(NWRAP_LOG_ERROR,
"Failed to initialize hash table");
- goto done;
+ exit(-1);
}
nwrap_main_global = &__nwrap_main_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;
}
p = hsearch(e, ENTER);
if (p == NULL) {
- NWRAP_LOG(NWRAP_LOG_ERROR, "Hash table is full!");
+ NWRAP_LOG(NWRAP_LOG_ERROR,
+ "Hash table is full (%s)!",
+ strerror(errno));
return false;
}
{
int ret;
- (void) b; /* unused */
- (void) pwdst; /* unused */
- (void) pwdstp; /* unused */
+ *pwdstp = NULL;
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:
+ *pwdstp = pwdst;
return 0;
case NSS_STATUS_NOTFOUND:
if (errno != 0) {
{
int ret;
- (void) pwdstp; /* unused */
+ *pwdstp = NULL;
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:
+ *pwdstp = pwdst;
return 0;
case NSS_STATUS_NOTFOUND:
if (errno != 0) {
{
int ret;
- (void) pwdstp; /* unused */
+ *pwdstp = NULL;
if (!b->fns->_nss_getpwent_r) {
return ENOENT;
ret = b->fns->_nss_getpwent_r(pwdst, buf, buflen, &errno);
switch (ret) {
case NSS_STATUS_SUCCESS:
+ *pwdstp = pwdst;
return 0;
case NSS_STATUS_NOTFOUND:
if (errno != 0) {
{
int ret;
- (void) grdstp; /* unused */
+ *grdstp = NULL;
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:
+ *grdstp = grdst;
return 0;
case NSS_STATUS_NOTFOUND:
if (errno != 0) {
{
int ret;
- (void) grdstp; /* unused */
+ *grdstp = NULL;
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:
+ *grdstp = grdst;
return 0;
case NSS_STATUS_NOTFOUND:
if (errno != 0) {
{
int ret;
- (void) grdstp; /* unused */
+ *grdstp = NULL;
if (!b->fns->_nss_getgrent_r) {
return ENOENT;
ret = b->fns->_nss_getgrent_r(grdst, buf, buflen, &errno);
switch (ret) {
case NSS_STATUS_SUCCESS:
+ *grdstp = grdst;
return 0;
case NSS_STATUS_NOTFOUND:
if (errno != 0) {
* GETPWENT_R
***************************************************************************/
+#ifdef HAVE_GETPWENT_R
static int nwrap_getpwent_r(struct passwd *pwdst, char *buf,
size_t buflen, struct passwd **pwdstp)
{
return ENOENT;
}
-#ifdef HAVE_SOLARIS_GETPWENT_R
+# ifdef HAVE_SOLARIS_GETPWENT_R
struct passwd *getpwent_r(struct passwd *pwdst, char *buf, int buflen)
{
struct passwd *pwdstp = NULL;
return pwdstp;
}
-#else /* HAVE_SOLARIS_GETPWENT_R */
+# else /* HAVE_SOLARIS_GETPWENT_R */
int getpwent_r(struct passwd *pwdst, char *buf,
size_t buflen, struct passwd **pwdstp)
{
return nwrap_getpwent_r(pwdst, buf, buflen, pwdstp);
}
-#endif /* HAVE_SOLARIS_GETPWENT_R */
+# endif /* HAVE_SOLARIS_GETPWENT_R */
+#endif /* HAVE_GETPWENT_R */
/****************************************************************************
* ENDPWENT
* GETGRENT_R
***************************************************************************/
+#ifdef HAVE_GETGRENT_R
static int nwrap_getgrent_r(struct group *grdst, char *buf,
size_t buflen, struct group **grdstp)
{
return ENOENT;
}
-#ifdef HAVE_SOLARIS_GETGRENT_R
+# ifdef HAVE_SOLARIS_GETGRENT_R
struct group *getgrent_r(struct group *src, char *buf, int buflen)
{
struct group *grdstp = NULL;
return grdstp;
}
-#else /* HAVE_SOLARIS_GETGRENT_R */
+# else /* HAVE_SOLARIS_GETGRENT_R */
int getgrent_r(struct group *src, char *buf,
size_t buflen, struct group **grdstp)
{
return nwrap_getgrent_r(src, buf, buflen, grdstp);
}
-#endif /* HAVE_SOLARIS_GETGRENT_R */
+# endif /* HAVE_SOLARIS_GETGRENT_R */
+#endif /* HAVE_GETGRENT_R */
/****************************************************************************
* ENDGRENT
return nwrap_gethostname(name, len);
}
+/****************************
+ * CONSTRUCTOR
+ ***************************/
+void nwrap_constructor(void)
+{
+ /*
+ * If we hold a lock and the application forks, then the child
+ * is not able to unlock the mutex and we are in a deadlock.
+ *
+ * Setting these handlers should prevent such deadlocks.
+ */
+ pthread_atfork(&nwrap_thread_prepare,
+ &nwrap_thread_parent,
+ &nwrap_thread_child);
+
+ /* Do not call nwrap_init() here. */
+}
+
/****************************
* DESTRUCTOR
***************************/
struct nwrap_main *m = nwrap_main_global;
/* libc */
- SAFE_FREE(m->libc->fns);
- if (m->libc->handle != NULL) {
- dlclose(m->libc->handle);
- }
- if (m->libc->nsl_handle != NULL) {
- dlclose(m->libc->nsl_handle);
- }
- if (m->libc->sock_handle != NULL) {
- dlclose(m->libc->sock_handle);
+ if (m->libc != NULL) {
+ 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);
}
- SAFE_FREE(m->libc);
/* backends */
- for (i = 0; i < m->num_backends; i++) {
- struct nwrap_backend *b = &(m->backends[i]);
+ if (m->backends != NULL) {
+ for (i = 0; i < m->num_backends; i++) {
+ struct nwrap_backend *b = &(m->backends[i]);
- if (b->so_handle != NULL) {
- dlclose(b->so_handle);
+ if (b->so_handle != NULL) {
+ dlclose(b->so_handle);
+ }
+ SAFE_FREE(b->fns);
}
- SAFE_FREE(b->fns);
+ SAFE_FREE(m->backends);
}
- SAFE_FREE(m->backends);
}
if (nwrap_pw_global.cache != NULL) {