1
0
mirror of https://github.com/samba-team/samba.git synced 2025-12-16 00:23:52 +03:00

r7968: Pull the PAC from within GSSAPI, rather than only when using our own

'mock GSSAPI'.

Many thanks to Luke Howard for the work he has done on Heimdal for
XAD, to provide the right API hooks in GSSAPI.

Next step is to verify the signatures, and to build the PAC for the
KDC end.

Andrew Bartlett
This commit is contained in:
Andrew Bartlett
2005-06-28 00:55:44 +00:00
committed by Gerald (Jerry) Carter
parent 56a5ccd7d9
commit 2e82743c98
6 changed files with 277 additions and 215 deletions

View File

@@ -3,8 +3,8 @@
Kerberos backend for GENSEC
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004
Copyright (C) Stefan Metzmacher <metze@samba.org> 2005
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
Copyright (C) Stefan Metzmacher <metze@samba.org> 2004-2005
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -224,6 +224,7 @@ static NTSTATUS gensec_gssapi_server_start(struct gensec_security *gensec_securi
static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_security)
{
struct gensec_gssapi_state *gensec_gssapi_state;
struct cli_credentials *creds = gensec_get_credentials(gensec_security);
NTSTATUS nt_status;
gss_buffer_desc name_token;
OM_uint32 maj_stat, min_stat;
@@ -251,8 +252,8 @@ static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_securi
return NT_STATUS_UNSUCCESSFUL;
}
name_token.value = cli_credentials_get_principal(gensec_get_credentials(gensec_security),
gensec_gssapi_state),
name_token.value = cli_credentials_get_principal(creds,
gensec_gssapi_state);
name_token.length = strlen(name_token.value);
maj_stat = gss_import_name (&min_stat,
@@ -267,7 +268,7 @@ static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_securi
}
nt_status = kinit_to_ccache(gensec_gssapi_state,
gensec_get_credentials(gensec_security),
creds,
gensec_gssapi_state->smb_krb5_context,
&gensec_gssapi_state->ccache, &gensec_gssapi_state->ccache_name);
if (!NT_STATUS_IS_OK(nt_status)) {
@@ -724,16 +725,22 @@ static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_securi
struct auth_session_info **_session_info)
{
NTSTATUS nt_status;
TALLOC_CTX *mem_ctx;
struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
struct auth_serversupplied_info *server_info = NULL;
struct auth_session_info *session_info = NULL;
struct PAC_LOGON_INFO *logon_info;
char *p;
char *principal;
const char *account_name;
const char *realm;
OM_uint32 maj_stat, min_stat;
gss_buffer_desc name_token;
gss_buffer_desc pac;
mem_ctx = talloc_named(gensec_gssapi_state, 0, "gensec_gssapi_session_info context");
NT_STATUS_HAVE_NO_MEMORY(mem_ctx);
maj_stat = gss_display_name (&min_stat,
gensec_gssapi_state->client_name,
&name_token,
@@ -742,11 +749,14 @@ static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_securi
return NT_STATUS_FOOBAR;
}
principal = talloc_strndup(gensec_gssapi_state, name_token.value, name_token.length);
principal = talloc_strndup(mem_ctx, name_token.value, name_token.length);
gss_release_buffer(&min_stat, &name_token);
NT_STATUS_HAVE_NO_MEMORY(principal);
if (!principal) {
talloc_free(mem_ctx);
return NT_STATUS_NO_MEMORY;
}
p = strchr(principal, '@');
if (p) {
@@ -757,24 +767,56 @@ static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_securi
realm = lp_realm();
}
account_name = principal;
maj_stat = gsskrb5_extract_authz_data_from_sec_context(&min_stat,
gensec_gssapi_state->gssapi_context,
1,
&pac);
if (maj_stat == 0) {
DATA_BLOB pac_blob = data_blob_talloc(mem_ctx, pac.value, pac.length);
pac_blob = unwrap_pac(mem_ctx, &pac_blob);
gss_release_buffer(&min_stat, &pac);
/* decode and verify the pac */
nt_status = kerberos_decode_pac(mem_ctx, &logon_info, pac_blob,
gensec_gssapi_state->smb_krb5_context);
/* IF we have the PAC - otherwise we need to get this
* data from elsewere - local ldb, or (TODO) lookup of some
* kind...
*
* when heimdal can generate the PAC, we should fail if there's
* no PAC present
*/
if (NT_STATUS_IS_OK(nt_status)) {
union netr_Validation validation;
validation.sam3 = &logon_info->info3;
nt_status = make_server_info_netlogon_validation(gensec_gssapi_state,
account_name,
3, &validation,
&server_info);
if (!NT_STATUS_IS_OK(nt_status)) {
talloc_free(mem_ctx);
return nt_status;
}
} else {
maj_stat = 1;
}
}
if (maj_stat) {
/* IF we have the PAC - otherwise we need to get this
* data from elsewere - local ldb, or (TODO) lookup of some
* kind...
*
* when heimdal can generate the PAC, we should fail if there's
* no PAC present
*/
{
DATA_BLOB user_sess_key = data_blob(NULL, 0);
DATA_BLOB lm_sess_key = data_blob(NULL, 0);
/* TODO: should we pass the krb5 session key in here? */
nt_status = sam_get_server_info(gensec_gssapi_state, account_name, realm,
nt_status = sam_get_server_info(mem_ctx, account_name, realm,
user_sess_key, lm_sess_key,
&server_info);
talloc_free(principal);
NT_STATUS_NOT_OK_RETURN(nt_status);
if (!NT_STATUS_IS_OK(nt_status)) {
talloc_free(mem_ctx);
return nt_status;
}
}
/* references the server_info into the session_info */

View File

@@ -51,185 +51,6 @@ struct gensec_krb5_state {
char *peer_principal;
};
#ifdef KRB5_DO_VERIFY_PAC
static NTSTATUS gensec_krb5_pac_checksum(DATA_BLOB pac_data,
struct PAC_SIGNATURE_DATA *sig,
struct gensec_krb5_state *gensec_krb5_state,
uint32 keyusage)
{
krb5_error_code ret;
krb5_crypto crypto;
Checksum cksum;
int i;
cksum.cksumtype = (CKSUMTYPE)sig->type;
cksum.checksum.length = sizeof(sig->signature);
cksum.checksum.data = sig->signature;
ret = krb5_crypto_init(gensec_krb5_state->smb_krb5_context->krb5_context,
&gensec_krb5_state->keyblock,
0,
&crypto);
if (ret) {
DEBUG(0,("krb5_crypto_init() failed\n"));
return NT_STATUS_FOOBAR;
}
for (i=0; i < 40; i++) {
keyusage = i;
ret = krb5_verify_checksum(gensec_krb5_state->smb_krb5_context->krb5_context,
crypto,
keyusage,
pac_data.data,
pac_data.length,
&cksum);
if (!ret) {
DEBUG(0,("PAC Verified: keyusage: %d\n", keyusage));
break;
}
}
krb5_crypto_destroy(gensec_krb5_state->smb_krb5_context->krb5_context, crypto);
if (ret) {
DEBUG(0,("NOT verifying PAC checksums yet!\n"));
//return NT_STATUS_LOGON_FAILURE;
} else {
DEBUG(0,("PAC checksums verified!\n"));
}
return NT_STATUS_OK;
}
#endif
static NTSTATUS gensec_krb5_decode_pac(TALLOC_CTX *mem_ctx,
struct PAC_LOGON_INFO **logon_info_out,
DATA_BLOB blob,
struct gensec_krb5_state *gensec_krb5_state)
{
NTSTATUS status;
struct PAC_SIGNATURE_DATA srv_sig;
struct PAC_SIGNATURE_DATA *srv_sig_ptr;
struct PAC_SIGNATURE_DATA kdc_sig;
struct PAC_SIGNATURE_DATA *kdc_sig_ptr;
struct PAC_LOGON_INFO *logon_info = NULL;
struct PAC_DATA pac_data;
#ifdef KRB5_DO_VERIFY_PAC
DATA_BLOB tmp_blob = data_blob(NULL, 0);
#endif
int i;
status = ndr_pull_struct_blob(&blob, mem_ctx, &pac_data,
(ndr_pull_flags_fn_t)ndr_pull_PAC_DATA);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("can't parse the PAC\n"));
return status;
}
NDR_PRINT_DEBUG(PAC_DATA, &pac_data);
if (pac_data.num_buffers < 3) {
/* we need logon_ingo, service_key and kdc_key */
DEBUG(0,("less than 3 PAC buffers\n"));
return NT_STATUS_FOOBAR;
}
for (i=0; i < pac_data.num_buffers; i++) {
switch (pac_data.buffers[i].type) {
case PAC_TYPE_LOGON_INFO:
if (!pac_data.buffers[i].info) {
break;
}
logon_info = &pac_data.buffers[i].info->logon_info;
break;
case PAC_TYPE_SRV_CHECKSUM:
if (!pac_data.buffers[i].info) {
break;
}
srv_sig_ptr = &pac_data.buffers[i].info->srv_cksum;
srv_sig = pac_data.buffers[i].info->srv_cksum;
break;
case PAC_TYPE_KDC_CHECKSUM:
if (!pac_data.buffers[i].info) {
break;
}
kdc_sig_ptr = &pac_data.buffers[i].info->kdc_cksum;
kdc_sig = pac_data.buffers[i].info->kdc_cksum;
break;
case PAC_TYPE_UNKNOWN_10:
break;
default:
break;
}
}
if (!logon_info) {
DEBUG(0,("PAC no logon_info\n"));
return NT_STATUS_FOOBAR;
}
if (!srv_sig_ptr) {
DEBUG(0,("PAC no srv_key\n"));
return NT_STATUS_FOOBAR;
}
if (!kdc_sig_ptr) {
DEBUG(0,("PAC no kdc_key\n"));
return NT_STATUS_FOOBAR;
}
#ifdef KRB5_DO_VERIFY_PAC
/* clear the kdc_key */
/* memset((void *)kdc_sig_ptr , '\0', sizeof(*kdc_sig_ptr));*/
status = ndr_push_struct_blob(&tmp_blob, mem_ctx, &pac_data,
(ndr_push_flags_fn_t)ndr_push_PAC_DATA);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
status = ndr_pull_struct_blob(&tmp_blob, mem_ctx, &pac_data,
(ndr_pull_flags_fn_t)ndr_pull_PAC_DATA);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("can't parse the PAC\n"));
return status;
}
/*NDR_PRINT_DEBUG(PAC_DATA, &pac_data);*/
/* verify by kdc_key */
status = gensec_krb5_pac_checksum(tmp_blob, &kdc_sig, gensec_krb5_state, 0);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
/* clear the service_key */
/* memset((void *)srv_sig_ptr , '\0', sizeof(*srv_sig_ptr));*/
status = ndr_push_struct_blob(&tmp_blob, mem_ctx, &pac_data,
(ndr_push_flags_fn_t)ndr_push_PAC_DATA);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
status = ndr_pull_struct_blob(&tmp_blob, mem_ctx, &pac_data,
(ndr_pull_flags_fn_t)ndr_pull_PAC_DATA);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("can't parse the PAC\n"));
return status;
}
NDR_PRINT_DEBUG(PAC_DATA, &pac_data);
/* verify by servie_key */
status = gensec_krb5_pac_checksum(tmp_blob, &srv_sig, gensec_krb5_state, 0);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
#endif
DEBUG(0,("account_name: %s [%s]\n",
logon_info->info3.base.account_name.string,
logon_info->info3.base.full_name.string));
*logon_info_out = logon_info;
return status;
}
static int gensec_krb5_destory(void *ptr)
{
struct gensec_krb5_state *gensec_krb5_state = ptr;
@@ -263,7 +84,6 @@ static NTSTATUS gensec_krb5_start(struct gensec_security *gensec_security)
gensec_security->private_data = gensec_krb5_state;
initialize_krb5_error_table();
gensec_krb5_state->auth_context = NULL;
gensec_krb5_state->ccache = NULL;
ZERO_STRUCT(gensec_krb5_state->ticket);
@@ -623,8 +443,8 @@ static NTSTATUS gensec_krb5_session_info(struct gensec_security *gensec_security
account_name = principal;
/* decode and verify the pac */
nt_status = gensec_krb5_decode_pac(gensec_krb5_state, &logon_info, gensec_krb5_state->pac,
gensec_krb5_state);
nt_status = kerberos_decode_pac(gensec_krb5_state, &logon_info, gensec_krb5_state->pac,
gensec_krb5_state);
/* IF we have the PAC - otherwise we need to get this
* data from elsewere - local ldb, or (TODO) lookup of some

View File

@@ -0,0 +1,213 @@
/*
Unix SMB/CIFS implementation.
Kerberos backend for GENSEC
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004
Copyright (C) Andrew Tridgell 2001
Copyright (C) Luke Howard 2002-2003
Copyright (C) Stefan Metzmacher 2004-2005
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "system/kerberos.h"
#include "system/time.h"
#include "system/network.h"
#include "auth/kerberos/kerberos.h"
#include "librpc/gen_ndr/ndr_krb5pac.h"
#include "auth/auth.h"
#ifdef KRB5_DO_VERIFY_PAC
static NTSTATUS kerberos_pac_checksum(DATA_BLOB pac_data,
struct PAC_SIGNATURE_DATA *sig,
struct smb_krb5_context *smb_krb5_context,
uint32 keyusage)
{
krb5_error_code ret;
krb5_crypto crypto;
Checksum cksum;
int i;
cksum.cksumtype = (CKSUMTYPE)sig->type;
cksum.checksum.length = sizeof(sig->signature);
cksum.checksum.data = sig->signature;
ret = krb5_crypto_init(smb_krb5_context->krb5_context,
&gensec_krb5_state->keyblock,
0,
&crypto);
if (ret) {
DEBUG(0,("krb5_crypto_init() failed\n"));
return NT_STATUS_FOOBAR;
}
for (i=0; i < 40; i++) {
keyusage = i;
ret = krb5_verify_checksum(smb_krb5_context->krb5_context,
crypto,
keyusage,
pac_data.data,
pac_data.length,
&cksum);
if (!ret) {
DEBUG(0,("PAC Verified: keyusage: %d\n", keyusage));
break;
}
}
krb5_crypto_destroy(smb_krb5_context->krb5_context, crypto);
if (ret) {
DEBUG(0,("NOT verifying PAC checksums yet!\n"));
//return NT_STATUS_LOGON_FAILURE;
} else {
DEBUG(0,("PAC checksums verified!\n"));
}
return NT_STATUS_OK;
}
#endif
NTSTATUS kerberos_decode_pac(TALLOC_CTX *mem_ctx,
struct PAC_LOGON_INFO **logon_info_out,
DATA_BLOB blob,
struct smb_krb5_context *smb_krb5_context)
{
NTSTATUS status;
struct PAC_SIGNATURE_DATA srv_sig;
struct PAC_SIGNATURE_DATA *srv_sig_ptr;
struct PAC_SIGNATURE_DATA kdc_sig;
struct PAC_SIGNATURE_DATA *kdc_sig_ptr;
struct PAC_LOGON_INFO *logon_info = NULL;
struct PAC_DATA pac_data;
#ifdef KRB5_DO_VERIFY_PAC
DATA_BLOB tmp_blob = data_blob(NULL, 0);
#endif
int i;
status = ndr_pull_struct_blob(&blob, mem_ctx, &pac_data,
(ndr_pull_flags_fn_t)ndr_pull_PAC_DATA);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("can't parse the PAC\n"));
return status;
}
NDR_PRINT_DEBUG(PAC_DATA, &pac_data);
if (pac_data.num_buffers < 3) {
/* we need logon_ingo, service_key and kdc_key */
DEBUG(0,("less than 3 PAC buffers\n"));
return NT_STATUS_FOOBAR;
}
for (i=0; i < pac_data.num_buffers; i++) {
switch (pac_data.buffers[i].type) {
case PAC_TYPE_LOGON_INFO:
if (!pac_data.buffers[i].info) {
break;
}
logon_info = &pac_data.buffers[i].info->logon_info;
break;
case PAC_TYPE_SRV_CHECKSUM:
if (!pac_data.buffers[i].info) {
break;
}
srv_sig_ptr = &pac_data.buffers[i].info->srv_cksum;
srv_sig = pac_data.buffers[i].info->srv_cksum;
break;
case PAC_TYPE_KDC_CHECKSUM:
if (!pac_data.buffers[i].info) {
break;
}
kdc_sig_ptr = &pac_data.buffers[i].info->kdc_cksum;
kdc_sig = pac_data.buffers[i].info->kdc_cksum;
break;
case PAC_TYPE_UNKNOWN_10:
break;
default:
break;
}
}
if (!logon_info) {
DEBUG(0,("PAC no logon_info\n"));
return NT_STATUS_FOOBAR;
}
if (!srv_sig_ptr) {
DEBUG(0,("PAC no srv_key\n"));
return NT_STATUS_FOOBAR;
}
if (!kdc_sig_ptr) {
DEBUG(0,("PAC no kdc_key\n"));
return NT_STATUS_FOOBAR;
}
#ifdef KRB5_DO_VERIFY_PAC
/* clear the kdc_key */
/* memset((void *)kdc_sig_ptr , '\0', sizeof(*kdc_sig_ptr));*/
status = ndr_push_struct_blob(&tmp_blob, mem_ctx, &pac_data,
(ndr_push_flags_fn_t)ndr_push_PAC_DATA);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
status = ndr_pull_struct_blob(&tmp_blob, mem_ctx, &pac_data,
(ndr_pull_flags_fn_t)ndr_pull_PAC_DATA);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("can't parse the PAC\n"));
return status;
}
/*NDR_PRINT_DEBUG(PAC_DATA, &pac_data);*/
/* verify by kdc_key */
status = kerberos_pac_checksum(tmp_blob, &kdc_sig, smb_krb5_context, 0);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
/* clear the service_key */
/* memset((void *)srv_sig_ptr , '\0', sizeof(*srv_sig_ptr));*/
status = ndr_push_struct_blob(&tmp_blob, mem_ctx, &pac_data,
(ndr_push_flags_fn_t)ndr_push_PAC_DATA);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
status = ndr_pull_struct_blob(&tmp_blob, mem_ctx, &pac_data,
(ndr_pull_flags_fn_t)ndr_pull_PAC_DATA);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("can't parse the PAC\n"));
return status;
}
NDR_PRINT_DEBUG(PAC_DATA, &pac_data);
/* verify by servie_key */
status = kerberos_pac_checksum(tmp_blob, &srv_sig, smb_krb5_context, 0);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
#endif
DEBUG(0,("account_name: %s [%s]\n",
logon_info->info3.base.account_name.string,
logon_info->info3.base.full_name.string));
*logon_info_out = logon_info;
return status;
}

