r8110: More PAC work. I still can't get WinXP to accept the PAC, but we are
authorAndrew Bartlett <abartlet@samba.org>
Mon, 4 Jul 2005 02:36:16 +0000 (02:36 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:19:09 +0000 (13:19 -0500)
much closer.

This changes PIDL to allow a subcontext to have a pad8 flag, saying to
pad behind to an 8 byte boundary.  This is the only way I can explain
the 4 trainling zeros in the signature struct.

Far more importantly, the PAC code is now under self-test, both in
creating/parsing our own PAC, but also a PAC from my win2k3 server.
This required changing auth_anonymous, because I wanted to reuse the
anonymous 'server_info' generation code.

I'm still having trouble with PIDL, particulary as surrounds value(),
but I'll follow up on the list.

Andrew Bartlett
(This used to be commit 50a54bf4e9bf04d2a8e0aebb3482a2ff655c8bbb)

12 files changed:
source4/auth/auth_anonymous.c
source4/auth/auth_util.c
source4/auth/kerberos/kerberos.h
source4/auth/kerberos/kerberos_pac.c
source4/build/pidl/ndr.pm
source4/build/pidl/ndr_parser.pm
source4/build/pidl/validator.pm
source4/kdc/pac-glue.c
source4/librpc/idl/krb5pac.idl
source4/torture/auth/pac.c [new file with mode: 0644]
source4/torture/config.mk
source4/torture/torture.c

index 4e78e77cc3f3f828ed0f99cbe82c2a5c7cd9ed3c..4325550413056135e3e33198394751d328d7f5fc 100644 (file)
@@ -37,74 +37,11 @@ static NTSTATUS anonymous_check_password(struct auth_method_context *ctx,
                                         const struct auth_usersupplied_info *user_info, 
                                         struct auth_serversupplied_info **_server_info)
 {
-       struct auth_serversupplied_info *server_info;
-
        if (user_info->account_name && *user_info->account_name) {
                return NT_STATUS_NOT_IMPLEMENTED;
        }
 
-       server_info = talloc(mem_ctx, struct auth_serversupplied_info);
-       NT_STATUS_HAVE_NO_MEMORY(server_info);
-
-       server_info->account_sid = dom_sid_parse_talloc(server_info, SID_NT_ANONYMOUS);
-       NT_STATUS_HAVE_NO_MEMORY(server_info->account_sid);
-
-       /* is this correct? */
-       server_info->primary_group_sid = dom_sid_parse_talloc(server_info, SID_BUILTIN_GUESTS);
-       NT_STATUS_HAVE_NO_MEMORY(server_info->primary_group_sid);
-
-       server_info->n_domain_groups = 0;
-       server_info->domain_groups = NULL;
-
-       /* annoying, but the Anonymous really does have a session key, 
-          and it is all zeros! */
-       server_info->user_session_key = data_blob_talloc(server_info, NULL, 16);
-       NT_STATUS_HAVE_NO_MEMORY(server_info->user_session_key.data);
-
-       server_info->lm_session_key = data_blob_talloc(server_info, NULL, 16);
-       NT_STATUS_HAVE_NO_MEMORY(server_info->lm_session_key.data);
-
-       data_blob_clear(&server_info->user_session_key);
-       data_blob_clear(&server_info->lm_session_key);
-
-       server_info->account_name = talloc_strdup(server_info, "ANONYMOUS LOGON");
-       NT_STATUS_HAVE_NO_MEMORY(server_info->account_name);
-
-       server_info->domain_name = talloc_strdup(server_info, "NT AUTHORITY");
-       NT_STATUS_HAVE_NO_MEMORY(server_info->domain_name);
-
-       server_info->full_name = talloc_strdup(server_info, "Anonymous Logon");
-       NT_STATUS_HAVE_NO_MEMORY(server_info->full_name);
-
-       server_info->logon_script = talloc_strdup(server_info, "");
-       NT_STATUS_HAVE_NO_MEMORY(server_info->logon_script);
-
-       server_info->profile_path = talloc_strdup(server_info, "");
-       NT_STATUS_HAVE_NO_MEMORY(server_info->profile_path);
-
-       server_info->home_directory = talloc_strdup(server_info, "");
-       NT_STATUS_HAVE_NO_MEMORY(server_info->home_directory);
-
-       server_info->home_drive = talloc_strdup(server_info, "");
-       NT_STATUS_HAVE_NO_MEMORY(server_info->home_drive);
-
-       server_info->last_logon = 0;
-       server_info->last_logoff = 0;
-       server_info->acct_expiry = 0;
-       server_info->last_password_change = 0;
-       server_info->allow_password_change = 0;
-       server_info->force_password_change = 0;
-
-       server_info->logon_count = 0;
-       server_info->bad_password_count = 0;
-
-       server_info->acct_flags = ACB_NORMAL;
-
-       server_info->authenticated = False;
-
-       *_server_info = server_info;
-
-       return NT_STATUS_OK;
+       return auth_anonymous_server_info(mem_ctx, _server_info);
 }
 
 static struct auth_operations anonymous_auth_ops = {
index 8c5bd4f057d9d14a29157c5a1a0e8508bd39ff69..2b9b0c25c24f55aed94117356b3f2f76dffbec43 100644 (file)
@@ -425,6 +425,74 @@ NTSTATUS make_server_info_netlogon_validation(TALLOC_CTX *mem_ctx,
        return NT_STATUS_OK;
 }
 
+
+NTSTATUS auth_anonymous_server_info(TALLOC_CTX *mem_ctx, struct auth_serversupplied_info **_server_info) 
+{
+       struct auth_serversupplied_info *server_info;
+       server_info = talloc(mem_ctx, struct auth_serversupplied_info);
+       NT_STATUS_HAVE_NO_MEMORY(server_info);
+
+       server_info->account_sid = dom_sid_parse_talloc(server_info, SID_NT_ANONYMOUS);
+       NT_STATUS_HAVE_NO_MEMORY(server_info->account_sid);
+
+       /* is this correct? */
+       server_info->primary_group_sid = dom_sid_parse_talloc(server_info, SID_BUILTIN_GUESTS);
+       NT_STATUS_HAVE_NO_MEMORY(server_info->primary_group_sid);
+
+       server_info->n_domain_groups = 0;
+       server_info->domain_groups = NULL;
+
+       /* annoying, but the Anonymous really does have a session key, 
+          and it is all zeros! */
+       server_info->user_session_key = data_blob_talloc(server_info, NULL, 16);
+       NT_STATUS_HAVE_NO_MEMORY(server_info->user_session_key.data);
+
+       server_info->lm_session_key = data_blob_talloc(server_info, NULL, 16);
+       NT_STATUS_HAVE_NO_MEMORY(server_info->lm_session_key.data);
+
+       data_blob_clear(&server_info->user_session_key);
+       data_blob_clear(&server_info->lm_session_key);
+
+       server_info->account_name = talloc_strdup(server_info, "ANONYMOUS LOGON");
+       NT_STATUS_HAVE_NO_MEMORY(server_info->account_name);
+
+       server_info->domain_name = talloc_strdup(server_info, "NT AUTHORITY");
+       NT_STATUS_HAVE_NO_MEMORY(server_info->domain_name);
+
+       server_info->full_name = talloc_strdup(server_info, "Anonymous Logon");
+       NT_STATUS_HAVE_NO_MEMORY(server_info->full_name);
+
+       server_info->logon_script = talloc_strdup(server_info, "");
+       NT_STATUS_HAVE_NO_MEMORY(server_info->logon_script);
+
+       server_info->profile_path = talloc_strdup(server_info, "");
+       NT_STATUS_HAVE_NO_MEMORY(server_info->profile_path);
+
+       server_info->home_directory = talloc_strdup(server_info, "");
+       NT_STATUS_HAVE_NO_MEMORY(server_info->home_directory);
+
+       server_info->home_drive = talloc_strdup(server_info, "");
+       NT_STATUS_HAVE_NO_MEMORY(server_info->home_drive);
+
+       server_info->last_logon = 0;
+       server_info->last_logoff = 0;
+       server_info->acct_expiry = 0;
+       server_info->last_password_change = 0;
+       server_info->allow_password_change = 0;
+       server_info->force_password_change = 0;
+
+       server_info->logon_count = 0;
+       server_info->bad_password_count = 0;
+
+       server_info->acct_flags = ACB_NORMAL;
+
+       server_info->authenticated = False;
+
+       *_server_info = server_info;
+
+       return NT_STATUS_OK;
+}
+
 NTSTATUS auth_generate_session_info(TALLOC_CTX *mem_ctx, 
                                    struct auth_serversupplied_info *server_info, 
                                    struct auth_session_info **_session_info) 
index 2fc000fd0d837e4800c91ed43c8d3a4692de78dd..a7c370a1e5d109d73e61c024472d713b28213966 100644 (file)
@@ -138,6 +138,6 @@ krb5_error_code kerberos_encode_pac(TALLOC_CTX *mem_ctx,
                                    krb5_context context,
                                    krb5_keyblock *krbtgt_keyblock,
                                    krb5_keyblock *server_keyblock,
-                                   krb5_data *pac);
+                                   DATA_BLOB *pac);
 #endif /* HAVE_KRB5 */
 
index fb8755c0b89f53f6474e570c5cad3af2a328d255..312013fdb9d643015e7bf9d7016496b7a8d8c11e 100644 (file)
@@ -1,9 +1,9 @@
 /* 
    Unix SMB/CIFS implementation.
 
-   Kerberos backend for GENSEC
+   Create and parse the krb5 PAC
    
-   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004
+   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
    Copyright (C) Andrew Tridgell 2001
    Copyright (C) Luke Howard 2002-2003
    Copyright (C) Stefan Metzmacher 2004-2005
@@ -92,8 +92,6 @@ static NTSTATUS check_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)) {
@@ -156,8 +154,6 @@ static NTSTATUS check_pac_checksum(TALLOC_CTX *mem_ctx,
        memset(&modified_pac_blob.data[modified_pac_blob.length - 44],
               '\0', 16);
 
-       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, 
@@ -224,9 +220,10 @@ static krb5_error_code make_pac_checksum(TALLOC_CTX *mem_ctx,
                                     krb5_context context,
                                     krb5_keyblock *krbtgt_keyblock,
                                     krb5_keyblock *server_keyblock,
-                                    krb5_data *pac)
+                                    DATA_BLOB *pac)
 {
        NTSTATUS nt_status;
+       DATA_BLOB zero_blob = data_blob(NULL, 0);
        DATA_BLOB tmp_blob = data_blob(NULL, 0);
        DATA_BLOB server_checksum_blob;
        krb5_error_code ret;
@@ -234,11 +231,19 @@ static krb5_error_code make_pac_checksum(TALLOC_CTX *mem_ctx,
        struct netr_SamBaseInfo *sam;
        struct timeval tv = timeval_current();
 
+       enum {
+               PAC_BUF_LOGON_TYPE = 0,
+               PAC_BUF_LOGON_NAME = 1,
+               PAC_BUF_KDC_CHECKSUM = 2,
+               PAC_BUF_SRV_CHECKSUM = 3,
+               PAC_BUF_NUM_BUFFERS = 4
+       };
+
        if (!pac_data) {
                return ENOMEM;
        }
 
-       pac_data->num_buffers = 4;
+       pac_data->num_buffers = PAC_BUF_NUM_BUFFERS;
        pac_data->version = 0;
 
        pac_data->buffers = talloc_array(pac_data, 
@@ -249,9 +254,10 @@ static krb5_error_code make_pac_checksum(TALLOC_CTX *mem_ctx,
                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);
+
+       pac_data->buffers[PAC_BUF_LOGON_TYPE].type = PAC_TYPE_LOGON_INFO;
+       pac_data->buffers[PAC_BUF_LOGON_TYPE].info = talloc_zero(pac_data->buffers,
+                                                                union PAC_INFO);
 
        nt_status = auth_convert_server_info_sambaseinfo(pac_data->buffers[0].info,
                                                         server_info, &sam);
@@ -261,81 +267,109 @@ static krb5_error_code make_pac_checksum(TALLOC_CTX *mem_ctx,
                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,
+       pac_data->buffers[PAC_BUF_LOGON_TYPE].info->logon_info.info3.base = *sam;
+       pac_data->buffers[PAC_BUF_LOGON_TYPE].size
+               = ndr_size_PAC_INFO(pac_data->buffers[PAC_BUF_LOGON_TYPE].info,
+                                   pac_data->buffers[PAC_BUF_LOGON_TYPE].type, 
+                                   0);
+       pac_data->buffers[PAC_BUF_LOGON_TYPE]._pad = 0;
+       
+       pac_data->buffers[PAC_BUF_LOGON_NAME].type = PAC_TYPE_LOGON_NAME;
+       pac_data->buffers[PAC_BUF_LOGON_NAME].info = talloc_zero(pac_data->buffers,
                                                union PAC_INFO);
-       pac_data->buffers[1].info->logon_name.account_name
+       pac_data->buffers[PAC_BUF_LOGON_NAME].info->logon_name.account_name
                = server_info->account_name;
-       pac_data->buffers[1].info->logon_name.logon_time
+       pac_data->buffers[PAC_BUF_LOGON_NAME].info->logon_name.logon_time
                = timeval_to_nttime(&tv);
+       pac_data->buffers[PAC_BUF_LOGON_NAME].size
+               = ndr_size_PAC_INFO(pac_data->buffers[PAC_BUF_LOGON_NAME].info,
+                                   pac_data->buffers[PAC_BUF_LOGON_NAME].type, 
+                                   0);
+       pac_data->buffers[PAC_BUF_LOGON_NAME]._pad = 0;
 
-       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,
+       pac_data->buffers[PAC_BUF_KDC_CHECKSUM].type = PAC_TYPE_KDC_CHECKSUM;
+       pac_data->buffers[PAC_BUF_KDC_CHECKSUM].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,
+       ret = make_pac_checksum(mem_ctx, zero_blob, 
+                               &pac_data->buffers[PAC_BUF_KDC_CHECKSUM].info->kdc_cksum,
                                context, krbtgt_keyblock);
+       if (ret) {
+               DEBUG(2, ("making krbtgt PAC checksum failed: %s\n", 
+                         smb_get_krb5_error_message(context, ret, mem_ctx)));
+               talloc_free(pac_data);
+               return ret;
+       }
 
-       ret = make_pac_checksum(mem_ctx, tmp_blob, &pac_data->buffers[3].info->srv_cksum,
+       pac_data->buffers[PAC_BUF_KDC_CHECKSUM].size
+               = ndr_size_PAC_INFO(pac_data->buffers[PAC_BUF_KDC_CHECKSUM].info,
+                                   pac_data->buffers[PAC_BUF_KDC_CHECKSUM].type, 
+                                   0);
+       pac_data->buffers[PAC_BUF_KDC_CHECKSUM]._pad = 0;
+
+
+       pac_data->buffers[PAC_BUF_SRV_CHECKSUM].type = PAC_TYPE_SRV_CHECKSUM;
+       pac_data->buffers[PAC_BUF_SRV_CHECKSUM].info = talloc_zero(pac_data->buffers,
+                                               union PAC_INFO);
+       ret = make_pac_checksum(mem_ctx, zero_blob, 
+                               &pac_data->buffers[PAC_BUF_SRV_CHECKSUM].info->srv_cksum,
                                context, server_keyblock);
        if (ret) {
-               DEBUG(2, ("making PAC checksum failed: %s\n", 
+               DEBUG(2, ("making server PAC checksum failed: %s\n", 
                          smb_get_krb5_error_message(context, ret, mem_ctx)));
                talloc_free(pac_data);
                return ret;
        }
 
+       pac_data->buffers[PAC_BUF_SRV_CHECKSUM].size
+               = ndr_size_PAC_INFO(pac_data->buffers[PAC_BUF_SRV_CHECKSUM].info,
+                                   pac_data->buffers[PAC_BUF_SRV_CHECKSUM].type, 
+                                   0);
+       pac_data->buffers[PAC_BUF_SRV_CHECKSUM]._pad = 0;
+
        /* 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);
+       ZERO_STRUCT(pac_data->buffers[PAC_BUF_KDC_CHECKSUM].info->kdc_cksum.signature);
+       ZERO_STRUCT(pac_data->buffers[PAC_BUF_SRV_CHECKSUM].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)));
+               DEBUG(1, ("PAC (presig) 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, server_keyblock);
 
        /* Push the Server checksum out */
-       nt_status = ndr_push_struct_blob(&server_checksum_blob, mem_ctx, &pac_data->buffers[3].info->srv_cksum,
+       nt_status = ndr_push_struct_blob(&server_checksum_blob, mem_ctx, 
+                                        &pac_data->buffers[PAC_BUF_SRV_CHECKSUM].info->srv_cksum,
                                         (ndr_push_flags_fn_t)ndr_push_PAC_SIGNATURE_DATA);
        if (!NT_STATUS_IS_OK(nt_status)) {
-               DEBUG(1, ("PAC push failed: %s\n", nt_errstr(nt_status)));
+               DEBUG(1, ("PAC_SIGNATURE push failed: %s\n", nt_errstr(nt_status)));
                talloc_free(pac_data);
                return EINVAL;
        }
 
        /* Then sign the result of the previous push, where the sig was zero'ed out */
-       ret = make_pac_checksum(mem_ctx, server_checksum_blob, &pac_data->buffers[2].info->kdc_cksum,
+       ret = make_pac_checksum(mem_ctx, server_checksum_blob, 
+                               &pac_data->buffers[PAC_BUF_KDC_CHECKSUM].info->kdc_cksum,
                                context, krbtgt_keyblock);
 
        /* And push it out again, this time 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)));
+               DEBUG(1, ("PAC (final) 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);
+       *pac = tmp_blob;
 
-       ret = krb5_data_copy(pac, tmp_blob.data, tmp_blob.length);
-       
        talloc_free(pac_data);
        return ret;
 }
index 2bf673b5e34c78e99d4bccab12d4c2aa3730ba32..c4ff1d8a897bd904a818eefc4e62952174eda9ba 100644 (file)
@@ -166,7 +166,8 @@ sub GetElementLevelTable($)
                        SUBCONTEXT_SIZE => $subsize,
                        IS_DEFERRED => $is_deferred,
                        COMPRESSION => util::has_property($e, "compression"),
-                       OBFUSCATION => util::has_property($e, "obfuscation")
+                       OBFUSCATION => util::has_property($e, "obfuscation"),
+                       PAD8 => util::has_property($e, "pad8")
                });
        }
 
index ba6b9d58da54b03c564a1f0ecead936169188ef8..48e243aa0cc3bd9575471ef7486ec0ef18cb2136 100644 (file)
@@ -452,6 +452,9 @@ sub ParseSubcontextPushEnd($$$$)
 
        pidl "NDR_CHECK(ndr_push_subcontext_header(ndr, $l->{HEADER_SIZE}, $subcontext_size, $ndr));";
        pidl "NDR_CHECK(ndr_push_bytes(ndr, $ndr->data, $ndr->offset));";
+       if (defined $l->{PAD8}) {
+           pidl "NDR_CHECK(ndr_push_align(ndr, 8));";
+       }
        deindent;
        pidl "}";
 }
@@ -501,6 +504,9 @@ sub ParseSubcontextPullEnd($$$)
                $advance = "$ndr->offset";
        }
        pidl "NDR_CHECK(ndr_pull_advance(ndr, $advance));";
+       if (defined $l->{PAD8}) {
+           pidl "NDR_CHECK(ndr_pull_align(ndr, 8));";
+       }
        deindent;
        pidl "}";
 }
index fbf7993b208931b7cde3528137d3b2ad63815dfa..f1677d1ae7e51f4ae97ee8073f7a4c3657460573 100644 (file)
@@ -106,6 +106,7 @@ my %property_list = (
        "default"               => ["ELEMENT"],
 
        # subcontext
+       "pad8"                  => ["ELEMENT"],
        "subcontext"            => ["ELEMENT"],
        "subcontext_size"       => ["ELEMENT"],
        "compression"           => ["ELEMENT"],
index 52685083bdcaf5e8fe29920bd20a7e92f05acebe..c986d60fdf3247d93f6d1850b90e89a3cda1e948 100644 (file)
@@ -37,6 +37,7 @@
        struct auth_serversupplied_info *server_info;
        char *username, *p;
        const char *realm;
+       DATA_BLOB tmp_blob;
        TALLOC_CTX *mem_ctx = talloc_named(config, 0, "samba_get_pac context");
        if (!mem_ctx) {
                return ENOMEM;
                                  context, 
                                  krbtgt_keyblock,
                                  server_keyblock,
-                                 pac);
+                                 &tmp_blob);
 
+       if (ret) {
+               DEBUG(1, ("PAC encoding failed: %s\n", 
+                         smb_get_krb5_error_message(context, ret, mem_ctx)));
+               talloc_free(mem_ctx);
+               return ret;
+       }
+
+       ret = krb5_data_copy(pac, tmp_blob.data, tmp_blob.length);
        talloc_free(mem_ctx);
-       
        return ret;
 }
index 71acfd79bd65cc85c212c4cae77dbd1ce276332d..4de54534784ad1baf125d71800337bab518e6ba2 100644 (file)
@@ -16,13 +16,11 @@ interface krb5pac
        typedef struct {
                NTTIME logon_time;
                [flag(STR_SIZE2|STR_NOTERM|STR_BYTESIZE)] string account_name;
-               [value(0)] uint32 _pad; 
        } PAC_LOGON_NAME;
 
        typedef [public,flag(NDR_PAHEX)] struct {
                uint32 type;
                uint8 signature[16];
-               [value(0)] uint32 _pad; 
        } PAC_SIGNATURE_DATA;
 
        typedef struct {
@@ -37,7 +35,7 @@ interface krb5pac
        const uint8 PAC_TYPE_KDC_CHECKSUM = 7;
        const uint8 PAC_TYPE_LOGON_NAME = 10;
 
-       typedef [nodiscriminant,gensize,flag(NDR_ALIGN8)] union {
+       typedef [nodiscriminant,gensize] union {
                [case(PAC_TYPE_LOGON_INFO)]     PAC_LOGON_INFO logon_info;
                [case(PAC_TYPE_SRV_CHECKSUM)]   PAC_SIGNATURE_DATA srv_cksum;
                [case(PAC_TYPE_KDC_CHECKSUM)]   PAC_SIGNATURE_DATA kdc_cksum;
@@ -46,12 +44,12 @@ interface krb5pac
 
        typedef struct {
                uint32 type;
-               [value(ndr_size_PAC_INFO(info,type,ndr->flags))] uint32 size;
-               [relative,switch_is(type)] PAC_INFO *info;
-               [value(0)] uint32 _pad; /* Top half of a 64 bit pointer? */
+               uint32 size;
+               [relative,switch_is(type),subcontext(0),subcontext_size(size),pad8] PAC_INFO *info;
+               uint32 _pad; /* Top half of a 64 bit pointer? */
        } PAC_BUFFER;
 
-       typedef [public,flag(NDR_ALIGN8)] struct {
+       typedef [public] struct {
                uint32 num_buffers;
                uint32 version;
                PAC_BUFFER buffers[num_buffers];
diff --git a/source4/torture/auth/pac.c b/source4/torture/auth/pac.c
new file mode 100644 (file)
index 0000000..79cae5c
--- /dev/null
@@ -0,0 +1,253 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   Validate the krb5 pac generation routines
+   
+   Copyright (C) Andrew Bartlett <abartlet@samba.org> 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/auth.h"
+#include "auth/kerberos/kerberos.h"
+#include "librpc/gen_ndr/ndr_krb5pac.h"
+#include "auth/auth.h"
+
+static BOOL torture_pac_self_check(void) 
+{
+       NTSTATUS nt_status;
+       TALLOC_CTX *mem_ctx = talloc_named(NULL, 0, "PAC self check");
+       DATA_BLOB tmp_blob;
+       struct PAC_LOGON_INFO *pac_info;
+
+       /* Generate a nice, arbitary keyblock */
+       uint8_t server_bytes[16];
+       uint8_t krbtgt_bytes[16];
+       krb5_keyblock server_keyblock;
+       krb5_keyblock krbtgt_keyblock;
+       
+       krb5_error_code ret;
+
+       struct smb_krb5_context *smb_krb5_context;
+
+       struct auth_serversupplied_info *server_info;
+
+       ret = smb_krb5_init_context(mem_ctx, &smb_krb5_context);
+
+       if (ret) {
+               talloc_free(mem_ctx);
+               return False;
+       }
+
+       generate_random_buffer(server_bytes, 16);
+       generate_random_buffer(krbtgt_bytes, 16);
+
+       ret = krb5_keyblock_init(smb_krb5_context->krb5_context,
+                                ENCTYPE_ARCFOUR_HMAC,
+                                server_bytes, sizeof(server_bytes),
+                                &server_keyblock);
+       if (ret) {
+               DEBUG(1, ("Server Keyblock encoding failed: %s\n", 
+                         smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
+                                                    ret, mem_ctx)));
+
+               talloc_free(mem_ctx);
+               return False;
+       }
+
+       ret = krb5_keyblock_init(smb_krb5_context->krb5_context,
+                                ENCTYPE_ARCFOUR_HMAC,
+                                krbtgt_bytes, sizeof(krbtgt_bytes),
+                                &krbtgt_keyblock);
+       if (ret) {
+               DEBUG(1, ("KRBTGT Keyblock encoding failed: %s\n", 
+                         smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
+                                                    ret, mem_ctx)));
+
+               krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
+                                           &server_keyblock);
+               talloc_free(mem_ctx);
+               return False;
+       }
+
+       /* We need an input, and this one requires no underlying database */
+       nt_status = auth_anonymous_server_info(mem_ctx, &server_info);
+
+       if (!NT_STATUS_IS_OK(nt_status)) {
+               krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
+                                           &server_keyblock);
+               krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
+                                           &krbtgt_keyblock);
+               talloc_free(mem_ctx);
+               return False;
+       }
+       
+       /* OK, go ahead and make a PAC */
+       ret = kerberos_encode_pac(mem_ctx, server_info, 
+                                 smb_krb5_context->krb5_context,  
+                                 &krbtgt_keyblock,
+                                 &server_keyblock,
+                                 &tmp_blob);
+       
+       krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
+                                   &krbtgt_keyblock);
+
+       if (ret) {
+               DEBUG(1, ("PAC encoding failed: %s\n", 
+                         smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
+                                                    ret, mem_ctx)));
+
+               krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
+                                           &server_keyblock);
+               talloc_free(mem_ctx);
+               return False;
+       }
+       
+       /* Now check that we can read it back */
+       nt_status = kerberos_decode_pac(mem_ctx, &pac_info,
+                                       tmp_blob,
+                                       smb_krb5_context,
+                                       &server_keyblock);
+       krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
+                                   &server_keyblock);
+       if (ret) {
+               DEBUG(1, ("PAC decoding failed: %s\n", 
+                         nt_errstr(nt_status)));
+
+               talloc_free(mem_ctx);
+               return False;
+       }
+
+       talloc_free(mem_ctx);
+       return True;
+}
+
+
+/* This is the PAC generated on my test network, by my test Win2k3 server.
+   -- abartlet 2005-07-04
+ */
+
+static const char saved_pac[] = {
+       0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xd8, 0x01, 0x00, 0x00, 
+       0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+       0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
+       0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
+       0x58, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc,
+       0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x30, 0xdf, 0xa6, 0xcb, 
+       0x4f, 0x7d, 0xc5, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 
+       0xff, 0xff, 0xff, 0x7f, 0xc0, 0x3c, 0x4e, 0x59, 0x62, 0x73, 0xc5, 0x01, 0xc0, 0x3c, 0x4e, 0x59,
+       0x62, 0x73, 0xc5, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x16, 0x00, 0x16, 0x00,
+       0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x0c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 
+       0x14, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x02, 0x00, 0x65, 0x00, 0x00, 0x00, 
+       0xed, 0x03, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x02, 0x00,
+       0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x16, 0x00, 0x20, 0x00, 0x02, 0x00, 0x16, 0x00, 0x18, 0x00,
+       0x24, 0x00, 0x02, 0x00, 0x28, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x01, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
+       0x57, 0x00, 0x32, 0x00, 0x30, 0x00, 0x30, 0x00, 0x33, 0x00, 0x46, 0x00, 0x49, 0x00, 0x4e, 0x00,
+       0x41, 0x00, 0x4c, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+       0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x57, 0x00, 0x32, 0x00,
+       0x30, 0x00, 0x30, 0x00, 0x33, 0x00, 0x46, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x41, 0x00, 0x4c, 0x00,
+       0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x57, 0x00, 0x49, 0x00,
+       0x4e, 0x00, 0x32, 0x00, 0x4b, 0x00, 0x33, 0x00, 0x54, 0x00, 0x48, 0x00, 0x49, 0x00, 0x4e, 0x00,
+       0x4b, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+       0x15, 0x00, 0x00, 0x00, 0x11, 0x2f, 0xaf, 0xb5, 0x90, 0x04, 0x1b, 0xec, 0x50, 0x3b, 0xec, 0xdc,
+       0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+       0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x80, 0x66, 0x28, 0xea, 0x37, 0x80, 0xc5, 0x01, 0x16, 0x00, 0x77, 0x00, 0x32, 0x00, 0x30, 0x00,
+       0x30, 0x00, 0x33, 0x00, 0x66, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x24, 0x00,
+       0x76, 0xff, 0xff, 0xff, 0x37, 0xd5, 0xb0, 0xf7, 0x24, 0xf0, 0xd6, 0xd4, 0xec, 0x09, 0x86, 0x5a,
+       0xa0, 0xe8, 0xc3, 0xa9, 0x00, 0x00, 0x00, 0x00, 0x76, 0xff, 0xff, 0xff, 0xb4, 0xd8, 0xb8, 0xfe,
+       0x83, 0xb3, 0x13, 0x3f, 0xfc, 0x5c, 0x41, 0xad, 0xe2, 0x64, 0x83, 0xe0, 0x00, 0x00, 0x00, 0x00
+};
+
+/* Check with a known 'well formed' PAC, from my test server */
+static BOOL torture_pac_saved_check(void) 
+{
+       NTSTATUS nt_status;
+       TALLOC_CTX *mem_ctx = talloc_named(NULL, 0, "PAC saved check");
+       DATA_BLOB tmp_blob;
+       struct PAC_LOGON_INFO *pac_info;
+       krb5_keyblock server_keyblock;
+       uint8_t server_bytes[16];
+       
+       krb5_error_code ret;
+
+       struct smb_krb5_context *smb_krb5_context;
+
+       ret = smb_krb5_init_context(mem_ctx, &smb_krb5_context);
+
+       if (ret) {
+               talloc_free(mem_ctx);
+               return False;
+       }
+
+       /* The machine trust account in use when the above PAC 
+          was generated.  It used arcfour-hmac-md5, so this is easy */
+       E_md4hash("iqvwmii8CuEkyY", server_bytes);
+
+       ret = krb5_keyblock_init(smb_krb5_context->krb5_context,
+                                ENCTYPE_ARCFOUR_HMAC,
+                                server_bytes, sizeof(server_bytes),
+                                &server_keyblock);
+       if (ret) {
+               DEBUG(1, ("Server Keyblock encoding failed: %s\n", 
+                         smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
+                                                    ret, mem_ctx)));
+
+               talloc_free(mem_ctx);
+               return False;
+       }
+
+       tmp_blob = data_blob_const(saved_pac, sizeof(saved_pac));
+
+       /* Decode and verify the signaure on the PAC */
+       nt_status = kerberos_decode_pac(mem_ctx, &pac_info,
+                                       tmp_blob,
+                                       smb_krb5_context,
+                                       &server_keyblock);
+       krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
+                                   &server_keyblock);
+       if (ret) {
+               DEBUG(1, ("PAC decoding failed: %s\n", 
+                         nt_errstr(nt_status)));
+
+               talloc_free(mem_ctx);
+               return False;
+       }
+       talloc_free(mem_ctx);
+       return True;
+}
+
+BOOL torture_pac(void) 
+{
+       BOOL ret = True;
+       ret &= torture_pac_self_check();
+       ret &= torture_pac_saved_check();
+       return ret;
+}
index 8144dcfe80c82e009dcc540b65e65e8a6f69dc9a..6b373f96505bb10ec17e4ffa189b04ef2a9f0b9d 100644 (file)
@@ -129,9 +129,10 @@ REQUIRED_SUBSYSTEMS = \
 # Start SUBSYSTEM TORTURE_AUTH
 [SUBSYSTEM::TORTURE_AUTH]
 ADD_OBJ_FILES = \
-               torture/auth/ntlmssp.o
+               torture/auth/ntlmssp.o \
+               torture/auth/pac.o
 REQUIRED_SUBSYSTEMS = \
-               LIBSMB
+               LIBSMB GENSEC AUTH
 # End SUBSYSTEM TORTURE_AUTH
 #################################
 
index c5ac8735912e2306598dc5e208878056a7303441..157233d43df4c3a4a48b88a6cbf72f6eb8a91b08 100644 (file)
@@ -2317,6 +2317,7 @@ static struct {
        {"LOCAL-BINDING", torture_local_binding_string, 0},
        {"LOCAL-IDTREE", torture_local_idtree, 0},
        {"LOCAL-SOCKET", torture_local_socket, 0},
+       {"LOCAL-PAC", torture_pac, 0},
 
        /* COM (Component Object Model) testers */
        {"COM-SIMPLE", torture_com_simple, 0 },