summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimo Sorce <simo@redhat.com>2014-08-04 18:06:58 -0400
committerSimo Sorce <simo@redhat.com>2014-08-07 12:44:46 -0400
commit5ac987ad3b18a551a86116791445824bbd82c4e2 (patch)
treea41a841e2bcb096a62beec570c29cc78ae777551
parent78cb0a7bf31554d90eccfe626ba3e2b4c6b2893a (diff)
downloadgss-ntlmssp-5ac987ad3b18a551a86116791445824bbd82c4e2.tar.gz
gss-ntlmssp-5ac987ad3b18a551a86116791445824bbd82c4e2.tar.xz
gss-ntlmssp-5ac987ad3b18a551a86116791445824bbd82c4e2.zip
Support client authentication using Winbind
Based on a patch by David Woodhouse <David.Woodhouse@intel.com> Original commit message: We need to screw around with the flags a little, since winbind doesn't really get it right. Thankfully, it doesn't support MIC and it does at least generally do the right thing (w.r.t. session negotiation and OEM vs. Unicode) so it's sufficient just to screw with the flags. Tested with Negotiate authentication to squid, and NTLM in datagram mode with pidgin-sipe. Also with Firefox, Chrome and a fixed libcurl.
-rw-r--r--src/external.c19
-rw-r--r--src/gss_auth.c14
-rw-r--r--src/gss_ntlmssp.h8
-rw-r--r--src/gss_ntlmssp_winbind.h8
-rw-r--r--src/gss_sec_ctx.c3
-rw-r--r--src/winbind.c100
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(&params.num_blobs, &params.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(&params.num_blobs, &params.blobs,
+ "initial_blob", 0,
+ nego_msg->data, nego_msg->length);
+ if (!WBC_ERROR_IS_OK(wbc_status)) {
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+
+ wbc_status = wbcCredentialCache(&params, &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,