LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/krb5 - pac.c (source / functions) Hit Total Coverage
Test: coverage report for vadcx-master-patch-75612 fe003de8 Lines: 837 1139 73.5 %
Date: 2024-02-29 22:57:05 Functions: 28 29 96.6 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2006 - 2017 Kungliga Tekniska Högskolan
       3             :  * (Royal Institute of Technology, Stockholm, Sweden).
       4             :  * All rights reserved.
       5             :  *
       6             :  * Redistribution and use in source and binary forms, with or without
       7             :  * modification, are permitted provided that the following conditions
       8             :  * are met:
       9             :  *
      10             :  * 1. Redistributions of source code must retain the above copyright
      11             :  *    notice, this list of conditions and the following disclaimer.
      12             :  *
      13             :  * 2. Redistributions in binary form must reproduce the above copyright
      14             :  *    notice, this list of conditions and the following disclaimer in the
      15             :  *    documentation and/or other materials provided with the distribution.
      16             :  *
      17             :  * 3. Neither the name of the Institute nor the names of its contributors
      18             :  *    may be used to endorse or promote products derived from this software
      19             :  *    without specific prior written permission.
      20             :  *
      21             :  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
      22             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      23             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      24             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
      25             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      26             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      27             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      28             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      29             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      30             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      31             :  * SUCH DAMAGE.
      32             :  */
      33             : 
      34             : #include "krb5_locl.h"
      35             : 
      36             : #include <heimbasepriv.h>
      37             : #include <wind.h>
      38             : #include <assert.h>
      39             : 
      40             : /*
      41             :  * https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-pac/3341cfa2-6ef5-42e0-b7bc-4544884bf399
      42             :  */
      43             : struct PAC_INFO_BUFFER {
      44             :     uint32_t type;          /* ULONG   ulType       in the original */
      45             :     uint32_t buffersize;    /* ULONG   cbBufferSize in the original */
      46             :     uint64_t offset;        /* ULONG64 Offset       in the original
      47             :                              * this being the offset from the beginning of the
      48             :                              * struct PACTYPE to the beginning of the buffer
      49             :                              * containing data of type ulType
      50             :                              */
      51             : };
      52             : 
      53             : /*
      54             :  * https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-pac/6655b92f-ab06-490b-845d-037e6987275f
      55             :  */
      56             : struct PACTYPE {
      57             :     uint32_t numbuffers;    /* named cBuffers of type ULONG in the original */
      58             :     uint32_t version;       /* Named Version  of type ULONG in the original */
      59             :     struct PAC_INFO_BUFFER buffers[1]; /* an ellipsis (...) in the original */
      60             : };
      61             : 
      62             : /*
      63             :  * A PAC starts with a PACTYPE header structure that is followed by an array of
      64             :  * numbuffers PAC_INFO_BUFFER structures, each of which points to a buffer
      65             :  * beyond the last PAC_INFO_BUFFER structures.
      66             :  */
      67             : 
      68             : struct krb5_pac_data {
      69             :     struct PACTYPE *pac;
      70             :     krb5_data data;
      71             :     struct PAC_INFO_BUFFER *server_checksum;
      72             :     struct PAC_INFO_BUFFER *privsvr_checksum;
      73             :     struct PAC_INFO_BUFFER *logon_name;
      74             :     struct PAC_INFO_BUFFER *upn_dns_info;
      75             :     struct PAC_INFO_BUFFER *ticket_checksum;
      76             :     struct PAC_INFO_BUFFER *attributes_info;
      77             :     struct PAC_INFO_BUFFER *full_checksum;
      78             :     krb5_data ticket_sign_data;
      79             : 
      80             :     /* PAC_UPN_DNS_INFO */
      81             :     krb5_principal upn_princ;
      82             :     uint32_t upn_flags;
      83             :     krb5_principal canon_princ;
      84             :     krb5_data sid;
      85             : 
      86             :     /* PAC_ATTRIBUTES_INFO */
      87             :     uint64_t pac_attributes;
      88             : 
      89             :     krb5_boolean is_trusted;
      90             : };
      91             : 
      92             : #define PAC_ALIGNMENT                   8
      93             : 
      94             : #define PACTYPE_SIZE                    8
      95             : #define PAC_INFO_BUFFER_SIZE            16
      96             : 
      97             : #define PAC_LOGON_INFO                  1
      98             : #define PAC_CREDENTIALS_INFO            2
      99             : #define PAC_SERVER_CHECKSUM             6
     100             : #define PAC_PRIVSVR_CHECKSUM            7
     101             : #define PAC_LOGON_NAME                  10
     102             : #define PAC_CONSTRAINED_DELEGATION      11
     103             : #define PAC_UPN_DNS_INFO                12
     104             : #define PAC_TICKET_CHECKSUM             16
     105             : #define PAC_ATTRIBUTES_INFO             17
     106             : #define PAC_REQUESTOR_SID               18
     107             : #define PAC_FULL_CHECKSUM               19
     108             : 
     109             : /* Flag in PAC_UPN_DNS_INFO */
     110             : #define PAC_EXTRA_LOGON_INFO_FLAGS_UPN_DEFAULTED        0x1
     111             : #define PAC_EXTRA_LOGON_INFO_FLAGS_HAS_SAM_NAME_AND_SID 0x2
     112             : 
     113             : #define CHECK(r,f,l)                                            \
     114             :         do {                                                    \
     115             :                 if (((r) = f ) != 0) {                          \
     116             :                         krb5_clear_error_message(context);      \
     117             :                         goto l;                                 \
     118             :                 }                                               \
     119             :         } while(0)
     120             : 
     121             : static const char zeros[PAC_ALIGNMENT];
     122             : 
     123             : static void HEIM_CALLCONV
     124      200161 : pac_dealloc(void *ctx)
     125             : {
     126      200161 :     krb5_pac pac = (krb5_pac)ctx;
     127             : 
     128      200161 :     krb5_data_free(&pac->data);
     129      200161 :     krb5_data_free(&pac->ticket_sign_data);
     130             : 
     131      200161 :     if (pac->upn_princ) {
     132       69904 :         free_Principal(pac->upn_princ);
     133       69904 :         free(pac->upn_princ);
     134             :     }
     135      200161 :     if (pac->canon_princ) {
     136       69904 :         free_Principal(pac->canon_princ);
     137       69904 :         free(pac->canon_princ);
     138             :     }
     139      200161 :     krb5_data_free(&pac->sid);
     140             : 
     141      200161 :     free(pac->pac);
     142      200161 : }
     143             : 
     144             : static const struct heim_type_data pac_object = {
     145             :     HEIM_TID_PAC,
     146             :     "heim-pac",
     147             :     NULL,
     148             :     pac_dealloc,
     149             :     NULL,
     150             :     NULL,
     151             :     NULL,
     152             :     NULL
     153             : };
     154             : 
     155             : /*
     156             :  * Returns the size of the PACTYPE header + the PAC_INFO_BUFFER array.  This is
     157             :  * also the end of the whole thing, and any offsets to buffers from
     158             :  * the PAC_INFO_BUFFER[] entries have to be beyond it.
     159             :  */
     160             : static krb5_error_code
     161      847241 : pac_header_size(krb5_context context, uint32_t num_buffers, uint32_t *result)
     162             : {
     163       28874 :     krb5_error_code ret;
     164       28874 :     uint32_t header_size;
     165             : 
     166             :     /* Guard against integer overflow */
     167      847241 :     if (num_buffers > UINT32_MAX / PAC_INFO_BUFFER_SIZE) {
     168           0 :         ret = EOVERFLOW;
     169           0 :         krb5_set_error_message(context, ret, "PAC has too many buffers");
     170           0 :         return ret;
     171             :     }
     172      847241 :     header_size = PAC_INFO_BUFFER_SIZE * num_buffers;
     173             : 
     174             :     /* Guard against integer overflow */
     175      847241 :     if (header_size > UINT32_MAX - PACTYPE_SIZE) {
     176           0 :         ret = EOVERFLOW;
     177           0 :         krb5_set_error_message(context, ret, "PAC has too many buffers");
     178           0 :         return ret;
     179             :     }
     180      847241 :     header_size += PACTYPE_SIZE;
     181             : 
     182      847241 :     *result = header_size;
     183             : 
     184      823582 :     return 0;
     185             : }
     186             : 
     187             : /* Output `size' + `addend' + padding for alignment if it doesn't overflow */
     188             : static krb5_error_code
     189     1643699 : pac_aligned_size(krb5_context context,
     190             :                  uint32_t size,
     191             :                  uint32_t addend,
     192             :                  uint32_t *aligned_size)
     193             : {
     194       60700 :     krb5_error_code ret;
     195             : 
     196     1704399 :     if (size > UINT32_MAX - addend ||
     197     1643699 :         (size + addend) > UINT32_MAX - (PAC_ALIGNMENT - 1)) {
     198           0 :         ret = EOVERFLOW;
     199           0 :         krb5_set_error_message(context, ret, "integer overrun");
     200           0 :         return ret;
     201             :     }
     202     1643699 :     size += addend;
     203     1643699 :     size += PAC_ALIGNMENT - 1;
     204     1643699 :     size &= ~(PAC_ALIGNMENT - 1);
     205     1643699 :     *aligned_size = size;
     206     1602037 :     return 0;
     207             : }
     208             : 
     209             : /*
     210             :  * HMAC-MD5 checksum over any key (needed for the PAC routines)
     211             :  */
     212             : 
     213             : static krb5_error_code
     214       24784 : HMAC_MD5_any_checksum(krb5_context context,
     215             :                       const krb5_keyblock *key,
     216             :                       const void *data,
     217             :                       size_t len,
     218             :                       unsigned usage,
     219             :                       Checksum *result)
     220             : {
     221           0 :     struct _krb5_key_data local_key;
     222           0 :     struct krb5_crypto_iov iov;
     223           0 :     krb5_error_code ret;
     224             : 
     225       24784 :     memset(&local_key, 0, sizeof(local_key));
     226             : 
     227       24784 :     ret = krb5_copy_keyblock(context, key, &local_key.key);
     228       24784 :     if (ret)
     229           0 :         return ret;
     230             : 
     231       24784 :     ret = krb5_data_alloc (&result->checksum, 16);
     232       24784 :     if (ret) {
     233           0 :         krb5_free_keyblock(context, local_key.key);
     234           0 :         return ret;
     235             :     }
     236             : 
     237       24784 :     result->cksumtype = CKSUMTYPE_HMAC_MD5;
     238       24784 :     iov.data.data = (void *)data;
     239       24784 :     iov.data.length = len;
     240       24784 :     iov.flags = KRB5_CRYPTO_TYPE_DATA;
     241             : 
     242       24784 :     ret = _krb5_HMAC_MD5_checksum(context, NULL, &local_key, usage, &iov, 1,
     243             :                                   result);
     244       24784 :     if (ret)
     245           0 :         krb5_data_free(&result->checksum);
     246             : 
     247       24784 :     krb5_free_keyblock(context, local_key.key);
     248       24784 :     return ret;
     249             : }
     250             : 
     251             : 
     252             : /*
     253             :  *
     254             :  */
     255             : 
     256             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     257      154684 : krb5_pac_parse(krb5_context context, const void *ptr, size_t len,
     258             :                krb5_pac *pac)
     259             : {
     260      154684 :     krb5_error_code ret = 0;
     261        3422 :     krb5_pac p;
     262      154684 :     krb5_storage *sp = NULL;
     263      154684 :     uint32_t i, num_buffers, version, header_size = 0;
     264      154684 :     uint32_t prev_start = 0;
     265      154684 :     uint32_t prev_end = 0;
     266             : 
     267      154684 :     *pac = NULL;
     268      154684 :     p = _heim_alloc_object(&pac_object, sizeof(*p));
     269      154684 :     if (p)
     270      154684 :         sp = krb5_storage_from_readonly_mem(ptr, len);
     271      154684 :     if (sp == NULL)
     272           0 :         ret = krb5_enomem(context);
     273      151262 :     if (ret == 0) {
     274      154684 :         krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
     275      154684 :         ret = krb5_ret_uint32(sp, &num_buffers);
     276             :     }
     277      154684 :     if (ret == 0)
     278      154684 :         ret = krb5_ret_uint32(sp, &version);
     279      154684 :     if (ret == 0 && num_buffers < 1)
     280           0 :         krb5_set_error_message(context, ret = EINVAL,
     281           0 :                                N_("PAC has too few buffers", ""));
     282      154684 :     if (ret == 0 && num_buffers > 1000)
     283           0 :         krb5_set_error_message(context, ret = EINVAL,
     284           0 :                                N_("PAC has too many buffers", ""));
     285      154684 :     if (ret == 0 && version != 0)
     286           0 :         krb5_set_error_message(context, ret = EINVAL,
     287           0 :                                N_("PAC has wrong version %d", ""),
     288             :                                (int)version);
     289      154684 :     if (ret == 0)
     290      154684 :         ret = pac_header_size(context, num_buffers, &header_size);
     291      154684 :     if (ret == 0 && header_size > len)
     292           0 :         krb5_set_error_message(context, ret = EOVERFLOW,
     293           0 :                                N_("PAC encoding invalid, would overflow buffers", ""));
     294      154684 :     if (ret == 0)
     295      154684 :         p->pac = calloc(1, header_size);
     296      154684 :     if (ret == 0 && p->pac == NULL)
     297           0 :         ret = krb5_enomem(context);
     298             : 
     299      154684 :     if (ret == 0) {
     300      154684 :         p->pac->numbuffers = num_buffers;
     301      154684 :         p->pac->version = version;
     302             :     }
     303             : 
     304     1391907 :     for (i = 0; ret == 0 && i < p->pac->numbuffers; i++) {
     305     1237223 :         ret = krb5_ret_uint32(sp, &p->pac->buffers[i].type);
     306     1237223 :         if (ret == 0)
     307     1237223 :             ret = krb5_ret_uint32(sp, &p->pac->buffers[i].buffersize);
     308     1237223 :         if (ret == 0)
     309     1237223 :             ret = krb5_ret_uint64(sp, &p->pac->buffers[i].offset);
     310     1237223 :         if (ret)
     311           0 :             break;
     312             : 
     313             :         /* Consistency checks (we don't check for wasted space) */
     314     1237223 :         if (p->pac->buffers[i].offset & (PAC_ALIGNMENT - 1)) {
     315           0 :             krb5_set_error_message(context, ret = EINVAL,
     316           0 :                                    N_("PAC out of alignment", ""));
     317           0 :             break;
     318             :         }
     319     1237223 :         if (p->pac->buffers[i].offset > len ||
     320     1237223 :             p->pac->buffers[i].buffersize > len ||
     321     1237223 :             len - p->pac->buffers[i].offset < p->pac->buffers[i].buffersize) {
     322           0 :             krb5_set_error_message(context, ret = EOVERFLOW,
     323           0 :                                    N_("PAC buffer overflow", ""));
     324           0 :             break;
     325             :         }
     326     1237223 :         if (p->pac->buffers[i].offset < header_size) {
     327           0 :             krb5_set_error_message(context, ret = EINVAL,
     328           0 :                                    N_("PAC offset inside header: %lu %lu", ""),
     329           0 :                                    (unsigned long)p->pac->buffers[i].offset,
     330             :                                    (unsigned long)header_size);
     331           0 :             break;
     332             :         }
     333             : 
     334             :         /*
     335             :          * We'd like to check for non-overlapping of buffers, but the buffers
     336             :          * need not be in the same order as the PAC_INFO_BUFFER[] entries
     337             :          * pointing to them!  To fully check for overlap we'd have to have an
     338             :          * O(N^2) loop after we parse all the PAC_INFO_BUFFER[].
     339             :          *
     340             :          * But we can check that each buffer does not overlap the previous
     341             :          * buffer.
     342             :          */
     343     1237223 :         if (prev_start) {
     344     1082539 :             if (p->pac->buffers[i].offset >= prev_start &&
     345     1082539 :                 p->pac->buffers[i].offset <  prev_end) {
     346           0 :                 krb5_set_error_message(context, ret = EINVAL,
     347           0 :                                        N_("PAC overlap", ""));
     348           0 :                 break;
     349             :             }
     350     1082539 :             if (p->pac->buffers[i].offset < prev_start &&
     351           0 :                 p->pac->buffers[i].offset +
     352           0 :                 p->pac->buffers[i].buffersize > prev_start) {
     353           0 :                 krb5_set_error_message(context, ret = EINVAL,
     354           0 :                                        N_("PAC overlap", ""));
     355           0 :                 break;
     356             :             }
     357             :         }
     358     1237223 :         prev_start = p->pac->buffers[i].offset;
     359     1237223 :         prev_end = p->pac->buffers[i].offset + p->pac->buffers[i].buffersize;
     360             : 
     361             :         /* Let's save pointers to buffers we'll need later */
     362     1237223 :         switch (p->pac->buffers[i].type) {
     363      154678 :         case PAC_SERVER_CHECKSUM:
     364      154678 :             if (p->server_checksum)
     365           0 :                 krb5_set_error_message(context, ret = EINVAL,
     366           0 :                                        N_("PAC has multiple server checksums", ""));
     367             :             else
     368      154678 :                 p->server_checksum = &p->pac->buffers[i];
     369      151256 :             break;
     370      154678 :         case PAC_PRIVSVR_CHECKSUM:
     371      154678 :             if (p->privsvr_checksum)
     372           0 :                 krb5_set_error_message(context, ret = EINVAL,
     373           0 :                                        N_("PAC has multiple KDC checksums", ""));
     374             :             else
     375      154678 :                 p->privsvr_checksum = &p->pac->buffers[i];
     376      151256 :             break;
     377      154684 :         case PAC_LOGON_NAME:
     378      154684 :             if (p->logon_name)
     379           0 :                 krb5_set_error_message(context, ret = EINVAL,
     380           0 :                                        N_("PAC has multiple logon names", ""));
     381             :             else
     382      154684 :                 p->logon_name = &p->pac->buffers[i];
     383      151262 :             break;
     384      154638 :         case PAC_UPN_DNS_INFO:
     385      154638 :             if (p->upn_dns_info)
     386           0 :                 krb5_set_error_message(context, ret = EINVAL,
     387           0 :                                        N_("PAC has multiple UPN DNS info buffers", ""));
     388             :             else
     389      154638 :                 p->upn_dns_info = &p->pac->buffers[i];
     390      151218 :             break;
     391      105572 :         case PAC_TICKET_CHECKSUM:
     392      105572 :             if (p->ticket_checksum)
     393           0 :                 krb5_set_error_message(context, ret = EINVAL,
     394           0 :                                        N_("PAC has multiple ticket checksums", ""));
     395             :             else
     396      105572 :                 p->ticket_checksum = &p->pac->buffers[i];
     397      103810 :             break;
     398       48964 :         case PAC_ATTRIBUTES_INFO:
     399       48964 :             if (p->attributes_info)
     400           0 :                 krb5_set_error_message(context, ret = EINVAL,
     401           0 :                                        N_("PAC has multiple attributes info buffers", ""));
     402             :             else
     403       48964 :                 p->attributes_info = &p->pac->buffers[i];
     404       47306 :             break;
     405      105572 :         case PAC_FULL_CHECKSUM:
     406      105572 :             if (p->full_checksum)
     407           0 :                 krb5_set_error_message(context, ret = EINVAL,
     408           0 :                                        N_("PAC has multiple full checksums", ""));
     409             :             else
     410      105572 :                 p->full_checksum = &p->pac->buffers[i];
     411      103810 :             break;
     412      349937 :         default: break;
     413             :         }
     414             :     }
     415             : 
     416      154684 :     if (ret == 0)
     417      154684 :         ret = krb5_data_copy(&p->data, ptr, len);
     418      154684 :     if (ret == 0) {
     419      154684 :         *pac = p;
     420      154684 :         p = NULL;
     421             :     }
     422      154684 :     if (sp)
     423      154684 :         krb5_storage_free(sp);
     424      154684 :     krb5_pac_free(context, p);
     425      154684 :     return ret;
     426             : }
     427             : 
     428             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     429       77702 : krb5_pac_init(krb5_context context, krb5_pac *pac)
     430             : {
     431        2828 :     krb5_error_code ret;
     432        2828 :     krb5_pac p;
     433             : 
     434       77702 :     p = _heim_alloc_object(&pac_object, sizeof(*p));
     435       77702 :     if (p == NULL) {
     436           0 :         return krb5_enomem(context);
     437             :     }
     438             : 
     439       77702 :     p->pac = calloc(1, sizeof(*p->pac));
     440       77702 :     if (p->pac == NULL) {
     441           0 :         krb5_pac_free(context, p);
     442           0 :         return krb5_enomem(context);
     443             :     }
     444             : 
     445       77702 :     ret = krb5_data_alloc(&p->data, PACTYPE_SIZE);
     446       77702 :     if (ret) {
     447           0 :         free (p->pac);
     448           0 :         krb5_pac_free(context, p);
     449           0 :         return krb5_enomem(context);
     450             :     }
     451       77702 :     memset(p->data.data, 0, p->data.length);
     452             : 
     453       77702 :     *pac = p;
     454       77702 :     return 0;
     455             : }
     456             : 
     457             : /**
     458             :  * Add a PAC buffer `nd' of type `type' to the pac `p'.
     459             :  *
     460             :  * @param context
     461             :  * @param p
     462             :  * @param type
     463             :  * @param nd
     464             :  *
     465             :  * @return 0 on success or a Kerberos or system error.
     466             :  */
     467             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     468      513745 : krb5_pac_add_buffer(krb5_context context, krb5_pac p,
     469             :                     uint32_t type, const krb5_data *nd)
     470             : {
     471       19038 :     krb5_error_code ret;
     472       19038 :     void *ptr;
     473      513745 :     size_t old_len = p->data.length;
     474       19038 :     uint32_t len, offset, header_size;
     475       19038 :     uint32_t i;
     476       19038 :     uint32_t num_buffers;
     477             : 
     478      513745 :     assert(nd->data != NULL);
     479             : 
     480      513745 :     num_buffers = p->pac->numbuffers;
     481      513745 :     ret = pac_header_size(context, num_buffers + 1, &header_size);
     482      513745 :     if (ret)
     483           0 :         return ret;
     484             : 
     485      513745 :     ptr = realloc(p->pac, header_size);
     486      513745 :     if (ptr == NULL)
     487           0 :         return krb5_enomem(context);
     488             : 
     489      513745 :     p->pac = ptr;
     490      513745 :     p->pac->buffers[num_buffers].type = 0;
     491      513745 :     p->pac->buffers[num_buffers].buffersize = 0;
     492      513745 :     p->pac->buffers[num_buffers].offset = 0;
     493             : 
     494             :     /*
     495             :      * Check that we can adjust all the buffer offsets in the existing
     496             :      * PAC_INFO_BUFFERs, since changing the size of PAC_INFO_BUFFER[] means
     497             :      * changing the offsets of buffers following that array.
     498             :      *
     499             :      * We don't adjust them until we can't fail.
     500             :      */
     501     2003037 :     for (i = 0; i < num_buffers; i++) {
     502     1489292 :         if (p->pac->buffers[i].offset > UINT32_MAX - PAC_INFO_BUFFER_SIZE) {
     503           0 :             krb5_set_error_message(context, ret = EOVERFLOW,
     504             :                                    "too many / too large PAC buffers");
     505           0 :             return ret;
     506             :         }
     507             :     }
     508             : 
     509             :     /*
     510             :      * The new buffer's offset must be past the end of the buffers we have
     511             :      * (p->data), which is the sum of the header and p->data.length.
     512             :      */
     513             : 
     514             :     /* Set offset = p->data.length + PAC_INFO_BUFFER_SIZE + alignment */
     515      513745 :     ret = pac_aligned_size(context, p->data.length, PAC_INFO_BUFFER_SIZE, &offset);
     516      494707 :     if (ret == 0)
     517             :         /* Set the new length = offset + nd->length + alignment */
     518      513745 :         ret = pac_aligned_size(context, offset, nd->length, &len);
     519      513745 :     if (ret) {
     520           0 :         krb5_set_error_message(context, ret, "PAC buffer too large");
     521           0 :         return ret;
     522             :     }
     523      513745 :     ret = krb5_data_realloc(&p->data, len);
     524      513745 :     if (ret) {
     525           0 :         krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
     526           0 :         return ret;
     527             :     }
     528             : 
     529             :     /* Zero out the new allocation to zero out any padding */
     530      513745 :     memset((char *)p->data.data + old_len, 0, len - old_len);
     531             : 
     532      513745 :     p->pac->buffers[num_buffers].type = type;
     533      513745 :     p->pac->buffers[num_buffers].buffersize = nd->length;
     534      513745 :     p->pac->buffers[num_buffers].offset = offset;
     535             : 
     536             :     /* Adjust all the buffer offsets in the existing PAC_INFO_BUFFERs now */
     537     2003037 :     for (i = 0; i < num_buffers; i++)
     538     1489292 :         p->pac->buffers[i].offset += PAC_INFO_BUFFER_SIZE;
     539             : 
     540             :     /*
     541             :      * Make place for new PAC INFO BUFFER header
     542             :      */
     543      513745 :     header_size -= PAC_INFO_BUFFER_SIZE;
     544      513745 :     memmove((unsigned char *)p->data.data + header_size + PAC_INFO_BUFFER_SIZE,
     545      513745 :             (unsigned char *)p->data.data + header_size ,
     546             :             old_len - header_size);
     547             :     /* Clear the space where we would put the new PAC_INFO_BUFFER[] element */
     548      513745 :     memset((unsigned char *)p->data.data + header_size, 0,
     549             :            PAC_INFO_BUFFER_SIZE);
     550             : 
     551             :     /*
     552             :      * Copy in new data part
     553             :      */
     554      513745 :     memcpy((unsigned char *)p->data.data + offset, nd->data, nd->length);
     555      513745 :     p->pac->numbuffers += 1;
     556      513745 :     return 0;
     557             : }
     558             : 
     559             : /**
     560             :  * Get the PAC buffer of specific type from the pac.
     561             :  *
     562             :  * @param context Kerberos 5 context.
     563             :  * @param p the pac structure returned by krb5_pac_parse().
     564             :  * @param type type of buffer to get
     565             :  * @param data return data, free with krb5_data_free().
     566             :  *
     567             :  * @return Returns 0 to indicate success, ENOENT to indicate that a buffer of
     568             :  * the given type was not found, or a Kerberos or system error code.
     569             :  *
     570             :  * @ingroup krb5_pac
     571             :  */
     572             : 
     573             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     574      521061 : krb5_pac_get_buffer(krb5_context context, krb5_const_pac p,
     575             :                     uint32_t type, krb5_data *data)
     576             : {
     577       15290 :     krb5_error_code ret;
     578       15290 :     uint32_t i;
     579             : 
     580     2247864 :     for (i = 0; i < p->pac->numbuffers; i++) {
     581     2194607 :         size_t len = p->pac->buffers[i].buffersize;
     582     2194607 :         size_t offset = p->pac->buffers[i].offset;
     583             : 
     584     2194607 :         if (p->pac->buffers[i].type != type)
     585     1726803 :             continue;
     586             : 
     587      467804 :         if (!data)
     588       46285 :             return 0;
     589             : 
     590      419861 :         ret = krb5_data_copy(data, (unsigned char *)p->data.data + offset, len);
     591      419861 :         if (ret)
     592           0 :             krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
     593      407114 :         return ret;
     594             :     }
     595       53257 :     krb5_set_error_message(context, ENOENT, "No PAC buffer of type %lu was found",
     596             :                            (unsigned long)type);
     597       53257 :     return ENOENT;
     598             : }
     599             : 
     600             : static const struct {
     601             :     uint32_t type;
     602             :     krb5_data name;
     603             : } pac_buffer_name_map[] = {
     604             : #define PAC_MAP_ENTRY(type, name) { PAC_##type, { sizeof(name) - 1, name } }
     605             :     PAC_MAP_ENTRY(LOGON_INFO,               "logon-info"      ),
     606             :     PAC_MAP_ENTRY(CREDENTIALS_INFO,         "credentials-info"  ),
     607             :     PAC_MAP_ENTRY(SERVER_CHECKSUM,          "server-checksum"   ),
     608             :     PAC_MAP_ENTRY(PRIVSVR_CHECKSUM,         "privsvr-checksum"  ),
     609             :     PAC_MAP_ENTRY(LOGON_NAME,               "client-info"     ),
     610             :     PAC_MAP_ENTRY(CONSTRAINED_DELEGATION,   "delegation-info"   ),
     611             :     PAC_MAP_ENTRY(UPN_DNS_INFO,             "upn-dns-info"    ),
     612             :     PAC_MAP_ENTRY(TICKET_CHECKSUM,          "ticket-checksum"   ),
     613             :     PAC_MAP_ENTRY(ATTRIBUTES_INFO,          "attributes-info"   ),
     614             :     PAC_MAP_ENTRY(REQUESTOR_SID,            "requestor-sid"   )
     615             : };
     616             : 
     617             : /*
     618             :  *
     619             :  */
     620             : 
     621             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     622           0 : _krb5_pac_get_buffer_by_name(krb5_context context, krb5_const_pac p,
     623             :                              const krb5_data *name, krb5_data *data)
     624             : {
     625           0 :     size_t i;
     626             : 
     627           0 :     for (i = 0;
     628           0 :          i < sizeof(pac_buffer_name_map) / sizeof(pac_buffer_name_map[0]);
     629           0 :          i++) {
     630           0 :         if (krb5_data_cmp(name, &pac_buffer_name_map[i].name) == 0)
     631           0 :             return krb5_pac_get_buffer(context, p, pac_buffer_name_map[i].type, data);
     632             :     }
     633             : 
     634           0 :     krb5_set_error_message(context, ENOENT, "No PAC buffer with name %.*s was found",
     635           0 :                            (int)name->length, (char *)name->data);
     636           0 :     return ENOENT;
     637             : }
     638             : 
     639             : /*
     640             :  *
     641             :  */
     642             : 
     643             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     644       96280 : krb5_pac_get_types(krb5_context context,
     645             :                    krb5_const_pac p,
     646             :                    size_t *len,
     647             :                    uint32_t **types)
     648             : {
     649        3316 :     size_t i;
     650             : 
     651       96280 :     *types = calloc(p->pac->numbuffers, sizeof(**types));
     652       96280 :     if (*types == NULL) {
     653           0 :         *len = 0;
     654           0 :         return krb5_enomem(context);
     655             :     }
     656      866686 :     for (i = 0; i < p->pac->numbuffers; i++)
     657      770406 :         (*types)[i] = p->pac->buffers[i].type;
     658       96280 :     *len = p->pac->numbuffers;
     659             : 
     660       96280 :     return 0;
     661             : }
     662             : 
     663             : /*
     664             :  *
     665             :  */
     666             : 
     667             : KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
     668      437165 : krb5_pac_is_trusted(krb5_const_pac p)
     669             : {
     670      437165 :     return p->is_trusted;
     671             : }
     672             : 
     673             : /*
     674             :  *
     675             :  */
     676             : 
     677             : KRB5_LIB_FUNCTION void KRB5_LIB_CALL
     678       49143 : krb5_pac_set_trusted(krb5_pac p, krb5_boolean is_trusted)
     679             : {
     680       49143 :     p->is_trusted = is_trusted;
     681       49143 : }
     682             : 
     683             : /*
     684             :  *
     685             :  */
     686             : 
     687             : /*
     688             :  *
     689             :  */
     690             : 
     691             : KRB5_LIB_FUNCTION void KRB5_LIB_CALL
     692      437879 : krb5_pac_free(krb5_context context, krb5_pac pac)
     693             : {
     694      437879 :     heim_release(pac);
     695      437879 : }
     696             : 
     697             : /*
     698             :  *
     699             :  */
     700             : 
     701             : static krb5_error_code
     702      102702 : verify_checksum(krb5_context context,
     703             :                 const struct PAC_INFO_BUFFER *sig,
     704             :                 const krb5_data *data,
     705             :                 void *ptr, size_t len,
     706             :                 const krb5_keyblock *key,
     707             :                 krb5_boolean strict_cksumtype_match)
     708             : {
     709      102702 :     krb5_storage *sp = NULL;
     710        2539 :     uint32_t type;
     711        2539 :     krb5_error_code ret;
     712        2539 :     Checksum cksum;
     713        2539 :     size_t cksumsize;
     714             : 
     715      102702 :     memset(&cksum, 0, sizeof(cksum));
     716             : 
     717      105241 :     sp = krb5_storage_from_mem((char *)data->data + sig->offset,
     718      102702 :                                sig->buffersize);
     719      102702 :     if (sp == NULL)
     720           0 :         return krb5_enomem(context);
     721             : 
     722      102702 :     krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
     723             : 
     724      102702 :     CHECK(ret, krb5_ret_uint32(sp, &type), out);
     725      102702 :     cksum.cksumtype = type;
     726             : 
     727      102702 :     ret = krb5_checksumsize(context, type, &cksumsize);
     728      102702 :     if (ret)
     729          12 :         goto out;
     730             : 
     731             :     /* Allow for RODCIdentifier trailer, see MS-PAC 2.8 */
     732      102690 :     if (cksumsize > (sig->buffersize - krb5_storage_seek(sp, 0, SEEK_CUR))) {
     733           0 :         ret = EINVAL;
     734           0 :         goto out;
     735             :     }
     736      102690 :     cksum.checksum.length = cksumsize;
     737      102690 :     cksum.checksum.data = malloc(cksum.checksum.length);
     738      102690 :     if (cksum.checksum.data == NULL) {
     739           0 :         ret = krb5_enomem(context);
     740           0 :         goto out;
     741             :     }
     742      102690 :     ret = krb5_storage_read(sp, cksum.checksum.data, cksum.checksum.length);
     743      102690 :     if (ret != (int)cksum.checksum.length) {
     744           0 :         ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
     745           0 :         krb5_set_error_message(context, ret, "PAC checksum missing checksum");
     746           0 :         goto out;
     747             :     }
     748             : 
     749      102690 :     if (!krb5_checksum_is_keyed(context, cksum.cksumtype)) {
     750          24 :         ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
     751          24 :         krb5_set_error_message(context, ret, "Checksum type %d not keyed",
     752          24 :                                cksum.cksumtype);
     753          24 :         goto out;
     754             :     }
     755             : 
     756             :     /* If the checksum is HMAC-MD5, the checksum type is not tied to
     757             :      * the key type, instead the HMAC-MD5 checksum is applied blindly
     758             :      * on whatever key is used for this connection, avoiding issues
     759             :      * with unkeyed checksums on des-cbc-md5 and des-cbc-crc.  See
     760             :      * http://comments.gmane.org/gmane.comp.encryption.kerberos.devel/8743
     761             :      * for the same issue in MIT, and
     762             :      * http://blogs.msdn.com/b/openspecification/archive/2010/01/01/verifying-the-server-signature-in-kerberos-privilege-account-certificate.aspx
     763             :      * for Microsoft's explanation */
     764             : 
     765      110593 :     if (cksum.cksumtype == CKSUMTYPE_HMAC_MD5 && !strict_cksumtype_match) {
     766           0 :         Checksum local_checksum;
     767             : 
     768        7927 :         memset(&local_checksum, 0, sizeof(local_checksum));
     769             : 
     770        7927 :         ret = HMAC_MD5_any_checksum(context, key, ptr, len,
     771             :                                     KRB5_KU_OTHER_CKSUM, &local_checksum);
     772             : 
     773        7927 :         if (ret != 0 || krb5_data_ct_cmp(&local_checksum.checksum, &cksum.checksum) != 0) {
     774           4 :             ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
     775           4 :             krb5_set_error_message(context, ret,
     776           4 :                                    N_("PAC integrity check failed for "
     777             :                                       "hmac-md5 checksum", ""));
     778             :         }
     779        7927 :         krb5_data_free(&local_checksum.checksum);
     780             : 
     781             :    } else {
     782       94739 :         krb5_crypto crypto = NULL;
     783             : 
     784       94739 :         ret = krb5_crypto_init(context, key, 0, &crypto);
     785       94739 :         if (ret)
     786           0 :                 goto out;
     787             : 
     788       94739 :         ret = krb5_verify_checksum(context, crypto, KRB5_KU_OTHER_CKSUM,
     789             :                                    ptr, len, &cksum);
     790       94739 :         krb5_crypto_destroy(context, crypto);
     791             :     }
     792      102666 :     free(cksum.checksum.data);
     793      102666 :     krb5_storage_free(sp);
     794             : 
     795      102666 :     return ret;
     796             : 
     797          36 : out:
     798          36 :     if (cksum.checksum.data)
     799          24 :         free(cksum.checksum.data);
     800          36 :     if (sp)
     801          36 :         krb5_storage_free(sp);
     802          36 :     return ret;
     803             : }
     804             : 
     805             : static krb5_error_code
     806      197218 : create_checksum(krb5_context context,
     807             :                 const krb5_keyblock *key,
     808             :                 uint32_t cksumtype,
     809             :                 void *data, size_t datalen,
     810             :                 void *sig, size_t siglen)
     811             : {
     812      197218 :     krb5_crypto crypto = NULL;
     813        6902 :     krb5_error_code ret;
     814        6902 :     Checksum cksum;
     815             : 
     816             :     /* If the checksum is HMAC-MD5, the checksum type is not tied to
     817             :      * the key type, instead the HMAC-MD5 checksum is applied blindly
     818             :      * on whatever key is used for this connection, avoiding issues
     819             :      * with unkeyed checksums on des-cbc-md5 and des-cbc-crc.  See
     820             :      * http://comments.gmane.org/gmane.comp.encryption.kerberos.devel/8743
     821             :      * for the same issue in MIT, and
     822             :      * http://blogs.msdn.com/b/openspecification/archive/2010/01/01/verifying-the-server-signature-in-kerberos-privilege-account-certificate.aspx
     823             :      * for Microsoft's explaination */
     824             : 
     825      197218 :     if (cksumtype == (uint32_t)CKSUMTYPE_HMAC_MD5) {
     826       16857 :         ret = HMAC_MD5_any_checksum(context, key, data, datalen,
     827             :                                     KRB5_KU_OTHER_CKSUM, &cksum);
     828       16857 :         if (ret)
     829           0 :             return ret;
     830             :     } else {
     831      180361 :         ret = krb5_crypto_init(context, key, 0, &crypto);
     832      180361 :         if (ret)
     833           0 :             return ret;
     834             : 
     835      180361 :         ret = krb5_create_checksum(context, crypto, KRB5_KU_OTHER_CKSUM, 0,
     836             :                                    data, datalen, &cksum);
     837      180361 :         krb5_crypto_destroy(context, crypto);
     838      180361 :         if (ret)
     839           0 :             return ret;
     840             :     }
     841      197218 :     if (cksum.checksum.length != siglen) {
     842           0 :         krb5_set_error_message(context, EINVAL, "pac checksum wrong length");
     843           0 :         free_Checksum(&cksum);
     844           0 :         return EINVAL;
     845             :     }
     846             : 
     847      197218 :     memcpy(sig, cksum.checksum.data, siglen);
     848      197218 :     free_Checksum(&cksum);
     849             : 
     850      197218 :     return 0;
     851             : }
     852             : 
     853             : static krb5_error_code
     854      102112 : parse_upn_dns_info(krb5_context context,
     855             :                    const struct PAC_INFO_BUFFER *upndnsinfo,
     856             :                    const krb5_data *data,
     857             :                    krb5_principal *upn_princ,
     858             :                    uint32_t *flags,
     859             :                    krb5_principal *canon_princ,
     860             :                    krb5_data *sid)
     861             : {
     862        2539 :     krb5_error_code ret;
     863      102112 :     krb5_storage *sp = NULL;
     864        2539 :     uint16_t upn_length, upn_offset;
     865        2539 :     uint16_t dns_domain_name_length, dns_domain_name_offset;
     866        2539 :     uint16_t canon_princ_length, canon_princ_offset;
     867        2539 :     uint16_t sid_length, sid_offset;
     868      102112 :     char *upn = NULL;
     869      102112 :     char *dns_domain_name = NULL;
     870      102112 :     char *sam_name = NULL;
     871             : 
     872      102112 :     *upn_princ = NULL;
     873      102112 :     *flags = 0;
     874      102112 :     *canon_princ = NULL;
     875      102112 :     krb5_data_zero(sid);
     876             : 
     877      104651 :     sp = krb5_storage_from_readonly_mem((const char *)data->data + upndnsinfo->offset,
     878      102112 :                                         upndnsinfo->buffersize);
     879      102112 :     if (sp == NULL)
     880           0 :         return krb5_enomem(context);
     881             : 
     882      102112 :     krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
     883             : 
     884      102112 :     CHECK(ret, krb5_ret_uint16(sp, &upn_length), out);
     885      102112 :     CHECK(ret, krb5_ret_uint16(sp, &upn_offset), out);
     886      102112 :     CHECK(ret, krb5_ret_uint16(sp, &dns_domain_name_length), out);
     887      102112 :     CHECK(ret, krb5_ret_uint16(sp, &dns_domain_name_offset), out);
     888      102112 :     CHECK(ret, krb5_ret_uint32(sp, flags), out);
     889             : 
     890      102112 :     if (*flags & PAC_EXTRA_LOGON_INFO_FLAGS_HAS_SAM_NAME_AND_SID) {
     891      102112 :         CHECK(ret, krb5_ret_uint16(sp, &canon_princ_length), out);
     892      102112 :         CHECK(ret, krb5_ret_uint16(sp, &canon_princ_offset), out);
     893      102112 :         CHECK(ret, krb5_ret_uint16(sp, &sid_length), out);
     894      102112 :         CHECK(ret, krb5_ret_uint16(sp, &sid_offset), out);
     895             :     } else {
     896           0 :         canon_princ_length = canon_princ_offset = 0;
     897           0 :         sid_length = sid_offset = 0;
     898             :     }
     899             : 
     900      102112 :     if (upn_offset) {
     901      102112 :         CHECK(ret, _krb5_ret_utf8_from_ucs2le_at_offset(sp, upn_offset,
     902             :                                                         upn_length, &upn), out);
     903             :     }
     904      102112 :     CHECK(ret, _krb5_ret_utf8_from_ucs2le_at_offset(sp, dns_domain_name_offset,
     905             :                                                     dns_domain_name_length, &dns_domain_name), out);
     906      102112 :     if ((*flags & PAC_EXTRA_LOGON_INFO_FLAGS_HAS_SAM_NAME_AND_SID) && canon_princ_offset) {
     907      102112 :         CHECK(ret, _krb5_ret_utf8_from_ucs2le_at_offset(sp, canon_princ_offset,
     908             :                                                         canon_princ_length, &sam_name), out);
     909             :     }
     910             : 
     911      102112 :     if (upn_offset) {
     912      102112 :         ret = krb5_parse_name_flags(context,
     913             :                                     upn,
     914             :                                     KRB5_PRINCIPAL_PARSE_ENTERPRISE |
     915             :                                     KRB5_PRINCIPAL_PARSE_NO_DEF_REALM,
     916             :                                     upn_princ);
     917      102112 :         if (ret)
     918           0 :             goto out;
     919             : 
     920      102112 :         ret = krb5_principal_set_realm(context, *upn_princ, dns_domain_name);
     921      102112 :         if (ret)
     922           0 :             goto out;
     923             :     }
     924             : 
     925      102112 :     if (canon_princ_offset) {
     926      102112 :         ret = krb5_parse_name_flags(context,
     927             :                                     sam_name,
     928             :                                     KRB5_PRINCIPAL_PARSE_NO_REALM |
     929             :                                     KRB5_PRINCIPAL_PARSE_NO_DEF_REALM,
     930             :                                     canon_princ);
     931      102112 :         if (ret)
     932           0 :             goto out;
     933             : 
     934      102112 :         ret = krb5_principal_set_realm(context, *canon_princ, dns_domain_name);
     935      102112 :         if (ret)
     936           0 :             goto out;
     937             :     }
     938             : 
     939      102112 :     if (sid_offset)
     940      102112 :         CHECK(ret, _krb5_ret_data_at_offset(sp, sid_offset, sid_length, sid), out);
     941             : 
     942      102112 : out:
     943      102112 :     free(upn);
     944      102112 :     free(dns_domain_name);
     945      102112 :     free(sam_name);
     946             : 
     947      102112 :     krb5_storage_free(sp);
     948             : 
     949      102112 :     return ret;
     950             : }
     951             : 
     952             : /*
     953             :  *
     954             :  */
     955             : 
     956             : #define NTTIME_EPOCH 0x019DB1DED53E8000LL
     957             : 
     958             : static uint64_t
     959      179804 : unix2nttime(time_t unix_time)
     960             : {
     961        5367 :     long long wt;
     962      179804 :     wt = unix_time * (uint64_t)10000000 + (uint64_t)NTTIME_EPOCH;
     963      179804 :     return wt;
     964             : }
     965             : 
     966             : static krb5_error_code
     967      102180 : verify_logonname(krb5_context context,
     968             :                  const struct PAC_INFO_BUFFER *logon_name,
     969             :                  const krb5_data *data,
     970             :                  time_t authtime,
     971             :                  krb5_const_principal principal)
     972             : {
     973        2539 :     krb5_error_code ret;
     974        2539 :     uint32_t time1, time2;
     975      102180 :     krb5_storage *sp = NULL;
     976        2539 :     uint16_t len;
     977      102180 :     char *s = NULL;
     978      102180 :     char *principal_string = NULL;
     979      102180 :     char *logon_string = NULL;
     980             : 
     981      104719 :     sp = krb5_storage_from_readonly_mem((const char *)data->data + logon_name->offset,
     982      102180 :                                         logon_name->buffersize);
     983      102180 :     if (sp == NULL)
     984           0 :         return krb5_enomem(context);
     985             : 
     986      102180 :     krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
     987             : 
     988      102180 :     CHECK(ret, krb5_ret_uint32(sp, &time1), out);
     989      102180 :     CHECK(ret, krb5_ret_uint32(sp, &time2), out);
     990             : 
     991             :     {
     992        2539 :         uint64_t t1, t2;
     993      102180 :         t1 = unix2nttime(authtime);
     994      102180 :         t2 = ((uint64_t)time2 << 32) | time1;
     995             :         /*
     996             :          * When neither the ticket nor the PAC set an explicit authtime,
     997             :          * both times are zero, but relative to different time scales.
     998             :          * So we must compare "not set" values without converting to a
     999             :          * common time reference.
    1000             :          */
    1001      102180 :         if (t1 != t2 && (t2 != 0 && authtime != 0)) {
    1002           0 :             krb5_storage_free(sp);
    1003           0 :             krb5_set_error_message(context, EINVAL, "PAC timestamp mismatch");
    1004           0 :             return EINVAL;
    1005             :         }
    1006             :     }
    1007      102180 :     CHECK(ret, krb5_ret_uint16(sp, &len), out);
    1008      102180 :     if (len == 0) {
    1009           0 :         krb5_storage_free(sp);
    1010           0 :         krb5_set_error_message(context, EINVAL, "PAC logon name length missing");
    1011           0 :         return EINVAL;
    1012             :     }
    1013             : 
    1014      102180 :     s = malloc(len);
    1015      102180 :     if (s == NULL) {
    1016           0 :         krb5_storage_free(sp);
    1017           0 :         return krb5_enomem(context);
    1018             :     }
    1019      102180 :     ret = krb5_storage_read(sp, s, len);
    1020      102180 :     if (ret != len) {
    1021           0 :         free(s);
    1022           0 :         krb5_storage_free(sp);
    1023           0 :         krb5_set_error_message(context, EINVAL, "Failed to read PAC logon name");
    1024           0 :         return EINVAL;
    1025             :     }
    1026      102180 :     krb5_storage_free(sp);
    1027             :     {
    1028      102180 :         size_t ucs2len = len / 2;
    1029        2539 :         uint16_t *ucs2;
    1030        2539 :         size_t u8len;
    1031      102180 :         unsigned int flags = WIND_RW_LE;
    1032             : 
    1033      102180 :         ucs2 = malloc(sizeof(ucs2[0]) * ucs2len);
    1034      102180 :         if (ucs2 == NULL) {
    1035           0 :             free(s);
    1036           0 :             return krb5_enomem(context);
    1037             :         }
    1038             : 
    1039      102180 :         ret = wind_ucs2read(s, len, &flags, ucs2, &ucs2len);
    1040      102180 :         free(s);
    1041      102180 :         if (ret) {
    1042           0 :             free(ucs2);
    1043           0 :             krb5_set_error_message(context, ret, "Failed to convert string to UCS-2");
    1044           0 :             return ret;
    1045             :         }
    1046      102180 :         ret = wind_ucs2utf8_length(ucs2, ucs2len, &u8len);
    1047      102180 :         if (ret) {
    1048           0 :             free(ucs2);
    1049           0 :             krb5_set_error_message(context, ret, "Failed to count length of UCS-2 string");
    1050           0 :             return ret;
    1051             :         }
    1052      102180 :         u8len += 1; /* Add space for NUL */
    1053      102180 :         logon_string = malloc(u8len);
    1054      102180 :         if (logon_string == NULL) {
    1055           0 :             free(ucs2);
    1056           0 :             return krb5_enomem(context);
    1057             :         }
    1058      102180 :         ret = wind_ucs2utf8(ucs2, ucs2len, logon_string, &u8len);
    1059      102180 :         free(ucs2);
    1060      102180 :         if (ret) {
    1061           0 :             free(logon_string);
    1062           0 :             krb5_set_error_message(context, ret, "Failed to convert to UTF-8");
    1063           0 :             return ret;
    1064             :         }
    1065             :     }
    1066      102180 :     ret = krb5_unparse_name_flags(context, principal,
    1067             :                                   KRB5_PRINCIPAL_UNPARSE_NO_REALM |
    1068             :                                   KRB5_PRINCIPAL_UNPARSE_DISPLAY,
    1069             :                                   &principal_string);
    1070      102180 :     if (ret) {
    1071           0 :         free(logon_string);
    1072           0 :         return ret;
    1073             :     }
    1074             : 
    1075      102180 :     if (strcmp(logon_string, principal_string) != 0) {
    1076           0 :         ret = EINVAL;
    1077           0 :         krb5_set_error_message(context, ret, "PAC logon name [%s] mismatch principal name [%s]",
    1078             :                                logon_string, principal_string);
    1079             :     }
    1080      102180 :     free(logon_string);
    1081      102180 :     free(principal_string);
    1082      102180 :     return ret;
    1083           0 : out:
    1084           0 :     krb5_storage_free(sp);
    1085           0 :     return ret;
    1086             : }
    1087             : 
    1088             : /*
    1089             :  *
    1090             :  */
    1091             : 
    1092             : static krb5_error_code
    1093       77624 : build_logon_name(krb5_context context,
    1094             :                  time_t authtime,
    1095             :                  krb5_const_principal principal,
    1096             :                  krb5_data *logon)
    1097             : {
    1098        2828 :     krb5_error_code ret;
    1099        2828 :     krb5_storage *sp;
    1100        2828 :     uint64_t t;
    1101       77624 :     char *s, *s2 = NULL;
    1102        2828 :     size_t s2_len;
    1103             : 
    1104       77624 :     t = unix2nttime(authtime);
    1105             : 
    1106       77624 :     krb5_data_zero(logon);
    1107             : 
    1108       77624 :     sp = krb5_storage_emem();
    1109       77624 :     if (sp == NULL)
    1110           0 :         return krb5_enomem(context);
    1111             : 
    1112       77624 :     krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
    1113             : 
    1114       77624 :     CHECK(ret, krb5_store_uint32(sp, t & 0xffffffff), out);
    1115       77624 :     CHECK(ret, krb5_store_uint32(sp, t >> 32), out);
    1116             : 
    1117       77624 :     ret = krb5_unparse_name_flags(context, principal,
    1118             :                                   KRB5_PRINCIPAL_UNPARSE_NO_REALM |
    1119             :                                   KRB5_PRINCIPAL_UNPARSE_DISPLAY,
    1120             :                                   &s);
    1121       77624 :     if (ret)
    1122           0 :         goto out;
    1123             : 
    1124             :     {
    1125        2828 :         size_t ucs2_len;
    1126        2828 :         uint16_t *ucs2;
    1127        2828 :         unsigned int flags;
    1128             : 
    1129       77624 :         ret = wind_utf8ucs2_length(s, &ucs2_len);
    1130       77624 :         if (ret) {
    1131           0 :             krb5_set_error_message(context, ret, "Principal %s is not valid UTF-8", s);
    1132           0 :             free(s);
    1133           0 :             return ret;
    1134             :         }
    1135             : 
    1136       77624 :         ucs2 = malloc(sizeof(ucs2[0]) * ucs2_len);
    1137       77624 :         if (ucs2 == NULL) {
    1138           0 :             free(s);
    1139           0 :             return krb5_enomem(context);
    1140             :         }
    1141             : 
    1142       77624 :         ret = wind_utf8ucs2(s, ucs2, &ucs2_len);
    1143       77624 :         if (ret) {
    1144           0 :             free(ucs2);
    1145           0 :             krb5_set_error_message(context, ret, "Principal %s is not valid UTF-8", s);
    1146           0 :             free(s);
    1147           0 :             return ret;
    1148             :         } else
    1149       77624 :             free(s);
    1150             : 
    1151       77624 :         s2_len = (ucs2_len + 1) * 2;
    1152       77624 :         s2 = malloc(s2_len);
    1153       77624 :         if (s2 == NULL) {
    1154           0 :             free(ucs2);
    1155           0 :             return krb5_enomem(context);
    1156             :         }
    1157             : 
    1158       77624 :         flags = WIND_RW_LE;
    1159       77624 :         ret = wind_ucs2write(ucs2, ucs2_len,
    1160             :                              &flags, s2, &s2_len);
    1161       77624 :         free(ucs2);
    1162       77624 :         if (ret) {
    1163           0 :             free(s2);
    1164           0 :             krb5_set_error_message(context, ret, "Failed to write to UCS-2 buffer");
    1165           0 :             return ret;
    1166             :         }
    1167             : 
    1168             :         /*
    1169             :          * we do not want zero termination
    1170             :          */
    1171       77624 :         s2_len = ucs2_len * 2;
    1172             :     }
    1173             : 
    1174       77624 :     CHECK(ret, krb5_store_uint16(sp, s2_len), out);
    1175             : 
    1176       77624 :     ret = krb5_storage_write(sp, s2, s2_len);
    1177       77624 :     if (ret != (int)s2_len) {
    1178           0 :         ret = krb5_enomem(context);
    1179           0 :         goto out;
    1180             :     }
    1181       77624 :     ret = krb5_storage_to_data(sp, logon);
    1182             : 
    1183       77624 :  out:
    1184       77624 :     free(s2);
    1185       77624 :     krb5_storage_free(sp);
    1186       77624 :     return ret;
    1187             : }
    1188             : 
    1189             : static krb5_error_code
    1190       48942 : parse_attributes_info(krb5_context context,
    1191             :                       const struct PAC_INFO_BUFFER *attributes_info,
    1192             :                       const krb5_data *data,
    1193             :                       uint64_t *pac_attributes)
    1194             : {
    1195        1658 :     krb5_error_code ret;
    1196       48942 :     krb5_storage *sp = NULL;
    1197        1658 :     uint32_t flags_length;
    1198             : 
    1199       48942 :     *pac_attributes = 0;
    1200             : 
    1201       50600 :     sp = krb5_storage_from_readonly_mem((const char *)data->data + attributes_info->offset,
    1202       48942 :                                         attributes_info->buffersize);
    1203       48942 :     if (sp == NULL)
    1204           0 :         return krb5_enomem(context);
    1205             : 
    1206       48942 :     krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
    1207             : 
    1208       48942 :     ret = krb5_ret_uint32(sp, &flags_length);
    1209       48942 :     if (ret == 0) {
    1210       48942 :         if (flags_length > 32)
    1211           0 :             ret = krb5_ret_uint64(sp, pac_attributes);
    1212             :         else {
    1213       48942 :             uint32_t pac_attributes32 = 0;
    1214       48942 :             ret = krb5_ret_uint32(sp, &pac_attributes32);
    1215       48942 :             *pac_attributes = pac_attributes32;
    1216             :         }
    1217             :     }
    1218             : 
    1219       48942 :     krb5_storage_free(sp);
    1220             : 
    1221       48942 :     return ret;
    1222             : }
    1223             : 
    1224             : /**
    1225             :  * Verify the PAC.
    1226             :  *
    1227             :  * @param context Kerberos 5 context.
    1228             :  * @param pac the pac structure returned by krb5_pac_parse().
    1229             :  * @param authtime The time of the ticket the PAC belongs to.
    1230             :  * @param principal the principal to verify.
    1231             :  * @param server The service key, may be given.
    1232             :  * @param privsvr The KDC key, may be given.
    1233             : 
    1234             :  * @return Returns 0 to indicate success. Otherwise an kerberos et
    1235             :  * error code is returned, see krb5_get_error_message().
    1236             :  *
    1237             :  * @ingroup krb5_pac
    1238             :  */
    1239             : 
    1240             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1241      102380 : krb5_pac_verify(krb5_context context,
    1242             :                 const krb5_pac pac,
    1243             :                 time_t authtime,
    1244             :                 krb5_const_principal principal,
    1245             :                 const krb5_keyblock *server,
    1246             :                 const krb5_keyblock *privsvr)
    1247             : {
    1248        2539 :     krb5_error_code ret;
    1249             :     /*
    1250             :      * If we are in the KDC, we expect back a full signature in the PAC
    1251             :      *
    1252             :      * This is set up as a separate variable to make it easier if a
    1253             :      * subsequent patch is added to make this configurable in the
    1254             :      * krb5.conf (or forced into the krb5_context via Samba)
    1255             :      */
    1256      102380 :     krb5_boolean expect_full_sig = privsvr != NULL;
    1257             : 
    1258             :     /*
    1259             :      * If we are on the KDC, then we trust we are not in a realm with
    1260             :      * buggy Windows 2008 or similar era DCs that give out HMAC-MD5
    1261             :      * signatures over AES keys.  DES is also already gone.
    1262             :      */
    1263      102380 :     krb5_boolean strict_cksumtype_match = expect_full_sig;
    1264             : 
    1265      102380 :     if (pac->server_checksum == NULL) {
    1266           6 :         krb5_set_error_message(context, EINVAL, "PAC missing server checksum");
    1267           6 :         return EINVAL;
    1268             :     }
    1269      102374 :     if (pac->privsvr_checksum == NULL) {
    1270           6 :         krb5_set_error_message(context, EINVAL, "PAC missing kdc checksum");
    1271           6 :         return EINVAL;
    1272             :     }
    1273      102368 :     if (pac->logon_name == NULL) {
    1274           0 :         krb5_set_error_message(context, EINVAL, "PAC missing logon name");
    1275           0 :         return EINVAL;
    1276             :     }
    1277      102368 :     if (expect_full_sig && pac->full_checksum == NULL) {
    1278           3 :         krb5_set_error_message(context, EINVAL, "PAC missing full checksum");
    1279           3 :         return EINVAL;
    1280             :     }
    1281             : 
    1282      102365 :     if (principal != NULL) {
    1283      102180 :         ret = verify_logonname(context, pac->logon_name, &pac->data, authtime,
    1284             :                                principal);
    1285      102180 :         if (ret)
    1286           0 :             return ret;
    1287             :     }
    1288             : 
    1289      102365 :     if (pac->server_checksum->buffersize < 4 ||
    1290      102365 :         pac->privsvr_checksum->buffersize < 4)
    1291           0 :         return EINVAL;
    1292             : 
    1293      102365 :     if (server != NULL || privsvr != NULL)
    1294             :     {
    1295        2539 :         krb5_data *copy;
    1296             : 
    1297             :         /*
    1298             :          * in the service case, clean out data option of the privsvr and
    1299             :          * server checksum before checking the checksum.
    1300             :          */
    1301             : 
    1302      102365 :         ret = krb5_copy_data(context, &pac->data, &copy);
    1303      102365 :         if (ret)
    1304          39 :             return ret;
    1305             : 
    1306      102365 :         memset((char *)copy->data + pac->server_checksum->offset + 4,
    1307             :                0,
    1308      102365 :                pac->server_checksum->buffersize - 4);
    1309             : 
    1310      102365 :         memset((char *)copy->data + pac->privsvr_checksum->offset + 4,
    1311             :                0,
    1312      102365 :                pac->privsvr_checksum->buffersize - 4);
    1313             : 
    1314      102365 :         if (server != NULL) {
    1315      104719 :             ret = verify_checksum(context,
    1316      102180 :                                   pac->server_checksum,
    1317       99641 :                                   &pac->data,
    1318       99641 :                                   copy->data,
    1319      102180 :                                   copy->length,
    1320             :                                   server,
    1321             :                                   strict_cksumtype_match);
    1322      102180 :             if (ret) {
    1323          24 :                 krb5_free_data(context, copy);
    1324          24 :                 return ret;
    1325             :             }
    1326             :         }
    1327             : 
    1328      102341 :         if (privsvr != NULL && pac->full_checksum != NULL) {
    1329             :             /*
    1330             :              * in the full checksum case, also clean out the full
    1331             :              * checksum before verifying it.
    1332             :              */
    1333         185 :             memset((char *)copy->data + pac->full_checksum->offset + 4,
    1334             :                    0,
    1335         185 :                    pac->full_checksum->buffersize - 4);
    1336             : 
    1337         185 :             ret = verify_checksum(context,
    1338         185 :                                   pac->full_checksum,
    1339         185 :                                   &pac->data,
    1340         185 :                                   copy->data,
    1341         185 :                                   copy->length,
    1342             :                                   privsvr,
    1343             :                                   strict_cksumtype_match);
    1344         185 :             if (ret) {
    1345          15 :                 krb5_free_data(context, copy);
    1346          15 :                 return ret;
    1347             :             }
    1348             :         }
    1349             : 
    1350      102326 :         krb5_free_data(context, copy);
    1351             :     }
    1352      102326 :     if (privsvr) {
    1353             :         /* The priv checksum covers the server checksum */
    1354         170 :         ret = verify_checksum(context,
    1355         170 :                               pac->privsvr_checksum,
    1356         170 :                               &pac->data,
    1357         170 :                               (char *)pac->data.data
    1358         170 :                               + pac->server_checksum->offset + 4,
    1359         170 :                               pac->server_checksum->buffersize - 4,
    1360             :                               privsvr,
    1361             :                               strict_cksumtype_match);
    1362         170 :         if (ret)
    1363           0 :             return ret;
    1364             : 
    1365         170 :         if (pac->ticket_sign_data.length != 0) {
    1366         167 :             if (pac->ticket_checksum == NULL) {
    1367           0 :                 krb5_set_error_message(context, EINVAL,
    1368             :                                        "PAC missing ticket checksum");
    1369           0 :                 return EINVAL;
    1370             :             }
    1371             : 
    1372         167 :             ret = verify_checksum(context, pac->ticket_checksum, &pac->data,
    1373             :                                  pac->ticket_sign_data.data,
    1374             :                                  pac->ticket_sign_data.length, privsvr,
    1375             :                                  strict_cksumtype_match);
    1376         167 :             if (ret)
    1377          15 :                 return ret;
    1378             :         }
    1379             :     }
    1380             : 
    1381      102311 :     if (pac->upn_dns_info &&
    1382      102267 :         pac->upn_princ == NULL && pac->canon_princ == NULL && pac->sid.data == NULL) {
    1383      102112 :         ret = parse_upn_dns_info(context, pac->upn_dns_info, &pac->data,
    1384             :                                  &pac->upn_princ, &pac->upn_flags,
    1385             :                                  &pac->canon_princ, &pac->sid);
    1386      102112 :         if (ret)
    1387           0 :             return ret;
    1388             :     }
    1389             : 
    1390      102311 :     if (pac->attributes_info) {
    1391       48942 :         ret = parse_attributes_info(context, pac->attributes_info, &pac->data,
    1392             :                                     &pac->pac_attributes);
    1393       48942 :         if (ret)
    1394           0 :             return ret;
    1395             :     }
    1396             : 
    1397       99772 :     return 0;
    1398             : }
    1399             : 
    1400             : /*
    1401             :  *
    1402             :  */
    1403             : 
    1404             : static krb5_error_code
    1405      351364 : fill_zeros(krb5_context context, krb5_storage *sp, size_t len)
    1406             : {
    1407       11847 :     ssize_t sret;
    1408       11847 :     size_t l;
    1409             : 
    1410      899946 :     while (len) {
    1411      548582 :         l = len;
    1412      548582 :         if (l > sizeof(zeros))
    1413      190316 :             l = sizeof(zeros);
    1414      548582 :         sret = krb5_storage_write(sp, zeros, l);
    1415      548582 :         if (sret != l)
    1416           0 :             return krb5_enomem(context);
    1417             : 
    1418      548582 :         len -= sret;
    1419             :     }
    1420      339517 :     return 0;
    1421             : }
    1422             : 
    1423             : static krb5_error_code
    1424      155248 : pac_checksum(krb5_context context,
    1425             :              const krb5_keyblock *key,
    1426             :              uint32_t *cksumtype,
    1427             :              size_t *cksumsize)
    1428             : {
    1429        5656 :     krb5_cksumtype cktype;
    1430        5656 :     krb5_error_code ret;
    1431      155248 :     krb5_crypto crypto = NULL;
    1432             : 
    1433      155248 :     ret = krb5_crypto_init(context, key, 0, &crypto);
    1434      155248 :     if (ret)
    1435           0 :         return ret;
    1436             : 
    1437      155248 :     ret = krb5_crypto_get_checksum_type(context, crypto, &cktype);
    1438      155248 :     krb5_crypto_destroy(context, crypto);
    1439      155248 :     if (ret)
    1440           0 :         return ret;
    1441             : 
    1442      155248 :     if (krb5_checksum_is_keyed(context, cktype) == FALSE) {
    1443           0 :         *cksumtype = CKSUMTYPE_HMAC_MD5;
    1444           0 :         *cksumsize = 16;
    1445             :     }
    1446             : 
    1447      155248 :     ret = krb5_checksumsize(context, cktype, cksumsize);
    1448      155248 :     if (ret)
    1449           0 :         return ret;
    1450             : 
    1451      155248 :     *cksumtype = (uint32_t)cktype;
    1452             : 
    1453      155248 :     return 0;
    1454             : }
    1455             : 
    1456             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1457       77624 : _krb5_pac_sign(krb5_context context,
    1458             :                krb5_pac p,
    1459             :                time_t authtime,
    1460             :                krb5_const_principal principal,
    1461             :                const krb5_keyblock *server_key,
    1462             :                const krb5_keyblock *priv_key,
    1463             :                uint16_t rodc_id,
    1464             :                krb5_const_principal upn_princ,
    1465             :                krb5_const_principal canon_princ,
    1466             :                krb5_boolean add_full_sig,
    1467             :                uint64_t *pac_attributes, /* optional */
    1468             :                krb5_data *data)
    1469             : {
    1470        2828 :     krb5_error_code ret;
    1471       77624 :     krb5_storage *sp = NULL, *spdata = NULL;
    1472        2828 :     uint32_t end;
    1473        2828 :     size_t server_size, priv_size;
    1474       77624 :     uint32_t server_offset = 0, priv_offset = 0, ticket_offset = 0, full_offset = 0;
    1475       77624 :     uint32_t server_cksumtype = 0, priv_cksumtype = 0;
    1476       77624 :     uint32_t num = 0;
    1477        2828 :     uint32_t i, sz;
    1478        2828 :     krb5_data logon, d;
    1479             : 
    1480       77624 :     krb5_data_zero(&d);
    1481       77624 :     krb5_data_zero(&logon);
    1482             : 
    1483             :     /*
    1484             :      * Set convenience buffer pointers.
    1485             :      *
    1486             :      * This could really stand to be moved to krb5_pac_add_buffer() and/or
    1487             :      * utility function, so that when this function gets called they must
    1488             :      * already have been set.
    1489             :      */
    1490      594173 :     for (i = 0; i < p->pac->numbuffers; i++) {
    1491      513721 :         if (p->pac->buffers[i].type == PAC_SERVER_CHECKSUM) {
    1492       47235 :             if (p->server_checksum == NULL) {
    1493       47235 :                 p->server_checksum = &p->pac->buffers[i];
    1494             :             }
    1495       47235 :             if (p->server_checksum != &p->pac->buffers[i]) {
    1496           0 :                 ret = KRB5KDC_ERR_BADOPTION;
    1497           0 :                 krb5_set_error_message(context, ret,
    1498           0 :                                        N_("PAC has multiple server checksums", ""));
    1499           0 :                 goto out;
    1500             :             }
    1501      466486 :         } else if (p->pac->buffers[i].type == PAC_PRIVSVR_CHECKSUM) {
    1502       47235 :             if (p->privsvr_checksum == NULL) {
    1503       47235 :                 p->privsvr_checksum = &p->pac->buffers[i];
    1504             :             }
    1505       47235 :             if (p->privsvr_checksum != &p->pac->buffers[i]) {
    1506           0 :                 ret = KRB5KDC_ERR_BADOPTION;
    1507           0 :                 krb5_set_error_message(context, ret,
    1508           0 :                                        N_("PAC has multiple KDC checksums", ""));
    1509           0 :                 goto out;
    1510             :             }
    1511      403529 :         } else if (p->pac->buffers[i].type == PAC_LOGON_NAME) {
    1512       77624 :             if (p->logon_name == NULL) {
    1513       77624 :                 p->logon_name = &p->pac->buffers[i];
    1514             :             }
    1515       77624 :             if (p->logon_name != &p->pac->buffers[i]) {
    1516           0 :                 ret = KRB5KDC_ERR_BADOPTION;
    1517           0 :                 krb5_set_error_message(context, ret,
    1518           0 :                                        N_("PAC has multiple logon names", ""));
    1519           0 :                 goto out;
    1520             :             }
    1521      328733 :         } else if (p->pac->buffers[i].type == PAC_UPN_DNS_INFO) {
    1522       77624 :             if (p->upn_dns_info == NULL) {
    1523       77624 :                 p->upn_dns_info = &p->pac->buffers[i];
    1524             :             }
    1525       77624 :             if (p->upn_dns_info != &p->pac->buffers[i]) {
    1526           0 :                 ret = KRB5KDC_ERR_BADOPTION;
    1527           0 :                 krb5_set_error_message(context, ret,
    1528           0 :                                        N_("PAC has multiple UPN DNS info buffers", ""));
    1529           0 :                 goto out;
    1530             :             }
    1531      253937 :         } else if (p->pac->buffers[i].type == PAC_TICKET_CHECKSUM) {
    1532         130 :             if (p->ticket_checksum == NULL) {
    1533         130 :                 p->ticket_checksum = &p->pac->buffers[i];
    1534             :             }
    1535         130 :             if (p->ticket_checksum != &p->pac->buffers[i]) {
    1536           0 :                 ret = KRB5KDC_ERR_BADOPTION;
    1537           0 :                 krb5_set_error_message(context, ret,
    1538           0 :                                        N_("PAC has multiple ticket checksums", ""));
    1539           0 :                 goto out;
    1540             :             }
    1541      253807 :         } else if (p->pac->buffers[i].type == PAC_ATTRIBUTES_INFO) {
    1542       54047 :             if (p->attributes_info == NULL) {
    1543       54047 :                 p->attributes_info = &p->pac->buffers[i];
    1544             :             }
    1545       54047 :             if (p->attributes_info != &p->pac->buffers[i]) {
    1546           0 :                 ret = KRB5KDC_ERR_BADOPTION;
    1547           0 :                 krb5_set_error_message(context, ret,
    1548           0 :                                        N_("PAC has multiple attributes info buffers", ""));
    1549           0 :                 goto out;
    1550             :             }
    1551      201965 :         } else if (p->pac->buffers[i].type == PAC_FULL_CHECKSUM) {
    1552         130 :             if (p->full_checksum == NULL) {
    1553         130 :                 p->full_checksum = &p->pac->buffers[i];
    1554             :             }
    1555         130 :             if (p->full_checksum != &p->pac->buffers[i]) {
    1556           0 :                 ret = KRB5KDC_ERR_BADOPTION;
    1557           0 :                 krb5_set_error_message(context, ret,
    1558           0 :                                        N_("PAC has multiple full checksums", ""));
    1559           0 :                 goto out;
    1560             :             }
    1561             :         }
    1562             :     }
    1563             : 
    1564             :     /* Count missing-but-necessary buffers */
    1565       77624 :     if (p->logon_name == NULL)
    1566           0 :         num++;
    1567       77624 :     if (p->server_checksum == NULL)
    1568       30389 :         num++;
    1569       77624 :     if (p->privsvr_checksum == NULL)
    1570       30389 :         num++;
    1571       77624 :     if (p->ticket_sign_data.length != 0 && p->ticket_checksum == NULL)
    1572       20855 :         num++;
    1573       77624 :     if (add_full_sig && p->full_checksum == NULL)
    1574       20855 :         num++;
    1575             : 
    1576             :     /* Allocate any missing-but-necessary buffers */
    1577       77624 :     if (num) {
    1578        1793 :         void *ptr;
    1579        1793 :         uint32_t old_len, len;
    1580             : 
    1581       50594 :         if (p->pac->numbuffers > UINT32_MAX - num) {
    1582           0 :             ret = EINVAL;
    1583           0 :             krb5_set_error_message(context, ret, "integer overrun");
    1584           0 :             goto out;
    1585             :         }
    1586       50594 :         ret = pac_header_size(context, p->pac->numbuffers, &old_len);
    1587       48801 :         if (ret == 0)
    1588       50594 :             ret = pac_header_size(context, p->pac->numbuffers + num, &len);
    1589       50594 :         if (ret)
    1590           0 :             goto out;
    1591             : 
    1592       50594 :         ptr = realloc(p->pac, len);
    1593       50594 :         if (ptr == NULL) {
    1594           0 :             ret = krb5_enomem(context);
    1595           0 :             goto out;
    1596             :         }
    1597       50594 :         memset((char *)ptr + old_len, 0, len - old_len);
    1598       50594 :         p->pac = ptr;
    1599             : 
    1600             : 
    1601       50594 :         if (p->logon_name == NULL) {
    1602           0 :             p->logon_name = &p->pac->buffers[p->pac->numbuffers++];
    1603           0 :             p->logon_name->type = PAC_LOGON_NAME;
    1604             :         }
    1605       50594 :         if (p->server_checksum == NULL) {
    1606       30389 :             p->server_checksum = &p->pac->buffers[p->pac->numbuffers++];
    1607       30389 :             p->server_checksum->type = PAC_SERVER_CHECKSUM;
    1608             :         }
    1609       50594 :         if (p->privsvr_checksum == NULL) {
    1610       30389 :             p->privsvr_checksum = &p->pac->buffers[p->pac->numbuffers++];
    1611       30389 :             p->privsvr_checksum->type = PAC_PRIVSVR_CHECKSUM;
    1612             :         }
    1613       50594 :         if (p->ticket_sign_data.length != 0 && p->ticket_checksum == NULL) {
    1614       20855 :             p->ticket_checksum = &p->pac->buffers[p->pac->numbuffers++];
    1615       20855 :             p->ticket_checksum->type = PAC_TICKET_CHECKSUM;
    1616             :         }
    1617       50594 :         if (add_full_sig && p->full_checksum == NULL) {
    1618       20855 :             p->full_checksum = &p->pac->buffers[p->pac->numbuffers++];
    1619       20855 :             memset(p->full_checksum, 0, sizeof(*p->full_checksum));
    1620       20855 :             p->full_checksum->type = PAC_FULL_CHECKSUM;
    1621             :         }
    1622             :     }
    1623             : 
    1624             :     /* Calculate LOGON NAME */
    1625       77624 :     ret = build_logon_name(context, authtime, principal, &logon);
    1626             : 
    1627             :     /* Set lengths for checksum */
    1628       77624 :     if (ret == 0)
    1629       77624 :         ret = pac_checksum(context, server_key, &server_cksumtype, &server_size);
    1630             : 
    1631       77624 :     if (ret == 0)
    1632       77624 :         ret = pac_checksum(context, priv_key, &priv_cksumtype, &priv_size);
    1633             : 
    1634             :     /* Encode PAC */
    1635       77624 :     if (ret == 0) {
    1636       77624 :         sp = krb5_storage_emem();
    1637       77624 :         if (sp == NULL)
    1638           0 :             ret = krb5_enomem(context);
    1639             :     }
    1640             : 
    1641       77624 :     if (ret == 0) {
    1642       77624 :         krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
    1643       77624 :         spdata = krb5_storage_emem();
    1644       77624 :         if (spdata == NULL)
    1645           0 :             ret = krb5_enomem(context);
    1646             :     }
    1647             : 
    1648       77624 :     if (ret)
    1649           0 :         goto out;
    1650             : 
    1651       77624 :     krb5_storage_set_flags(spdata, KRB5_STORAGE_BYTEORDER_LE);
    1652             : 
    1653             :     /* `sp' has the header, `spdata' has the buffers */
    1654       77624 :     CHECK(ret, krb5_store_uint32(sp, p->pac->numbuffers), out);
    1655       77624 :     CHECK(ret, krb5_store_uint32(sp, p->pac->version), out);
    1656             : 
    1657       77624 :     ret = pac_header_size(context, p->pac->numbuffers, &end);
    1658       77624 :     if (ret)
    1659           0 :         goto out;
    1660             : 
    1661             :     /*
    1662             :      * For each buffer we write its contents to `spdata' and then append the
    1663             :      * PAC_INFO_BUFFER for that buffer into the header in `sp'.  The logical
    1664             :      * end of the whole thing is kept in `end', which functions as the offset
    1665             :      * to write in the buffer's PAC_INFO_BUFFER, then we update it at the
    1666             :      * bottom so that the next buffer can be written there.
    1667             :      *
    1668             :      * TODO?  Maybe rewrite all of this so that:
    1669             :      *
    1670             :      *  - we use krb5_pac_add_buffer() to add the buffers we produce
    1671             :      *  - we use the krb5_data of the concatenated buffers that's maintained by
    1672             :      *    krb5_pac_add_buffer() so we don't need `spdata' here
    1673             :      *
    1674             :      * We do way too much here, and that makes this code hard to read.  Plus we
    1675             :      * throw away all the work done in krb5_pac_add_buffer().  On the other
    1676             :      * hand, krb5_pac_add_buffer() has to loop over all the buffers, so if we
    1677             :      * call krb5_pac_add_buffer() here in a loop, we'll be accidentally
    1678             :      * quadratic, but we only need to loop over adding the buffers we add,
    1679             :      * which is very few, so not quite quadratic.  We should also cap the
    1680             :      * number of buffers we're willing to accept in a PAC we parse to something
    1681             :      * reasonable, like a few tens.
    1682             :      */
    1683      693833 :     for (i = 0; i < p->pac->numbuffers; i++) {
    1684       22624 :         uint32_t len;
    1685       22624 :         size_t sret;
    1686      616209 :         void *ptr = NULL;
    1687             : 
    1688             :         /* store data */
    1689             : 
    1690      616209 :         if (p->pac->buffers[i].type == PAC_SERVER_CHECKSUM) {
    1691       77624 :             if (server_size > UINT32_MAX - 4) {
    1692           0 :                 ret = EINVAL;
    1693           0 :                 krb5_set_error_message(context, ret, "integer overrun");
    1694           0 :                 goto out;
    1695             :             }
    1696       77624 :             len = server_size + 4;
    1697       77624 :             if (end > UINT32_MAX - 4) {
    1698           0 :                 ret = EINVAL;
    1699           0 :                 krb5_set_error_message(context, ret, "integer overrun");
    1700           0 :                 goto out;
    1701             :             }
    1702       77624 :             server_offset = end + 4;
    1703       77624 :             CHECK(ret, krb5_store_uint32(spdata, server_cksumtype), out);
    1704       77624 :             CHECK(ret, fill_zeros(context, spdata, server_size), out);
    1705      538585 :         } else if (p->pac->buffers[i].type == PAC_PRIVSVR_CHECKSUM) {
    1706       77624 :             if (priv_size > UINT32_MAX - 4) {
    1707           0 :                 ret = EINVAL;
    1708           0 :                 krb5_set_error_message(context, ret, "integer overrun");
    1709           0 :                 goto out;
    1710             :             }
    1711       77624 :             len = priv_size + 4;
    1712       77624 :             if (end > UINT32_MAX - 4) {
    1713           0 :                 ret = EINVAL;
    1714           0 :                 krb5_set_error_message(context, ret, "integer overrun");
    1715           0 :                 goto out;
    1716             :             }
    1717       77624 :             priv_offset = end + 4;
    1718       77624 :             CHECK(ret, krb5_store_uint32(spdata, priv_cksumtype), out);
    1719       77624 :             CHECK(ret, fill_zeros(context, spdata, priv_size), out);
    1720       77624 :             if (rodc_id != 0) {
    1721        2865 :                 if (len > UINT32_MAX - sizeof(rodc_id)) {
    1722           0 :                     ret = EINVAL;
    1723           0 :                     krb5_set_error_message(context, ret, "integer overrun");
    1724           0 :                     goto out;
    1725             :                 }
    1726        2865 :                 len += sizeof(rodc_id);
    1727        2865 :                 CHECK(ret, fill_zeros(context, spdata, sizeof(rodc_id)), out);
    1728             :             }
    1729      460961 :         } else if (p->ticket_sign_data.length != 0 &&
    1730      122488 :                    p->pac->buffers[i].type == PAC_TICKET_CHECKSUM) {
    1731       20985 :             if (priv_size > UINT32_MAX - 4) {
    1732           0 :                 ret = EINVAL;
    1733           0 :                 krb5_set_error_message(context, ret, "integer overrun");
    1734           0 :                 goto out;
    1735             :             }
    1736       20985 :             len = priv_size + 4;
    1737       20985 :             if (end > UINT32_MAX - 4) {
    1738           0 :                 ret = EINVAL;
    1739           0 :                 krb5_set_error_message(context, ret, "integer overrun");
    1740           0 :                 goto out;
    1741             :             }
    1742       20985 :             ticket_offset = end + 4;
    1743       20985 :             CHECK(ret, krb5_store_uint32(spdata, priv_cksumtype), out);
    1744       20985 :             CHECK(ret, fill_zeros(context, spdata, priv_size), out);
    1745       20985 :             if (rodc_id != 0) {
    1746        1574 :                 if (len > UINT32_MAX - sizeof(rodc_id)) {
    1747           0 :                     ret = EINVAL;
    1748           0 :                     krb5_set_error_message(context, ret, "integer overrun");
    1749           0 :                     goto out;
    1750             :                 }
    1751        1574 :                 len += sizeof(rodc_id);
    1752        1574 :                 CHECK(ret, krb5_store_uint16(spdata, rodc_id), out);
    1753             :             }
    1754      439976 :         } else if (add_full_sig &&
    1755      102126 :                    p->pac->buffers[i].type == PAC_FULL_CHECKSUM) {
    1756       20985 :             if (priv_size > UINT32_MAX - 4) {
    1757           0 :                 ret = EINVAL;
    1758           0 :                 krb5_set_error_message(context, ret, "integer overrun");
    1759           0 :                 goto out;
    1760             :             }
    1761       20985 :             len = priv_size + 4;
    1762       20985 :             if (end > UINT32_MAX - 4) {
    1763           0 :                 ret = EINVAL;
    1764           0 :                 krb5_set_error_message(context, ret, "integer overrun");
    1765           0 :                 goto out;
    1766             :             }
    1767       20985 :             full_offset = end + 4;
    1768       20985 :             CHECK(ret, krb5_store_uint32(spdata, priv_cksumtype), out);
    1769       20985 :             CHECK(ret, fill_zeros(context, spdata, priv_size), out);
    1770       20985 :             if (rodc_id != 0) {
    1771        1574 :                 if (len > UINT32_MAX - sizeof(rodc_id)) {
    1772           0 :                     ret = EINVAL;
    1773           0 :                     krb5_set_error_message(context, ret, "integer overrun");
    1774           0 :                     goto out;
    1775             :                 }
    1776        1574 :                 len += sizeof(rodc_id);
    1777        1574 :                 CHECK(ret, fill_zeros(context, spdata, sizeof(rodc_id)), out);
    1778             :             }
    1779      418991 :         } else if (p->pac->buffers[i].type == PAC_LOGON_NAME) {
    1780       77624 :             len = krb5_storage_write(spdata, logon.data, logon.length);
    1781       77624 :             if (logon.length != len) {
    1782           0 :                 ret = KRB5KDC_ERR_BADOPTION;
    1783           0 :                 goto out;
    1784             :             }
    1785             :         } else {
    1786      341367 :             len = p->pac->buffers[i].buffersize;
    1787      341367 :             ptr = (char *)p->data.data + p->pac->buffers[i].offset;
    1788             : 
    1789      341367 :             sret = krb5_storage_write(spdata, ptr, len);
    1790      341367 :             if (sret != len) {
    1791           0 :                 ret = krb5_enomem(context);
    1792           0 :                 goto out;
    1793             :             }
    1794             :             /* XXX if not aligned, fill_zeros */
    1795             :         }
    1796             : 
    1797             :         /* write header */
    1798      616209 :         CHECK(ret, krb5_store_uint32(sp, p->pac->buffers[i].type), out);
    1799      616209 :         CHECK(ret, krb5_store_uint32(sp, len), out);
    1800      616209 :         CHECK(ret, krb5_store_uint64(sp, end), out); /* offset */
    1801             : 
    1802             :         /* advance data endpointer and align */
    1803             :         {
    1804       22624 :             uint32_t e;
    1805             : 
    1806      616209 :             ret = pac_aligned_size(context, end, len, &e);
    1807      616209 :             if (ret == 0 && end + len != e)
    1808      149707 :                 ret = fill_zeros(context, spdata, e - (end + len));
    1809      616209 :             if (ret)
    1810           0 :                 goto out;
    1811      616209 :             end = e;
    1812             :         }
    1813             : 
    1814             :     }
    1815             : 
    1816             :     /* assert (server_offset != 0 && priv_offset != 0); */
    1817             : 
    1818             :     /* export PAC */
    1819       77624 :     if (ret == 0)
    1820       77624 :         ret = krb5_storage_to_data(spdata, &d);
    1821       77624 :     if (ret == 0) {
    1822       77624 :         sz = krb5_storage_write(sp, d.data, d.length);
    1823       77624 :         if (sz != d.length) {
    1824           0 :             krb5_data_free(&d);
    1825           0 :             ret = krb5_enomem(context);
    1826           0 :             goto out;
    1827             :         }
    1828             :     }
    1829       77624 :     krb5_data_free(&d);
    1830             : 
    1831       77624 :     if (ret == 0)
    1832       77624 :         ret = krb5_storage_to_data(sp, &d);
    1833             : 
    1834             :     /* sign */
    1835       77624 :     if (ret == 0 && p->ticket_sign_data.length)
    1836       20985 :         ret = create_checksum(context, priv_key, priv_cksumtype,
    1837             :                               p->ticket_sign_data.data,
    1838             :                               p->ticket_sign_data.length,
    1839       20985 :                               (char *)d.data + ticket_offset, priv_size);
    1840       77624 :     if (ret == 0 && add_full_sig)
    1841       20985 :         ret = create_checksum(context, priv_key, priv_cksumtype,
    1842             :                               d.data, d.length,
    1843       20985 :                               (char *)d.data + full_offset, priv_size);
    1844       77624 :     if (ret == 0 && add_full_sig && rodc_id != 0) {
    1845        1574 :         void *buf = (char *)d.data + full_offset + priv_size;
    1846        1574 :         krb5_storage *rs = krb5_storage_from_mem(buf, sizeof(rodc_id));
    1847        1574 :         if (rs == NULL)
    1848           0 :             ret = krb5_enomem(context);
    1849             :         else
    1850        1574 :             krb5_storage_set_flags(rs, KRB5_STORAGE_BYTEORDER_LE);
    1851        1574 :         if (ret == 0)
    1852        1574 :             ret = krb5_store_uint16(rs, rodc_id);
    1853        1574 :         krb5_storage_free(rs);
    1854             :     }
    1855       77624 :     if (ret == 0)
    1856       77624 :         ret = create_checksum(context, server_key, server_cksumtype,
    1857             :                               d.data, d.length,
    1858       77624 :                               (char *)d.data + server_offset, server_size);
    1859       77624 :     if (ret == 0)
    1860       77624 :         ret = create_checksum(context, priv_key, priv_cksumtype,
    1861       74796 :                               (char *)d.data + server_offset, server_size,
    1862       77624 :                               (char *)d.data + priv_offset, priv_size);
    1863       77624 :     if (ret == 0 && rodc_id != 0) {
    1864        2865 :         void *buf = (char *)d.data + priv_offset + priv_size;
    1865        2865 :         krb5_storage *rs = krb5_storage_from_mem(buf, sizeof(rodc_id));
    1866        2865 :         if (rs == NULL)
    1867           0 :             ret = krb5_enomem(context);
    1868             :         else
    1869        2865 :             krb5_storage_set_flags(rs, KRB5_STORAGE_BYTEORDER_LE);
    1870        2865 :         if (ret == 0)
    1871        2865 :             ret = krb5_store_uint16(rs, rodc_id);
    1872        2865 :         krb5_storage_free(rs);
    1873             :     }
    1874             : 
    1875       77624 :     if (ret)
    1876           0 :         goto out;
    1877             : 
    1878             :     /* done */
    1879       77624 :     *data = d;
    1880             : 
    1881       77624 :     krb5_data_free(&logon);
    1882       77624 :     krb5_storage_free(sp);
    1883       77624 :     krb5_storage_free(spdata);
    1884             : 
    1885       77624 :     return 0;
    1886           0 : out:
    1887           0 :     krb5_data_free(&d);
    1888           0 :     krb5_data_free(&logon);
    1889           0 :     if (sp)
    1890           0 :         krb5_storage_free(sp);
    1891           0 :     if (spdata)
    1892           0 :         krb5_storage_free(spdata);
    1893           0 :     return ret;
    1894             : }
    1895             : 
    1896             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1897         199 : krb5_pac_get_kdc_checksum_info(krb5_context context,
    1898             :                                krb5_const_pac pac,
    1899             :                                krb5_cksumtype *cstype,
    1900             :                                uint16_t *rodc_id)
    1901             : {
    1902           0 :     krb5_error_code ret;
    1903         199 :     krb5_storage *sp = NULL;
    1904           0 :     const struct PAC_INFO_BUFFER *sig;
    1905           0 :     size_t cksumsize, prefix;
    1906         199 :     uint32_t type = 0;
    1907             : 
    1908         199 :     *cstype = 0;
    1909         199 :     *rodc_id = 0;
    1910             : 
    1911         199 :     sig = pac->privsvr_checksum;
    1912         199 :     if (sig == NULL) {
    1913           0 :         krb5_set_error_message(context, KRB5KDC_ERR_BADOPTION,
    1914             :                                "PAC missing kdc checksum");
    1915           0 :         return KRB5KDC_ERR_BADOPTION;
    1916             :     }
    1917             : 
    1918         199 :     sp = krb5_storage_from_mem((char *)pac->data.data + sig->offset,
    1919         199 :                                sig->buffersize);
    1920         199 :     if (sp == NULL)
    1921           0 :         return krb5_enomem(context);
    1922             : 
    1923         199 :     krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
    1924             : 
    1925         199 :     ret = krb5_ret_uint32(sp, &type);
    1926         199 :     if (ret)
    1927           0 :         goto out;
    1928             : 
    1929         199 :     ret = krb5_checksumsize(context, type, &cksumsize);
    1930         199 :     if (ret)
    1931           3 :         goto out;
    1932             : 
    1933         196 :     prefix = krb5_storage_seek(sp, 0, SEEK_CUR);
    1934             : 
    1935         196 :     if ((sig->buffersize - prefix) >= cksumsize + 2) {
    1936           7 :         krb5_storage_seek(sp, cksumsize, SEEK_CUR);
    1937           7 :         ret = krb5_ret_uint16(sp, rodc_id);
    1938           7 :         if (ret)
    1939           0 :             goto out;
    1940             :     }
    1941             : 
    1942         196 :     *cstype = type;
    1943             : 
    1944         199 : out:
    1945         199 :     krb5_storage_free(sp);
    1946             : 
    1947         199 :     return ret;
    1948             : }
    1949             : 
    1950             : 
    1951             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1952       48236 : _krb5_pac_get_canon_principal(krb5_context context,
    1953             :                               krb5_const_pac pac,
    1954             :                               krb5_principal *canon_princ)
    1955             : {
    1956       48236 :     *canon_princ = NULL;
    1957             : 
    1958       48236 :     if (pac->canon_princ == NULL) {
    1959           0 :         krb5_set_error_message(context, ENOENT,
    1960             :                                "PAC missing UPN DNS info buffer");
    1961           0 :         return ENOENT;
    1962             :     }
    1963             : 
    1964       48236 :     return krb5_copy_principal(context, pac->canon_princ, canon_princ);
    1965             : }
    1966             : 
    1967             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1968       48236 : _krb5_pac_get_attributes_info(krb5_context context,
    1969             :                               krb5_const_pac pac,
    1970             :                               uint64_t *pac_attributes)
    1971             : {
    1972       48236 :     *pac_attributes = 0;
    1973             : 
    1974       48236 :     if (pac->attributes_info == NULL) {
    1975         170 :         krb5_set_error_message(context, ENOENT,
    1976             :                                "PAC missing attributes info buffer");
    1977         170 :         return ENOENT;
    1978             :     }
    1979             : 
    1980       48066 :     *pac_attributes = pac->pac_attributes;
    1981             : 
    1982       48066 :     return 0;
    1983             : }
    1984             : 
    1985             : static const unsigned char single_zero = '\0';
    1986             : static const krb5_data single_zero_pac = { 1, rk_UNCONST(&single_zero) };
    1987             : 
    1988             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1989       49223 : _krb5_kdc_pac_ticket_parse(krb5_context context,
    1990             :                            EncTicketPart *tkt,
    1991             :                            krb5_boolean *signedticket,
    1992             :                            krb5_pac *ppac)
    1993             : {
    1994       49223 :     AuthorizationData *ad = tkt->authorization_data;
    1995       49223 :     krb5_pac pac = NULL;
    1996        1658 :     unsigned i, j;
    1997       49223 :     size_t len = 0;
    1998       49223 :     krb5_error_code ret = 0;
    1999             : 
    2000       49223 :     *signedticket = FALSE;
    2001       49223 :     *ppac = NULL;
    2002             : 
    2003       49223 :     if (ad == NULL || ad->len == 0)
    2004          26 :         return 0;
    2005             : 
    2006       98411 :     for (i = 0; i < ad->len; i++) {
    2007        1658 :         AuthorizationData child;
    2008             : 
    2009       49214 :         if (ad->val[i].ad_type == KRB5_AUTHDATA_WIN2K_PAC) {
    2010           0 :             ret = KRB5KDC_ERR_BADOPTION;
    2011           0 :             goto out;
    2012             :         }
    2013             : 
    2014       49214 :         if (ad->val[i].ad_type != KRB5_AUTHDATA_IF_RELEVANT)
    2015           1 :             continue;
    2016             : 
    2017       49213 :         ret = decode_AuthorizationData(ad->val[i].ad_data.data,
    2018       47555 :                                        ad->val[i].ad_data.length,
    2019             :                                        &child,
    2020             :                                        NULL);
    2021       49213 :         if (ret) {
    2022           0 :             krb5_set_error_message(context, ret, "Failed to decode "
    2023             :                                    "AD-IF-RELEVANT with %d", ret);
    2024           0 :             goto out;
    2025             :         }
    2026             : 
    2027       98419 :         for (j = 0; j < child.len; j++) {
    2028       49206 :             krb5_data adifr_data = ad->val[i].ad_data;
    2029       49206 :             krb5_data pac_data = child.val[j].ad_data;
    2030        1658 :             krb5_data recoded_adifr;
    2031             : 
    2032       49206 :             if (child.val[j].ad_type != KRB5_AUTHDATA_WIN2K_PAC)
    2033       48980 :                 continue;
    2034             : 
    2035       49190 :             if (pac != NULL) {
    2036           0 :                 free_AuthorizationData(&child);
    2037           0 :                 ret = KRB5KDC_ERR_BADOPTION;
    2038           0 :                 goto out;
    2039             :             }
    2040             : 
    2041       49190 :             ret = krb5_pac_parse(context,
    2042       47532 :                                  pac_data.data,
    2043             :                                  pac_data.length,
    2044             :                                  &pac);
    2045       49190 :             if (ret) {
    2046           0 :                 free_AuthorizationData(&child);
    2047           0 :                 goto out;
    2048             :             }
    2049             : 
    2050       49190 :             if (pac->ticket_checksum == NULL)
    2051       48964 :                 continue;
    2052             : 
    2053             :             /*
    2054             :              * Encode the ticket with the PAC replaced with a single zero
    2055             :              * byte, to be used as input data to the ticket signature.
    2056             :              */
    2057             : 
    2058         226 :             child.val[j].ad_data = single_zero_pac;
    2059             : 
    2060         226 :             ASN1_MALLOC_ENCODE(AuthorizationData, recoded_adifr.data,
    2061             :                                recoded_adifr.length, &child, &len, ret);
    2062         226 :             if (recoded_adifr.length != len)
    2063           0 :                 krb5_abortx(context, "Internal error in ASN.1 encoder");
    2064             : 
    2065         226 :             child.val[j].ad_data = pac_data;
    2066             : 
    2067         226 :             if (ret) {
    2068           0 :                 free_AuthorizationData(&child);
    2069           0 :                 goto out;
    2070             :             }
    2071             : 
    2072         226 :             ad->val[i].ad_data = recoded_adifr;
    2073             : 
    2074         226 :             ASN1_MALLOC_ENCODE(EncTicketPart,
    2075             :                                pac->ticket_sign_data.data,
    2076             :                                pac->ticket_sign_data.length, tkt, &len,
    2077             :                                ret);
    2078         226 :             if (pac->ticket_sign_data.length != len)
    2079           0 :                 krb5_abortx(context, "Internal error in ASN.1 encoder");
    2080             : 
    2081         226 :             ad->val[i].ad_data = adifr_data;
    2082         226 :             krb5_data_free(&recoded_adifr);
    2083             : 
    2084         226 :             if (ret) {
    2085           0 :                 free_AuthorizationData(&child);
    2086           0 :                 goto out;
    2087             :             }
    2088             : 
    2089         226 :             *signedticket = TRUE;
    2090             :         }
    2091       49213 :         free_AuthorizationData(&child);
    2092             :     }
    2093             : 
    2094       49197 : out:
    2095       49197 :     if (ret) {
    2096           0 :         krb5_pac_free(context, pac);
    2097           0 :         return ret;
    2098             :     }
    2099             : 
    2100       49197 :     *ppac = pac;
    2101             : 
    2102       49197 :     return 0;
    2103             : }
    2104             : 
    2105             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    2106       47885 : _krb5_kdc_pac_sign_ticket(krb5_context context,
    2107             :                           const krb5_pac pac,
    2108             :                           krb5_const_principal client,
    2109             :                           const krb5_keyblock *server_key,
    2110             :                           const krb5_keyblock *kdc_key,
    2111             :                           uint16_t rodc_id,
    2112             :                           krb5_const_principal upn,
    2113             :                           krb5_const_principal canon_name,
    2114             :                           krb5_boolean add_ticket_sig,
    2115             :                           krb5_boolean add_full_sig,
    2116             :                           EncTicketPart *tkt,
    2117             :                           uint64_t *pac_attributes) /* optional */
    2118             : {
    2119        1658 :     krb5_error_code ret;
    2120        1658 :     krb5_data tkt_data;
    2121        1658 :     krb5_data rspac;
    2122             : 
    2123       47885 :     krb5_data_zero(&rspac);
    2124       47885 :     krb5_data_zero(&tkt_data);
    2125             : 
    2126       47885 :     krb5_data_free(&pac->ticket_sign_data);
    2127             : 
    2128       47885 :     if (add_ticket_sig) {
    2129       20985 :         size_t len = 0;
    2130             : 
    2131       20985 :         ret = _kdc_tkt_insert_pac(context, tkt, &single_zero_pac);
    2132       20985 :         if (ret)
    2133           0 :             return ret;
    2134             : 
    2135       20985 :         ASN1_MALLOC_ENCODE(EncTicketPart, tkt_data.data, tkt_data.length,
    2136             :                            tkt, &len, ret);
    2137       20985 :         if(tkt_data.length != len)
    2138           0 :             krb5_abortx(context, "Internal error in ASN.1 encoder");
    2139       20985 :         if (ret)
    2140           0 :             return ret;
    2141             : 
    2142       20985 :         ret = remove_AuthorizationData(tkt->authorization_data, 0);
    2143       20985 :         if (ret) {
    2144           0 :             krb5_data_free(&tkt_data);
    2145           0 :             return ret;
    2146             :         }
    2147             : 
    2148       20985 :         pac->ticket_sign_data = tkt_data;
    2149             :     }
    2150             : 
    2151       47885 :     ret = _krb5_pac_sign(context, pac, tkt->authtime, client, server_key,
    2152             :                          kdc_key, rodc_id, upn, canon_name,
    2153             :                          add_full_sig,
    2154             :                          pac_attributes, &rspac);
    2155       47885 :     if (ret == 0)
    2156       47885 :         ret = _kdc_tkt_insert_pac(context, tkt, &rspac);
    2157       47885 :     krb5_data_free(&rspac);
    2158       47885 :     return ret;
    2159             : }

Generated by: LCOV version 1.14