10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * lib/krb5/ccache/ccbase.c
30Sstevel@tonic-gate *
4781Sgtb * Copyright 1990,2004 by the Massachusetts Institute of Technology.
50Sstevel@tonic-gate * All Rights Reserved.
60Sstevel@tonic-gate *
70Sstevel@tonic-gate * Export of this software from the United States of America may
80Sstevel@tonic-gate * require a specific license from the United States Government.
90Sstevel@tonic-gate * It is the responsibility of any person or organization contemplating
100Sstevel@tonic-gate * export to obtain such a license before exporting.
11781Sgtb *
120Sstevel@tonic-gate * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
130Sstevel@tonic-gate * distribute this software and its documentation for any purpose and
140Sstevel@tonic-gate * without fee is hereby granted, provided that the above copyright
150Sstevel@tonic-gate * notice appear in all copies and that both that copyright notice and
160Sstevel@tonic-gate * this permission notice appear in supporting documentation, and that
170Sstevel@tonic-gate * the name of M.I.T. not be used in advertising or publicity pertaining
180Sstevel@tonic-gate * to distribution of the software without specific, written prior
190Sstevel@tonic-gate * permission. Furthermore if you modify this software you must label
200Sstevel@tonic-gate * your software as modified software and not distribute it in such a
210Sstevel@tonic-gate * fashion that it might be confused with the original M.I.T. software.
220Sstevel@tonic-gate * M.I.T. makes no representations about the suitability of
230Sstevel@tonic-gate * this software for any purpose. It is provided "as is" without express
240Sstevel@tonic-gate * or implied warranty.
25781Sgtb *
260Sstevel@tonic-gate *
270Sstevel@tonic-gate * Registration functions for ccache.
280Sstevel@tonic-gate */
290Sstevel@tonic-gate
303375Smp153739 /*
31*7934SMark.Phalan@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
323375Smp153739 * Use is subject to license terms.
333375Smp153739 */
343375Smp153739
353375Smp153739
36781Sgtb #include "k5-int.h"
37781Sgtb #include "k5-thread.h"
38781Sgtb
39781Sgtb #include "fcc.h"
40781Sgtb #include "cc-int.h"
41781Sgtb
42781Sgtb struct krb5_cc_typelist {
43781Sgtb const krb5_cc_ops *ops;
44781Sgtb struct krb5_cc_typelist *next;
45781Sgtb };
46*7934SMark.Phalan@Sun.COM
47*7934SMark.Phalan@Sun.COM struct krb5_cc_typecursor {
48*7934SMark.Phalan@Sun.COM struct krb5_cc_typelist *tptr;
49*7934SMark.Phalan@Sun.COM };
50*7934SMark.Phalan@Sun.COM /* typedef krb5_cc_typecursor in k5-int.h */
51*7934SMark.Phalan@Sun.COM
52781Sgtb extern const krb5_cc_ops krb5_mcc_ops;
53*7934SMark.Phalan@Sun.COM #ifdef USE_KEYRING_CCACHE
54*7934SMark.Phalan@Sun.COM extern const krb5_cc_ops krb5_krcc_ops;
55*7934SMark.Phalan@Sun.COM #endif
56781Sgtb
57781Sgtb #ifdef _WIN32
58781Sgtb extern const krb5_cc_ops krb5_lcc_ops;
59781Sgtb static struct krb5_cc_typelist cc_lcc_entry = { &krb5_lcc_ops, NULL };
60781Sgtb static struct krb5_cc_typelist cc_mcc_entry = { &krb5_mcc_ops, &cc_lcc_entry };
61781Sgtb #else
62*7934SMark.Phalan@Sun.COM
63*7934SMark.Phalan@Sun.COM #ifdef USE_CCAPI_V3
64*7934SMark.Phalan@Sun.COM extern const krb5_cc_ops krb5_cc_stdcc_ops;
65*7934SMark.Phalan@Sun.COM static struct krb5_cc_typelist cc_stdcc_entry = { &krb5_cc_stdcc_ops, NULL };
66*7934SMark.Phalan@Sun.COM static struct krb5_cc_typelist cc_mcc_entry = { &krb5_mcc_ops, &cc_stdcc_entry };
67*7934SMark.Phalan@Sun.COM #else
68*7934SMark.Phalan@Sun.COM
69781Sgtb static struct krb5_cc_typelist cc_mcc_entry = { &krb5_mcc_ops, NULL };
70*7934SMark.Phalan@Sun.COM #endif /* USE_CCAPI_V3 */
71*7934SMark.Phalan@Sun.COM
72*7934SMark.Phalan@Sun.COM #ifdef USE_KEYRING_CCACHE
73*7934SMark.Phalan@Sun.COM static struct krb5_cc_typelist cc_file_entry = { &krb5_cc_file_ops,
74*7934SMark.Phalan@Sun.COM &cc_mcc_entry };
75*7934SMark.Phalan@Sun.COM static struct krb5_cc_typelist cc_krcc_entry = { &krb5_krcc_ops,
76*7934SMark.Phalan@Sun.COM &cc_file_entry };
77*7934SMark.Phalan@Sun.COM #endif /* USE_KEYRING_CCACHE */
78781Sgtb #endif
79781Sgtb
80781Sgtb static struct krb5_cc_typelist cc_fcc_entry = { &krb5_cc_file_ops,
81781Sgtb &cc_mcc_entry };
82*7934SMark.Phalan@Sun.COM #ifdef USE_KEYRING_CCACHE
83*7934SMark.Phalan@Sun.COM #define INITIAL_TYPEHEAD (&cc_krcc_entry)
84*7934SMark.Phalan@Sun.COM #else
85*7934SMark.Phalan@Sun.COM #define INITIAL_TYPEHEAD (&cc_fcc_entry)
86*7934SMark.Phalan@Sun.COM #endif
87*7934SMark.Phalan@Sun.COM static struct krb5_cc_typelist *cc_typehead = INITIAL_TYPEHEAD;
88*7934SMark.Phalan@Sun.COM static k5_mutex_t cc_typelist_lock = K5_MUTEX_PARTIAL_INITIALIZER;
89781Sgtb
90*7934SMark.Phalan@Sun.COM static krb5_error_code
91*7934SMark.Phalan@Sun.COM krb5int_cc_getops(krb5_context, const char *, const krb5_cc_ops **);
920Sstevel@tonic-gate
93781Sgtb int
krb5int_cc_initialize(void)94781Sgtb krb5int_cc_initialize(void)
95781Sgtb {
96781Sgtb int err;
970Sstevel@tonic-gate
98781Sgtb err = k5_mutex_finish_init(&krb5int_mcc_mutex);
99781Sgtb if (err)
100781Sgtb return err;
101781Sgtb err = k5_mutex_finish_init(&cc_typelist_lock);
102781Sgtb if (err)
103781Sgtb return err;
104781Sgtb err = k5_mutex_finish_init(&krb5int_cc_file_mutex);
105781Sgtb if (err)
106781Sgtb return err;
107*7934SMark.Phalan@Sun.COM #ifdef USE_KEYRING_CCACHE
108*7934SMark.Phalan@Sun.COM err = k5_mutex_finish_init(&krb5int_krcc_mutex);
109*7934SMark.Phalan@Sun.COM if (err)
110*7934SMark.Phalan@Sun.COM return err;
111*7934SMark.Phalan@Sun.COM #endif
112781Sgtb return 0;
113781Sgtb }
1140Sstevel@tonic-gate
115781Sgtb void
krb5int_cc_finalize(void)116781Sgtb krb5int_cc_finalize(void)
117781Sgtb {
118781Sgtb struct krb5_cc_typelist *t, *t_next;
119781Sgtb k5_mutex_destroy(&cc_typelist_lock);
120781Sgtb k5_mutex_destroy(&krb5int_cc_file_mutex);
121781Sgtb k5_mutex_destroy(&krb5int_mcc_mutex);
122*7934SMark.Phalan@Sun.COM #ifdef USE_KEYRING_CCACHE
123*7934SMark.Phalan@Sun.COM k5_mutex_destroy(&krb5int_krcc_mutex);
124*7934SMark.Phalan@Sun.COM #endif
125*7934SMark.Phalan@Sun.COM for (t = cc_typehead; t != INITIAL_TYPEHEAD; t = t_next) {
126781Sgtb t_next = t->next;
127781Sgtb free(t);
128781Sgtb }
129781Sgtb }
130781Sgtb
1310Sstevel@tonic-gate
1320Sstevel@tonic-gate /*
1330Sstevel@tonic-gate * Register a new credentials cache type
1340Sstevel@tonic-gate * If override is set, replace any existing ccache with that type tag
1350Sstevel@tonic-gate */
1360Sstevel@tonic-gate
137781Sgtb krb5_error_code KRB5_CALLCONV
krb5_cc_register(krb5_context context,krb5_cc_ops * ops,krb5_boolean override)138781Sgtb krb5_cc_register(krb5_context context, krb5_cc_ops *ops, krb5_boolean override)
1390Sstevel@tonic-gate {
1400Sstevel@tonic-gate struct krb5_cc_typelist *t;
141781Sgtb krb5_error_code err;
142781Sgtb
143781Sgtb err = k5_mutex_lock(&cc_typelist_lock);
144781Sgtb if (err)
145781Sgtb return err;
1460Sstevel@tonic-gate for (t = cc_typehead;t && strcmp(t->ops->prefix,ops->prefix);t = t->next)
1470Sstevel@tonic-gate ;
1480Sstevel@tonic-gate if (t) {
1490Sstevel@tonic-gate if (override) {
1500Sstevel@tonic-gate t->ops = ops;
151781Sgtb k5_mutex_unlock(&cc_typelist_lock);
1520Sstevel@tonic-gate return 0;
153781Sgtb } else {
154781Sgtb k5_mutex_unlock(&cc_typelist_lock);
1550Sstevel@tonic-gate return KRB5_CC_TYPE_EXISTS;
156781Sgtb }
1570Sstevel@tonic-gate }
158781Sgtb if (!(t = (struct krb5_cc_typelist *) malloc(sizeof(*t)))) {
159781Sgtb k5_mutex_unlock(&cc_typelist_lock);
1600Sstevel@tonic-gate return ENOMEM;
161781Sgtb }
1620Sstevel@tonic-gate t->next = cc_typehead;
1630Sstevel@tonic-gate t->ops = ops;
1640Sstevel@tonic-gate cc_typehead = t;
165781Sgtb k5_mutex_unlock(&cc_typelist_lock);
1660Sstevel@tonic-gate return 0;
1670Sstevel@tonic-gate }
1680Sstevel@tonic-gate
1690Sstevel@tonic-gate /*
1700Sstevel@tonic-gate * Resolve a credential cache name into a cred. cache object.
1710Sstevel@tonic-gate *
1720Sstevel@tonic-gate * The name is currently constrained to be of the form "type:residual";
1730Sstevel@tonic-gate *
1740Sstevel@tonic-gate * The "type" portion corresponds to one of the predefined credential
1750Sstevel@tonic-gate * cache types, while the "residual" portion is specific to the
1760Sstevel@tonic-gate * particular cache type.
1770Sstevel@tonic-gate */
1780Sstevel@tonic-gate
179781Sgtb #include <ctype.h>
180781Sgtb krb5_error_code KRB5_CALLCONV
krb5_cc_resolve(krb5_context context,const char * name,krb5_ccache * cache)181781Sgtb krb5_cc_resolve (krb5_context context, const char *name, krb5_ccache *cache)
1820Sstevel@tonic-gate {
1830Sstevel@tonic-gate char *pfx, *cp;
184781Sgtb const char *resid;
185781Sgtb unsigned int pfxlen;
186781Sgtb krb5_error_code err;
187*7934SMark.Phalan@Sun.COM const krb5_cc_ops *ops;
188781Sgtb
1893375Smp153739 /* Solaris Kerberos */
1903375Smp153739 if (!name)
1913375Smp153739 return KRB5_CC_BADNAME;
1923375Smp153739
193*7934SMark.Phalan@Sun.COM pfx = NULL;
1940Sstevel@tonic-gate cp = strchr (name, ':');
1950Sstevel@tonic-gate if (!cp) {
1960Sstevel@tonic-gate if (krb5_cc_dfl_ops)
197781Sgtb return (*krb5_cc_dfl_ops->resolve)(context, cache, name);
1980Sstevel@tonic-gate else
1990Sstevel@tonic-gate return KRB5_CC_BADNAME;
2000Sstevel@tonic-gate }
2010Sstevel@tonic-gate
2020Sstevel@tonic-gate pfxlen = cp - name;
203781Sgtb
204*7934SMark.Phalan@Sun.COM if ( pfxlen == 1 && isalpha((unsigned char) name[0]) ) {
205*7934SMark.Phalan@Sun.COM /* We found a drive letter not a prefix - use FILE */
206*7934SMark.Phalan@Sun.COM pfx = strdup("FILE");
207781Sgtb if (!pfx)
208781Sgtb return ENOMEM;
2090Sstevel@tonic-gate
210781Sgtb resid = name;
211781Sgtb } else {
212781Sgtb resid = name + pfxlen + 1;
213781Sgtb
214781Sgtb pfx = malloc (pfxlen+1);
215781Sgtb if (!pfx)
216781Sgtb return ENOMEM;
217781Sgtb
218781Sgtb memcpy (pfx, name, pfxlen);
219781Sgtb pfx[pfxlen] = '\0';
220781Sgtb }
2210Sstevel@tonic-gate
2220Sstevel@tonic-gate *cache = (krb5_ccache) 0;
2230Sstevel@tonic-gate
224*7934SMark.Phalan@Sun.COM err = krb5int_cc_getops(context, pfx, &ops);
225*7934SMark.Phalan@Sun.COM if (pfx != NULL)
226781Sgtb free(pfx);
227*7934SMark.Phalan@Sun.COM if (err)
228781Sgtb return err;
229*7934SMark.Phalan@Sun.COM
230*7934SMark.Phalan@Sun.COM return ops->resolve(context, cache, resid);
231*7934SMark.Phalan@Sun.COM }
232*7934SMark.Phalan@Sun.COM
233*7934SMark.Phalan@Sun.COM /*
234*7934SMark.Phalan@Sun.COM * cc_getops
235*7934SMark.Phalan@Sun.COM *
236*7934SMark.Phalan@Sun.COM * Internal function to return the ops vector for a given ccache
237*7934SMark.Phalan@Sun.COM * prefix string.
238*7934SMark.Phalan@Sun.COM */
239*7934SMark.Phalan@Sun.COM static krb5_error_code
krb5int_cc_getops(krb5_context context,const char * pfx,const krb5_cc_ops ** ops)240*7934SMark.Phalan@Sun.COM krb5int_cc_getops(
241*7934SMark.Phalan@Sun.COM krb5_context context,
242*7934SMark.Phalan@Sun.COM const char *pfx,
243*7934SMark.Phalan@Sun.COM const krb5_cc_ops **ops)
244*7934SMark.Phalan@Sun.COM {
245*7934SMark.Phalan@Sun.COM krb5_error_code err;
246*7934SMark.Phalan@Sun.COM struct krb5_cc_typelist *tlist;
247*7934SMark.Phalan@Sun.COM
248*7934SMark.Phalan@Sun.COM err = k5_mutex_lock(&cc_typelist_lock);
249*7934SMark.Phalan@Sun.COM if (err)
250*7934SMark.Phalan@Sun.COM return err;
251*7934SMark.Phalan@Sun.COM
2520Sstevel@tonic-gate for (tlist = cc_typehead; tlist; tlist = tlist->next) {
2530Sstevel@tonic-gate if (strcmp (tlist->ops->prefix, pfx) == 0) {
254*7934SMark.Phalan@Sun.COM *ops = tlist->ops;
255781Sgtb k5_mutex_unlock(&cc_typelist_lock);
256*7934SMark.Phalan@Sun.COM return 0;
2570Sstevel@tonic-gate }
2580Sstevel@tonic-gate }
259781Sgtb k5_mutex_unlock(&cc_typelist_lock);
2600Sstevel@tonic-gate if (krb5_cc_dfl_ops && !strcmp (pfx, krb5_cc_dfl_ops->prefix)) {
261*7934SMark.Phalan@Sun.COM *ops = krb5_cc_dfl_ops;
262*7934SMark.Phalan@Sun.COM return 0;
2630Sstevel@tonic-gate }
2640Sstevel@tonic-gate return KRB5_CC_UNKNOWN_TYPE;
2650Sstevel@tonic-gate }
266*7934SMark.Phalan@Sun.COM
267*7934SMark.Phalan@Sun.COM /*
268*7934SMark.Phalan@Sun.COM * cc_new_unique
269*7934SMark.Phalan@Sun.COM *
270*7934SMark.Phalan@Sun.COM * Generate a new unique ccache, given a ccache type and a hint
271*7934SMark.Phalan@Sun.COM * string. Ignores the hint string for now.
272*7934SMark.Phalan@Sun.COM */
273*7934SMark.Phalan@Sun.COM krb5_error_code KRB5_CALLCONV
krb5_cc_new_unique(krb5_context context,const char * type,const char * hint,krb5_ccache * id)274*7934SMark.Phalan@Sun.COM krb5_cc_new_unique(
275*7934SMark.Phalan@Sun.COM krb5_context context,
276*7934SMark.Phalan@Sun.COM const char *type,
277*7934SMark.Phalan@Sun.COM const char *hint,
278*7934SMark.Phalan@Sun.COM krb5_ccache *id)
279*7934SMark.Phalan@Sun.COM {
280*7934SMark.Phalan@Sun.COM const krb5_cc_ops *ops;
281*7934SMark.Phalan@Sun.COM krb5_error_code err;
282*7934SMark.Phalan@Sun.COM
283*7934SMark.Phalan@Sun.COM *id = NULL;
284*7934SMark.Phalan@Sun.COM
285*7934SMark.Phalan@Sun.COM err = krb5int_cc_getops(context, type, &ops);
286*7934SMark.Phalan@Sun.COM if (err)
287*7934SMark.Phalan@Sun.COM return err;
288*7934SMark.Phalan@Sun.COM
289*7934SMark.Phalan@Sun.COM return ops->gen_new(context, id);
290*7934SMark.Phalan@Sun.COM }
291*7934SMark.Phalan@Sun.COM
292*7934SMark.Phalan@Sun.COM /*
293*7934SMark.Phalan@Sun.COM * cc_typecursor
294*7934SMark.Phalan@Sun.COM *
295*7934SMark.Phalan@Sun.COM * Note: to avoid copying the typelist at cursor creation time, among
296*7934SMark.Phalan@Sun.COM * other things, we assume that the only additions ever occur to the
297*7934SMark.Phalan@Sun.COM * typelist.
298*7934SMark.Phalan@Sun.COM */
299*7934SMark.Phalan@Sun.COM krb5_error_code
krb5int_cc_typecursor_new(krb5_context context,krb5_cc_typecursor * t)300*7934SMark.Phalan@Sun.COM krb5int_cc_typecursor_new(krb5_context context, krb5_cc_typecursor *t)
301*7934SMark.Phalan@Sun.COM {
302*7934SMark.Phalan@Sun.COM krb5_error_code err = 0;
303*7934SMark.Phalan@Sun.COM krb5_cc_typecursor n = NULL;
304*7934SMark.Phalan@Sun.COM
305*7934SMark.Phalan@Sun.COM *t = NULL;
306*7934SMark.Phalan@Sun.COM n = malloc(sizeof(*n));
307*7934SMark.Phalan@Sun.COM if (n == NULL)
308*7934SMark.Phalan@Sun.COM return ENOMEM;
309*7934SMark.Phalan@Sun.COM
310*7934SMark.Phalan@Sun.COM err = k5_mutex_lock(&cc_typelist_lock);
311*7934SMark.Phalan@Sun.COM if (err)
312*7934SMark.Phalan@Sun.COM goto errout;
313*7934SMark.Phalan@Sun.COM n->tptr = cc_typehead;
314*7934SMark.Phalan@Sun.COM err = k5_mutex_unlock(&cc_typelist_lock);
315*7934SMark.Phalan@Sun.COM if (err)
316*7934SMark.Phalan@Sun.COM goto errout;
317*7934SMark.Phalan@Sun.COM
318*7934SMark.Phalan@Sun.COM *t = n;
319*7934SMark.Phalan@Sun.COM errout:
320*7934SMark.Phalan@Sun.COM if (err)
321*7934SMark.Phalan@Sun.COM free(n);
322*7934SMark.Phalan@Sun.COM return err;
323*7934SMark.Phalan@Sun.COM }
324*7934SMark.Phalan@Sun.COM
325*7934SMark.Phalan@Sun.COM krb5_error_code
krb5int_cc_typecursor_next(krb5_context context,krb5_cc_typecursor t,const krb5_cc_ops ** ops)326*7934SMark.Phalan@Sun.COM krb5int_cc_typecursor_next(
327*7934SMark.Phalan@Sun.COM krb5_context context,
328*7934SMark.Phalan@Sun.COM krb5_cc_typecursor t,
329*7934SMark.Phalan@Sun.COM const krb5_cc_ops **ops)
330*7934SMark.Phalan@Sun.COM {
331*7934SMark.Phalan@Sun.COM krb5_error_code err = 0;
332*7934SMark.Phalan@Sun.COM
333*7934SMark.Phalan@Sun.COM *ops = NULL;
334*7934SMark.Phalan@Sun.COM if (t->tptr == NULL)
335*7934SMark.Phalan@Sun.COM return 0;
336*7934SMark.Phalan@Sun.COM
337*7934SMark.Phalan@Sun.COM err = k5_mutex_lock(&cc_typelist_lock);
338*7934SMark.Phalan@Sun.COM if (err)
339*7934SMark.Phalan@Sun.COM goto errout;
340*7934SMark.Phalan@Sun.COM *ops = t->tptr->ops;
341*7934SMark.Phalan@Sun.COM t->tptr = t->tptr->next;
342*7934SMark.Phalan@Sun.COM err = k5_mutex_unlock(&cc_typelist_lock);
343*7934SMark.Phalan@Sun.COM if (err)
344*7934SMark.Phalan@Sun.COM goto errout;
345*7934SMark.Phalan@Sun.COM
346*7934SMark.Phalan@Sun.COM errout:
347*7934SMark.Phalan@Sun.COM return err;
348*7934SMark.Phalan@Sun.COM }
349*7934SMark.Phalan@Sun.COM
350*7934SMark.Phalan@Sun.COM krb5_error_code
krb5int_cc_typecursor_free(krb5_context context,krb5_cc_typecursor * t)351*7934SMark.Phalan@Sun.COM krb5int_cc_typecursor_free(krb5_context context, krb5_cc_typecursor *t)
352*7934SMark.Phalan@Sun.COM {
353*7934SMark.Phalan@Sun.COM free(*t);
354*7934SMark.Phalan@Sun.COM *t = NULL;
355*7934SMark.Phalan@Sun.COM return 0;
356*7934SMark.Phalan@Sun.COM }
357