CVE-2020-25719 s4:kdc: Add KDC support for PAC_ATTRIBUTES_INFO PAC buffer
authorJoseph Sutton <josephsutton@catalyst.net.nz>
Tue, 26 Oct 2021 07:41:31 +0000 (20:41 +1300)
committerJule Anger <janger@samba.org>
Mon, 8 Nov 2021 09:52:12 +0000 (10:52 +0100)
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14561

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
selftest/knownfail_heimdal_kdc
source4/heimdal/kdc/kerberos5.c
source4/heimdal/kdc/krb5tgs.c
source4/heimdal/kdc/windc.c
source4/heimdal/kdc/windc_plugin.h
source4/kdc/mit_samba.c
source4/kdc/pac-glue.c
source4/kdc/pac-glue.h
source4/kdc/wdc-samba4.c

index 75ca4bba8c4d108b9ff906cf3a1bad5614123a43..0f03e17c2428f91d6f398bfe55648f7bc21b0e3b 100644 (file)
 #
 # KDC TGS PAC tests
 #
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_no_pac_service_no_auth_data_required
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_remove_pac
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_remove_pac_client_no_auth_data_required
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_remove_pac_service_no_auth_data_required
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_request_no_pac
 #
 # KDC TGT tests
 #
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_not_allowed
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_not_revealed
 #
