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;