summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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,