Skip to content

Instantly share code, notes, and snippets.

@mcnewton
Created January 23, 2015 00:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mcnewton/b9d4e9f43020243dcacf to your computer and use it in GitHub Desktop.
Save mcnewton/b9d4e9f43020243dcacf to your computer and use it in GitHub Desktop.
Patch against Samba v3-6-stable to make libwbclient thread-safe
From 96c6263840943cc84ba78d9d5ae95e7fa08daa5c Mon Sep 17 00:00:00 2001
From: Matthew Newton <mcn4@leicester.ac.uk>
Date: Thu, 22 Jan 2015 23:47:08 +0000
Subject: [PATCH] libwbclient thread safe for samba 3.6
This version is good enough for FreeRADIUS auth, but won't clean up if
the library is dlclose()'d and will leak memory in that case, so not
suitable for merging.
---
nsswitch/wb_common.c | 153 ++++++++++++++++++++++++++++++++++++---------
nsswitch/winbind_client.h | 7 +++
source3/Makefile.in | 4 +-
3 files changed, 134 insertions(+), 30 deletions(-)
diff --git a/nsswitch/wb_common.c b/nsswitch/wb_common.c
index 3ba2bb5..a0ab666 100644
--- a/nsswitch/wb_common.c
+++ b/nsswitch/wb_common.c
@@ -26,10 +26,79 @@
#include "system/select.h"
#include "winbind_client.h"
-/* Global variables. These are effectively the client state information */
+/*
+ Client state - how this is stored depends on whether pthreads is
+ available. When multithreaded, these values should not be shared
+ amongst different threads.
+*/
+
+#ifdef HAVE_PTHREAD
+
+#include <pthread.h>
+
+static pthread_once_t thread_storage_once = PTHREAD_ONCE_INIT;
+static pthread_key_t winbindd_fd_info_key;
+
+static void winbindd_fd_info_destructor(void *ptr)
+{
+ struct fd_info_s *fd_info = ptr;
+
+ if (fd_info != NULL) {
+ if (fd_info->winbindd_fd != -1) {
+ close(fd_info->winbindd_fd);
+ }
+
+ free(fd_info);
+ }
+
+ pthread_setspecific(winbindd_fd_info_key, NULL);
+}
+
+static void init_thread_storage(void)
+{
+ pthread_key_create(&winbindd_fd_info_key, winbindd_fd_info_destructor);
+}
+
+/* Return pointer to file descriptor info from thread local storage */
+
+struct fd_info_s *winbindd_fd_info(void)
+{
+ struct fd_info_s *fd_info;
+
+ pthread_once(&thread_storage_once, init_thread_storage);
+
+ fd_info = pthread_getspecific(winbindd_fd_info_key);
+
+ if (fd_info == NULL) {
+ fd_info = malloc(sizeof(struct fd_info_s));
+
+ if (fd_info == NULL) {
+ return NULL;
+ }
+
+ pthread_setspecific(winbindd_fd_info_key, fd_info);
+
+ fd_info->winbindd_fd = -1;
+ fd_info->is_privileged = 0;
+ }
+ return fd_info;
+}
+
+#else
+
+/* If compiled without pthread support then use global variables. */
+
+struct fd_info_s fd_info_global = { .winbindd_fd = -1, .is_privileged = 0 };
+
+/* Return pointer to fd_info struct */
+
+struct fd_info_s *winbindd_fd_info(void)
+{
+ return &fd_info_global;
+}
+
+#endif
-int winbindd_fd = -1; /* fd for winbindd socket */
-static int is_privileged = 0;
/* Free a response structure */
@@ -65,13 +134,23 @@ static void init_response(struct winbindd_response *response)
/* Close established socket */
#if HAVE_FUNCTION_ATTRIBUTE_DESTRUCTOR
+#ifndef HAVE_PTHREAD
__attribute__((destructor))
#endif
+#endif
static void winbind_close_sock(void)
{
- if (winbindd_fd != -1) {
- close(winbindd_fd);
- winbindd_fd = -1;
+ struct fd_info_s *fd_info;
+
+ fd_info = winbindd_fd_info();
+
+ if (fd_info == NULL) {
+ return;
+ }
+
+ if (fd_info->winbindd_fd != -1) {
+ close(fd_info->winbindd_fd);
+ fd_info->winbindd_fd = -1;
}
}
@@ -306,31 +385,41 @@ static int winbind_open_pipe_sock(int recursing, int need_priv)
static pid_t our_pid;
struct winbindd_request request;
struct winbindd_response response;
+ struct fd_info_s *fd_info;
+
ZERO_STRUCT(request);
ZERO_STRUCT(response);
+ fd_info = winbindd_fd_info();
+
+ if (fd_info == NULL) {
+ return -1;
+ }
+
if (our_pid != getpid()) {
winbind_close_sock();
our_pid = getpid();
}
- if ((need_priv != 0) && (is_privileged == 0)) {
+ if ((need_priv != 0) && (fd_info->is_privileged == 0)) {
winbind_close_sock();
}
- if (winbindd_fd != -1) {
- return winbindd_fd;
+ if (fd_info->winbindd_fd != -1) {
+ return fd_info->winbindd_fd;
}
if (recursing) {
return -1;
}
- if ((winbindd_fd = winbind_named_pipe_sock(winbindd_socket_dir())) == -1) {
+ fd_info->winbindd_fd = winbind_named_pipe_sock(winbindd_socket_dir());
+
+ if (fd_info->winbindd_fd == -1) {
return -1;
}
- is_privileged = 0;
+ fd_info->is_privileged = 0;
/* version-check the socket */
@@ -345,20 +434,23 @@ static int winbind_open_pipe_sock(int recursing, int need_priv)
request.wb_flags = WBFLAG_RECURSE;
if (winbindd_request_response(WINBINDD_PRIV_PIPE_DIR, &request, &response) == NSS_STATUS_SUCCESS) {
int fd;
- if ((fd = winbind_named_pipe_sock((char *)response.extra_data.data)) != -1) {
- close(winbindd_fd);
- winbindd_fd = fd;
- is_privileged = 1;
+
+ fd = winbind_named_pipe_sock((char *)response.extra_data.data);
+
+ if (fd != -1) {
+ close(fd_info->winbindd_fd);
+ fd_info->winbindd_fd = fd;
+ fd_info->is_privileged = 1;
}
}
- if ((need_priv != 0) && (is_privileged == 0)) {
+ if ((need_priv != 0) && (fd_info->is_privileged == 0)) {
return -1;
}
SAFE_FREE(response.extra_data.data);
- return winbindd_fd;
+ return fd_info->winbindd_fd;
#else
return -1;
#endif /* HAVE_UNIXSOCKET */
@@ -370,12 +462,14 @@ static int winbind_write_sock(void *buffer, int count, int recursing,
int need_priv)
{
int result, nwritten;
+ int fd;
/* Open connection to winbind daemon */
restart:
- if (winbind_open_pipe_sock(recursing, need_priv) == -1) {
+ fd = winbind_open_pipe_sock(recursing, need_priv);
+ if (fd == -1) {
errno = ENOENT;
return -1;
}
@@ -412,7 +506,7 @@ static int winbind_write_sock(void *buffer, int count, int recursing,
/* Do the write */
- result = write(winbindd_fd,
+ result = write(fd,
(char *)buffer + nwritten,
count - nwritten);
@@ -436,8 +530,10 @@ static int winbind_read_sock(void *buffer, int count)
{
int nread = 0;
int total_time = 0;
+ int fd;
- if (winbindd_fd == -1) {
+ fd = winbind_open_pipe_sock(false, false);
+ if (fd == -1) {
return -1;
}
@@ -449,7 +545,7 @@ static int winbind_read_sock(void *buffer, int count)
/* Catch pipe close on other end by checking if a read()
call would not block by calling poll(). */
- pfd.fd = winbindd_fd;
+ pfd.fd = fd;
pfd.events = POLLIN|POLLHUP;
/* Wait for 5 seconds for a reply. May need to parameterise this... */
@@ -475,7 +571,7 @@ static int winbind_read_sock(void *buffer, int count)
/* Do the Read */
- int result = read(winbindd_fd, (char *)buffer + nread,
+ int result = read(fd, (char *)buffer + nread,
count - nread);
if ((result == -1) || (result == 0)) {
@@ -510,6 +606,13 @@ static int winbindd_read_reply(struct winbindd_response *response)
result1 = winbind_read_sock(response,
sizeof(struct winbindd_response));
+
+ /* We actually send the pointer value of the extra_data field from
+ the server. This has no meaning in the client's address space
+ so we clear it out. */
+
+ response->extra_data.data = NULL;
+
if (result1 == -1) {
return -1;
}
@@ -518,12 +621,6 @@ static int winbindd_read_reply(struct winbindd_response *response)
return -1;
}
- /* We actually send the pointer value of the extra_data field from
- the server. This has no meaning in the client's address space
- so we clear it out. */
-
- response->extra_data.data = NULL;
-
/* Read variable length response */
if (response->length > sizeof(struct winbindd_response)) {
diff --git a/nsswitch/winbind_client.h b/nsswitch/winbind_client.h
index 905a189..cb9a08c 100644
--- a/nsswitch/winbind_client.h
+++ b/nsswitch/winbind_client.h
@@ -47,4 +47,11 @@ NSS_STATUS winbindd_priv_request_response(int req_type,
#define winbind_on() \
(setenv(WINBINDD_DONT_ENV, "0", 1) == 0)
+/* winbind file descriptor and privileged flag */
+
+struct fd_info_s {
+ int winbindd_fd;
+ int is_privileged;
+};
+
#endif /* _NSSWITCH_WINBIND_CLIENT_H_ */
diff --git a/source3/Makefile.in b/source3/Makefile.in
index 9e8e03d..998b689 100644
--- a/source3/Makefile.in
+++ b/source3/Makefile.in
@@ -73,7 +73,7 @@ LDAP_LIBS=@LDAP_LIBS@
NSCD_LIBS=@NSCD_LIBS@
UUID_LIBS=@UUID_LIBS@
LIBWBCLIENT=@LIBWBCLIENT_STATIC@ @LIBWBCLIENT_SHARED@
-LIBWBCLIENT_LIBS=@LIBWBCLIENT_LIBS@
+LIBWBCLIENT_LIBS=@LIBWBCLIENT_LIBS@ -lpthread
PTHREAD_LDFLAGS=@PTHREAD_LDFLAGS@
PTHREAD_CFLAGS=@PTHREAD_CFLAGS@
DNSSD_LIBS=@DNSSD_LIBS@
@@ -2325,7 +2325,7 @@ $(LIBWBCLIENT_SYMS): $(LIBWBCLIENT_HEADERS)
$(LIBWBCLIENT_SHARED_TARGET_SONAME): $(BINARY_PREREQS) $(LIBWBCLIENT_OBJ) $(LIBWBCLIENT_SYMS)
@echo Linking shared library $@
@$(SHLD_DSO) $(LIBWBCLIENT_OBJ) $(LIBREPLACE_LIBS) \
- @SONAMEFLAG@`basename $@`
+ @SONAMEFLAG@`basename $@` -lpthread
$(LIBWBCLIENT_SHARED_TARGET): $(LIBWBCLIENT_SHARED_TARGET_SONAME)
@rm -f $@
--
1.7.10.4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment