diff --git a/src/gss_creds.c b/src/gss_creds.c
index e4c759a..180b959 100644
--- a/src/gss_creds.c
+++ b/src/gss_creds.c
@@ -15,6 +15,8 @@
License along with this library; if not, see .
*/
+#include
+
#include
#include
#include
@@ -25,6 +27,65 @@
#include "gss_ntlmssp.h"
+#ifdef HAVE_WBCLIENT
+#include
+
+int get_wbclient_creds(struct gssntlm_name *name,
+ struct gssntlm_cred *cred)
+{
+ struct wbcCredentialCacheParams params;
+ struct wbcCredentialCacheInfo *result;
+ struct wbcInterfaceDetails *details = NULL;
+ wbcErr wbc_status;
+ int ret = ENOENT;
+
+ if (name && name->data.user.domain)
+ params.domain_name = name->data.user.domain;
+ else {
+ wbc_status = wbcInterfaceDetails(&details);
+ if (!WBC_ERROR_IS_OK(wbc_status))
+ goto out;
+ params.domain_name = details->netbios_domain;
+ }
+ if (name && name->data.user.name)
+ params.account_name = name->data.user.name;
+ else {
+ params.account_name = getenv("NTLMUSER");
+ if (!params.account_name)
+ params.account_name = getenv("USER");
+ if (!params.account_name)
+ goto out;
+ }
+
+ params.level = WBC_CREDENTIAL_CACHE_LEVEL_NTLMSSP;
+ params.num_blobs = 0;
+ params.blobs = NULL;
+ wbc_status = wbcCredentialCache(¶ms, &result, NULL);
+
+ if(!WBC_ERROR_IS_OK(wbc_status))
+ goto out;
+
+ /* Yes, winbind seems to think it has credentials for us */
+ wbcFreeMemory(result);
+
+ cred->type = GSSNTLM_CRED_USER;
+ cred->cred.user.user.type = GSSNTLM_NAME_USER;
+ cred->cred.user.user.data.user.domain = strdup(params.domain_name);
+ if (!cred->cred.user.user.data.user.domain) return ENOMEM;
+ cred->cred.user.user.data.user.name = strdup(params.account_name);
+ if (!cred->cred.user.user.data.user.name) return ENOMEM;
+
+ /* Use length == 0 to indicate that we're using winbind */
+ cred->cred.user.nt_hash.length = 0;
+ cred->cred.user.lm_hash.length = 0;
+ ret = 0;
+ out:
+ if (details)
+ wbcFreeMemory(details);
+ return ret;
+}
+#endif
+
static int get_user_file_creds(struct gssntlm_name *name,
struct gssntlm_cred *cred)
{
@@ -325,6 +386,10 @@ uint32_t gssntlm_acquire_cred_from(uint32_t *minor_status,
retmin = get_creds_from_store(name, cred, cred_store);
} else {
retmin = get_user_file_creds(name, cred);
+#ifdef HAVE_WBCLIENT
+ if (retmin)
+ retmin = get_wbclient_creds(name, cred);
+#endif
}
if (retmin) {
retmaj = GSS_S_CRED_UNAVAIL;
diff --git a/src/gss_sec_ctx.c b/src/gss_sec_ctx.c
index 4dbccc2..f369210 100644
--- a/src/gss_sec_ctx.c
+++ b/src/gss_sec_ctx.c
@@ -15,6 +15,8 @@
License along with this library; if not, see .
*/
+#include "config.h"
+
#include
#include
#include
@@ -24,6 +26,11 @@
#include "gssapi_ntlmssp.h"
#include "gss_ntlmssp.h"
+#ifdef HAVE_WBCLIENT
+#include
+#endif
+
+#include
uint32_t gssntlm_init_sec_context(uint32_t *minor_status,
gss_cred_id_t claimant_cred_handle,
@@ -414,6 +421,72 @@ uint32_t gssntlm_init_sec_context(uint32_t *minor_status,
lm_chal_resp.data[0] = 0;
lm_chal_resp.length = 1;
+#ifdef HAVE_WBCLIENT
+ } else if (!cred->cred.user.nt_hash.length) {
+ /* Get responses and session key from winbind */
+ struct wbcCredentialCacheParams params;
+ struct wbcCredentialCacheInfo *result = NULL;
+ struct wbcNamedBlob *auth_blob = NULL, *sesskey_blob = NULL;
+ struct wire_auth_msg *msg;
+ wbcErr wbc_status;
+ int i;
+
+ params.account_name = cred->cred.user.user.data.user.name;
+ params.domain_name= cred->cred.user.user.data.user.domain;
+ params.level = WBC_CREDENTIAL_CACHE_LEVEL_NTLMSSP;
+ params.num_blobs = 0;
+ params.blobs = NULL;
+
+ wbc_status = wbcAddNamedBlob(¶ms.num_blobs, ¶ms.blobs, "challenge_blob", 0,
+ input_token->value, input_token->length);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ retmin = ENOMEM;
+ goto wbcfail;
+ }
+ /* Put this in second. https://bugzilla.samba.org/show_bug.cgi?id=10692 */
+ if (ctx->nego_msg.length) {
+ wbc_status = wbcAddNamedBlob(¶ms.num_blobs, ¶ms.blobs, "initial_blob", 0,
+ ctx->nego_msg.data, ctx->nego_msg.length);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ retmin = ENOMEM;
+ goto wbcfail;
+ }
+ }
+ wbc_status = wbcCredentialCache(¶ms, &result, NULL);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ retmin = ENOENT; /* XXX: Attempt to convert meaningfully? */
+ goto wbcfail;
+ }
+ for (i=0; i < result->num_blobs; i++) {
+ if (!strcmp(result->blobs[i].name, "auth_blob"))
+ auth_blob = &result->blobs[i];
+ else if (!strcmp(result->blobs[i].name, "session_key"))
+ sesskey_blob = &result->blobs[i];
+ }
+
+ if (!auth_blob || auth_blob->blob.length < sizeof(*msg) ||
+ !sesskey_blob || sesskey_blob->blob.length != 16 ) {
+ retmin = EIO;
+ wbcfail:
+ retmaj = GSS_S_FAILURE;
+ wbcFreeMemory(params.blobs);
+ wbcFreeMemory(result);
+ goto done;
+ }
+
+ ctx->auth_msg.length = auth_blob->blob.length;
+ ctx->auth_msg.data = auth_blob->blob.data;
+ auth_blob->blob.data = NULL;
+
+ ctx->exported_session_key.length = sesskey_blob->blob.length;
+ memcpy(ctx->exported_session_key.data, sesskey_blob->blob.data, sesskey_blob->blob.length);
+
+ /* XXX: Check in_flags against what winbind actually put in the response? */
+ wbcFreeMemory(params.blobs);
+ wbcFreeMemory(result);
+
+ goto ntlmssp_done;
+#endif
} else if (sec_req & SEC_V2_ONLY) {
/* ### NTLMv2 ### */
@@ -610,30 +683,9 @@ uint32_t gssntlm_init_sec_context(uint32_t *minor_status,
}
}
- if (protect) {
- retmin = ntlm_signseal_keys(in_flags, true,
- &ctx->exported_session_key,
- &ctx->send.sign_key,
- &ctx->recv.sign_key,
- &ctx->send.seal_key,
- &ctx->recv.seal_key,
- &ctx->send.seal_handle,
- &ctx->recv.seal_handle);
- if (retmin) {
- retmaj = GSS_S_FAILURE;
- goto done;
- }
- }
-
/* in_flags all verified, assign as current flags */
ctx->neg_flags |= in_flags;
- if (ctx->neg_flags & NTLMSSP_NEGOTIATE_SIGN) {
- ctx->gss_flags |= GSS_C_INTEG_FLAG;
- }
- if (ctx->neg_flags & NTLMSSP_NEGOTIATE_SEAL) {
- ctx->gss_flags |= GSS_C_CONF_FLAG & GSS_C_INTEG_FLAG;
- }
enc_sess_key.data = encrypted_random_session_key.data;
enc_sess_key.length = encrypted_random_session_key.length;
@@ -667,6 +719,28 @@ uint32_t gssntlm_init_sec_context(uint32_t *minor_status,
/* Make sure SPNEGO gets to know it has to add mechlistMIC too */
ctx->int_flags |= NTLMSSP_CTX_FLAG_AUTH_WITH_MIC;
}
+ ntlmssp_done:
+ if (protect) {
+ retmin = ntlm_signseal_keys(in_flags, true,
+ &ctx->exported_session_key,
+ &ctx->send.sign_key,
+ &ctx->recv.sign_key,
+ &ctx->send.seal_key,
+ &ctx->recv.seal_key,
+ &ctx->send.seal_handle,
+ &ctx->recv.seal_handle);
+ if (retmin) {
+ retmaj = GSS_S_FAILURE;
+ goto done;
+ }
+ }
+
+ if (ctx->neg_flags & NTLMSSP_NEGOTIATE_SIGN) {
+ ctx->gss_flags |= GSS_C_INTEG_FLAG;
+ }
+ if (ctx->neg_flags & NTLMSSP_NEGOTIATE_SEAL) {
+ ctx->gss_flags |= GSS_C_CONF_FLAG & GSS_C_INTEG_FLAG;
+ }
ctx->stage = NTLMSSP_STAGE_DONE;