keytab.c revision 57416
155682Smarkm/* 257416Smarkm * Copyright (c) 1997 - 2000 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 3657416SmarkmRCSID("$Id: keytab.c,v 1.46 2000/02/07 03:18:05 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{ 11757416Smarkm if (strlcpy (name, context->default_keytab, namesize) >= namesize) 11855682Smarkm return KRB5_CONFIG_NOTENUFSPACE; 11955682Smarkm return 0; 12055682Smarkm} 12155682Smarkm 12255682Smarkm/* 12355682Smarkm * Set `id' to the default keytab. 12455682Smarkm * Return 0 or an error. 12555682Smarkm */ 12655682Smarkm 12755682Smarkmkrb5_error_code 12855682Smarkmkrb5_kt_default(krb5_context context, krb5_keytab *id) 12955682Smarkm{ 13055682Smarkm return krb5_kt_resolve (context, context->default_keytab, id); 13155682Smarkm} 13255682Smarkm 13355682Smarkm/* 13455682Smarkm * Read the key identified by `(principal, vno, enctype)' from the 13555682Smarkm * keytab in `keyprocarg' (the default if == NULL) into `*key'. 13655682Smarkm * Return 0 or an error. 13755682Smarkm */ 13855682Smarkm 13955682Smarkmkrb5_error_code 14055682Smarkmkrb5_kt_read_service_key(krb5_context context, 14155682Smarkm krb5_pointer keyprocarg, 14255682Smarkm krb5_principal principal, 14355682Smarkm krb5_kvno vno, 14455682Smarkm krb5_enctype enctype, 14555682Smarkm krb5_keyblock **key) 14655682Smarkm{ 14755682Smarkm krb5_keytab keytab; 14855682Smarkm krb5_keytab_entry entry; 14955682Smarkm krb5_error_code ret; 15055682Smarkm 15155682Smarkm if (keyprocarg) 15255682Smarkm ret = krb5_kt_resolve (context, keyprocarg, &keytab); 15355682Smarkm else 15455682Smarkm ret = krb5_kt_default (context, &keytab); 15555682Smarkm 15655682Smarkm if (ret) 15755682Smarkm return ret; 15855682Smarkm 15955682Smarkm ret = krb5_kt_get_entry (context, keytab, principal, vno, enctype, &entry); 16055682Smarkm krb5_kt_close (context, keytab); 16155682Smarkm if (ret) 16255682Smarkm return ret; 16355682Smarkm ret = krb5_copy_keyblock (context, &entry.keyblock, key); 16455682Smarkm krb5_kt_free_entry(context, &entry); 16555682Smarkm return ret; 16655682Smarkm} 16755682Smarkm 16855682Smarkm/* 16955682Smarkm * Retrieve the name of the keytab `keytab' into `name', `namesize' 17055682Smarkm * Return 0 or an error. 17155682Smarkm */ 17255682Smarkm 17355682Smarkmkrb5_error_code 17455682Smarkmkrb5_kt_get_name(krb5_context context, 17555682Smarkm krb5_keytab keytab, 17655682Smarkm char *name, 17755682Smarkm size_t namesize) 17855682Smarkm{ 17955682Smarkm return (*keytab->get_name)(context, keytab, name, namesize); 18055682Smarkm} 18155682Smarkm 18255682Smarkm/* 18355682Smarkm * Finish using the keytab in `id'. All resources will be released. 18455682Smarkm * Return 0 or an error. 18555682Smarkm */ 18655682Smarkm 18755682Smarkmkrb5_error_code 18855682Smarkmkrb5_kt_close(krb5_context context, 18955682Smarkm krb5_keytab id) 19055682Smarkm{ 19155682Smarkm krb5_error_code ret; 19255682Smarkm 19355682Smarkm ret = (*id->close)(context, id); 19455682Smarkm if(ret == 0) 19555682Smarkm free(id); 19655682Smarkm return ret; 19755682Smarkm} 19855682Smarkm 19955682Smarkm/* 20055682Smarkm * Compare `entry' against `principal, vno, enctype'. 20155682Smarkm * Any of `principal, vno, enctype' might be 0 which acts as a wildcard. 20255682Smarkm * Return TRUE if they compare the same, FALSE otherwise. 20355682Smarkm */ 20455682Smarkm 20555682Smarkmkrb5_boolean 20655682Smarkmkrb5_kt_compare(krb5_context context, 20755682Smarkm krb5_keytab_entry *entry, 20855682Smarkm krb5_const_principal principal, 20955682Smarkm krb5_kvno vno, 21055682Smarkm krb5_enctype enctype) 21155682Smarkm{ 21255682Smarkm if(principal != NULL && 21355682Smarkm !krb5_principal_compare(context, entry->principal, principal)) 21455682Smarkm return FALSE; 21555682Smarkm if(vno && vno != entry->vno) 21655682Smarkm return FALSE; 21755682Smarkm if(enctype && enctype != entry->keyblock.keytype) 21855682Smarkm return FALSE; 21955682Smarkm return TRUE; 22055682Smarkm} 22155682Smarkm 22255682Smarkm/* 22355682Smarkm * Retrieve the keytab entry for `principal, kvno, enctype' into `entry' 22455682Smarkm * from the keytab `id'. 22555682Smarkm * Return 0 or an error. 22655682Smarkm */ 22755682Smarkm 22855682Smarkmkrb5_error_code 22955682Smarkmkrb5_kt_get_entry(krb5_context context, 23055682Smarkm krb5_keytab id, 23155682Smarkm krb5_const_principal principal, 23255682Smarkm krb5_kvno kvno, 23355682Smarkm krb5_enctype enctype, 23455682Smarkm krb5_keytab_entry *entry) 23555682Smarkm{ 23655682Smarkm krb5_keytab_entry tmp; 23755682Smarkm krb5_error_code ret; 23855682Smarkm krb5_kt_cursor cursor; 23955682Smarkm 24055682Smarkm if(id->get) 24155682Smarkm return (*id->get)(context, id, principal, kvno, enctype, entry); 24255682Smarkm 24355682Smarkm ret = krb5_kt_start_seq_get (context, id, &cursor); 24455682Smarkm if (ret) 24555682Smarkm return KRB5_KT_NOTFOUND; /* XXX i.e. file not found */ 24655682Smarkm 24755682Smarkm entry->vno = 0; 24855682Smarkm while (krb5_kt_next_entry(context, id, &tmp, &cursor) == 0) { 24955682Smarkm if (krb5_kt_compare(context, &tmp, principal, 0, enctype)) { 25055682Smarkm if (kvno == tmp.vno) { 25155682Smarkm krb5_kt_copy_entry_contents (context, &tmp, entry); 25255682Smarkm krb5_kt_free_entry (context, &tmp); 25355682Smarkm krb5_kt_end_seq_get(context, id, &cursor); 25455682Smarkm return 0; 25555682Smarkm } else if (kvno == 0 && tmp.vno > entry->vno) { 25655682Smarkm if (entry->vno) 25755682Smarkm krb5_kt_free_entry (context, entry); 25855682Smarkm krb5_kt_copy_entry_contents (context, &tmp, entry); 25955682Smarkm } 26055682Smarkm } 26155682Smarkm krb5_kt_free_entry(context, &tmp); 26255682Smarkm } 26355682Smarkm krb5_kt_end_seq_get (context, id, &cursor); 26455682Smarkm if (entry->vno) 26555682Smarkm return 0; 26655682Smarkm else 26755682Smarkm return KRB5_KT_NOTFOUND; 26855682Smarkm} 26955682Smarkm 27055682Smarkm/* 27155682Smarkm * Copy the contents of `in' into `out'. 27255682Smarkm * Return 0 or an error. 27355682Smarkm */ 27455682Smarkm 27555682Smarkmkrb5_error_code 27655682Smarkmkrb5_kt_copy_entry_contents(krb5_context context, 27755682Smarkm const krb5_keytab_entry *in, 27855682Smarkm krb5_keytab_entry *out) 27955682Smarkm{ 28055682Smarkm krb5_error_code ret; 28155682Smarkm 28255682Smarkm memset(out, 0, sizeof(*out)); 28355682Smarkm out->vno = in->vno; 28455682Smarkm 28555682Smarkm ret = krb5_copy_principal (context, in->principal, &out->principal); 28655682Smarkm if (ret) 28755682Smarkm goto fail; 28855682Smarkm ret = krb5_copy_keyblock_contents (context, 28955682Smarkm &in->keyblock, 29055682Smarkm &out->keyblock); 29155682Smarkm if (ret) 29255682Smarkm goto fail; 29355682Smarkm out->timestamp = in->timestamp; 29455682Smarkm return 0; 29555682Smarkmfail: 29655682Smarkm krb5_kt_free_entry (context, out); 29755682Smarkm return ret; 29855682Smarkm} 29955682Smarkm 30055682Smarkm/* 30155682Smarkm * Free the contents of `entry'. 30255682Smarkm */ 30355682Smarkm 30455682Smarkmkrb5_error_code 30555682Smarkmkrb5_kt_free_entry(krb5_context context, 30655682Smarkm krb5_keytab_entry *entry) 30755682Smarkm{ 30855682Smarkm krb5_free_principal (context, entry->principal); 30955682Smarkm krb5_free_keyblock_contents (context, &entry->keyblock); 31055682Smarkm return 0; 31155682Smarkm} 31255682Smarkm 31355682Smarkm#if 0 31455682Smarkmstatic int 31555682Smarkmxxxlock(int fd, int write) 31655682Smarkm{ 31755682Smarkm if(flock(fd, (write ? LOCK_EX : LOCK_SH) | LOCK_NB) < 0) { 31855682Smarkm sleep(1); 31955682Smarkm if(flock(fd, (write ? LOCK_EX : LOCK_SH) | LOCK_NB) < 0) 32055682Smarkm return -1; 32155682Smarkm } 32255682Smarkm return 0; 32355682Smarkm} 32455682Smarkm 32555682Smarkmstatic void 32655682Smarkmxxxunlock(int fd) 32755682Smarkm{ 32855682Smarkm flock(fd, LOCK_UN); 32955682Smarkm} 33055682Smarkm#endif 33155682Smarkm 33255682Smarkm/* 33355682Smarkm * Set `cursor' to point at the beginning of `id'. 33455682Smarkm * Return 0 or an error. 33555682Smarkm */ 33655682Smarkm 33755682Smarkmkrb5_error_code 33855682Smarkmkrb5_kt_start_seq_get(krb5_context context, 33955682Smarkm krb5_keytab id, 34055682Smarkm krb5_kt_cursor *cursor) 34155682Smarkm{ 34255682Smarkm if(id->start_seq_get == NULL) 34355682Smarkm return HEIM_ERR_OPNOTSUPP; 34455682Smarkm return (*id->start_seq_get)(context, id, cursor); 34555682Smarkm} 34655682Smarkm 34755682Smarkm/* 34855682Smarkm * Get the next entry from `id' pointed to by `cursor' and advance the 34955682Smarkm * `cursor'. 35055682Smarkm * Return 0 or an error. 35155682Smarkm */ 35255682Smarkm 35355682Smarkmkrb5_error_code 35455682Smarkmkrb5_kt_next_entry(krb5_context context, 35555682Smarkm krb5_keytab id, 35655682Smarkm krb5_keytab_entry *entry, 35755682Smarkm krb5_kt_cursor *cursor) 35855682Smarkm{ 35955682Smarkm if(id->next_entry == NULL) 36055682Smarkm return HEIM_ERR_OPNOTSUPP; 36155682Smarkm return (*id->next_entry)(context, id, entry, cursor); 36255682Smarkm} 36355682Smarkm 36455682Smarkm/* 36555682Smarkm * Release all resources associated with `cursor'. 36655682Smarkm */ 36755682Smarkm 36855682Smarkmkrb5_error_code 36955682Smarkmkrb5_kt_end_seq_get(krb5_context context, 37055682Smarkm krb5_keytab id, 37155682Smarkm krb5_kt_cursor *cursor) 37255682Smarkm{ 37355682Smarkm if(id->end_seq_get == NULL) 37455682Smarkm return HEIM_ERR_OPNOTSUPP; 37555682Smarkm return (*id->end_seq_get)(context, id, cursor); 37655682Smarkm} 37755682Smarkm 37855682Smarkm/* 37955682Smarkm * Add the entry in `entry' to the keytab `id'. 38055682Smarkm * Return 0 or an error. 38155682Smarkm */ 38255682Smarkm 38355682Smarkmkrb5_error_code 38455682Smarkmkrb5_kt_add_entry(krb5_context context, 38555682Smarkm krb5_keytab id, 38655682Smarkm krb5_keytab_entry *entry) 38755682Smarkm{ 38855682Smarkm if(id->add == NULL) 38955682Smarkm return KRB5_KT_NOWRITE; 39057416Smarkm entry->timestamp = time(NULL); 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