keytab.c revision 90926
155682Smarkm/* 278527Sassar * Copyright (c) 1997 - 2001 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 3690926SnectarRCSID("$Id: keytab.c,v 1.52 2002/01/30 10:09:35 joda Exp $"); 3755682Smarkm 3855682Smarkm/* 3955682Smarkm * Register a new keytab in `ops' 4055682Smarkm * Return 0 or an error. 4155682Smarkm */ 4255682Smarkm 4355682Smarkmkrb5_error_code 4455682Smarkmkrb5_kt_register(krb5_context context, 4555682Smarkm const krb5_kt_ops *ops) 4655682Smarkm{ 4755682Smarkm struct krb5_keytab_data *tmp; 4855682Smarkm 4955682Smarkm tmp = realloc(context->kt_types, 5055682Smarkm (context->num_kt_types + 1) * sizeof(*context->kt_types)); 5178527Sassar if(tmp == NULL) { 5278527Sassar krb5_set_error_string(context, "malloc: out of memory"); 5355682Smarkm return ENOMEM; 5478527Sassar } 5555682Smarkm memcpy(&tmp[context->num_kt_types], ops, 5655682Smarkm sizeof(tmp[context->num_kt_types])); 5755682Smarkm context->kt_types = tmp; 5855682Smarkm context->num_kt_types++; 5955682Smarkm return 0; 6055682Smarkm} 6155682Smarkm 6255682Smarkm/* 6355682Smarkm * Resolve the keytab name (of the form `type:residual') in `name' 6455682Smarkm * into a keytab in `id'. 6555682Smarkm * Return 0 or an error 6655682Smarkm */ 6755682Smarkm 6855682Smarkmkrb5_error_code 6955682Smarkmkrb5_kt_resolve(krb5_context context, 7055682Smarkm const char *name, 7155682Smarkm krb5_keytab *id) 7255682Smarkm{ 7355682Smarkm krb5_keytab k; 7455682Smarkm int i; 7555682Smarkm const char *type, *residual; 7655682Smarkm size_t type_len; 7755682Smarkm krb5_error_code ret; 7855682Smarkm 7955682Smarkm residual = strchr(name, ':'); 8055682Smarkm if(residual == NULL) { 8155682Smarkm type = "FILE"; 8255682Smarkm type_len = strlen(type); 8355682Smarkm residual = name; 8455682Smarkm } else { 8555682Smarkm type = name; 8655682Smarkm type_len = residual - name; 8755682Smarkm residual++; 8855682Smarkm } 8955682Smarkm 9055682Smarkm for(i = 0; i < context->num_kt_types; i++) { 9190926Snectar if(strncasecmp(type, context->kt_types[i].prefix, type_len) == 0) 9255682Smarkm break; 9355682Smarkm } 9478527Sassar if(i == context->num_kt_types) { 9578527Sassar krb5_set_error_string(context, "unknown keytab type %.*s", 9678527Sassar (int)type_len, type); 9755682Smarkm return KRB5_KT_UNKNOWN_TYPE; 9878527Sassar } 9955682Smarkm 10055682Smarkm k = malloc (sizeof(*k)); 10178527Sassar if (k == NULL) { 10278527Sassar krb5_set_error_string(context, "malloc: out of memory"); 10355682Smarkm return ENOMEM; 10478527Sassar } 10555682Smarkm memcpy(k, &context->kt_types[i], sizeof(*k)); 10655682Smarkm k->data = NULL; 10755682Smarkm ret = (*k->resolve)(context, residual, k); 10855682Smarkm if(ret) { 10955682Smarkm free(k); 11055682Smarkm k = NULL; 11155682Smarkm } 11255682Smarkm *id = k; 11355682Smarkm return ret; 11455682Smarkm} 11555682Smarkm 11655682Smarkm/* 11755682Smarkm * copy the name of the default keytab into `name'. 11855682Smarkm * Return 0 or KRB5_CONFIG_NOTENUFSPACE if `namesize' is too short. 11955682Smarkm */ 12055682Smarkm 12155682Smarkmkrb5_error_code 12255682Smarkmkrb5_kt_default_name(krb5_context context, char *name, size_t namesize) 12355682Smarkm{ 12478527Sassar if (strlcpy (name, context->default_keytab, namesize) >= namesize) { 12578527Sassar krb5_clear_error_string (context); 12655682Smarkm return KRB5_CONFIG_NOTENUFSPACE; 12778527Sassar } 12855682Smarkm return 0; 12955682Smarkm} 13055682Smarkm 13155682Smarkm/* 13278527Sassar * copy the name of the default modify keytab into `name'. 13378527Sassar * Return 0 or KRB5_CONFIG_NOTENUFSPACE if `namesize' is too short. 13478527Sassar */ 13578527Sassar 13678527Sassarkrb5_error_code 13778527Sassarkrb5_kt_default_modify_name(krb5_context context, char *name, size_t namesize) 13878527Sassar{ 13990926Snectar const char *kt = NULL; 14090926Snectar if(context->default_keytab_modify == NULL) { 14190926Snectar if(strncasecmp(context->default_keytab, "ANY:", 4) != 0) 14290926Snectar kt = context->default_keytab; 14390926Snectar else { 14490926Snectar size_t len = strcspn(context->default_keytab + 4, ","); 14590926Snectar if(len >= namesize) { 14690926Snectar krb5_clear_error_string(context); 14790926Snectar return KRB5_CONFIG_NOTENUFSPACE; 14890926Snectar } 14990926Snectar strlcpy(name, context->default_keytab + 4, namesize); 15090926Snectar name[len] = '\0'; 15190926Snectar return 0; 15290926Snectar } 15390926Snectar } else 15490926Snectar kt = context->default_keytab_modify; 15590926Snectar if (strlcpy (name, kt, namesize) >= namesize) { 15678527Sassar krb5_clear_error_string (context); 15778527Sassar return KRB5_CONFIG_NOTENUFSPACE; 15878527Sassar } 15978527Sassar return 0; 16078527Sassar} 16178527Sassar 16278527Sassar/* 16355682Smarkm * Set `id' to the default keytab. 16455682Smarkm * Return 0 or an error. 16555682Smarkm */ 16655682Smarkm 16755682Smarkmkrb5_error_code 16855682Smarkmkrb5_kt_default(krb5_context context, krb5_keytab *id) 16955682Smarkm{ 17055682Smarkm return krb5_kt_resolve (context, context->default_keytab, id); 17155682Smarkm} 17255682Smarkm 17355682Smarkm/* 17455682Smarkm * Read the key identified by `(principal, vno, enctype)' from the 17555682Smarkm * keytab in `keyprocarg' (the default if == NULL) into `*key'. 17655682Smarkm * Return 0 or an error. 17755682Smarkm */ 17855682Smarkm 17955682Smarkmkrb5_error_code 18055682Smarkmkrb5_kt_read_service_key(krb5_context context, 18155682Smarkm krb5_pointer keyprocarg, 18255682Smarkm krb5_principal principal, 18355682Smarkm krb5_kvno vno, 18455682Smarkm krb5_enctype enctype, 18555682Smarkm krb5_keyblock **key) 18655682Smarkm{ 18755682Smarkm krb5_keytab keytab; 18855682Smarkm krb5_keytab_entry entry; 18955682Smarkm krb5_error_code ret; 19055682Smarkm 19155682Smarkm if (keyprocarg) 19255682Smarkm ret = krb5_kt_resolve (context, keyprocarg, &keytab); 19355682Smarkm else 19455682Smarkm ret = krb5_kt_default (context, &keytab); 19555682Smarkm 19655682Smarkm if (ret) 19755682Smarkm return ret; 19855682Smarkm 19955682Smarkm ret = krb5_kt_get_entry (context, keytab, principal, vno, enctype, &entry); 20055682Smarkm krb5_kt_close (context, keytab); 20155682Smarkm if (ret) 20255682Smarkm return ret; 20355682Smarkm ret = krb5_copy_keyblock (context, &entry.keyblock, key); 20455682Smarkm krb5_kt_free_entry(context, &entry); 20555682Smarkm return ret; 20655682Smarkm} 20755682Smarkm 20855682Smarkm/* 20955682Smarkm * Retrieve the name of the keytab `keytab' into `name', `namesize' 21055682Smarkm * Return 0 or an error. 21155682Smarkm */ 21255682Smarkm 21355682Smarkmkrb5_error_code 21455682Smarkmkrb5_kt_get_name(krb5_context context, 21555682Smarkm krb5_keytab keytab, 21655682Smarkm char *name, 21755682Smarkm size_t namesize) 21855682Smarkm{ 21955682Smarkm return (*keytab->get_name)(context, keytab, name, namesize); 22055682Smarkm} 22155682Smarkm 22255682Smarkm/* 22355682Smarkm * Finish using the keytab in `id'. All resources will be released. 22455682Smarkm * Return 0 or an error. 22555682Smarkm */ 22655682Smarkm 22755682Smarkmkrb5_error_code 22855682Smarkmkrb5_kt_close(krb5_context context, 22955682Smarkm krb5_keytab id) 23055682Smarkm{ 23155682Smarkm krb5_error_code ret; 23255682Smarkm 23355682Smarkm ret = (*id->close)(context, id); 23455682Smarkm if(ret == 0) 23555682Smarkm free(id); 23655682Smarkm return ret; 23755682Smarkm} 23855682Smarkm 23955682Smarkm/* 24055682Smarkm * Compare `entry' against `principal, vno, enctype'. 24155682Smarkm * Any of `principal, vno, enctype' might be 0 which acts as a wildcard. 24255682Smarkm * Return TRUE if they compare the same, FALSE otherwise. 24355682Smarkm */ 24455682Smarkm 24555682Smarkmkrb5_boolean 24655682Smarkmkrb5_kt_compare(krb5_context context, 24755682Smarkm krb5_keytab_entry *entry, 24855682Smarkm krb5_const_principal principal, 24955682Smarkm krb5_kvno vno, 25055682Smarkm krb5_enctype enctype) 25155682Smarkm{ 25255682Smarkm if(principal != NULL && 25355682Smarkm !krb5_principal_compare(context, entry->principal, principal)) 25455682Smarkm return FALSE; 25555682Smarkm if(vno && vno != entry->vno) 25655682Smarkm return FALSE; 25755682Smarkm if(enctype && enctype != entry->keyblock.keytype) 25855682Smarkm return FALSE; 25955682Smarkm return TRUE; 26055682Smarkm} 26155682Smarkm 26255682Smarkm/* 26355682Smarkm * Retrieve the keytab entry for `principal, kvno, enctype' into `entry' 26455682Smarkm * from the keytab `id'. 26555682Smarkm * Return 0 or an error. 26655682Smarkm */ 26755682Smarkm 26855682Smarkmkrb5_error_code 26955682Smarkmkrb5_kt_get_entry(krb5_context context, 27055682Smarkm krb5_keytab id, 27155682Smarkm krb5_const_principal principal, 27255682Smarkm krb5_kvno kvno, 27355682Smarkm krb5_enctype enctype, 27455682Smarkm krb5_keytab_entry *entry) 27555682Smarkm{ 27655682Smarkm krb5_keytab_entry tmp; 27755682Smarkm krb5_error_code ret; 27855682Smarkm krb5_kt_cursor cursor; 27955682Smarkm 28055682Smarkm if(id->get) 28155682Smarkm return (*id->get)(context, id, principal, kvno, enctype, entry); 28255682Smarkm 28355682Smarkm ret = krb5_kt_start_seq_get (context, id, &cursor); 28455682Smarkm if (ret) 28555682Smarkm return KRB5_KT_NOTFOUND; /* XXX i.e. file not found */ 28655682Smarkm 28755682Smarkm entry->vno = 0; 28855682Smarkm while (krb5_kt_next_entry(context, id, &tmp, &cursor) == 0) { 28955682Smarkm if (krb5_kt_compare(context, &tmp, principal, 0, enctype)) { 29055682Smarkm if (kvno == tmp.vno) { 29155682Smarkm krb5_kt_copy_entry_contents (context, &tmp, entry); 29255682Smarkm krb5_kt_free_entry (context, &tmp); 29355682Smarkm krb5_kt_end_seq_get(context, id, &cursor); 29455682Smarkm return 0; 29555682Smarkm } else if (kvno == 0 && tmp.vno > entry->vno) { 29655682Smarkm if (entry->vno) 29755682Smarkm krb5_kt_free_entry (context, entry); 29855682Smarkm krb5_kt_copy_entry_contents (context, &tmp, entry); 29955682Smarkm } 30055682Smarkm } 30155682Smarkm krb5_kt_free_entry(context, &tmp); 30255682Smarkm } 30355682Smarkm krb5_kt_end_seq_get (context, id, &cursor); 30478527Sassar if (entry->vno) { 30555682Smarkm return 0; 30678527Sassar } else { 30778527Sassar char princ[256], kt_name[256]; 30878527Sassar 30978527Sassar krb5_unparse_name_fixed (context, principal, princ, sizeof(princ)); 31078527Sassar krb5_kt_get_name (context, id, kt_name, sizeof(kt_name)); 31178527Sassar 31278527Sassar krb5_set_error_string (context, 31378527Sassar "failed to find %s in keytab %s", 31478527Sassar princ, kt_name); 31555682Smarkm return KRB5_KT_NOTFOUND; 31678527Sassar } 31755682Smarkm} 31855682Smarkm 31955682Smarkm/* 32055682Smarkm * Copy the contents of `in' into `out'. 32155682Smarkm * Return 0 or an error. 32255682Smarkm */ 32355682Smarkm 32455682Smarkmkrb5_error_code 32555682Smarkmkrb5_kt_copy_entry_contents(krb5_context context, 32655682Smarkm const krb5_keytab_entry *in, 32755682Smarkm krb5_keytab_entry *out) 32855682Smarkm{ 32955682Smarkm krb5_error_code ret; 33055682Smarkm 33155682Smarkm memset(out, 0, sizeof(*out)); 33255682Smarkm out->vno = in->vno; 33355682Smarkm 33455682Smarkm ret = krb5_copy_principal (context, in->principal, &out->principal); 33555682Smarkm if (ret) 33655682Smarkm goto fail; 33755682Smarkm ret = krb5_copy_keyblock_contents (context, 33855682Smarkm &in->keyblock, 33955682Smarkm &out->keyblock); 34055682Smarkm if (ret) 34155682Smarkm goto fail; 34255682Smarkm out->timestamp = in->timestamp; 34355682Smarkm return 0; 34455682Smarkmfail: 34555682Smarkm krb5_kt_free_entry (context, out); 34655682Smarkm return ret; 34755682Smarkm} 34855682Smarkm 34955682Smarkm/* 35055682Smarkm * Free the contents of `entry'. 35155682Smarkm */ 35255682Smarkm 35355682Smarkmkrb5_error_code 35455682Smarkmkrb5_kt_free_entry(krb5_context context, 35555682Smarkm krb5_keytab_entry *entry) 35655682Smarkm{ 35755682Smarkm krb5_free_principal (context, entry->principal); 35855682Smarkm krb5_free_keyblock_contents (context, &entry->keyblock); 35955682Smarkm return 0; 36055682Smarkm} 36155682Smarkm 36255682Smarkm#if 0 36355682Smarkmstatic int 36455682Smarkmxxxlock(int fd, int write) 36555682Smarkm{ 36655682Smarkm if(flock(fd, (write ? LOCK_EX : LOCK_SH) | LOCK_NB) < 0) { 36755682Smarkm sleep(1); 36855682Smarkm if(flock(fd, (write ? LOCK_EX : LOCK_SH) | LOCK_NB) < 0) 36955682Smarkm return -1; 37055682Smarkm } 37155682Smarkm return 0; 37255682Smarkm} 37355682Smarkm 37455682Smarkmstatic void 37555682Smarkmxxxunlock(int fd) 37655682Smarkm{ 37755682Smarkm flock(fd, LOCK_UN); 37855682Smarkm} 37955682Smarkm#endif 38055682Smarkm 38155682Smarkm/* 38255682Smarkm * Set `cursor' to point at the beginning of `id'. 38355682Smarkm * Return 0 or an error. 38455682Smarkm */ 38555682Smarkm 38655682Smarkmkrb5_error_code 38755682Smarkmkrb5_kt_start_seq_get(krb5_context context, 38855682Smarkm krb5_keytab id, 38955682Smarkm krb5_kt_cursor *cursor) 39055682Smarkm{ 39178527Sassar if(id->start_seq_get == NULL) { 39278527Sassar krb5_set_error_string(context, 39378527Sassar "start_seq_get is not supported in the %s " 39478527Sassar " keytab", id->prefix); 39555682Smarkm return HEIM_ERR_OPNOTSUPP; 39678527Sassar } 39755682Smarkm return (*id->start_seq_get)(context, id, cursor); 39855682Smarkm} 39955682Smarkm 40055682Smarkm/* 40155682Smarkm * Get the next entry from `id' pointed to by `cursor' and advance the 40255682Smarkm * `cursor'. 40355682Smarkm * Return 0 or an error. 40455682Smarkm */ 40555682Smarkm 40655682Smarkmkrb5_error_code 40755682Smarkmkrb5_kt_next_entry(krb5_context context, 40855682Smarkm krb5_keytab id, 40955682Smarkm krb5_keytab_entry *entry, 41055682Smarkm krb5_kt_cursor *cursor) 41155682Smarkm{ 41278527Sassar if(id->next_entry == NULL) { 41378527Sassar krb5_set_error_string(context, 41478527Sassar "next_entry is not supported in the %s " 41578527Sassar " keytab", id->prefix); 41655682Smarkm return HEIM_ERR_OPNOTSUPP; 41778527Sassar } 41855682Smarkm return (*id->next_entry)(context, id, entry, cursor); 41955682Smarkm} 42055682Smarkm 42155682Smarkm/* 42255682Smarkm * Release all resources associated with `cursor'. 42355682Smarkm */ 42455682Smarkm 42555682Smarkmkrb5_error_code 42655682Smarkmkrb5_kt_end_seq_get(krb5_context context, 42755682Smarkm krb5_keytab id, 42855682Smarkm krb5_kt_cursor *cursor) 42955682Smarkm{ 43078527Sassar if(id->end_seq_get == NULL) { 43178527Sassar krb5_set_error_string(context, 43278527Sassar "end_seq_get is not supported in the %s " 43378527Sassar " keytab", id->prefix); 43455682Smarkm return HEIM_ERR_OPNOTSUPP; 43578527Sassar } 43655682Smarkm return (*id->end_seq_get)(context, id, cursor); 43755682Smarkm} 43855682Smarkm 43955682Smarkm/* 44055682Smarkm * Add the entry in `entry' to the keytab `id'. 44155682Smarkm * Return 0 or an error. 44255682Smarkm */ 44355682Smarkm 44455682Smarkmkrb5_error_code 44555682Smarkmkrb5_kt_add_entry(krb5_context context, 44655682Smarkm krb5_keytab id, 44755682Smarkm krb5_keytab_entry *entry) 44855682Smarkm{ 44978527Sassar if(id->add == NULL) { 45078527Sassar krb5_set_error_string(context, "Add is not supported in the %s keytab", 45178527Sassar id->prefix); 45255682Smarkm return KRB5_KT_NOWRITE; 45378527Sassar } 45457416Smarkm entry->timestamp = time(NULL); 45555682Smarkm return (*id->add)(context, id,entry); 45655682Smarkm} 45755682Smarkm 45855682Smarkm/* 45955682Smarkm * Remove the entry `entry' from the keytab `id'. 46055682Smarkm * Return 0 or an error. 46155682Smarkm */ 46255682Smarkm 46355682Smarkmkrb5_error_code 46455682Smarkmkrb5_kt_remove_entry(krb5_context context, 46555682Smarkm krb5_keytab id, 46655682Smarkm krb5_keytab_entry *entry) 46755682Smarkm{ 46878527Sassar if(id->remove == NULL) { 46978527Sassar krb5_set_error_string(context, 47078527Sassar "Remove is not supported in the %s keytab", 47178527Sassar id->prefix); 47255682Smarkm return KRB5_KT_NOWRITE; 47378527Sassar } 47455682Smarkm return (*id->remove)(context, id, entry); 47555682Smarkm} 476