LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/krb5 - pac.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 765 1060 72.2 %
Date: 2024-06-13 04:01:37 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      152189 : pac_dealloc(void *ctx)
     123             : {
     124      152189 :     krb5_pac pac = (krb5_pac)ctx;
     125             : 
     126      152189 :     krb5_data_free(&pac->data);
     127      152189 :     krb5_data_free(&pac->ticket_sign_data);
     128             : 
     129      152189 :     if (pac->upn_princ) {
     130       51906 :         free_Principal(pac->upn_princ);
     131       51906 :         free(pac->upn_princ);
     132             :     }
     133      152189 :     if (pac->canon_princ) {
     134       51906 :         free_Principal(pac->canon_princ);
     135       51906 :         free(pac->canon_princ);
     136             :     }
     137      152189 :     krb5_data_free(&pac->sid);
     138             : 
     139      152189 :     free(pac->pac);
     140      152189 : }
     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      560707 : 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      560707 :     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      560707 :     header_size = PAC_INFO_BUFFER_SIZE * num_buffers;
     171             : 
     172             :     /* Guard against integer overflow */
     173      560707 :     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      560707 :     header_size += PACTYPE_SIZE;
     179             : 
     180      560707 :     *result = header_size;
     181             : 
     182      560707 :     return 0;
     183             : }
     184             : 
     185             : /* Output `size' + `addend' + padding for alignment if it doesn't overflow */
     186             : static krb5_error_code
     187     1003598 : 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     2007196 :     if (size > UINT32_MAX - addend ||
     195     1003598 :         (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     1003598 :     size += addend;
     201     1003598 :     size += PAC_ALIGNMENT - 1;
     202     1003598 :     size &= ~(PAC_ALIGNMENT - 1);
     203     1003598 :     *aligned_size = size;
     204     1003598 :     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       22443 : 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       22443 :     memset(&local_key, 0, sizeof(local_key));
     224             : 
     225       22443 :     ret = krb5_copy_keyblock(context, key, &local_key.key);
     226       22443 :     if (ret)
     227           0 :         return ret;
     228             : 
     229       22443 :     ret = krb5_data_alloc (&result->checksum, 16);
     230       22443 :     if (ret) {
     231           0 :         krb5_free_keyblock(context, local_key.key);
     232           0 :         return ret;
     233             :     }
     234             : 
     235       22443 :     result->cksumtype = CKSUMTYPE_HMAC_MD5;
     236       22443 :     iov.data.data = (void *)data;
     237       22443 :     iov.data.length = len;
     238       22443 :     iov.flags = KRB5_CRYPTO_TYPE_DATA;
     239             : 
     240       22443 :     ret = _krb5_HMAC_MD5_checksum(context, NULL, &local_key, usage, &iov, 1,
     241             :                                   result);
     242       22443 :     if (ret)
     243           0 :         krb5_data_free(&result->checksum);
     244             : 
     245       22443 :     krb5_free_keyblock(context, local_key.key);
     246       22443 :     return ret;
     247             : }
     248             : 
     249             : 
     250             : /*
     251             :  *
     252             :  */
     253             : 
     254             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     255      126964 : krb5_pac_parse(krb5_context context, const void *ptr, size_t len,
     256             :                krb5_pac *pac)
     257             : {
     258      126964 :     krb5_error_code ret = 0;
     259             :     krb5_pac p;
     260      126964 :     krb5_storage *sp = NULL;
     261      126964 :     uint32_t i, num_buffers, version, header_size = 0;
     262      126964 :     uint32_t prev_start = 0;
     263      126964 :     uint32_t prev_end = 0;
     264             : 
     265      126964 :     *pac = NULL;
     266      126964 :     p = _heim_alloc_object(&pac_object, sizeof(*p));
     267      126964 :     if (p)
     268      126964 :         sp = krb5_storage_from_readonly_mem(ptr, len);
     269      126964 :     if (sp == NULL)
     270           0 :         ret = krb5_enomem(context);
     271      126964 :     if (ret == 0) {
     272      126964 :         krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
     273      126964 :         ret = krb5_ret_uint32(sp, &num_buffers);
     274             :     }
     275      126964 :     if (ret == 0)
     276      126964 :         ret = krb5_ret_uint32(sp, &version);
     277      126964 :     if (ret == 0 && num_buffers < 1)
     278           0 :         krb5_set_error_message(context, ret = EINVAL,
     279           0 :                                N_("PAC has too few buffers", ""));
     280      126964 :     if (ret == 0 && num_buffers > 1000)
     281           0 :         krb5_set_error_message(context, ret = EINVAL,
     282           0 :                                N_("PAC has too many buffers", ""));
     283      126964 :     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      126964 :     if (ret == 0)
     288      126964 :         ret = pac_header_size(context, num_buffers, &header_size);
     289      126964 :     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      126964 :     if (ret == 0)
     293      126964 :         p->pac = calloc(1, header_size);
     294      126964 :     if (ret == 0 && p->pac == NULL)
     295           0 :         ret = krb5_enomem(context);
     296             : 
     297      126964 :     if (ret == 0) {
     298      126964 :         p->pac->numbuffers = num_buffers;
     299      126964 :         p->pac->version = version;
     300             :     }
     301             : 
     302     1015514 :     for (i = 0; ret == 0 && i < p->pac->numbuffers; i++) {
     303      888550 :         ret = krb5_ret_uint32(sp, &p->pac->buffers[i].type);
     304      888550 :         if (ret == 0)
     305      888550 :             ret = krb5_ret_uint32(sp, &p->pac->buffers[i].buffersize);
     306      888550 :         if (ret == 0)
     307      888550 :             ret = krb5_ret_uint64(sp, &p->pac->buffers[i].offset);
     308      888550 :         if (ret)
     309           0 :             break;
     310             : 
     311             :         /* Consistency checks (we don't check for wasted space) */
     312      888550 :         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     1777100 :         if (p->pac->buffers[i].offset > len ||
     318     1777100 :             p->pac->buffers[i].buffersize > len ||
     319      888550 :             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      888550 :         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      888550 :         if (prev_start) {
     342     1523172 :             if (p->pac->buffers[i].offset >= prev_start &&
     343      761586 :                 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      761586 :             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      888550 :         prev_start = p->pac->buffers[i].offset;
     357      888550 :         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      888550 :         switch (p->pac->buffers[i].type) {
     361      126959 :         case PAC_SERVER_CHECKSUM:
     362      126959 :             if (p->server_checksum)
     363           0 :                 krb5_set_error_message(context, ret = EINVAL,
     364           0 :                                        N_("PAC has multiple server checksums", ""));
     365             :             else
     366      126959 :                 p->server_checksum = &p->pac->buffers[i];
     367      126959 :             break;
     368      126959 :         case PAC_PRIVSVR_CHECKSUM:
     369      126959 :             if (p->privsvr_checksum)
     370           0 :                 krb5_set_error_message(context, ret = EINVAL,
     371           0 :                                        N_("PAC has multiple KDC checksums", ""));
     372             :             else
     373      126959 :                 p->privsvr_checksum = &p->pac->buffers[i];
     374      126959 :             break;
     375      126964 :         case PAC_LOGON_NAME:
     376      126964 :             if (p->logon_name)
     377           0 :                 krb5_set_error_message(context, ret = EINVAL,
     378           0 :                                        N_("PAC has multiple logon names", ""));
     379             :             else
     380      126964 :                 p->logon_name = &p->pac->buffers[i];
     381      126964 :             break;
     382      126920 :         case PAC_UPN_DNS_INFO:
     383      126920 :             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      126920 :                 p->upn_dns_info = &p->pac->buffers[i];
     388      126920 :             break;
     389       90904 :         case PAC_TICKET_CHECKSUM:
     390       90904 :             if (p->ticket_checksum)
     391           0 :                 krb5_set_error_message(context, ret = EINVAL,
     392           0 :                                        N_("PAC has multiple ticket checksums", ""));
     393             :             else
     394       90904 :                 p->ticket_checksum = &p->pac->buffers[i];
     395       90904 :             break;
     396       35978 :         case PAC_ATTRIBUTES_INFO:
     397       35978 :             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       35978 :                 p->attributes_info = &p->pac->buffers[i];
     402       35978 :             break;
     403       90902 :         case PAC_FULL_CHECKSUM:
     404       90902 :             if (p->full_checksum)
     405           0 :                 krb5_set_error_message(context, ret = EINVAL,
     406           0 :                                        N_("PAC has multiple full checksums", ""));
     407             :             else
     408       90902 :                 p->full_checksum = &p->pac->buffers[i];
     409       90902 :             break;
     410      162964 :         default: break;
     411             :         }
     412             :     }
     413             : 
     414      126964 :     if (ret == 0)
     415      126964 :         ret = krb5_data_copy(&p->data, ptr, len);
     416      126964 :     if (ret == 0) {
     417      126964 :         *pac = p;
     418      126964 :         p = NULL;
     419             :     }
     420      126964 :     if (sp)
     421      126964 :         krb5_storage_free(sp);
     422      126964 :     krb5_pac_free(context, p);
     423      126964 :     return ret;
     424             : }
     425             : 
     426             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     427       54978 : krb5_pac_init(krb5_context context, krb5_pac *pac)
     428             : {
     429             :     krb5_error_code ret;
     430             :     krb5_pac p;
     431             : 
     432       54978 :     p = _heim_alloc_object(&pac_object, sizeof(*p));
     433       54978 :     if (p == NULL) {
     434           0 :         return krb5_enomem(context);
     435             :     }
     436             : 
     437       54978 :     p->pac = calloc(1, sizeof(*p->pac));
     438       54978 :     if (p->pac == NULL) {
     439           0 :         krb5_pac_free(context, p);
     440           0 :         return krb5_enomem(context);
     441             :     }
     442             : 
     443       54978 :     ret = krb5_data_alloc(&p->data, PACTYPE_SIZE);
     444       54978 :     if (ret) {
     445           0 :         free (p->pac);
     446           0 :         krb5_pac_free(context, p);
     447           0 :         return krb5_enomem(context);
     448             :     }
     449       54978 :     memset(p->data.data, 0, p->data.length);
     450             : 
     451       54978 :     *pac = p;
     452       54978 :     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      313768 : 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      313768 :     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      313768 :     assert(nd->data != NULL);
     477             : 
     478      313768 :     num_buffers = p->pac->numbuffers;
     479      313768 :     ret = pac_header_size(context, num_buffers + 1, &header_size);
     480      313768 :     if (ret)
     481           0 :         return ret;
     482             : 
     483      313768 :     ptr = realloc(p->pac, header_size);
     484      313768 :     if (ptr == NULL)
     485           0 :         return krb5_enomem(context);
     486             : 
     487      313768 :     p->pac = ptr;
     488      313768 :     p->pac->buffers[num_buffers].type = 0;
     489      313768 :     p->pac->buffers[num_buffers].buffersize = 0;
     490      313768 :     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     1084887 :     for (i = 0; i < num_buffers; i++) {
     500      771119 :         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      313768 :     ret = pac_aligned_size(context, p->data.length, PAC_INFO_BUFFER_SIZE, &offset);
     514      313768 :     if (ret == 0)
     515             :         /* Set the new length = offset + nd->length + alignment */
     516      313768 :         ret = pac_aligned_size(context, offset, nd->length, &len);
     517      313768 :     if (ret) {
     518           0 :         krb5_set_error_message(context, ret, "PAC buffer too large");
     519           0 :         return ret;
     520             :     }
     521      313768 :     ret = krb5_data_realloc(&p->data, len);
     522      313768 :     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      313768 :     memset((char *)p->data.data + old_len, 0, len - old_len);
     529             : 
     530      313768 :     p->pac->buffers[num_buffers].type = type;
     531      313768 :     p->pac->buffers[num_buffers].buffersize = nd->length;
     532      313768 :     p->pac->buffers[num_buffers].offset = offset;
     533             : 
     534             :     /* Adjust all the buffer offsets in the existing PAC_INFO_BUFFERs now */
     535     1084887 :     for (i = 0; i < num_buffers; i++)
     536      771119 :         p->pac->buffers[i].offset += PAC_INFO_BUFFER_SIZE;
     537             : 
     538             :     /*
     539             :      * Make place for new PAC INFO BUFFER header
     540             :      */
     541      313768 :     header_size -= PAC_INFO_BUFFER_SIZE;
     542      627536 :     memmove((unsigned char *)p->data.data + header_size + PAC_INFO_BUFFER_SIZE,
     543      313768 :             (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      313768 :     memset((unsigned char *)p->data.data + header_size, 0,
     547             :            PAC_INFO_BUFFER_SIZE);
     548             : 
     549             :     /*
     550             :      * Copy in new data part
     551             :      */
     552      313768 :     memcpy((unsigned char *)p->data.data + offset, nd->data, nd->length);
     553      313768 :     p->pac->numbuffers += 1;
     554      313768 :     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      373050 : 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     2812514 :     for (i = 0; i < p->pac->numbuffers; i++) {
     579     1360756 :         size_t len = p->pac->buffers[i].buffersize;
     580     1360756 :         size_t offset = p->pac->buffers[i].offset;
     581             : 
     582     1360756 :         if (p->pac->buffers[i].type != type)
     583     1033207 :             continue;
     584             : 
     585      327549 :         if (!data)
     586       35917 :             return 0;
     587             : 
     588      291632 :         ret = krb5_data_copy(data, (unsigned char *)p->data.data + offset, len);
     589      291632 :         if (ret)
     590           0 :             krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
     591      291632 :         return ret;
     592             :     }
     593       45501 :     krb5_set_error_message(context, ENOENT, "No PAC buffer of type %lu was found",
     594             :                            (unsigned long)type);
     595       45501 :     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             :          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       36015 : 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       36015 :     *types = calloc(p->pac->numbuffers, sizeof(**types));
     650       36015 :     if (*types == NULL) {
     651           0 :         *len = 0;
     652           0 :         return krb5_enomem(context);
     653             :     }
     654      288138 :     for (i = 0; i < p->pac->numbuffers; i++)
     655      252123 :         (*types)[i] = p->pac->buffers[i].type;
     656       36015 :     *len = p->pac->numbuffers;
     657             : 
     658       36015 :     return 0;
     659             : }
     660             : 
     661             : /*
     662             :  *
     663             :  */
     664             : 
     665             : KRB5_LIB_FUNCTION void KRB5_LIB_CALL
     666      335651 : krb5_pac_free(krb5_context context, krb5_pac pac)
     667             : {
     668      335651 :     heim_release(pac);
     669      335651 : }
     670             : 
     671             : /*
     672             :  *
     673             :  */
     674             : 
     675             : static krb5_error_code
     676       81889 : 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       81889 :     krb5_storage *sp = NULL;
     684             :     uint32_t type;
     685             :     krb5_error_code ret;
     686             :     Checksum cksum;
     687             :     size_t cksumsize;
     688             : 
     689       81889 :     memset(&cksum, 0, sizeof(cksum));
     690             : 
     691       81889 :     sp = krb5_storage_from_mem((char *)data->data + sig->offset,
     692       81889 :                                sig->buffersize);
     693       81889 :     if (sp == NULL)
     694           0 :         return krb5_enomem(context);
     695             : 
     696       81889 :     krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
     697             : 
     698       81889 :     CHECK(ret, krb5_ret_uint32(sp, &type), out);
     699       81889 :     cksum.cksumtype = type;
     700             : 
     701       81889 :     ret = krb5_checksumsize(context, type, &cksumsize);
     702       81889 :     if (ret)
     703           8 :         goto out;
     704             : 
     705             :     /* Allow for RODCIdentifier trailer, see MS-PAC 2.8 */
     706       81881 :     if (cksumsize > (sig->buffersize - krb5_storage_seek(sp, 0, SEEK_CUR))) {
     707           0 :         ret = EINVAL;
     708           0 :         goto out;
     709             :     }
     710       81881 :     cksum.checksum.length = cksumsize;
     711       81881 :     cksum.checksum.data = malloc(cksum.checksum.length);
     712       81881 :     if (cksum.checksum.data == NULL) {
     713           0 :         ret = krb5_enomem(context);
     714           0 :         goto out;
     715             :     }
     716       81881 :     ret = krb5_storage_read(sp, cksum.checksum.data, cksum.checksum.length);
     717       81881 :     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       81881 :     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       89507 :     if (cksum.cksumtype == CKSUMTYPE_HMAC_MD5 && !strict_cksumtype_match) {
     740             :         Checksum local_checksum;
     741             : 
     742        7642 :         memset(&local_checksum, 0, sizeof(local_checksum));
     743             : 
     744        7642 :         ret = HMAC_MD5_any_checksum(context, key, ptr, len,
     745             :                                     KRB5_KU_OTHER_CKSUM, &local_checksum);
     746             : 
     747        7642 :         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        7642 :         krb5_data_free(&local_checksum.checksum);
     754             : 
     755             :    } else {
     756       74223 :         krb5_crypto crypto = NULL;
     757             : 
     758       74223 :         ret = krb5_crypto_init(context, key, 0, &crypto);
     759       74223 :         if (ret)
     760           0 :                 goto out;
     761             : 
     762       74223 :         ret = krb5_verify_checksum(context, crypto, KRB5_KU_OTHER_CKSUM,
     763             :                                    ptr, len, &cksum);
     764       74223 :         krb5_crypto_destroy(context, crypto);
     765             :     }
     766       81865 :     free(cksum.checksum.data);
     767       81865 :     krb5_storage_free(sp);
     768             : 
     769       81865 :     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      137474 : 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      137474 :     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      137474 :     if (cksumtype == (uint32_t)CKSUMTYPE_HMAC_MD5) {
     800       14801 :         ret = HMAC_MD5_any_checksum(context, key, data, datalen,
     801             :                                     KRB5_KU_OTHER_CKSUM, &cksum);
     802       14801 :         if (ret)
     803           0 :             return ret;
     804             :     } else {
     805      122673 :         ret = krb5_crypto_init(context, key, 0, &crypto);
     806      122673 :         if (ret)
     807           0 :             return ret;
     808             : 
     809      122673 :         ret = krb5_create_checksum(context, crypto, KRB5_KU_OTHER_CKSUM, 0,
     810             :                                    data, datalen, &cksum);
     811      122673 :         krb5_crypto_destroy(context, crypto);
     812      122673 :         if (ret)
     813           0 :             return ret;
     814             :     }
     815      137474 :     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      137474 :     memcpy(sig, cksum.checksum.data, siglen);
     822      137474 :     free_Checksum(&cksum);
     823             : 
     824      137474 :     return 0;
     825             : }
     826             : 
     827             : static krb5_error_code
     828       81642 : 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       81642 :     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       81642 :     char *upn = NULL;
     843       81642 :     char *dns_domain_name = NULL;
     844       81642 :     char *sam_name = NULL;
     845             : 
     846       81642 :     *upn_princ = NULL;
     847       81642 :     *flags = 0;
     848       81642 :     *canon_princ = NULL;
     849       81642 :     krb5_data_zero(sid);
     850             : 
     851       81642 :     sp = krb5_storage_from_readonly_mem((const char *)data->data + upndnsinfo->offset,
     852       81642 :                                         upndnsinfo->buffersize);
     853       81642 :     if (sp == NULL)
     854           0 :         return krb5_enomem(context);
     855             : 
     856       81642 :     krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
     857             : 
     858       81642 :     CHECK(ret, krb5_ret_uint16(sp, &upn_length), out);
     859       81642 :     CHECK(ret, krb5_ret_uint16(sp, &upn_offset), out);
     860       81642 :     CHECK(ret, krb5_ret_uint16(sp, &dns_domain_name_length), out);
     861       81642 :     CHECK(ret, krb5_ret_uint16(sp, &dns_domain_name_offset), out);
     862       81642 :     CHECK(ret, krb5_ret_uint32(sp, flags), out);
     863             : 
     864       81642 :     if (*flags & PAC_EXTRA_LOGON_INFO_FLAGS_HAS_SAM_NAME_AND_SID) {
     865       81642 :         CHECK(ret, krb5_ret_uint16(sp, &canon_princ_length), out);
     866       81642 :         CHECK(ret, krb5_ret_uint16(sp, &canon_princ_offset), out);
     867       81642 :         CHECK(ret, krb5_ret_uint16(sp, &sid_length), out);
     868       81642 :         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       81642 :     if (upn_offset) {
     875       81642 :         CHECK(ret, _krb5_ret_utf8_from_ucs2le_at_offset(sp, upn_offset,
     876             :                                                         upn_length, &upn), out);
     877             :     }
     878       81642 :     CHECK(ret, _krb5_ret_utf8_from_ucs2le_at_offset(sp, dns_domain_name_offset,
     879             :                                                     dns_domain_name_length, &dns_domain_name), out);
     880       81642 :     if ((*flags & PAC_EXTRA_LOGON_INFO_FLAGS_HAS_SAM_NAME_AND_SID) && canon_princ_offset) {
     881       81642 :         CHECK(ret, _krb5_ret_utf8_from_ucs2le_at_offset(sp, canon_princ_offset,
     882             :                                                         canon_princ_length, &sam_name), out);
     883             :     }
     884             : 
     885       81642 :     if (upn_offset) {
     886       81642 :         ret = krb5_parse_name_flags(context,
     887             :                                     upn,
     888             :                                     KRB5_PRINCIPAL_PARSE_ENTERPRISE |
     889             :                                     KRB5_PRINCIPAL_PARSE_NO_DEF_REALM,
     890             :                                     upn_princ);
     891       81642 :         if (ret)
     892           0 :             goto out;
     893             : 
     894       81642 :         ret = krb5_principal_set_realm(context, *upn_princ, dns_domain_name);
     895       81642 :         if (ret)
     896           0 :             goto out;
     897             :     }
     898             : 
     899       81642 :     if (canon_princ_offset) {
     900       81642 :         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       81642 :         if (ret)
     906           0 :             goto out;
     907             : 
     908       81642 :         ret = krb5_principal_set_realm(context, *canon_princ, dns_domain_name);
     909       81642 :         if (ret)
     910           0 :             goto out;
     911             :     }
     912             : 
     913       81642 :     if (sid_offset)
     914       81642 :         CHECK(ret, _krb5_ret_data_at_offset(sp, sid_offset, sid_length, sid), out);
     915             : 
     916      163284 : out:
     917       81642 :     free(upn);
     918       81642 :     free(dns_domain_name);
     919       81642 :     free(sam_name);
     920             : 
     921       81642 :     krb5_storage_free(sp);
     922             : 
     923       81642 :     return ret;
     924             : }
     925             : 
     926             : /*
     927             :  *
     928             :  */
     929             : 
     930             : #define NTTIME_EPOCH 0x019DB1DED53E8000LL
     931             : 
     932             : static uint64_t
     933      135759 : unix2nttime(time_t unix_time)
     934             : {
     935             :     long long wt;
     936      135759 :     wt = unix_time * (uint64_t)10000000 + (uint64_t)NTTIME_EPOCH;
     937      135759 :     return wt;
     938             : }
     939             : 
     940             : static krb5_error_code
     941       81704 : 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       81704 :     krb5_storage *sp = NULL;
     950             :     uint16_t len;
     951       81704 :     char *s = NULL;
     952       81704 :     char *principal_string = NULL;
     953       81704 :     char *logon_string = NULL;
     954             : 
     955       81704 :     sp = krb5_storage_from_readonly_mem((const char *)data->data + logon_name->offset,
     956       81704 :                                         logon_name->buffersize);
     957       81704 :     if (sp == NULL)
     958           0 :         return krb5_enomem(context);
     959             : 
     960       81704 :     krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
     961             : 
     962       81704 :     CHECK(ret, krb5_ret_uint32(sp, &time1), out);
     963       81704 :     CHECK(ret, krb5_ret_uint32(sp, &time2), out);
     964             : 
     965             :     {
     966             :         uint64_t t1, t2;
     967       81704 :         t1 = unix2nttime(authtime);
     968       81704 :         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       81704 :         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       81704 :     CHECK(ret, krb5_ret_uint16(sp, &len), out);
     982       81704 :     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       81704 :     s = malloc(len);
     989       81704 :     if (s == NULL) {
     990           0 :         krb5_storage_free(sp);
     991           0 :         return krb5_enomem(context);
     992             :     }
     993       81704 :     ret = krb5_storage_read(sp, s, len);
     994       81704 :     if (ret != len) {
     995           0 :         krb5_storage_free(sp);
     996           0 :         krb5_set_error_message(context, EINVAL, "Failed to read PAC logon name");
     997           0 :         return EINVAL;
     998             :     }
     999       81704 :     krb5_storage_free(sp);
    1000             :     {
    1001       81704 :         size_t ucs2len = len / 2;
    1002             :         uint16_t *ucs2;
    1003             :         size_t u8len;
    1004       81704 :         unsigned int flags = WIND_RW_LE;
    1005             : 
    1006       81704 :         ucs2 = malloc(sizeof(ucs2[0]) * ucs2len);
    1007       81704 :         if (ucs2 == NULL)
    1008           0 :             return krb5_enomem(context);
    1009             : 
    1010       81704 :         ret = wind_ucs2read(s, len, &flags, ucs2, &ucs2len);
    1011       81704 :         free(s);
    1012       81704 :         if (ret) {
    1013           0 :             free(ucs2);
    1014           0 :             krb5_set_error_message(context, ret, "Failed to convert string to UCS-2");
    1015           0 :             return ret;
    1016             :         }
    1017       81704 :         ret = wind_ucs2utf8_length(ucs2, ucs2len, &u8len);
    1018       81704 :         if (ret) {
    1019           0 :             free(ucs2);
    1020           0 :             krb5_set_error_message(context, ret, "Failed to count length of UCS-2 string");
    1021           0 :             return ret;
    1022             :         }
    1023       81704 :         u8len += 1; /* Add space for NUL */
    1024       81704 :         logon_string = malloc(u8len);
    1025       81704 :         if (logon_string == NULL) {
    1026           0 :             free(ucs2);
    1027           0 :             return krb5_enomem(context);
    1028             :         }
    1029       81704 :         ret = wind_ucs2utf8(ucs2, ucs2len, logon_string, &u8len);
    1030       81704 :         free(ucs2);
    1031       81704 :         if (ret) {
    1032           0 :             free(logon_string);
    1033           0 :             krb5_set_error_message(context, ret, "Failed to convert to UTF-8");
    1034           0 :             return ret;
    1035             :         }
    1036             :     }
    1037       81704 :     ret = krb5_unparse_name_flags(context, principal,
    1038             :                                   KRB5_PRINCIPAL_UNPARSE_NO_REALM |
    1039             :                                   KRB5_PRINCIPAL_UNPARSE_DISPLAY,
    1040             :                                   &principal_string);
    1041       81704 :     if (ret) {
    1042           0 :         free(logon_string);
    1043           0 :         return ret;
    1044             :     }
    1045             : 
    1046       81704 :     if (strcmp(logon_string, principal_string) != 0) {
    1047           0 :         ret = EINVAL;
    1048           0 :         krb5_set_error_message(context, ret, "PAC logon name [%s] mismatch principal name [%s]",
    1049             :                                logon_string, principal_string);
    1050             :     }
    1051       81704 :     free(logon_string);
    1052       81704 :     free(principal_string);
    1053       81704 :     return ret;
    1054           0 : out:
    1055           0 :     krb5_storage_free(sp);
    1056           0 :     return ret;
    1057             : }
    1058             : 
    1059             : /*
    1060             :  *
    1061             :  */
    1062             : 
    1063             : static krb5_error_code
    1064       54055 : build_logon_name(krb5_context context,
    1065             :                  time_t authtime,
    1066             :                  krb5_const_principal principal,
    1067             :                  krb5_data *logon)
    1068             : {
    1069             :     krb5_error_code ret;
    1070             :     krb5_storage *sp;
    1071             :     uint64_t t;
    1072       54055 :     char *s, *s2 = NULL;
    1073             :     size_t s2_len;
    1074             : 
    1075       54055 :     t = unix2nttime(authtime);
    1076             : 
    1077       54055 :     krb5_data_zero(logon);
    1078             : 
    1079       54055 :     sp = krb5_storage_emem();
    1080       54055 :     if (sp == NULL)
    1081           0 :         return krb5_enomem(context);
    1082             : 
    1083       54055 :     krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
    1084             : 
    1085       54055 :     CHECK(ret, krb5_store_uint32(sp, t & 0xffffffff), out);
    1086       54055 :     CHECK(ret, krb5_store_uint32(sp, t >> 32), out);
    1087             : 
    1088       54055 :     ret = krb5_unparse_name_flags(context, principal,
    1089             :                                   KRB5_PRINCIPAL_UNPARSE_NO_REALM |
    1090             :                                   KRB5_PRINCIPAL_UNPARSE_DISPLAY,
    1091             :                                   &s);
    1092       54055 :     if (ret)
    1093           0 :         goto out;
    1094             : 
    1095             :     {
    1096             :         size_t ucs2_len;
    1097             :         uint16_t *ucs2;
    1098             :         unsigned int flags;
    1099             : 
    1100       54055 :         ret = wind_utf8ucs2_length(s, &ucs2_len);
    1101       54055 :         if (ret) {
    1102           0 :             krb5_set_error_message(context, ret, "Principal %s is not valid UTF-8", s);
    1103           0 :             free(s);
    1104           0 :             return ret;
    1105             :         }
    1106             : 
    1107       54055 :         ucs2 = malloc(sizeof(ucs2[0]) * ucs2_len);
    1108       54055 :         if (ucs2 == NULL) {
    1109           0 :             free(s);
    1110           0 :             return krb5_enomem(context);
    1111             :         }
    1112             : 
    1113       54055 :         ret = wind_utf8ucs2(s, ucs2, &ucs2_len);
    1114       54055 :         if (ret) {
    1115           0 :             free(ucs2);
    1116           0 :             krb5_set_error_message(context, ret, "Principal %s is not valid UTF-8", s);
    1117           0 :             free(s);
    1118           0 :             return ret;
    1119             :         } else
    1120       54055 :             free(s);
    1121             : 
    1122       54055 :         s2_len = (ucs2_len + 1) * 2;
    1123       54055 :         s2 = malloc(s2_len);
    1124       54055 :         if (s2 == NULL) {
    1125           0 :             free(ucs2);
    1126           0 :             return krb5_enomem(context);
    1127             :         }
    1128             : 
    1129       54055 :         flags = WIND_RW_LE;
    1130       54055 :         ret = wind_ucs2write(ucs2, ucs2_len,
    1131             :                              &flags, s2, &s2_len);
    1132       54055 :         free(ucs2);
    1133       54055 :         if (ret) {
    1134           0 :             free(s2);
    1135           0 :             krb5_set_error_message(context, ret, "Failed to write to UCS-2 buffer");
    1136           0 :             return ret;
    1137             :         }
    1138             : 
    1139             :         /*
    1140             :          * we do not want zero termination
    1141             :          */
    1142       54055 :         s2_len = ucs2_len * 2;
    1143             :     }
    1144             : 
    1145       54055 :     CHECK(ret, krb5_store_uint16(sp, s2_len), out);
    1146             : 
    1147       54055 :     ret = krb5_storage_write(sp, s2, s2_len);
    1148       54055 :     if (ret != (int)s2_len) {
    1149           0 :         ret = krb5_enomem(context);
    1150           0 :         goto out;
    1151             :     }
    1152       54055 :     ret = krb5_storage_to_data(sp, logon);
    1153             : 
    1154       54055 :  out:
    1155       54055 :     free(s2);
    1156       54055 :     krb5_storage_free(sp);
    1157       54055 :     return ret;
    1158             : }
    1159             : 
    1160             : static krb5_error_code
    1161       35964 : parse_attributes_info(krb5_context context,
    1162             :                       const struct PAC_INFO_BUFFER *attributes_info,
    1163             :                       const krb5_data *data,
    1164             :                       uint64_t *pac_attributes)
    1165             : {
    1166             :     krb5_error_code ret;
    1167       35964 :     krb5_storage *sp = NULL;
    1168             :     uint32_t flags_length;
    1169             : 
    1170       35964 :     *pac_attributes = 0;
    1171             : 
    1172       35964 :     sp = krb5_storage_from_readonly_mem((const char *)data->data + attributes_info->offset,
    1173       35964 :                                         attributes_info->buffersize);
    1174       35964 :     if (sp == NULL)
    1175           0 :         return krb5_enomem(context);
    1176             : 
    1177       35964 :     krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
    1178             : 
    1179       35964 :     ret = krb5_ret_uint32(sp, &flags_length);
    1180       35964 :     if (ret == 0) {
    1181       35964 :         if (flags_length > 32)
    1182           0 :             ret = krb5_ret_uint64(sp, pac_attributes);
    1183             :         else {
    1184       35964 :             uint32_t pac_attributes32 = 0;
    1185       35964 :             ret = krb5_ret_uint32(sp, &pac_attributes32);
    1186       35964 :             *pac_attributes = pac_attributes32;
    1187             :         }
    1188             :     }
    1189             : 
    1190       35964 :     krb5_storage_free(sp);
    1191             : 
    1192       35964 :     return ret;
    1193             : }
    1194             : 
    1195             : /**
    1196             :  * Verify the PAC.
    1197             :  *
    1198             :  * @param context Kerberos 5 context.
    1199             :  * @param pac the pac structure returned by krb5_pac_parse().
    1200             :  * @param authtime The time of the ticket the PAC belongs to.
    1201             :  * @param principal the principal to verify.
    1202             :  * @param server The service key, may be given.
    1203             :  * @param privsvr The KDC key, may be given.
    1204             : 
    1205             :  * @return Returns 0 to indicate success. Otherwise an kerberos et
    1206             :  * error code is returned, see krb5_get_error_message().
    1207             :  *
    1208             :  * @ingroup krb5_pac
    1209             :  */
    1210             : 
    1211             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1212       81785 : krb5_pac_verify(krb5_context context,
    1213             :                 const krb5_pac pac,
    1214             :                 time_t authtime,
    1215             :                 krb5_const_principal principal,
    1216             :                 const krb5_keyblock *server,
    1217             :                 const krb5_keyblock *privsvr)
    1218             : {
    1219             :     krb5_error_code ret;
    1220             :     /*
    1221             :      * If we are in the KDC, we expect back a full signature in the PAC
    1222             :      *
    1223             :      * This is set up as a seperate variable to make it easier if a
    1224             :      * subsequent patch is added to make this configurable in the
    1225             :      * krb5.conf (or forced into the krb5_context via Samba)
    1226             :      */
    1227       81785 :     krb5_boolean expect_full_sig = privsvr != NULL;
    1228             : 
    1229             :     /*
    1230             :      * If we are on the KDC, then we trust we are not in a realm with
    1231             :      * buggy Windows 2008 or similar era DCs that give our HMAC-MD5
    1232             :      * sigatures over AES keys.  DES is also already gone.
    1233             :      */
    1234       81785 :     krb5_boolean strict_cksumtype_match = expect_full_sig;
    1235             : 
    1236       81785 :     if (pac->server_checksum == NULL) {
    1237           5 :         krb5_set_error_message(context, EINVAL, "PAC missing server checksum");
    1238           5 :         return EINVAL;
    1239             :     }
    1240       81780 :     if (pac->privsvr_checksum == NULL) {
    1241           5 :         krb5_set_error_message(context, EINVAL, "PAC missing kdc checksum");
    1242           5 :         return EINVAL;
    1243             :     }
    1244       81775 :     if (pac->logon_name == NULL) {
    1245           0 :         krb5_set_error_message(context, EINVAL, "PAC missing logon name");
    1246           0 :         return EINVAL;
    1247             :     }
    1248       81775 :     if (expect_full_sig && pac->full_checksum == NULL) {
    1249           2 :         krb5_set_error_message(context, EINVAL, "PAC missing full checksum");
    1250           2 :         return EINVAL;
    1251             :     }
    1252             : 
    1253       81773 :     if (principal != NULL) {
    1254       81704 :         ret = verify_logonname(context, pac->logon_name, &pac->data, authtime,
    1255             :                                principal);
    1256       81704 :         if (ret)
    1257           0 :             return ret;
    1258             :     }
    1259             : 
    1260      163546 :     if (pac->server_checksum->buffersize < 4 ||
    1261       81773 :         pac->privsvr_checksum->buffersize < 4)
    1262           0 :         return EINVAL;
    1263             : 
    1264       81773 :     if (server != NULL || privsvr != NULL)
    1265             :     {
    1266             :         krb5_data *copy;
    1267             : 
    1268             :         /*
    1269             :          * in the service case, clean out data option of the privsvr and
    1270             :          * server checksum before checking the checksum.
    1271             :          */
    1272             : 
    1273       81773 :         ret = krb5_copy_data(context, &pac->data, &copy);
    1274       81773 :         if (ret)
    1275          28 :             return ret;
    1276             : 
    1277       81773 :         memset((char *)copy->data + pac->server_checksum->offset + 4,
    1278             :                0,
    1279       81773 :                pac->server_checksum->buffersize - 4);
    1280             : 
    1281       81773 :         memset((char *)copy->data + pac->privsvr_checksum->offset + 4,
    1282             :                0,
    1283       81773 :                pac->privsvr_checksum->buffersize - 4);
    1284             : 
    1285       81773 :         if (server != NULL) {
    1286      245112 :             ret = verify_checksum(context,
    1287       81704 :                                   pac->server_checksum,
    1288       81704 :                                   &pac->data,
    1289       81704 :                                   copy->data,
    1290       81704 :                                   copy->length,
    1291             :                                   server,
    1292             :                                   strict_cksumtype_match);
    1293       81704 :             if (ret) {
    1294          18 :                 krb5_free_data(context, copy);
    1295          18 :                 return ret;
    1296             :             }
    1297             :         }
    1298             : 
    1299       81755 :         if (privsvr != NULL && pac->full_checksum != NULL) {
    1300             :             /*
    1301             :              * in the full checksum case, also clean out the full
    1302             :              * checksum before verifying it.
    1303             :              */
    1304          69 :             memset((char *)copy->data + pac->full_checksum->offset + 4,
    1305             :                    0,
    1306          69 :                    pac->full_checksum->buffersize - 4);
    1307             : 
    1308         207 :             ret = verify_checksum(context,
    1309          69 :                                   pac->full_checksum,
    1310          69 :                                   &pac->data,
    1311          69 :                                   copy->data,
    1312          69 :                                   copy->length,
    1313             :                                   privsvr,
    1314             :                                   strict_cksumtype_match);
    1315          69 :             if (ret) {
    1316          10 :                 krb5_free_data(context, copy);
    1317          10 :                 return ret;
    1318             :             }
    1319             :         }
    1320             : 
    1321       81745 :         krb5_free_data(context, copy);
    1322             :     }
    1323       81745 :     if (privsvr) {
    1324             :         /* The priv checksum covers the server checksum */
    1325         177 :         ret = verify_checksum(context,
    1326          59 :                               pac->privsvr_checksum,
    1327          59 :                               &pac->data,
    1328          59 :                               (char *)pac->data.data
    1329          59 :                               + pac->server_checksum->offset + 4,
    1330          59 :                               pac->server_checksum->buffersize - 4,
    1331             :                               privsvr,
    1332             :                               strict_cksumtype_match);
    1333          59 :         if (ret)
    1334           0 :             return ret;
    1335             : 
    1336          59 :         if (pac->ticket_sign_data.length != 0) {
    1337          57 :             if (pac->ticket_checksum == NULL) {
    1338           0 :                 krb5_set_error_message(context, EINVAL,
    1339             :                                        "PAC missing ticket checksum");
    1340           0 :                 return EINVAL;
    1341             :             }
    1342             : 
    1343          57 :             ret = verify_checksum(context, pac->ticket_checksum, &pac->data,
    1344             :                                  pac->ticket_sign_data.data,
    1345             :                                  pac->ticket_sign_data.length, privsvr,
    1346             :                                  strict_cksumtype_match);
    1347          57 :             if (ret)
    1348           8 :                 return ret;
    1349             :         }
    1350             :     }
    1351             : 
    1352      163430 :     if (pac->upn_dns_info &&
    1353      163335 :         pac->upn_princ == NULL && pac->canon_princ == NULL && pac->sid.data == NULL) {
    1354       81642 :         ret = parse_upn_dns_info(context, pac->upn_dns_info, &pac->data,
    1355             :                                  &pac->upn_princ, &pac->upn_flags,
    1356             :                                  &pac->canon_princ, &pac->sid);
    1357       81642 :         if (ret)
    1358           0 :             return ret;
    1359             :     }
    1360             : 
    1361       81737 :     if (pac->attributes_info) {
    1362       35964 :         ret = parse_attributes_info(context, pac->attributes_info, &pac->data,
    1363             :                                     &pac->pac_attributes);
    1364       35964 :         if (ret)
    1365           0 :             return ret;
    1366             :     }
    1367             : 
    1368       81737 :     return 0;
    1369             : }
    1370             : 
    1371             : /*
    1372             :  *
    1373             :  */
    1374             : 
    1375             : static krb5_error_code
    1376      250952 : fill_zeros(krb5_context context, krb5_storage *sp, size_t len)
    1377             : {
    1378             :     ssize_t sret;
    1379             :     size_t l;
    1380             : 
    1381      890330 :     while (len) {
    1382      388426 :         l = len;
    1383      388426 :         if (l > sizeof(zeros))
    1384      137474 :             l = sizeof(zeros);
    1385      388426 :         sret = krb5_storage_write(sp, zeros, l);
    1386      388426 :         if (sret != l)
    1387           0 :             return krb5_enomem(context);
    1388             : 
    1389      388426 :         len -= sret;
    1390             :     }
    1391      250952 :     return 0;
    1392             : }
    1393             : 
    1394             : static krb5_error_code
    1395      108110 : pac_checksum(krb5_context context,
    1396             :              const krb5_keyblock *key,
    1397             :              uint32_t *cksumtype,
    1398             :              size_t *cksumsize)
    1399             : {
    1400             :     krb5_cksumtype cktype;
    1401             :     krb5_error_code ret;
    1402      108110 :     krb5_crypto crypto = NULL;
    1403             : 
    1404      108110 :     ret = krb5_crypto_init(context, key, 0, &crypto);
    1405      108110 :     if (ret)
    1406           0 :         return ret;
    1407             : 
    1408      108110 :     ret = krb5_crypto_get_checksum_type(context, crypto, &cktype);
    1409      108110 :     krb5_crypto_destroy(context, crypto);
    1410      108110 :     if (ret)
    1411           0 :         return ret;
    1412             : 
    1413      108110 :     if (krb5_checksum_is_keyed(context, cktype) == FALSE) {
    1414           0 :         *cksumtype = CKSUMTYPE_HMAC_MD5;
    1415           0 :         *cksumsize = 16;
    1416             :     }
    1417             : 
    1418      108110 :     ret = krb5_checksumsize(context, cktype, cksumsize);
    1419      108110 :     if (ret)
    1420           0 :         return ret;
    1421             : 
    1422      108110 :     *cksumtype = (uint32_t)cktype;
    1423             : 
    1424      108110 :     return 0;
    1425             : }
    1426             : 
    1427             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1428       54055 : _krb5_pac_sign(krb5_context context,
    1429             :                krb5_pac p,
    1430             :                time_t authtime,
    1431             :                krb5_const_principal principal,
    1432             :                const krb5_keyblock *server_key,
    1433             :                const krb5_keyblock *priv_key,
    1434             :                uint16_t rodc_id,
    1435             :                krb5_const_principal upn_princ,
    1436             :                krb5_const_principal canon_princ,
    1437             :                krb5_boolean add_full_sig,
    1438             :                uint64_t *pac_attributes, /* optional */
    1439             :                krb5_data *data)
    1440             : {
    1441             :     krb5_error_code ret;
    1442       54055 :     krb5_storage *sp = NULL, *spdata = NULL;
    1443             :     uint32_t end;
    1444             :     size_t server_size, priv_size;
    1445       54055 :     uint32_t server_offset = 0, priv_offset = 0, ticket_offset = 0, full_offset = 0;
    1446       54055 :     uint32_t server_cksumtype = 0, priv_cksumtype = 0;
    1447       54055 :     uint32_t num = 0;
    1448             :     uint32_t i, sz;
    1449             :     krb5_data logon, d;
    1450             : 
    1451       54055 :     krb5_data_zero(&d);
    1452       54055 :     krb5_data_zero(&logon);
    1453             : 
    1454             :     /*
    1455             :      * Set convenience buffer pointers.
    1456             :      *
    1457             :      * This could really stand to be moved to krb5_pac_add_buffer() and/or
    1458             :      * utility function, so that when this function gets called they must
    1459             :      * already have been set.
    1460             :      */
    1461      362929 :     for (i = 0; i < p->pac->numbuffers; i++) {
    1462      308874 :         if (p->pac->buffers[i].type == PAC_SERVER_CHECKSUM) {
    1463       35094 :             if (p->server_checksum == NULL) {
    1464       35094 :                 p->server_checksum = &p->pac->buffers[i];
    1465             :             }
    1466       35094 :             if (p->server_checksum != &p->pac->buffers[i]) {
    1467           0 :                 ret = KRB5KDC_ERR_BADOPTION;
    1468           0 :                 krb5_set_error_message(context, ret,
    1469           0 :                                        N_("PAC has multiple server checksums", ""));
    1470           0 :                 goto out;
    1471             :             }
    1472      273780 :         } else if (p->pac->buffers[i].type == PAC_PRIVSVR_CHECKSUM) {
    1473       35094 :             if (p->privsvr_checksum == NULL) {
    1474       35094 :                 p->privsvr_checksum = &p->pac->buffers[i];
    1475             :             }
    1476       35094 :             if (p->privsvr_checksum != &p->pac->buffers[i]) {
    1477           0 :                 ret = KRB5KDC_ERR_BADOPTION;
    1478           0 :                 krb5_set_error_message(context, ret,
    1479           0 :                                        N_("PAC has multiple KDC checksums", ""));
    1480           0 :                 goto out;
    1481             :             }
    1482      238686 :         } else if (p->pac->buffers[i].type == PAC_LOGON_NAME) {
    1483       54055 :             if (p->logon_name == NULL) {
    1484       54055 :                 p->logon_name = &p->pac->buffers[i];
    1485             :             }
    1486       54055 :             if (p->logon_name != &p->pac->buffers[i]) {
    1487           0 :                 ret = KRB5KDC_ERR_BADOPTION;
    1488           0 :                 krb5_set_error_message(context, ret,
    1489           0 :                                        N_("PAC has multiple logon names", ""));
    1490           0 :                 goto out;
    1491             :             }
    1492      184631 :         } else if (p->pac->buffers[i].type == PAC_UPN_DNS_INFO) {
    1493       54055 :             if (p->upn_dns_info == NULL) {
    1494       54055 :                 p->upn_dns_info = &p->pac->buffers[i];
    1495             :             }
    1496       54055 :             if (p->upn_dns_info != &p->pac->buffers[i]) {
    1497           0 :                 ret = KRB5KDC_ERR_BADOPTION;
    1498           0 :                 krb5_set_error_message(context, ret,
    1499           0 :                                        N_("PAC has multiple UPN DNS info buffers", ""));
    1500           0 :                 goto out;
    1501             :             }
    1502      130576 :         } else if (p->pac->buffers[i].type == PAC_TICKET_CHECKSUM) {
    1503          49 :             if (p->ticket_checksum == NULL) {
    1504          49 :                 p->ticket_checksum = &p->pac->buffers[i];
    1505             :             }
    1506          49 :             if (p->ticket_checksum != &p->pac->buffers[i]) {
    1507           0 :                 ret = KRB5KDC_ERR_BADOPTION;
    1508           0 :                 krb5_set_error_message(context, ret,
    1509           0 :                                        N_("PAC has multiple ticket checksums", ""));
    1510           0 :                 goto out;
    1511             :             }
    1512      130527 :         } else if (p->pac->buffers[i].type == PAC_ATTRIBUTES_INFO) {
    1513       38187 :             if (p->attributes_info == NULL) {
    1514       38187 :                 p->attributes_info = &p->pac->buffers[i];
    1515             :             }
    1516       38187 :             if (p->attributes_info != &p->pac->buffers[i]) {
    1517           0 :                 ret = KRB5KDC_ERR_BADOPTION;
    1518           0 :                 krb5_set_error_message(context, ret,
    1519           0 :                                        N_("PAC has multiple attributes info buffers", ""));
    1520           0 :                 goto out;
    1521             :             }
    1522       92340 :         } else if (p->pac->buffers[i].type == PAC_FULL_CHECKSUM) {
    1523          49 :             if (p->full_checksum == NULL) {
    1524          49 :                 p->full_checksum = &p->pac->buffers[i];
    1525             :             }
    1526          49 :             if (p->full_checksum != &p->pac->buffers[i]) {
    1527           0 :                 ret = KRB5KDC_ERR_BADOPTION;
    1528           0 :                 krb5_set_error_message(context, ret,
    1529           0 :                                        N_("PAC has multiple full checksums", ""));
    1530           0 :                 goto out;
    1531             :             }
    1532             :         }
    1533             :     }
    1534             : 
    1535             :     /* Count missing-but-necessary buffers */
    1536       54055 :     if (p->logon_name == NULL)
    1537           0 :         num++;
    1538       54055 :     if (p->server_checksum == NULL)
    1539       18961 :         num++;
    1540       54055 :     if (p->privsvr_checksum == NULL)
    1541       18961 :         num++;
    1542       54055 :     if (p->ticket_sign_data.length != 0 && p->ticket_checksum == NULL)
    1543       14633 :         num++;
    1544       54055 :     if (add_full_sig && p->full_checksum == NULL)
    1545       14633 :         num++;
    1546             : 
    1547             :     /* Allocate any missing-but-necessary buffers */
    1548       54055 :     if (num) {
    1549             :         void *ptr;
    1550             :         uint32_t old_len, len;
    1551             : 
    1552       32960 :         if (p->pac->numbuffers > UINT32_MAX - num) {
    1553           0 :             ret = EINVAL;
    1554           0 :             krb5_set_error_message(context, ret, "integer overrun");
    1555           0 :             goto out;
    1556             :         }
    1557       32960 :         ret = pac_header_size(context, p->pac->numbuffers, &old_len);
    1558       32960 :         if (ret == 0)
    1559       32960 :             ret = pac_header_size(context, p->pac->numbuffers + num, &len);
    1560       32960 :         if (ret)
    1561           0 :             goto out;
    1562             : 
    1563       32960 :         ptr = realloc(p->pac, len);
    1564       32960 :         if (ptr == NULL) {
    1565           0 :             ret = krb5_enomem(context);
    1566           0 :             goto out;
    1567             :         }
    1568       32960 :         memset((char *)ptr + old_len, 0, len - old_len);
    1569       32960 :         p->pac = ptr;
    1570             : 
    1571             : 
    1572       32960 :         if (p->logon_name == NULL) {
    1573           0 :             p->logon_name = &p->pac->buffers[p->pac->numbuffers++];
    1574           0 :             p->logon_name->type = PAC_LOGON_NAME;
    1575             :         }
    1576       32960 :         if (p->server_checksum == NULL) {
    1577       18961 :             p->server_checksum = &p->pac->buffers[p->pac->numbuffers++];
    1578       18961 :             p->server_checksum->type = PAC_SERVER_CHECKSUM;
    1579             :         }
    1580       32960 :         if (p->privsvr_checksum == NULL) {
    1581       18961 :             p->privsvr_checksum = &p->pac->buffers[p->pac->numbuffers++];
    1582       18961 :             p->privsvr_checksum->type = PAC_PRIVSVR_CHECKSUM;
    1583             :         }
    1584       32960 :         if (p->ticket_sign_data.length != 0 && p->ticket_checksum == NULL) {
    1585       14633 :             p->ticket_checksum = &p->pac->buffers[p->pac->numbuffers++];
    1586       14633 :             p->ticket_checksum->type = PAC_TICKET_CHECKSUM;
    1587             :         }
    1588       32960 :         if (add_full_sig && p->full_checksum == NULL) {
    1589       14633 :             p->full_checksum = &p->pac->buffers[p->pac->numbuffers++];
    1590       14633 :             memset(p->full_checksum, 0, sizeof(*p->full_checksum));
    1591       14633 :             p->full_checksum->type = PAC_FULL_CHECKSUM;
    1592             :         }
    1593             :     }
    1594             : 
    1595             :     /* Calculate LOGON NAME */
    1596       54055 :     ret = build_logon_name(context, authtime, principal, &logon);
    1597             : 
    1598             :     /* Set lengths for checksum */
    1599       54055 :     if (ret == 0)
    1600       54055 :         ret = pac_checksum(context, server_key, &server_cksumtype, &server_size);
    1601             : 
    1602       54055 :     if (ret == 0)
    1603       54055 :         ret = pac_checksum(context, priv_key, &priv_cksumtype, &priv_size);
    1604             : 
    1605             :     /* Encode PAC */
    1606       54055 :     if (ret == 0) {
    1607       54055 :         sp = krb5_storage_emem();
    1608       54055 :         if (sp == NULL)
    1609           0 :             ret = krb5_enomem(context);
    1610             :     }
    1611             : 
    1612       54055 :     if (ret == 0) {
    1613       54055 :         krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
    1614       54055 :         spdata = krb5_storage_emem();
    1615       54055 :         if (spdata == NULL)
    1616           0 :             ret = krb5_enomem(context);
    1617             :     }
    1618             : 
    1619       54055 :     if (ret)
    1620           0 :         goto out;
    1621             : 
    1622       54055 :     krb5_storage_set_flags(spdata, KRB5_STORAGE_BYTEORDER_LE);
    1623             : 
    1624             :     /* `sp' has the header, `spdata' has the buffers */
    1625       54055 :     CHECK(ret, krb5_store_uint32(sp, p->pac->numbuffers), out);
    1626       54055 :     CHECK(ret, krb5_store_uint32(sp, p->pac->version), out);
    1627             : 
    1628       54055 :     ret = pac_header_size(context, p->pac->numbuffers, &end);
    1629       54055 :     if (ret)
    1630           0 :         goto out;
    1631             : 
    1632             :     /*
    1633             :      * For each buffer we write its contents to `spdata' and then append the
    1634             :      * PAC_INFO_BUFFER for that buffer into the header in `sp'.  The logical
    1635             :      * end of the whole thing is kept in `end', which functions as the offset
    1636             :      * to write in the buffer's PAC_INFO_BUFFER, then we update it at the
    1637             :      * bottom so that the next buffer can be written there.
    1638             :      *
    1639             :      * TODO?  Maybe rewrite all of this so that:
    1640             :      *
    1641             :      *  - we use krb5_pac_add_buffer() to add the buffers we produce
    1642             :      *  - we use the krb5_data of the concatenated buffers that's maintained by
    1643             :      *    krb5_pac_add_buffer() so we don't need `spdata' here
    1644             :      *
    1645             :      * We do way too much here, and that makes this code hard to read.  Plus we
    1646             :      * throw away all the work done in krb5_pac_add_buffer().  On the other
    1647             :      * hand, krb5_pac_add_buffer() has to loop over all the buffers, so if we
    1648             :      * call krb5_pac_add_buffer() here in a loop, we'll be accidentally
    1649             :      * quadratic, but we only need to loop over adding the buffers we add,
    1650             :      * which is very few, so not quite quadratic.  We should also cap the
    1651             :      * number of buffers we're willing to accept in a PAC we parse to something
    1652             :      * reasonable, like a few tens.
    1653             :      */
    1654      430117 :     for (i = 0; i < p->pac->numbuffers; i++) {
    1655             :         uint32_t len;
    1656             :         size_t sret;
    1657      376062 :         void *ptr = NULL;
    1658             : 
    1659             :         /* store data */
    1660             : 
    1661      376062 :         if (p->pac->buffers[i].type == PAC_SERVER_CHECKSUM) {
    1662       54055 :             if (server_size > UINT32_MAX - 4) {
    1663           0 :                 ret = EINVAL;
    1664           0 :                 krb5_set_error_message(context, ret, "integer overrun");
    1665           0 :                 goto out;
    1666             :             }
    1667       54055 :             len = server_size + 4;
    1668       54055 :             if (end > UINT32_MAX - 4) {
    1669           0 :                 ret = EINVAL;
    1670           0 :                 krb5_set_error_message(context, ret, "integer overrun");
    1671           0 :                 goto out;
    1672             :             }
    1673       54055 :             server_offset = end + 4;
    1674       54055 :             CHECK(ret, krb5_store_uint32(spdata, server_cksumtype), out);
    1675       54055 :             CHECK(ret, fill_zeros(context, spdata, server_size), out);
    1676      322007 :         } else if (p->pac->buffers[i].type == PAC_PRIVSVR_CHECKSUM) {
    1677       54055 :             if (priv_size > UINT32_MAX - 4) {
    1678           0 :                 ret = EINVAL;
    1679           0 :                 krb5_set_error_message(context, ret, "integer overrun");
    1680           0 :                 goto out;
    1681             :             }
    1682       54055 :             len = priv_size + 4;
    1683       54055 :             if (end > UINT32_MAX - 4) {
    1684           0 :                 ret = EINVAL;
    1685           0 :                 krb5_set_error_message(context, ret, "integer overrun");
    1686           0 :                 goto out;
    1687             :             }
    1688       54055 :             priv_offset = end + 4;
    1689       54055 :             CHECK(ret, krb5_store_uint32(spdata, priv_cksumtype), out);
    1690       54055 :             CHECK(ret, fill_zeros(context, spdata, priv_size), out);
    1691       54055 :             if (rodc_id != 0) {
    1692        2873 :                 if (len > UINT32_MAX - sizeof(rodc_id)) {
    1693           0 :                     ret = EINVAL;
    1694           0 :                     krb5_set_error_message(context, ret, "integer overrun");
    1695           0 :                     goto out;
    1696             :                 }
    1697        2873 :                 len += sizeof(rodc_id);
    1698        2873 :                 CHECK(ret, fill_zeros(context, spdata, sizeof(rodc_id)), out);
    1699             :             }
    1700      341411 :         } else if (p->ticket_sign_data.length != 0 &&
    1701       73459 :                    p->pac->buffers[i].type == PAC_TICKET_CHECKSUM) {
    1702       14682 :             if (priv_size > UINT32_MAX - 4) {
    1703           0 :                 ret = EINVAL;
    1704           0 :                 krb5_set_error_message(context, ret, "integer overrun");
    1705           0 :                 goto out;
    1706             :             }
    1707       14682 :             len = priv_size + 4;
    1708       14682 :             if (end > UINT32_MAX - 4) {
    1709           0 :                 ret = EINVAL;
    1710           0 :                 krb5_set_error_message(context, ret, "integer overrun");
    1711           0 :                 goto out;
    1712             :             }
    1713       14682 :             ticket_offset = end + 4;
    1714       14682 :             CHECK(ret, krb5_store_uint32(spdata, priv_cksumtype), out);
    1715       14682 :             CHECK(ret, fill_zeros(context, spdata, priv_size), out);
    1716       29364 :             if (rodc_id != 0) {
    1717        1574 :                 if (len > UINT32_MAX - sizeof(rodc_id)) {
    1718           0 :                     ret = EINVAL;
    1719           0 :                     krb5_set_error_message(context, ret, "integer overrun");
    1720           0 :                     goto out;
    1721             :                 }
    1722        1574 :                 len += sizeof(rodc_id);
    1723        1574 :                 CHECK(ret, krb5_store_uint16(spdata, rodc_id), out);
    1724             :             }
    1725      312047 :         } else if (add_full_sig &&
    1726       58777 :                    p->pac->buffers[i].type == PAC_FULL_CHECKSUM) {
    1727       14682 :             if (priv_size > UINT32_MAX - 4) {
    1728           0 :                 ret = EINVAL;
    1729           0 :                 krb5_set_error_message(context, ret, "integer overrun");
    1730           0 :                 goto out;
    1731             :             }
    1732       14682 :             len = priv_size + 4;
    1733       14682 :             if (end > UINT32_MAX - 4) {
    1734           0 :                 ret = EINVAL;
    1735           0 :                 krb5_set_error_message(context, ret, "integer overrun");
    1736           0 :                 goto out;
    1737             :             }
    1738       14682 :             full_offset = end + 4;
    1739       14682 :             CHECK(ret, krb5_store_uint32(spdata, priv_cksumtype), out);
    1740       14682 :             CHECK(ret, fill_zeros(context, spdata, priv_size), out);
    1741       29364 :             if (rodc_id != 0) {
    1742        1574 :                 if (len > UINT32_MAX - sizeof(rodc_id)) {
    1743           0 :                     ret = EINVAL;
    1744           0 :                     krb5_set_error_message(context, ret, "integer overrun");
    1745           0 :                     goto out;
    1746             :                 }
    1747        1574 :                 len += sizeof(rodc_id);
    1748        1574 :                 CHECK(ret, fill_zeros(context, spdata, sizeof(rodc_id)), out);
    1749             :             }
    1750      238588 :         } else if (p->pac->buffers[i].type == PAC_LOGON_NAME) {
    1751       54055 :             len = krb5_storage_write(spdata, logon.data, logon.length);
    1752       54055 :             if (logon.length != len) {
    1753           0 :                 ret = KRB5KDC_ERR_BADOPTION;
    1754           0 :                 goto out;
    1755             :             }
    1756             :         } else {
    1757      184533 :             len = p->pac->buffers[i].buffersize;
    1758      184533 :             ptr = (char *)p->data.data + p->pac->buffers[i].offset;
    1759             : 
    1760      184533 :             sret = krb5_storage_write(spdata, ptr, len);
    1761      184533 :             if (sret != len) {
    1762           0 :                 ret = krb5_enomem(context);
    1763           0 :                 goto out;
    1764             :             }
    1765             :             /* XXX if not aligned, fill_zeros */
    1766             :         }
    1767             : 
    1768             :         /* write header */
    1769      376062 :         CHECK(ret, krb5_store_uint32(sp, p->pac->buffers[i].type), out);
    1770      376062 :         CHECK(ret, krb5_store_uint32(sp, len), out);
    1771      376062 :         CHECK(ret, krb5_store_uint64(sp, end), out); /* offset */
    1772             : 
    1773             :         /* advance data endpointer and align */
    1774             :         {
    1775             :             uint32_t e;
    1776             : 
    1777      376062 :             ret = pac_aligned_size(context, end, len, &e);
    1778      376062 :             if (ret == 0 && end + len != e)
    1779      109031 :                 ret = fill_zeros(context, spdata, e - (end + len));
    1780      376062 :             if (ret)
    1781           0 :                 goto out;
    1782      376062 :             end = e;
    1783             :         }
    1784             : 
    1785             :     }
    1786             : 
    1787             :     /* assert (server_offset != 0 && priv_offset != 0); */
    1788             : 
    1789             :     /* export PAC */
    1790       54055 :     if (ret == 0)
    1791       54055 :         ret = krb5_storage_to_data(spdata, &d);
    1792       54055 :     if (ret == 0) {
    1793       54055 :         sz = krb5_storage_write(sp, d.data, d.length);
    1794       54055 :         if (sz != d.length) {
    1795           0 :             krb5_data_free(&d);
    1796           0 :             ret = krb5_enomem(context);
    1797           0 :             goto out;
    1798             :         }
    1799             :     }
    1800       54055 :     krb5_data_free(&d);
    1801             : 
    1802       54055 :     if (ret == 0)
    1803       54055 :         ret = krb5_storage_to_data(sp, &d);
    1804             : 
    1805             :     /* sign */
    1806       54055 :     if (ret == 0 && p->ticket_sign_data.length)
    1807       29364 :         ret = create_checksum(context, priv_key, priv_cksumtype,
    1808             :                               p->ticket_sign_data.data,
    1809             :                               p->ticket_sign_data.length,
    1810       14682 :                               (char *)d.data + ticket_offset, priv_size);
    1811       54055 :     if (ret == 0 && add_full_sig)
    1812       29364 :         ret = create_checksum(context, priv_key, priv_cksumtype,
    1813             :                               d.data, d.length,
    1814       14682 :                               (char *)d.data + full_offset, priv_size);
    1815       54055 :     if (ret == 0 && add_full_sig && rodc_id != 0) {
    1816        1574 :         void *buf = (char *)d.data + full_offset + priv_size;
    1817        1574 :         krb5_storage *rs = krb5_storage_from_mem(buf, sizeof(rodc_id));
    1818        1574 :         if (rs == NULL)
    1819           0 :             ret = krb5_enomem(context);
    1820             :         else
    1821        1574 :             krb5_storage_set_flags(rs, KRB5_STORAGE_BYTEORDER_LE);
    1822        1574 :         if (ret == 0)
    1823        1574 :             ret = krb5_store_uint16(rs, rodc_id);
    1824        1574 :         krb5_storage_free(rs);
    1825             :     }
    1826       54055 :     if (ret == 0)
    1827      108110 :         ret = create_checksum(context, server_key, server_cksumtype,
    1828             :                               d.data, d.length,
    1829       54055 :                               (char *)d.data + server_offset, server_size);
    1830       54055 :     if (ret == 0)
    1831      162165 :         ret = create_checksum(context, priv_key, priv_cksumtype,
    1832       54055 :                               (char *)d.data + server_offset, server_size,
    1833       54055 :                               (char *)d.data + priv_offset, priv_size);
    1834       54055 :     if (ret == 0 && rodc_id != 0) {
    1835        2873 :         void *buf = (char *)d.data + priv_offset + priv_size;
    1836        2873 :         krb5_storage *rs = krb5_storage_from_mem(buf, sizeof(rodc_id));
    1837        2873 :         if (rs == NULL)
    1838           0 :             ret = krb5_enomem(context);
    1839             :         else
    1840        2873 :             krb5_storage_set_flags(rs, KRB5_STORAGE_BYTEORDER_LE);
    1841        2873 :         if (ret == 0)
    1842        2873 :             ret = krb5_store_uint16(rs, rodc_id);
    1843        2873 :         krb5_storage_free(rs);
    1844             :     }
    1845             : 
    1846       54055 :     if (ret)
    1847           0 :         goto out;
    1848             : 
    1849             :     /* done */
    1850       54055 :     *data = d;
    1851             : 
    1852       54055 :     krb5_data_free(&logon);
    1853       54055 :     krb5_storage_free(sp);
    1854       54055 :     krb5_storage_free(spdata);
    1855             : 
    1856       54055 :     return 0;
    1857           0 : out:
    1858           0 :     krb5_data_free(&d);
    1859           0 :     krb5_data_free(&logon);
    1860           0 :     if (sp)
    1861           0 :         krb5_storage_free(sp);
    1862           0 :     if (spdata)
    1863           0 :         krb5_storage_free(spdata);
    1864           0 :     return ret;
    1865             : }
    1866             : 
    1867             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1868          78 : krb5_pac_get_kdc_checksum_info(krb5_context context,
    1869             :                                krb5_const_pac pac,
    1870             :                                krb5_cksumtype *cstype,
    1871             :                                uint16_t *rodc_id)
    1872             : {
    1873             :     krb5_error_code ret;
    1874          78 :     krb5_storage *sp = NULL;
    1875             :     const struct PAC_INFO_BUFFER *sig;
    1876             :     size_t cksumsize, prefix;
    1877          78 :     uint32_t type = 0;
    1878             : 
    1879          78 :     *cstype = 0;
    1880          78 :     *rodc_id = 0;
    1881             : 
    1882          78 :     sig = pac->privsvr_checksum;
    1883          78 :     if (sig == NULL) {
    1884           0 :         krb5_set_error_message(context, KRB5KDC_ERR_BADOPTION,
    1885             :                                "PAC missing kdc checksum");
    1886           0 :         return KRB5KDC_ERR_BADOPTION;
    1887             :     }
    1888             : 
    1889          78 :     sp = krb5_storage_from_mem((char *)pac->data.data + sig->offset,
    1890          78 :                                sig->buffersize);
    1891          78 :     if (sp == NULL)
    1892           0 :         return krb5_enomem(context);
    1893             : 
    1894          78 :     krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
    1895             : 
    1896          78 :     ret = krb5_ret_uint32(sp, &type);
    1897          78 :     if (ret)
    1898           0 :         goto out;
    1899             : 
    1900          78 :     ret = krb5_checksumsize(context, type, &cksumsize);
    1901          78 :     if (ret)
    1902           2 :         goto out;
    1903             : 
    1904          76 :     prefix = krb5_storage_seek(sp, 0, SEEK_CUR);
    1905             : 
    1906          76 :     if ((sig->buffersize - prefix) >= cksumsize + 2) {
    1907           0 :         krb5_storage_seek(sp, cksumsize, SEEK_CUR);
    1908           0 :         ret = krb5_ret_uint16(sp, rodc_id);
    1909           0 :         if (ret)
    1910           0 :             goto out;
    1911             :     }
    1912             : 
    1913          76 :     *cstype = type;
    1914             : 
    1915          78 : out:
    1916          78 :     krb5_storage_free(sp);
    1917             : 
    1918          78 :     return ret;
    1919             : }
    1920             : 
    1921             : 
    1922             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1923       36042 : _krb5_pac_get_canon_principal(krb5_context context,
    1924             :                               krb5_const_pac pac,
    1925             :                               krb5_principal *canon_princ)
    1926             : {
    1927       36042 :     *canon_princ = NULL;
    1928             : 
    1929       36042 :     if (pac->canon_princ == NULL) {
    1930           0 :         krb5_set_error_message(context, ENOENT,
    1931             :                                "PAC missing UPN DNS info buffer");
    1932           0 :         return ENOENT;
    1933             :     }
    1934             : 
    1935       36042 :     return krb5_copy_principal(context, pac->canon_princ, canon_princ);
    1936             : }
    1937             : 
    1938             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1939       36042 : _krb5_pac_get_attributes_info(krb5_context context,
    1940             :                               krb5_const_pac pac,
    1941             :                               uint64_t *pac_attributes)
    1942             : {
    1943       36042 :     *pac_attributes = 0;
    1944             : 
    1945       36042 :     if (pac->attributes_info == NULL) {
    1946          78 :         krb5_set_error_message(context, ENOENT,
    1947             :                                "PAC missing attributes info buffer");
    1948          78 :         return ENOENT;
    1949             :     }
    1950             : 
    1951       35964 :     *pac_attributes = pac->pac_attributes;
    1952             : 
    1953       35964 :     return 0;
    1954             : }
    1955             : 
    1956             : static unsigned char single_zero = '\0';
    1957             : static krb5_data single_zero_pac = { 1, &single_zero };
    1958             : 
    1959             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1960       36080 : _krb5_kdc_pac_ticket_parse(krb5_context context,
    1961             :                            EncTicketPart *tkt,
    1962             :                            krb5_boolean *signedticket,
    1963             :                            krb5_pac *ppac)
    1964             : {
    1965       36080 :     AuthorizationData *ad = tkt->authorization_data;
    1966       36080 :     krb5_pac pac = NULL;
    1967             :     unsigned i, j;
    1968       36080 :     size_t len = 0;
    1969       36080 :     krb5_error_code ret = 0;
    1970             : 
    1971       36080 :     *signedticket = FALSE;
    1972       36080 :     *ppac = NULL;
    1973             : 
    1974       36080 :     if (ad == NULL || ad->len == 0)
    1975          10 :         return 0;
    1976             : 
    1977       72140 :     for (i = 0; i < ad->len; i++) {
    1978             :         AuthorizationData child;
    1979             : 
    1980       36070 :         if (ad->val[i].ad_type == KRB5_AUTHDATA_WIN2K_PAC) {
    1981           0 :             ret = KRB5KDC_ERR_BADOPTION;
    1982           0 :             goto out;
    1983             :         }
    1984             : 
    1985       36070 :         if (ad->val[i].ad_type != KRB5_AUTHDATA_IF_RELEVANT)
    1986           0 :             continue;
    1987             : 
    1988       36070 :         ret = decode_AuthorizationData(ad->val[i].ad_data.data,
    1989       36070 :                                        ad->val[i].ad_data.length,
    1990             :                                        &child,
    1991             :                                        NULL);
    1992       36070 :         if (ret) {
    1993           0 :             krb5_set_error_message(context, ret, "Failed to decode "
    1994             :                                    "AD-IF-RELEVANT with %d", ret);
    1995           0 :             goto out;
    1996             :         }
    1997             : 
    1998       72140 :         for (j = 0; j < child.len; j++) {
    1999       36070 :             krb5_data adifr_data = ad->val[i].ad_data;
    2000       36070 :             krb5_data pac_data = child.val[j].ad_data;
    2001             :             krb5_data recoded_adifr;
    2002             : 
    2003       36070 :             if (child.val[j].ad_type != KRB5_AUTHDATA_WIN2K_PAC)
    2004       35970 :                 continue;
    2005             : 
    2006       36070 :             if (pac != NULL) {
    2007           0 :                 free_AuthorizationData(&child);
    2008           0 :                 ret = KRB5KDC_ERR_BADOPTION;
    2009           0 :                 goto out;
    2010             :             }
    2011             : 
    2012       72140 :             ret = krb5_pac_parse(context,
    2013       36070 :                                  pac_data.data,
    2014             :                                  pac_data.length,
    2015             :                                  &pac);
    2016       36070 :             if (ret) {
    2017           0 :                 free_AuthorizationData(&child);
    2018           0 :                 goto out;
    2019             :             }
    2020             : 
    2021       36070 :             if (pac->ticket_checksum == NULL)
    2022       35970 :                 continue;
    2023             : 
    2024             :             /*
    2025             :              * Encode the ticket with the PAC replaced with a single zero
    2026             :              * byte, to be used as input data to the ticket signature.
    2027             :              */
    2028             : 
    2029         100 :             child.val[j].ad_data = single_zero_pac;
    2030             : 
    2031         100 :             ASN1_MALLOC_ENCODE(AuthorizationData, recoded_adifr.data,
    2032             :                                recoded_adifr.length, &child, &len, ret);
    2033         100 :             if (recoded_adifr.length != len)
    2034           0 :                 krb5_abortx(context, "Internal error in ASN.1 encoder");
    2035             : 
    2036         100 :             child.val[j].ad_data = pac_data;
    2037             : 
    2038         100 :             if (ret) {
    2039           0 :                 free_AuthorizationData(&child);
    2040           0 :                 goto out;
    2041             :             }
    2042             : 
    2043         100 :             ad->val[i].ad_data = recoded_adifr;
    2044             : 
    2045         100 :             ASN1_MALLOC_ENCODE(EncTicketPart,
    2046             :                                pac->ticket_sign_data.data,
    2047             :                                pac->ticket_sign_data.length, tkt, &len,
    2048             :                                ret);
    2049         100 :             if (pac->ticket_sign_data.length != len)
    2050           0 :                 krb5_abortx(context, "Internal error in ASN.1 encoder");
    2051             : 
    2052         100 :             ad->val[i].ad_data = adifr_data;
    2053         100 :             krb5_data_free(&recoded_adifr);
    2054             : 
    2055         100 :             if (ret) {
    2056           0 :                 free_AuthorizationData(&child);
    2057           0 :                 goto out;
    2058             :             }
    2059             : 
    2060         100 :             *signedticket = TRUE;
    2061             :         }
    2062       36070 :         free_AuthorizationData(&child);
    2063             :     }
    2064             : 
    2065       36070 : out:
    2066       36070 :     if (ret) {
    2067           0 :         krb5_pac_free(context, pac);
    2068           0 :         return ret;
    2069             :     }
    2070             : 
    2071       36070 :     *ppac = pac;
    2072             : 
    2073       36070 :     return 0;
    2074             : }
    2075             : 
    2076             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    2077       35728 : _krb5_kdc_pac_sign_ticket(krb5_context context,
    2078             :                           const krb5_pac pac,
    2079             :                           krb5_const_principal client,
    2080             :                           const krb5_keyblock *server_key,
    2081             :                           const krb5_keyblock *kdc_key,
    2082             :                           uint16_t rodc_id,
    2083             :                           krb5_const_principal upn,
    2084             :                           krb5_const_principal canon_name,
    2085             :                           krb5_boolean add_ticket_sig,
    2086             :                           krb5_boolean add_full_sig,
    2087             :                           EncTicketPart *tkt,
    2088             :                           uint64_t *pac_attributes) /* optional */
    2089             : {
    2090             :     krb5_error_code ret;
    2091             :     krb5_data tkt_data;
    2092             :     krb5_data rspac;
    2093             : 
    2094       35728 :     krb5_data_zero(&rspac);
    2095       35728 :     krb5_data_zero(&tkt_data);
    2096             : 
    2097       35728 :     krb5_data_free(&pac->ticket_sign_data);
    2098             : 
    2099       35728 :     if (add_ticket_sig) {
    2100       14682 :         size_t len = 0;
    2101             : 
    2102       14682 :         ret = _kdc_tkt_insert_pac(context, tkt, &single_zero_pac);
    2103       14682 :         if (ret)
    2104           0 :             return ret;
    2105             : 
    2106       14682 :         ASN1_MALLOC_ENCODE(EncTicketPart, tkt_data.data, tkt_data.length,
    2107             :                            tkt, &len, ret);
    2108       14682 :         if(tkt_data.length != len)
    2109           0 :             krb5_abortx(context, "Internal error in ASN.1 encoder");
    2110       14682 :         if (ret)
    2111           0 :             return ret;
    2112             : 
    2113       14682 :         ret = remove_AuthorizationData(tkt->authorization_data, 0);
    2114       14682 :         if (ret) {
    2115           0 :             krb5_data_free(&tkt_data);
    2116           0 :             return ret;
    2117             :         }
    2118             : 
    2119       14682 :         pac->ticket_sign_data = tkt_data;
    2120             :     }
    2121             : 
    2122       35728 :     ret = _krb5_pac_sign(context, pac, tkt->authtime, client, server_key,
    2123             :                          kdc_key, rodc_id, upn, canon_name,
    2124             :                          add_full_sig,
    2125             :                          pac_attributes, &rspac);
    2126       35728 :     if (ret == 0)
    2127       35728 :         ret = _kdc_tkt_insert_pac(context, tkt, &rspac);
    2128       35728 :     krb5_data_free(&rspac);
    2129       35728 :     return ret;
    2130             : }

Generated by: LCOV version 1.13