keytab_file.c revision 102644
155682Smarkm/*
2102644Snectar * Copyright (c) 1997 - 2002 Kungliga Tekniska H�gskolan
355682Smarkm * (Royal Institute of Technology, Stockholm, Sweden).
455682Smarkm * All rights reserved.
555682Smarkm *
655682Smarkm * Redistribution and use in source and binary forms, with or without
755682Smarkm * modification, are permitted provided that the following conditions
855682Smarkm * are met:
955682Smarkm *
1055682Smarkm * 1. Redistributions of source code must retain the above copyright
1155682Smarkm *    notice, this list of conditions and the following disclaimer.
1255682Smarkm *
1355682Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1455682Smarkm *    notice, this list of conditions and the following disclaimer in the
1555682Smarkm *    documentation and/or other materials provided with the distribution.
1655682Smarkm *
1755682Smarkm * 3. Neither the name of the Institute nor the names of its contributors
1855682Smarkm *    may be used to endorse or promote products derived from this software
1955682Smarkm *    without specific prior written permission.
2055682Smarkm *
2155682Smarkm * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
2255682Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2355682Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2455682Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
2555682Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2655682Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2755682Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2855682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2955682Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3055682Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3155682Smarkm * SUCH DAMAGE.
3255682Smarkm */
3355682Smarkm
3455682Smarkm#include "krb5_locl.h"
3555682Smarkm
36102644SnectarRCSID("$Id: keytab_file.c,v 1.11 2002/05/28 12:57:27 joda Exp $");
3755682Smarkm
3855682Smarkm#define KRB5_KT_VNO_1 1
3955682Smarkm#define KRB5_KT_VNO_2 2
4055682Smarkm#define KRB5_KT_VNO   KRB5_KT_VNO_2
4155682Smarkm
4255682Smarkm/* file operations -------------------------------------------- */
4355682Smarkm
4455682Smarkmstruct fkt_data {
4555682Smarkm    char *filename;
4655682Smarkm};
4755682Smarkm
4855682Smarkmstatic krb5_error_code
4978527Sassarkrb5_kt_ret_data(krb5_context context,
5078527Sassar		 krb5_storage *sp,
5155682Smarkm		 krb5_data *data)
5255682Smarkm{
5355682Smarkm    int ret;
5455682Smarkm    int16_t size;
5555682Smarkm    ret = krb5_ret_int16(sp, &size);
5655682Smarkm    if(ret)
5755682Smarkm	return ret;
5855682Smarkm    data->length = size;
5955682Smarkm    data->data = malloc(size);
6078527Sassar    if (data->data == NULL) {
6178527Sassar	krb5_set_error_string (context, "malloc: out of memory");
6255682Smarkm	return ENOMEM;
6378527Sassar    }
64102644Snectar    ret = krb5_storage_read(sp, data->data, size);
6555682Smarkm    if(ret != size)
6655682Smarkm	return (ret < 0)? errno : KRB5_KT_END;
6755682Smarkm    return 0;
6855682Smarkm}
6955682Smarkm
7055682Smarkmstatic krb5_error_code
7178527Sassarkrb5_kt_ret_string(krb5_context context,
7278527Sassar		   krb5_storage *sp,
7355682Smarkm		   general_string *data)
7455682Smarkm{
7555682Smarkm    int ret;
7655682Smarkm    int16_t size;
7755682Smarkm    ret = krb5_ret_int16(sp, &size);
7855682Smarkm    if(ret)
7955682Smarkm	return ret;
8055682Smarkm    *data = malloc(size + 1);
8178527Sassar    if (*data == NULL) {
8278527Sassar	krb5_set_error_string (context, "malloc: out of memory");
8355682Smarkm	return ENOMEM;
8478527Sassar    }
85102644Snectar    ret = krb5_storage_read(sp, *data, size);
8655682Smarkm    (*data)[size] = '\0';
8755682Smarkm    if(ret != size)
8855682Smarkm	return (ret < 0)? errno : KRB5_KT_END;
8955682Smarkm    return 0;
9055682Smarkm}
9155682Smarkm
9255682Smarkmstatic krb5_error_code
9378527Sassarkrb5_kt_store_data(krb5_context context,
9478527Sassar		   krb5_storage *sp,
9555682Smarkm		   krb5_data data)
9655682Smarkm{
9755682Smarkm    int ret;
9855682Smarkm    ret = krb5_store_int16(sp, data.length);
9955682Smarkm    if(ret < 0)
10055682Smarkm	return ret;
101102644Snectar    ret = krb5_storage_write(sp, data.data, data.length);
10255682Smarkm    if(ret != data.length){
10355682Smarkm	if(ret < 0)
10455682Smarkm	    return errno;
10555682Smarkm	return KRB5_KT_END;
10655682Smarkm    }
10755682Smarkm    return 0;
10855682Smarkm}
10955682Smarkm
11055682Smarkmstatic krb5_error_code
11155682Smarkmkrb5_kt_store_string(krb5_storage *sp,
11255682Smarkm		     general_string data)
11355682Smarkm{
11455682Smarkm    int ret;
11555682Smarkm    size_t len = strlen(data);
11655682Smarkm    ret = krb5_store_int16(sp, len);
11755682Smarkm    if(ret < 0)
11855682Smarkm	return ret;
119102644Snectar    ret = krb5_storage_write(sp, data, len);
12055682Smarkm    if(ret != len){
12155682Smarkm	if(ret < 0)
12255682Smarkm	    return errno;
12355682Smarkm	return KRB5_KT_END;
12455682Smarkm    }
12555682Smarkm    return 0;
12655682Smarkm}
12755682Smarkm
12855682Smarkmstatic krb5_error_code
12978527Sassarkrb5_kt_ret_keyblock(krb5_context context, krb5_storage *sp, krb5_keyblock *p)
13055682Smarkm{
13155682Smarkm    int ret;
13255682Smarkm    int16_t tmp;
13355682Smarkm
13455682Smarkm    ret = krb5_ret_int16(sp, &tmp); /* keytype + etype */
13555682Smarkm    if(ret) return ret;
13655682Smarkm    p->keytype = tmp;
13778527Sassar    ret = krb5_kt_ret_data(context, sp, &p->keyvalue);
13855682Smarkm    return ret;
13955682Smarkm}
14055682Smarkm
14155682Smarkmstatic krb5_error_code
14278527Sassarkrb5_kt_store_keyblock(krb5_context context,
14378527Sassar		       krb5_storage *sp,
14455682Smarkm		       krb5_keyblock *p)
14555682Smarkm{
14655682Smarkm    int ret;
14755682Smarkm
14855682Smarkm    ret = krb5_store_int16(sp, p->keytype); /* keytype + etype */
14955682Smarkm    if(ret) return ret;
15078527Sassar    ret = krb5_kt_store_data(context, sp, p->keyvalue);
15155682Smarkm    return ret;
15255682Smarkm}
15355682Smarkm
15455682Smarkm
15555682Smarkmstatic krb5_error_code
15678527Sassarkrb5_kt_ret_principal(krb5_context context,
15778527Sassar		      krb5_storage *sp,
15855682Smarkm		      krb5_principal *princ)
15955682Smarkm{
16055682Smarkm    int i;
16155682Smarkm    int ret;
16255682Smarkm    krb5_principal p;
16355682Smarkm    int16_t tmp;
16455682Smarkm
16555682Smarkm    ALLOC(p, 1);
16678527Sassar    if(p == NULL) {
16778527Sassar	krb5_set_error_string (context, "malloc: out of memory");
16855682Smarkm	return ENOMEM;
16978527Sassar    }
17055682Smarkm
17155682Smarkm    ret = krb5_ret_int16(sp, &tmp);
17255682Smarkm    if(ret)
17355682Smarkm	return ret;
174102644Snectar    if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS))
17555682Smarkm	tmp--;
17655682Smarkm    p->name.name_string.len = tmp;
17778527Sassar    ret = krb5_kt_ret_string(context, sp, &p->realm);
17878527Sassar    if(ret)
17978527Sassar	return ret;
18055682Smarkm    p->name.name_string.val = calloc(p->name.name_string.len,
18155682Smarkm				     sizeof(*p->name.name_string.val));
18278527Sassar    if(p->name.name_string.val == NULL) {
18378527Sassar	krb5_set_error_string (context, "malloc: out of memory");
18455682Smarkm	return ENOMEM;
18578527Sassar    }
18655682Smarkm    for(i = 0; i < p->name.name_string.len; i++){
18778527Sassar	ret = krb5_kt_ret_string(context, sp, p->name.name_string.val + i);
18878527Sassar	if(ret)
18978527Sassar	    return ret;
19055682Smarkm    }
19155682Smarkm    if (krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE))
19255682Smarkm	p->name.name_type = KRB5_NT_UNKNOWN;
19355682Smarkm    else {
19455682Smarkm	int32_t tmp32;
19555682Smarkm	ret = krb5_ret_int32(sp, &tmp32);
19655682Smarkm	p->name.name_type = tmp32;
19755682Smarkm	if (ret)
19855682Smarkm	    return ret;
19955682Smarkm    }
20055682Smarkm    *princ = p;
20155682Smarkm    return 0;
20255682Smarkm}
20355682Smarkm
20455682Smarkmstatic krb5_error_code
20578527Sassarkrb5_kt_store_principal(krb5_context context,
20678527Sassar			krb5_storage *sp,
20755682Smarkm			krb5_principal p)
20855682Smarkm{
20955682Smarkm    int i;
21055682Smarkm    int ret;
21155682Smarkm
21255682Smarkm    if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS))
21355682Smarkm	ret = krb5_store_int16(sp, p->name.name_string.len + 1);
21455682Smarkm    else
21555682Smarkm	ret = krb5_store_int16(sp, p->name.name_string.len);
21655682Smarkm    if(ret) return ret;
21755682Smarkm    ret = krb5_kt_store_string(sp, p->realm);
21855682Smarkm    if(ret) return ret;
21955682Smarkm    for(i = 0; i < p->name.name_string.len; i++){
22055682Smarkm	ret = krb5_kt_store_string(sp, p->name.name_string.val[i]);
22178527Sassar	if(ret)
22278527Sassar	    return ret;
22355682Smarkm    }
22455682Smarkm    if(!krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE)) {
22555682Smarkm	ret = krb5_store_int32(sp, p->name.name_type);
22655682Smarkm	if(ret)
22755682Smarkm	    return ret;
22855682Smarkm    }
22955682Smarkm
23055682Smarkm    return 0;
23155682Smarkm}
23255682Smarkm
23355682Smarkmstatic krb5_error_code
23455682Smarkmfkt_resolve(krb5_context context, const char *name, krb5_keytab id)
23555682Smarkm{
23655682Smarkm    struct fkt_data *d;
23778527Sassar
23855682Smarkm    d = malloc(sizeof(*d));
23978527Sassar    if(d == NULL) {
24078527Sassar	krb5_set_error_string (context, "malloc: out of memory");
24155682Smarkm	return ENOMEM;
24278527Sassar    }
24355682Smarkm    d->filename = strdup(name);
24455682Smarkm    if(d->filename == NULL) {
24555682Smarkm	free(d);
24678527Sassar	krb5_set_error_string (context, "malloc: out of memory");
24755682Smarkm	return ENOMEM;
24855682Smarkm    }
24955682Smarkm    id->data = d;
25055682Smarkm    return 0;
25155682Smarkm}
25255682Smarkm
25355682Smarkmstatic krb5_error_code
25455682Smarkmfkt_close(krb5_context context, krb5_keytab id)
25555682Smarkm{
25655682Smarkm    struct fkt_data *d = id->data;
25755682Smarkm    free(d->filename);
25855682Smarkm    free(d);
25955682Smarkm    return 0;
26055682Smarkm}
26155682Smarkm
26255682Smarkmstatic krb5_error_code
26355682Smarkmfkt_get_name(krb5_context context,
26455682Smarkm	     krb5_keytab id,
26555682Smarkm	     char *name,
26655682Smarkm	     size_t namesize)
26755682Smarkm{
26855682Smarkm    /* This function is XXX */
26955682Smarkm    struct fkt_data *d = id->data;
27055682Smarkm    strlcpy(name, d->filename, namesize);
27155682Smarkm    return 0;
27255682Smarkm}
27355682Smarkm
27455682Smarkmstatic void
27555682Smarkmstorage_set_flags(krb5_context context, krb5_storage *sp, int vno)
27655682Smarkm{
27755682Smarkm    int flags = 0;
27855682Smarkm    switch(vno) {
27955682Smarkm    case KRB5_KT_VNO_1:
28055682Smarkm	flags |= KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS;
28155682Smarkm	flags |= KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE;
28255682Smarkm	flags |= KRB5_STORAGE_HOST_BYTEORDER;
28355682Smarkm	break;
28455682Smarkm    case KRB5_KT_VNO_2:
28555682Smarkm	break;
28655682Smarkm    default:
287102644Snectar	krb5_warnx(context,
288102644Snectar		   "storage_set_flags called with bad vno (%d)", vno);
28955682Smarkm    }
29055682Smarkm    krb5_storage_set_flags(sp, flags);
29155682Smarkm}
29255682Smarkm
29355682Smarkmstatic krb5_error_code
29455682Smarkmfkt_start_seq_get_int(krb5_context context,
29555682Smarkm		      krb5_keytab id,
29655682Smarkm		      int flags,
29755682Smarkm		      krb5_kt_cursor *c)
29855682Smarkm{
29955682Smarkm    int8_t pvno, tag;
30055682Smarkm    krb5_error_code ret;
30155682Smarkm    struct fkt_data *d = id->data;
30255682Smarkm
30355682Smarkm    c->fd = open (d->filename, flags);
30478527Sassar    if (c->fd < 0) {
30578527Sassar	ret = errno;
30678527Sassar	krb5_set_error_string(context, "open(%s): %s", d->filename,
30778527Sassar			      strerror(ret));
30878527Sassar	return ret;
30978527Sassar    }
31055682Smarkm    c->sp = krb5_storage_from_fd(c->fd);
311102644Snectar    krb5_storage_set_eof_code(c->sp, KRB5_KT_END);
31255682Smarkm    ret = krb5_ret_int8(c->sp, &pvno);
31355682Smarkm    if(ret) {
31455682Smarkm	krb5_storage_free(c->sp);
31555682Smarkm	close(c->fd);
31655682Smarkm	return ret;
31755682Smarkm    }
31855682Smarkm    if(pvno != 5) {
31955682Smarkm	krb5_storage_free(c->sp);
32055682Smarkm	close(c->fd);
32178527Sassar	krb5_clear_error_string (context);
32255682Smarkm	return KRB5_KEYTAB_BADVNO;
32355682Smarkm    }
32455682Smarkm    ret = krb5_ret_int8(c->sp, &tag);
32555682Smarkm    if (ret) {
32655682Smarkm	krb5_storage_free(c->sp);
32755682Smarkm	close(c->fd);
32855682Smarkm	return ret;
32955682Smarkm    }
33055682Smarkm    id->version = tag;
33155682Smarkm    storage_set_flags(context, c->sp, id->version);
33255682Smarkm    return 0;
33355682Smarkm}
33455682Smarkm
33555682Smarkmstatic krb5_error_code
33655682Smarkmfkt_start_seq_get(krb5_context context,
33755682Smarkm		  krb5_keytab id,
33855682Smarkm		  krb5_kt_cursor *c)
33955682Smarkm{
34055682Smarkm    return fkt_start_seq_get_int(context, id, O_RDONLY | O_BINARY, c);
34155682Smarkm}
34255682Smarkm
34355682Smarkmstatic krb5_error_code
34455682Smarkmfkt_next_entry_int(krb5_context context,
34555682Smarkm		   krb5_keytab id,
34655682Smarkm		   krb5_keytab_entry *entry,
34755682Smarkm		   krb5_kt_cursor *cursor,
34855682Smarkm		   off_t *start,
34955682Smarkm		   off_t *end)
35055682Smarkm{
35155682Smarkm    int32_t len;
35255682Smarkm    int ret;
35355682Smarkm    int8_t tmp8;
35455682Smarkm    int32_t tmp32;
355102644Snectar    off_t pos, curpos;
35655682Smarkm
357102644Snectar    pos = krb5_storage_seek(cursor->sp, 0, SEEK_CUR);
35855682Smarkmloop:
35955682Smarkm    ret = krb5_ret_int32(cursor->sp, &len);
36055682Smarkm    if (ret)
36155682Smarkm	return ret;
36255682Smarkm    if(len < 0) {
363102644Snectar	pos = krb5_storage_seek(cursor->sp, -len, SEEK_CUR);
36455682Smarkm	goto loop;
36555682Smarkm    }
36678527Sassar    ret = krb5_kt_ret_principal (context, cursor->sp, &entry->principal);
36755682Smarkm    if (ret)
36855682Smarkm	goto out;
36955682Smarkm    ret = krb5_ret_int32(cursor->sp, &tmp32);
37055682Smarkm    entry->timestamp = tmp32;
37155682Smarkm    if (ret)
37255682Smarkm	goto out;
37355682Smarkm    ret = krb5_ret_int8(cursor->sp, &tmp8);
37455682Smarkm    if (ret)
37555682Smarkm	goto out;
37655682Smarkm    entry->vno = tmp8;
37778527Sassar    ret = krb5_kt_ret_keyblock (context, cursor->sp, &entry->keyblock);
37855682Smarkm    if (ret)
37955682Smarkm	goto out;
380102644Snectar    /* there might be a 32 bit kvno here
381102644Snectar     * if it's zero, assume that the 8bit one was right,
382102644Snectar     * otherwise trust the new value */
383102644Snectar    curpos = krb5_storage_seek(cursor->sp, 0, SEEK_CUR);
384102644Snectar    if(len + 4 + pos - curpos == 4) {
385102644Snectar	ret = krb5_ret_int32(cursor->sp, &tmp32);
386102644Snectar	if (ret == 0 && tmp32 != 0) {
387102644Snectar	    entry->vno = tmp32;
388102644Snectar	}
389102644Snectar    }
39055682Smarkm    if(start) *start = pos;
39155682Smarkm    if(end) *end = *start + 4 + len;
39255682Smarkm out:
393102644Snectar    krb5_storage_seek(cursor->sp, pos + 4 + len, SEEK_SET);
39455682Smarkm    return ret;
39555682Smarkm}
39655682Smarkm
39755682Smarkmstatic krb5_error_code
39855682Smarkmfkt_next_entry(krb5_context context,
39955682Smarkm	       krb5_keytab id,
40055682Smarkm	       krb5_keytab_entry *entry,
40155682Smarkm	       krb5_kt_cursor *cursor)
40255682Smarkm{
40355682Smarkm    return fkt_next_entry_int(context, id, entry, cursor, NULL, NULL);
40455682Smarkm}
40555682Smarkm
40655682Smarkmstatic krb5_error_code
40755682Smarkmfkt_end_seq_get(krb5_context context,
40855682Smarkm		krb5_keytab id,
40955682Smarkm		krb5_kt_cursor *cursor)
41055682Smarkm{
41155682Smarkm    krb5_storage_free(cursor->sp);
41255682Smarkm    close(cursor->fd);
41355682Smarkm    return 0;
41455682Smarkm}
41555682Smarkm
41655682Smarkmstatic krb5_error_code
417102644Snectarfkt_setup_keytab(krb5_context context,
418102644Snectar		 krb5_keytab id,
419102644Snectar		 krb5_storage *sp)
420102644Snectar{
421102644Snectar    krb5_error_code ret;
422102644Snectar    ret = krb5_store_int8(sp, 5);
423102644Snectar    if(ret)
424102644Snectar	return ret;
425102644Snectar    if(id->version == 0)
426102644Snectar	id->version = KRB5_KT_VNO;
427102644Snectar    return krb5_store_int8 (sp, id->version);
428102644Snectar}
429102644Snectar
430102644Snectarstatic krb5_error_code
43155682Smarkmfkt_add_entry(krb5_context context,
43255682Smarkm	      krb5_keytab id,
43355682Smarkm	      krb5_keytab_entry *entry)
43455682Smarkm{
43555682Smarkm    int ret;
43655682Smarkm    int fd;
43755682Smarkm    krb5_storage *sp;
43855682Smarkm    struct fkt_data *d = id->data;
43955682Smarkm    krb5_data keytab;
44055682Smarkm    int32_t len;
44155682Smarkm
44255682Smarkm    fd = open (d->filename, O_RDWR | O_BINARY);
44355682Smarkm    if (fd < 0) {
44455682Smarkm	fd = open (d->filename, O_RDWR | O_CREAT | O_BINARY, 0600);
44578527Sassar	if (fd < 0) {
44678527Sassar	    ret = errno;
44778527Sassar	    krb5_set_error_string(context, "open(%s): %s", d->filename,
44878527Sassar				  strerror(ret));
44978527Sassar	    return ret;
45078527Sassar	}
45155682Smarkm	sp = krb5_storage_from_fd(fd);
452102644Snectar	krb5_storage_set_eof_code(sp, KRB5_KT_END);
453102644Snectar	ret = fkt_setup_keytab(context, id, sp);
45455682Smarkm	if(ret) {
45555682Smarkm	    krb5_storage_free(sp);
45655682Smarkm	    close(fd);
45755682Smarkm	    return ret;
45855682Smarkm	}
45955682Smarkm	storage_set_flags(context, sp, id->version);
46055682Smarkm    } else {
46155682Smarkm	int8_t pvno, tag;
46255682Smarkm	sp = krb5_storage_from_fd(fd);
463102644Snectar	krb5_storage_set_eof_code(sp, KRB5_KT_END);
46455682Smarkm	ret = krb5_ret_int8(sp, &pvno);
46555682Smarkm	if(ret) {
466102644Snectar	    /* we probably have a zero byte file, so try to set it up
467102644Snectar               properly */
468102644Snectar	    ret = fkt_setup_keytab(context, id, sp);
469102644Snectar	    if(ret) {
470102644Snectar		krb5_set_error_string(context, "%s: keytab is corrupted: %s",
471102644Snectar				      d->filename, strerror(ret));
472102644Snectar		krb5_storage_free(sp);
473102644Snectar		close(fd);
474102644Snectar		return ret;
475102644Snectar	    }
476102644Snectar	    storage_set_flags(context, sp, id->version);
477102644Snectar	} else {
478102644Snectar	    if(pvno != 5) {
479102644Snectar		krb5_storage_free(sp);
480102644Snectar		close(fd);
481102644Snectar		krb5_clear_error_string (context);
482102644Snectar		ret = KRB5_KEYTAB_BADVNO;
483102644Snectar		krb5_set_error_string(context, "%s: %s",
484102644Snectar				      d->filename, strerror(ret));
485102644Snectar		return ret;
486102644Snectar	    }
487102644Snectar	    ret = krb5_ret_int8 (sp, &tag);
488102644Snectar	    if (ret) {
489102644Snectar		krb5_set_error_string(context, "%s: reading tag: %s",
490102644Snectar				      d->filename, strerror(ret));
491102644Snectar		krb5_storage_free(sp);
492102644Snectar		close(fd);
493102644Snectar		return ret;
494102644Snectar	    }
495102644Snectar	    id->version = tag;
496102644Snectar	    storage_set_flags(context, sp, id->version);
49755682Smarkm	}
49855682Smarkm    }
49955682Smarkm
50055682Smarkm    {
50155682Smarkm	krb5_storage *emem;
50255682Smarkm	emem = krb5_storage_emem();
50355682Smarkm	if(emem == NULL) {
50455682Smarkm	    ret = ENOMEM;
50578527Sassar	    krb5_set_error_string (context, "malloc: out of memory");
50655682Smarkm	    goto out;
50755682Smarkm	}
50878527Sassar	ret = krb5_kt_store_principal(context, emem, entry->principal);
50955682Smarkm	if(ret) {
51055682Smarkm	    krb5_storage_free(emem);
51155682Smarkm	    goto out;
51255682Smarkm	}
51355682Smarkm	ret = krb5_store_int32 (emem, entry->timestamp);
51455682Smarkm	if(ret) {
51555682Smarkm	    krb5_storage_free(emem);
51655682Smarkm	    goto out;
51755682Smarkm	}
518102644Snectar	ret = krb5_store_int8 (emem, entry->vno % 256);
51955682Smarkm	if(ret) {
52055682Smarkm	    krb5_storage_free(emem);
52155682Smarkm	    goto out;
52255682Smarkm	}
52378527Sassar	ret = krb5_kt_store_keyblock (context, emem, &entry->keyblock);
52455682Smarkm	if(ret) {
52555682Smarkm	    krb5_storage_free(emem);
52655682Smarkm	    goto out;
52755682Smarkm	}
528102644Snectar	ret = krb5_store_int32 (emem, entry->vno);
529102644Snectar	if (ret) {
530102644Snectar	    krb5_storage_free(emem);
531102644Snectar	    goto out;
532102644Snectar	}
533102644Snectar
53455682Smarkm	ret = krb5_storage_to_data(emem, &keytab);
53555682Smarkm	krb5_storage_free(emem);
53655682Smarkm	if(ret)
53755682Smarkm	    goto out;
53855682Smarkm    }
53955682Smarkm
54055682Smarkm    while(1) {
54155682Smarkm	ret = krb5_ret_int32(sp, &len);
542102644Snectar	if(ret == KRB5_KT_END) {
54355682Smarkm	    len = keytab.length;
54455682Smarkm	    break;
54555682Smarkm	}
54655682Smarkm	if(len < 0) {
54755682Smarkm	    len = -len;
54855682Smarkm	    if(len >= keytab.length) {
549102644Snectar		krb5_storage_seek(sp, -4, SEEK_CUR);
55055682Smarkm		break;
55155682Smarkm	    }
55255682Smarkm	}
553102644Snectar	krb5_storage_seek(sp, len, SEEK_CUR);
55455682Smarkm    }
55555682Smarkm    ret = krb5_store_int32(sp, len);
556102644Snectar    if(krb5_storage_write(sp, keytab.data, keytab.length) < 0)
55755682Smarkm	ret = errno;
55855682Smarkm    memset(keytab.data, 0, keytab.length);
55955682Smarkm    krb5_data_free(&keytab);
560102644Snectar  out:
56155682Smarkm    krb5_storage_free(sp);
56255682Smarkm    close(fd);
56355682Smarkm    return ret;
56455682Smarkm}
56555682Smarkm
56655682Smarkmstatic krb5_error_code
56755682Smarkmfkt_remove_entry(krb5_context context,
56855682Smarkm		 krb5_keytab id,
56955682Smarkm		 krb5_keytab_entry *entry)
57055682Smarkm{
57155682Smarkm    krb5_keytab_entry e;
57255682Smarkm    krb5_kt_cursor cursor;
57355682Smarkm    off_t pos_start, pos_end;
57455682Smarkm    int found = 0;
57555682Smarkm
57655682Smarkm    fkt_start_seq_get_int(context, id, O_RDWR | O_BINARY, &cursor);
57755682Smarkm    while(fkt_next_entry_int(context, id, &e, &cursor,
57855682Smarkm			     &pos_start, &pos_end) == 0) {
57955682Smarkm	if(krb5_kt_compare(context, &e, entry->principal,
58055682Smarkm			   entry->vno, entry->keyblock.keytype)) {
58155682Smarkm	    int32_t len;
58255682Smarkm	    unsigned char buf[128];
58355682Smarkm	    found = 1;
584102644Snectar	    krb5_storage_seek(cursor.sp, pos_start, SEEK_SET);
58555682Smarkm	    len = pos_end - pos_start - 4;
58655682Smarkm	    krb5_store_int32(cursor.sp, -len);
58755682Smarkm	    memset(buf, 0, sizeof(buf));
58855682Smarkm	    while(len > 0) {
589102644Snectar		krb5_storage_write(cursor.sp, buf, min(len, sizeof(buf)));
59055682Smarkm		len -= min(len, sizeof(buf));
59155682Smarkm	    }
59255682Smarkm	}
59355682Smarkm    }
59455682Smarkm    krb5_kt_end_seq_get(context, id, &cursor);
59578527Sassar    if (!found) {
59678527Sassar	krb5_clear_error_string (context);
59755682Smarkm	return KRB5_KT_NOTFOUND;
59878527Sassar    }
59955682Smarkm    return 0;
60055682Smarkm}
60155682Smarkm
60255682Smarkmconst krb5_kt_ops krb5_fkt_ops = {
60355682Smarkm    "FILE",
60455682Smarkm    fkt_resolve,
60555682Smarkm    fkt_get_name,
60655682Smarkm    fkt_close,
60755682Smarkm    NULL, /* get */
60855682Smarkm    fkt_start_seq_get,
60955682Smarkm    fkt_next_entry,
61055682Smarkm    fkt_end_seq_get,
61155682Smarkm    fkt_add_entry,
61255682Smarkm    fkt_remove_entry
61355682Smarkm};
614