LCOV - code coverage report
Current view: top level - source4/kdc - wdc-samba4.c (source / functions) Hit Total Coverage
Test: coverage report for support-claim-type-attributes 6b5c566e Lines: 341 415 82.2 %
Date: 2023-11-21 12:31:41 Functions: 11 12 91.7 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    PAC Glue between Samba and the KDC
       5             : 
       6             :    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2009
       7             :    Copyright (C) Simo Sorce <idra@samba.org> 2010
       8             : 
       9             :    This program is free software; you can redistribute it and/or modify
      10             :    it under the terms of the GNU General Public License as published by
      11             :    the Free Software Foundation; either version 3 of the License, or
      12             :    (at your option) any later version.
      13             : 
      14             :    This program is distributed in the hope that it will be useful,
      15             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :    GNU General Public License for more details.
      18             : 
      19             : 
      20             :    You should have received a copy of the GNU General Public License
      21             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      22             : */
      23             : 
      24             : #include "includes.h"
      25             : #include "kdc/authn_policy_util.h"
      26             : #include "kdc/kdc-glue.h"
      27             : #include "kdc/db-glue.h"
      28             : #include "kdc/pac-glue.h"
      29             : #include "sdb.h"
      30             : #include "sdb_hdb.h"
      31             : #include "librpc/gen_ndr/auth.h"
      32             : #include <krb5_locl.h>
      33             : #include "lib/replace/system/filesys.h"
      34             : 
      35             : #undef DBGC_CLASS
      36             : #define DBGC_CLASS DBGC_KERBEROS
      37             : 
      38       79264 : static bool samba_wdc_is_s4u2self_req(astgs_request_t r)
      39             : {
      40       79264 :         const KDC_REQ *req = kdc_request_get_req(r);
      41       79264 :         const PA_DATA *pa_for_user = NULL;
      42             : 
      43       79264 :         if (req->msg_type != krb_tgs_req) {
      44       28732 :                 return false;
      45             :         }
      46             : 
      47       49362 :         if (req->padata != NULL) {
      48       49362 :                 int idx = 0;
      49             : 
      50       49362 :                 pa_for_user = krb5_find_padata(req->padata->val,
      51       47704 :                                                req->padata->len,
      52             :                                                KRB5_PADATA_FOR_USER,
      53             :                                                &idx);
      54             :         }
      55             : 
      56       49362 :         if (pa_for_user != NULL) {
      57        1330 :                 return true;
      58             :         }
      59             : 
      60       46374 :         return false;
      61             : }
      62             : 
      63             : /*
      64             :  * Given the right private pointer from hdb_samba4,
      65             :  * get a PAC from the attached ldb messages.
      66             :  *
      67             :  * For PKINIT we also get pk_reply_key and can add PAC_CREDENTIAL_INFO.
      68             :  */
      69       30111 : static krb5_error_code samba_wdc_get_pac(void *priv,
      70             :                                          astgs_request_t r,
      71             :                                          hdb_entry *client,
      72             :                                          hdb_entry *server,
      73             :                                          const krb5_keyblock *pk_reply_key,
      74             :                                          uint64_t pac_attributes,
      75             :                                          krb5_pac *pac)
      76             : {
      77       30111 :         krb5_context context = kdc_request_get_context((kdc_request_t)r);
      78        1170 :         TALLOC_CTX *mem_ctx;
      79       30111 :         DATA_BLOB *logon_blob = NULL;
      80       30111 :         DATA_BLOB *cred_ndr = NULL;
      81       30111 :         DATA_BLOB **cred_ndr_ptr = NULL;
      82       30111 :         DATA_BLOB _cred_blob = data_blob_null;
      83       30111 :         DATA_BLOB *cred_blob = NULL;
      84       30111 :         DATA_BLOB *upn_blob = NULL;
      85       30111 :         DATA_BLOB *pac_attrs_blob = NULL;
      86       30111 :         DATA_BLOB *requester_sid_blob = NULL;
      87       30111 :         DATA_BLOB client_claims_blob = {};
      88        1170 :         krb5_error_code ret;
      89        1170 :         NTSTATUS nt_status;
      90        1170 :         struct samba_kdc_entry *skdc_entry =
      91       30111 :                 talloc_get_type_abort(client->context,
      92             :                 struct samba_kdc_entry);
      93        1170 :         const struct samba_kdc_entry *server_entry =
      94       30111 :                 talloc_get_type_abort(server->context,
      95             :                 struct samba_kdc_entry);
      96       30111 :         bool is_krbtgt = krb5_principal_is_krbtgt(context, server->principal);
      97        1170 :         enum auth_group_inclusion group_inclusion;
      98       30111 :         bool is_s4u2self = samba_wdc_is_s4u2self_req(r);
      99       31281 :         enum samba_asserted_identity asserted_identity =
     100             :                 (is_s4u2self) ?
     101       30111 :                         SAMBA_ASSERTED_IDENTITY_SERVICE :
     102             :                         SAMBA_ASSERTED_IDENTITY_AUTHENTICATION_AUTHORITY;
     103       30111 :         struct authn_audit_info *server_audit_info = NULL;
     104       30111 :         NTSTATUS reply_status = NT_STATUS_OK;
     105             : 
     106       30111 :         const struct auth_user_info_dc *user_info_dc_const = NULL;
     107       30111 :         struct auth_user_info_dc *user_info_dc_shallow_copy = NULL;
     108       30111 :         struct auth_claims auth_claims = {};
     109             : 
     110             :         /* Only include resource groups in a service ticket. */
     111       30111 :         if (is_krbtgt) {
     112       25718 :                 group_inclusion = AUTH_EXCLUDE_RESOURCE_GROUPS;
     113        3223 :         } else if (server_entry->supported_enctypes & KERB_ENCTYPE_RESOURCE_SID_COMPRESSION_DISABLED) {
     114           4 :                 group_inclusion = AUTH_INCLUDE_RESOURCE_GROUPS;
     115             :         } else {
     116        3219 :                 group_inclusion = AUTH_INCLUDE_RESOURCE_GROUPS_COMPRESSED;
     117             :         }
     118             : 
     119       30111 :         mem_ctx = talloc_named(client->context, 0, "samba_wdc_get_pac context");
     120       30111 :         if (!mem_ctx) {
     121           0 :                 return ENOMEM;
     122             :         }
     123             : 
     124       30111 :         if (pk_reply_key != NULL) {
     125          41 :                 cred_ndr_ptr = &cred_ndr;
     126             :         }
     127             : 
     128       31281 :         ret = samba_kdc_get_user_info_from_db(mem_ctx,
     129       30111 :                                               server_entry->kdc_db_ctx->samdb,
     130             :                                               skdc_entry,
     131       30111 :                                               skdc_entry->msg,
     132             :                                               &user_info_dc_const);
     133       30111 :         if (ret) {
     134           0 :                 talloc_free(mem_ctx);
     135           0 :                 return ret;
     136             :         }
     137             : 
     138             :         /* Make a shallow copy of the user_info_dc structure. */
     139       30111 :         nt_status = authsam_shallow_copy_user_info_dc(mem_ctx,
     140             :                                                       user_info_dc_const,
     141             :                                                       &user_info_dc_shallow_copy);
     142       30111 :         user_info_dc_const = NULL;
     143             : 
     144       30111 :         if (!NT_STATUS_IS_OK(nt_status)) {
     145           0 :                 DBG_ERR("Failed to allocate user_info_dc SIDs: %s\n",
     146             :                         nt_errstr(nt_status));
     147           0 :                 talloc_free(mem_ctx);
     148           0 :                 return map_errno_from_nt_status(nt_status);
     149             :         }
     150             : 
     151       30111 :         nt_status = samba_kdc_add_asserted_identity(asserted_identity,
     152             :                                                     user_info_dc_shallow_copy);
     153       30111 :         if (!NT_STATUS_IS_OK(nt_status)) {
     154           0 :                 DBG_ERR("Failed to add asserted identity: %s\n",
     155             :                         nt_errstr(nt_status));
     156           0 :                 talloc_free(mem_ctx);
     157           0 :                 return map_errno_from_nt_status(nt_status);
     158             :         }
     159             : 
     160       30111 :         nt_status = samba_kdc_add_claims_valid(user_info_dc_shallow_copy);
     161       30111 :         if (!NT_STATUS_IS_OK(nt_status)) {
     162           0 :                 DBG_ERR("Failed to add Claims Valid: %s\n",
     163             :                         nt_errstr(nt_status));
     164           0 :                 talloc_free(mem_ctx);
     165           0 :                 return map_errno_from_nt_status(nt_status);
     166             :         }
     167             : 
     168       30111 :         ret = samba_kdc_get_claims_data_from_db(server_entry->kdc_db_ctx->samdb,
     169             :                                                 skdc_entry,
     170             :                                                 &auth_claims.user_claims);
     171       30111 :         if (ret) {
     172           0 :                 talloc_free(mem_ctx);
     173           0 :                 return ret;
     174             :         }
     175             : 
     176       30111 :         nt_status = claims_data_encoded_claims_set(mem_ctx,
     177             :                                                    auth_claims.user_claims,
     178             :                                                    &client_claims_blob);
     179       30111 :         if (!NT_STATUS_IS_OK(nt_status)) {
     180           0 :                 talloc_free(mem_ctx);
     181           0 :                 return map_errno_from_nt_status(nt_status);
     182             :         }
     183             : 
     184             :         /*
     185             :          * For an S4U2Self request, the authentication policy is not enforced.
     186             :          */
     187       30111 :         if (!is_s4u2self && authn_policy_restrictions_present(server_entry->server_policy)) {
     188           1 :                 const hdb_entry *device = kdc_request_get_armor_client(r);
     189           1 :                 const struct auth_user_info_dc *device_info = NULL;
     190             : 
     191           1 :                 if (device != NULL) {
     192           1 :                         const hdb_entry *device_krbtgt = NULL;
     193           1 :                         struct samba_kdc_entry *device_skdc_entry = NULL;
     194           1 :                         const struct samba_kdc_entry *device_krbtgt_skdc_entry = NULL;
     195           1 :                         const krb5_const_pac device_pac = kdc_request_get_armor_pac(r);
     196           1 :                         struct samba_kdc_entry_pac device_pac_entry = {};
     197             : 
     198           1 :                         device_skdc_entry = talloc_get_type_abort(device->context,
     199             :                                                                   struct samba_kdc_entry);
     200             : 
     201           1 :                         device_krbtgt = kdc_request_get_armor_server(r);
     202           1 :                         if (device_krbtgt != NULL) {
     203           1 :                                 device_krbtgt_skdc_entry = talloc_get_type_abort(device_krbtgt->context,
     204             :                                                                                  struct samba_kdc_entry);
     205             :                         }
     206             : 
     207           1 :                         device_pac_entry = samba_kdc_entry_pac(device_pac,
     208             :                                                                device_skdc_entry,
     209           1 :                                                                samba_kdc_entry_is_trust(device_krbtgt_skdc_entry));
     210             : 
     211           1 :                         ret = samba_kdc_get_user_info_dc(mem_ctx,
     212             :                                                          context,
     213           1 :                                                          server_entry->kdc_db_ctx->samdb,
     214             :                                                          device_pac_entry,
     215             :                                                          &device_info,
     216             :                                                          NULL /* resource_groups_out */);
     217           1 :                         if (ret) {
     218           0 :                                 talloc_free(mem_ctx);
     219           0 :                                 return ret;
     220             :                         }
     221             : 
     222           1 :                         ret = samba_kdc_get_claims_data(mem_ctx,
     223             :                                                         context,
     224           1 :                                                         server_entry->kdc_db_ctx->samdb,
     225             :                                                         device_pac_entry,
     226             :                                                         &auth_claims.device_claims);
     227           1 :                         if (ret) {
     228           0 :                                 talloc_free(mem_ctx);
     229           0 :                                 return ret;
     230             :                         }
     231             :                 }
     232             : 
     233           1 :                 ret = samba_kdc_allowed_to_authenticate_to(mem_ctx,
     234           1 :                                                            server_entry->kdc_db_ctx->samdb,
     235           1 :                                                            server_entry->kdc_db_ctx->lp_ctx,
     236             :                                                            skdc_entry,
     237             :                                                            user_info_dc_shallow_copy,
     238             :                                                            device_info,
     239             :                                                            auth_claims,
     240             :                                                            server_entry,
     241             :                                                            &server_audit_info,
     242             :                                                            &reply_status);
     243           1 :                 if (server_audit_info != NULL) {
     244           0 :                         krb5_error_code ret2;
     245             : 
     246           1 :                         ret2 = hdb_samba4_set_steal_server_audit_info(r, server_audit_info);
     247           1 :                         if (ret == 0) {
     248           1 :                                 ret = ret2;
     249             :                         }
     250             :                 }
     251           1 :                 if (!NT_STATUS_IS_OK(reply_status)) {
     252           0 :                         krb5_error_code ret2;
     253             : 
     254           0 :                         ret2 = hdb_samba4_set_ntstatus(r, reply_status, ret);
     255           0 :                         if (ret == 0) {
     256           0 :                                 ret = ret2;
     257             :                         }
     258             :                 }
     259           1 :                 if (ret) {
     260           0 :                         talloc_free(mem_ctx);
     261           0 :                         return ret;
     262             :                 }
     263             :         }
     264             : 
     265       30111 :         nt_status = samba_kdc_get_logon_info_blob(mem_ctx,
     266             :                                                   user_info_dc_shallow_copy,
     267             :                                                   group_inclusion,
     268             :                                                   &logon_blob);
     269       30111 :         if (!NT_STATUS_IS_OK(nt_status)) {
     270           0 :                 talloc_free(mem_ctx);
     271           0 :                 return map_errno_from_nt_status(nt_status);
     272             :         }
     273             : 
     274       30111 :         if (cred_ndr_ptr != NULL) {
     275          41 :                 nt_status = samba_kdc_get_cred_ndr_blob(mem_ctx,
     276             :                                                         skdc_entry,
     277             :                                                         cred_ndr_ptr);
     278          41 :                 if (!NT_STATUS_IS_OK(nt_status)) {
     279           0 :                         talloc_free(mem_ctx);
     280           0 :                         return map_errno_from_nt_status(nt_status);
     281             :                 }
     282             :         }
     283             : 
     284       30111 :         nt_status = samba_kdc_get_upn_info_blob(mem_ctx,
     285             :                                                 user_info_dc_shallow_copy,
     286             :                                                 &upn_blob);
     287       30111 :         if (!NT_STATUS_IS_OK(nt_status)) {
     288           0 :                 talloc_free(mem_ctx);
     289           0 :                 return map_errno_from_nt_status(nt_status);
     290             :         }
     291             : 
     292       30111 :         if (is_krbtgt) {
     293       26888 :                 nt_status = samba_kdc_get_pac_attrs_blob(mem_ctx,
     294             :                                                          pac_attributes,
     295             :                                                          &pac_attrs_blob);
     296       26888 :                 if (!NT_STATUS_IS_OK(nt_status)) {
     297           0 :                         talloc_free(mem_ctx);
     298           0 :                         return map_errno_from_nt_status(nt_status);
     299             :                 }
     300             : 
     301       26888 :                 nt_status = samba_kdc_get_requester_sid_blob(mem_ctx,
     302             :                                                              user_info_dc_shallow_copy,
     303             :                                                              &requester_sid_blob);
     304       26888 :                 if (!NT_STATUS_IS_OK(nt_status)) {
     305           0 :                         talloc_free(mem_ctx);
     306           0 :                         return map_errno_from_nt_status(nt_status);
     307             :                 }
     308             :         }
     309             : 
     310       30111 :         if (pk_reply_key != NULL && cred_ndr != NULL) {
     311          41 :                 ret = samba_kdc_encrypt_pac_credentials(context,
     312             :                                                         pk_reply_key,
     313             :                                                         cred_ndr,
     314             :                                                         mem_ctx,
     315             :                                                         &_cred_blob);
     316          41 :                 if (ret != 0) {
     317           0 :                         talloc_free(mem_ctx);
     318           0 :                         return ret;
     319             :                 }
     320          41 :                 cred_blob = &_cred_blob;
     321             :         }
     322             : 
     323       30111 :         ret = krb5_pac_init(context, pac);
     324       30111 :         if (ret != 0) {
     325           0 :                 talloc_free(mem_ctx);
     326           0 :                 return ret;
     327             :         }
     328             : 
     329       30111 :         ret = samba_make_krb5_pac(context, logon_blob, cred_blob,
     330             :                                   upn_blob, pac_attrs_blob,
     331             :                                   requester_sid_blob, NULL,
     332             :                                   &client_claims_blob, NULL, NULL,
     333             :                                   *pac);
     334             : 
     335       30111 :         talloc_free(mem_ctx);
     336       30111 :         return ret;
     337             : }
     338             : 
     339       49153 : static krb5_error_code samba_wdc_verify_pac2(astgs_request_t r,
     340             :                                              const hdb_entry *delegated_proxy,
     341             :                                              const hdb_entry *client,
     342             :                                              const hdb_entry *krbtgt,
     343             :                                              const krb5_pac pac,
     344             :                                              krb5_cksumtype ctype)
     345             : {
     346       49153 :         krb5_context context = kdc_request_get_context((kdc_request_t)r);
     347       49153 :         struct samba_kdc_entry *client_skdc_entry = NULL;
     348        1658 :         struct samba_kdc_entry *krbtgt_skdc_entry =
     349       49153 :                 talloc_get_type_abort(krbtgt->context, struct samba_kdc_entry);
     350       49153 :         struct samba_kdc_entry_pac client_pac_entry = {};
     351       49153 :         TALLOC_CTX *mem_ctx = NULL;
     352        1658 :         krb5_error_code ret;
     353       49153 :         bool is_s4u2self = samba_wdc_is_s4u2self_req(r);
     354       49153 :         bool is_in_db = false;
     355       49153 :         bool is_trusted = false;
     356       49153 :         uint32_t flags = 0;
     357             : 
     358       49153 :         if (pac == NULL) {
     359           0 :                 return EINVAL;
     360             :         }
     361             : 
     362       49153 :         mem_ctx = talloc_named(NULL, 0, "samba_wdc_verify_pac2 context");
     363       49153 :         if (mem_ctx == NULL) {
     364           0 :                 return ENOMEM;
     365             :         }
     366             : 
     367       49153 :         if (client != NULL) {
     368       49103 :                 client_skdc_entry = talloc_get_type_abort(client->context,
     369             :                                                           struct samba_kdc_entry);
     370             :         }
     371             : 
     372             :         /*
     373             :          * If the krbtgt was generated by an RODC, and we are not that
     374             :          * RODC, then we need to regenerate the PAC - we can't trust
     375             :          * it, and confirm that the RODC was permitted to print this ticket
     376             :          *
     377             :          * Because of the samba_kdc_validate_pac_blob() step we can be
     378             :          * sure that the record in 'client' matches the SID in the
     379             :          * original PAC.
     380             :          */
     381       49153 :         ret = samba_krbtgt_is_in_db(krbtgt_skdc_entry, &is_in_db, &is_trusted);
     382       49153 :         if (ret != 0) {
     383           0 :                 goto out;
     384             :         }
     385             : 
     386       49153 :         krb5_pac_set_trusted(pac, is_trusted);
     387       49153 :         client_pac_entry = samba_kdc_entry_pac(pac,
     388             :                                                client_skdc_entry,
     389       49153 :                                                samba_kdc_entry_is_trust(krbtgt_skdc_entry));
     390             : 
     391       49153 :         if (is_s4u2self) {
     392         678 :                 flags |= SAMBA_KDC_FLAG_PROTOCOL_TRANSITION;
     393             :         }
     394             : 
     395       49153 :         if (delegated_proxy != NULL) {
     396           0 :                 krb5_enctype etype;
     397         196 :                 Key *key = NULL;
     398             : 
     399         196 :                 if (!is_in_db) {
     400             :                         /*
     401             :                          * The RODC-issued PAC was signed by a KDC entry that we
     402             :                          * don't have a key for. The server signature is not
     403             :                          * trustworthy, since it could have been created by the
     404             :                          * server we got the ticket from. We must not proceed as
     405             :                          * otherwise the ticket signature is unchecked.
     406             :                          */
     407           0 :                         ret = HDB_ERR_NOT_FOUND_HERE;
     408          41 :                         goto out;
     409             :                 }
     410             : 
     411             :                 /* Fetch the correct key depending on the checksum type. */
     412         196 :                 if (ctype == CKSUMTYPE_HMAC_MD5) {
     413          41 :                         etype = ENCTYPE_ARCFOUR_HMAC;
     414             :                 } else {
     415         155 :                         ret = krb5_cksumtype_to_enctype(context,
     416             :                                                         ctype,
     417             :                                                         &etype);
     418         155 :                         if (ret != 0) {
     419           6 :                                 goto out;
     420             :                         }
     421             :                 }
     422         190 :                 ret = hdb_enctype2key(context, krbtgt, NULL, etype, &key);
     423         190 :                 if (ret != 0) {
     424           2 :                         goto out;
     425             :                 }
     426             : 
     427             :                 /* Check the KDC, whole-PAC and ticket signatures. */
     428         188 :                 ret = krb5_pac_verify(context,
     429             :                                       pac,
     430             :                                       0,
     431             :                                       NULL,
     432             :                                       NULL,
     433         188 :                                       &key->key);
     434         188 :                 if (ret != 0) {
     435          33 :                         DBG_WARNING("PAC KDC signature failed to verify\n");
     436          33 :                         goto out;
     437             :                 }
     438             : 
     439         155 :                 flags |= SAMBA_KDC_FLAG_CONSTRAINED_DELEGATION;
     440             :         }
     441             : 
     442       50770 :         ret = samba_kdc_verify_pac(mem_ctx,
     443             :                                    context,
     444       49112 :                                    krbtgt_skdc_entry->kdc_db_ctx->samdb,
     445             :                                    flags,
     446             :                                    client_pac_entry,
     447             :                                    krbtgt_skdc_entry);
     448       49112 :         if (ret != 0) {
     449          76 :                 goto out;
     450             :         }
     451             : 
     452       49036 : out:
     453       49153 :         talloc_free(mem_ctx);
     454       49153 :         return ret;
     455             : }
     456             : 
     457             : /* Re-sign (and reform, including possibly new groups) a PAC */
     458             : 
     459       47338 : static krb5_error_code samba_wdc_reget_pac(void *priv, astgs_request_t r,
     460             :                                            krb5_const_principal _client_principal,
     461             :                                            hdb_entry *delegated_proxy,
     462             :                                            krb5_const_pac delegated_proxy_pac,
     463             :                                            hdb_entry *client,
     464             :                                            hdb_entry *server,
     465             :                                            hdb_entry *krbtgt,
     466             :                                            krb5_pac *pac)
     467             : {
     468       47338 :         krb5_context context = kdc_request_get_context((kdc_request_t)r);
     469       47338 :         struct samba_kdc_entry *delegated_proxy_skdc_entry = NULL;
     470       47338 :         krb5_const_principal delegated_proxy_principal = NULL;
     471       47338 :         struct samba_kdc_entry_pac delegated_proxy_pac_entry = {};
     472       47338 :         struct samba_kdc_entry *client_skdc_entry = NULL;
     473       47338 :         struct samba_kdc_entry_pac client_pac_entry = {};
     474       47338 :         struct samba_kdc_entry_pac device = {};
     475        1658 :         const struct samba_kdc_entry *server_skdc_entry =
     476       47338 :                 talloc_get_type_abort(server->context, struct samba_kdc_entry);
     477        1658 :         const struct samba_kdc_entry *krbtgt_skdc_entry =
     478       47338 :                 talloc_get_type_abort(krbtgt->context, struct samba_kdc_entry);
     479       47338 :         TALLOC_CTX *mem_ctx = NULL;
     480       47338 :         krb5_pac new_pac = NULL;
     481       47338 :         struct authn_audit_info *server_audit_info = NULL;
     482        1658 :         krb5_error_code ret;
     483       47338 :         NTSTATUS reply_status = NT_STATUS_OK;
     484       47338 :         uint32_t flags = 0;
     485             : 
     486       47338 :         if (pac == NULL) {
     487           0 :                 return EINVAL;
     488             :         }
     489             : 
     490       47338 :         mem_ctx = talloc_named(NULL, 0, "samba_wdc_reget_pac context");
     491       47338 :         if (mem_ctx == NULL) {
     492           0 :                 return ENOMEM;
     493             :         }
     494             : 
     495       47338 :         if (delegated_proxy != NULL) {
     496         152 :                 delegated_proxy_skdc_entry = talloc_get_type_abort(delegated_proxy->context,
     497             :                                                                    struct samba_kdc_entry);
     498         152 :                 delegated_proxy_principal = delegated_proxy->principal;
     499             :         }
     500             : 
     501       47338 :         delegated_proxy_pac_entry = samba_kdc_entry_pac(delegated_proxy_pac,
     502             :                                                         delegated_proxy_skdc_entry,
     503             :                                                         /* The S4U2Proxy
     504             :                                                          * evidence ticket could
     505             :                                                          * not have been signed
     506             :                                                          * or issued by a krbtgt
     507             :                                                          * trust account. */
     508             :                                                         false /* is_from_trust */);
     509             : 
     510       47338 :         if (client != NULL) {
     511       47288 :                 client_skdc_entry = talloc_get_type_abort(client->context,
     512             :                                                           struct samba_kdc_entry);
     513             :         }
     514             : 
     515       47338 :         device = samba_kdc_get_device_pac(r);
     516             : 
     517       47338 :         ret = krb5_pac_init(context, &new_pac);
     518       47338 :         if (ret != 0) {
     519           0 :                 new_pac = NULL;
     520           0 :                 goto out;
     521             :         }
     522             : 
     523       47338 :         client_pac_entry = samba_kdc_entry_pac(*pac,
     524             :                                                client_skdc_entry,
     525       47338 :                                                samba_kdc_entry_is_trust(krbtgt_skdc_entry));
     526             : 
     527       48996 :         ret = samba_kdc_update_pac(mem_ctx,
     528             :                                    context,
     529       45680 :                                    krbtgt_skdc_entry->kdc_db_ctx->samdb,
     530       47338 :                                    krbtgt_skdc_entry->kdc_db_ctx->lp_ctx,
     531             :                                    flags,
     532             :                                    client_pac_entry,
     533       47338 :                                    server->principal,
     534             :                                    server_skdc_entry,
     535             :                                    delegated_proxy_principal,
     536             :                                    delegated_proxy_pac_entry,
     537             :                                    device,
     538             :                                    new_pac,
     539             :                                    &server_audit_info,
     540             :                                    &reply_status);
     541       47338 :         if (server_audit_info != NULL) {
     542           0 :                 krb5_error_code ret2;
     543             : 
     544         152 :                 ret2 = hdb_samba4_set_steal_server_audit_info(r, server_audit_info);
     545         152 :                 if (ret == 0) {
     546          95 :                         ret = ret2;
     547             :                 }
     548             :         }
     549       47338 :         if (!NT_STATUS_IS_OK(reply_status)) {
     550           0 :                 krb5_error_code ret2;
     551             : 
     552          57 :                 ret2 = hdb_samba4_set_ntstatus(r, reply_status, ret);
     553          57 :                 if (ret == 0) {
     554           0 :                         ret = ret2;
     555             :                 }
     556             :         }
     557       47338 :         if (ret != 0) {
     558          68 :                 krb5_pac_free(context, new_pac);
     559          68 :                 if (ret == ENOATTR) {
     560          11 :                         krb5_pac_free(context, *pac);
     561          11 :                         *pac = NULL;
     562          11 :                         ret = 0;
     563             :                 }
     564          68 :                 goto out;
     565             :         }
     566             : 
     567             :         /* Replace the pac */
     568       47270 :         krb5_pac_free(context, *pac);
     569       47270 :         *pac = new_pac;
     570             : 
     571       47338 : out:
     572       47338 :         talloc_free(mem_ctx);
     573       47338 :         return ret;
     574             : }
     575             : 
     576             : /* Verify a PAC's SID and signatures */
     577             : 
     578       49164 : static krb5_error_code samba_wdc_verify_pac(void *priv, astgs_request_t r,
     579             :                                             krb5_const_principal _client_principal,
     580             :                                             hdb_entry *delegated_proxy,
     581             :                                             hdb_entry *client,
     582             :                                             hdb_entry *_server,
     583             :                                             hdb_entry *krbtgt,
     584             :                                             EncTicketPart *ticket,
     585             :                                             krb5_pac pac)
     586             : {
     587       49164 :         krb5_context context = kdc_request_get_context((kdc_request_t)r);
     588       49164 :         krb5_kdc_configuration *config = kdc_request_get_config((kdc_request_t)r);
     589        1658 :         struct samba_kdc_entry *krbtgt_skdc_entry =
     590       49164 :                 talloc_get_type_abort(krbtgt->context,
     591             :                                       struct samba_kdc_entry);
     592        1658 :         krb5_error_code ret;
     593       49164 :         krb5_cksumtype ctype = CKSUMTYPE_NONE;
     594        1658 :         hdb_entry signing_krbtgt_hdb;
     595             : 
     596       49164 :         if (delegated_proxy) {
     597           0 :                 uint16_t pac_kdc_signature_rodc_id;
     598         199 :                 const unsigned int local_tgs_rodc_id = krbtgt_skdc_entry->kdc_db_ctx->my_krbtgt_number;
     599         199 :                 const uint16_t header_ticket_rodc_id = krbtgt->kvno >> 16;
     600             : 
     601             :                 /*
     602             :                  * We're using delegated_proxy for the moment to indicate cases
     603             :                  * where the ticket was encrypted with the server key, and not a
     604             :                  * krbtgt key. This cannot be trusted, so we need to find a
     605             :                  * krbtgt key that signs the PAC in order to trust the ticket.
     606             :                  *
     607             :                  * The krbtgt passed in to this function refers to the krbtgt
     608             :                  * used to decrypt the ticket of the server requesting
     609             :                  * S4U2Proxy.
     610             :                  *
     611             :                  * When we implement service ticket renewal, we need to check
     612             :                  * the PAC, and this will need to be updated.
     613             :                  */
     614         199 :                 ret = krb5_pac_get_kdc_checksum_info(context,
     615             :                                                      pac,
     616             :                                                      &ctype,
     617             :                                                      &pac_kdc_signature_rodc_id);
     618         199 :                 if (ret != 0) {
     619           3 :                         DBG_WARNING("Failed to get PAC checksum info\n");
     620           3 :                         return ret;
     621             :                 }
     622             : 
     623             :                 /*
     624             :                  * We need to check the KDC and ticket signatures, fetching the
     625             :                  * correct key based on the enctype.
     626             :                  */
     627         196 :                 if (local_tgs_rodc_id != 0) {
     628             :                         /*
     629             :                          * If we are an RODC, and we are not the KDC that signed
     630             :                          * the evidence ticket, then we need to proxy the
     631             :                          * request.
     632             :                          */
     633           0 :                         if (local_tgs_rodc_id != pac_kdc_signature_rodc_id) {
     634           0 :                                 return HDB_ERR_NOT_FOUND_HERE;
     635             :                         }
     636             :                 } else {
     637             :                         /*
     638             :                          * If we are a DC, the ticket may have been signed by a
     639             :                          * different KDC than the one that issued the header
     640             :                          * ticket.
     641             :                          */
     642         196 :                         if (pac_kdc_signature_rodc_id != header_ticket_rodc_id) {
     643           0 :                                 struct sdb_entry signing_krbtgt_sdb;
     644             : 
     645             :                                 /*
     646             :                                  * Fetch our key from the database. To support
     647             :                                  * key rollover, we're going to need to try
     648             :                                  * multiple keys by trial and error. For now,
     649             :                                  * krbtgt keys aren't assumed to change.
     650             :                                  */
     651           4 :                                 ret = samba_kdc_fetch(context,
     652             :                                                       krbtgt_skdc_entry->kdc_db_ctx,
     653           4 :                                                       krbtgt->principal,
     654             :                                                       SDB_F_GET_KRBTGT | SDB_F_RODC_NUMBER_SPECIFIED | SDB_F_CANON,
     655           4 :                                                       ((uint32_t)pac_kdc_signature_rodc_id) << 16,
     656             :                                                       &signing_krbtgt_sdb);
     657           4 :                                 if (ret != 0) {
     658           0 :                                         return ret;
     659             :                                 }
     660             : 
     661           4 :                                 ret = sdb_entry_to_hdb_entry(context,
     662             :                                                              &signing_krbtgt_sdb,
     663             :                                                              &signing_krbtgt_hdb);
     664           4 :                                 sdb_entry_free(&signing_krbtgt_sdb);
     665           4 :                                 if (ret != 0) {
     666           0 :                                         return ret;
     667             :                                 }
     668             : 
     669             :                                 /*
     670             :                                  * Replace the krbtgt entry with our own entry
     671             :                                  * for further processing.
     672             :                                  */
     673           4 :                                 krbtgt = &signing_krbtgt_hdb;
     674             :                         }
     675             :                 }
     676       48965 :         } else if (!krbtgt_skdc_entry->is_trust) {
     677             :                 /*
     678             :                  * We expect to have received a TGT, so check that we haven't
     679             :                  * been given a kpasswd ticket instead. We don't need to do this
     680             :                  * check for an incoming trust, as they use a different secret
     681             :                  * and can't be confused with a normal TGT.
     682             :                  */
     683             : 
     684       48916 :                 struct timeval now = krb5_kdc_get_time();
     685             : 
     686             :                 /*
     687             :                  * Check if the ticket is in the last two minutes of its
     688             :                  * life.
     689             :                  */
     690       48916 :                 KerberosTime lifetime = rk_time_sub(ticket->endtime, now.tv_sec);
     691       48916 :                 if (lifetime <= CHANGEPW_LIFETIME) {
     692             :                         /*
     693             :                          * This ticket has at most two minutes left to live. It
     694             :                          * may be a kpasswd ticket rather than a TGT, so don't
     695             :                          * accept it.
     696             :                          */
     697           8 :                         kdc_audit_addreason((kdc_request_t)r,
     698             :                                             "Ticket is not a ticket-granting ticket");
     699           8 :                         return KRB5KRB_AP_ERR_TKT_EXPIRED;
     700             :                 }
     701             :         }
     702             : 
     703       49153 :         ret = samba_wdc_verify_pac2(r,
     704             :                                     delegated_proxy,
     705             :                                     client,
     706             :                                     krbtgt,
     707             :                                     pac,
     708             :                                     ctype);
     709             : 
     710       49153 :         if (krbtgt == &signing_krbtgt_hdb) {
     711           4 :                 hdb_free_entry(context, config->db[0], &signing_krbtgt_hdb);
     712             :         }
     713             : 
     714       47495 :         return ret;
     715             : }
     716             : 
     717       47792 : static char *get_netbios_name(TALLOC_CTX *mem_ctx, HostAddresses *addrs)
     718             : {
     719       47792 :         char *nb_name = NULL;
     720        1755 :         size_t len;
     721        1755 :         unsigned int i;
     722             : 
     723       47792 :         for (i = 0; addrs && i < addrs->len; i++) {
     724         181 :                 if (addrs->val[i].addr_type != KRB5_ADDRESS_NETBIOS) {
     725           0 :                         continue;
     726             :                 }
     727         181 :                 len = MIN(addrs->val[i].address.length, 15);
     728         181 :                 nb_name = talloc_strndup(mem_ctx,
     729         181 :                                          addrs->val[i].address.data, len);
     730         181 :                 if (nb_name) {
     731         181 :                         break;
     732             :                 }
     733             :         }
     734             : 
     735       47792 :         if ((nb_name == NULL) || (nb_name[0] == '\0')) {
     736       45856 :                 return NULL;
     737             :         }
     738             : 
     739             :         /* Strip space padding */
     740         181 :         for (len = strlen(nb_name) - 1;
     741         944 :              (len > 0) && (nb_name[len] == ' ');
     742         763 :              --len) {
     743         763 :                 nb_name[len] = '\0';
     744             :         }
     745             : 
     746         181 :         return nb_name;
     747             : }
     748             : 
     749       48050 : static krb5_error_code samba_wdc_check_client_access(void *priv,
     750             :                                                      astgs_request_t r)
     751             : {
     752       48050 :         krb5_context context = kdc_request_get_context((kdc_request_t)r);
     753       48050 :         TALLOC_CTX *tmp_ctx = NULL;
     754       48050 :         const hdb_entry *client = NULL;
     755        1755 :         struct samba_kdc_entry *kdc_entry;
     756       48050 :         struct samba_kdc_entry_pac device = {};
     757       48050 :         struct authn_audit_info *client_audit_info = NULL;
     758        1755 :         bool password_change;
     759        1755 :         char *workstation;
     760        1755 :         NTSTATUS nt_status;
     761       48050 :         NTSTATUS check_device_status = NT_STATUS_OK;
     762       48050 :         krb5_error_code ret = 0;
     763             : 
     764       48050 :         client = kdc_request_get_client(r);
     765             : 
     766       48050 :         tmp_ctx = talloc_named(client->context, 0, "samba_wdc_check_client_access");
     767       48050 :         if (tmp_ctx == NULL) {
     768           0 :                 return ENOMEM;
     769             :         }
     770             : 
     771       48050 :         kdc_entry = talloc_get_type_abort(client->context, struct samba_kdc_entry);
     772             : 
     773       48050 :         device = samba_kdc_get_device_pac(r);
     774             : 
     775       49805 :         ret = samba_kdc_check_device(tmp_ctx,
     776             :                                      context,
     777       46295 :                                      kdc_entry->kdc_db_ctx->samdb,
     778       48050 :                                      kdc_entry->kdc_db_ctx->lp_ctx,
     779             :                                      device,
     780             :                                      kdc_entry->client_policy,
     781             :                                      &client_audit_info,
     782             :                                      &check_device_status);
     783       48050 :         if (client_audit_info != NULL) {
     784           0 :                 krb5_error_code ret2;
     785             : 
     786         388 :                 ret2 = hdb_samba4_set_steal_client_audit_info(r, client_audit_info);
     787         388 :                 if (ret2) {
     788           0 :                         ret = ret2;
     789             :                 }
     790             :         }
     791       48050 :         kdc_entry->reject_status = check_device_status;
     792       48050 :         if (!NT_STATUS_IS_OK(check_device_status)) {
     793           0 :                 krb5_error_code ret2;
     794             : 
     795             :                 /*
     796             :                  * Add the NTSTATUS to the request so we can return it in the
     797             :                  * ‘e-data’ field later.
     798             :                  */
     799           2 :                 ret2 = hdb_samba4_set_ntstatus(r, check_device_status, ret);
     800           2 :                 if (ret2) {
     801           0 :                         ret = ret2;
     802             :                 }
     803             :         }
     804             : 
     805       48050 :         if (ret) {
     806             :                 /*
     807             :                  * As we didn’t get far enough to check the server policy, only
     808             :                  * the client policy will be referenced in the authentication
     809             :                  * log message.
     810             :                  */
     811             : 
     812         258 :                 talloc_free(tmp_ctx);
     813         258 :                 return ret;
     814             :         }
     815             : 
     816       51302 :         workstation = get_netbios_name(tmp_ctx,
     817       47792 :                                        kdc_request_get_req(r)->req_body.addresses);
     818       47792 :         password_change = (kdc_request_get_server(r) && kdc_request_get_server(r)->flags.change_pw);
     819             : 
     820       47792 :         nt_status = samba_kdc_check_client_access(kdc_entry,
     821             :                                                   kdc_request_get_cname((kdc_request_t)r),
     822             :                                                   workstation,
     823             :                                                   password_change);
     824             : 
     825       47792 :         kdc_entry->reject_status = nt_status;
     826       47792 :         if (!NT_STATUS_IS_OK(nt_status)) {
     827           0 :                 krb5_error_code ret2;
     828             : 
     829          40 :                 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_MEMORY)) {
     830           0 :                         talloc_free(tmp_ctx);
     831           0 :                         return ENOMEM;
     832             :                 }
     833             : 
     834          40 :                 ret = samba_kdc_map_policy_err(nt_status);
     835             : 
     836             :                 /*
     837             :                  * Add the NTSTATUS to the request so we can return it in the
     838             :                  * ‘e-data’ field later.
     839             :                  */
     840          40 :                 ret2 = hdb_samba4_set_ntstatus(r, nt_status, ret);
     841          40 :                 if (ret2) {
     842           0 :                         ret = ret2;
     843             :                 }
     844             : 
     845          40 :                 talloc_free(tmp_ctx);
     846          40 :                 return ret;
     847             :         }
     848             : 
     849             :         /* Now do the standard Heimdal check */
     850       47752 :         talloc_free(tmp_ctx);
     851       47752 :         return KRB5_PLUGIN_NO_HANDLE;
     852             : }
     853             : 
     854             : /* this function allocates 'data' using malloc.
     855             :  * The caller is responsible for freeing it */
     856       35170 : static krb5_error_code samba_kdc_build_supported_etypes(uint32_t supported_etypes,
     857             :                                                         krb5_data *e_data)
     858             : {
     859       35170 :         e_data->data = malloc(4);
     860       35170 :         if (e_data->data == NULL) {
     861           0 :                 return ENOMEM;
     862             :         }
     863       35170 :         e_data->length = 4;
     864             : 
     865       35170 :         PUSH_LE_U32(e_data->data, 0, supported_etypes);
     866             : 
     867       35170 :         return 0;
     868             : }
     869             : 
     870       77389 : static krb5_error_code samba_wdc_finalize_reply(void *priv,
     871             :                                                 astgs_request_t r)
     872             : {
     873        2828 :         struct samba_kdc_entry *server_kdc_entry;
     874        2828 :         uint32_t supported_enctypes;
     875             : 
     876       77389 :         server_kdc_entry = talloc_get_type(kdc_request_get_server(r)->context, struct samba_kdc_entry);
     877             : 
     878             :         /*
     879             :          * If the canonicalize flag is set, add PA-SUPPORTED-ENCTYPES padata
     880             :          * type to indicate what encryption types the server supports.
     881             :          */
     882       77389 :         supported_enctypes = server_kdc_entry->supported_enctypes;
     883       77389 :         if (kdc_request_get_req(r)->req_body.kdc_options.canonicalize && supported_enctypes != 0) {
     884        1170 :                 krb5_error_code ret;
     885             : 
     886        1170 :                 PA_DATA md;
     887             : 
     888       35170 :                 ret = samba_kdc_build_supported_etypes(supported_enctypes, &md.padata_value);
     889       35170 :                 if (ret != 0) {
     890           0 :                         return ret;
     891             :                 }
     892             : 
     893       35170 :                 md.padata_type = KRB5_PADATA_SUPPORTED_ETYPES;
     894             : 
     895       35170 :                 ret = kdc_request_add_encrypted_padata(r, &md);
     896       35170 :                 if (ret != 0) {
     897             :                         /*
     898             :                          * So we do not leak the allocated
     899             :                          * memory on md in the error case
     900             :                          */
     901           0 :                         krb5_data_free(&md.padata_value);
     902             :                 }
     903             :         }
     904             : 
     905       74561 :         return 0;
     906             : }
     907             : 
     908          93 : static krb5_error_code samba_wdc_plugin_init(krb5_context context, void **ptr)
     909             : {
     910          93 :         *ptr = NULL;
     911          93 :         return 0;
     912             : }
     913             : 
     914           0 : static void samba_wdc_plugin_fini(void *ptr)
     915             : {
     916           0 :         return;
     917             : }
     918             : 
     919        1104 : static krb5_error_code samba_wdc_referral_policy(void *priv,
     920             :                                                  astgs_request_t r)
     921             : {
     922        1104 :         return kdc_request_get_error_code((kdc_request_t)r);
     923             : }
     924             : 
     925             : struct krb5plugin_kdc_ftable kdc_plugin_table = {
     926             :         .minor_version = KRB5_PLUGIN_KDC_VERSION_11,
     927             :         .init = samba_wdc_plugin_init,
     928             :         .fini = samba_wdc_plugin_fini,
     929             :         .pac_verify = samba_wdc_verify_pac,
     930             :         .pac_update = samba_wdc_reget_pac,
     931             :         .client_access = samba_wdc_check_client_access,
     932             :         .finalize_reply = samba_wdc_finalize_reply,
     933             :         .pac_generate = samba_wdc_get_pac,
     934             :         .referral_policy = samba_wdc_referral_policy,
     935             : };
     936             : 
     937             : 

Generated by: LCOV version 1.14