1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/krb5/ccache/ccselect.c - krb5_cc_select API and module loader */
4 * Copyright (C) 2011 by the Massachusetts Institute of Technology.
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. Furthermore if you modify this software you must label
20 * your software as modified software and not distribute it in such a
21 * fashion that it might be confused with the original M.I.T. software.
22 * M.I.T. makes no representations about the suitability of
23 * this software for any purpose. It is provided "as is" without express
24 * or implied warranty.
29 #include <krb5/ccselect_plugin.h>
30 #include "../krb/int-proto.h"
32 struct ccselect_module_handle {
33 struct krb5_ccselect_vtable_st vt;
34 krb5_ccselect_moddata data;
39 free_handles(krb5_context context, struct ccselect_module_handle **handles)
41 struct ccselect_module_handle *h, **hp;
45 for (hp = handles; *hp != NULL; hp++) {
48 h->vt.fini(context, h->data);
54 static krb5_error_code
55 load_modules(krb5_context context)
58 struct ccselect_module_handle **list = NULL, *handle;
59 krb5_plugin_initvt_fn *modules = NULL, *mod;
63 ret = k5_plugin_register(context, PLUGIN_INTERFACE_CCSELECT, "k5identity",
64 ccselect_k5identity_initvt);
69 ret = k5_plugin_register(context, PLUGIN_INTERFACE_CCSELECT, "realm",
70 ccselect_realm_initvt);
74 ret = k5_plugin_load_all(context, PLUGIN_INTERFACE_CCSELECT, &modules);
78 /* Allocate a large enough list of handles. */
79 for (count = 0; modules[count] != NULL; count++);
80 list = k5calloc(count + 1, sizeof(*list), &ret);
84 /* Initialize each module, ignoring ones that fail. */
86 for (mod = modules; *mod != NULL; mod++) {
87 handle = k5alloc(sizeof(*handle), &ret);
90 ret = (*mod)(context, 1, 1, (krb5_plugin_vtable)&handle->vt);
91 if (ret != 0) { /* Failed vtable init is non-fatal. */
92 TRACE_CCSELECT_VTINIT_FAIL(context, ret);
97 ret = handle->vt.init(context, &handle->data, &handle->priority);
98 if (ret != 0) { /* Failed initialization is non-fatal. */
99 TRACE_CCSELECT_INIT_FAIL(context, handle->vt.name, ret);
103 list[count++] = handle;
109 context->ccselect_handles = list;
113 k5_plugin_free_modules(context, modules);
114 free_handles(context, list);
118 static krb5_error_code
119 choose(krb5_context context, struct ccselect_module_handle *h,
120 krb5_principal server, krb5_ccache *cache_out,
121 krb5_principal *princ_out)
123 return h->vt.choose(context, h->data, server, cache_out, princ_out);
126 krb5_error_code KRB5_CALLCONV
127 krb5_cc_select(krb5_context context, krb5_principal server,
128 krb5_ccache *cache_out, krb5_principal *princ_out)
132 struct ccselect_module_handle **hp, *h;
134 krb5_principal princ;
139 if (context->ccselect_handles == NULL) {
140 ret = load_modules(context);
145 /* Consult authoritative modules first, then heuristic ones. */
146 for (priority = KRB5_CCSELECT_PRIORITY_AUTHORITATIVE;
147 priority >= KRB5_CCSELECT_PRIORITY_HEURISTIC; priority--) {
148 for (hp = context->ccselect_handles; *hp != NULL; hp++) {
150 if (h->priority != priority)
152 ret = choose(context, h, server, &cache, &princ);
154 TRACE_CCSELECT_MODCHOICE(context, h->vt.name, server, cache,
159 } else if (ret == KRB5_CC_NOTFOUND) {
160 TRACE_CCSELECT_MODNOTFOUND(context, h->vt.name, server, princ);
163 } else if (ret != KRB5_PLUGIN_NO_HANDLE) {
164 TRACE_CCSELECT_MODFAIL(context, h->vt.name, ret, server);
170 TRACE_CCSELECT_NOTFOUND(context, server);
171 return KRB5_CC_NOTFOUND;
175 k5_ccselect_free_context(krb5_context context)
177 free_handles(context, context->ccselect_handles);
178 context->ccselect_handles = NULL;