View File

@@ -34,7 +34,7 @@
#ifdef HAVE_KRB5
static DATA_BLOB unwrap_pac(TALLOC_CTX *mem_ctx, DATA_BLOB *auth_data)
DATA_BLOB unwrap_pac(TALLOC_CTX *mem_ctx, DATA_BLOB *auth_data)
{
DATA_BLOB out;
DATA_BLOB pac_contents = data_blob(NULL, 0);

View File

@@ -60,19 +60,6 @@ build_bison() {
cd $TOP || exit 1
}
build_awk() {
f=$1
dir=`dirname $f`
file=`basename $f`
base=`basename $f .h.in`
echo Building $f
cd $dir && $AWK -f $base.awk $base.h.in > gen.c
$CC -I$TOP/heimdal_build -I$TOP -Iheimdal/lib/roken -DHAVE_CONFIG_H -o gen gen.c || exit 1
./gen > $base.h || exit 1
rm -f gen gen.c
cd $TOP || exit 1
}
build_cp() {
f=$1
dir=`dirname $f`
@@ -89,7 +76,6 @@ build_lex heimdal/lib/asn1/lex.l
build_lex heimdal/lib/com_err/lex.l
build_bison heimdal/lib/com_err/parse.y
build_bison heimdal/lib/asn1/parse.y
build_awk heimdal/lib/roken/roken.h.in
make bin/asn1_compile || exit 1
build_asn1 heimdal/lib/hdb/hdb.asn1 hdb_asn1

View File

@@ -61,6 +61,7 @@ ADD_OBJ_FILES = \
heimdal/lib/gssapi/add_oid_set_member.o \
heimdal/lib/gssapi/arcfour.o \
heimdal/lib/gssapi/ccache_name.o \
heimdal/lib/gssapi/copy_ccache.o \
heimdal/lib/gssapi/cfx.o \
heimdal/lib/gssapi/compat.o \
heimdal/lib/gssapi/context_time.o \