>From 7377401c17ebeb43812b0be55cb48622fbae4e82 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Mon, 9 May 2011 11:33:41 -0400 Subject: [PATCH] s3-gse: Use gss_get_name_attribute to fetch the pac This is the only way to be sure the pac signatures are correct. It requires a fairly new version of MIT Kerberos, but that should be fine, it is new functionality in 3.6 anyways. --- source3/configure.in | 1 + source3/librpc/crypto/gse.c | 74 ++++++++++++++++++++++++------------ source3/librpc/crypto/gse.h | 3 +- source3/rpc_server/dcesrv_gssapi.c | 42 +-------------------- 4 files changed, 53 insertions(+), 67 deletions(-) diff --git a/source3/configure.in b/source3/configure.in index d8c59b675bd0793181e683da813b39a5ccd1043e..72568d838f2b751e566dd4c8f09bdbdea0b240d4 100644 --- a/source3/configure.in +++ b/source3/configure.in @@ -3860,6 +3860,7 @@ if test x"$with_ads_support" != x"no"; then AC_CHECK_FUNC_EXT(krb5_get_credentials_for_user, $KRB5_LIBS) AC_CHECK_FUNC_EXT(krb5_get_host_realm, $KRB5_LIBS) AC_CHECK_FUNC_EXT(krb5_free_host_realm, $KRB5_LIBS) + AC_CHECK_FUNC_EXT(gss_get_name_attribute, $KRB5_LIBS) # MIT krb5 1.8 does not expose this call (yet) AC_CHECK_DECLS(krb5_get_credentials_for_user, [], [], [#include ]) diff --git a/source3/librpc/crypto/gse.c b/source3/librpc/crypto/gse.c index 064ccda2eb1d3cf222ce6f9462f77452c4c5a371..335dc1c53f149fb08af44e7d753c99149a02d961 100644 --- a/source3/librpc/crypto/gse.c +++ b/source3/librpc/crypto/gse.c @@ -22,7 +22,10 @@ #include "includes.h" #include "gse.h" -#if defined(HAVE_KRB5) && defined(HAVE_GSSAPI_GSSAPI_EXT_H) && defined(HAVE_GSS_WRAP_IOV) +#if defined(HAVE_KRB5) \ + && defined(HAVE_GSSAPI_GSSAPI_EXT_H) \ + && defined(HAVE_GSS_WRAP_IOV) \ + && defined(HAVE_GSS_GET_NAME_ATTRIBUTE) #include "smb_krb5.h" #include "gse_krb5.h" @@ -681,42 +684,62 @@ NTSTATUS gse_get_authz_data(struct gse_context *gse_ctx, return NT_STATUS_OK; } -NTSTATUS gse_get_authtime(struct gse_context *gse_ctx, time_t *authtime) +NTSTATUS gse_get_pac_blob(struct gse_context *gse_ctx, + TALLOC_CTX *mem_ctx, DATA_BLOB *pac_blob) { OM_uint32 gss_min, gss_maj; - gss_buffer_set_t set = GSS_C_NO_BUFFER_SET; - int32_t tkttime; + gss_buffer_desc pac_buffer; + gss_buffer_desc pac_display_buffer; + gss_buffer_desc pac_name = { + .value = discard_const_p(char, "urn:mspac:"), + .length = sizeof("urn:mspac:") - 1 + }; + int more = -1; + int authenticated = false; + int complete = false; + NTSTATUS status; if (!gse_ctx->authenticated) { return NT_STATUS_ACCESS_DENIED; } - gss_maj = gss_inquire_sec_context_by_oid( - &gss_min, gse_ctx->gss_ctx, - &gse_authtime_oid, &set); - if (gss_maj) { - DEBUG(0, ("gss_inquire_sec_context_by_oid failed [%s]\n", - gse_errstr(talloc_tos(), gss_maj, gss_min))); - return NT_STATUS_NOT_FOUND; - } + gss_maj = gss_get_name_attribute(&gss_min, + gse_ctx->client_name, &pac_name, + &authenticated, &complete, + &pac_buffer, &pac_display_buffer, + &more); - if ((set == GSS_C_NO_BUFFER_SET) || (set->count != 1) != 0) { - DEBUG(0, ("gss_inquire_sec_context_by_oid returned unknown " - "data in results.\n")); - return NT_STATUS_INTERNAL_ERROR; + if (gss_maj != 0) { + DEBUG(0, ("obtaining PAC via GSSAPI gss_get_name_attribute " + "failed: %s\n", + gse_errstr(mem_ctx, gss_maj, gss_min))); + return NT_STATUS_ACCESS_DENIED; } - if (set->elements[0].length != sizeof(int32_t)) { - DEBUG(0, ("Invalid authtime size!\n")); - return NT_STATUS_INTERNAL_ERROR; - } + if (authenticated && complete) { + /* The PAC blob is returned directly */ + *pac_blob = data_blob_talloc(mem_ctx, + pac_buffer.value, + pac_buffer.length); + if (!pac_blob->data) { + status = NT_STATUS_NO_MEMORY; + } else { + status = NT_STATUS_OK; + } - tkttime = *((int32_t *)set->elements[0].value); + gss_maj = gss_release_buffer(&gss_min, &pac_buffer); + gss_maj = gss_release_buffer(&gss_min, &pac_display_buffer); + + return status; + } - gss_maj = gss_release_buffer_set(&gss_min, &set); + DEBUG(0, ("obtaining PAC via GSSAPI failed: authenticated: %s, " + "complete: %s, more: %s\n", + authenticated ? "true" : "false", + complete ? "true" : "false", + more ? "true" : "false")); - *authtime = (time_t)tkttime; - return NT_STATUS_OK; + return NT_STATUS_ACCESS_DENIED; } size_t gse_get_signature_length(struct gse_context *gse_ctx, @@ -972,7 +995,8 @@ NTSTATUS gse_get_authz_data(struct gse_context *gse_ctx, return NT_STATUS_NOT_IMPLEMENTED; } -NTSTATUS gse_get_authtime(struct gse_context *gse_ctx, time_t *authtime) +NTSTATUS gse_get_pac_blob(struct gse_context *gse_ctx, + TALLOC_CTX *mem_ctx, DATA_BLOB *pac) { return NT_STATUS_NOT_IMPLEMENTED; } diff --git a/source3/librpc/crypto/gse.h b/source3/librpc/crypto/gse.h index a6d9a35a7ffdaf0c913e10625f78d0eedda4e931..d9e4a82e0ee3d62f0fd942d66d2fccf3badf8f39 100644 --- a/source3/librpc/crypto/gse.h +++ b/source3/librpc/crypto/gse.h @@ -57,7 +57,8 @@ NTSTATUS gse_get_client_name(struct gse_context *gse_ctx, TALLOC_CTX *mem_ctx, char **client_name); NTSTATUS gse_get_authz_data(struct gse_context *gse_ctx, TALLOC_CTX *mem_ctx, DATA_BLOB *pac); -NTSTATUS gse_get_authtime(struct gse_context *gse_ctx, time_t *authtime); +NTSTATUS gse_get_pac_blob(struct gse_context *gse_ctx, + TALLOC_CTX *mem_ctx, DATA_BLOB *pac); size_t gse_get_signature_length(struct gse_context *gse_ctx, int seal, size_t payload_size); diff --git a/source3/rpc_server/dcesrv_gssapi.c b/source3/rpc_server/dcesrv_gssapi.c index f60f6ce245136a5f30de21f5d58d893f2da2a925..25d85a6730ccad8c5859f3af3897fa2d881c7266 100644 --- a/source3/rpc_server/dcesrv_gssapi.c +++ b/source3/rpc_server/dcesrv_gssapi.c @@ -106,11 +106,8 @@ NTSTATUS gssapi_server_get_user_info(struct gse_context *gse_ctx, { TALLOC_CTX *tmp_ctx; DATA_BLOB auth_data; - time_t tgs_authtime; - NTTIME tgs_authtime_nttime; DATA_BLOB pac; struct PAC_DATA *pac_data; - struct PAC_LOGON_NAME *logon_name = NULL; struct PAC_LOGON_INFO *logon_info = NULL; enum ndr_err_code ndr_err; unsigned int i; @@ -122,14 +119,13 @@ NTSTATUS gssapi_server_get_user_info(struct gse_context *gse_ctx, char *username; struct passwd *pw; NTSTATUS status; - bool bret; tmp_ctx = talloc_new(mem_ctx); if (!tmp_ctx) { return NT_STATUS_NO_MEMORY; } - status = gse_get_authz_data(gse_ctx, tmp_ctx, &auth_data); + status = gse_get_pac_blob(gse_ctx, tmp_ctx, &pac); if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) { /* TODO: Fetch user by principal name ? */ status = NT_STATUS_ACCESS_DENIED; @@ -139,24 +135,6 @@ NTSTATUS gssapi_server_get_user_info(struct gse_context *gse_ctx, goto done; } - bret = unwrap_pac(tmp_ctx, &auth_data, &pac); - if (!bret) { - DEBUG(1, ("Failed to unwrap PAC\n")); - status = NT_STATUS_ACCESS_DENIED; - goto done; - } - - status = gse_get_client_name(gse_ctx, tmp_ctx, &princ_name); - if (!NT_STATUS_IS_OK(status)) { - goto done; - } - - status = gse_get_authtime(gse_ctx, &tgs_authtime); - if (!NT_STATUS_IS_OK(status)) { - goto done; - } - unix_to_nt_time(&tgs_authtime_nttime, tgs_authtime); - pac_data = talloc_zero(tmp_ctx, struct PAC_DATA); if (!pac_data) { status = NT_STATUS_NO_MEMORY; @@ -182,9 +160,6 @@ NTSTATUS gssapi_server_get_user_info(struct gse_context *gse_ctx, } logon_info = data_buf->info->logon_info.info; break; - case PAC_TYPE_LOGON_NAME: - logon_name = &data_buf->info->logon_name; - break; default: break; } @@ -194,21 +169,6 @@ NTSTATUS gssapi_server_get_user_info(struct gse_context *gse_ctx, status = NT_STATUS_NOT_FOUND; goto done; } - if (!logon_name) { - DEBUG(1, ("Invalid PAC data, missing logon info!\n")); - status = NT_STATUS_NOT_FOUND; - goto done; - } - - /* check time */ - if (tgs_authtime_nttime != logon_name->logon_time) { - DEBUG(1, ("Logon time mismatch between ticket and PAC!\n" - "PAC Time = %s | Ticket Time = %s\n", - nt_time_string(tmp_ctx, logon_name->logon_time), - nt_time_string(tmp_ctx, tgs_authtime_nttime))); - status = NT_STATUS_ACCESS_DENIED; - goto done; - } /* TODO: Should we check princ_name against account_name in * logon_name ? Are they supposed to be identical, or can an -- 1.7.4.4