144743Smarkm/*
244743Smarkm * Copyright (c) 2001-2002 Kungliga Tekniska H��gskolan
344743Smarkm * (Royal Institute of Technology, Stockholm, Sweden).
444743Smarkm * All rights reserved.
544743Smarkm *
644743Smarkm * Redistribution and use in source and binary forms, with or without
744743Smarkm * modification, are permitted provided that the following conditions
844743Smarkm * are met:
944743Smarkm *
1044743Smarkm * 1. Redistributions of source code must retain the above copyright
1144743Smarkm *    notice, this list of conditions and the following disclaimer.
1244743Smarkm *
1344743Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1444743Smarkm *    notice, this list of conditions and the following disclaimer in the
1544743Smarkm *    documentation and/or other materials provided with the distribution.
1656977Sshin *
1756977Sshin * 3. Neither the name of the Institute nor the names of its contributors
1844743Smarkm *    may be used to endorse or promote products derived from this software
1944743Smarkm *    without specific prior written permission.
2044743Smarkm *
2144743Smarkm * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
2244743Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2344743Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2444743Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
2544743Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2644743Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2744743Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2844743Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2944743Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3044743Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3144743Smarkm * SUCH DAMAGE.
3244743Smarkm */
3344743Smarkm
3444743Smarkm#include "krb5_locl.h"
35146187Sume
3663158Sumestruct any_data {
3756977Sshin    krb5_keytab kt;
3856977Sshin    char *name;
3944743Smarkm    struct any_data *next;
4044743Smarkm};
4144743Smarkm
4244743Smarkmstatic void
4344743Smarkmfree_list (krb5_context context, struct any_data *a)
4444743Smarkm{
4544743Smarkm    struct any_data *next;
4644743Smarkm
4744743Smarkm    for (; a != NULL; a = next) {
4844743Smarkm	next = a->next;
4944743Smarkm	free (a->name);
5044743Smarkm	if(a->kt)
5144743Smarkm	    krb5_kt_close(context, a->kt);
5244743Smarkm	free (a);
5344743Smarkm    }
5444743Smarkm}
5544743Smarkm
5644743Smarkmstatic krb5_error_code KRB5_CALLCONV
5744743Smarkmany_resolve(krb5_context context, const char *name, krb5_keytab id)
5844743Smarkm{
5944743Smarkm    struct any_data *a, *a0 = NULL, *prev = NULL;
6044743Smarkm    krb5_error_code ret;
6144743Smarkm    char buf[256];
6244743Smarkm
6344743Smarkm    while (strsep_copy(&name, ",", buf, sizeof(buf)) != -1) {
6444743Smarkm	a = calloc(1, sizeof(*a));
6544743Smarkm	if (a == NULL) {
6644743Smarkm	    ret = ENOMEM;
6744743Smarkm	    goto fail;
6844743Smarkm	}
6944743Smarkm	if (a0 == NULL) {
7044743Smarkm	    a0 = a;
7144743Smarkm	    a->name = strdup(buf);
7244743Smarkm	    if (a->name == NULL) {
7344743Smarkm		ret = ENOMEM;
7444743Smarkm		krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
7544743Smarkm		goto fail;
7644743Smarkm	    }
7744743Smarkm	} else
7844743Smarkm	    a->name = NULL;
7944743Smarkm	if (prev != NULL)
8044743Smarkm	    prev->next = a;
8156977Sshin	a->next = NULL;
8256977Sshin	ret = krb5_kt_resolve (context, buf, &a->kt);
8356977Sshin	if (ret)
8456977Sshin	    goto fail;
8544743Smarkm	prev = a;
8644743Smarkm    }
8756977Sshin    if (a0 == NULL) {
8844743Smarkm	krb5_set_error_message(context, ENOENT, N_("empty ANY: keytab", ""));
8944743Smarkm	return ENOENT;
9044743Smarkm    }
9144743Smarkm    id->data = a0;
9244743Smarkm    return 0;
9344743Smarkm fail:
9444743Smarkm    free_list (context, a0);
9544743Smarkm    return ret;
9644743Smarkm}
9744743Smarkm
9844743Smarkmstatic krb5_error_code KRB5_CALLCONV
9944743Smarkmany_get_name (krb5_context context,
10044743Smarkm	      krb5_keytab id,
10144743Smarkm	      char *name,
10244743Smarkm	      size_t namesize)
10344743Smarkm{
10444743Smarkm    struct any_data *a = id->data;
10544743Smarkm    strlcpy(name, a->name, namesize);
10644743Smarkm    return 0;
10744743Smarkm}
10844743Smarkm
10944743Smarkmstatic krb5_error_code KRB5_CALLCONV
11044743Smarkmany_close (krb5_context context,
11144743Smarkm	   krb5_keytab id)
11244743Smarkm{
113123895Sceri    struct any_data *a = id->data;
11444743Smarkm
11544743Smarkm    free_list (context, a);
11656977Sshin    return 0;
11756977Sshin}
11856977Sshin
11944743Smarkmstruct any_cursor_extra_data {
12056977Sshin    struct any_data *a;
12144743Smarkm    krb5_kt_cursor cursor;
12244743Smarkm};
12344743Smarkm
12444743Smarkmstatic krb5_error_code KRB5_CALLCONV
12544743Smarkmany_start_seq_get(krb5_context context,
12644743Smarkm		  krb5_keytab id,
12744743Smarkm		  krb5_kt_cursor *c)
12844743Smarkm{
12944743Smarkm    struct any_data *a = id->data;
13044743Smarkm    struct any_cursor_extra_data *ed;
13144743Smarkm    krb5_error_code ret;
13244743Smarkm
13356977Sshin    c->data = malloc (sizeof(struct any_cursor_extra_data));
13456977Sshin    if(c->data == NULL){
13556977Sshin	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
13644743Smarkm	return ENOMEM;
13756977Sshin    }
13844743Smarkm    ed = (struct any_cursor_extra_data *)c->data;
13944743Smarkm    for (ed->a = a; ed->a != NULL; ed->a = ed->a->next) {
14044743Smarkm	ret = krb5_kt_start_seq_get(context, ed->a->kt, &ed->cursor);
14144743Smarkm	if (ret == 0)
14244743Smarkm	    break;
14344743Smarkm    }
14444743Smarkm    if (ed->a == NULL) {
14556977Sshin	free (c->data);
14656977Sshin	c->data = NULL;
14763158Sume	krb5_clear_error_message (context);
14856977Sshin	return KRB5_KT_END;
14956977Sshin    }
15056977Sshin    return 0;
15163158Sume}
15263158Sume
15356977Sshinstatic krb5_error_code KRB5_CALLCONV
15463158Sumeany_next_entry (krb5_context context,
15563158Sume		krb5_keytab id,
15663158Sume		krb5_keytab_entry *entry,
15763158Sume		krb5_kt_cursor *cursor)
158146187Sume{
15963158Sume    krb5_error_code ret, ret2;
16044743Smarkm    struct any_cursor_extra_data *ed;
16144743Smarkm
16244743Smarkm    ed = (struct any_cursor_extra_data *)cursor->data;
16344743Smarkm    do {
16456977Sshin	ret = krb5_kt_next_entry(context, ed->a->kt, entry, &ed->cursor);
16544743Smarkm	if (ret == 0)
16644743Smarkm	    return 0;
16744743Smarkm	else if (ret != KRB5_KT_END)
16844743Smarkm	    return ret;
16944743Smarkm
17044743Smarkm	ret2 = krb5_kt_end_seq_get (context, ed->a->kt, &ed->cursor);
17144743Smarkm	if (ret2)
17256977Sshin	    return ret2;
17356977Sshin	while ((ed->a = ed->a->next) != NULL) {
17463158Sume	    ret2 = krb5_kt_start_seq_get(context, ed->a->kt, &ed->cursor);
17563158Sume	    if (ret2 == 0)
17663158Sume		break;
17763158Sume	}
17863158Sume	if (ed->a == NULL) {
17963158Sume	    krb5_clear_error_message (context);
18063158Sume	    return KRB5_KT_END;
18163158Sume	}
18263158Sume    } while (1);
18363158Sume}
18463158Sume
18563158Sumestatic krb5_error_code KRB5_CALLCONV
18663158Sumeany_end_seq_get(krb5_context context,
18756977Sshin		krb5_keytab id,
18863158Sume		krb5_kt_cursor *cursor)
18963158Sume{
19063158Sume    krb5_error_code ret = 0;
19163158Sume    struct any_cursor_extra_data *ed;
19263158Sume
19363158Sume    ed = (struct any_cursor_extra_data *)cursor->data;
19463158Sume    if (ed->a != NULL)
19563158Sume	ret = krb5_kt_end_seq_get(context, ed->a->kt, &ed->cursor);
19663158Sume    free (ed);
19763158Sume    cursor->data = NULL;
19863158Sume    return ret;
19963158Sume}
20063158Sume
20163158Sumestatic krb5_error_code KRB5_CALLCONV
20263158Sumeany_add_entry(krb5_context context,
20363158Sume	      krb5_keytab id,
20463158Sume	      krb5_keytab_entry *entry)
20563158Sume{
20663158Sume    struct any_data *a = id->data;
20763158Sume    krb5_error_code ret;
20863158Sume    while(a != NULL) {
20963158Sume	ret = krb5_kt_add_entry(context, a->kt, entry);
210146187Sume	if(ret != 0 && ret != KRB5_KT_NOWRITE) {
21163158Sume	    krb5_set_error_message(context, ret,
21263158Sume				   N_("failed to add entry to %s", ""),
21363158Sume				   a->name);
21463158Sume	    return ret;
21563158Sume	}
21666329Sume	a = a->next;
21766329Sume    }
21866329Sume    return 0;
21966329Sume}
22066329Sume
22179249Skrisstatic krb5_error_code KRB5_CALLCONV
22266329Sumeany_remove_entry(krb5_context context,
22366329Sume		 krb5_keytab id,
22466329Sume		 krb5_keytab_entry *entry)
22566329Sume{
22666329Sume    struct any_data *a = id->data;
22766329Sume    krb5_error_code ret;
22866329Sume    int found = 0;
22966329Sume    while(a != NULL) {
23066329Sume	ret = krb5_kt_remove_entry(context, a->kt, entry);
23166329Sume	if(ret == 0)
23266329Sume	    found++;
23363158Sume	else {
23463158Sume	    if(ret != KRB5_KT_NOWRITE && ret != KRB5_KT_NOTFOUND) {
23563158Sume		krb5_set_error_message(context, ret,
23663158Sume				       N_("Failed to remove keytab "
23763158Sume					  "entry from %s", "keytab name"),
23863158Sume				       a->name);
23963158Sume		return ret;
24063158Sume	    }
24163158Sume	}
24263158Sume	a = a->next;
24363158Sume    }
24463158Sume    if(!found)
24563158Sume	return KRB5_KT_NOTFOUND;
24663158Sume    return 0;
24763158Sume}
24863158Sume
24963158Sumeconst krb5_kt_ops krb5_any_ops = {
25063158Sume    "ANY",
25163158Sume    any_resolve,
25263158Sume    any_get_name,
25363158Sume    any_close,
25463158Sume    NULL, /* destroy */
25563158Sume    NULL, /* get */
25663158Sume    any_start_seq_get,
25763158Sume    any_next_entry,
25863158Sume    any_end_seq_get,
25963158Sume    any_add_entry,
26063158Sume    any_remove_entry
26166297Sume};
26266297Sume