LCOV - code coverage report
Current view: top level - source4/heimdal/lib/krb5 - pac.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 379 601 63.1 %
Date: 2021-09-23 10:06:22 Functions: 18 18 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2006 - 2007 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             : #include <wind.h>
      36             : 
      37             : struct PAC_INFO_BUFFER {
      38             :     uint32_t type;
      39             :     uint32_t buffersize;
      40             :     uint32_t offset_hi;
      41             :     uint32_t offset_lo;
      42             : };
      43             : 
      44             : struct PACTYPE {
      45             :     uint32_t numbuffers;
      46             :     uint32_t version;
      47             :     struct PAC_INFO_BUFFER buffers[1];
      48             : };
      49             : 
      50             : struct krb5_pac_data {
      51             :     struct PACTYPE *pac;
      52             :     krb5_data data;
      53             :     struct PAC_INFO_BUFFER *server_checksum;
      54             :     struct PAC_INFO_BUFFER *privsvr_checksum;
      55             :     struct PAC_INFO_BUFFER *logon_name;
      56             : };
      57             : 
      58             : #define PAC_ALIGNMENT                   8
      59             : 
      60             : #define PACTYPE_SIZE                    8
      61             : #define PAC_INFO_BUFFER_SIZE            16
      62             : 
      63             : #define PAC_SERVER_CHECKSUM             6
      64             : #define PAC_PRIVSVR_CHECKSUM            7
      65             : #define PAC_LOGON_NAME                  10
      66             : #define PAC_CONSTRAINED_DELEGATION      11
      67             : 
      68             : #define CHECK(r,f,l)                                            \
      69             :         do {                                                    \
      70             :                 if (((r) = f ) != 0) {                          \
      71             :                         krb5_clear_error_message(context);      \
      72             :                         goto l;                                 \
      73             :                 }                                               \
      74             :         } while(0)
      75             : 
      76             : static const char zeros[PAC_ALIGNMENT] = { 0 };
      77             : 
      78             : /*
      79             :  * HMAC-MD5 checksum over any key (needed for the PAC routines)
      80             :  */
      81             : 
      82             : static krb5_error_code
      83       22268 : HMAC_MD5_any_checksum(krb5_context context,
      84             :                       const krb5_keyblock *key,
      85             :                       const void *data,
      86             :                       size_t len,
      87             :                       unsigned usage,
      88             :                       Checksum *result)
      89             : {
      90             :     struct _krb5_key_data local_key;
      91             :     krb5_error_code ret;
      92             : 
      93       22268 :     memset(&local_key, 0, sizeof(local_key));
      94             : 
      95       22268 :     ret = krb5_copy_keyblock(context, key, &local_key.key);
      96       22268 :     if (ret)
      97           0 :         return ret;
      98             : 
      99       22268 :     ret = krb5_data_alloc (&result->checksum, 16);
     100       22268 :     if (ret) {
     101           0 :         krb5_free_keyblock(context, local_key.key);
     102           0 :         return ret;
     103             :     }
     104             : 
     105       22268 :     result->cksumtype = CKSUMTYPE_HMAC_MD5;
     106       22268 :     ret = _krb5_HMAC_MD5_checksum(context, &local_key, data, len, usage, result);
     107       22268 :     if (ret)
     108           0 :         krb5_data_free(&result->checksum);
     109             : 
     110       22268 :     krb5_free_keyblock(context, local_key.key);
     111       22268 :     return ret;
     112             : }
     113             : 
     114             : 
     115             : /*
     116             :  *
     117             :  */
     118             : 
     119             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     120      131924 : krb5_pac_parse(krb5_context context, const void *ptr, size_t len,
     121             :                krb5_pac *pac)
     122             : {
     123             :     krb5_error_code ret;
     124             :     krb5_pac p;
     125      131924 :     krb5_storage *sp = NULL;
     126             :     uint32_t i, tmp, tmp2, header_end;
     127             : 
     128      131924 :     p = calloc(1, sizeof(*p));
     129      131924 :     if (p == NULL) {
     130           0 :         ret = krb5_enomem(context);
     131           0 :         goto out;
     132             :     }
     133             : 
     134      131924 :     sp = krb5_storage_from_readonly_mem(ptr, len);
     135      131924 :     if (sp == NULL) {
     136           0 :         ret = krb5_enomem(context);
     137           0 :         goto out;
     138             :     }
     139      131924 :     krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
     140             : 
     141      131924 :     CHECK(ret, krb5_ret_uint32(sp, &tmp), out);
     142      131924 :     CHECK(ret, krb5_ret_uint32(sp, &tmp2), out);
     143      131924 :     if (tmp < 1) {
     144           0 :         ret = EINVAL; /* Too few buffers */
     145           0 :         krb5_set_error_message(context, ret, N_("PAC have too few buffer", ""));
     146           0 :         goto out;
     147             :     }
     148      131924 :     if (tmp2 != 0) {
     149           0 :         ret = EINVAL; /* Wrong version */
     150           0 :         krb5_set_error_message(context, ret,
     151           0 :                                N_("PAC have wrong version %d", ""),
     152             :                                (int)tmp2);
     153           0 :         goto out;
     154             :     }
     155             : 
     156      131924 :     p->pac = calloc(1,
     157      131924 :                     sizeof(*p->pac) + (sizeof(p->pac->buffers[0]) * (tmp - 1)));
     158      131924 :     if (p->pac == NULL) {
     159           0 :         ret = krb5_enomem(context);
     160           0 :         goto out;
     161             :     }
     162             : 
     163      131924 :     p->pac->numbuffers = tmp;
     164      131924 :     p->pac->version = tmp2;
     165             : 
     166      131924 :     header_end = PACTYPE_SIZE + (PAC_INFO_BUFFER_SIZE * p->pac->numbuffers);
     167      131924 :     if (header_end > len) {
     168           0 :         ret = EINVAL;
     169           0 :         goto out;
     170             :     }
     171             : 
     172      789103 :     for (i = 0; i < p->pac->numbuffers; i++) {
     173      659746 :         CHECK(ret, krb5_ret_uint32(sp, &p->pac->buffers[i].type), out);
     174      659746 :         CHECK(ret, krb5_ret_uint32(sp, &p->pac->buffers[i].buffersize), out);
     175      659746 :         CHECK(ret, krb5_ret_uint32(sp, &p->pac->buffers[i].offset_lo), out);
     176      659746 :         CHECK(ret, krb5_ret_uint32(sp, &p->pac->buffers[i].offset_hi), out);
     177             : 
     178             :         /* consistency checks */
     179      659746 :         if (p->pac->buffers[i].offset_lo & (PAC_ALIGNMENT - 1)) {
     180           0 :             ret = EINVAL;
     181           0 :             krb5_set_error_message(context, ret,
     182           0 :                                    N_("PAC out of alignment", ""));
     183           0 :             goto out;
     184             :         }
     185      659746 :         if (p->pac->buffers[i].offset_hi) {
     186           0 :             ret = EINVAL;
     187           0 :             krb5_set_error_message(context, ret,
     188           0 :                                    N_("PAC high offset set", ""));
     189           0 :             goto out;
     190             :         }
     191      659746 :         if (p->pac->buffers[i].offset_lo > len) {
     192           0 :             ret = EINVAL;
     193           0 :             krb5_set_error_message(context, ret,
     194           0 :                                    N_("PAC offset off end", ""));
     195           0 :             goto out;
     196             :         }
     197      659746 :         if (p->pac->buffers[i].offset_lo < header_end) {
     198           0 :             ret = EINVAL;
     199           0 :             krb5_set_error_message(context, ret,
     200           0 :                                    N_("PAC offset inside header: %lu %lu", ""),
     201           0 :                                    (unsigned long)p->pac->buffers[i].offset_lo,
     202             :                                    (unsigned long)header_end);
     203           0 :             goto out;
     204             :         }
     205      659746 :         if (p->pac->buffers[i].buffersize > len - p->pac->buffers[i].offset_lo){
     206           0 :             ret = EINVAL;
     207           0 :             krb5_set_error_message(context, ret, N_("PAC length off end", ""));
     208           0 :             goto out;
     209             :         }
     210             : 
     211             :         /* let save pointer to data we need later */
     212      659746 :         if (p->pac->buffers[i].type == PAC_SERVER_CHECKSUM) {
     213      131924 :             if (p->server_checksum) {
     214           0 :                 ret = EINVAL;
     215           0 :                 krb5_set_error_message(context, ret,
     216           0 :                                        N_("PAC have two server checksums", ""));
     217           0 :                 goto out;
     218             :             }
     219      131924 :             p->server_checksum = &p->pac->buffers[i];
     220      527822 :         } else if (p->pac->buffers[i].type == PAC_PRIVSVR_CHECKSUM) {
     221      131924 :             if (p->privsvr_checksum) {
     222           0 :                 ret = EINVAL;
     223           0 :                 krb5_set_error_message(context, ret,
     224           0 :                                        N_("PAC have two KDC checksums", ""));
     225           0 :                 goto out;
     226             :             }
     227      131924 :             p->privsvr_checksum = &p->pac->buffers[i];
     228      395898 :         } else if (p->pac->buffers[i].type == PAC_LOGON_NAME) {
     229      131924 :             if (p->logon_name) {
     230           0 :                 ret = EINVAL;
     231           0 :                 krb5_set_error_message(context, ret,
     232           0 :                                        N_("PAC have two logon names", ""));
     233           0 :                 goto out;
     234             :             }
     235      131924 :             p->logon_name = &p->pac->buffers[i];
     236             :         }
     237             :     }
     238             : 
     239      131924 :     ret = krb5_data_copy(&p->data, ptr, len);
     240      131924 :     if (ret)
     241           0 :         goto out;
     242             : 
     243      131924 :     krb5_storage_free(sp);
     244             : 
     245      131924 :     *pac = p;
     246      131924 :     return 0;
     247             : 
     248           0 : out:
     249           0 :     if (sp)
     250           0 :         krb5_storage_free(sp);
     251           0 :     if (p) {
     252           0 :         if (p->pac)
     253           0 :             free(p->pac);
     254           0 :         free(p);
     255             :     }
     256           0 :     *pac = NULL;
     257             : 
     258           0 :     return ret;
     259             : }
     260             : 
     261             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     262       66861 : krb5_pac_init(krb5_context context, krb5_pac *pac)
     263             : {
     264             :     krb5_error_code ret;
     265             :     krb5_pac p;
     266             : 
     267       66861 :     p = calloc(1, sizeof(*p));
     268       66861 :     if (p == NULL) {
     269           0 :         return krb5_enomem(context);
     270             :     }
     271             : 
     272       66861 :     p->pac = calloc(1, sizeof(*p->pac));
     273       66861 :     if (p->pac == NULL) {
     274           0 :         free(p);
     275           0 :         return krb5_enomem(context);
     276             :     }
     277             : 
     278       66861 :     ret = krb5_data_alloc(&p->data, PACTYPE_SIZE);
     279       66861 :     if (ret) {
     280           0 :         free (p->pac);
     281           0 :         free(p);
     282           0 :         return krb5_enomem(context);
     283             :     }
     284             : 
     285       66861 :     *pac = p;
     286       66861 :     return 0;
     287             : }
     288             : 
     289             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     290      280499 : krb5_pac_add_buffer(krb5_context context, krb5_pac p,
     291             :                     uint32_t type, const krb5_data *data)
     292             : {
     293             :     krb5_error_code ret;
     294             :     void *ptr;
     295             :     size_t len, offset, header_end, old_end;
     296             :     uint32_t i;
     297             : 
     298      280499 :     len = p->pac->numbuffers;
     299             : 
     300      280499 :     ptr = realloc(p->pac,
     301      280499 :                   sizeof(*p->pac) + (sizeof(p->pac->buffers[0]) * len));
     302      280499 :     if (ptr == NULL)
     303           0 :         return krb5_enomem(context);
     304             : 
     305      280499 :     p->pac = ptr;
     306             : 
     307      760922 :     for (i = 0; i < len; i++)
     308      480423 :         p->pac->buffers[i].offset_lo += PAC_INFO_BUFFER_SIZE;
     309             : 
     310      280499 :     offset = p->data.length + PAC_INFO_BUFFER_SIZE;
     311             : 
     312      280499 :     p->pac->buffers[len].type = type;
     313      280499 :     p->pac->buffers[len].buffersize = data->length;
     314      280499 :     p->pac->buffers[len].offset_lo = offset;
     315      280499 :     p->pac->buffers[len].offset_hi = 0;
     316             : 
     317      280499 :     old_end = p->data.length;
     318      280499 :     len = p->data.length + data->length + PAC_INFO_BUFFER_SIZE;
     319      280499 :     if (len < p->data.length) {
     320           0 :         krb5_set_error_message(context, EINVAL, "integer overrun");
     321           0 :         return EINVAL;
     322             :     }
     323             : 
     324             :     /* align to PAC_ALIGNMENT */
     325      280499 :     len = ((len + PAC_ALIGNMENT - 1) / PAC_ALIGNMENT) * PAC_ALIGNMENT;
     326             : 
     327      280499 :     ret = krb5_data_realloc(&p->data, len);
     328      280499 :     if (ret) {
     329           0 :         krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
     330           0 :         return ret;
     331             :     }
     332             : 
     333             :     /*
     334             :      * make place for new PAC INFO BUFFER header
     335             :      */
     336      280499 :     header_end = PACTYPE_SIZE + (PAC_INFO_BUFFER_SIZE * p->pac->numbuffers);
     337      568213 :     memmove((unsigned char *)p->data.data + header_end + PAC_INFO_BUFFER_SIZE,
     338      280499 :             (unsigned char *)p->data.data + header_end ,
     339             :             old_end - header_end);
     340      287714 :     memset((unsigned char *)p->data.data + header_end, 0, PAC_INFO_BUFFER_SIZE);
     341             : 
     342             :     /*
     343             :      * copy in new data part
     344             :      */
     345             : 
     346      568213 :     memcpy((unsigned char *)p->data.data + offset,
     347      280499 :            data->data, data->length);
     348      287714 :     memset((unsigned char *)p->data.data + offset + data->length,
     349      280499 :            0, p->data.length - offset - data->length);
     350             : 
     351      280499 :     p->pac->numbuffers += 1;
     352             : 
     353      280499 :     return 0;
     354             : }
     355             : 
     356             : /**
     357             :  * Get the PAC buffer of specific type from the pac.
     358             :  *
     359             :  * @param context Kerberos 5 context.
     360             :  * @param p the pac structure returned by krb5_pac_parse().
     361             :  * @param type type of buffer to get
     362             :  * @param data return data, free with krb5_data_free().
     363             :  *
     364             :  * @return Returns 0 to indicate success. Otherwise an kerberos et
     365             :  * error code is returned, see krb5_get_error_message().
     366             :  *
     367             :  * @ingroup krb5_pac
     368             :  */
     369             : 
     370             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     371      291197 : krb5_pac_get_buffer(krb5_context context, krb5_pac p,
     372             :                     uint32_t type, krb5_data *data)
     373             : {
     374             :     krb5_error_code ret;
     375             :     uint32_t i;
     376             : 
     377     1644780 :     for (i = 0; i < p->pac->numbuffers; i++) {
     378      822370 :         const size_t len = p->pac->buffers[i].buffersize;
     379      822370 :         const size_t offset = p->pac->buffers[i].offset_lo;
     380             : 
     381      822370 :         if (p->pac->buffers[i].type != type)
     382      531193 :             continue;
     383             : 
     384      291177 :         ret = krb5_data_copy(data, (unsigned char *)p->data.data + offset, len);
     385      291177 :         if (ret) {
     386           0 :             krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
     387           0 :             return ret;
     388             :         }
     389      284254 :         return 0;
     390             :     }
     391          20 :     krb5_set_error_message(context, ENOENT, "No PAC buffer of type %lu was found",
     392             :                            (unsigned long)type);
     393          20 :     return ENOENT;
     394             : }
     395             : 
     396             : /*
     397             :  *
     398             :  */
     399             : 
     400             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     401       39896 : krb5_pac_get_types(krb5_context context,
     402             :                    krb5_pac p,
     403             :                    size_t *len,
     404             :                    uint32_t **types)
     405             : {
     406             :     size_t i;
     407             : 
     408       39896 :     *types = calloc(p->pac->numbuffers, sizeof(*types));
     409       39896 :     if (*types == NULL) {
     410           0 :         *len = 0;
     411           0 :         return krb5_enomem(context);
     412             :     }
     413      238367 :     for (i = 0; i < p->pac->numbuffers; i++)
     414      199560 :         (*types)[i] = p->pac->buffers[i].type;
     415       39896 :     *len = p->pac->numbuffers;
     416             : 
     417       39896 :     return 0;
     418             : }
     419             : 
     420             : /*
     421             :  *
     422             :  */
     423             : 
     424             : KRB5_LIB_FUNCTION void KRB5_LIB_CALL
     425      198785 : krb5_pac_free(krb5_context context, krb5_pac pac)
     426             : {
     427      198785 :     krb5_data_free(&pac->data);
     428      198785 :     free(pac->pac);
     429      198785 :     free(pac);
     430      198785 : }
     431             : 
     432             : /*
     433             :  *
     434             :  */
     435             : 
     436             : static krb5_error_code
     437       86081 : verify_checksum(krb5_context context,
     438             :                 const struct PAC_INFO_BUFFER *sig,
     439             :                 const krb5_data *data,
     440             :                 void *ptr, size_t len,
     441             :                 const krb5_keyblock *key)
     442             : {
     443       86081 :     krb5_storage *sp = NULL;
     444             :     uint32_t type;
     445             :     krb5_error_code ret;
     446             :     Checksum cksum;
     447             : 
     448       86081 :     memset(&cksum, 0, sizeof(cksum));
     449             : 
     450       86081 :     sp = krb5_storage_from_mem((char *)data->data + sig->offset_lo,
     451       86081 :                                sig->buffersize);
     452       86081 :     if (sp == NULL)
     453           0 :         return krb5_enomem(context);
     454             : 
     455       86081 :     krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
     456             : 
     457       86081 :     CHECK(ret, krb5_ret_uint32(sp, &type), out);
     458       86081 :     cksum.cksumtype = type;
     459       86081 :     cksum.checksum.length =
     460       86081 :         sig->buffersize - krb5_storage_seek(sp, 0, SEEK_CUR);
     461       86081 :     cksum.checksum.data = malloc(cksum.checksum.length);
     462       86081 :     if (cksum.checksum.data == NULL) {
     463           0 :         ret = krb5_enomem(context);
     464           0 :         goto out;
     465             :     }
     466       86081 :     ret = krb5_storage_read(sp, cksum.checksum.data, cksum.checksum.length);
     467       86081 :     if (ret != (int)cksum.checksum.length) {
     468           0 :         ret = EINVAL;
     469           0 :         krb5_set_error_message(context, ret, "PAC checksum missing checksum");
     470           0 :         goto out;
     471             :     }
     472             : 
     473       86081 :     if (!krb5_checksum_is_keyed(context, cksum.cksumtype)) {
     474           0 :         ret = EINVAL;
     475           0 :         krb5_set_error_message(context, ret, "Checksum type %d not keyed",
     476           0 :                                cksum.cksumtype);
     477           0 :         goto out;
     478             :     }
     479             : 
     480             :     /* If the checksum is HMAC-MD5, the checksum type is not tied to
     481             :      * the key type, instead the HMAC-MD5 checksum is applied blindly
     482             :      * on whatever key is used for this connection, avoiding issues
     483             :      * with unkeyed checksums on des-cbc-md5 and des-cbc-crc.  See
     484             :      * http://comments.gmane.org/gmane.comp.encryption.kerberos.devel/8743
     485             :      * for the same issue in MIT, and
     486             :      * http://blogs.msdn.com/b/openspecification/archive/2010/01/01/verifying-the-server-signature-in-kerberos-privilege-account-certificate.aspx
     487             :      * for Microsoft's explaination */
     488             : 
     489       86081 :     if (cksum.cksumtype == CKSUMTYPE_HMAC_MD5) {
     490             :         Checksum local_checksum;
     491             : 
     492        7502 :         memset(&local_checksum, 0, sizeof(local_checksum));
     493             : 
     494        7502 :         ret = HMAC_MD5_any_checksum(context, key, ptr, len,
     495             :                                     KRB5_KU_OTHER_CKSUM, &local_checksum);
     496             : 
     497        7502 :         if (ret != 0 || krb5_data_ct_cmp(&local_checksum.checksum, &cksum.checksum) != 0) {
     498           0 :             ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
     499           0 :             krb5_set_error_message(context, ret,
     500           0 :                                    N_("PAC integrity check failed for "
     501             :                                       "hmac-md5 checksum", ""));
     502             :         }
     503        7502 :         krb5_data_free(&local_checksum.checksum);
     504             : 
     505             :    } else {
     506       78579 :         krb5_crypto crypto = NULL;
     507             : 
     508       78579 :         ret = krb5_crypto_init(context, key, 0, &crypto);
     509       78579 :         if (ret)
     510           0 :                 goto out;
     511             : 
     512       78579 :         ret = krb5_verify_checksum(context, crypto, KRB5_KU_OTHER_CKSUM,
     513             :                                    ptr, len, &cksum);
     514       78579 :         krb5_crypto_destroy(context, crypto);
     515             :     }
     516       86081 :     free(cksum.checksum.data);
     517       86081 :     krb5_storage_free(sp);
     518             : 
     519       84254 :     return ret;
     520             : 
     521           0 : out:
     522           0 :     if (cksum.checksum.data)
     523           0 :         free(cksum.checksum.data);
     524           0 :     if (sp)
     525           0 :         krb5_storage_free(sp);
     526           0 :     return ret;
     527             : }
     528             : 
     529             : static krb5_error_code
     530      133722 : create_checksum(krb5_context context,
     531             :                 const krb5_keyblock *key,
     532             :                 uint32_t cksumtype,
     533             :                 void *data, size_t datalen,
     534             :                 void *sig, size_t siglen)
     535             : {
     536      133722 :     krb5_crypto crypto = NULL;
     537             :     krb5_error_code ret;
     538             :     Checksum cksum;
     539             : 
     540             :     /* If the checksum is HMAC-MD5, the checksum type is not tied to
     541             :      * the key type, instead the HMAC-MD5 checksum is applied blindly
     542             :      * on whatever key is used for this connection, avoiding issues
     543             :      * with unkeyed checksums on des-cbc-md5 and des-cbc-crc.  See
     544             :      * http://comments.gmane.org/gmane.comp.encryption.kerberos.devel/8743
     545             :      * for the same issue in MIT, and
     546             :      * http://blogs.msdn.com/b/openspecification/archive/2010/01/01/verifying-the-server-signature-in-kerberos-privilege-account-certificate.aspx
     547             :      * for Microsoft's explaination */
     548             : 
     549      133722 :     if (cksumtype == (uint32_t)CKSUMTYPE_HMAC_MD5) {
     550       14766 :         ret = HMAC_MD5_any_checksum(context, key, data, datalen,
     551             :                                     KRB5_KU_OTHER_CKSUM, &cksum);
     552             :     } else {
     553      118956 :         ret = krb5_crypto_init(context, key, 0, &crypto);
     554      118956 :         if (ret)
     555           0 :             return ret;
     556             : 
     557      118956 :         ret = krb5_create_checksum(context, crypto, KRB5_KU_OTHER_CKSUM, 0,
     558             :                                    data, datalen, &cksum);
     559      118956 :         krb5_crypto_destroy(context, crypto);
     560      118956 :         if (ret)
     561           0 :             return ret;
     562             :     }
     563      133722 :     if (cksum.checksum.length != siglen) {
     564           0 :         krb5_set_error_message(context, EINVAL, "pac checksum wrong length");
     565           0 :         free_Checksum(&cksum);
     566           0 :         return EINVAL;
     567             :     }
     568             : 
     569      137080 :     memcpy(sig, cksum.checksum.data, siglen);
     570      133722 :     free_Checksum(&cksum);
     571             : 
     572      133722 :     return 0;
     573             : }
     574             : 
     575             : 
     576             : /*
     577             :  *
     578             :  */
     579             : 
     580             : #define NTTIME_EPOCH 0x019DB1DED53E8000LL
     581             : 
     582             : static uint64_t
     583      149436 : unix2nttime(time_t unix_time)
     584             : {
     585             :     long long wt;
     586      152942 :     wt = unix_time * (uint64_t)10000000 + (uint64_t)NTTIME_EPOCH;
     587      149436 :     return wt;
     588             : }
     589             : 
     590             : static krb5_error_code
     591       86081 : verify_logonname(krb5_context context,
     592             :                  const struct PAC_INFO_BUFFER *logon_name,
     593             :                  const krb5_data *data,
     594             :                  time_t authtime,
     595             :                  krb5_const_principal principal)
     596             : {
     597             :     krb5_error_code ret;
     598             :     uint32_t time1, time2;
     599             :     krb5_storage *sp;
     600             :     uint16_t len;
     601       86081 :     char *s = NULL;
     602       86081 :     char *principal_string = NULL;
     603       86081 :     char *logon_string = NULL;
     604             : 
     605       86081 :     sp = krb5_storage_from_readonly_mem((const char *)data->data + logon_name->offset_lo,
     606       86081 :                                         logon_name->buffersize);
     607       86081 :     if (sp == NULL)
     608           0 :         return krb5_enomem(context);
     609             : 
     610       86081 :     krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
     611             : 
     612       86081 :     CHECK(ret, krb5_ret_uint32(sp, &time1), out);
     613       86081 :     CHECK(ret, krb5_ret_uint32(sp, &time2), out);
     614             : 
     615             :     {
     616             :         uint64_t t1, t2;
     617       86081 :         t1 = unix2nttime(authtime);
     618       86081 :         t2 = ((uint64_t)time2 << 32) | time1;
     619       86081 :         if (t1 != t2) {
     620           0 :             krb5_storage_free(sp);
     621           0 :             krb5_set_error_message(context, EINVAL, "PAC timestamp mismatch");
     622           0 :             return EINVAL;
     623             :         }
     624             :     }
     625       86081 :     CHECK(ret, krb5_ret_uint16(sp, &len), out);
     626       86081 :     if (len == 0) {
     627           0 :         krb5_storage_free(sp);
     628           0 :         krb5_set_error_message(context, EINVAL, "PAC logon name length missing");
     629           0 :         return EINVAL;
     630             :     }
     631             : 
     632       86081 :     s = malloc(len);
     633       86081 :     if (s == NULL) {
     634           0 :         krb5_storage_free(sp);
     635           0 :         return krb5_enomem(context);
     636             :     }
     637       86081 :     ret = krb5_storage_read(sp, s, len);
     638       86081 :     if (ret != len) {
     639           0 :         krb5_storage_free(sp);
     640           0 :         krb5_set_error_message(context, EINVAL, "Failed to read PAC logon name");
     641           0 :         return EINVAL;
     642             :     }
     643       86081 :     krb5_storage_free(sp);
     644             :     {
     645       86081 :         size_t ucs2len = len / 2;
     646             :         uint16_t *ucs2;
     647             :         size_t u8len;
     648       86081 :         unsigned int flags = WIND_RW_LE;
     649             : 
     650       86081 :         ucs2 = malloc(sizeof(ucs2[0]) * ucs2len);
     651       86081 :         if (ucs2 == NULL)
     652           0 :             return krb5_enomem(context);
     653             : 
     654       86081 :         ret = wind_ucs2read(s, len, &flags, ucs2, &ucs2len);
     655       86081 :         free(s);
     656       86081 :         if (ret) {
     657           0 :             free(ucs2);
     658           0 :             krb5_set_error_message(context, ret, "Failed to convert string to UCS-2");
     659           0 :             return ret;
     660             :         }
     661       86081 :         ret = wind_ucs2utf8_length(ucs2, ucs2len, &u8len);
     662       86081 :         if (ret) {
     663           0 :             free(ucs2);
     664           0 :             krb5_set_error_message(context, ret, "Failed to count length of UCS-2 string");
     665           0 :             return ret;
     666             :         }
     667       86081 :         u8len += 1; /* Add space for NUL */
     668       86081 :         logon_string = malloc(u8len);
     669       86081 :         if (logon_string == NULL) {
     670           0 :             free(ucs2);
     671           0 :             return krb5_enomem(context);
     672             :         }
     673       86081 :         ret = wind_ucs2utf8(ucs2, ucs2len, logon_string, &u8len);
     674       86081 :         free(ucs2);
     675       86081 :         if (ret) {
     676           0 :             free(logon_string);
     677           0 :             krb5_set_error_message(context, ret, "Failed to convert to UTF-8");
     678           0 :             return ret;
     679             :         }
     680             :     }
     681       86081 :     ret = krb5_unparse_name_flags(context, principal,
     682             :                                   KRB5_PRINCIPAL_UNPARSE_NO_REALM |
     683             :                                   KRB5_PRINCIPAL_UNPARSE_DISPLAY,
     684             :                                   &principal_string);
     685       86081 :     if (ret) {
     686           0 :         free(logon_string);
     687           0 :         return ret;
     688             :     }
     689             : 
     690       86081 :     ret = strcmp(logon_string, principal_string);
     691       86081 :     if (ret != 0) {
     692           0 :         ret = EINVAL;
     693           0 :         krb5_set_error_message(context, ret, "PAC logon name [%s] mismatch principal name [%s]",
     694             :                                logon_string, principal_string);
     695             :     }
     696       86081 :     free(logon_string);
     697       86081 :     free(principal_string);
     698       84254 :     return ret;
     699           0 : out:
     700           0 :     return ret;
     701             : }
     702             : 
     703             : /*
     704             :  *
     705             :  */
     706             : 
     707             : static krb5_error_code
     708       66861 : build_logon_name(krb5_context context,
     709             :                  time_t authtime,
     710             :                  krb5_const_principal principal,
     711             :                  krb5_data *logon)
     712             : {
     713             :     krb5_error_code ret;
     714             :     krb5_storage *sp;
     715             :     uint64_t t;
     716             :     char *s, *s2;
     717             :     size_t s2_len;
     718             : 
     719       66861 :     t = unix2nttime(authtime);
     720             : 
     721       66861 :     krb5_data_zero(logon);
     722             : 
     723       66861 :     sp = krb5_storage_emem();
     724       66861 :     if (sp == NULL)
     725           0 :         return krb5_enomem(context);
     726             : 
     727       66861 :     krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
     728             : 
     729       66861 :     CHECK(ret, krb5_store_uint32(sp, t & 0xffffffff), out);
     730       66861 :     CHECK(ret, krb5_store_uint32(sp, t >> 32), out);
     731             : 
     732       66861 :     ret = krb5_unparse_name_flags(context, principal,
     733             :                                   KRB5_PRINCIPAL_UNPARSE_NO_REALM |
     734             :                                   KRB5_PRINCIPAL_UNPARSE_DISPLAY,
     735             :                                   &s);
     736       66861 :     if (ret)
     737           0 :         goto out;
     738             : 
     739             :     {
     740             :         size_t ucs2_len;
     741             :         uint16_t *ucs2;
     742             :         unsigned int flags;
     743             : 
     744       66861 :         ret = wind_utf8ucs2_length(s, &ucs2_len);
     745       66861 :         if (ret) {
     746           0 :             free(s);
     747           0 :             krb5_set_error_message(context, ret, "Failed to count length of UTF-8 string");
     748           0 :             return ret;
     749             :         }
     750             : 
     751       66861 :         ucs2 = malloc(sizeof(ucs2[0]) * ucs2_len);
     752       66861 :         if (ucs2 == NULL) {
     753           0 :             free(s);
     754           0 :             return krb5_enomem(context);
     755             :         }
     756             : 
     757       66861 :         ret = wind_utf8ucs2(s, ucs2, &ucs2_len);
     758       66861 :         free(s);
     759       66861 :         if (ret) {
     760           0 :             free(ucs2);
     761           0 :             krb5_set_error_message(context, ret, "Failed to convert string to UCS-2");
     762           0 :             return ret;
     763             :         }
     764             : 
     765       66861 :         s2_len = (ucs2_len + 1) * 2;
     766       66861 :         s2 = malloc(s2_len);
     767       66861 :         if (s2 == NULL) {
     768           0 :             free(ucs2);
     769           0 :             return krb5_enomem(context);
     770             :         }
     771             : 
     772       66861 :         flags = WIND_RW_LE;
     773       66861 :         ret = wind_ucs2write(ucs2, ucs2_len,
     774             :                              &flags, s2, &s2_len);
     775       66861 :         free(ucs2);
     776       66861 :         if (ret) {
     777           0 :             free(s2);
     778           0 :             krb5_set_error_message(context, ret, "Failed to write to UCS-2 buffer");
     779           0 :             return ret;
     780             :         }
     781             : 
     782             :         /*
     783             :          * we do not want zero termination
     784             :          */
     785       66861 :         s2_len = ucs2_len * 2;
     786             :     }
     787             : 
     788       66861 :     CHECK(ret, krb5_store_uint16(sp, s2_len), out);
     789             : 
     790       66861 :     ret = krb5_storage_write(sp, s2, s2_len);
     791       66861 :     free(s2);
     792       66861 :     if (ret != (int)s2_len) {
     793           0 :         ret = krb5_enomem(context);
     794           0 :         goto out;
     795             :     }
     796       66861 :     ret = krb5_storage_to_data(sp, logon);
     797       66861 :     if (ret)
     798           0 :         goto out;
     799       66861 :     krb5_storage_free(sp);
     800             : 
     801       66861 :     return 0;
     802           0 : out:
     803           0 :     krb5_storage_free(sp);
     804           0 :     return ret;
     805             : }
     806             : 
     807             : 
     808             : /**
     809             :  * Verify the PAC.
     810             :  *
     811             :  * @param context Kerberos 5 context.
     812             :  * @param pac the pac structure returned by krb5_pac_parse().
     813             :  * @param authtime The time of the ticket the PAC belongs to.
     814             :  * @param principal the principal to verify.
     815             :  * @param server The service key, most always be given.
     816             :  * @param privsvr The KDC key, may be given.
     817             : 
     818             :  * @return Returns 0 to indicate success. Otherwise an kerberos et
     819             :  * error code is returned, see krb5_get_error_message().
     820             :  *
     821             :  * @ingroup krb5_pac
     822             :  */
     823             : 
     824             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     825       86081 : krb5_pac_verify(krb5_context context,
     826             :                 const krb5_pac pac,
     827             :                 time_t authtime,
     828             :                 krb5_const_principal principal,
     829             :                 const krb5_keyblock *server,
     830             :                 const krb5_keyblock *privsvr)
     831             : {
     832             :     krb5_error_code ret;
     833             : 
     834       86081 :     if (pac->server_checksum == NULL) {
     835           0 :         krb5_set_error_message(context, EINVAL, "PAC missing server checksum");
     836           0 :         return EINVAL;
     837             :     }
     838       86081 :     if (pac->privsvr_checksum == NULL) {
     839           0 :         krb5_set_error_message(context, EINVAL, "PAC missing kdc checksum");
     840           0 :         return EINVAL;
     841             :     }
     842       86081 :     if (pac->logon_name == NULL) {
     843           0 :         krb5_set_error_message(context, EINVAL, "PAC missing logon name");
     844           0 :         return EINVAL;
     845             :     }
     846             : 
     847       86081 :     ret = verify_logonname(context,
     848       84254 :                            pac->logon_name,
     849       86081 :                            &pac->data,
     850             :                            authtime,
     851             :                            principal);
     852       86081 :     if (ret)
     853           0 :         return ret;
     854             : 
     855             :     /*
     856             :      * in the service case, clean out data option of the privsvr and
     857             :      * server checksum before checking the checksum.
     858             :      */
     859             :     {
     860             :         krb5_data *copy;
     861             : 
     862       86081 :         ret = krb5_copy_data(context, &pac->data, &copy);
     863       86081 :         if (ret)
     864           0 :             return ret;
     865             : 
     866       86081 :         if (pac->server_checksum->buffersize < 4)
     867           0 :             return EINVAL;
     868       86081 :         if (pac->privsvr_checksum->buffersize < 4)
     869           0 :             return EINVAL;
     870             : 
     871       87908 :         memset((char *)copy->data + pac->server_checksum->offset_lo + 4,
     872             :                0,
     873       86081 :                pac->server_checksum->buffersize - 4);
     874             : 
     875       87908 :         memset((char *)copy->data + pac->privsvr_checksum->offset_lo + 4,
     876             :                0,
     877       86081 :                pac->privsvr_checksum->buffersize - 4);
     878             : 
     879      256416 :         ret = verify_checksum(context,
     880       86081 :                               pac->server_checksum,
     881       86081 :                               &pac->data,
     882       84254 :                               copy->data,
     883       86081 :                               copy->length,
     884             :                               server);
     885       86081 :         krb5_free_data(context, copy);
     886       86081 :         if (ret)
     887           0 :             return ret;
     888             :     }
     889       86081 :     if (privsvr) {
     890             :         /* The priv checksum covers the server checksum */
     891           0 :         ret = verify_checksum(context,
     892           0 :                               pac->privsvr_checksum,
     893           0 :                               &pac->data,
     894           0 :                               (char *)pac->data.data
     895           0 :                               + pac->server_checksum->offset_lo + 4,
     896           0 :                               pac->server_checksum->buffersize - 4,
     897             :                               privsvr);
     898           0 :         if (ret)
     899           0 :             return ret;
     900             :     }
     901             : 
     902       84254 :     return 0;
     903             : }
     904             : 
     905             : /*
     906             :  *
     907             :  */
     908             : 
     909             : static krb5_error_code
     910      273647 : fill_zeros(krb5_context context, krb5_storage *sp, size_t len)
     911             : {
     912             :     ssize_t sret;
     913             :     size_t l;
     914             : 
     915      954663 :     while (len) {
     916      407369 :         l = len;
     917      407369 :         if (l > sizeof(zeros))
     918      133722 :             l = sizeof(zeros);
     919      407369 :         sret = krb5_storage_write(sp, zeros, l);
     920      407369 :         if (sret <= 0)
     921           0 :             return krb5_enomem(context);
     922             : 
     923      407369 :         len -= sret;
     924             :     }
     925      267615 :     return 0;
     926             : }
     927             : 
     928             : static krb5_error_code
     929      133722 : pac_checksum(krb5_context context,
     930             :              const krb5_keyblock *key,
     931             :              uint32_t *cksumtype,
     932             :              size_t *cksumsize)
     933             : {
     934             :     krb5_cksumtype cktype;
     935             :     krb5_error_code ret;
     936      133722 :     krb5_crypto crypto = NULL;
     937             : 
     938      133722 :     ret = krb5_crypto_init(context, key, 0, &crypto);
     939      133722 :     if (ret)
     940           0 :         return ret;
     941             : 
     942      133722 :     ret = krb5_crypto_get_checksum_type(context, crypto, &cktype);
     943      133722 :     krb5_crypto_destroy(context, crypto);
     944      133722 :     if (ret)
     945           0 :         return ret;
     946             : 
     947      133722 :     if (krb5_checksum_is_keyed(context, cktype) == FALSE) {
     948           0 :         *cksumtype = CKSUMTYPE_HMAC_MD5;
     949           0 :         *cksumsize = 16;
     950             :     }
     951             : 
     952      133722 :     ret = krb5_checksumsize(context, cktype, cksumsize);
     953      133722 :     if (ret)
     954           0 :         return ret;
     955             : 
     956      133722 :     *cksumtype = (uint32_t)cktype;
     957             : 
     958      133722 :     return 0;
     959             : }
     960             : 
     961             : krb5_error_code
     962       66861 : _krb5_pac_sign(krb5_context context,
     963             :                krb5_pac p,
     964             :                time_t authtime,
     965             :                krb5_principal principal,
     966             :                const krb5_keyblock *server_key,
     967             :                const krb5_keyblock *priv_key,
     968             :                krb5_data *data)
     969             : {
     970             :     krb5_error_code ret;
     971       66861 :     krb5_storage *sp = NULL, *spdata = NULL;
     972             :     uint32_t end;
     973             :     size_t server_size, priv_size;
     974       66861 :     uint32_t server_offset = 0, priv_offset = 0;
     975       66861 :     uint32_t server_cksumtype = 0, priv_cksumtype = 0;
     976       66861 :     int num = 0;
     977             :     size_t i;
     978             :     krb5_data logon, d;
     979             : 
     980       66861 :     krb5_data_zero(&logon);
     981             : 
     982      347360 :     for (i = 0; i < p->pac->numbuffers; i++) {
     983      280499 :         if (p->pac->buffers[i].type == PAC_SERVER_CHECKSUM) {
     984       39896 :             if (p->server_checksum == NULL) {
     985       39896 :                 p->server_checksum = &p->pac->buffers[i];
     986             :             }
     987       39896 :             if (p->server_checksum != &p->pac->buffers[i]) {
     988           0 :                 ret = EINVAL;
     989           0 :                 krb5_set_error_message(context, ret,
     990           0 :                                        N_("PAC have two server checksums", ""));
     991           0 :                 goto out;
     992             :             }
     993      240603 :         } else if (p->pac->buffers[i].type == PAC_PRIVSVR_CHECKSUM) {
     994       39896 :             if (p->privsvr_checksum == NULL) {
     995       39896 :                 p->privsvr_checksum = &p->pac->buffers[i];
     996             :             }
     997       39896 :             if (p->privsvr_checksum != &p->pac->buffers[i]) {
     998           0 :                 ret = EINVAL;
     999           0 :                 krb5_set_error_message(context, ret,
    1000           0 :                                        N_("PAC have two KDC checksums", ""));
    1001           0 :                 goto out;
    1002             :             }
    1003      200707 :         } else if (p->pac->buffers[i].type == PAC_LOGON_NAME) {
    1004       66861 :             if (p->logon_name == NULL) {
    1005       66861 :                 p->logon_name = &p->pac->buffers[i];
    1006             :             }
    1007       66861 :             if (p->logon_name != &p->pac->buffers[i]) {
    1008           0 :                 ret = EINVAL;
    1009           0 :                 krb5_set_error_message(context, ret,
    1010           0 :                                        N_("PAC have two logon names", ""));
    1011           0 :                 goto out;
    1012             :             }
    1013             :         }
    1014             :     }
    1015             : 
    1016       66861 :     if (p->logon_name == NULL)
    1017           0 :         num++;
    1018       66861 :     if (p->server_checksum == NULL)
    1019       26965 :         num++;
    1020       66861 :     if (p->privsvr_checksum == NULL)
    1021       26965 :         num++;
    1022             : 
    1023       66861 :     if (num) {
    1024             :         void *ptr;
    1025             : 
    1026       26965 :         ptr = realloc(p->pac, sizeof(*p->pac) + (sizeof(p->pac->buffers[0]) * (p->pac->numbuffers + num - 1)));
    1027       26965 :         if (ptr == NULL)
    1028           0 :             return krb5_enomem(context);
    1029             : 
    1030       26965 :         p->pac = ptr;
    1031             : 
    1032       26965 :         if (p->logon_name == NULL) {
    1033           0 :             p->logon_name = &p->pac->buffers[p->pac->numbuffers++];
    1034           0 :             memset(p->logon_name, 0, sizeof(*p->logon_name));
    1035           0 :             p->logon_name->type = PAC_LOGON_NAME;
    1036             :         }
    1037       26965 :         if (p->server_checksum == NULL) {
    1038       26965 :             p->server_checksum = &p->pac->buffers[p->pac->numbuffers++];
    1039       27555 :             memset(p->server_checksum, 0, sizeof(*p->server_checksum));
    1040       26965 :             p->server_checksum->type = PAC_SERVER_CHECKSUM;
    1041             :         }
    1042       26965 :         if (p->privsvr_checksum == NULL) {
    1043       26965 :             p->privsvr_checksum = &p->pac->buffers[p->pac->numbuffers++];
    1044       27555 :             memset(p->privsvr_checksum, 0, sizeof(*p->privsvr_checksum));
    1045       26965 :             p->privsvr_checksum->type = PAC_PRIVSVR_CHECKSUM;
    1046             :         }
    1047             :     }
    1048             : 
    1049             :     /* Calculate LOGON NAME */
    1050       66861 :     ret = build_logon_name(context, authtime, principal, &logon);
    1051       66861 :     if (ret)
    1052           0 :         goto out;
    1053             : 
    1054             :     /* Set lengths for checksum */
    1055       66861 :     ret = pac_checksum(context, server_key, &server_cksumtype, &server_size);
    1056       66861 :     if (ret)
    1057           0 :         goto out;
    1058       66861 :     ret = pac_checksum(context, priv_key, &priv_cksumtype, &priv_size);
    1059       66861 :     if (ret)
    1060           0 :         goto out;
    1061             : 
    1062             :     /* Encode PAC */
    1063       66861 :     sp = krb5_storage_emem();
    1064       66861 :     if (sp == NULL)
    1065           0 :         return krb5_enomem(context);
    1066             : 
    1067       66861 :     krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
    1068             : 
    1069       66861 :     spdata = krb5_storage_emem();
    1070       66861 :     if (spdata == NULL) {
    1071           0 :         krb5_storage_free(sp);
    1072           0 :         return krb5_enomem(context);
    1073             :     }
    1074       66861 :     krb5_storage_set_flags(spdata, KRB5_STORAGE_BYTEORDER_LE);
    1075             : 
    1076       66861 :     CHECK(ret, krb5_store_uint32(sp, p->pac->numbuffers), out);
    1077       66861 :     CHECK(ret, krb5_store_uint32(sp, p->pac->version), out);
    1078             : 
    1079       66861 :     end = PACTYPE_SIZE + (PAC_INFO_BUFFER_SIZE * p->pac->numbuffers);
    1080             : 
    1081      401290 :     for (i = 0; i < p->pac->numbuffers; i++) {
    1082             :         uint32_t len;
    1083             :         size_t sret;
    1084      334429 :         void *ptr = NULL;
    1085             : 
    1086             :         /* store data */
    1087             : 
    1088      334429 :         if (p->pac->buffers[i].type == PAC_SERVER_CHECKSUM) {
    1089       66861 :             len = server_size + 4;
    1090       66861 :             server_offset = end + 4;
    1091       66861 :             CHECK(ret, krb5_store_uint32(spdata, server_cksumtype), out);
    1092       66861 :             CHECK(ret, fill_zeros(context, spdata, server_size), out);
    1093      267568 :         } else if (p->pac->buffers[i].type == PAC_PRIVSVR_CHECKSUM) {
    1094       66861 :             len = priv_size + 4;
    1095       66861 :             priv_offset = end + 4;
    1096       66861 :             CHECK(ret, krb5_store_uint32(spdata, priv_cksumtype), out);
    1097       66861 :             CHECK(ret, fill_zeros(context, spdata, priv_size), out);
    1098      200707 :         } else if (p->pac->buffers[i].type == PAC_LOGON_NAME) {
    1099       66861 :             len = krb5_storage_write(spdata, logon.data, logon.length);
    1100       66861 :             if (logon.length != len) {
    1101           0 :                 ret = EINVAL;
    1102           0 :                 goto out;
    1103             :             }
    1104             :         } else {
    1105      133846 :             len = p->pac->buffers[i].buffersize;
    1106      133846 :             ptr = (char *)p->data.data + p->pac->buffers[i].offset_lo;
    1107             : 
    1108      133846 :             sret = krb5_storage_write(spdata, ptr, len);
    1109      133846 :             if (sret != len) {
    1110           0 :                 ret = krb5_enomem(context);
    1111           0 :                 goto out;
    1112             :             }
    1113             :             /* XXX if not aligned, fill_zeros */
    1114             :         }
    1115             : 
    1116             :         /* write header */
    1117      334429 :         CHECK(ret, krb5_store_uint32(sp, p->pac->buffers[i].type), out);
    1118      334429 :         CHECK(ret, krb5_store_uint32(sp, len), out);
    1119      334429 :         CHECK(ret, krb5_store_uint32(sp, end), out);
    1120      334429 :         CHECK(ret, krb5_store_uint32(sp, 0), out);
    1121             : 
    1122             :         /* advance data endpointer and align */
    1123             :         {
    1124             :             int32_t e;
    1125             : 
    1126      334429 :             end += len;
    1127      334429 :             e = ((end + PAC_ALIGNMENT - 1) / PAC_ALIGNMENT) * PAC_ALIGNMENT;
    1128      334429 :             if ((int32_t)end != e) {
    1129      139925 :                 CHECK(ret, fill_zeros(context, spdata, e - end), out);
    1130             :             }
    1131      334429 :             end = e;
    1132             :         }
    1133             : 
    1134             :     }
    1135             : 
    1136             :     /* assert (server_offset != 0 && priv_offset != 0); */
    1137             : 
    1138             :     /* export PAC */
    1139       66861 :     ret = krb5_storage_to_data(spdata, &d);
    1140       66861 :     if (ret) {
    1141           0 :         krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
    1142           0 :         goto out;
    1143             :     }
    1144       66861 :     ret = krb5_storage_write(sp, d.data, d.length);
    1145       66861 :     if (ret != (int)d.length) {
    1146           0 :         krb5_data_free(&d);
    1147           0 :         ret = krb5_enomem(context);
    1148           0 :         goto out;
    1149             :     }
    1150       66861 :     krb5_data_free(&d);
    1151             : 
    1152       66861 :     ret = krb5_storage_to_data(sp, &d);
    1153       66861 :     if (ret) {
    1154           0 :         ret = krb5_enomem(context);
    1155           0 :         goto out;
    1156             :     }
    1157             : 
    1158             :     /* sign */
    1159      133722 :     ret = create_checksum(context, server_key, server_cksumtype,
    1160             :                           d.data, d.length,
    1161       66861 :                           (char *)d.data + server_offset, server_size);
    1162       66861 :     if (ret) {
    1163           0 :         krb5_data_free(&d);
    1164           0 :         goto out;
    1165             :     }
    1166      198904 :     ret = create_checksum(context, priv_key, priv_cksumtype,
    1167       65182 :                           (char *)d.data + server_offset, server_size,
    1168       66861 :                           (char *)d.data + priv_offset, priv_size);
    1169       66861 :     if (ret) {
    1170           0 :         krb5_data_free(&d);
    1171           0 :         goto out;
    1172             :     }
    1173             : 
    1174             :     /* done */
    1175       66861 :     *data = d;
    1176             : 
    1177       66861 :     krb5_data_free(&logon);
    1178       66861 :     krb5_storage_free(sp);
    1179       66861 :     krb5_storage_free(spdata);
    1180             : 
    1181       66861 :     return 0;
    1182           0 : out:
    1183           0 :     krb5_data_free(&logon);
    1184           0 :     if (sp)
    1185           0 :         krb5_storage_free(sp);
    1186           0 :     if (spdata)
    1187           0 :         krb5_storage_free(spdata);
    1188           0 :     return ret;
    1189             : }

Generated by: LCOV version 1.13