summaryrefslogtreecommitdiff
path: root/source4/auth/kerberos
diff options
context:
space:
mode:
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;