155682Smarkm/*
2178825Sdfr * Copyright (c) 1997 - 2005 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
36178825SdfrRCSID("$Id: keytab.c 20211 2007-02-09 07:11:03Z lha $");
3755682Smarkm
3855682Smarkm/*
3955682Smarkm * Register a new keytab in `ops'
4055682Smarkm * Return 0 or an error.
4155682Smarkm */
4255682Smarkm
43178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
4455682Smarkmkrb5_kt_register(krb5_context context,
4555682Smarkm		 const krb5_kt_ops *ops)
4655682Smarkm{
4755682Smarkm    struct krb5_keytab_data *tmp;
4855682Smarkm
49120945Snectar    if (strlen(ops->prefix) > KRB5_KT_PREFIX_MAX_LEN - 1) {
50120945Snectar	krb5_set_error_string(context, "krb5_kt_register; prefix too long");
51178825Sdfr	return KRB5_KT_BADNAME;
52120945Snectar    }
53120945Snectar
5455682Smarkm    tmp = realloc(context->kt_types,
5555682Smarkm		  (context->num_kt_types + 1) * sizeof(*context->kt_types));
5678527Sassar    if(tmp == NULL) {
5778527Sassar	krb5_set_error_string(context, "malloc: out of memory");
5855682Smarkm	return ENOMEM;
5978527Sassar    }
6055682Smarkm    memcpy(&tmp[context->num_kt_types], ops,
6155682Smarkm	   sizeof(tmp[context->num_kt_types]));
6255682Smarkm    context->kt_types = tmp;
6355682Smarkm    context->num_kt_types++;
6455682Smarkm    return 0;
6555682Smarkm}
6655682Smarkm
6755682Smarkm/*
6855682Smarkm * Resolve the keytab name (of the form `type:residual') in `name'
6955682Smarkm * into a keytab in `id'.
7055682Smarkm * Return 0 or an error
7155682Smarkm */
7255682Smarkm
73178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
7455682Smarkmkrb5_kt_resolve(krb5_context context,
7555682Smarkm		const char *name,
7655682Smarkm		krb5_keytab *id)
7755682Smarkm{
7855682Smarkm    krb5_keytab k;
7955682Smarkm    int i;
8055682Smarkm    const char *type, *residual;
8155682Smarkm    size_t type_len;
8255682Smarkm    krb5_error_code ret;
8355682Smarkm
8455682Smarkm    residual = strchr(name, ':');
8555682Smarkm    if(residual == NULL) {
8655682Smarkm	type = "FILE";
8755682Smarkm	type_len = strlen(type);
8855682Smarkm	residual = name;
8955682Smarkm    } else {
9055682Smarkm	type = name;
9155682Smarkm	type_len = residual - name;
9255682Smarkm	residual++;
9355682Smarkm    }
9455682Smarkm
9555682Smarkm    for(i = 0; i < context->num_kt_types; i++) {
9690926Snectar	if(strncasecmp(type, context->kt_types[i].prefix, type_len) == 0)
9755682Smarkm	    break;
9855682Smarkm    }
9978527Sassar    if(i == context->num_kt_types) {
10078527Sassar	krb5_set_error_string(context, "unknown keytab type %.*s",
10178527Sassar			      (int)type_len, type);
10255682Smarkm	return KRB5_KT_UNKNOWN_TYPE;
10378527Sassar    }
10455682Smarkm
10555682Smarkm    k = malloc (sizeof(*k));
10678527Sassar    if (k == NULL) {
10778527Sassar	krb5_set_error_string(context, "malloc: out of memory");
10855682Smarkm	return ENOMEM;
10978527Sassar    }
11055682Smarkm    memcpy(k, &context->kt_types[i], sizeof(*k));
11155682Smarkm    k->data = NULL;
11255682Smarkm    ret = (*k->resolve)(context, residual, k);
11355682Smarkm    if(ret) {
11455682Smarkm	free(k);
11555682Smarkm	k = NULL;
11655682Smarkm    }
11755682Smarkm    *id = k;
11855682Smarkm    return ret;
11955682Smarkm}
12055682Smarkm
12155682Smarkm/*
12255682Smarkm * copy the name of the default keytab into `name'.
12355682Smarkm * Return 0 or KRB5_CONFIG_NOTENUFSPACE if `namesize' is too short.
12455682Smarkm */
12555682Smarkm
126178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
12755682Smarkmkrb5_kt_default_name(krb5_context context, char *name, size_t namesize)
12855682Smarkm{
12978527Sassar    if (strlcpy (name, context->default_keytab, namesize) >= namesize) {
13078527Sassar	krb5_clear_error_string (context);
13155682Smarkm	return KRB5_CONFIG_NOTENUFSPACE;
13278527Sassar    }
13355682Smarkm    return 0;
13455682Smarkm}
13555682Smarkm
13655682Smarkm/*
13778527Sassar * copy the name of the default modify keytab into `name'.
13878527Sassar * Return 0 or KRB5_CONFIG_NOTENUFSPACE if `namesize' is too short.
13978527Sassar */
14078527Sassar
141178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
14278527Sassarkrb5_kt_default_modify_name(krb5_context context, char *name, size_t namesize)
14378527Sassar{
14490926Snectar    const char *kt = NULL;
14590926Snectar    if(context->default_keytab_modify == NULL) {
14690926Snectar	if(strncasecmp(context->default_keytab, "ANY:", 4) != 0)
14790926Snectar	    kt = context->default_keytab;
14890926Snectar	else {
14990926Snectar	    size_t len = strcspn(context->default_keytab + 4, ",");
15090926Snectar	    if(len >= namesize) {
15190926Snectar		krb5_clear_error_string(context);
15290926Snectar		return KRB5_CONFIG_NOTENUFSPACE;
15390926Snectar	    }
15490926Snectar	    strlcpy(name, context->default_keytab + 4, namesize);
15590926Snectar	    name[len] = '\0';
15690926Snectar	    return 0;
15790926Snectar	}
15890926Snectar    } else
15990926Snectar	kt = context->default_keytab_modify;
16090926Snectar    if (strlcpy (name, kt, namesize) >= namesize) {
16178527Sassar	krb5_clear_error_string (context);
16278527Sassar	return KRB5_CONFIG_NOTENUFSPACE;
16378527Sassar    }
16478527Sassar    return 0;
16578527Sassar}
16678527Sassar
16778527Sassar/*
16855682Smarkm * Set `id' to the default keytab.
16955682Smarkm * Return 0 or an error.
17055682Smarkm */
17155682Smarkm
172178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
17355682Smarkmkrb5_kt_default(krb5_context context, krb5_keytab *id)
17455682Smarkm{
17555682Smarkm    return krb5_kt_resolve (context, context->default_keytab, id);
17655682Smarkm}
17755682Smarkm
17855682Smarkm/*
17955682Smarkm * Read the key identified by `(principal, vno, enctype)' from the
18055682Smarkm * keytab in `keyprocarg' (the default if == NULL) into `*key'.
18155682Smarkm * Return 0 or an error.
18255682Smarkm */
18355682Smarkm
184178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
18555682Smarkmkrb5_kt_read_service_key(krb5_context context,
18655682Smarkm			 krb5_pointer keyprocarg,
18755682Smarkm			 krb5_principal principal,
18855682Smarkm			 krb5_kvno vno,
18955682Smarkm			 krb5_enctype enctype,
19055682Smarkm			 krb5_keyblock **key)
19155682Smarkm{
19255682Smarkm    krb5_keytab keytab;
19355682Smarkm    krb5_keytab_entry entry;
19455682Smarkm    krb5_error_code ret;
19555682Smarkm
19655682Smarkm    if (keyprocarg)
19755682Smarkm	ret = krb5_kt_resolve (context, keyprocarg, &keytab);
19855682Smarkm    else
19955682Smarkm	ret = krb5_kt_default (context, &keytab);
20055682Smarkm
20155682Smarkm    if (ret)
20255682Smarkm	return ret;
20355682Smarkm
20455682Smarkm    ret = krb5_kt_get_entry (context, keytab, principal, vno, enctype, &entry);
20555682Smarkm    krb5_kt_close (context, keytab);
20655682Smarkm    if (ret)
20755682Smarkm	return ret;
20855682Smarkm    ret = krb5_copy_keyblock (context, &entry.keyblock, key);
20955682Smarkm    krb5_kt_free_entry(context, &entry);
21055682Smarkm    return ret;
21155682Smarkm}
21255682Smarkm
21355682Smarkm/*
214120945Snectar * Return the type of the `keytab' in the string `prefix of length
215120945Snectar * `prefixsize'.
216120945Snectar */
217120945Snectar
218178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
219120945Snectarkrb5_kt_get_type(krb5_context context,
220120945Snectar		 krb5_keytab keytab,
221120945Snectar		 char *prefix,
222120945Snectar		 size_t prefixsize)
223120945Snectar{
224120945Snectar    strlcpy(prefix, keytab->prefix, prefixsize);
225120945Snectar    return 0;
226120945Snectar}
227120945Snectar
228120945Snectar/*
22955682Smarkm * Retrieve the name of the keytab `keytab' into `name', `namesize'
23055682Smarkm * Return 0 or an error.
23155682Smarkm */
23255682Smarkm
233178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
23455682Smarkmkrb5_kt_get_name(krb5_context context,
23555682Smarkm		 krb5_keytab keytab,
23655682Smarkm		 char *name,
23755682Smarkm		 size_t namesize)
23855682Smarkm{
23955682Smarkm    return (*keytab->get_name)(context, keytab, name, namesize);
24055682Smarkm}
24155682Smarkm
24255682Smarkm/*
243178825Sdfr * Retrieve the full name of the keytab `keytab' and store the name in
244178825Sdfr * `str'. `str' needs to be freed by the caller using free(3).
245178825Sdfr * Returns 0 or an error. On error, *str is set to NULL.
24655682Smarkm */
24755682Smarkm
248178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
249178825Sdfrkrb5_kt_get_full_name(krb5_context context,
250178825Sdfr		      krb5_keytab keytab,
251178825Sdfr		      char **str)
252178825Sdfr{
253178825Sdfr    char type[KRB5_KT_PREFIX_MAX_LEN];
254178825Sdfr    char name[MAXPATHLEN];
255178825Sdfr    krb5_error_code ret;
256178825Sdfr
257178825Sdfr    *str = NULL;
258178825Sdfr
259178825Sdfr    ret = krb5_kt_get_type(context, keytab, type, sizeof(type));
260178825Sdfr    if (ret)
261178825Sdfr	return ret;
262178825Sdfr
263178825Sdfr    ret = krb5_kt_get_name(context, keytab, name, sizeof(name));
264178825Sdfr    if (ret)
265178825Sdfr	return ret;
266178825Sdfr
267178825Sdfr    if (asprintf(str, "%s:%s", type, name) == -1) {
268178825Sdfr	krb5_set_error_string(context, "malloc - out of memory");
269178825Sdfr	*str = NULL;
270178825Sdfr	return ENOMEM;
271178825Sdfr    }
272178825Sdfr
273178825Sdfr    return 0;
274178825Sdfr}
275178825Sdfr
276178825Sdfr/*
277178825Sdfr * Finish using the keytab in `id'.  All resources will be released,
278178825Sdfr * even on errors.  Return 0 or an error.
279178825Sdfr */
280178825Sdfr
281178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
28255682Smarkmkrb5_kt_close(krb5_context context,
28355682Smarkm	      krb5_keytab id)
28455682Smarkm{
28555682Smarkm    krb5_error_code ret;
28655682Smarkm
28755682Smarkm    ret = (*id->close)(context, id);
288178825Sdfr    memset(id, 0, sizeof(*id));
289178825Sdfr    free(id);
29055682Smarkm    return ret;
29155682Smarkm}
29255682Smarkm
29355682Smarkm/*
29455682Smarkm * Compare `entry' against `principal, vno, enctype'.
29555682Smarkm * Any of `principal, vno, enctype' might be 0 which acts as a wildcard.
29655682Smarkm * Return TRUE if they compare the same, FALSE otherwise.
29755682Smarkm */
29855682Smarkm
299178825Sdfrkrb5_boolean KRB5_LIB_FUNCTION
30055682Smarkmkrb5_kt_compare(krb5_context context,
30155682Smarkm		krb5_keytab_entry *entry,
30255682Smarkm		krb5_const_principal principal,
30355682Smarkm		krb5_kvno vno,
30455682Smarkm		krb5_enctype enctype)
30555682Smarkm{
30655682Smarkm    if(principal != NULL &&
30755682Smarkm       !krb5_principal_compare(context, entry->principal, principal))
30855682Smarkm	return FALSE;
30955682Smarkm    if(vno && vno != entry->vno)
31055682Smarkm	return FALSE;
31155682Smarkm    if(enctype && enctype != entry->keyblock.keytype)
31255682Smarkm	return FALSE;
31355682Smarkm    return TRUE;
31455682Smarkm}
31555682Smarkm
31655682Smarkm/*
31755682Smarkm * Retrieve the keytab entry for `principal, kvno, enctype' into `entry'
31855682Smarkm * from the keytab `id'.
319102644Snectar * kvno == 0 is a wildcard and gives the keytab with the highest vno.
32055682Smarkm * Return 0 or an error.
32155682Smarkm */
32255682Smarkm
323178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
32455682Smarkmkrb5_kt_get_entry(krb5_context context,
32555682Smarkm		  krb5_keytab id,
32655682Smarkm		  krb5_const_principal principal,
32755682Smarkm		  krb5_kvno kvno,
32855682Smarkm		  krb5_enctype enctype,
32955682Smarkm		  krb5_keytab_entry *entry)
33055682Smarkm{
33155682Smarkm    krb5_keytab_entry tmp;
33255682Smarkm    krb5_error_code ret;
33355682Smarkm    krb5_kt_cursor cursor;
33455682Smarkm
33555682Smarkm    if(id->get)
33655682Smarkm	return (*id->get)(context, id, principal, kvno, enctype, entry);
33755682Smarkm
33855682Smarkm    ret = krb5_kt_start_seq_get (context, id, &cursor);
339178825Sdfr    if (ret) {
340178825Sdfr	krb5_clear_error_string(context);
34155682Smarkm	return KRB5_KT_NOTFOUND; /* XXX i.e. file not found */
342178825Sdfr    }
34355682Smarkm
34455682Smarkm    entry->vno = 0;
34555682Smarkm    while (krb5_kt_next_entry(context, id, &tmp, &cursor) == 0) {
34655682Smarkm	if (krb5_kt_compare(context, &tmp, principal, 0, enctype)) {
347102644Snectar	    /* the file keytab might only store the lower 8 bits of
348102644Snectar	       the kvno, so only compare those bits */
349102644Snectar	    if (kvno == tmp.vno
350102644Snectar		|| (tmp.vno < 256 && kvno % 256 == tmp.vno)) {
35155682Smarkm		krb5_kt_copy_entry_contents (context, &tmp, entry);
35255682Smarkm		krb5_kt_free_entry (context, &tmp);
35355682Smarkm		krb5_kt_end_seq_get(context, id, &cursor);
35455682Smarkm		return 0;
35555682Smarkm	    } else if (kvno == 0 && tmp.vno > entry->vno) {
35655682Smarkm		if (entry->vno)
35755682Smarkm		    krb5_kt_free_entry (context, entry);
35855682Smarkm		krb5_kt_copy_entry_contents (context, &tmp, entry);
35955682Smarkm	    }
36055682Smarkm	}
36155682Smarkm	krb5_kt_free_entry(context, &tmp);
36255682Smarkm    }
36355682Smarkm    krb5_kt_end_seq_get (context, id, &cursor);
36478527Sassar    if (entry->vno) {
36555682Smarkm	return 0;
36678527Sassar    } else {
367178825Sdfr	char princ[256], kvno_str[25], *kt_name;
368178825Sdfr	char *enctype_str = NULL;
36978527Sassar
37078527Sassar	krb5_unparse_name_fixed (context, principal, princ, sizeof(princ));
371178825Sdfr	krb5_kt_get_full_name (context, id, &kt_name);
372178825Sdfr	krb5_enctype_to_string(context, enctype, &enctype_str);
37378527Sassar
374120945Snectar	if (kvno)
375120945Snectar	    snprintf(kvno_str, sizeof(kvno_str), "(kvno %d)", kvno);
376120945Snectar	else
377120945Snectar	    kvno_str[0] = '\0';
378120945Snectar
37978527Sassar	krb5_set_error_string (context,
380178825Sdfr 			       "Failed to find %s%s in keytab %s (%s)",
381102644Snectar			       princ,
382120945Snectar			       kvno_str,
383178825Sdfr			       kt_name ? kt_name : "unknown keytab",
384178825Sdfr			       enctype_str ? enctype_str : "unknown enctype");
385178825Sdfr	free(kt_name);
386178825Sdfr	free(enctype_str);
38755682Smarkm	return KRB5_KT_NOTFOUND;
38878527Sassar    }
38955682Smarkm}
39055682Smarkm
39155682Smarkm/*
39255682Smarkm * Copy the contents of `in' into `out'.
393102644Snectar * Return 0 or an error.  */
39455682Smarkm
395178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
39655682Smarkmkrb5_kt_copy_entry_contents(krb5_context context,
39755682Smarkm			    const krb5_keytab_entry *in,
39855682Smarkm			    krb5_keytab_entry *out)
39955682Smarkm{
40055682Smarkm    krb5_error_code ret;
40155682Smarkm
40255682Smarkm    memset(out, 0, sizeof(*out));
40355682Smarkm    out->vno = in->vno;
40455682Smarkm
40555682Smarkm    ret = krb5_copy_principal (context, in->principal, &out->principal);
40655682Smarkm    if (ret)
40755682Smarkm	goto fail;
40855682Smarkm    ret = krb5_copy_keyblock_contents (context,
40955682Smarkm				       &in->keyblock,
41055682Smarkm				       &out->keyblock);
41155682Smarkm    if (ret)
41255682Smarkm	goto fail;
41355682Smarkm    out->timestamp = in->timestamp;
41455682Smarkm    return 0;
41555682Smarkmfail:
41655682Smarkm    krb5_kt_free_entry (context, out);
41755682Smarkm    return ret;
41855682Smarkm}
41955682Smarkm
42055682Smarkm/*
42155682Smarkm * Free the contents of `entry'.
42255682Smarkm */
42355682Smarkm
424178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
42555682Smarkmkrb5_kt_free_entry(krb5_context context,
42655682Smarkm		   krb5_keytab_entry *entry)
42755682Smarkm{
428178825Sdfr    krb5_free_principal (context, entry->principal);
429178825Sdfr    krb5_free_keyblock_contents (context, &entry->keyblock);
430178825Sdfr    memset(entry, 0, sizeof(*entry));
43155682Smarkm    return 0;
43255682Smarkm}
43355682Smarkm
43455682Smarkm/*
43555682Smarkm * Set `cursor' to point at the beginning of `id'.
43655682Smarkm * Return 0 or an error.
43755682Smarkm */
43855682Smarkm
439178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
44055682Smarkmkrb5_kt_start_seq_get(krb5_context context,
44155682Smarkm		      krb5_keytab id,
44255682Smarkm		      krb5_kt_cursor *cursor)
44355682Smarkm{
44478527Sassar    if(id->start_seq_get == NULL) {
44578527Sassar	krb5_set_error_string(context,
44678527Sassar			      "start_seq_get is not supported in the %s "
44778527Sassar			      " keytab", id->prefix);
44855682Smarkm	return HEIM_ERR_OPNOTSUPP;
44978527Sassar    }
45055682Smarkm    return (*id->start_seq_get)(context, id, cursor);
45155682Smarkm}
45255682Smarkm
45355682Smarkm/*
45455682Smarkm * Get the next entry from `id' pointed to by `cursor' and advance the
45555682Smarkm * `cursor'.
45655682Smarkm * Return 0 or an error.
45755682Smarkm */
45855682Smarkm
459178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
46055682Smarkmkrb5_kt_next_entry(krb5_context context,
46155682Smarkm		   krb5_keytab id,
46255682Smarkm		   krb5_keytab_entry *entry,
46355682Smarkm		   krb5_kt_cursor *cursor)
46455682Smarkm{
46578527Sassar    if(id->next_entry == NULL) {
46678527Sassar	krb5_set_error_string(context,
46778527Sassar			      "next_entry is not supported in the %s "
46878527Sassar			      " keytab", id->prefix);
46955682Smarkm	return HEIM_ERR_OPNOTSUPP;
47078527Sassar    }
47155682Smarkm    return (*id->next_entry)(context, id, entry, cursor);
47255682Smarkm}
47355682Smarkm
47455682Smarkm/*
47555682Smarkm * Release all resources associated with `cursor'.
47655682Smarkm */
47755682Smarkm
478178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
47955682Smarkmkrb5_kt_end_seq_get(krb5_context context,
48055682Smarkm		    krb5_keytab id,
48155682Smarkm		    krb5_kt_cursor *cursor)
48255682Smarkm{
48378527Sassar    if(id->end_seq_get == NULL) {
48478527Sassar	krb5_set_error_string(context,
48578527Sassar			      "end_seq_get is not supported in the %s "
48678527Sassar			      " keytab", id->prefix);
48755682Smarkm	return HEIM_ERR_OPNOTSUPP;
48878527Sassar    }
48955682Smarkm    return (*id->end_seq_get)(context, id, cursor);
49055682Smarkm}
49155682Smarkm
49255682Smarkm/*
49355682Smarkm * Add the entry in `entry' to the keytab `id'.
49455682Smarkm * Return 0 or an error.
49555682Smarkm */
49655682Smarkm
497178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
49855682Smarkmkrb5_kt_add_entry(krb5_context context,
49955682Smarkm		  krb5_keytab id,
50055682Smarkm		  krb5_keytab_entry *entry)
50155682Smarkm{
50278527Sassar    if(id->add == NULL) {
50378527Sassar	krb5_set_error_string(context, "Add is not supported in the %s keytab",
50478527Sassar			      id->prefix);
50555682Smarkm	return KRB5_KT_NOWRITE;
50678527Sassar    }
50757416Smarkm    entry->timestamp = time(NULL);
50855682Smarkm    return (*id->add)(context, id,entry);
50955682Smarkm}
51055682Smarkm
51155682Smarkm/*
51255682Smarkm * Remove the entry `entry' from the keytab `id'.
51355682Smarkm * Return 0 or an error.
51455682Smarkm */
51555682Smarkm
516178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
51755682Smarkmkrb5_kt_remove_entry(krb5_context context,
51855682Smarkm		     krb5_keytab id,
51955682Smarkm		     krb5_keytab_entry *entry)
52055682Smarkm{
52178527Sassar    if(id->remove == NULL) {
52278527Sassar	krb5_set_error_string(context,
52378527Sassar			      "Remove is not supported in the %s keytab",
52478527Sassar			      id->prefix);
52555682Smarkm	return KRB5_KT_NOWRITE;
52678527Sassar    }
52755682Smarkm    return (*id->remove)(context, id, entry);
52855682Smarkm}
529