Skip to content

Commit d55c0e5

Browse files
committed
Use thread local storage for winbind context
This allow multiple calls into winbindd from parallel threads without suffering from a common mutex that serializaes all authentications. The price to pay is that a new context is allocated for each thread, and the way windbind works, this probably mean a separate file descriptor is created for each of this thread on the application side (winbindd will be ok as it will kick idle connections). The users of gssntlmssp in a multi-threaded environment will need to be careful to limit the number of threads they allow to use gssapi in this case. Signed-off-by: Simo Sorce <[email protected]>
1 parent 7949fa8 commit d55c0e5

File tree

1 file changed

+87
-5
lines changed

1 file changed

+87
-5
lines changed

src/winbind.c

Lines changed: 87 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,74 @@
99

1010
#include <wbclient.h>
1111

12+
#ifdef HAVE_PTHREAD
13+
#include <pthread.h>
14+
15+
static pthread_key_t key;
16+
static pthread_once_t key_once = PTHREAD_ONCE_INIT;
17+
18+
/* note that the destructor is given directly the content of the key in
19+
* ptr, not the key itself. */
20+
static void key_destructor(void *ptr)
21+
{
22+
wbcCtxFree((struct wbcContext *)ptr);
23+
}
24+
25+
static void key_create(void)
26+
{
27+
/* we have no way to report errors ... */
28+
(void)pthread_key_create(&key, key_destructor);
29+
}
30+
31+
static struct wbcContext *winbind_get_context(void)
32+
{
33+
struct wbcContext *ctx;
34+
int ret;
35+
36+
ret = pthread_once(&key_once, key_create);
37+
if (ret != 0) {
38+
return NULL;
39+
}
40+
ctx = pthread_getspecific(key);
41+
if (ctx == NULL) {
42+
ctx = wbcCtxCreate();
43+
ret = pthread_setspecific(key, ctx);
44+
if (ret != 0) {
45+
wbcCtxFree(ctx);
46+
ctx = NULL;
47+
}
48+
}
49+
return ctx;
50+
}
51+
52+
#else /* HAVE_PTHREAD */
53+
54+
/* non thread-safe version */
55+
static struct wbcContext *gctx = NULL;
56+
57+
static struct wbcContext *winbind_get_context(void)
58+
{
59+
if (gctx == NULL) {
60+
gctx = wbcCtxCreate();
61+
}
62+
return gctx;
63+
}
64+
#endif /* HAVE_PTHREAD */
65+
1266
uint32_t winbind_get_names(char **computer, char **domain)
1367
{
68+
struct wbcContext *ctx;
1469
struct wbcInterfaceDetails *details = NULL;
1570
wbcErr wbc_status;
1671
int ret = ERR_NOTAVAIL;
1772

18-
wbc_status = wbcInterfaceDetails(&details);
73+
ctx = winbind_get_context();
74+
if (ctx == NULL) {
75+
ret = ERR_BADCTX;
76+
goto done;
77+
}
78+
79+
wbc_status = wbcCtxInterfaceDetails(ctx, &details);
1980
if (!WBC_ERROR_IS_OK(wbc_status)) goto done;
2081

2182
if (computer &&
@@ -51,17 +112,24 @@ uint32_t winbind_get_names(char **computer, char **domain)
51112
uint32_t winbind_get_creds(struct gssntlm_name *name,
52113
struct gssntlm_cred *cred)
53114
{
115+
struct wbcContext *ctx;
54116
struct wbcCredentialCacheParams params;
55117
struct wbcCredentialCacheInfo *result;
56118
struct wbcInterfaceDetails *details = NULL;
57119
wbcErr wbc_status;
58120
bool cached = false;
59121
int ret = ERR_NOTAVAIL;
60122

123+
ctx = winbind_get_context();
124+
if (ctx == NULL) {
125+
ret = ERR_BADCTX;
126+
goto done;
127+
}
128+
61129
if (name && name->data.user.domain) {
62130
params.domain_name = name->data.user.domain;
63131
} else {
64-
wbc_status = wbcInterfaceDetails(&details);
132+
wbc_status = wbcCtxInterfaceDetails(ctx, &details);
65133
if (!WBC_ERROR_IS_OK(wbc_status)) goto done;
66134

67135
params.domain_name = details->netbios_domain;
@@ -80,7 +148,7 @@ uint32_t winbind_get_creds(struct gssntlm_name *name,
80148
params.level = WBC_CREDENTIAL_CACHE_LEVEL_NTLMSSP;
81149
params.num_blobs = 0;
82150
params.blobs = NULL;
83-
wbc_status = wbcCredentialCache(&params, &result, NULL);
151+
wbc_status = wbcCtxCredentialCache(ctx, &params, &result, NULL);
84152

85153
if (WBC_ERROR_IS_OK(wbc_status)) {
86154
/* Yes, winbind seems to think it has credentials for us */
@@ -120,6 +188,7 @@ uint32_t winbind_cli_auth(char *user, char *domain,
120188
struct ntlm_key *exported_session_key)
121189
{
122190
/* Get responses and session key from winbind */
191+
struct wbcContext *ctx;
123192
struct wbcCredentialCacheParams params;
124193
struct wbcCredentialCacheInfo *result = NULL;
125194
struct wbcNamedBlob *sesskey_blob = NULL;
@@ -130,6 +199,12 @@ uint32_t winbind_cli_auth(char *user, char *domain,
130199
int ret;
131200
int i;
132201

202+
ctx = winbind_get_context();
203+
if (ctx == NULL) {
204+
ret = ERR_BADCTX;
205+
goto done;
206+
}
207+
133208
if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS) {
134209
/* Winbind doesn't support this (yet). We'd want to pass our
135210
* own client_target_info in with the request. */
@@ -167,7 +242,7 @@ uint32_t winbind_cli_auth(char *user, char *domain,
167242
}
168243
}
169244

170-
wbc_status = wbcCredentialCache(&params, &result, NULL);
245+
wbc_status = wbcCtxCredentialCache(ctx, &params, &result, NULL);
171246
if (!WBC_ERROR_IS_OK(wbc_status)) {
172247
ret = ERR_NOTAVAIL;
173248
goto done;
@@ -295,6 +370,7 @@ uint32_t winbind_srv_auth(char *user, char *domain,
295370
struct ntlm_key *ntlmv2_key,
296371
struct gssntlm_name_attribute **auth_attrs)
297372
{
373+
struct wbcContext *ctx;
298374
struct wbcAuthUserParams wbc_params = { 0 };
299375
struct wbcAuthUserInfo *wbc_info = NULL;
300376
struct wbcAuthErrorInfo *wbc_err = NULL;
@@ -306,6 +382,11 @@ uint32_t winbind_srv_auth(char *user, char *domain,
306382
return ERR_KEYLEN;
307383
}
308384

385+
ctx = winbind_get_context();
386+
if (ctx == NULL) {
387+
return ERR_BADCTX;
388+
}
389+
309390
wbc_params.account_name = user;
310391
wbc_params.domain_name = domain;
311392
wbc_params.workstation_name = workstation;
@@ -320,7 +401,8 @@ uint32_t winbind_srv_auth(char *user, char *domain,
320401
wbc_params.password.response.lm_length = lm_chal_resp->length;
321402
wbc_params.password.response.lm_data = lm_chal_resp->data;
322403

323-
wbc_status = wbcAuthenticateUserEx(&wbc_params, &wbc_info, &wbc_err);
404+
wbc_status = wbcCtxAuthenticateUserEx(ctx, &wbc_params, &wbc_info,
405+
&wbc_err);
324406

325407
if (!WBC_ERROR_IS_OK(wbc_status)) {
326408
/* TODO: use wbcErrorString, to save error message */

0 commit comments

Comments
 (0)