diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/external.c | 19 | ||||
-rw-r--r-- | src/gss_auth.c | 14 | ||||
-rw-r--r-- | src/gss_ntlmssp.h | 8 | ||||
-rw-r--r-- | src/gss_ntlmssp_winbind.h | 8 | ||||
-rw-r--r-- | src/gss_sec_ctx.c | 3 | ||||
-rw-r--r-- | src/winbind.c | 100 |
6 files changed, 151 insertions, 1 deletions
diff --git a/src/external.c b/src/external.c index adf8e5e..4d04b71 100644 --- a/src/external.c +++ b/src/external.c @@ -27,6 +27,25 @@ uint32_t external_get_creds(struct gssntlm_name *name, #endif } +uint32_t external_cli_auth(char *user, char *domain, + gss_channel_bindings_t input_chan_bindings, + uint32_t in_flags, + uint32_t *neg_flags, + struct ntlm_buffer *nego_msg, + struct ntlm_buffer *chal_msg, + struct ntlm_buffer *auth_msg, + struct ntlm_key *exported_session_key) +{ +#if HAVE_WBCLIENT + return winbind_cli_auth(user, domain, input_chan_bindings, + in_flags, neg_flags, + nego_msg, chal_msg, auth_msg, + exported_session_key); +#else + return ENOSYS; +#endif +} + uint32_t external_srv_auth(char *user, char *domain, char *workstation, uint8_t *challenge, struct ntlm_buffer *nt_chal_resp, diff --git a/src/gss_auth.c b/src/gss_auth.c index 6103ba9..60f85a9 100644 --- a/src/gss_auth.c +++ b/src/gss_auth.c @@ -279,6 +279,20 @@ uint32_t gssntlm_cli_auth(uint32_t *minor, retmaj = GSS_S_COMPLETE; break; + case GSSNTLM_CRED_EXTERNAL: + retmin = external_cli_auth(cred->cred.external.user.data.user.name, + cred->cred.external.user.data.user.domain, + input_chan_bindings, in_flags, + &ctx->neg_flags, &ctx->nego_msg, + &ctx->chal_msg, &ctx->auth_msg, + &ctx->exported_session_key); + if (retmin) { + retmaj = GSS_S_FAILURE; + goto done; + } + retmaj = GSS_S_COMPLETE; + break; + default: retmin = EINVAL; retmaj = GSS_S_FAILURE; diff --git a/src/gss_ntlmssp.h b/src/gss_ntlmssp.h index 964483b..55e6570 100644 --- a/src/gss_ntlmssp.h +++ b/src/gss_ntlmssp.h @@ -173,6 +173,14 @@ int gssntlm_copy_creds(struct gssntlm_cred *in, struct gssntlm_cred *out); uint32_t external_netbios_get_names(char **computer, char **domain); uint32_t external_get_creds(struct gssntlm_name *name, struct gssntlm_cred *cred); +uint32_t external_cli_auth(char *user, char *domain, + gss_channel_bindings_t input_chan_bindings, + uint32_t in_flags, + uint32_t *neg_flags, + struct ntlm_buffer *nego_msg, + struct ntlm_buffer *chal_msg, + struct ntlm_buffer *auth_msg, + struct ntlm_key *exported_session_key); uint32_t external_srv_auth(char *user, char *domain, char *workstation, uint8_t *challenge, struct ntlm_buffer *nt_chal_resp, diff --git a/src/gss_ntlmssp_winbind.h b/src/gss_ntlmssp_winbind.h index b4e050e..acd1774 100644 --- a/src/gss_ntlmssp_winbind.h +++ b/src/gss_ntlmssp_winbind.h @@ -5,6 +5,14 @@ uint32_t winbind_get_names(char **computer, char **domain); uint32_t winbind_get_creds(struct gssntlm_name *name, struct gssntlm_cred *cred); +uint32_t winbind_cli_auth(char *user, char *domain, + gss_channel_bindings_t input_chan_bindings, + uint32_t in_flags, + uint32_t *neg_flags, + struct ntlm_buffer *nego_msg, + struct ntlm_buffer *chal_msg, + struct ntlm_buffer *auth_msg, + struct ntlm_key *exported_session_key); uint32_t winbind_srv_auth(char *user, char *domain, char *workstation, uint8_t *challenge, struct ntlm_buffer *nt_chal_resp, diff --git a/src/gss_sec_ctx.c b/src/gss_sec_ctx.c index 33e6aa0..05d352f 100644 --- a/src/gss_sec_ctx.c +++ b/src/gss_sec_ctx.c @@ -92,7 +92,8 @@ uint32_t gssntlm_init_sec_context(uint32_t *minor_status, } } else { cred = (struct gssntlm_cred *)claimant_cred_handle; - if (cred->type != GSSNTLM_CRED_USER) { + if (cred->type != GSSNTLM_CRED_USER && + cred->type != GSSNTLM_CRED_EXTERNAL) { retmin = EINVAL; retmaj = GSS_S_CRED_UNAVAIL; goto done; diff --git a/src/winbind.c b/src/winbind.c index 3469f81..b2f82d0 100644 --- a/src/winbind.c +++ b/src/winbind.c @@ -103,6 +103,106 @@ done: return ret; } +uint32_t winbind_cli_auth(char *user, char *domain, + gss_channel_bindings_t input_chan_bindings, + uint32_t in_flags, + uint32_t *neg_flags, + struct ntlm_buffer *nego_msg, + struct ntlm_buffer *chal_msg, + struct ntlm_buffer *auth_msg, + struct ntlm_key *exported_session_key) +{ + /* Get responses and session key from winbind */ + struct wbcCredentialCacheParams params; + struct wbcCredentialCacheInfo *result = NULL; + struct wbcNamedBlob *sesskey_blob = NULL; + struct wbcNamedBlob *auth_blob = NULL; + struct wire_auth_msg *w_auth_msg; + struct wire_chal_msg *w_chal_msg; + wbcErr wbc_status; + int ret = EINVAL; + int i; + + if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS) { + /* Winbind doesn't support this (yet). We'd want to pass our + * own client_target_info in with the request. */ + ret = EINVAL; + goto done; + } + + params.account_name = user; + params.domain_name= 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, + chal_msg->data, chal_msg->length); + if (!WBC_ERROR_IS_OK(wbc_status)) { + ret = ENOMEM; + goto done; + } + /* If we've masked out flags in in_flags, don't let + * winbind see them in the challenge */ + w_chal_msg = (struct wire_chal_msg *)params.blobs[0].blob.data; + w_chal_msg->neg_flags = htole32(in_flags); + + /* Put this in second. + * https://bugzilla.samba.org/show_bug.cgi?id=10692 */ + if (nego_msg->length) { + wbc_status = wbcAddNamedBlob(¶ms.num_blobs, ¶ms.blobs, + "initial_blob", 0, + nego_msg->data, nego_msg->length); + if (!WBC_ERROR_IS_OK(wbc_status)) { + ret = ENOMEM; + goto done; + } + } + + wbc_status = wbcCredentialCache(¶ms, &result, NULL); + if (!WBC_ERROR_IS_OK(wbc_status)) { + ret = ENOENT; + goto done; + } + for (i = 0; i < result->num_blobs; i++) { + if (strcmp(result->blobs[i].name, "auth_blob") == 0) { + auth_blob = &result->blobs[i]; + } else if (strcmp(result->blobs[i].name, "session_key") == 0) { + sesskey_blob = &result->blobs[i]; + } + } + + if (!auth_blob || auth_blob->blob.length < sizeof(*auth_msg) || + !sesskey_blob || sesskey_blob->blob.length != 16 ) { + ret = EIO; + goto done; + } + /* We need to 'correct' the flags in the auth message that + * winbind generates. In datagram mode they do matter. + * Winbind leaves out the DATAGRAM and SEAL flags, amongst + * others. Thankfully winbind also doesn't support MIC so + * we can tamper as much as we like... */ + w_auth_msg = (struct wire_auth_msg *)auth_blob->blob.data; + *neg_flags |= in_flags; + w_auth_msg->neg_flags = htole32(*neg_flags); + + auth_msg->length = auth_blob->blob.length; + auth_msg->data = auth_blob->blob.data; + auth_blob->blob.data = NULL; + + exported_session_key->length = sesskey_blob->blob.length; + memcpy(exported_session_key->data, sesskey_blob->blob.data, + sesskey_blob->blob.length); + + ret = 0; + +done: + wbcFreeMemory(params.blobs); + wbcFreeMemory(result); + return ret; +} + uint32_t winbind_srv_auth(char *user, char *domain, char *workstation, uint8_t *challenge, struct ntlm_buffer *nt_chal_resp, |