LCOV - code coverage report
Current view: top level - source4/kdc - pac-blobs.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 85 98 86.7 %
Date: 2024-04-21 15:09:00 Functions: 7 7 100.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    PAC Glue between Samba and the KDC
       5             : 
       6             :    Copyright (C) Catalyst.Net Ltd 2023
       7             : 
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             : 
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include "source4/kdc/pac-blobs.h"
      23             : 
      24             : #include "lib/util/debug.h"
      25             : #include "lib/util/samba_util.h"
      26             : 
      27     1619884 : static inline size_t *pac_blobs_get_index(struct pac_blobs *pac_blobs, size_t type)
      28             : {
      29             :         /* Ensure the type is valid. */
      30     1619884 :         SMB_ASSERT(type >= PAC_TYPE_BEGIN);
      31     1619884 :         SMB_ASSERT(type < PAC_TYPE_END);
      32             : 
      33     1619884 :         return &pac_blobs->type_index[type - PAC_TYPE_BEGIN];
      34             : }
      35             : 
      36      195181 : static inline struct type_data *pac_blobs_get(struct pac_blobs *pac_blobs, size_t type)
      37             : {
      38      195181 :         size_t index = *pac_blobs_get_index(pac_blobs, type);
      39      195181 :         SMB_ASSERT(index < pac_blobs->num_types);
      40             : 
      41      195181 :         return &pac_blobs->type_blobs[index];
      42             : }
      43             : 
      44       99088 : krb5_error_code pac_blobs_from_krb5_pac(TALLOC_CTX *mem_ctx,
      45             :                                         krb5_context context,
      46             :                                         const krb5_const_pac pac,
      47             :                                         struct pac_blobs **pac_blobs)
      48             : {
      49       99088 :         krb5_error_code code = 0;
      50       99088 :         uint32_t *types = NULL;
      51       99088 :         struct pac_blobs *blobs = NULL;
      52        3316 :         size_t i;
      53             : 
      54       99088 :         SMB_ASSERT(pac_blobs != NULL);
      55       99088 :         *pac_blobs = NULL;
      56             : 
      57       99088 :         blobs = talloc(mem_ctx, struct pac_blobs);
      58       99088 :         if (blobs == NULL) {
      59           0 :                 code = ENOMEM;
      60           0 :                 goto out;
      61             :         }
      62             : 
      63       99088 :         *blobs = (struct pac_blobs) {};
      64             : 
      65             :         /* Initialize the array indices. */
      66     1981760 :         for (i = 0; i < ARRAY_SIZE(blobs->type_index); ++i) {
      67     1882672 :                 blobs->type_index[i] = SIZE_MAX;
      68             :         }
      69             : 
      70       99088 :         code = krb5_pac_get_types(context, pac, &blobs->num_types, &types);
      71       99088 :         if (code != 0) {
      72           0 :                 DBG_ERR("krb5_pac_get_types failed\n");
      73           0 :                 goto out;
      74             :         }
      75             : 
      76       99088 :         blobs->type_blobs = talloc_array(blobs, struct type_data, blobs->num_types);
      77       99088 :         if (blobs->type_blobs == NULL) {
      78           0 :                 DBG_ERR("Out of memory\n");
      79           0 :                 code = ENOMEM;
      80           0 :                 goto out;
      81             :         }
      82             : 
      83      891958 :         for (i = 0; i < blobs->num_types; ++i) {
      84      792870 :                 uint32_t type = types[i];
      85      792870 :                 size_t *type_index = NULL;
      86             : 
      87      792870 :                 blobs->type_blobs[i] = (struct type_data) {
      88             :                         .type = type,
      89             :                         .data = NULL,
      90             :                 };
      91             : 
      92      792870 :                 switch (type) {
      93             :                         /* PAC buffer types that we support. */
      94      792858 :                 case PAC_TYPE_LOGON_INFO:
      95             :                 case PAC_TYPE_CREDENTIAL_INFO:
      96             :                 case PAC_TYPE_SRV_CHECKSUM:
      97             :                 case PAC_TYPE_KDC_CHECKSUM:
      98             :                 case PAC_TYPE_LOGON_NAME:
      99             :                 case PAC_TYPE_CONSTRAINED_DELEGATION:
     100             :                 case PAC_TYPE_UPN_DNS_INFO:
     101             :                 case PAC_TYPE_CLIENT_CLAIMS_INFO:
     102             :                 case PAC_TYPE_DEVICE_INFO:
     103             :                 case PAC_TYPE_DEVICE_CLAIMS_INFO:
     104             :                 case PAC_TYPE_TICKET_CHECKSUM:
     105             :                 case PAC_TYPE_ATTRIBUTES_INFO:
     106             :                 case PAC_TYPE_REQUESTER_SID:
     107             :                 case PAC_TYPE_FULL_CHECKSUM:
     108      792858 :                         type_index = pac_blobs_get_index(blobs, type);
     109      792858 :                         if (*type_index != SIZE_MAX) {
     110           0 :                                 DBG_WARNING("PAC buffer type[%"PRIu32"] twice\n", type);
     111           0 :                                 code = EINVAL;
     112           0 :                                 goto out;
     113             :                         }
     114      792858 :                         *type_index = i;
     115             : 
     116      792858 :                         break;
     117          12 :                 default:
     118          12 :                         break;
     119             :                 }
     120             :         }
     121             : 
     122       99088 :         *pac_blobs = blobs;
     123       99088 :         blobs = NULL;
     124             : 
     125       99088 : out:
     126       99088 :         SAFE_FREE(types);
     127       99088 :         TALLOC_FREE(blobs);
     128       99088 :         return code;
     129             : }
     130             : 
     131      446636 : krb5_error_code _pac_blobs_ensure_exists(struct pac_blobs *pac_blobs,
     132             :                                          const uint32_t type,
     133             :                                          const char *name,
     134             :                                          const char *location,
     135             :                                          const char *function)
     136             : {
     137      446636 :         if (*pac_blobs_get_index(pac_blobs, type) == SIZE_MAX) {
     138           6 :                 DEBUGLF(DBGLVL_ERR, ("%s: %s missing\n", function, name), location, function);
     139           6 :                 return EINVAL;
     140             :         }
     141             : 
     142      431708 :         return 0;
     143             : }
     144             : 
     145      194596 : krb5_error_code _pac_blobs_replace_existing(struct pac_blobs *pac_blobs,
     146             :                                             const uint32_t type,
     147             :                                             const char *name,
     148             :                                             const DATA_BLOB *blob,
     149             :                                             const char *location,
     150             :                                             const char *function)
     151             : {
     152        6632 :         krb5_error_code code;
     153             : 
     154      194596 :         code = _pac_blobs_ensure_exists(pac_blobs,
     155             :                                         type,
     156             :                                         name,
     157             :                                         location,
     158             :                                         function);
     159      194596 :         if (code != 0) {
     160           0 :                 return code;
     161             :         }
     162             : 
     163      194596 :         pac_blobs_get(pac_blobs, type)->data = blob;
     164             : 
     165      194596 :         return 0;
     166             : }
     167             : 
     168      291894 : krb5_error_code pac_blobs_add_blob(struct pac_blobs *pac_blobs,
     169             :                                    const uint32_t type,
     170             :                                    const DATA_BLOB *blob)
     171             : {
     172      291894 :         size_t *index = NULL;
     173             : 
     174      291894 :         if (blob == NULL) {
     175      281361 :                 return 0;
     176             :         }
     177             : 
     178         585 :         index = pac_blobs_get_index(pac_blobs, type);
     179         585 :         if (*index == SIZE_MAX) {
     180         261 :                 struct type_data *type_blobs = NULL;
     181             : 
     182         261 :                 type_blobs = talloc_realloc(pac_blobs,
     183             :                                             pac_blobs->type_blobs,
     184             :                                             struct type_data,
     185             :                                             pac_blobs->num_types + 1);
     186         261 :                 if (type_blobs == NULL) {
     187           0 :                         DBG_ERR("Out of memory\n");
     188           0 :                         return ENOMEM;
     189             :                 }
     190             : 
     191         261 :                 pac_blobs->type_blobs = type_blobs;
     192         261 :                 *index = pac_blobs->num_types++;
     193             :         }
     194             : 
     195         585 :         *pac_blobs_get(pac_blobs, type) = (struct type_data) {
     196             :                 .type = type,
     197             :                 .data = blob,
     198             :         };
     199             : 
     200         585 :         return 0;
     201             : }
     202             : 
     203       41178 : void pac_blobs_remove_blob(struct pac_blobs *pac_blobs,
     204             :                            const uint32_t type)
     205             : {
     206       41178 :         struct type_data *type_blobs = NULL;
     207        1246 :         size_t found_index;
     208        1246 :         size_t i;
     209             : 
     210             :         /* Get the index of this PAC buffer type. */
     211       41178 :         found_index = *pac_blobs_get_index(pac_blobs, type);
     212       41178 :         if (found_index == SIZE_MAX) {
     213             :                 /* We don't have a PAC buffer of this type, so we're done. */
     214         292 :                 return;
     215             :         }
     216             : 
     217             :         /* Since the PAC buffer is present, there will be at least one type in the array. */
     218       40886 :         SMB_ASSERT(pac_blobs->num_types > 0);
     219             : 
     220             :         /* The index should be valid. */
     221       40886 :         SMB_ASSERT(found_index < pac_blobs->num_types);
     222             : 
     223             :         /*
     224             :          * Even though a consistent ordering of PAC buffers is not to be relied
     225             :          * upon, we must still maintain the ordering we are given.
     226             :          */
     227      143458 :         for (i = found_index; i < pac_blobs->num_types - 1; ++i) {
     228        3115 :                 size_t moved_type;
     229             : 
     230             :                 /* Shift each following element backwards by one. */
     231      102572 :                 pac_blobs->type_blobs[i] = pac_blobs->type_blobs[i + 1];
     232             : 
     233             :                 /* Mark the new position of the moved element in the index. */
     234      102572 :                 moved_type = pac_blobs->type_blobs[i].type;
     235      102572 :                 if (moved_type >= PAC_TYPE_BEGIN && moved_type < PAC_TYPE_END) {
     236      102560 :                         *pac_blobs_get_index(pac_blobs, moved_type) = i;
     237             :                 }
     238             :         }
     239             : 
     240             :         /* Mark the removed element as no longer present. */
     241       40886 :         *pac_blobs_get_index(pac_blobs, type) = SIZE_MAX;
     242             : 
     243             :         /* We do not free the removed data blob, as it may be statically allocated (e.g., a null blob). */
     244             : 
     245             :         /* Remove the last element from the array. */
     246       40886 :         type_blobs = talloc_realloc(pac_blobs,
     247             :                                     pac_blobs->type_blobs,
     248             :                                     struct type_data,
     249             :                                     --pac_blobs->num_types);
     250       40886 :         if (type_blobs != NULL) {
     251       40886 :                 pac_blobs->type_blobs = type_blobs;
     252             :         }
     253             : }

Generated by: LCOV version 1.14