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