LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/krb5 - pac.c (source / functions) Hit Total Coverage
Test: coverage report for recycleplus df22b230 Lines: 765 1063 72.0 %
Date: 2024-02-14 10:14:15 Functions: 26 27 96.3 %

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

Generated by: LCOV version 1.14