summaryrefslogtreecommitdiff
path: root/source4/auth/kerberos
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2005-06-29 13:55:09 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 13:18:57 -0500
commit9a7481bcfeff29495334eff8803878c2c238878f (patch)
tree040ffa0f4b35ebe93b749a7b32166a9be1e525ad /source4/auth/kerberos
parentf4e75294be1f4c9d110d4ca48c5143078ade2bce (diff)
downloadsamba-9a7481bcfeff29495334eff8803878c2c238878f.tar.gz
samba-9a7481bcfeff29495334eff8803878c2c238878f.tar.bz2
samba-9a7481bcfeff29495334eff8803878c2c238878f.zip
r7993: Further work on the Krb5 PAC.
We now generate the PAC, and can verifiy both our own PAC and the PAC from Win2k3. This commit adds the PAC generation code, spits out the code to get the information we need from the NETLOGON server back into a auth/ helper function, and adds a number of glue functions. In the process of building the PAC generation code, some hints in the Microsoft PAC specification shed light on other parts of the code, and the updates to samr.idl and netlogon.idl come from those hints. Also in this commit: The Heimdal build package has been split up, so as to only link the KDC with smbd, not the client utils. To enable the PAC to be veified with gensec_krb5 (which isn't quite dead yet), the keyblock has been passed back to the calling layer. Andrew Bartlett (This used to be commit e2015671c2f7501f832ff402873ffe6e53b89466)
Diffstat (limited to 'source4/auth/kerberos')
-rw-r--r--source4/auth/kerberos/config.mk1
-rw-r--r--source4/auth/kerberos/kerberos.h7
-rw-r--r--source4/auth/kerberos/kerberos_pac.c182
-rw-r--r--source4/auth/kerberos/kerberos_verify.c17
4 files changed, 184 insertions, 23 deletions
diff --git a/source4/auth/kerberos/config.mk b/source4/auth/kerberos/config.mk
index 62710f3cc4..56ce64fdb1 100644
--- a/source4/auth/kerberos/config.mk
+++ b/source4/auth/kerberos/config.mk
@@ -8,5 +8,6 @@ ADD_OBJ_FILES = \
auth/kerberos/kerberos_util.o \
auth/kerberos/kerberos_pac.o \
auth/kerberos/gssapi_parse.o
+REQUIRED_SUBSYSTEMS = KERBEROS_LIB NDR_KRB5PAC
# End SUBSYSTEM KERBEROS
#################################
diff --git a/source4/auth/kerberos/kerberos.h b/source4/auth/kerberos/kerberos.h
index ca0bbbed0e..1fd48197f8 100644
--- a/source4/auth/kerberos/kerberos.h
+++ b/source4/auth/kerberos/kerberos.h
@@ -97,7 +97,7 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx,
const DATA_BLOB *ticket,
char **principal, DATA_BLOB *auth_data,
DATA_BLOB *ap_rep,
- krb5_keyblock *keyblock);
+ krb5_keyblock **keyblock);
int kerberos_kinit_password_cc(krb5_context ctx, krb5_ccache cc,
const char *principal, const char *password,
time_t *expire_time, time_t *kdc_time);
@@ -132,5 +132,10 @@ NTSTATUS kerberos_decode_pac(TALLOC_CTX *mem_ctx,
DATA_BLOB blob,
struct smb_krb5_context *smb_krb5_context,
krb5_keyblock *keyblock);
+krb5_error_code kerberos_encode_pac(TALLOC_CTX *mem_ctx,
+ struct auth_serversupplied_info *server_info,
+ krb5_context context,
+ krb5_keyblock *keyblock,
+ krb5_data *pac);
#endif /* HAVE_KRB5 */
diff --git a/source4/auth/kerberos/kerberos_pac.c b/source4/auth/kerberos/kerberos_pac.c
index 9d57245798..e1d05b9949 100644
--- a/source4/auth/kerberos/kerberos_pac.c
+++ b/source4/auth/kerberos/kerberos_pac.c
@@ -28,16 +28,16 @@
#include "system/kerberos.h"
#include "system/time.h"
#include "system/network.h"
+#include "auth/auth.h"
#include "auth/kerberos/kerberos.h"
#include "librpc/gen_ndr/ndr_krb5pac.h"
#include "auth/auth.h"
-static NTSTATUS kerberos_pac_checksum(TALLOC_CTX *mem_ctx,
- DATA_BLOB pac_data,
- struct PAC_SIGNATURE_DATA *sig,
- struct smb_krb5_context *smb_krb5_context,
- krb5_keyblock *keyblock,
- uint32_t keyusage)
+static NTSTATUS check_pac_checksum(TALLOC_CTX *mem_ctx,
+ DATA_BLOB pac_data,
+ struct PAC_SIGNATURE_DATA *sig,
+ krb5_context context,
+ krb5_keyblock *keyblock)
{
krb5_error_code ret;
krb5_crypto crypto;
@@ -48,7 +48,7 @@ static NTSTATUS kerberos_pac_checksum(TALLOC_CTX *mem_ctx,
cksum.checksum.data = sig->signature;
- ret = krb5_crypto_init(smb_krb5_context->krb5_context,
+ ret = krb5_crypto_init(context,
keyblock,
0,
&crypto);
@@ -56,7 +56,7 @@ static NTSTATUS kerberos_pac_checksum(TALLOC_CTX *mem_ctx,
DEBUG(0,("krb5_crypto_init() failed\n"));
return NT_STATUS_FOOBAR;
}
- ret = krb5_verify_checksum(smb_krb5_context->krb5_context,
+ ret = krb5_verify_checksum(context,
crypto,
KRB5_KU_OTHER_CKSUM,
pac_data.data,
@@ -64,10 +64,10 @@ static NTSTATUS kerberos_pac_checksum(TALLOC_CTX *mem_ctx,
&cksum);
if (ret) {
DEBUG(2, ("PAC Verification failed: %s\n",
- smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx)));
+ smb_get_krb5_error_message(context, ret, mem_ctx)));
}
- krb5_crypto_destroy(smb_krb5_context->krb5_context, crypto);
+ krb5_crypto_destroy(context, crypto);
if (ret) {
return NT_STATUS_ACCESS_DENIED;
@@ -92,6 +92,8 @@ static NTSTATUS kerberos_pac_checksum(TALLOC_CTX *mem_ctx,
DATA_BLOB modified_pac_blob = data_blob_talloc(mem_ctx, blob.data, blob.length);
int i;
+ file_save("/tmp/pac.in", blob.data, blob.length);
+
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)) {
@@ -127,7 +129,7 @@ static NTSTATUS kerberos_pac_checksum(TALLOC_CTX *mem_ctx,
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:
+ case PAC_TYPE_LOGON_NAME:
break;
default:
break;
@@ -154,11 +156,13 @@ static NTSTATUS kerberos_pac_checksum(TALLOC_CTX *mem_ctx,
memset(&modified_pac_blob.data[modified_pac_blob.length - 44],
'\0', 16);
- /* verify by servie_key */
- status = kerberos_pac_checksum(mem_ctx,
- modified_pac_blob, &srv_sig,
- smb_krb5_context, keyblock, 0);
+ file_save("/tmp/pac.in.blanked", modified_pac_blob.data, modified_pac_blob.length);
+ /* verify by service_key */
+ status = check_pac_checksum(mem_ctx,
+ modified_pac_blob, &srv_sig,
+ smb_krb5_context->krb5_context, keyblock);
+
if (!NT_STATUS_IS_OK(status)) {
return status;
}
@@ -170,3 +174,151 @@ static NTSTATUS kerberos_pac_checksum(TALLOC_CTX *mem_ctx,
return status;
}
+static krb5_error_code make_pac_checksum(TALLOC_CTX *mem_ctx,
+ DATA_BLOB pac_data,
+ struct PAC_SIGNATURE_DATA *sig,
+ krb5_context context,
+ krb5_keyblock *keyblock)
+{
+ krb5_error_code ret;
+ krb5_crypto crypto;
+ Checksum cksum;
+
+
+ ret = krb5_crypto_init(context,
+ keyblock,
+ 0,
+ &crypto);
+ if (ret) {
+ DEBUG(0,("krb5_crypto_init() failed\n"));
+ return ret;
+ }
+ ret = krb5_create_checksum(context,
+ crypto,
+ KRB5_KU_OTHER_CKSUM,
+ 0,
+ pac_data.data,
+ pac_data.length,
+ &cksum);
+ if (ret) {
+ DEBUG(2, ("PAC Verification failed: %s\n",
+ smb_get_krb5_error_message(context, ret, mem_ctx)));
+ }
+
+ krb5_crypto_destroy(context, crypto);
+
+ if (ret) {
+ return ret;
+ }
+
+ sig->type = cksum.cksumtype;
+ if (cksum.checksum.length == sizeof(sig->signature)) {
+ memcpy(sig->signature, cksum.checksum.data, sizeof(sig->signature));
+ }
+
+ return 0;
+}
+
+ krb5_error_code kerberos_encode_pac(TALLOC_CTX *mem_ctx,
+ struct auth_serversupplied_info *server_info,
+ krb5_context context,
+ krb5_keyblock *keyblock,
+ krb5_data *pac)
+{
+ NTSTATUS nt_status;
+ DATA_BLOB tmp_blob = data_blob(NULL, 0);
+ krb5_error_code ret;
+ struct PAC_DATA *pac_data = talloc(mem_ctx, struct PAC_DATA);
+ struct netr_SamBaseInfo *sam;
+ struct timeval tv = timeval_current();
+
+ if (!pac_data) {
+ return ENOMEM;
+ }
+
+ pac_data->num_buffers = 4;
+ pac_data->version = 0;
+
+ pac_data->buffers = talloc_array(pac_data,
+ struct PAC_BUFFER,
+ pac_data->num_buffers);
+
+ if (!pac_data->buffers) {
+ talloc_free(pac_data);
+ return ENOMEM;
+ }
+ pac_data->buffers[0].type = PAC_TYPE_LOGON_INFO;
+ pac_data->buffers[0].info = talloc_zero(pac_data->buffers,
+ union PAC_INFO);
+
+ nt_status = auth_convert_server_info_sambaseinfo(pac_data->buffers[0].info,
+ server_info, &sam);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(1, ("Getting Samba info failed: %s\n", nt_errstr(nt_status)));
+ talloc_free(pac_data);
+ return EINVAL;
+ }
+
+ pac_data->buffers[0].info->logon_info.info3.base = *sam;
+
+ pac_data->buffers[1].type = PAC_TYPE_LOGON_NAME;
+ pac_data->buffers[1].info = talloc_zero(pac_data->buffers,
+ union PAC_INFO);
+ pac_data->buffers[1].info->logon_name.account_name
+ = server_info->account_name;
+ pac_data->buffers[1].info->logon_name.logon_time
+ = timeval_to_nttime(&tv);
+
+ pac_data->buffers[2].type = PAC_TYPE_KDC_CHECKSUM;
+ pac_data->buffers[2].info = talloc_zero(pac_data->buffers,
+ union PAC_INFO);
+
+ pac_data->buffers[3].type = PAC_TYPE_SRV_CHECKSUM;
+ pac_data->buffers[3].info = talloc_zero(pac_data->buffers,
+ union PAC_INFO);
+
+ /* First, just get the keytypes filled in (and lengths right, eventually) */
+ ret = make_pac_checksum(mem_ctx, tmp_blob, &pac_data->buffers[2].info->srv_cksum,
+ context, keyblock);
+ if (ret) {
+ DEBUG(2, ("making PAC checksum failed: %s\n",
+ smb_get_krb5_error_message(context, ret, mem_ctx)));
+ talloc_free(pac_data);
+ return ret;
+ }
+
+ /* But wipe out the actual signatures */
+ ZERO_STRUCT(pac_data->buffers[2].info->kdc_cksum.signature);
+ ZERO_STRUCT(pac_data->buffers[3].info->srv_cksum.signature);
+
+ nt_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(nt_status)) {
+ DEBUG(1, ("PAC push failed: %s\n", nt_errstr(nt_status)));
+ talloc_free(pac_data);
+ return EINVAL;
+ }
+
+ file_save("/tmp/pac.out.blank", tmp_blob.data, tmp_blob.length);
+
+ /* Then sign the result of the previous push, where the sig was zero'ed out */
+ ret = make_pac_checksum(mem_ctx, tmp_blob, &pac_data->buffers[3].info->srv_cksum,
+ context, keyblock);
+
+ /* And push it out to the world. This relies on determanistic pointer values */
+ nt_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(nt_status)) {
+ DEBUG(1, ("PAC push failed: %s\n", nt_errstr(nt_status)));
+ talloc_free(pac_data);
+ return EINVAL;
+ }
+
+ file_save("/tmp/pac.out.signed", tmp_blob.data, tmp_blob.length);
+
+ ret = krb5_data_copy(pac, tmp_blob.data, tmp_blob.length);
+
+ talloc_free(pac_data);
+ return ret;
+}
+
diff --git a/source4/auth/kerberos/kerberos_verify.c b/source4/auth/kerberos/kerberos_verify.c
index 01b8a75c95..b140eb6ae9 100644
--- a/source4/auth/kerberos/kerberos_verify.c
+++ b/source4/auth/kerberos/kerberos_verify.c
@@ -75,7 +75,7 @@ static krb5_error_code ads_keytab_verify_ticket(TALLOC_CTX *mem_ctx, krb5_contex
const char *service,
const DATA_BLOB *ticket, krb5_data *p_packet,
krb5_ticket **pp_tkt,
- krb5_keyblock *keyblock)
+ krb5_keyblock **keyblock)
{
krb5_error_code ret = 0;
krb5_keytab keytab = NULL;
@@ -149,7 +149,9 @@ static krb5_error_code ads_keytab_verify_ticket(TALLOC_CTX *mem_ctx, krb5_contex
p_packet->length = ticket->length;
p_packet->data = (krb5_pointer)ticket->data;
*pp_tkt = NULL;
- ret = krb5_rd_req(context, &auth_context, p_packet, kt_entry.principal, keytab, NULL, pp_tkt);
+ ret = krb5_rd_req_return_keyblock(context, &auth_context, p_packet,
+ kt_entry.principal, keytab,
+ NULL, pp_tkt, keyblock);
if (ret) {
last_error_message = smb_get_krb5_error_message(context, ret, mem_ctx);
DEBUG(10, ("ads_keytab_verify_ticket: krb5_rd_req(%s) failed: %s\n",
@@ -224,7 +226,7 @@ static krb5_error_code ads_secrets_verify_ticket(TALLOC_CTX *mem_ctx,
krb5_principal salt_princ,
const DATA_BLOB *ticket, krb5_data *p_packet,
krb5_ticket **pp_tkt,
- krb5_keyblock *keyblock)
+ krb5_keyblock **keyblock)
{
krb5_error_code ret = 0;
krb5_error_code our_ret;
@@ -274,9 +276,10 @@ static krb5_error_code ads_secrets_verify_ticket(TALLOC_CTX *mem_ctx,
krb5_free_keyblock(context, key);
- our_ret = krb5_rd_req(context, &auth_context, p_packet,
- NULL,
- NULL, NULL, pp_tkt);
+ our_ret = krb5_rd_req_return_keyblock(context, &auth_context, p_packet,
+ NULL,
+ NULL, NULL, pp_tkt,
+ keyblock);
if (!our_ret) {
DEBUG(10,("ads_secrets_verify_ticket: enc type [%u] decrypted message !\n",
@@ -311,7 +314,7 @@ static krb5_error_code ads_secrets_verify_ticket(TALLOC_CTX *mem_ctx,
const DATA_BLOB *ticket,
char **principal, DATA_BLOB *auth_data,
DATA_BLOB *ap_rep,
- krb5_keyblock *keyblock)
+ krb5_keyblock **keyblock)
{
NTSTATUS sret = NT_STATUS_LOGON_FAILURE;
krb5_data packet;