]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
s4:kdc: provide a PAC_UPN_DNS_INFO element for logons
authorStefan Metzmacher <metze@samba.org>
Thu, 12 May 2016 22:13:33 +0000 (00:13 +0200)
committerAndrew Bartlett <abartlet@samba.org>
Fri, 22 Jul 2016 21:34:22 +0000 (23:34 +0200)
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
source4/kdc/pac-glue.c
source4/kdc/pac-glue.h
source4/kdc/wdc-samba4.c
source4/torture/rpc/remote_pac.c

index 0b9fd12b764f03381c38a617a57694d379da48d4..ff3f62a11c4859bb5f6ff7652b3ac1b9b416d51f 100644 (file)
@@ -77,6 +77,42 @@ NTSTATUS samba_get_logon_info_pac_blob(TALLOC_CTX *mem_ctx,
        return NT_STATUS_OK;
 }
 
+static
+NTSTATUS samba_get_upn_info_pac_blob(TALLOC_CTX *mem_ctx,
+                                    const struct auth_user_info_dc *info,
+                                    DATA_BLOB *upn_data)
+{
+       union PAC_INFO pac_upn;
+       enum ndr_err_code ndr_err;
+       NTSTATUS nt_status;
+
+       ZERO_STRUCT(pac_upn);
+
+       *upn_data = data_blob_null;
+
+       pac_upn.upn_dns_info.upn_name = info->info->user_principal_name;
+       pac_upn.upn_dns_info.dns_domain_name = strupper_talloc(mem_ctx,
+                                               info->info->dns_domain_name);
+       if (pac_upn.upn_dns_info.dns_domain_name == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+       if (info->info->user_principal_constructed) {
+               pac_upn.upn_dns_info.flags |= PAC_UPN_DNS_FLAG_CONSTRUCTED;
+       }
+
+       ndr_err = ndr_push_union_blob(upn_data, mem_ctx, &pac_upn,
+                                     PAC_TYPE_UPN_DNS_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 UPN_DNS_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,
@@ -277,11 +313,13 @@ krb5_error_code samba_kdc_encrypt_pac_credentials(krb5_context context,
 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 *deleg_blob,
                                    krb5_pac *pac)
 {
        krb5_data logon_data;
        krb5_data cred_data;
+       krb5_data upn_data;
        krb5_data deleg_data;
        krb5_data null_data;
        krb5_error_code ret;
@@ -311,6 +349,18 @@ krb5_error_code samba_make_krb5_pac(krb5_context context,
                }
        }
 
+       ZERO_STRUCT(upn_data);
+       if (upn_blob != NULL) {
+               ret = krb5_copy_data_contents(&upn_data,
+                                             upn_blob->data,
+                                             upn_blob->length);
+               if (ret != 0) {
+                       kerberos_free_data_contents(context, &logon_data);
+                       kerberos_free_data_contents(context, &cred_data);
+                       return ret;
+               }
+       }
+
        ZERO_STRUCT(deleg_data);
        if (deleg_blob != NULL) {
                ret = krb5_copy_data_contents(&deleg_data,
@@ -319,6 +369,7 @@ krb5_error_code samba_make_krb5_pac(krb5_context context,
                if (ret != 0) {
                        kerberos_free_data_contents(context, &logon_data);
                        kerberos_free_data_contents(context, &cred_data);
+                       kerberos_free_data_contents(context, &upn_data);
                        return ret;
                }
        }
@@ -327,6 +378,7 @@ krb5_error_code samba_make_krb5_pac(krb5_context context,
        if (ret != 0) {
                kerberos_free_data_contents(context, &logon_data);
                kerberos_free_data_contents(context, &cred_data);
+               kerberos_free_data_contents(context, &upn_data);
                kerberos_free_data_contents(context, &deleg_data);
                return ret;
        }
@@ -334,6 +386,7 @@ krb5_error_code samba_make_krb5_pac(krb5_context context,
        ret = krb5_pac_add_buffer(context, *pac, PAC_TYPE_LOGON_INFO, &logon_data);
        kerberos_free_data_contents(context, &logon_data);
        if (ret != 0) {
+               kerberos_free_data_contents(context, &upn_data);
                kerberos_free_data_contents(context, &cred_data);
                kerberos_free_data_contents(context, &deleg_data);
                return ret;
@@ -344,6 +397,32 @@ krb5_error_code samba_make_krb5_pac(krb5_context context,
                                          PAC_TYPE_CREDENTIAL_INFO,
                                          &cred_data);
                kerberos_free_data_contents(context, &cred_data);
+               if (ret != 0) {
+                       kerberos_free_data_contents(context, &upn_data);
+                       kerberos_free_data_contents(context, &deleg_data);
+                       return ret;
+               }
+       }
+
+       /*
+        * null_data will be filled by the generic KDC code in the caller
+        * here we just add it in order to have it before
+        * PAC_TYPE_UPN_DNS_INFO
+        */
+       ret = krb5_pac_add_buffer(context, *pac,
+                                 PAC_TYPE_LOGON_NAME,
+                                 &null_data);
+       if (ret != 0) {
+               kerberos_free_data_contents(context, &upn_data);
+               kerberos_free_data_contents(context, &deleg_data);
+               return ret;
+       }
+
+       if (upn_blob != NULL) {
+               ret = krb5_pac_add_buffer(context, *pac,
+                                         PAC_TYPE_UPN_DNS_INFO,
+                                         &upn_data);
+               kerberos_free_data_contents(context, &upn_data);
                if (ret != 0) {
                        kerberos_free_data_contents(context, &deleg_data);
                        return ret;
@@ -451,17 +530,20 @@ int samba_krbtgt_is_in_db(struct samba_kdc_entry *p,
 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 **_cred_ndr_blob,
+                                DATA_BLOB **_upn_info_blob)
 {
        struct auth_user_info_dc *user_info_dc;
        DATA_BLOB *logon_blob = NULL;
        DATA_BLOB *cred_blob = NULL;
+       DATA_BLOB *upn_blob = NULL;
        NTSTATUS nt_status;
 
        *_logon_info_blob = NULL;
        if (_cred_ndr_blob != NULL) {
                *_cred_ndr_blob = NULL;
        }
+       *_upn_info_blob = NULL;
 
        /* The user account may be set not to want the PAC */
        if ( ! samba_princ_needs_pac(p)) {
@@ -480,6 +562,11 @@ NTSTATUS samba_kdc_get_pac_blobs(TALLOC_CTX *mem_ctx,
                }
        }
 
+       upn_blob = talloc_zero(mem_ctx, DATA_BLOB);
+       if (upn_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),
@@ -515,11 +602,21 @@ NTSTATUS samba_kdc_get_pac_blobs(TALLOC_CTX *mem_ctx,
                }
        }
 
+       nt_status = samba_get_upn_info_pac_blob(upn_blob,
+                                               user_info_dc,
+                                               upn_blob);
+       if (!NT_STATUS_IS_OK(nt_status)) {
+               DEBUG(0, ("Building PAC UPN INFO 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;
        return NT_STATUS_OK;
 }
 
@@ -528,14 +625,17 @@ NTSTATUS samba_kdc_get_pac_blob(TALLOC_CTX *mem_ctx,
                                DATA_BLOB **_logon_info_blob)
 {
        NTSTATUS nt_status;
+       DATA_BLOB *upn_blob = NULL;
 
        nt_status = samba_kdc_get_pac_blobs(mem_ctx, p,
                                            _logon_info_blob,
-                                           NULL);
+                                           NULL, /* cred_blob */
+                                           &upn_blob);
        if (!NT_STATUS_IS_OK(nt_status)) {
                return nt_status;
        }
 
+       TALLOC_FREE(upn_blob);
        return NT_STATUS_OK;
 }
 
index 22f96c8d42570de0ce84bbb6d54ade47afd77bac..92a6bc78023290f03c6c28e0508c2a74e32e354a 100644 (file)
@@ -30,6 +30,7 @@ krb5_error_code samba_kdc_encrypt_pac_credentials(krb5_context context,
 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 *deleg_blob,
                                    krb5_pac *pac);
 
@@ -42,7 +43,8 @@ int samba_krbtgt_is_in_db(struct samba_kdc_entry *skdc_entry,
 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 **_cred_ndr_blob,
+                                DATA_BLOB **_upn_info_blob);
 NTSTATUS samba_kdc_get_pac_blob(TALLOC_CTX *mem_ctx,
                                struct samba_kdc_entry *skdc_entry,
                                DATA_BLOB **_logon_info_blob);
index 3c0a012fb8029ef8fada00f90fce0e01a4745745..fddf342787f30ad6c468d2fe8e83f04efc7b6178 100644 (file)
@@ -42,6 +42,7 @@ static krb5_error_code samba_wdc_get_pac(void *priv, krb5_context context,
        DATA_BLOB **cred_ndr_ptr = NULL;
        DATA_BLOB _cred_blob = data_blob_null;
        DATA_BLOB *cred_blob = NULL;
+       DATA_BLOB *upn_blob = NULL;
        krb5_error_code ret;
        NTSTATUS nt_status;
        struct samba_kdc_entry *skdc_entry =
@@ -59,7 +60,8 @@ 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);
+                                           cred_ndr_ptr,
+                                           &upn_blob);
        if (!NT_STATUS_IS_OK(nt_status)) {
                talloc_free(mem_ctx);
                return EINVAL;
@@ -79,7 +81,7 @@ static krb5_error_code samba_wdc_get_pac(void *priv, krb5_context context,
        }
 
        ret = samba_make_krb5_pac(context, logon_blob, cred_blob,
-                                 NULL, pac);
+                                 upn_blob, NULL, pac);
 
        talloc_free(mem_ctx);
        return ret;
@@ -111,6 +113,7 @@ static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context,
        TALLOC_CTX *mem_ctx = talloc_named(p, 0, "samba_kdc_reget_pac context");
        krb5_pac new_pac = NULL;
        DATA_BLOB *pac_blob = NULL;
+       DATA_BLOB *upn_blob = NULL;
        DATA_BLOB *deleg_blob = NULL;
        krb5_error_code ret;
        NTSTATUS nt_status;
@@ -124,6 +127,7 @@ static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context,
        ssize_t logon_info_idx = -1;
        ssize_t delegation_idx = -1;
        ssize_t logon_name_idx = -1;
+       ssize_t upn_dns_info_idx = -1;
        ssize_t srv_checksum_idx = -1;
        ssize_t kdc_checksum_idx = -1;
 
@@ -156,7 +160,8 @@ static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context,
                client_skdc_entry = talloc_get_type_abort(client->ctx,
                                                          struct samba_kdc_entry);
 
-               nt_status = samba_kdc_get_pac_blob(mem_ctx, client_skdc_entry, &pac_blob);
+               nt_status = samba_kdc_get_pac_blobs(mem_ctx, client_skdc_entry,
+                                                   &pac_blob, NULL, &upn_blob);
                if (!NT_STATUS_IS_OK(nt_status)) {
                        talloc_free(mem_ctx);
                        return EINVAL;
@@ -266,6 +271,18 @@ static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context,
                        }
                        logon_name_idx = i;
                        break;
+               case PAC_TYPE_UPN_DNS_INFO:
+                       if (upn_dns_info_idx != -1) {
+                               DEBUG(1, ("logon type[%d] twice [%d] and [%d]: \n",
+                                         (int)types[i],
+                                         (int)logon_info_idx,
+                                         (int)i));
+                               SAFE_FREE(types);
+                               talloc_free(mem_ctx);
+                               return EINVAL;
+                       }
+                       upn_dns_info_idx = i;
+                       break;
                case PAC_TYPE_SRV_CHECKSUM:
                        if (srv_checksum_idx != -1) {
                                DEBUG(1, ("logon type[%d] twice [%d] and [%d]: \n",
@@ -377,6 +394,20 @@ static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context,
                         * we just add a place holder here.
                         */
                        type_blob = data_blob_const(&zero_byte, 1);
+
+                       if (upn_dns_info_idx == -1 && upn_blob != NULL) {
+                               /* inject UPN_DNS_INFO behind */
+                               forced_next_type = PAC_TYPE_UPN_DNS_INFO;
+                       }
+                       break;
+               case PAC_TYPE_UPN_DNS_INFO:
+                       /*
+                        * Replace in the RODC case, otherwise
+                        * upn_blob is NULL and we just copy.
+                        */
+                       if (upn_blob != NULL) {
+                               type_blob = *upn_blob;
+                       }
                        break;
                case PAC_TYPE_SRV_CHECKSUM:
                        /*
index dabc37ac2a193a1aac8eccd31da19e42f8a6d65c..25a581bb46b9bd859c61d9e40e03505929114846 100644 (file)
@@ -133,7 +133,7 @@ static bool test_PACVerify(struct torture_context *tctx,
 {
        NTSTATUS status;
        bool pkinit_in_use = torture_setting_bool(tctx, "pkinit_in_use", false);
-       bool expect_pac_upn_dns_info = torture_setting_bool(tctx, "expect_pac_upn_dns_info", false);
+       bool expect_pac_upn_dns_info = torture_setting_bool(tctx, "expect_pac_upn_dns_info", true);
        size_t num_pac_buffers;
 
        struct netr_LogonSamLogon r;