-# PAC attributes tests
-#
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_false
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_missing_renew_false
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_missing_renew_none
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_missing_renew_true
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_missing_rodc_renew_false
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_missing_rodc_renew_none
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_missing_rodc_renew_true
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_none
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_renew_false
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_renew_none
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_renew_true
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_rodc_renew_false
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_rodc_renew_none
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_rodc_renew_true
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_true
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_pac_attrs_false
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_pac_attrs_none
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_pac_attrs_true
-#
 # PAC request tests
 #
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_pac_request_false
index a131f1af08e78f5edef9de87b61f3bb9128be6fd..c1d4cb1d4aa130065ed6f491ea741fee32caf68f 100644 (file)
@@ -913,27 +913,30 @@ _kdc_check_addresses(krb5_context context,
  */
 
 static krb5_boolean
-send_pac_p(krb5_context context, KDC_REQ *req)
+send_pac_p(krb5_context context, KDC_REQ *req, krb5_boolean *pac_request)
 {
     krb5_error_code ret;
     PA_PAC_REQUEST pacreq;
     const PA_DATA *pa;
     int i = 0;
 
+    *pac_request = TRUE;
+
     pa = _kdc_find_padata(req, &i, KRB5_PADATA_PA_PAC_REQUEST);
     if (pa == NULL)
-       return TRUE;
+       return FALSE;
 
     ret = decode_PA_PAC_REQUEST(pa->padata_value.data,
                                pa->padata_value.length,
                                &pacreq,
                                NULL);
     if (ret)
-       return TRUE;
+       return FALSE;
     i = pacreq.include_pac;
     free_PA_PAC_REQUEST(&pacreq);
-    if (i == 0)
-       return FALSE;
+    if (i == 0) {
+       *pac_request = FALSE;
+    }
     return TRUE;
 }
 
@@ -1757,13 +1760,19 @@ _kdc_as_rep(krb5_context context,
     }
 
     /* Add the PAC */
-    if (send_pac_p(context, req)) {
+    {
        krb5_pac p = NULL;
        krb5_data data;
        uint16_t rodc_id;
        krb5_principal client_pac;
+       krb5_boolean sent_pac_request;
+       krb5_boolean pac_request;
+
+       sent_pac_request = send_pac_p(context, req, &pac_request);
 
-       ret = _kdc_pac_generate(context, client, pk_reply_key, &p);
+       ret = _kdc_pac_generate(context, client, pk_reply_key,
+                               sent_pac_request ? &pac_request : NULL,
+                               &p);
        if (ret) {
            kdc_log(context, config, 0, "PAC generation failed for -- %s",
                    client_name);
index 7e9379db64a38e735e85d42ce4752ff04cd5bacf..301ca92091a97209b27255b299a148d4ae16105e 100644 (file)
@@ -1762,7 +1762,7 @@ server_lookup:
            if (mspac) {
                krb5_pac_free(context, mspac);
                mspac = NULL;
-               ret = _kdc_pac_generate(context, s4u2self_impersonated_client, NULL, &mspac);
+               ret = _kdc_pac_generate(context, s4u2self_impersonated_client, NULL, NULL, &mspac);
                if (ret) {
                    kdc_log(context, config, 0, "PAC generation failed for -- %s",
                            tpn);
index 43dc89e2bc010233f114312fbe071b5d0f76f440..93b973f576b3129bde0a2e54fe936d2dbdbfb3fa 100644 (file)
@@ -74,6 +74,7 @@ krb5_error_code
 _kdc_pac_generate(krb5_context context,
                  hdb_entry_ex *client,
                  const krb5_keyblock *pk_reply_key,
+                 const krb5_boolean *pac_request,
                  krb5_pac *pac)
 {
     *pac = NULL;
@@ -87,8 +88,10 @@ _kdc_pac_generate(krb5_context context,
 
     if (windcft->pac_pk_generate != NULL && pk_reply_key != NULL)
        return (windcft->pac_pk_generate)(windcctx, context,
-                                         client, pk_reply_key, pac);
-    return (windcft->pac_generate)(windcctx, context, client, pac);
+                                         client, pk_reply_key,
+                                         pac_request, pac);
+    return (windcft->pac_generate)(windcctx, context, client,
+                                  pac_request, pac);
 }
 
 krb5_error_code
index dda258da3d11090e59359062fa7cdd6949250605..c7f2bcb5ed9eacd0370af88a68332b7f1dc868e3 100644 (file)
@@ -55,12 +55,14 @@ struct hdb_entry_ex;
 typedef krb5_error_code
 (*krb5plugin_windc_pac_generate)(void *, krb5_context,
                                 struct hdb_entry_ex *, /* client */
+                                const krb5_boolean *, /* pac_request */
                                 krb5_pac *);
 
 typedef krb5_error_code
 (*krb5plugin_windc_pac_pk_generate)(void *, krb5_context,
                                    struct hdb_entry_ex *, /* client */
                                    const krb5_keyblock *, /* pk_replykey */
+                                   const krb5_boolean *, /* pac_request */
                                    krb5_pac *);
 
 typedef krb5_error_code
index 592f6a3bac471aaa1fd92241f72a91638cef94ce..69cdbfba929f6d0adcc2ca607d69af101925e46b 100644 (file)
@@ -434,7 +434,8 @@ int mit_samba_get_pac(struct mit_samba_context *smb_ctx,
                                            skdc_entry,
                                            &logon_info_blob,
                                            cred_ndr_ptr,
-                                           &upn_dns_info_blob);
+                                           &upn_dns_info_blob,
+                                           NULL, NULL);
        if (!NT_STATUS_IS_OK(nt_status)) {
                talloc_free(tmp_ctx);
                if (NT_STATUS_EQUAL(nt_status,
@@ -462,6 +463,7 @@ int mit_samba_get_pac(struct mit_samba_context *smb_ctx,
                                   pcred_blob,
                                   upn_dns_info_blob,
                                   NULL,
+                                  NULL,
                                   pac);
 
        talloc_free(tmp_ctx);
@@ -564,7 +566,8 @@ krb5_error_code mit_samba_reget_pac(struct mit_samba_context *ctx,
                                                    client_skdc_entry,
                                                    &pac_blob,
                                                    NULL,
-                                                   &upn_blob);
+                                                   &upn_blob,
+                                                   NULL, NULL);
                if (!NT_STATUS_IS_OK(nt_status)) {
                        code = EINVAL;
                        goto done;
index 8a3ec22190c8a5d606bce08663e25f72ad9a7230..06019e579ebbc555ec92097f19863cd93a6804b7 100644 (file)
@@ -113,6 +113,43 @@ NTSTATUS samba_get_upn_info_pac_blob(TALLOC_CTX *mem_ctx,
        return NT_STATUS_OK;
 }
 
+static
+NTSTATUS samba_get_pac_attrs_blob(TALLOC_CTX *mem_ctx,
+                                 const krb5_boolean *pac_request,
+                                 DATA_BLOB *pac_attrs_data)
+{
+       union PAC_INFO pac_attrs;
+       enum ndr_err_code ndr_err;
+       NTSTATUS nt_status;
+
+       ZERO_STRUCT(pac_attrs);
+
+       *pac_attrs_data = data_blob_null;
+
+       /* Set the length of the flags in bits. */
+       pac_attrs.attributes_info.flags_length = 2;
+
+       if (pac_request == NULL) {
+               pac_attrs.attributes_info.flags
+                       |= PAC_ATTRIBUTE_FLAG_PAC_WAS_GIVEN_IMPLICITLY;
+       } else if (*pac_request) {
+               pac_attrs.attributes_info.flags
+                       |= PAC_ATTRIBUTE_FLAG_PAC_WAS_REQUESTED;
+       }
+
+       ndr_err = ndr_push_union_blob(pac_attrs_data, mem_ctx, &pac_attrs,
+                                     PAC_TYPE_ATTRIBUTES_INFO,
+                                     (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               nt_status = ndr_map_error2ntstatus(ndr_err);
+               DEBUG(1, ("PAC ATTRIBUTES_INFO (presig) push failed: %s\n",
+                         nt_errstr(nt_status)));
+               return nt_status;
+       }
+
+       return NT_STATUS_OK;
+}
+
 static
 NTSTATUS samba_get_cred_info_ndr_blob(TALLOC_CTX *mem_ctx,
                                      const struct ldb_message *msg,
@@ -413,12 +450,14 @@ krb5_error_code samba_make_krb5_pac(krb5_context context,
                                    const DATA_BLOB *logon_blob,
                                    const DATA_BLOB *cred_blob,
                                    const DATA_BLOB *upn_blob,
+                                   const DATA_BLOB *pac_attrs_blob,
                                    const DATA_BLOB *deleg_blob,
                                    krb5_pac *pac)
 {
        krb5_data logon_data;
        krb5_data cred_data;
        krb5_data upn_data;
+       krb5_data pac_attrs_data;
        krb5_data deleg_data;
        krb5_error_code ret;
 #ifdef SAMBA4_USES_HEIMDAL
@@ -463,6 +502,19 @@ krb5_error_code samba_make_krb5_pac(krb5_context context,
                }
        }
 
+       ZERO_STRUCT(pac_attrs_data);
+       if (pac_attrs_blob != NULL) {
+               ret = smb_krb5_copy_data_contents(&pac_attrs_data,
+                                                 pac_attrs_blob->data,
+                                                 pac_attrs_blob->length);
+               if (ret != 0) {
+                       smb_krb5_free_data_contents(context, &logon_data);
+                       smb_krb5_free_data_contents(context, &cred_data);
+                       smb_krb5_free_data_contents(context, &upn_data);
+                       return ret;
+               }
+       }
+
        ZERO_STRUCT(deleg_data);
        if (deleg_blob != NULL) {
                ret = smb_krb5_copy_data_contents(&deleg_data,
@@ -472,6 +524,7 @@ krb5_error_code samba_make_krb5_pac(krb5_context context,
                        smb_krb5_free_data_contents(context, &logon_data);
                        smb_krb5_free_data_contents(context, &cred_data);
                        smb_krb5_free_data_contents(context, &upn_data);
+                       smb_krb5_free_data_contents(context, &pac_attrs_data);
                        return ret;
                }
        }
@@ -481,6 +534,7 @@ krb5_error_code samba_make_krb5_pac(krb5_context context,
                smb_krb5_free_data_contents(context, &logon_data);
                smb_krb5_free_data_contents(context, &cred_data);
                smb_krb5_free_data_contents(context, &upn_data);
+               smb_krb5_free_data_contents(context, &pac_attrs_data);
                smb_krb5_free_data_contents(context, &deleg_data);
                return ret;
        }
@@ -488,8 +542,9 @@ krb5_error_code samba_make_krb5_pac(krb5_context context,
        ret = krb5_pac_add_buffer(context, *pac, PAC_TYPE_LOGON_INFO, &logon_data);
        smb_krb5_free_data_contents(context, &logon_data);
        if (ret != 0) {
-               smb_krb5_free_data_contents(context, &upn_data);
                smb_krb5_free_data_contents(context, &cred_data);
+               smb_krb5_free_data_contents(context, &upn_data);
+               smb_krb5_free_data_contents(context, &pac_attrs_data);
                smb_krb5_free_data_contents(context, &deleg_data);
                return ret;
        }
@@ -501,6 +556,7 @@ krb5_error_code samba_make_krb5_pac(krb5_context context,
                smb_krb5_free_data_contents(context, &cred_data);
                if (ret != 0) {
                        smb_krb5_free_data_contents(context, &upn_data);
+                       smb_krb5_free_data_contents(context, &pac_attrs_data);
                        smb_krb5_free_data_contents(context, &deleg_data);
                        return ret;
                }
@@ -519,6 +575,7 @@ krb5_error_code samba_make_krb5_pac(krb5_context context,
                                  &null_data);
        if (ret != 0) {
                smb_krb5_free_data_contents(context, &upn_data);
+               smb_krb5_free_data_contents(context, &pac_attrs_data);
                smb_krb5_free_data_contents(context, &deleg_data);
                return ret;
        }
@@ -529,6 +586,18 @@ krb5_error_code samba_make_krb5_pac(krb5_context context,
                                          PAC_TYPE_UPN_DNS_INFO,
                                          &upn_data);
                smb_krb5_free_data_contents(context, &upn_data);
+               if (ret != 0) {
+                       smb_krb5_free_data_contents(context, &pac_attrs_data);
+                       smb_krb5_free_data_contents(context, &deleg_data);
+                       return ret;
+               }
+       }
+
+       if (pac_attrs_blob != NULL) {
+               ret = krb5_pac_add_buffer(context, *pac,
+                                         PAC_TYPE_ATTRIBUTES_INFO,
+                                         &pac_attrs_data);
+               smb_krb5_free_data_contents(context, &pac_attrs_data);
                if (ret != 0) {
                        smb_krb5_free_data_contents(context, &deleg_data);
                        return ret;
@@ -562,6 +631,48 @@ bool samba_princ_needs_pac(struct samba_kdc_entry *skdc_entry)
        return true;
 }
 
+int samba_client_requested_pac(krb5_context context,
+                              krb5_pac *pac,
+                              TALLOC_CTX *mem_ctx,
+                              bool *requested_pac)
+{
+       enum ndr_err_code ndr_err;
+       krb5_data k5pac_attrs_in;
+       DATA_BLOB pac_attrs_in;
+       union PAC_INFO pac_attrs;
+       int ret;
+
+       *requested_pac = true;
+
+       ret = krb5_pac_get_buffer(context, *pac, PAC_TYPE_ATTRIBUTES_INFO,
+                                 &k5pac_attrs_in);
+       if (ret != 0) {
+               return ret == ENOENT ? 0 : ret;
+       }
+
+       pac_attrs_in = data_blob_const(k5pac_attrs_in.data,
+                                      k5pac_attrs_in.length);
+
+       ndr_err = ndr_pull_union_blob(&pac_attrs_in, mem_ctx, &pac_attrs,
+                                     PAC_TYPE_ATTRIBUTES_INFO,
+                                     (ndr_pull_flags_fn_t)ndr_pull_PAC_INFO);
+       smb_krb5_free_data_contents(context, &k5pac_attrs_in);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
+               DEBUG(0,("can't parse the PAC ATTRIBUTES_INFO: %s\n", nt_errstr(nt_status)));
+               return EINVAL;
+       }
+
+       if (pac_attrs.attributes_info.flags & (PAC_ATTRIBUTE_FLAG_PAC_WAS_GIVEN_IMPLICITLY
+                                              | PAC_ATTRIBUTE_FLAG_PAC_WAS_REQUESTED)) {
+               *requested_pac = true;
+       } else {
+               *requested_pac = false;
+       }
+
+       return 0;
+}
+
 /* Was the krbtgt in this DB (ie, should we check the incoming signature) and was it an RODC */
 int samba_krbtgt_is_in_db(struct samba_kdc_entry *p,
                          bool *is_in_db,
@@ -637,12 +748,15 @@ NTSTATUS samba_kdc_get_pac_blobs(TALLOC_CTX *mem_ctx,
                                 struct samba_kdc_entry *p,
                                 DATA_BLOB **_logon_info_blob,
                                 DATA_BLOB **_cred_ndr_blob,
-                                DATA_BLOB **_upn_info_blob)
+                                DATA_BLOB **_upn_info_blob,
+                                DATA_BLOB **_pac_attrs_blob,
+                                const krb5_boolean *pac_request)
 {
        struct auth_user_info_dc *user_info_dc;
        DATA_BLOB *logon_blob = NULL;
        DATA_BLOB *cred_blob = NULL;
        DATA_BLOB *upn_blob = NULL;
+       DATA_BLOB *pac_attrs_blob = NULL;
        NTSTATUS nt_status;
 
        *_logon_info_blob = NULL;
@@ -650,6 +764,9 @@ NTSTATUS samba_kdc_get_pac_blobs(TALLOC_CTX *mem_ctx,
                *_cred_ndr_blob = NULL;
        }
        *_upn_info_blob = NULL;
+       if (_pac_attrs_blob != NULL) {
+               *_pac_attrs_blob = NULL;
+       }
 
        logon_blob = talloc_zero(mem_ctx, DATA_BLOB);
        if (logon_blob == NULL) {
@@ -668,6 +785,13 @@ NTSTATUS samba_kdc_get_pac_blobs(TALLOC_CTX *mem_ctx,
                return NT_STATUS_NO_MEMORY;
        }
 
+       if (_pac_attrs_blob != NULL) {
+               pac_attrs_blob = talloc_zero(mem_ctx, DATA_BLOB);
+               if (pac_attrs_blob == NULL) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+       }
+
        nt_status = authsam_make_user_info_dc(mem_ctx, p->kdc_db_ctx->samdb,
                                             lpcfg_netbios_name(p->kdc_db_ctx->lp_ctx),
                                             lpcfg_sam_name(p->kdc_db_ctx->lp_ctx),
@@ -712,12 +836,27 @@ NTSTATUS samba_kdc_get_pac_blobs(TALLOC_CTX *mem_ctx,
                return nt_status;
        }
 
+       if (pac_attrs_blob != NULL) {
+               nt_status = samba_get_pac_attrs_blob(pac_attrs_blob,
+                                                    pac_request,
+                                                    pac_attrs_blob);
+
+               if (!NT_STATUS_IS_OK(nt_status)) {
+                       DEBUG(0, ("Building PAC ATTRIBUTES failed: %s\n",
+                                 nt_errstr(nt_status)));
+                       return nt_status;
+               }
+       }
+
        TALLOC_FREE(user_info_dc);
        *_logon_info_blob = logon_blob;
        if (_cred_ndr_blob != NULL) {
                *_cred_ndr_blob = cred_blob;
        }
        *_upn_info_blob = upn_blob;
+       if (_pac_attrs_blob != NULL) {
+               *_pac_attrs_blob = pac_attrs_blob;
+       }
        return NT_STATUS_OK;
 }
 
@@ -731,7 +870,9 @@ NTSTATUS samba_kdc_get_pac_blob(TALLOC_CTX *mem_ctx,
        nt_status = samba_kdc_get_pac_blobs(mem_ctx, p,
                                            _logon_info_blob,
                                            NULL, /* cred_blob */
-                                           &upn_blob);
+                                           &upn_blob,
+                                           NULL,
+                                           NULL);
        if (!NT_STATUS_IS_OK(nt_status)) {
                return nt_status;
        }
index e83446647b332efd7c7f59857d49b06f5e4c0997..1b6264cb2c304c032eda1e47cb6938df5635547c 100644 (file)
@@ -31,11 +31,17 @@ krb5_error_code samba_make_krb5_pac(krb5_context context,
                                    const DATA_BLOB *logon_blob,
                                    const DATA_BLOB *cred_blob,
                                    const DATA_BLOB *upn_blob,
+                                   const DATA_BLOB *pac_attrs_blob,
                                    const DATA_BLOB *deleg_blob,
                                    krb5_pac *pac);
 
 bool samba_princ_needs_pac(struct samba_kdc_entry *skdc_entry);
 
+int samba_client_requested_pac(krb5_context context,
+                              krb5_pac *pac,
+                              TALLOC_CTX *mem_ctx,
+                              bool *requested_pac);
+
 int samba_krbtgt_is_in_db(struct samba_kdc_entry *skdc_entry,
                          bool *is_in_db,
                          bool *is_untrusted);
@@ -44,7 +50,9 @@ NTSTATUS samba_kdc_get_pac_blobs(TALLOC_CTX *mem_ctx,
                                 struct samba_kdc_entry *skdc_entry,
                                 DATA_BLOB **_logon_info_blob,
                                 DATA_BLOB **_cred_ndr_blob,
-                                DATA_BLOB **_upn_info_blob);
+                                DATA_BLOB **_upn_info_blob,
+                                DATA_BLOB **_pac_attrs_blob,
+                                const krb5_boolean *pac_request);
 NTSTATUS samba_kdc_get_pac_blob(TALLOC_CTX *mem_ctx,
                                struct samba_kdc_entry *skdc_entry,
                                DATA_BLOB **_logon_info_blob);
index ed6e9fb9b6338bbacbdc626e6c88a173883723b5..11d9ff84f04b7afb9e589408299fbce425af46fb 100644 (file)
@@ -37,6 +37,7 @@
 static krb5_error_code samba_wdc_get_pac(void *priv, krb5_context context,
                                         struct hdb_entry_ex *client,
                                         const krb5_keyblock *pk_reply_key,
+                                        const krb5_boolean *pac_request,
                                         krb5_pac *pac)
 {
        TALLOC_CTX *mem_ctx;
@@ -46,6 +47,7 @@ static krb5_error_code samba_wdc_get_pac(void *priv, krb5_context context,
        DATA_BLOB _cred_blob = data_blob_null;
        DATA_BLOB *cred_blob = NULL;
        DATA_BLOB *upn_blob = NULL;
+       DATA_BLOB *pac_attrs_blob = NULL;
        krb5_error_code ret;
        NTSTATUS nt_status;
        struct samba_kdc_entry *skdc_entry =
@@ -64,7 +66,9 @@ static krb5_error_code samba_wdc_get_pac(void *priv, krb5_context context,
        nt_status = samba_kdc_get_pac_blobs(mem_ctx, skdc_entry,
                                            &logon_blob,
                                            cred_ndr_ptr,
-                                           &upn_blob);
+                                           &upn_blob,
+                                           &pac_attrs_blob,
+                                           pac_request);
        if (!NT_STATUS_IS_OK(nt_status)) {
                talloc_free(mem_ctx);
                return EINVAL;
@@ -84,7 +88,8 @@ static krb5_error_code samba_wdc_get_pac(void *priv, krb5_context context,
        }
 
        ret = samba_make_krb5_pac(context, logon_blob, cred_blob,
-                                 upn_blob, NULL, pac);
+                                 upn_blob, pac_attrs_blob,
+                                 NULL, pac);
 
        talloc_free(mem_ctx);
        return ret;
@@ -92,9 +97,10 @@ static krb5_error_code samba_wdc_get_pac(void *priv, krb5_context context,
 
 static krb5_error_code samba_wdc_get_pac_compat(void *priv, krb5_context context,
                                                struct hdb_entry_ex *client,
+                                               const krb5_boolean *pac_request,
                                                krb5_pac *pac)
 {
-       return samba_wdc_get_pac(priv, context, client, NULL, pac);
+       return samba_wdc_get_pac(priv, context, client, NULL, pac_request, pac);
 }
 
 static krb5_error_code samba_wdc_reget_pac2(krb5_context context,
@@ -132,6 +138,7 @@ static krb5_error_code samba_wdc_reget_pac2(krb5_context context,
        ssize_t srv_checksum_idx = -1;
        ssize_t kdc_checksum_idx = -1;
        ssize_t tkt_checksum_idx = -1;
+       ssize_t attrs_info_idx = -1;
 
        if (!mem_ctx) {
                return ENOMEM;
@@ -239,7 +246,8 @@ static krb5_error_code samba_wdc_reget_pac2(krb5_context context,
                                                          struct samba_kdc_entry);
 
                nt_status = samba_kdc_get_pac_blobs(mem_ctx, client_skdc_entry,
-                                                   &pac_blob, NULL, &upn_blob);
+                                                   &pac_blob, NULL, &upn_blob,
+                                                   NULL, NULL);
                if (!NT_STATUS_IS_OK(nt_status)) {
                        talloc_free(mem_ctx);
                        return EINVAL;
@@ -356,6 +364,18 @@ static krb5_error_code samba_wdc_reget_pac2(krb5_context context,
                        }
                        tkt_checksum_idx = i;
                        break;
+               case PAC_TYPE_ATTRIBUTES_INFO:
+                       if (attrs_info_idx != -1) {
+                               DEBUG(1, ("attributes info type[%"PRIu32"] twice [%zd] and [%zu]: \n",
+                                         types[i],
+                                         attrs_info_idx,
+                                         i));
+                               SAFE_FREE(types);
+                               talloc_free(mem_ctx);
+                               return EINVAL;
+                       }
+                       attrs_info_idx = i;
+                       break;
                default:
                        continue;
                }
@@ -403,6 +423,20 @@ static krb5_error_code samba_wdc_reget_pac2(krb5_context context,
                goto out;
        }
 
+       if (!server_skdc_entry->is_krbtgt) {
+               /*
+                * The client may have requested no PAC when obtaining the
+                * TGT.
+                */
+               bool requested_pac;
+               ret = samba_client_requested_pac(context, pac, mem_ctx,
+                                                &requested_pac);
+               if (ret != 0 || !requested_pac) {
+                       new_pac = NULL;
+                       goto out;
+               }
+       }
+
        /* Otherwise build an updated PAC */
        ret = krb5_pac_init(context, &new_pac);
        if (ret != 0) {
@@ -488,6 +522,9 @@ static krb5_error_code samba_wdc_reget_pac2(krb5_context context,
                         */
                        type_blob = data_blob_const(&zero_byte, 1);
                        break;
+               case PAC_TYPE_ATTRIBUTES_INFO:
+                       /* just copy... */
+                       break;
                default:
                        /* just copy... */
                        break;