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