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 master 70ed9daf Lines: 324 491 66.0 %
Date: 2024-01-11 09:59:51 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      201429 : krb5_kt_ret_data(krb5_context context,
      52             :                  krb5_storage *sp,
      53             :                  krb5_data *data)
      54             : {
      55        3165 :     krb5_error_code ret;
      56        3165 :     krb5_ssize_t bytes;
      57        3165 :     int16_t size;
      58             : 
      59      201429 :     ret = krb5_ret_int16(sp, &size);
      60      201429 :     if(ret)
      61           0 :         return ret;
      62      201429 :     data->length = size;
      63      201429 :     data->data = malloc(size);
      64      201429 :     if (data->data == NULL)
      65           0 :         return krb5_enomem(context);
      66      201429 :     bytes = krb5_storage_read(sp, data->data, size);
      67      201429 :     if (bytes != size)
      68           0 :         return (bytes == -1) ? errno : KRB5_KT_END;
      69      198264 :     return 0;
      70             : }
      71             : 
      72             : static krb5_error_code
      73      539267 : krb5_kt_ret_string(krb5_context context,
      74             :                    krb5_storage *sp,
      75             :                    heim_general_string *data)
      76             : {
      77        8431 :     krb5_error_code ret;
      78        8431 :     krb5_ssize_t bytes;
      79        8431 :     int16_t size;
      80             : 
      81      539267 :     ret = krb5_ret_int16(sp, &size);
      82      539267 :     if(ret)
      83           0 :         return ret;
      84      539267 :     *data = malloc(size + 1);
      85      539267 :     if (*data == NULL)
      86           0 :         return krb5_enomem(context);
      87      539267 :     bytes = krb5_storage_read(sp, *data, size);
      88      539267 :     (*data)[size] = '\0';
      89      539267 :     if (bytes != size)
      90           0 :         return (bytes == -1) ? errno : KRB5_KT_END;
      91      530836 :     return 0;
      92             : }
      93             : 
      94             : static krb5_error_code
      95        2214 : krb5_kt_store_data(krb5_context context,
      96             :                    krb5_storage *sp,
      97             :                    krb5_data data)
      98             : {
      99         231 :     krb5_error_code ret;
     100         231 :     krb5_ssize_t bytes;
     101             : 
     102        2214 :     ret = krb5_store_int16(sp, data.length);
     103        2214 :     if (ret != 0)
     104           0 :         return ret;
     105        2214 :     bytes = krb5_storage_write(sp, data.data, data.length);
     106        2214 :     if (bytes != (int)data.length)
     107           0 :         return bytes == -1 ? errno : KRB5_KT_END;
     108        1983 :     return 0;
     109             : }
     110             : 
     111             : static krb5_error_code
     112        5907 : krb5_kt_store_string(krb5_storage *sp,
     113             :                      heim_general_string data)
     114             : {
     115         615 :     krb5_error_code ret;
     116         615 :     krb5_ssize_t bytes;
     117        5907 :     size_t len = strlen(data);
     118             : 
     119        5907 :     ret = krb5_store_int16(sp, len);
     120        5907 :     if (ret != 0)
     121           0 :         return ret;
     122        5907 :     bytes = krb5_storage_write(sp, data, len);
     123        5907 :     if (bytes != (int)len)
     124           0 :         return bytes == -1 ? errno : KRB5_KT_END;
     125        5292 :     return 0;
     126             : }
     127             : 
     128             : static krb5_error_code
     129      201429 : krb5_kt_ret_keyblock(krb5_context context,
     130             :                      struct fkt_data *fkt,
     131             :                      krb5_storage *sp,
     132             :                      krb5_keyblock *p)
     133             : {
     134        3165 :     int ret;
     135        3165 :     int16_t tmp;
     136             : 
     137      201429 :     ret = krb5_ret_int16(sp, &tmp); /* keytype + etype */
     138      201429 :     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      201429 :     p->keytype = tmp;
     145      201429 :     ret = krb5_kt_ret_data(context, sp, &p->keyvalue);
     146      201429 :     if (ret)
     147           0 :         krb5_set_error_message(context, ret,
     148           0 :                                N_("Cant read keyblock from file %s", ""),
     149             :                                fkt->filename);
     150      198264 :     return ret;
     151             : }
     152             : 
     153             : static krb5_error_code
     154        2214 : krb5_kt_store_keyblock(krb5_context context,
     155             :                        struct fkt_data *fkt,
     156             :                        krb5_storage *sp,
     157             :                        krb5_keyblock *p)
     158             : {
     159         231 :     int ret;
     160             : 
     161        2214 :     ret = krb5_store_int16(sp, p->keytype); /* keytype + etype */
     162        2214 :     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        2214 :     ret = krb5_kt_store_data(context, sp, p->keyvalue);
     169        2214 :     if (ret)
     170           0 :         krb5_set_error_message(context, ret,
     171           0 :                                N_("Cant store keyblock to file %s", ""),
     172             :                                fkt->filename);
     173        1983 :     return ret;
     174             : }
     175             : 
     176             : 
     177             : static krb5_error_code
     178      201429 : krb5_kt_ret_principal(krb5_context context,
     179             :                       struct fkt_data *fkt,
     180             :                       krb5_storage *sp,
     181             :                       krb5_principal *princ)
     182             : {
     183        3165 :     size_t i;
     184        3165 :     int ret;
     185        3165 :     krb5_principal p;
     186        3165 :     int16_t len;
     187             : 
     188      201429 :     ALLOC(p, 1);
     189      201429 :     if(p == NULL)
     190           0 :         return krb5_enomem(context);
     191             : 
     192      201429 :     ret = krb5_ret_int16(sp, &len);
     193      201429 :     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      201429 :     if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS))
     201           0 :         len--;
     202      201429 :     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      201429 :     ret = krb5_kt_ret_string(context, sp, &p->realm);
     211      201429 :     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      201429 :     p->name.name_string.val = calloc(len, sizeof(*p->name.name_string.val));
     218      201429 :     if(p->name.name_string.val == NULL) {
     219           0 :         ret = krb5_enomem(context);
     220           0 :         goto out;
     221             :     }
     222      201429 :     p->name.name_string.len = len;
     223      539267 :     for(i = 0; i < p->name.name_string.len; i++){
     224      337838 :         ret = krb5_kt_ret_string(context, sp, p->name.name_string.val + i);
     225      337838 :         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      201429 :     if (krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE))
     234           0 :         p->name.name_type = KRB5_NT_UNKNOWN;
     235             :     else {
     236        3165 :         int32_t tmp32;
     237      201429 :         ret = krb5_ret_int32(sp, &tmp32);
     238      201429 :         p->name.name_type = tmp32;
     239      201429 :         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      201429 :     *princ = p;
     248      201429 :     return 0;
     249           0 : out:
     250           0 :     krb5_free_principal(context, p);
     251           0 :     return ret;
     252             : }
     253             : 
     254             : static krb5_error_code
     255        2214 : krb5_kt_store_principal(krb5_context context,
     256             :                         krb5_storage *sp,
     257             :                         krb5_principal p)
     258             : {
     259         231 :     size_t i;
     260         231 :     int ret;
     261             : 
     262        2214 :     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        2214 :         ret = krb5_store_int16(sp, p->name.name_string.len);
     266        2214 :     if(ret) return ret;
     267        2214 :     ret = krb5_kt_store_string(sp, p->realm);
     268        2214 :     if(ret) return ret;
     269        5907 :     for(i = 0; i < p->name.name_string.len; i++){
     270        3693 :         ret = krb5_kt_store_string(sp, p->name.name_string.val[i]);
     271        3693 :         if(ret)
     272           0 :             return ret;
     273             :     }
     274        2214 :     if(!krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE)) {
     275        2214 :         ret = krb5_store_int32(sp, p->name.name_type);
     276        2214 :         if(ret)
     277           0 :             return ret;
     278             :     }
     279             : 
     280        1983 :     return 0;
     281             : }
     282             : 
     283             : static krb5_error_code KRB5_CALLCONV
     284      221542 : fkt_resolve(krb5_context context, const char *name, krb5_keytab id)
     285             : {
     286        6998 :     struct fkt_data *d;
     287             : 
     288      221542 :     d = malloc(sizeof(*d));
     289      221542 :     if(d == NULL)
     290           0 :         return krb5_enomem(context);
     291      221542 :     d->filename = strdup(name);
     292      221542 :     if(d->filename == NULL) {
     293           0 :         free(d);
     294           0 :         return krb5_enomem(context);
     295             :     }
     296      221542 :     d->flags = 0;
     297      221542 :     id->data = d;
     298      221542 :     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           0 :     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      221514 : fkt_close(krb5_context context, krb5_keytab id)
     316             : {
     317      221514 :     struct fkt_data *d = id->data;
     318      221514 :     free(d->filename);
     319      221514 :     free(d);
     320      221514 :     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      123197 : fkt_get_name(krb5_context context,
     333             :              krb5_keytab id,
     334             :              char *name,
     335             :              size_t namesize)
     336             : {
     337             :     /* This function is XXX */
     338      123197 :     struct fkt_data *d = id->data;
     339      123197 :     strlcpy(name, d->filename, namesize);
     340      123197 :     return 0;
     341             : }
     342             : 
     343             : static void
     344       56519 : storage_set_flags(krb5_context context, krb5_storage *sp, int vno)
     345             : {
     346       56519 :     int flags = 0;
     347       56519 :     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       55349 :     case KRB5_KT_VNO_2:
     354       55349 :         break;
     355           0 :     default:
     356           0 :         krb5_warnx(context,
     357             :                    "storage_set_flags called with bad vno (%d)", vno);
     358             :     }
     359       56519 :     krb5_storage_set_flags(sp, flags);
     360       56519 : }
     361             : 
     362             : static krb5_error_code
     363       54481 : 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         961 :     int8_t pvno, tag;
     370         961 :     krb5_error_code ret;
     371       54481 :     struct fkt_data *d = id->data;
     372       54481 :     const char *stdio_mode = "rb";
     373             : 
     374       54481 :     memset(c, 0, sizeof(*c));
     375       54481 :     c->fd = open (d->filename, flags);
     376       54481 :     if (c->fd < 0) {
     377         176 :         ret = errno;
     378         176 :         krb5_set_error_message(context, ret,
     379         176 :                                N_("keytab %s open failed: %s", ""),
     380             :                                d->filename, strerror(ret));
     381         176 :         return ret;
     382             :     }
     383       54305 :     rk_cloexec(c->fd);
     384       54305 :     ret = _krb5_xlock(context, c->fd, exclusive, d->filename);
     385       54305 :     if (ret) {
     386           0 :         close(c->fd);
     387           0 :         return ret;
     388             :     }
     389       54305 :     if ((flags & O_ACCMODE) == O_RDWR && (flags & O_APPEND))
     390           0 :         stdio_mode = "ab+";
     391       54305 :     else if ((flags & O_ACCMODE) == O_RDWR)
     392         476 :         stdio_mode = "rb+";
     393       53802 :     else if ((flags & O_ACCMODE) == O_WRONLY)
     394           0 :         stdio_mode = "wb";
     395       54305 :     c->sp = krb5_storage_stdio_from_fd(c->fd, stdio_mode);
     396       54305 :     if (c->sp == NULL) {
     397           0 :         close(c->fd);
     398           0 :         return krb5_enomem(context);
     399             :     }
     400       54305 :     krb5_storage_set_eof_code(c->sp, KRB5_KT_END);
     401       54305 :     ret = krb5_ret_int8(c->sp, &pvno);
     402       54305 :     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       54305 :     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       54305 :     ret = krb5_ret_int8(c->sp, &tag);
     415       54305 :     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       54305 :     id->version = tag;
     422       54305 :     storage_set_flags(context, c->sp, id->version);
     423       54305 :     return 0;
     424             : }
     425             : 
     426             : static krb5_error_code KRB5_CALLCONV
     427       53978 : fkt_start_seq_get(krb5_context context,
     428             :                   krb5_keytab id,
     429             :                   krb5_kt_cursor *c)
     430             : {
     431       53978 :     return fkt_start_seq_get_int(context, id, O_RDONLY | O_BINARY | O_CLOEXEC, 0, c);
     432             : }
     433             : 
     434             : static krb5_error_code
     435      202428 : 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      202428 :     struct fkt_data *d = id->data;
     443        3196 :     int32_t len;
     444        3196 :     int ret;
     445        3196 :     int8_t tmp8;
     446        3196 :     int32_t tmp32;
     447        3196 :     uint32_t utmp32;
     448        3196 :     off_t pos, curpos;
     449             : 
     450      202428 :     pos = krb5_storage_seek(cursor->sp, 0, SEEK_CUR);
     451      206195 : loop:
     452      206195 :     ret = krb5_ret_int32(cursor->sp, &len);
     453      206195 :     if (ret)
     454         999 :         return ret;
     455      205196 :     if(len < 0) {
     456        3767 :         pos = krb5_storage_seek(cursor->sp, -len, SEEK_CUR);
     457        3767 :         goto loop;
     458             :     }
     459      201429 :     ret = krb5_kt_ret_principal (context, d, cursor->sp, &entry->principal);
     460      201429 :     if (ret)
     461           0 :         goto out;
     462      201429 :     ret = krb5_ret_uint32(cursor->sp, &utmp32);
     463      201429 :     entry->timestamp = utmp32;
     464      201429 :     if (ret)
     465           0 :         goto out;
     466      201429 :     ret = krb5_ret_int8(cursor->sp, &tmp8);
     467      201429 :     if (ret)
     468           0 :         goto out;
     469      201429 :     entry->vno = tmp8;
     470      201429 :     ret = krb5_kt_ret_keyblock (context, d, cursor->sp, &entry->keyblock);
     471      201429 :     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      201429 :     curpos = krb5_storage_seek(cursor->sp, 0, SEEK_CUR);
     477      201429 :     if(len + 4 + pos - curpos >= 4) {
     478      201429 :         ret = krb5_ret_int32(cursor->sp, &tmp32);
     479      201429 :         if (ret == 0 && tmp32 != 0)
     480      201429 :             entry->vno = tmp32;
     481             :     }
     482             :     /* there might be a flags field here */
     483      201429 :     if(len + 4 + pos - curpos >= 8) {
     484      201429 :         ret = krb5_ret_uint32(cursor->sp, &utmp32);
     485      201429 :         if (ret == 0)
     486      201429 :             entry->flags = utmp32;
     487             :     } else
     488           0 :         entry->flags = 0;
     489             : 
     490      201429 :     entry->aliases = NULL;
     491             : 
     492      201429 :     if(start) *start = pos;
     493      201429 :     if(end) *end = pos + 4 + len;
     494      193000 :  out:
     495      201429 :     if (ret)
     496           0 :         krb5_kt_free_entry(context, entry);
     497      201429 :     krb5_storage_seek(cursor->sp, pos + 4 + len, SEEK_SET);
     498      201429 :     return ret;
     499             : }
     500             : 
     501             : static krb5_error_code KRB5_CALLCONV
     502      193496 : fkt_next_entry(krb5_context context,
     503             :                krb5_keytab id,
     504             :                krb5_keytab_entry *entry,
     505             :                krb5_kt_cursor *cursor)
     506             : {
     507      193496 :     return fkt_next_entry_int(context, id, entry, cursor, NULL, NULL);
     508             : }
     509             : 
     510             : static krb5_error_code KRB5_CALLCONV
     511       54305 : fkt_end_seq_get(krb5_context context,
     512             :                 krb5_keytab id,
     513             :                 krb5_kt_cursor *cursor)
     514             : {
     515       54305 :     krb5_storage_free(cursor->sp);
     516       54305 :     close(cursor->fd);
     517       54305 :     return 0;
     518             : }
     519             : 
     520             : static krb5_error_code KRB5_CALLCONV
     521         174 : fkt_setup_keytab(krb5_context context,
     522             :                  krb5_keytab id,
     523             :                  krb5_storage *sp)
     524             : {
     525          22 :     krb5_error_code ret;
     526         174 :     ret = krb5_store_int8(sp, 5);
     527         174 :     if(ret)
     528           0 :         return ret;
     529         174 :     if(id->version == 0)
     530         174 :         id->version = KRB5_KT_VNO;
     531         174 :     return krb5_store_int8 (sp, id->version);
     532             : }
     533             : 
     534             : static krb5_error_code KRB5_CALLCONV
     535        2214 : fkt_add_entry(krb5_context context,
     536             :               krb5_keytab id,
     537             :               krb5_keytab_entry *entry)
     538             : {
     539         231 :     int ret;
     540         231 :     int fd;
     541         231 :     krb5_storage *sp;
     542         231 :     krb5_ssize_t bytes;
     543        2214 :     struct fkt_data *d = id->data;
     544         231 :     krb5_data keytab;
     545         231 :     int32_t len;
     546             : 
     547        2214 :     fd = open(d->filename, O_RDWR | O_BINARY | O_CLOEXEC);
     548        2214 :     if (fd < 0) {
     549         174 :         fd = open(d->filename, O_RDWR | O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC, 0600);
     550         174 :         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         174 :         rk_cloexec(fd);
     558             : 
     559         174 :         ret = _krb5_xlock(context, fd, 1, d->filename);
     560         174 :         if (ret) {
     561           0 :             close(fd);
     562           0 :             return ret;
     563             :         }
     564         174 :         sp = krb5_storage_stdio_from_fd(fd, "wb+");
     565         174 :         if (sp == NULL) {
     566           0 :             close(fd);
     567           0 :             return krb5_enomem(context);
     568             :         }
     569         174 :         krb5_storage_set_eof_code(sp, KRB5_KT_END);
     570         174 :         ret = fkt_setup_keytab(context, id, sp);
     571         174 :         if (ret) {
     572           0 :             goto out;
     573             :         }
     574         174 :         storage_set_flags(context, sp, id->version);
     575             :     } else {
     576         209 :         int8_t pvno, tag;
     577             : 
     578        2040 :         rk_cloexec(fd);
     579             : 
     580        2040 :         ret = _krb5_xlock(context, fd, 1, d->filename);
     581        2040 :         if (ret) {
     582           0 :             close(fd);
     583           0 :             return ret;
     584             :         }
     585        2040 :         sp = krb5_storage_stdio_from_fd(fd, "wb+");
     586        2040 :         if (sp == NULL) {
     587           0 :             (void) close(fd);
     588           0 :             return ret;
     589             :         }
     590        2040 :         krb5_storage_set_eof_code(sp, KRB5_KT_END);
     591        2040 :         ret = krb5_ret_int8(sp, &pvno);
     592        2040 :         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        2040 :             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        2040 :             ret = krb5_ret_int8 (sp, &tag);
     612        2040 :             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        2040 :             id->version = tag;
     620        2040 :             storage_set_flags(context, sp, id->version);
     621             :         }
     622             :     }
     623             : 
     624             :     {
     625         231 :         krb5_storage *emem;
     626        2214 :         emem = krb5_storage_emem();
     627        2214 :         if(emem == NULL) {
     628           0 :             ret = krb5_enomem(context);
     629           0 :             goto out;
     630             :         }
     631        2214 :         ret = krb5_kt_store_principal(context, emem, entry->principal);
     632        2214 :         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        2214 :         ret = krb5_store_int32 (emem, entry->timestamp);
     641        2214 :         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        2214 :         ret = krb5_store_int8 (emem, entry->vno % 256);
     650        2214 :         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        2214 :         ret = krb5_kt_store_keyblock (context, d, emem, &entry->keyblock);
     659        2214 :         if(ret) {
     660           0 :             krb5_storage_free(emem);
     661           0 :             goto out;
     662             :         }
     663        2214 :         if ((d->flags & KRB5_KT_FL_JAVA) == 0) {
     664        2214 :             ret = krb5_store_int32 (emem, entry->vno);
     665        2214 :             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        2214 :             ret = krb5_store_uint32 (emem, entry->flags);
     674        2214 :             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        2214 :         ret = krb5_storage_to_data(emem, &keytab);
     685        2214 :         krb5_storage_free(emem);
     686        2214 :         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       14582 :     while(1) {
     696        1308 :         off_t here;
     697             : 
     698       16796 :         here = krb5_storage_seek(sp, 0, SEEK_CUR);
     699       16796 :         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       16796 :         ret = krb5_ret_int32(sp, &len);
     708       16796 :         if (ret) {
     709             :             /* There could have been a partial length.  Recover! */
     710        1754 :             (void) krb5_storage_truncate(sp, here);
     711        1754 :             len = keytab.length;
     712        1754 :             break;
     713             :         }
     714       15042 :         if(len < 0) {
     715         776 :             len = -len;
     716         776 :             if(len >= (int)keytab.length) {
     717         460 :                 krb5_storage_seek(sp, -4, SEEK_CUR);
     718         460 :                 break;
     719             :             }
     720             :         }
     721       14582 :         krb5_storage_seek(sp, len, SEEK_CUR);
     722             :     }
     723        2214 :     ret = krb5_store_int32(sp, len);
     724        2214 :     if (ret != 0)
     725           0 :         goto out;
     726        2214 :     bytes = krb5_storage_write(sp, keytab.data, keytab.length);
     727        2214 :     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        2214 :     memset(keytab.data, 0, keytab.length);
     735        2214 :     krb5_data_free(&keytab);
     736        2214 :   out:
     737        2214 :     if (ret == 0)
     738        2214 :         ret = krb5_storage_fsync(sp);
     739        2214 :     krb5_storage_free(sp);
     740        2214 :     close(fd);
     741        2214 :     return ret;
     742             : }
     743             : 
     744             : static krb5_error_code KRB5_CALLCONV
     745         503 : fkt_remove_entry(krb5_context context,
     746             :                  krb5_keytab id,
     747             :                  krb5_keytab_entry *entry)
     748             : {
     749         503 :     struct fkt_data *fkt = id->data;
     750          27 :     krb5_ssize_t bytes;
     751          27 :     krb5_keytab_entry e;
     752          27 :     krb5_kt_cursor cursor;
     753          27 :     off_t pos_start, pos_end;
     754         503 :     int found = 0;
     755          27 :     krb5_error_code ret;
     756             : 
     757         503 :     ret = fkt_start_seq_get_int(context, id, O_RDWR | O_BINARY | O_CLOEXEC, 1, &cursor);
     758         503 :     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       17459 :     while (ret == 0 &&
     769        8932 :            (ret = fkt_next_entry_int(context, id, &e, &cursor,
     770             :                                      &pos_start, &pos_end)) == 0) {
     771        8429 :         if (krb5_kt_compare(context, &e, entry->principal,
     772        8429 :                             entry->vno, entry->keyblock.keytype)) {
     773          27 :             int32_t len;
     774          27 :             unsigned char buf[128];
     775         503 :             found = 1;
     776         503 :             krb5_storage_seek(cursor.sp, pos_start, SEEK_SET);
     777         503 :             len = pos_end - pos_start - 4;
     778         503 :             ret = krb5_store_int32(cursor.sp, -len);
     779         503 :             memset(buf, 0, sizeof(buf));
     780        1032 :             while (ret == 0 && len > 0) {
     781         529 :                 bytes = krb5_storage_write(cursor.sp, buf,
     782         529 :                     min((size_t)len, sizeof(buf)));
     783         529 :                 if (bytes != min((size_t)len, sizeof(buf))) {
     784           0 :                     ret = bytes == -1 ? errno : KRB5_KT_END;
     785           0 :                     break;
     786             :                 }
     787         556 :                 len -= min((size_t)len, sizeof(buf));
     788             :             }
     789             :         }
     790        8429 :         krb5_kt_free_entry(context, &e);
     791             :     }
     792         503 :     (void) krb5_kt_end_seq_get(context, id, &cursor);
     793         503 :     if (ret == KRB5_KT_END)
     794         476 :         ret = 0;
     795         476 :     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         503 :     } else if (!found) {
     804           0 :         krb5_clear_error_message(context);
     805           0 :         return KRB5_KT_NOTFOUND;
     806             :     }
     807         476 :     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.14