LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/krb5 - keytab_file.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 277 443 62.5 %
Date: 2024-06-13 04:01:37 Functions: 20 22 90.9 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 1997 - 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             : #define KRB5_KT_VNO_1 1
      37             : #define KRB5_KT_VNO_2 2
      38             : #define KRB5_KT_VNO   KRB5_KT_VNO_2
      39             : 
      40             : #define KRB5_KT_FL_JAVA 1
      41             : 
      42             : 
      43             : /* file operations -------------------------------------------- */
      44             : 
      45             : struct fkt_data {
      46             :     char *filename;
      47             :     int flags;
      48             : };
      49             : 
      50             : static krb5_error_code
      51      161076 : krb5_kt_ret_data(krb5_context context,
      52             :                  krb5_storage *sp,
      53             :                  krb5_data *data)
      54             : {
      55             :     krb5_error_code ret;
      56             :     krb5_ssize_t bytes;
      57             :     int16_t size;
      58             : 
      59      161076 :     ret = krb5_ret_int16(sp, &size);
      60      161076 :     if(ret)
      61           0 :         return ret;
      62      161076 :     data->length = size;
      63      161076 :     data->data = malloc(size);
      64      161076 :     if (data->data == NULL)
      65           0 :         return krb5_enomem(context);
      66      161076 :     bytes = krb5_storage_read(sp, data->data, size);
      67      161076 :     if (bytes != size)
      68           0 :         return (bytes == -1) ? errno : KRB5_KT_END;
      69      161076 :     return 0;
      70             : }
      71             : 
      72             : static krb5_error_code
      73      427659 : krb5_kt_ret_string(krb5_context context,
      74             :                    krb5_storage *sp,
      75             :                    heim_general_string *data)
      76             : {
      77             :     krb5_error_code ret;
      78             :     krb5_ssize_t bytes;
      79             :     int16_t size;
      80             : 
      81      427659 :     ret = krb5_ret_int16(sp, &size);
      82      427659 :     if(ret)
      83           0 :         return ret;
      84      427659 :     *data = malloc(size + 1);
      85      427659 :     if (*data == NULL)
      86           0 :         return krb5_enomem(context);
      87      427659 :     bytes = krb5_storage_read(sp, *data, size);
      88      427659 :     (*data)[size] = '\0';
      89      427659 :     if (bytes != size)
      90           0 :         return (bytes == -1) ? errno : KRB5_KT_END;
      91      427659 :     return 0;
      92             : }
      93             : 
      94             : static krb5_error_code
      95        1452 : krb5_kt_store_data(krb5_context context,
      96             :                    krb5_storage *sp,
      97             :                    krb5_data data)
      98             : {
      99             :     krb5_error_code ret;
     100             :     krb5_ssize_t bytes;
     101             : 
     102        1452 :     ret = krb5_store_int16(sp, data.length);
     103        1452 :     if (ret != 0)
     104           0 :         return ret;
     105        1452 :     bytes = krb5_storage_write(sp, data.data, data.length);
     106        1452 :     if (bytes != (int)data.length)
     107           0 :         return bytes == -1 ? errno : KRB5_KT_END;
     108        1452 :     return 0;
     109             : }
     110             : 
     111             : static krb5_error_code
     112        3810 : krb5_kt_store_string(krb5_storage *sp,
     113             :                      heim_general_string data)
     114             : {
     115             :     krb5_error_code ret;
     116             :     krb5_ssize_t bytes;
     117        3810 :     size_t len = strlen(data);
     118             : 
     119        3810 :     ret = krb5_store_int16(sp, len);
     120        3810 :     if (ret != 0)
     121           0 :         return ret;
     122        3810 :     bytes = krb5_storage_write(sp, data, len);
     123        3810 :     if (bytes != (int)len)
     124           0 :         return bytes == -1 ? errno : KRB5_KT_END;
     125        3810 :     return 0;
     126             : }
     127             : 
     128             : static krb5_error_code
     129      161076 : krb5_kt_ret_keyblock(krb5_context context,
     130             :                      struct fkt_data *fkt,
     131             :                      krb5_storage *sp,
     132             :                      krb5_keyblock *p)
     133             : {
     134             :     int ret;
     135             :     int16_t tmp;
     136             : 
     137      161076 :     ret = krb5_ret_int16(sp, &tmp); /* keytype + etype */
     138      161076 :     if(ret)  {
     139           0 :         krb5_set_error_message(context, ret,
     140           0 :                                N_("Cant read keyblock from file %s", ""),
     141             :                                fkt->filename);
     142           0 :         return ret;
     143             :     }
     144      161076 :     p->keytype = tmp;
     145      161076 :     ret = krb5_kt_ret_data(context, sp, &p->keyvalue);
     146      161076 :     if (ret)
     147           0 :         krb5_set_error_message(context, ret,
     148           0 :                                N_("Cant read keyblock from file %s", ""),
     149             :                                fkt->filename);
     150      161076 :     return ret;
     151             : }
     152             : 
     153             : static krb5_error_code
     154        1452 : krb5_kt_store_keyblock(krb5_context context,
     155             :                        struct fkt_data *fkt,
     156             :                        krb5_storage *sp,
     157             :                        krb5_keyblock *p)
     158             : {
     159             :     int ret;
     160             : 
     161        1452 :     ret = krb5_store_int16(sp, p->keytype); /* keytype + etype */
     162        1452 :     if(ret) {
     163           0 :         krb5_set_error_message(context, ret,
     164           0 :                                N_("Cant store keyblock to file %s", ""),
     165             :                                fkt->filename);
     166           0 :         return ret;
     167             :     }
     168        1452 :     ret = krb5_kt_store_data(context, sp, p->keyvalue);
     169        1452 :     if (ret)
     170           0 :         krb5_set_error_message(context, ret,
     171           0 :                                N_("Cant store keyblock to file %s", ""),
     172             :                                fkt->filename);
     173        1452 :     return ret;
     174             : }
     175             : 
     176             : 
     177             : static krb5_error_code
     178      161076 : krb5_kt_ret_principal(krb5_context context,
     179             :                       struct fkt_data *fkt,
     180             :                       krb5_storage *sp,
     181             :                       krb5_principal *princ)
     182             : {
     183             :     size_t i;
     184             :     int ret;
     185             :     krb5_principal p;
     186             :     int16_t len;
     187             : 
     188      161076 :     ALLOC(p, 1);
     189      161076 :     if(p == NULL)
     190           0 :         return krb5_enomem(context);
     191             : 
     192      161076 :     ret = krb5_ret_int16(sp, &len);
     193      161076 :     if(ret) {
     194           0 :         krb5_set_error_message(context, ret,
     195           0 :                                N_("Failed decoding length of "
     196             :                                   "keytab principal in keytab file %s", ""),
     197             :                                fkt->filename);
     198           0 :         goto out;
     199             :     }
     200      161076 :     if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS))
     201           0 :         len--;
     202      161076 :     if (len < 0) {
     203           0 :         ret = KRB5_KT_END;
     204           0 :         krb5_set_error_message(context, ret,
     205           0 :                                N_("Keytab principal contains "
     206             :                                   "invalid length in keytab %s", ""),
     207             :                                fkt->filename);
     208           0 :         goto out;
     209             :     }
     210      161076 :     ret = krb5_kt_ret_string(context, sp, &p->realm);
     211      161076 :     if(ret) {
     212           0 :         krb5_set_error_message(context, ret,
     213           0 :                                N_("Can't read realm from keytab: %s", ""),
     214             :                                fkt->filename);
     215           0 :         goto out;
     216             :     }
     217      161076 :     p->name.name_string.val = calloc(len, sizeof(*p->name.name_string.val));
     218      161076 :     if(p->name.name_string.val == NULL) {
     219           0 :         ret = krb5_enomem(context);
     220           0 :         goto out;
     221             :     }
     222      161076 :     p->name.name_string.len = len;
     223      427659 :     for(i = 0; i < p->name.name_string.len; i++){
     224      266583 :         ret = krb5_kt_ret_string(context, sp, p->name.name_string.val + i);
     225      266583 :         if(ret) {
     226           0 :             krb5_set_error_message(context, ret,
     227           0 :                                    N_("Can't read principal from "
     228             :                                       "keytab: %s", ""),
     229             :                                    fkt->filename);
     230           0 :             goto out;
     231             :         }
     232             :     }
     233      161076 :     if (krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE))
     234           0 :         p->name.name_type = KRB5_NT_UNKNOWN;
     235             :     else {
     236             :         int32_t tmp32;
     237      161076 :         ret = krb5_ret_int32(sp, &tmp32);
     238      161076 :         p->name.name_type = tmp32;
     239      161076 :         if (ret) {
     240           0 :             krb5_set_error_message(context, ret,
     241           0 :                                    N_("Can't read name-type from "
     242             :                                       "keytab: %s", ""),
     243             :                                    fkt->filename);
     244           0 :             goto out;
     245             :         }
     246             :     }
     247      161076 :     *princ = p;
     248      161076 :     return 0;
     249           0 : out:
     250           0 :     krb5_free_principal(context, p);
     251           0 :     return ret;
     252             : }
     253             : 
     254             : static krb5_error_code
     255        1452 : krb5_kt_store_principal(krb5_context context,
     256             :                         krb5_storage *sp,
     257             :                         krb5_principal p)
     258             : {
     259             :     size_t i;
     260             :     int ret;
     261             : 
     262        1452 :     if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS))
     263           0 :         ret = krb5_store_int16(sp, p->name.name_string.len + 1);
     264             :     else
     265        1452 :         ret = krb5_store_int16(sp, p->name.name_string.len);
     266        1452 :     if(ret) return ret;
     267        1452 :     ret = krb5_kt_store_string(sp, p->realm);
     268        1452 :     if(ret) return ret;
     269        3810 :     for(i = 0; i < p->name.name_string.len; i++){
     270        2358 :         ret = krb5_kt_store_string(sp, p->name.name_string.val[i]);
     271        2358 :         if(ret)
     272           0 :             return ret;
     273             :     }
     274        1452 :     if(!krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE)) {
     275        1452 :         ret = krb5_store_int32(sp, p->name.name_type);
     276        1452 :         if(ret)
     277           0 :             return ret;
     278             :     }
     279             : 
     280        1452 :     return 0;
     281             : }
     282             : 
     283             : static krb5_error_code KRB5_CALLCONV
     284      175886 : fkt_resolve(krb5_context context, const char *name, krb5_keytab id)
     285             : {
     286             :     struct fkt_data *d;
     287             : 
     288      175886 :     d = malloc(sizeof(*d));
     289      175886 :     if(d == NULL)
     290           0 :         return krb5_enomem(context);
     291      175886 :     d->filename = strdup(name);
     292      175886 :     if(d->filename == NULL) {
     293           0 :         free(d);
     294           0 :         return krb5_enomem(context);
     295             :     }
     296      175886 :     d->flags = 0;
     297      175886 :     id->data = d;
     298      175886 :     return 0;
     299             : }
     300             : 
     301             : static krb5_error_code KRB5_CALLCONV
     302           0 : fkt_resolve_java14(krb5_context context, const char *name, krb5_keytab id)
     303             : {
     304             :     krb5_error_code ret;
     305             : 
     306           0 :     ret = fkt_resolve(context, name, id);
     307           0 :     if (ret == 0) {
     308           0 :         struct fkt_data *d = id->data;
     309           0 :         d->flags |= KRB5_KT_FL_JAVA;
     310             :     }
     311           0 :     return ret;
     312             : }
     313             : 
     314             : static krb5_error_code KRB5_CALLCONV
     315      175855 : fkt_close(krb5_context context, krb5_keytab id)
     316             : {
     317      175855 :     struct fkt_data *d = id->data;
     318      175855 :     free(d->filename);
     319      175855 :     free(d);
     320      175855 :     return 0;
     321             : }
     322             : 
     323             : static krb5_error_code KRB5_CALLCONV
     324           0 : fkt_destroy(krb5_context context, krb5_keytab id)
     325             : {
     326           0 :     struct fkt_data *d = id->data;
     327           0 :     _krb5_erase_file(context, d->filename);
     328           0 :     return 0;
     329             : }
     330             : 
     331             : static krb5_error_code KRB5_CALLCONV
     332       97635 : fkt_get_name(krb5_context context,
     333             :              krb5_keytab id,
     334             :              char *name,
     335             :              size_t namesize)
     336             : {
     337             :     /* This function is XXX */
     338       97635 :     struct fkt_data *d = id->data;
     339       97635 :     strlcpy(name, d->filename, namesize);
     340       97635 :     return 0;
     341             : }
     342             : 
     343             : static void
     344       46967 : storage_set_flags(krb5_context context, krb5_storage *sp, int vno)
     345             : {
     346       46967 :     int flags = 0;
     347       46967 :     switch(vno) {
     348           0 :     case KRB5_KT_VNO_1:
     349           0 :         flags |= KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS;
     350           0 :         flags |= KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE;
     351           0 :         flags |= KRB5_STORAGE_HOST_BYTEORDER;
     352           0 :         break;
     353       46967 :     case KRB5_KT_VNO_2:
     354       46967 :         break;
     355           0 :     default:
     356           0 :         krb5_warnx(context,
     357             :                    "storage_set_flags called with bad vno (%d)", vno);
     358             :     }
     359       46967 :     krb5_storage_set_flags(sp, flags);
     360       46967 : }
     361             : 
     362             : static krb5_error_code
     363       45643 : fkt_start_seq_get_int(krb5_context context,
     364             :                       krb5_keytab id,
     365             :                       int flags,
     366             :                       int exclusive,
     367             :                       krb5_kt_cursor *c)
     368             : {
     369             :     int8_t pvno, tag;
     370             :     krb5_error_code ret;
     371       45643 :     struct fkt_data *d = id->data;
     372       45643 :     const char *stdio_mode = "rb";
     373             : 
     374       45643 :     memset(c, 0, sizeof(*c));
     375       45643 :     c->fd = open (d->filename, flags);
     376       45643 :     if (c->fd < 0) {
     377         128 :         ret = errno;
     378         256 :         krb5_set_error_message(context, ret,
     379         128 :                                N_("keytab %s open failed: %s", ""),
     380             :                                d->filename, strerror(ret));
     381         128 :         return ret;
     382             :     }
     383       45515 :     rk_cloexec(c->fd);
     384       45515 :     ret = _krb5_xlock(context, c->fd, exclusive, d->filename);
     385       45515 :     if (ret) {
     386           0 :         close(c->fd);
     387           0 :         return ret;
     388             :     }
     389       45515 :     if ((flags & O_ACCMODE) == O_RDWR && (flags & O_APPEND))
     390           0 :         stdio_mode = "ab+";
     391       45515 :     else if ((flags & O_ACCMODE) == O_RDWR)
     392         236 :         stdio_mode = "rb+";
     393       45279 :     else if ((flags & O_ACCMODE) == O_WRONLY)
     394           0 :         stdio_mode = "wb";
     395       45515 :     c->sp = krb5_storage_stdio_from_fd(c->fd, stdio_mode);
     396       45515 :     if (c->sp == NULL) {
     397           0 :         close(c->fd);
     398           0 :         return krb5_enomem(context);
     399             :     }
     400       45515 :     krb5_storage_set_eof_code(c->sp, KRB5_KT_END);
     401       45515 :     ret = krb5_ret_int8(c->sp, &pvno);
     402       45515 :     if(ret) {
     403           0 :         krb5_storage_free(c->sp);
     404           0 :         close(c->fd);
     405           0 :         krb5_clear_error_message(context);
     406           0 :         return ret;
     407             :     }
     408       45515 :     if(pvno != 5) {
     409           0 :         krb5_storage_free(c->sp);
     410           0 :         close(c->fd);
     411           0 :         krb5_clear_error_message (context);
     412           0 :         return KRB5_KEYTAB_BADVNO;
     413             :     }
     414       45515 :     ret = krb5_ret_int8(c->sp, &tag);
     415       45515 :     if (ret) {
     416           0 :         krb5_storage_free(c->sp);
     417           0 :         close(c->fd);
     418           0 :         krb5_clear_error_message(context);
     419           0 :         return ret;
     420             :     }
     421       45515 :     id->version = tag;
     422       45515 :     storage_set_flags(context, c->sp, id->version);
     423       45515 :     return 0;
     424             : }
     425             : 
     426             : static krb5_error_code KRB5_CALLCONV
     427       45407 : fkt_start_seq_get(krb5_context context,
     428             :                   krb5_keytab id,
     429             :                   krb5_kt_cursor *c)
     430             : {
     431       45407 :     return fkt_start_seq_get_int(context, id, O_RDONLY | O_BINARY | O_CLOEXEC, 0, c);
     432             : }
     433             : 
     434             : static krb5_error_code
     435      161486 : fkt_next_entry_int(krb5_context context,
     436             :                    krb5_keytab id,
     437             :                    krb5_keytab_entry *entry,
     438             :                    krb5_kt_cursor *cursor,
     439             :                    off_t *start,
     440             :                    off_t *end)
     441             : {
     442      161486 :     struct fkt_data *d = id->data;
     443             :     int32_t len;
     444             :     int ret;
     445             :     int8_t tmp8;
     446             :     int32_t tmp32;
     447             :     uint32_t utmp32;
     448             :     off_t pos, curpos;
     449             : 
     450      161486 :     pos = krb5_storage_seek(cursor->sp, 0, SEEK_CUR);
     451      163816 : loop:
     452      163816 :     ret = krb5_ret_int32(cursor->sp, &len);
     453      163816 :     if (ret)
     454         410 :         return ret;
     455      163406 :     if(len < 0) {
     456        2330 :         pos = krb5_storage_seek(cursor->sp, -len, SEEK_CUR);
     457        2330 :         goto loop;
     458             :     }
     459      161076 :     ret = krb5_kt_ret_principal (context, d, cursor->sp, &entry->principal);
     460      161076 :     if (ret)
     461           0 :         goto out;
     462      161076 :     ret = krb5_ret_uint32(cursor->sp, &utmp32);
     463      161076 :     entry->timestamp = utmp32;
     464      161076 :     if (ret)
     465           0 :         goto out;
     466      161076 :     ret = krb5_ret_int8(cursor->sp, &tmp8);
     467      161076 :     if (ret)
     468           0 :         goto out;
     469      161076 :     entry->vno = tmp8;
     470      161076 :     ret = krb5_kt_ret_keyblock (context, d, cursor->sp, &entry->keyblock);
     471      161076 :     if (ret)
     472           0 :         goto out;
     473             :     /* there might be a 32 bit kvno here
     474             :      * if it's zero, assume that the 8bit one was right,
     475             :      * otherwise trust the new value */
     476      161076 :     curpos = krb5_storage_seek(cursor->sp, 0, SEEK_CUR);
     477      161076 :     if(len + 4 + pos - curpos >= 4) {
     478      161076 :         ret = krb5_ret_int32(cursor->sp, &tmp32);
     479      161076 :         if (ret == 0 && tmp32 != 0)
     480      161076 :             entry->vno = tmp32;
     481             :     }
     482             :     /* there might be a flags field here */
     483      161076 :     if(len + 4 + pos - curpos >= 8) {
     484      161076 :         ret = krb5_ret_uint32(cursor->sp, &utmp32);
     485      161076 :         if (ret == 0)
     486      161076 :             entry->flags = utmp32;
     487             :     } else
     488           0 :         entry->flags = 0;
     489             : 
     490      161076 :     entry->aliases = NULL;
     491             : 
     492      161076 :     if(start) *start = pos;
     493      163481 :     if(end) *end = pos + 4 + len;
     494      319747 :  out:
     495      161076 :     if (ret)
     496           0 :         krb5_kt_free_entry(context, entry);
     497      161076 :     krb5_storage_seek(cursor->sp, pos + 4 + len, SEEK_SET);
     498      161076 :     return ret;
     499             : }
     500             : 
     501             : static krb5_error_code KRB5_CALLCONV
     502      158845 : fkt_next_entry(krb5_context context,
     503             :                krb5_keytab id,
     504             :                krb5_keytab_entry *entry,
     505             :                krb5_kt_cursor *cursor)
     506             : {
     507      158845 :     return fkt_next_entry_int(context, id, entry, cursor, NULL, NULL);
     508             : }
     509             : 
     510             : static krb5_error_code KRB5_CALLCONV
     511       45515 : fkt_end_seq_get(krb5_context context,
     512             :                 krb5_keytab id,
     513             :                 krb5_kt_cursor *cursor)
     514             : {
     515       45515 :     krb5_storage_free(cursor->sp);
     516       45515 :     close(cursor->fd);
     517       45515 :     return 0;
     518             : }
     519             : 
     520             : static krb5_error_code KRB5_CALLCONV
     521         126 : fkt_setup_keytab(krb5_context context,
     522             :                  krb5_keytab id,
     523             :                  krb5_storage *sp)
     524             : {
     525             :     krb5_error_code ret;
     526         126 :     ret = krb5_store_int8(sp, 5);
     527         126 :     if(ret)
     528           0 :         return ret;
     529         126 :     if(id->version == 0)
     530         126 :         id->version = KRB5_KT_VNO;
     531         126 :     return krb5_store_int8 (sp, id->version);
     532             : }
     533             : 
     534             : static krb5_error_code KRB5_CALLCONV
     535        1452 : fkt_add_entry(krb5_context context,
     536             :               krb5_keytab id,
     537             :               krb5_keytab_entry *entry)
     538             : {
     539             :     int ret;
     540             :     int fd;
     541             :     krb5_storage *sp;
     542             :     krb5_ssize_t bytes;
     543        1452 :     struct fkt_data *d = id->data;
     544             :     krb5_data keytab;
     545             :     int32_t len;
     546             : 
     547        1452 :     fd = open(d->filename, O_RDWR | O_BINARY | O_CLOEXEC);
     548        1452 :     if (fd < 0) {
     549         126 :         fd = open(d->filename, O_RDWR | O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC, 0600);
     550         126 :         if (fd < 0) {
     551           0 :             ret = errno;
     552           0 :             krb5_set_error_message(context, ret,
     553           0 :                                    N_("open(%s): %s", ""), d->filename,
     554             :                                    strerror(ret));
     555           0 :             return ret;
     556             :         }
     557         126 :         rk_cloexec(fd);
     558             : 
     559         126 :         ret = _krb5_xlock(context, fd, 1, d->filename);
     560         126 :         if (ret) {
     561           0 :             close(fd);
     562           0 :             return ret;
     563             :         }
     564         126 :         sp = krb5_storage_stdio_from_fd(fd, "wb+");
     565         126 :         if (sp == NULL) {
     566           0 :             close(fd);
     567           0 :             return krb5_enomem(context);
     568             :         }
     569         126 :         krb5_storage_set_eof_code(sp, KRB5_KT_END);
     570         126 :         ret = fkt_setup_keytab(context, id, sp);
     571         126 :         if (ret) {
     572           0 :             goto out;
     573             :         }
     574         126 :         storage_set_flags(context, sp, id->version);
     575             :     } else {
     576             :         int8_t pvno, tag;
     577             : 
     578        1326 :         rk_cloexec(fd);
     579             : 
     580        1326 :         ret = _krb5_xlock(context, fd, 1, d->filename);
     581        1326 :         if (ret) {
     582           0 :             close(fd);
     583           0 :             return ret;
     584             :         }
     585        1326 :         sp = krb5_storage_stdio_from_fd(fd, "wb+");
     586        1326 :         if (sp == NULL) {
     587           0 :             (void) close(fd);
     588           0 :             return ret;
     589             :         }
     590        1326 :         krb5_storage_set_eof_code(sp, KRB5_KT_END);
     591        1326 :         ret = krb5_ret_int8(sp, &pvno);
     592        1326 :         if(ret) {
     593             :             /* we probably have a zero byte file, so try to set it up
     594             :                properly */
     595           0 :             ret = fkt_setup_keytab(context, id, sp);
     596           0 :             if(ret) {
     597           0 :                 krb5_set_error_message(context, ret,
     598           0 :                                        N_("%s: keytab is corrupted: %s", ""),
     599             :                                        d->filename, strerror(ret));
     600           0 :                 goto out;
     601             :             }
     602           0 :             storage_set_flags(context, sp, id->version);
     603             :         } else {
     604        1326 :             if(pvno != 5) {
     605           0 :                 ret = KRB5_KEYTAB_BADVNO;
     606           0 :                 krb5_set_error_message(context, ret,
     607           0 :                                        N_("Bad version in keytab %s", ""),
     608             :                                        d->filename);
     609           0 :                 goto out;
     610             :             }
     611        1326 :             ret = krb5_ret_int8 (sp, &tag);
     612        1326 :             if (ret) {
     613           0 :                 krb5_set_error_message(context, ret,
     614           0 :                                        N_("failed reading tag from "
     615             :                                           "keytab %s", ""),
     616             :                                        d->filename);
     617           0 :                 goto out;
     618             :             }
     619        1326 :             id->version = tag;
     620        1326 :             storage_set_flags(context, sp, id->version);
     621             :         }
     622             :     }
     623             : 
     624             :     {
     625             :         krb5_storage *emem;
     626        1452 :         emem = krb5_storage_emem();
     627        1452 :         if(emem == NULL) {
     628           0 :             ret = krb5_enomem(context);
     629           0 :             goto out;
     630             :         }
     631        1452 :         ret = krb5_kt_store_principal(context, emem, entry->principal);
     632        1452 :         if(ret) {
     633           0 :             krb5_set_error_message(context, ret,
     634           0 :                                    N_("Failed storing principal "
     635             :                                       "in keytab %s", ""),
     636             :                                    d->filename);
     637           0 :             krb5_storage_free(emem);
     638           0 :             goto out;
     639             :         }
     640        1452 :         ret = krb5_store_int32 (emem, entry->timestamp);
     641        1452 :         if(ret) {
     642           0 :             krb5_set_error_message(context, ret,
     643           0 :                                    N_("Failed storing timpstamp "
     644             :                                       "in keytab %s", ""),
     645             :                                    d->filename);
     646           0 :             krb5_storage_free(emem);
     647           0 :             goto out;
     648             :         }
     649        1452 :         ret = krb5_store_int8 (emem, entry->vno % 256);
     650        1452 :         if(ret) {
     651           0 :             krb5_set_error_message(context, ret,
     652           0 :                                    N_("Failed storing kvno "
     653             :                                       "in keytab %s", ""),
     654             :                                    d->filename);
     655           0 :             krb5_storage_free(emem);
     656           0 :             goto out;
     657             :         }
     658        1452 :         ret = krb5_kt_store_keyblock (context, d, emem, &entry->keyblock);
     659        1452 :         if(ret) {
     660           0 :             krb5_storage_free(emem);
     661           0 :             goto out;
     662             :         }
     663        1452 :         if ((d->flags & KRB5_KT_FL_JAVA) == 0) {
     664        1452 :             ret = krb5_store_int32 (emem, entry->vno);
     665        1452 :             if (ret) {
     666           0 :                 krb5_set_error_message(context, ret,
     667           0 :                                        N_("Failed storing extended kvno "
     668             :                                           "in keytab %s", ""),
     669             :                                        d->filename);
     670           0 :                 krb5_storage_free(emem);
     671           0 :                 goto out;
     672             :             }
     673        1452 :             ret = krb5_store_uint32 (emem, entry->flags);
     674        1452 :             if (ret) {
     675           0 :                 krb5_set_error_message(context, ret,
     676           0 :                                        N_("Failed storing extended kvno "
     677             :                                           "in keytab %s", ""),
     678             :                                        d->filename);
     679           0 :                 krb5_storage_free(emem);
     680           0 :                 goto out;
     681             :             }
     682             :         }
     683             : 
     684        1452 :         ret = krb5_storage_to_data(emem, &keytab);
     685        1452 :         krb5_storage_free(emem);
     686        1452 :         if(ret) {
     687           0 :             krb5_set_error_message(context, ret,
     688           0 :                                    N_("Failed converting keytab entry "
     689             :                                       "to memory block for keytab %s", ""),
     690             :                                    d->filename);
     691           0 :             goto out;
     692             :         }
     693             :     }
     694             : 
     695        8639 :     while(1) {
     696             :         off_t here;
     697             : 
     698       10091 :         here = krb5_storage_seek(sp, 0, SEEK_CUR);
     699       10091 :         if (here == -1) {
     700           0 :             ret = errno;
     701           0 :             krb5_set_error_message(context, ret,
     702           0 :                                    N_("Failed writing keytab block "
     703             :                                       "in keytab %s: %s", ""),
     704             :                                    d->filename, strerror(ret));
     705           0 :             goto out;
     706             :         }
     707       10091 :         ret = krb5_ret_int32(sp, &len);
     708       10091 :         if (ret) {
     709             :             /* There could have been a partial length.  Recover! */
     710        1238 :             (void) krb5_storage_truncate(sp, here);
     711        1238 :             len = keytab.length;
     712        1238 :             break;
     713             :         }
     714        8853 :         if(len < 0) {
     715         522 :             len = -len;
     716         522 :             if(len >= (int)keytab.length) {
     717         214 :                 krb5_storage_seek(sp, -4, SEEK_CUR);
     718         214 :                 break;
     719             :             }
     720             :         }
     721        8639 :         krb5_storage_seek(sp, len, SEEK_CUR);
     722             :     }
     723        1452 :     ret = krb5_store_int32(sp, len);
     724        1452 :     if (ret != 0)
     725           0 :         goto out;
     726        1452 :     bytes = krb5_storage_write(sp, keytab.data, keytab.length);
     727        1452 :     if (bytes != keytab.length) {
     728           0 :         ret = bytes == -1 ? errno : KRB5_KT_END;
     729           0 :         krb5_set_error_message(context, ret,
     730           0 :                                N_("Failed writing keytab block "
     731             :                                   "in keytab %s: %s", ""),
     732             :                                d->filename, strerror(ret));
     733             :     }
     734        1452 :     memset(keytab.data, 0, keytab.length);
     735        1452 :     krb5_data_free(&keytab);
     736        1452 :   out:
     737        1452 :     if (ret == 0)
     738        1452 :         ret = krb5_storage_fsync(sp);
     739        1452 :     krb5_storage_free(sp);
     740        1452 :     close(fd);
     741        1452 :     return ret;
     742             : }
     743             : 
     744             : static krb5_error_code KRB5_CALLCONV
     745         236 : fkt_remove_entry(krb5_context context,
     746             :                  krb5_keytab id,
     747             :                  krb5_keytab_entry *entry)
     748             : {
     749         236 :     struct fkt_data *fkt = id->data;
     750             :     krb5_ssize_t bytes;
     751             :     krb5_keytab_entry e;
     752             :     krb5_kt_cursor cursor;
     753             :     off_t pos_start, pos_end;
     754         236 :     int found = 0;
     755             :     krb5_error_code ret;
     756             : 
     757         236 :     ret = fkt_start_seq_get_int(context, id, O_RDWR | O_BINARY | O_CLOEXEC, 1, &cursor);
     758         236 :     if (ret != 0) {
     759           0 :         const char *emsg = krb5_get_error_message(context, ret);
     760             : 
     761           0 :         krb5_set_error_message(context, ret,
     762           0 :                                N_("Could not open keytab file for write: %s: %s", ""),
     763             :                                fkt->filename,
     764             :                                emsg);
     765           0 :         krb5_free_error_message(context, emsg);
     766           0 :         return ret;
     767             :     }
     768        2877 :     while (ret == 0 &&
     769             :            (ret = fkt_next_entry_int(context, id, &e, &cursor,
     770             :                                      &pos_start, &pos_end)) == 0) {
     771        2405 :         if (krb5_kt_compare(context, &e, entry->principal,
     772        2405 :                             entry->vno, entry->keyblock.keytype)) {
     773             :             int32_t len;
     774             :             unsigned char buf[128];
     775         236 :             found = 1;
     776         236 :             krb5_storage_seek(cursor.sp, pos_start, SEEK_SET);
     777         236 :             len = pos_end - pos_start - 4;
     778         236 :             ret = krb5_store_int32(cursor.sp, -len);
     779         236 :             memset(buf, 0, sizeof(buf));
     780         719 :             while (ret == 0 && len > 0) {
     781         247 :                 bytes = krb5_storage_write(cursor.sp, buf,
     782         247 :                     min((size_t)len, sizeof(buf)));
     783         247 :                 if (bytes != min((size_t)len, sizeof(buf))) {
     784           0 :                     ret = bytes == -1 ? errno : KRB5_KT_END;
     785           0 :                     break;
     786             :                 }
     787         247 :                 len -= min((size_t)len, sizeof(buf));
     788             :             }
     789             :         }
     790        2405 :         krb5_kt_free_entry(context, &e);
     791             :     }
     792         236 :     (void) krb5_kt_end_seq_get(context, id, &cursor);
     793         236 :     if (ret == KRB5_KT_END)
     794         236 :         ret = 0;
     795         236 :     if (ret) {
     796           0 :         const char *emsg = krb5_get_error_message(context, ret);
     797             : 
     798           0 :         krb5_set_error_message(context, ret,
     799           0 :                                N_("Could not remove keytab entry from %s: %s", ""),
     800             :                                fkt->filename,
     801             :                                emsg);
     802           0 :         krb5_free_error_message(context, emsg);
     803         236 :     } else if (!found) {
     804           0 :         krb5_clear_error_message(context);
     805           0 :         return KRB5_KT_NOTFOUND;
     806             :     }
     807         236 :     return ret;
     808             : }
     809             : 
     810             : const krb5_kt_ops krb5_fkt_ops = {
     811             :     "FILE",
     812             :     fkt_resolve,
     813             :     fkt_get_name,
     814             :     fkt_close,
     815             :     fkt_destroy,
     816             :     NULL, /* get */
     817             :     fkt_start_seq_get,
     818             :     fkt_next_entry,
     819             :     fkt_end_seq_get,
     820             :     fkt_add_entry,
     821             :     fkt_remove_entry,
     822             :     NULL,
     823             :     0
     824             : };
     825             : 
     826             : const krb5_kt_ops krb5_wrfkt_ops = {
     827             :     "WRFILE",
     828             :     fkt_resolve,
     829             :     fkt_get_name,
     830             :     fkt_close,
     831             :     fkt_destroy,
     832             :     NULL, /* get */
     833             :     fkt_start_seq_get,
     834             :     fkt_next_entry,
     835             :     fkt_end_seq_get,
     836             :     fkt_add_entry,
     837             :     fkt_remove_entry,
     838             :     NULL,
     839             :     0
     840             : };
     841             : 
     842             : const krb5_kt_ops krb5_javakt_ops = {
     843             :     "JAVA14",
     844             :     fkt_resolve_java14,
     845             :     fkt_get_name,
     846             :     fkt_close,
     847             :     fkt_destroy,
     848             :     NULL, /* get */
     849             :     fkt_start_seq_get,
     850             :     fkt_next_entry,
     851             :     fkt_end_seq_get,
     852             :     fkt_add_entry,
     853             :     fkt_remove_entry,
     854             :     NULL,
     855             :     0
     856             : };

Generated by: LCOV version 1.13