summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimo Sorce <idra@samba.org>2011-05-09 11:33:41 -0400
committerKarolin Seeger <kseeger@samba.org>2011-05-15 20:21:42 +0200
commit1bb6b8419e9f777ab780e0c41e9a31851832838d (patch)
tree109029e1e454b2c6a4f2071c5f22ed994c107a72
parent5bae0b6c76448919887fa7a2780254295a85d75e (diff)
downloadsamba-1bb6b8419e9f777ab780e0c41e9a31851832838d.tar.gz
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. (cherry picked from commit ad8415cb8a7bbd1f653eecce1aa2b88242bcc9e5)
-rw-r--r--source3/configure.in1
-rw-r--r--source3/librpc/crypto/gse.c74
-rw-r--r--source3/librpc/crypto/gse.h3
-rw-r--r--source3/rpc_server/dcesrv_gssapi.c42
4 files changed, 53 insertions, 67 deletions
diff --git a/source3/configure.in b/source3/configure.in
index d8c59b675bd..72568d838f2 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 <krb5.h>])
diff --git a/source3/librpc/crypto/gse.c b/source3/librpc/crypto/gse.c
index 064ccda2eb1..335dc1c53f1 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);
- gss_maj = gss_release_buffer_set(&gss_min, &set);
+ return status;
+ }
- *authtime = (time_t)tkttime;
- return NT_STATUS_OK;
+ DEBUG(0, ("obtaining PAC via GSSAPI failed: authenticated: %s, "
+ "complete: %s, more: %s\n",
+ authenticated ? "true" : "false",
+ complete ? "true" : "false",
+ more ? "true" : "false"));
+
+ 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 a6d9a35a7ff..d9e4a82e0ee 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 f60f6ce2451..25d85a6730c 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