155682Smarkm/* 2233294Sstas * Copyright (c) 1997 - 2008 Kungliga Tekniska H��gskolan 3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden). 4233294Sstas * All rights reserved. 555682Smarkm * 6233294Sstas * Redistribution and use in source and binary forms, with or without 7233294Sstas * modification, are permitted provided that the following conditions 8233294Sstas * are met: 955682Smarkm * 10233294Sstas * 1. Redistributions of source code must retain the above copyright 11233294Sstas * notice, this list of conditions and the following disclaimer. 1255682Smarkm * 13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright 14233294Sstas * notice, this list of conditions and the following disclaimer in the 15233294Sstas * documentation and/or other materials provided with the distribution. 1655682Smarkm * 17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors 18233294Sstas * may be used to endorse or promote products derived from this software 19233294Sstas * without specific prior written permission. 2055682Smarkm * 21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24233294Sstas * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31233294Sstas * SUCH DAMAGE. 3255682Smarkm */ 3355682Smarkm 3455682Smarkm#include "krb5_locl.h" 3555682Smarkm 3655682Smarkm#define KRB5_KT_VNO_1 1 3755682Smarkm#define KRB5_KT_VNO_2 2 3855682Smarkm#define KRB5_KT_VNO KRB5_KT_VNO_2 3955682Smarkm 40178825Sdfr#define KRB5_KT_FL_JAVA 1 41178825Sdfr 42178825Sdfr 4355682Smarkm/* file operations -------------------------------------------- */ 4455682Smarkm 4555682Smarkmstruct fkt_data { 4655682Smarkm char *filename; 47178825Sdfr int flags; 4855682Smarkm}; 4955682Smarkm 5055682Smarkmstatic krb5_error_code 5178527Sassarkrb5_kt_ret_data(krb5_context context, 5278527Sassar krb5_storage *sp, 5355682Smarkm krb5_data *data) 5455682Smarkm{ 5555682Smarkm int ret; 5655682Smarkm int16_t size; 5755682Smarkm ret = krb5_ret_int16(sp, &size); 5855682Smarkm if(ret) 5955682Smarkm return ret; 6055682Smarkm data->length = size; 6155682Smarkm data->data = malloc(size); 6278527Sassar if (data->data == NULL) { 63233294Sstas krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 6455682Smarkm return ENOMEM; 6578527Sassar } 66102644Snectar ret = krb5_storage_read(sp, data->data, size); 6755682Smarkm if(ret != size) 6855682Smarkm return (ret < 0)? errno : KRB5_KT_END; 6955682Smarkm return 0; 7055682Smarkm} 7155682Smarkm 7255682Smarkmstatic krb5_error_code 7378527Sassarkrb5_kt_ret_string(krb5_context context, 7478527Sassar krb5_storage *sp, 75178825Sdfr heim_general_string *data) 7655682Smarkm{ 7755682Smarkm int ret; 7855682Smarkm int16_t size; 7955682Smarkm ret = krb5_ret_int16(sp, &size); 8055682Smarkm if(ret) 8155682Smarkm return ret; 8255682Smarkm *data = malloc(size + 1); 8378527Sassar if (*data == NULL) { 84233294Sstas krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 8555682Smarkm return ENOMEM; 8678527Sassar } 87102644Snectar ret = krb5_storage_read(sp, *data, size); 8855682Smarkm (*data)[size] = '\0'; 8955682Smarkm if(ret != size) 9055682Smarkm return (ret < 0)? errno : KRB5_KT_END; 9155682Smarkm return 0; 9255682Smarkm} 9355682Smarkm 9455682Smarkmstatic krb5_error_code 9578527Sassarkrb5_kt_store_data(krb5_context context, 9678527Sassar krb5_storage *sp, 9755682Smarkm krb5_data data) 9855682Smarkm{ 9955682Smarkm int ret; 10055682Smarkm ret = krb5_store_int16(sp, data.length); 10155682Smarkm if(ret < 0) 10255682Smarkm return ret; 103102644Snectar ret = krb5_storage_write(sp, data.data, data.length); 104233294Sstas if(ret != (int)data.length){ 10555682Smarkm if(ret < 0) 10655682Smarkm return errno; 10755682Smarkm return KRB5_KT_END; 10855682Smarkm } 10955682Smarkm return 0; 11055682Smarkm} 11155682Smarkm 11255682Smarkmstatic krb5_error_code 11355682Smarkmkrb5_kt_store_string(krb5_storage *sp, 114178825Sdfr heim_general_string data) 11555682Smarkm{ 11655682Smarkm int ret; 11755682Smarkm size_t len = strlen(data); 11855682Smarkm ret = krb5_store_int16(sp, len); 11955682Smarkm if(ret < 0) 12055682Smarkm return ret; 121102644Snectar ret = krb5_storage_write(sp, data, len); 122233294Sstas if(ret != (int)len){ 12355682Smarkm if(ret < 0) 12455682Smarkm return errno; 12555682Smarkm return KRB5_KT_END; 12655682Smarkm } 12755682Smarkm return 0; 12855682Smarkm} 12955682Smarkm 13055682Smarkmstatic krb5_error_code 131233294Sstaskrb5_kt_ret_keyblock(krb5_context context, 132233294Sstas struct fkt_data *fkt, 133233294Sstas krb5_storage *sp, 134233294Sstas krb5_keyblock *p) 13555682Smarkm{ 13655682Smarkm int ret; 13755682Smarkm int16_t tmp; 13855682Smarkm 13955682Smarkm ret = krb5_ret_int16(sp, &tmp); /* keytype + etype */ 140233294Sstas if(ret) { 141233294Sstas krb5_set_error_message(context, ret, 142233294Sstas N_("Cant read keyblock from file %s", ""), 143233294Sstas fkt->filename); 144233294Sstas return ret; 145233294Sstas } 14655682Smarkm p->keytype = tmp; 14778527Sassar ret = krb5_kt_ret_data(context, sp, &p->keyvalue); 148233294Sstas if (ret) 149233294Sstas krb5_set_error_message(context, ret, 150233294Sstas N_("Cant read keyblock from file %s", ""), 151233294Sstas fkt->filename); 15255682Smarkm return ret; 15355682Smarkm} 15455682Smarkm 15555682Smarkmstatic krb5_error_code 15678527Sassarkrb5_kt_store_keyblock(krb5_context context, 157233294Sstas struct fkt_data *fkt, 158233294Sstas krb5_storage *sp, 15955682Smarkm krb5_keyblock *p) 16055682Smarkm{ 16155682Smarkm int ret; 16255682Smarkm 16355682Smarkm ret = krb5_store_int16(sp, p->keytype); /* keytype + etype */ 164233294Sstas if(ret) { 165233294Sstas krb5_set_error_message(context, ret, 166233294Sstas N_("Cant store keyblock to file %s", ""), 167233294Sstas fkt->filename); 168233294Sstas return ret; 169233294Sstas } 17078527Sassar ret = krb5_kt_store_data(context, sp, p->keyvalue); 171233294Sstas if (ret) 172233294Sstas krb5_set_error_message(context, ret, 173233294Sstas N_("Cant store keyblock to file %s", ""), 174233294Sstas fkt->filename); 17555682Smarkm return ret; 17655682Smarkm} 17755682Smarkm 17855682Smarkm 17955682Smarkmstatic krb5_error_code 18078527Sassarkrb5_kt_ret_principal(krb5_context context, 181233294Sstas struct fkt_data *fkt, 18278527Sassar krb5_storage *sp, 18355682Smarkm krb5_principal *princ) 18455682Smarkm{ 185233294Sstas size_t i; 18655682Smarkm int ret; 18755682Smarkm krb5_principal p; 188178825Sdfr int16_t len; 189233294Sstas 19055682Smarkm ALLOC(p, 1); 19178527Sassar if(p == NULL) { 192233294Sstas krb5_set_error_message(context, ENOMEM, 193233294Sstas N_("malloc: out of memory", "")); 19455682Smarkm return ENOMEM; 19578527Sassar } 19655682Smarkm 197178825Sdfr ret = krb5_ret_int16(sp, &len); 198178825Sdfr if(ret) { 199233294Sstas krb5_set_error_message(context, ret, 200233294Sstas N_("Failed decoding length of " 201233294Sstas "keytab principal in keytab file %s", ""), 202233294Sstas fkt->filename); 203178825Sdfr goto out; 204178825Sdfr } 205102644Snectar if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS)) 206178825Sdfr len--; 207178825Sdfr if (len < 0) { 208178825Sdfr ret = KRB5_KT_END; 209233294Sstas krb5_set_error_message(context, ret, 210233294Sstas N_("Keytab principal contains " 211233294Sstas "invalid length in keytab %s", ""), 212233294Sstas fkt->filename); 213178825Sdfr goto out; 214178825Sdfr } 21578527Sassar ret = krb5_kt_ret_string(context, sp, &p->realm); 216233294Sstas if(ret) { 217233294Sstas krb5_set_error_message(context, ret, 218233294Sstas N_("Can't read realm from keytab: %s", ""), 219233294Sstas fkt->filename); 220178825Sdfr goto out; 221233294Sstas } 222178825Sdfr p->name.name_string.val = calloc(len, sizeof(*p->name.name_string.val)); 22378527Sassar if(p->name.name_string.val == NULL) { 224178825Sdfr ret = ENOMEM; 225233294Sstas krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 226178825Sdfr goto out; 22778527Sassar } 228178825Sdfr p->name.name_string.len = len; 22955682Smarkm for(i = 0; i < p->name.name_string.len; i++){ 23078527Sassar ret = krb5_kt_ret_string(context, sp, p->name.name_string.val + i); 231233294Sstas if(ret) { 232233294Sstas krb5_set_error_message(context, ret, 233233294Sstas N_("Can't read principal from " 234233294Sstas "keytab: %s", ""), 235233294Sstas fkt->filename); 236178825Sdfr goto out; 237233294Sstas } 23855682Smarkm } 23955682Smarkm if (krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE)) 24055682Smarkm p->name.name_type = KRB5_NT_UNKNOWN; 24155682Smarkm else { 24255682Smarkm int32_t tmp32; 24355682Smarkm ret = krb5_ret_int32(sp, &tmp32); 24455682Smarkm p->name.name_type = tmp32; 245233294Sstas if (ret) { 246233294Sstas krb5_set_error_message(context, ret, 247233294Sstas N_("Can't read name-type from " 248233294Sstas "keytab: %s", ""), 249233294Sstas fkt->filename); 250178825Sdfr goto out; 251233294Sstas } 25255682Smarkm } 25355682Smarkm *princ = p; 25455682Smarkm return 0; 255178825Sdfrout: 256178825Sdfr krb5_free_principal(context, p); 257178825Sdfr return ret; 25855682Smarkm} 25955682Smarkm 26055682Smarkmstatic krb5_error_code 26178527Sassarkrb5_kt_store_principal(krb5_context context, 26278527Sassar krb5_storage *sp, 26355682Smarkm krb5_principal p) 26455682Smarkm{ 265233294Sstas size_t i; 26655682Smarkm int ret; 267233294Sstas 26855682Smarkm if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS)) 26955682Smarkm ret = krb5_store_int16(sp, p->name.name_string.len + 1); 27055682Smarkm else 27155682Smarkm ret = krb5_store_int16(sp, p->name.name_string.len); 27255682Smarkm if(ret) return ret; 27355682Smarkm ret = krb5_kt_store_string(sp, p->realm); 27455682Smarkm if(ret) return ret; 27555682Smarkm for(i = 0; i < p->name.name_string.len; i++){ 27655682Smarkm ret = krb5_kt_store_string(sp, p->name.name_string.val[i]); 27778527Sassar if(ret) 27878527Sassar return ret; 27955682Smarkm } 28055682Smarkm if(!krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE)) { 28155682Smarkm ret = krb5_store_int32(sp, p->name.name_type); 28255682Smarkm if(ret) 28355682Smarkm return ret; 28455682Smarkm } 28555682Smarkm 28655682Smarkm return 0; 28755682Smarkm} 28855682Smarkm 289233294Sstasstatic krb5_error_code KRB5_CALLCONV 29055682Smarkmfkt_resolve(krb5_context context, const char *name, krb5_keytab id) 29155682Smarkm{ 29255682Smarkm struct fkt_data *d; 29378527Sassar 29455682Smarkm d = malloc(sizeof(*d)); 29578527Sassar if(d == NULL) { 296233294Sstas krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 29755682Smarkm return ENOMEM; 29878527Sassar } 29955682Smarkm d->filename = strdup(name); 30055682Smarkm if(d->filename == NULL) { 30155682Smarkm free(d); 302233294Sstas krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 30355682Smarkm return ENOMEM; 30455682Smarkm } 305178825Sdfr d->flags = 0; 30655682Smarkm id->data = d; 30755682Smarkm return 0; 30855682Smarkm} 30955682Smarkm 310233294Sstasstatic krb5_error_code KRB5_CALLCONV 311178825Sdfrfkt_resolve_java14(krb5_context context, const char *name, krb5_keytab id) 312178825Sdfr{ 313178825Sdfr krb5_error_code ret; 314178825Sdfr 315178825Sdfr ret = fkt_resolve(context, name, id); 316178825Sdfr if (ret == 0) { 317178825Sdfr struct fkt_data *d = id->data; 318178825Sdfr d->flags |= KRB5_KT_FL_JAVA; 319178825Sdfr } 320178825Sdfr return ret; 321178825Sdfr} 322178825Sdfr 323233294Sstasstatic krb5_error_code KRB5_CALLCONV 32455682Smarkmfkt_close(krb5_context context, krb5_keytab id) 32555682Smarkm{ 32655682Smarkm struct fkt_data *d = id->data; 32755682Smarkm free(d->filename); 32855682Smarkm free(d); 32955682Smarkm return 0; 33055682Smarkm} 33155682Smarkm 332233294Sstasstatic krb5_error_code KRB5_CALLCONV 333233294Sstasfkt_destroy(krb5_context context, krb5_keytab id) 334233294Sstas{ 335233294Sstas struct fkt_data *d = id->data; 336233294Sstas _krb5_erase_file(context, d->filename); 337233294Sstas return 0; 338233294Sstas} 339233294Sstas 340233294Sstasstatic krb5_error_code KRB5_CALLCONV 341233294Sstasfkt_get_name(krb5_context context, 342233294Sstas krb5_keytab id, 343233294Sstas char *name, 34455682Smarkm size_t namesize) 34555682Smarkm{ 34655682Smarkm /* This function is XXX */ 34755682Smarkm struct fkt_data *d = id->data; 34855682Smarkm strlcpy(name, d->filename, namesize); 34955682Smarkm return 0; 35055682Smarkm} 35155682Smarkm 35255682Smarkmstatic void 35355682Smarkmstorage_set_flags(krb5_context context, krb5_storage *sp, int vno) 35455682Smarkm{ 35555682Smarkm int flags = 0; 35655682Smarkm switch(vno) { 35755682Smarkm case KRB5_KT_VNO_1: 35855682Smarkm flags |= KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS; 35955682Smarkm flags |= KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE; 36055682Smarkm flags |= KRB5_STORAGE_HOST_BYTEORDER; 36155682Smarkm break; 36255682Smarkm case KRB5_KT_VNO_2: 36355682Smarkm break; 36455682Smarkm default: 365233294Sstas krb5_warnx(context, 366102644Snectar "storage_set_flags called with bad vno (%d)", vno); 36755682Smarkm } 36855682Smarkm krb5_storage_set_flags(sp, flags); 36955682Smarkm} 37055682Smarkm 37155682Smarkmstatic krb5_error_code 372233294Sstasfkt_start_seq_get_int(krb5_context context, 373233294Sstas krb5_keytab id, 37455682Smarkm int flags, 375178825Sdfr int exclusive, 37655682Smarkm krb5_kt_cursor *c) 37755682Smarkm{ 37855682Smarkm int8_t pvno, tag; 37955682Smarkm krb5_error_code ret; 38055682Smarkm struct fkt_data *d = id->data; 381233294Sstas 38255682Smarkm c->fd = open (d->filename, flags); 38378527Sassar if (c->fd < 0) { 38478527Sassar ret = errno; 385233294Sstas krb5_set_error_message(context, ret, 386233294Sstas N_("keytab %s open failed: %s", ""), 387233294Sstas d->filename, strerror(ret)); 38878527Sassar return ret; 38978527Sassar } 390233294Sstas rk_cloexec(c->fd); 391178825Sdfr ret = _krb5_xlock(context, c->fd, exclusive, d->filename); 392178825Sdfr if (ret) { 393178825Sdfr close(c->fd); 394178825Sdfr return ret; 395178825Sdfr } 39655682Smarkm c->sp = krb5_storage_from_fd(c->fd); 397178825Sdfr if (c->sp == NULL) { 398178825Sdfr _krb5_xunlock(context, c->fd); 399178825Sdfr close(c->fd); 400233294Sstas krb5_set_error_message(context, ENOMEM, 401233294Sstas N_("malloc: out of memory", "")); 402178825Sdfr return ENOMEM; 403178825Sdfr } 404102644Snectar krb5_storage_set_eof_code(c->sp, KRB5_KT_END); 40555682Smarkm ret = krb5_ret_int8(c->sp, &pvno); 40655682Smarkm if(ret) { 40755682Smarkm krb5_storage_free(c->sp); 408178825Sdfr _krb5_xunlock(context, c->fd); 40955682Smarkm close(c->fd); 410233294Sstas krb5_clear_error_message(context); 41155682Smarkm return ret; 41255682Smarkm } 41355682Smarkm if(pvno != 5) { 41455682Smarkm krb5_storage_free(c->sp); 415178825Sdfr _krb5_xunlock(context, c->fd); 41655682Smarkm close(c->fd); 417233294Sstas krb5_clear_error_message (context); 41855682Smarkm return KRB5_KEYTAB_BADVNO; 41955682Smarkm } 42055682Smarkm ret = krb5_ret_int8(c->sp, &tag); 42155682Smarkm if (ret) { 42255682Smarkm krb5_storage_free(c->sp); 423178825Sdfr _krb5_xunlock(context, c->fd); 42455682Smarkm close(c->fd); 425233294Sstas krb5_clear_error_message(context); 42655682Smarkm return ret; 42755682Smarkm } 42855682Smarkm id->version = tag; 42955682Smarkm storage_set_flags(context, c->sp, id->version); 43055682Smarkm return 0; 43155682Smarkm} 43255682Smarkm 433233294Sstasstatic krb5_error_code KRB5_CALLCONV 434233294Sstasfkt_start_seq_get(krb5_context context, 435233294Sstas krb5_keytab id, 43655682Smarkm krb5_kt_cursor *c) 43755682Smarkm{ 438233294Sstas return fkt_start_seq_get_int(context, id, O_RDONLY | O_BINARY | O_CLOEXEC, 0, c); 43955682Smarkm} 44055682Smarkm 44155682Smarkmstatic krb5_error_code 442233294Sstasfkt_next_entry_int(krb5_context context, 443233294Sstas krb5_keytab id, 444233294Sstas krb5_keytab_entry *entry, 44555682Smarkm krb5_kt_cursor *cursor, 44655682Smarkm off_t *start, 44755682Smarkm off_t *end) 44855682Smarkm{ 449233294Sstas struct fkt_data *d = id->data; 45055682Smarkm int32_t len; 45155682Smarkm int ret; 45255682Smarkm int8_t tmp8; 45355682Smarkm int32_t tmp32; 454233294Sstas uint32_t utmp32; 455102644Snectar off_t pos, curpos; 45655682Smarkm 457102644Snectar pos = krb5_storage_seek(cursor->sp, 0, SEEK_CUR); 45855682Smarkmloop: 45955682Smarkm ret = krb5_ret_int32(cursor->sp, &len); 46055682Smarkm if (ret) 46155682Smarkm return ret; 46255682Smarkm if(len < 0) { 463102644Snectar pos = krb5_storage_seek(cursor->sp, -len, SEEK_CUR); 46455682Smarkm goto loop; 46555682Smarkm } 466233294Sstas ret = krb5_kt_ret_principal (context, d, cursor->sp, &entry->principal); 46755682Smarkm if (ret) 46855682Smarkm goto out; 469233294Sstas ret = krb5_ret_uint32(cursor->sp, &utmp32); 470233294Sstas entry->timestamp = utmp32; 47155682Smarkm if (ret) 47255682Smarkm goto out; 47355682Smarkm ret = krb5_ret_int8(cursor->sp, &tmp8); 47455682Smarkm if (ret) 47555682Smarkm goto out; 47655682Smarkm entry->vno = tmp8; 477233294Sstas ret = krb5_kt_ret_keyblock (context, d, cursor->sp, &entry->keyblock); 47855682Smarkm if (ret) 47955682Smarkm goto out; 480102644Snectar /* there might be a 32 bit kvno here 481102644Snectar * if it's zero, assume that the 8bit one was right, 482102644Snectar * otherwise trust the new value */ 483102644Snectar curpos = krb5_storage_seek(cursor->sp, 0, SEEK_CUR); 484178825Sdfr if(len + 4 + pos - curpos >= 4) { 485102644Snectar ret = krb5_ret_int32(cursor->sp, &tmp32); 486233294Sstas if (ret == 0 && tmp32 != 0) 487102644Snectar entry->vno = tmp32; 488102644Snectar } 489233294Sstas /* there might be a flags field here */ 490233294Sstas if(len + 4 + pos - curpos >= 8) { 491233294Sstas ret = krb5_ret_uint32(cursor->sp, &utmp32); 492233294Sstas if (ret == 0) 493233294Sstas entry->flags = utmp32; 494233294Sstas } else 495233294Sstas entry->flags = 0; 496233294Sstas 497233294Sstas entry->aliases = NULL; 498233294Sstas 49955682Smarkm if(start) *start = pos; 500178825Sdfr if(end) *end = pos + 4 + len; 50155682Smarkm out: 502102644Snectar krb5_storage_seek(cursor->sp, pos + 4 + len, SEEK_SET); 50355682Smarkm return ret; 50455682Smarkm} 50555682Smarkm 506233294Sstasstatic krb5_error_code KRB5_CALLCONV 507233294Sstasfkt_next_entry(krb5_context context, 508233294Sstas krb5_keytab id, 509233294Sstas krb5_keytab_entry *entry, 51055682Smarkm krb5_kt_cursor *cursor) 51155682Smarkm{ 51255682Smarkm return fkt_next_entry_int(context, id, entry, cursor, NULL, NULL); 51355682Smarkm} 51455682Smarkm 515233294Sstasstatic krb5_error_code KRB5_CALLCONV 516233294Sstasfkt_end_seq_get(krb5_context context, 51755682Smarkm krb5_keytab id, 51855682Smarkm krb5_kt_cursor *cursor) 51955682Smarkm{ 52055682Smarkm krb5_storage_free(cursor->sp); 521178825Sdfr _krb5_xunlock(context, cursor->fd); 52255682Smarkm close(cursor->fd); 52355682Smarkm return 0; 52455682Smarkm} 52555682Smarkm 526233294Sstasstatic krb5_error_code KRB5_CALLCONV 527102644Snectarfkt_setup_keytab(krb5_context context, 528102644Snectar krb5_keytab id, 529102644Snectar krb5_storage *sp) 530102644Snectar{ 531102644Snectar krb5_error_code ret; 532102644Snectar ret = krb5_store_int8(sp, 5); 533102644Snectar if(ret) 534102644Snectar return ret; 535102644Snectar if(id->version == 0) 536102644Snectar id->version = KRB5_KT_VNO; 537102644Snectar return krb5_store_int8 (sp, id->version); 538102644Snectar} 539233294Sstas 540233294Sstasstatic krb5_error_code KRB5_CALLCONV 54155682Smarkmfkt_add_entry(krb5_context context, 54255682Smarkm krb5_keytab id, 54355682Smarkm krb5_keytab_entry *entry) 54455682Smarkm{ 54555682Smarkm int ret; 54655682Smarkm int fd; 54755682Smarkm krb5_storage *sp; 54855682Smarkm struct fkt_data *d = id->data; 54955682Smarkm krb5_data keytab; 55055682Smarkm int32_t len; 551233294Sstas 552233294Sstas fd = open (d->filename, O_RDWR | O_BINARY | O_CLOEXEC); 55355682Smarkm if (fd < 0) { 554233294Sstas fd = open (d->filename, O_RDWR | O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC, 0600); 55578527Sassar if (fd < 0) { 55678527Sassar ret = errno; 557233294Sstas krb5_set_error_message(context, ret, 558233294Sstas N_("open(%s): %s", ""), d->filename, 559233294Sstas strerror(ret)); 56078527Sassar return ret; 56178527Sassar } 562233294Sstas rk_cloexec(fd); 563233294Sstas 564178825Sdfr ret = _krb5_xlock(context, fd, 1, d->filename); 565178825Sdfr if (ret) { 566178825Sdfr close(fd); 567178825Sdfr return ret; 568178825Sdfr } 56955682Smarkm sp = krb5_storage_from_fd(fd); 570102644Snectar krb5_storage_set_eof_code(sp, KRB5_KT_END); 571102644Snectar ret = fkt_setup_keytab(context, id, sp); 57255682Smarkm if(ret) { 573178825Sdfr goto out; 57455682Smarkm } 57555682Smarkm storage_set_flags(context, sp, id->version); 57655682Smarkm } else { 57755682Smarkm int8_t pvno, tag; 578233294Sstas 579233294Sstas rk_cloexec(fd); 580233294Sstas 581178825Sdfr ret = _krb5_xlock(context, fd, 1, d->filename); 582178825Sdfr if (ret) { 583178825Sdfr close(fd); 584178825Sdfr return ret; 585178825Sdfr } 58655682Smarkm sp = krb5_storage_from_fd(fd); 587102644Snectar krb5_storage_set_eof_code(sp, KRB5_KT_END); 58855682Smarkm ret = krb5_ret_int8(sp, &pvno); 58955682Smarkm if(ret) { 590102644Snectar /* we probably have a zero byte file, so try to set it up 591102644Snectar properly */ 592102644Snectar ret = fkt_setup_keytab(context, id, sp); 593102644Snectar if(ret) { 594233294Sstas krb5_set_error_message(context, ret, 595233294Sstas N_("%s: keytab is corrupted: %s", ""), 596233294Sstas d->filename, strerror(ret)); 597178825Sdfr goto out; 598102644Snectar } 599102644Snectar storage_set_flags(context, sp, id->version); 600102644Snectar } else { 601102644Snectar if(pvno != 5) { 602102644Snectar ret = KRB5_KEYTAB_BADVNO; 603233294Sstas krb5_set_error_message(context, ret, 604233294Sstas N_("Bad version in keytab %s", ""), 605233294Sstas d->filename); 606178825Sdfr goto out; 607102644Snectar } 608102644Snectar ret = krb5_ret_int8 (sp, &tag); 609102644Snectar if (ret) { 610233294Sstas krb5_set_error_message(context, ret, 611233294Sstas N_("failed reading tag from " 612233294Sstas "keytab %s", ""), 613233294Sstas d->filename); 614178825Sdfr goto out; 615102644Snectar } 616102644Snectar id->version = tag; 617102644Snectar storage_set_flags(context, sp, id->version); 61855682Smarkm } 61955682Smarkm } 62055682Smarkm 62155682Smarkm { 62255682Smarkm krb5_storage *emem; 62355682Smarkm emem = krb5_storage_emem(); 62455682Smarkm if(emem == NULL) { 62555682Smarkm ret = ENOMEM; 626233294Sstas krb5_set_error_message(context, ret, 627233294Sstas N_("malloc: out of memory", "")); 62855682Smarkm goto out; 62955682Smarkm } 63078527Sassar ret = krb5_kt_store_principal(context, emem, entry->principal); 63155682Smarkm if(ret) { 632233294Sstas krb5_set_error_message(context, ret, 633233294Sstas N_("Failed storing principal " 634233294Sstas "in keytab %s", ""), 635233294Sstas d->filename); 63655682Smarkm krb5_storage_free(emem); 63755682Smarkm goto out; 63855682Smarkm } 63955682Smarkm ret = krb5_store_int32 (emem, entry->timestamp); 64055682Smarkm if(ret) { 641233294Sstas krb5_set_error_message(context, ret, 642233294Sstas N_("Failed storing timpstamp " 643233294Sstas "in keytab %s", ""), 644233294Sstas d->filename); 64555682Smarkm krb5_storage_free(emem); 64655682Smarkm goto out; 64755682Smarkm } 648102644Snectar ret = krb5_store_int8 (emem, entry->vno % 256); 64955682Smarkm if(ret) { 650233294Sstas krb5_set_error_message(context, ret, 651233294Sstas N_("Failed storing kvno " 652233294Sstas "in keytab %s", ""), 653233294Sstas d->filename); 65455682Smarkm krb5_storage_free(emem); 65555682Smarkm goto out; 65655682Smarkm } 657233294Sstas ret = krb5_kt_store_keyblock (context, d, emem, &entry->keyblock); 65855682Smarkm if(ret) { 65955682Smarkm krb5_storage_free(emem); 66055682Smarkm goto out; 66155682Smarkm } 662178825Sdfr if ((d->flags & KRB5_KT_FL_JAVA) == 0) { 663178825Sdfr ret = krb5_store_int32 (emem, entry->vno); 664178825Sdfr if (ret) { 665233294Sstas krb5_set_error_message(context, ret, 666233294Sstas N_("Failed storing extended kvno " 667233294Sstas "in keytab %s", ""), 668233294Sstas d->filename); 669178825Sdfr krb5_storage_free(emem); 670178825Sdfr goto out; 671178825Sdfr } 672233294Sstas ret = krb5_store_uint32 (emem, entry->flags); 673233294Sstas if (ret) { 674233294Sstas krb5_set_error_message(context, ret, 675233294Sstas N_("Failed storing extended kvno " 676233294Sstas "in keytab %s", ""), 677233294Sstas d->filename); 678233294Sstas krb5_storage_free(emem); 679233294Sstas goto out; 680233294Sstas } 681102644Snectar } 682102644Snectar 68355682Smarkm ret = krb5_storage_to_data(emem, &keytab); 68455682Smarkm krb5_storage_free(emem); 685233294Sstas if(ret) { 686233294Sstas krb5_set_error_message(context, ret, 687233294Sstas N_("Failed converting keytab entry " 688233294Sstas "to memory block for keytab %s", ""), 689233294Sstas d->filename); 69055682Smarkm goto out; 691233294Sstas } 69255682Smarkm } 693233294Sstas 69455682Smarkm while(1) { 69555682Smarkm ret = krb5_ret_int32(sp, &len); 696102644Snectar if(ret == KRB5_KT_END) { 69755682Smarkm len = keytab.length; 69855682Smarkm break; 69955682Smarkm } 70055682Smarkm if(len < 0) { 70155682Smarkm len = -len; 702233294Sstas if(len >= (int)keytab.length) { 703102644Snectar krb5_storage_seek(sp, -4, SEEK_CUR); 70455682Smarkm break; 70555682Smarkm } 70655682Smarkm } 707102644Snectar krb5_storage_seek(sp, len, SEEK_CUR); 70855682Smarkm } 70955682Smarkm ret = krb5_store_int32(sp, len); 710233294Sstas if(krb5_storage_write(sp, keytab.data, keytab.length) < 0) { 71155682Smarkm ret = errno; 712233294Sstas krb5_set_error_message(context, ret, 713233294Sstas N_("Failed writing keytab block " 714233294Sstas "in keytab %s: %s", ""), 715233294Sstas d->filename, strerror(ret)); 716233294Sstas } 71755682Smarkm memset(keytab.data, 0, keytab.length); 71855682Smarkm krb5_data_free(&keytab); 719102644Snectar out: 72055682Smarkm krb5_storage_free(sp); 721178825Sdfr _krb5_xunlock(context, fd); 72255682Smarkm close(fd); 72355682Smarkm return ret; 72455682Smarkm} 72555682Smarkm 726233294Sstasstatic krb5_error_code KRB5_CALLCONV 72755682Smarkmfkt_remove_entry(krb5_context context, 72855682Smarkm krb5_keytab id, 72955682Smarkm krb5_keytab_entry *entry) 73055682Smarkm{ 73155682Smarkm krb5_keytab_entry e; 73255682Smarkm krb5_kt_cursor cursor; 73355682Smarkm off_t pos_start, pos_end; 73455682Smarkm int found = 0; 735107207Snectar krb5_error_code ret; 736233294Sstas 737233294Sstas ret = fkt_start_seq_get_int(context, id, O_RDWR | O_BINARY | O_CLOEXEC, 1, &cursor); 738233294Sstas if(ret != 0) 739107207Snectar goto out; /* return other error here? */ 740233294Sstas while(fkt_next_entry_int(context, id, &e, &cursor, 74155682Smarkm &pos_start, &pos_end) == 0) { 742233294Sstas if(krb5_kt_compare(context, &e, entry->principal, 74355682Smarkm entry->vno, entry->keyblock.keytype)) { 74455682Smarkm int32_t len; 74555682Smarkm unsigned char buf[128]; 74655682Smarkm found = 1; 747102644Snectar krb5_storage_seek(cursor.sp, pos_start, SEEK_SET); 74855682Smarkm len = pos_end - pos_start - 4; 74955682Smarkm krb5_store_int32(cursor.sp, -len); 75055682Smarkm memset(buf, 0, sizeof(buf)); 75155682Smarkm while(len > 0) { 752233294Sstas krb5_storage_write(cursor.sp, buf, 753233294Sstas min((size_t)len, sizeof(buf))); 754233294Sstas len -= min((size_t)len, sizeof(buf)); 75555682Smarkm } 75655682Smarkm } 757178825Sdfr krb5_kt_free_entry(context, &e); 75855682Smarkm } 75955682Smarkm krb5_kt_end_seq_get(context, id, &cursor); 760107207Snectar out: 76178527Sassar if (!found) { 762233294Sstas krb5_clear_error_message (context); 76355682Smarkm return KRB5_KT_NOTFOUND; 76478527Sassar } 76555682Smarkm return 0; 76655682Smarkm} 76755682Smarkm 76855682Smarkmconst krb5_kt_ops krb5_fkt_ops = { 76955682Smarkm "FILE", 77055682Smarkm fkt_resolve, 77155682Smarkm fkt_get_name, 77255682Smarkm fkt_close, 773233294Sstas fkt_destroy, 77455682Smarkm NULL, /* get */ 77555682Smarkm fkt_start_seq_get, 77655682Smarkm fkt_next_entry, 77755682Smarkm fkt_end_seq_get, 77855682Smarkm fkt_add_entry, 77955682Smarkm fkt_remove_entry 78055682Smarkm}; 781178825Sdfr 782178825Sdfrconst krb5_kt_ops krb5_wrfkt_ops = { 783178825Sdfr "WRFILE", 784178825Sdfr fkt_resolve, 785178825Sdfr fkt_get_name, 786178825Sdfr fkt_close, 787233294Sstas fkt_destroy, 788178825Sdfr NULL, /* get */ 789178825Sdfr fkt_start_seq_get, 790178825Sdfr fkt_next_entry, 791178825Sdfr fkt_end_seq_get, 792178825Sdfr fkt_add_entry, 793178825Sdfr fkt_remove_entry 794178825Sdfr}; 795178825Sdfr 796178825Sdfrconst krb5_kt_ops krb5_javakt_ops = { 797178825Sdfr "JAVA14", 798178825Sdfr fkt_resolve_java14, 799178825Sdfr fkt_get_name, 800178825Sdfr fkt_close, 801233294Sstas fkt_destroy, 802178825Sdfr NULL, /* get */ 803178825Sdfr fkt_start_seq_get, 804178825Sdfr fkt_next_entry, 805178825Sdfr fkt_end_seq_get, 806178825Sdfr fkt_add_entry, 807178825Sdfr fkt_remove_entry 808178825Sdfr}; 809