Adds an "ANY" keytab type which is a list of other keytab locations to search when searching for a specific entry. When iterated through, it only presents the contents of the first keytab. diff -up /dev/null krb5-1.7/src/lib/krb5/keytab/kt_any.c --- /dev/null 2009-06-04 10:34:55.169007373 -0400 +++ krb5-1.7/src/lib/krb5/keytab/kt_any.c 2009-06-04 13:54:36.000000000 -0400 @@ -0,0 +1,292 @@ +/* + * lib/krb5/keytab/kt_any.c + * + * Copyright 1998, 1999 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * + * krb5_kta_ops + */ + +#include "k5-int.h" + +typedef struct _krb5_ktany_data { + char *name; + krb5_keytab *choices; + int nchoices; +} krb5_ktany_data; + +typedef struct _krb5_ktany_cursor_data { + int which; + krb5_kt_cursor cursor; +} krb5_ktany_cursor_data; + +static krb5_error_code krb5_ktany_resolve + (krb5_context, + const char *, + krb5_keytab *); +static krb5_error_code krb5_ktany_get_name + (krb5_context context, + krb5_keytab id, + char *name, + unsigned int len); +static krb5_error_code krb5_ktany_close + (krb5_context context, + krb5_keytab id); +static krb5_error_code krb5_ktany_get_entry + (krb5_context context, + krb5_keytab id, + krb5_const_principal principal, + krb5_kvno kvno, + krb5_enctype enctype, + krb5_keytab_entry *entry); +static krb5_error_code krb5_ktany_start_seq_get + (krb5_context context, + krb5_keytab id, + krb5_kt_cursor *cursorp); +static krb5_error_code krb5_ktany_next_entry + (krb5_context context, + krb5_keytab id, + krb5_keytab_entry *entry, + krb5_kt_cursor *cursor); +static krb5_error_code krb5_ktany_end_seq_get + (krb5_context context, + krb5_keytab id, + krb5_kt_cursor *cursor); +static void cleanup + (krb5_context context, + krb5_ktany_data *data, + int nchoices); + +struct _krb5_kt_ops krb5_kta_ops = { + 0, + "ANY", /* Prefix -- this string should not appear anywhere else! */ + krb5_ktany_resolve, + krb5_ktany_get_name, + krb5_ktany_close, + krb5_ktany_get_entry, + krb5_ktany_start_seq_get, + krb5_ktany_next_entry, + krb5_ktany_end_seq_get, + NULL, + NULL, + NULL, +}; + +static krb5_error_code +krb5_ktany_resolve(context, name, id) + krb5_context context; + const char *name; + krb5_keytab *id; +{ + const char *p, *q; + char *copy; + krb5_error_code kerror; + krb5_ktany_data *data; + int i; + + /* Allocate space for our data and remember a copy of the name. */ + if ((data = (krb5_ktany_data *)malloc(sizeof(krb5_ktany_data))) == NULL) + return(ENOMEM); + if ((data->name = (char *)malloc(strlen(name) + 1)) == NULL) { + krb5_xfree(data); + return(ENOMEM); + } + strcpy(data->name, name); + + /* Count the number of choices and allocate memory for them. */ + data->nchoices = 1; + for (p = name; (q = strchr(p, ',')) != NULL; p = q + 1) + data->nchoices++; + if ((data->choices = (krb5_keytab *) + malloc(data->nchoices * sizeof(krb5_keytab))) == NULL) { + krb5_xfree(data->name); + krb5_xfree(data); + return(ENOMEM); + } + + /* Resolve each of the choices. */ + i = 0; + for (p = name; (q = strchr(p, ',')) != NULL; p = q + 1) { + /* Make a copy of the choice name so we can terminate it. */ + if ((copy = (char *)malloc(q - p + 1)) == NULL) { + cleanup(context, data, i); + return(ENOMEM); + } + memcpy(copy, p, q - p); + copy[q - p] = 0; + + /* Try resolving the choice name. */ + kerror = krb5_kt_resolve(context, copy, &data->choices[i]); + krb5_xfree(copy); + if (kerror) { + cleanup(context, data, i); + return(kerror); + } + i++; + } + if ((kerror = krb5_kt_resolve(context, p, &data->choices[i]))) { + cleanup(context, data, i); + return(kerror); + } + + /* Allocate and fill in an ID for the caller. */ + if ((*id = (krb5_keytab)malloc(sizeof(**id))) == NULL) { + cleanup(context, data, i); + return(ENOMEM); + } + (*id)->ops = &krb5_kta_ops; + (*id)->data = (krb5_pointer)data; + (*id)->magic = KV5M_KEYTAB; + + return(0); +} + +static krb5_error_code +krb5_ktany_get_name(context, id, name, len) + krb5_context context; + krb5_keytab id; + char *name; + unsigned int len; +{ + krb5_ktany_data *data = (krb5_ktany_data *)id->data; + + if (len < strlen(data->name) + 1) + return(KRB5_KT_NAME_TOOLONG); + strcpy(name, data->name); + return(0); +} + +static krb5_error_code +krb5_ktany_close(context, id) + krb5_context context; + krb5_keytab id; +{ + krb5_ktany_data *data = (krb5_ktany_data *)id->data; + + cleanup(context, data, data->nchoices); + id->ops = 0; + krb5_xfree(id); + return(0); +} + +static krb5_error_code +krb5_ktany_get_entry(context, id, principal, kvno, enctype, entry) + krb5_context context; + krb5_keytab id; + krb5_const_principal principal; + krb5_kvno kvno; + krb5_enctype enctype; + krb5_keytab_entry *entry; +{ + krb5_ktany_data *data = (krb5_ktany_data *)id->data; + krb5_error_code kerror = KRB5_KT_NOTFOUND; + int i; + + for (i = 0; i < data->nchoices; i++) { + if ((kerror = krb5_kt_get_entry(context, data->choices[i], principal, + kvno, enctype, entry)) != ENOENT) + return kerror; + } + return kerror; +} + +static krb5_error_code +krb5_ktany_start_seq_get(context, id, cursorp) + krb5_context context; + krb5_keytab id; + krb5_kt_cursor *cursorp; +{ + krb5_ktany_data *data = (krb5_ktany_data *)id->data; + krb5_ktany_cursor_data *cdata; + krb5_error_code kerror = ENOENT; + int i; + + if ((cdata = (krb5_ktany_cursor_data *) + malloc(sizeof(krb5_ktany_cursor_data))) == NULL) + return(ENOMEM); + + /* Find a choice which can handle the serialization request. */ + for (i = 0; i < data->nchoices; i++) { + if ((kerror = krb5_kt_start_seq_get(context, data->choices[i], + &cdata->cursor)) == 0) + break; + else if (kerror != ENOENT) { + krb5_xfree(cdata); + return(kerror); + } + } + + if (i == data->nchoices) { + /* Everyone returned ENOENT, so no go. */ + krb5_xfree(cdata); + return(kerror); + } + + cdata->which = i; + *cursorp = (krb5_kt_cursor)cdata; + return(0); +} + +static krb5_error_code +krb5_ktany_next_entry(context, id, entry, cursor) + krb5_context context; + krb5_keytab id; + krb5_keytab_entry *entry; + krb5_kt_cursor *cursor; +{ + krb5_ktany_data *data = (krb5_ktany_data *)id->data; + krb5_ktany_cursor_data *cdata = (krb5_ktany_cursor_data *)*cursor; + krb5_keytab choice_id; + + choice_id = data->choices[cdata->which]; + return(krb5_kt_next_entry(context, choice_id, entry, &cdata->cursor)); +} + +static krb5_error_code +krb5_ktany_end_seq_get(context, id, cursor) + krb5_context context; + krb5_keytab id; + krb5_kt_cursor *cursor; +{ + krb5_ktany_data *data = (krb5_ktany_data *)id->data; + krb5_ktany_cursor_data *cdata = (krb5_ktany_cursor_data *)*cursor; + krb5_keytab choice_id; + krb5_error_code kerror; + + choice_id = data->choices[cdata->which]; + kerror = krb5_kt_end_seq_get(context, choice_id, &cdata->cursor); + krb5_xfree(cdata); + return(kerror); +} + +static void +cleanup(context, data, nchoices) + krb5_context context; + krb5_ktany_data *data; + int nchoices; +{ + int i; + + krb5_xfree(data->name); + for (i = 0; i < nchoices; i++) + krb5_kt_close(context, data->choices[i]); + krb5_xfree(data->choices); + krb5_xfree(data); +} diff -up krb5-1.7/src/lib/krb5/keytab/ktbase.c krb5-1.7/src/lib/krb5/keytab/ktbase.c --- krb5-1.7/src/lib/krb5/keytab/ktbase.c 2009-02-18 13:18:56.000000000 -0500 +++ krb5-1.7/src/lib/krb5/keytab/ktbase.c 2009-06-04 13:54:36.000000000 -0400 @@ -59,14 +59,19 @@ extern const krb5_kt_ops krb5_ktf_ops; extern const krb5_kt_ops krb5_ktf_writable_ops; extern const krb5_kt_ops krb5_kts_ops; extern const krb5_kt_ops krb5_mkt_ops; +extern const krb5_kt_ops krb5_kta_ops; struct krb5_kt_typelist { const krb5_kt_ops *ops; const struct krb5_kt_typelist *next; }; +static struct krb5_kt_typelist krb5_kt_typelist_any = { + &krb5_kta_ops, + NULL +}; const static struct krb5_kt_typelist krb5_kt_typelist_srvtab = { &krb5_kts_ops, - NULL + &krb5_kt_typelist_any }; const static struct krb5_kt_typelist krb5_kt_typelist_memory = { &krb5_mkt_ops, diff -up krb5-1.7/src/lib/krb5/keytab/Makefile.in krb5-1.7/src/lib/krb5/keytab/Makefile.in --- krb5-1.7/src/lib/krb5/keytab/Makefile.in 2009-01-05 15:27:53.000000000 -0500 +++ krb5-1.7/src/lib/krb5/keytab/Makefile.in 2009-06-04 13:54:36.000000000 -0400 @@ -19,6 +19,7 @@ STLIBOBJS= \ ktfr_entry.o \ ktremove.o \ ktfns.o \ + kt_any.o \ kt_file.o \ kt_memory.o \ kt_srvtab.o \ @@ -31,6 +32,7 @@ OBJS= \ $(OUTPRE)ktfr_entry.$(OBJEXT) \ $(OUTPRE)ktremove.$(OBJEXT) \ $(OUTPRE)ktfns.$(OBJEXT) \ + $(OUTPRE)kt_any.$(OBJEXT) \ $(OUTPRE)kt_file.$(OBJEXT) \ $(OUTPRE)kt_memory.$(OBJEXT) \ $(OUTPRE)kt_srvtab.$(OBJEXT) \ @@ -43,6 +45,7 @@ SRCS= \ $(srcdir)/ktfr_entry.c \ $(srcdir)/ktremove.c \ $(srcdir)/ktfns.c \ + $(srcdir)/kt_any.c \ $(srcdir)/kt_file.c \ $(srcdir)/kt_memory.c \ $(srcdir)/kt_srvtab.c \