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