keytab.c revision 55682
155682Smarkm/* 255682Smarkm * Copyright (c) 1997, 1998, 1999 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 3655682SmarkmRCSID("$Id: keytab.c,v 1.45 2000/01/02 00:31:20 assar 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)); 5155682Smarkm if(tmp == NULL) 5255682Smarkm return ENOMEM; 5355682Smarkm memcpy(&tmp[context->num_kt_types], ops, 5455682Smarkm sizeof(tmp[context->num_kt_types])); 5555682Smarkm context->kt_types = tmp; 5655682Smarkm context->num_kt_types++; 5755682Smarkm return 0; 5855682Smarkm} 5955682Smarkm 6055682Smarkm/* 6155682Smarkm * Resolve the keytab name (of the form `type:residual') in `name' 6255682Smarkm * into a keytab in `id'. 6355682Smarkm * Return 0 or an error 6455682Smarkm */ 6555682Smarkm 6655682Smarkmkrb5_error_code 6755682Smarkmkrb5_kt_resolve(krb5_context context, 6855682Smarkm const char *name, 6955682Smarkm krb5_keytab *id) 7055682Smarkm{ 7155682Smarkm krb5_keytab k; 7255682Smarkm int i; 7355682Smarkm const char *type, *residual; 7455682Smarkm size_t type_len; 7555682Smarkm krb5_error_code ret; 7655682Smarkm 7755682Smarkm residual = strchr(name, ':'); 7855682Smarkm if(residual == NULL) { 7955682Smarkm type = "FILE"; 8055682Smarkm type_len = strlen(type); 8155682Smarkm residual = name; 8255682Smarkm } else { 8355682Smarkm type = name; 8455682Smarkm type_len = residual - name; 8555682Smarkm residual++; 8655682Smarkm } 8755682Smarkm 8855682Smarkm for(i = 0; i < context->num_kt_types; i++) { 8955682Smarkm if(strncmp(type, context->kt_types[i].prefix, type_len) == 0) 9055682Smarkm break; 9155682Smarkm } 9255682Smarkm if(i == context->num_kt_types) 9355682Smarkm return KRB5_KT_UNKNOWN_TYPE; 9455682Smarkm 9555682Smarkm k = malloc (sizeof(*k)); 9655682Smarkm if (k == NULL) 9755682Smarkm return ENOMEM; 9855682Smarkm memcpy(k, &context->kt_types[i], sizeof(*k)); 9955682Smarkm k->data = NULL; 10055682Smarkm ret = (*k->resolve)(context, residual, k); 10155682Smarkm if(ret) { 10255682Smarkm free(k); 10355682Smarkm k = NULL; 10455682Smarkm } 10555682Smarkm *id = k; 10655682Smarkm return ret; 10755682Smarkm} 10855682Smarkm 10955682Smarkm/* 11055682Smarkm * copy the name of the default keytab into `name'. 11155682Smarkm * Return 0 or KRB5_CONFIG_NOTENUFSPACE if `namesize' is too short. 11255682Smarkm */ 11355682Smarkm 11455682Smarkmkrb5_error_code 11555682Smarkmkrb5_kt_default_name(krb5_context context, char *name, size_t namesize) 11655682Smarkm{ 11755682Smarkm strncpy(name, context->default_keytab, namesize); 11855682Smarkm if(strlen(context->default_keytab) >= namesize) 11955682Smarkm return KRB5_CONFIG_NOTENUFSPACE; 12055682Smarkm return 0; 12155682Smarkm} 12255682Smarkm 12355682Smarkm/* 12455682Smarkm * Set `id' to the default keytab. 12555682Smarkm * Return 0 or an error. 12655682Smarkm */ 12755682Smarkm 12855682Smarkmkrb5_error_code 12955682Smarkmkrb5_kt_default(krb5_context context, krb5_keytab *id) 13055682Smarkm{ 13155682Smarkm return krb5_kt_resolve (context, context->default_keytab, id); 13255682Smarkm} 13355682Smarkm 13455682Smarkm/* 13555682Smarkm * Read the key identified by `(principal, vno, enctype)' from the 13655682Smarkm * keytab in `keyprocarg' (the default if == NULL) into `*key'. 13755682Smarkm * Return 0 or an error. 13855682Smarkm */ 13955682Smarkm 14055682Smarkmkrb5_error_code 14155682Smarkmkrb5_kt_read_service_key(krb5_context context, 14255682Smarkm krb5_pointer keyprocarg, 14355682Smarkm krb5_principal principal, 14455682Smarkm krb5_kvno vno, 14555682Smarkm krb5_enctype enctype, 14655682Smarkm krb5_keyblock **key) 14755682Smarkm{ 14855682Smarkm krb5_keytab keytab; 14955682Smarkm krb5_keytab_entry entry; 15055682Smarkm krb5_error_code ret; 15155682Smarkm 15255682Smarkm if (keyprocarg) 15355682Smarkm ret = krb5_kt_resolve (context, keyprocarg, &keytab); 15455682Smarkm else 15555682Smarkm ret = krb5_kt_default (context, &keytab); 15655682Smarkm 15755682Smarkm if (ret) 15855682Smarkm return ret; 15955682Smarkm 16055682Smarkm ret = krb5_kt_get_entry (context, keytab, principal, vno, enctype, &entry); 16155682Smarkm krb5_kt_close (context, keytab); 16255682Smarkm if (ret) 16355682Smarkm return ret; 16455682Smarkm ret = krb5_copy_keyblock (context, &entry.keyblock, key); 16555682Smarkm krb5_kt_free_entry(context, &entry); 16655682Smarkm return ret; 16755682Smarkm} 16855682Smarkm 16955682Smarkm/* 17055682Smarkm * Retrieve the name of the keytab `keytab' into `name', `namesize' 17155682Smarkm * Return 0 or an error. 17255682Smarkm */ 17355682Smarkm 17455682Smarkmkrb5_error_code 17555682Smarkmkrb5_kt_get_name(krb5_context context, 17655682Smarkm krb5_keytab keytab, 17755682Smarkm char *name, 17855682Smarkm size_t namesize) 17955682Smarkm{ 18055682Smarkm return (*keytab->get_name)(context, keytab, name, namesize); 18155682Smarkm} 18255682Smarkm 18355682Smarkm/* 18455682Smarkm * Finish using the keytab in `id'. All resources will be released. 18555682Smarkm * Return 0 or an error. 18655682Smarkm */ 18755682Smarkm 18855682Smarkmkrb5_error_code 18955682Smarkmkrb5_kt_close(krb5_context context, 19055682Smarkm krb5_keytab id) 19155682Smarkm{ 19255682Smarkm krb5_error_code ret; 19355682Smarkm 19455682Smarkm ret = (*id->close)(context, id); 19555682Smarkm if(ret == 0) 19655682Smarkm free(id); 19755682Smarkm return ret; 19855682Smarkm} 19955682Smarkm 20055682Smarkm/* 20155682Smarkm * Compare `entry' against `principal, vno, enctype'. 20255682Smarkm * Any of `principal, vno, enctype' might be 0 which acts as a wildcard. 20355682Smarkm * Return TRUE if they compare the same, FALSE otherwise. 20455682Smarkm */ 20555682Smarkm 20655682Smarkmkrb5_boolean 20755682Smarkmkrb5_kt_compare(krb5_context context, 20855682Smarkm krb5_keytab_entry *entry, 20955682Smarkm krb5_const_principal principal, 21055682Smarkm krb5_kvno vno, 21155682Smarkm krb5_enctype enctype) 21255682Smarkm{ 21355682Smarkm if(principal != NULL && 21455682Smarkm !krb5_principal_compare(context, entry->principal, principal)) 21555682Smarkm return FALSE; 21655682Smarkm if(vno && vno != entry->vno) 21755682Smarkm return FALSE; 21855682Smarkm if(enctype && enctype != entry->keyblock.keytype) 21955682Smarkm return FALSE; 22055682Smarkm return TRUE; 22155682Smarkm} 22255682Smarkm 22355682Smarkm/* 22455682Smarkm * Retrieve the keytab entry for `principal, kvno, enctype' into `entry' 22555682Smarkm * from the keytab `id'. 22655682Smarkm * Return 0 or an error. 22755682Smarkm */ 22855682Smarkm 22955682Smarkmkrb5_error_code 23055682Smarkmkrb5_kt_get_entry(krb5_context context, 23155682Smarkm krb5_keytab id, 23255682Smarkm krb5_const_principal principal, 23355682Smarkm krb5_kvno kvno, 23455682Smarkm krb5_enctype enctype, 23555682Smarkm krb5_keytab_entry *entry) 23655682Smarkm{ 23755682Smarkm krb5_keytab_entry tmp; 23855682Smarkm krb5_error_code ret; 23955682Smarkm krb5_kt_cursor cursor; 24055682Smarkm 24155682Smarkm if(id->get) 24255682Smarkm return (*id->get)(context, id, principal, kvno, enctype, entry); 24355682Smarkm 24455682Smarkm ret = krb5_kt_start_seq_get (context, id, &cursor); 24555682Smarkm if (ret) 24655682Smarkm return KRB5_KT_NOTFOUND; /* XXX i.e. file not found */ 24755682Smarkm 24855682Smarkm entry->vno = 0; 24955682Smarkm while (krb5_kt_next_entry(context, id, &tmp, &cursor) == 0) { 25055682Smarkm if (krb5_kt_compare(context, &tmp, principal, 0, enctype)) { 25155682Smarkm if (kvno == tmp.vno) { 25255682Smarkm krb5_kt_copy_entry_contents (context, &tmp, entry); 25355682Smarkm krb5_kt_free_entry (context, &tmp); 25455682Smarkm krb5_kt_end_seq_get(context, id, &cursor); 25555682Smarkm return 0; 25655682Smarkm } else if (kvno == 0 && tmp.vno > entry->vno) { 25755682Smarkm if (entry->vno) 25855682Smarkm krb5_kt_free_entry (context, entry); 25955682Smarkm krb5_kt_copy_entry_contents (context, &tmp, entry); 26055682Smarkm } 26155682Smarkm } 26255682Smarkm krb5_kt_free_entry(context, &tmp); 26355682Smarkm } 26455682Smarkm krb5_kt_end_seq_get (context, id, &cursor); 26555682Smarkm if (entry->vno) 26655682Smarkm return 0; 26755682Smarkm else 26855682Smarkm return KRB5_KT_NOTFOUND; 26955682Smarkm} 27055682Smarkm 27155682Smarkm/* 27255682Smarkm * Copy the contents of `in' into `out'. 27355682Smarkm * Return 0 or an error. 27455682Smarkm */ 27555682Smarkm 27655682Smarkmkrb5_error_code 27755682Smarkmkrb5_kt_copy_entry_contents(krb5_context context, 27855682Smarkm const krb5_keytab_entry *in, 27955682Smarkm krb5_keytab_entry *out) 28055682Smarkm{ 28155682Smarkm krb5_error_code ret; 28255682Smarkm 28355682Smarkm memset(out, 0, sizeof(*out)); 28455682Smarkm out->vno = in->vno; 28555682Smarkm 28655682Smarkm ret = krb5_copy_principal (context, in->principal, &out->principal); 28755682Smarkm if (ret) 28855682Smarkm goto fail; 28955682Smarkm ret = krb5_copy_keyblock_contents (context, 29055682Smarkm &in->keyblock, 29155682Smarkm &out->keyblock); 29255682Smarkm if (ret) 29355682Smarkm goto fail; 29455682Smarkm out->timestamp = in->timestamp; 29555682Smarkm return 0; 29655682Smarkmfail: 29755682Smarkm krb5_kt_free_entry (context, out); 29855682Smarkm return ret; 29955682Smarkm} 30055682Smarkm 30155682Smarkm/* 30255682Smarkm * Free the contents of `entry'. 30355682Smarkm */ 30455682Smarkm 30555682Smarkmkrb5_error_code 30655682Smarkmkrb5_kt_free_entry(krb5_context context, 30755682Smarkm krb5_keytab_entry *entry) 30855682Smarkm{ 30955682Smarkm krb5_free_principal (context, entry->principal); 31055682Smarkm krb5_free_keyblock_contents (context, &entry->keyblock); 31155682Smarkm return 0; 31255682Smarkm} 31355682Smarkm 31455682Smarkm#if 0 31555682Smarkmstatic int 31655682Smarkmxxxlock(int fd, int write) 31755682Smarkm{ 31855682Smarkm if(flock(fd, (write ? LOCK_EX : LOCK_SH) | LOCK_NB) < 0) { 31955682Smarkm sleep(1); 32055682Smarkm if(flock(fd, (write ? LOCK_EX : LOCK_SH) | LOCK_NB) < 0) 32155682Smarkm return -1; 32255682Smarkm } 32355682Smarkm return 0; 32455682Smarkm} 32555682Smarkm 32655682Smarkmstatic void 32755682Smarkmxxxunlock(int fd) 32855682Smarkm{ 32955682Smarkm flock(fd, LOCK_UN); 33055682Smarkm} 33155682Smarkm#endif 33255682Smarkm 33355682Smarkm/* 33455682Smarkm * Set `cursor' to point at the beginning of `id'. 33555682Smarkm * Return 0 or an error. 33655682Smarkm */ 33755682Smarkm 33855682Smarkmkrb5_error_code 33955682Smarkmkrb5_kt_start_seq_get(krb5_context context, 34055682Smarkm krb5_keytab id, 34155682Smarkm krb5_kt_cursor *cursor) 34255682Smarkm{ 34355682Smarkm if(id->start_seq_get == NULL) 34455682Smarkm return HEIM_ERR_OPNOTSUPP; 34555682Smarkm return (*id->start_seq_get)(context, id, cursor); 34655682Smarkm} 34755682Smarkm 34855682Smarkm/* 34955682Smarkm * Get the next entry from `id' pointed to by `cursor' and advance the 35055682Smarkm * `cursor'. 35155682Smarkm * Return 0 or an error. 35255682Smarkm */ 35355682Smarkm 35455682Smarkmkrb5_error_code 35555682Smarkmkrb5_kt_next_entry(krb5_context context, 35655682Smarkm krb5_keytab id, 35755682Smarkm krb5_keytab_entry *entry, 35855682Smarkm krb5_kt_cursor *cursor) 35955682Smarkm{ 36055682Smarkm if(id->next_entry == NULL) 36155682Smarkm return HEIM_ERR_OPNOTSUPP; 36255682Smarkm return (*id->next_entry)(context, id, entry, cursor); 36355682Smarkm} 36455682Smarkm 36555682Smarkm/* 36655682Smarkm * Release all resources associated with `cursor'. 36755682Smarkm */ 36855682Smarkm 36955682Smarkmkrb5_error_code 37055682Smarkmkrb5_kt_end_seq_get(krb5_context context, 37155682Smarkm krb5_keytab id, 37255682Smarkm krb5_kt_cursor *cursor) 37355682Smarkm{ 37455682Smarkm if(id->end_seq_get == NULL) 37555682Smarkm return HEIM_ERR_OPNOTSUPP; 37655682Smarkm return (*id->end_seq_get)(context, id, cursor); 37755682Smarkm} 37855682Smarkm 37955682Smarkm/* 38055682Smarkm * Add the entry in `entry' to the keytab `id'. 38155682Smarkm * Return 0 or an error. 38255682Smarkm */ 38355682Smarkm 38455682Smarkmkrb5_error_code 38555682Smarkmkrb5_kt_add_entry(krb5_context context, 38655682Smarkm krb5_keytab id, 38755682Smarkm krb5_keytab_entry *entry) 38855682Smarkm{ 38955682Smarkm if(id->add == NULL) 39055682Smarkm return KRB5_KT_NOWRITE; 39155682Smarkm return (*id->add)(context, id,entry); 39255682Smarkm} 39355682Smarkm 39455682Smarkm/* 39555682Smarkm * Remove the entry `entry' from the keytab `id'. 39655682Smarkm * Return 0 or an error. 39755682Smarkm */ 39855682Smarkm 39955682Smarkmkrb5_error_code 40055682Smarkmkrb5_kt_remove_entry(krb5_context context, 40155682Smarkm krb5_keytab id, 40255682Smarkm krb5_keytab_entry *entry) 40355682Smarkm{ 40455682Smarkm if(id->remove == NULL) 40555682Smarkm return KRB5_KT_NOWRITE; 40655682Smarkm return (*id->remove)(context, id, entry); 40755682Smarkm} 408