17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * lib/krb5/ccache/ccbase.c
37c478bd9Sstevel@tonic-gate  *
4505d05c7Sgtb  * Copyright 1990,2004 by the Massachusetts Institute of Technology.
57c478bd9Sstevel@tonic-gate  * All Rights Reserved.
67c478bd9Sstevel@tonic-gate  *
77c478bd9Sstevel@tonic-gate  * Export of this software from the United States of America may
87c478bd9Sstevel@tonic-gate  *   require a specific license from the United States Government.
97c478bd9Sstevel@tonic-gate  *   It is the responsibility of any person or organization contemplating
107c478bd9Sstevel@tonic-gate  *   export to obtain such a license before exporting.
11*55fea89dSDan Cross  *
127c478bd9Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
137c478bd9Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
147c478bd9Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
157c478bd9Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
167c478bd9Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
177c478bd9Sstevel@tonic-gate  * the name of M.I.T. not be used in advertising or publicity pertaining
187c478bd9Sstevel@tonic-gate  * to distribution of the software without specific, written prior
197c478bd9Sstevel@tonic-gate  * permission.  Furthermore if you modify this software you must label
207c478bd9Sstevel@tonic-gate  * your software as modified software and not distribute it in such a
217c478bd9Sstevel@tonic-gate  * fashion that it might be confused with the original M.I.T. software.
227c478bd9Sstevel@tonic-gate  * M.I.T. makes no representations about the suitability of
237c478bd9Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
247c478bd9Sstevel@tonic-gate  * or implied warranty.
25*55fea89dSDan Cross  *
267c478bd9Sstevel@tonic-gate  *
277c478bd9Sstevel@tonic-gate  * Registration functions for ccache.
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate 
30d51f1d33Smp /*
31159d09a2SMark Phalan  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
32d51f1d33Smp  * Use is subject to license terms.
33d51f1d33Smp  */
34d51f1d33Smp 
35d51f1d33Smp 
36505d05c7Sgtb #include "k5-int.h"
37505d05c7Sgtb #include "k5-thread.h"
38505d05c7Sgtb 
39505d05c7Sgtb #include "fcc.h"
40505d05c7Sgtb #include "cc-int.h"
41505d05c7Sgtb 
42505d05c7Sgtb struct krb5_cc_typelist {
43505d05c7Sgtb     const krb5_cc_ops *ops;
44505d05c7Sgtb     struct krb5_cc_typelist *next;
45505d05c7Sgtb };
46159d09a2SMark Phalan 
47159d09a2SMark Phalan struct krb5_cc_typecursor {
48159d09a2SMark Phalan     struct krb5_cc_typelist *tptr;
49159d09a2SMark Phalan };
50159d09a2SMark Phalan /* typedef krb5_cc_typecursor in k5-int.h */
51159d09a2SMark Phalan 
52505d05c7Sgtb extern const krb5_cc_ops krb5_mcc_ops;
53159d09a2SMark Phalan #ifdef USE_KEYRING_CCACHE
54159d09a2SMark Phalan extern const krb5_cc_ops krb5_krcc_ops;
55159d09a2SMark Phalan #endif
567c478bd9Sstevel@tonic-gate 
57505d05c7Sgtb #ifdef _WIN32
58505d05c7Sgtb extern const krb5_cc_ops krb5_lcc_ops;
59505d05c7Sgtb static struct krb5_cc_typelist cc_lcc_entry = { &krb5_lcc_ops, NULL };
60505d05c7Sgtb static struct krb5_cc_typelist cc_mcc_entry = { &krb5_mcc_ops, &cc_lcc_entry };
61505d05c7Sgtb #else
62159d09a2SMark Phalan 
63159d09a2SMark Phalan #ifdef USE_CCAPI_V3
64159d09a2SMark Phalan extern const krb5_cc_ops krb5_cc_stdcc_ops;
65159d09a2SMark Phalan static struct krb5_cc_typelist cc_stdcc_entry = { &krb5_cc_stdcc_ops, NULL };
66159d09a2SMark Phalan static struct krb5_cc_typelist cc_mcc_entry = { &krb5_mcc_ops, &cc_stdcc_entry };
67159d09a2SMark Phalan #else
68159d09a2SMark Phalan 
69505d05c7Sgtb static struct krb5_cc_typelist cc_mcc_entry = { &krb5_mcc_ops, NULL };
70159d09a2SMark Phalan #endif /* USE_CCAPI_V3 */
71159d09a2SMark Phalan 
72159d09a2SMark Phalan #ifdef USE_KEYRING_CCACHE
73159d09a2SMark Phalan static struct krb5_cc_typelist cc_file_entry = { &krb5_cc_file_ops,
74159d09a2SMark Phalan 						 &cc_mcc_entry };
75159d09a2SMark Phalan static struct krb5_cc_typelist cc_krcc_entry = { &krb5_krcc_ops,
76159d09a2SMark Phalan 						 &cc_file_entry };
77159d09a2SMark Phalan #endif /* USE_KEYRING_CCACHE */
78505d05c7Sgtb #endif
797c478bd9Sstevel@tonic-gate 
80505d05c7Sgtb static struct krb5_cc_typelist cc_fcc_entry = { &krb5_cc_file_ops,
81505d05c7Sgtb 						&cc_mcc_entry };
82159d09a2SMark Phalan #ifdef USE_KEYRING_CCACHE
83159d09a2SMark Phalan #define INITIAL_TYPEHEAD (&cc_krcc_entry)
84159d09a2SMark Phalan #else
85159d09a2SMark Phalan #define INITIAL_TYPEHEAD (&cc_fcc_entry)
86159d09a2SMark Phalan #endif
87159d09a2SMark Phalan static struct krb5_cc_typelist *cc_typehead = INITIAL_TYPEHEAD;
88505d05c7Sgtb static k5_mutex_t cc_typelist_lock = K5_MUTEX_PARTIAL_INITIALIZER;
89505d05c7Sgtb 
90159d09a2SMark Phalan static krb5_error_code
91159d09a2SMark Phalan krb5int_cc_getops(krb5_context, const char *, const krb5_cc_ops **);
92159d09a2SMark Phalan 
93505d05c7Sgtb int
krb5int_cc_initialize(void)94505d05c7Sgtb krb5int_cc_initialize(void)
95505d05c7Sgtb {
96505d05c7Sgtb     int err;
97505d05c7Sgtb 
98505d05c7Sgtb     err = k5_mutex_finish_init(&krb5int_mcc_mutex);
99505d05c7Sgtb     if (err)
100505d05c7Sgtb 	return err;
101505d05c7Sgtb     err = k5_mutex_finish_init(&cc_typelist_lock);
102505d05c7Sgtb     if (err)
103505d05c7Sgtb 	return err;
104505d05c7Sgtb     err = k5_mutex_finish_init(&krb5int_cc_file_mutex);
105505d05c7Sgtb     if (err)
106505d05c7Sgtb 	return err;
107159d09a2SMark Phalan #ifdef USE_KEYRING_CCACHE
108159d09a2SMark Phalan     err = k5_mutex_finish_init(&krb5int_krcc_mutex);
109159d09a2SMark Phalan     if (err)
110159d09a2SMark Phalan 	return err;
111159d09a2SMark Phalan #endif
112505d05c7Sgtb     return 0;
113505d05c7Sgtb }
114505d05c7Sgtb 
115505d05c7Sgtb void
krb5int_cc_finalize(void)116505d05c7Sgtb krb5int_cc_finalize(void)
117505d05c7Sgtb {
118505d05c7Sgtb     struct krb5_cc_typelist *t, *t_next;
119505d05c7Sgtb     k5_mutex_destroy(&cc_typelist_lock);
120505d05c7Sgtb     k5_mutex_destroy(&krb5int_cc_file_mutex);
121505d05c7Sgtb     k5_mutex_destroy(&krb5int_mcc_mutex);
122159d09a2SMark Phalan #ifdef USE_KEYRING_CCACHE
123159d09a2SMark Phalan     k5_mutex_destroy(&krb5int_krcc_mutex);
124159d09a2SMark Phalan #endif
125159d09a2SMark Phalan     for (t = cc_typehead; t != INITIAL_TYPEHEAD; t = t_next) {
126505d05c7Sgtb 	t_next = t->next;
127505d05c7Sgtb 	free(t);
128505d05c7Sgtb     }
129505d05c7Sgtb }
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate /*
1337c478bd9Sstevel@tonic-gate  * Register a new credentials cache type
1347c478bd9Sstevel@tonic-gate  * If override is set, replace any existing ccache with that type tag
1357c478bd9Sstevel@tonic-gate  */
1367c478bd9Sstevel@tonic-gate 
137505d05c7Sgtb krb5_error_code KRB5_CALLCONV
krb5_cc_register(krb5_context context,krb5_cc_ops * ops,krb5_boolean override)138505d05c7Sgtb krb5_cc_register(krb5_context context, krb5_cc_ops *ops, krb5_boolean override)
1397c478bd9Sstevel@tonic-gate {
1407c478bd9Sstevel@tonic-gate     struct krb5_cc_typelist *t;
141505d05c7Sgtb     krb5_error_code err;
142505d05c7Sgtb 
143505d05c7Sgtb     err = k5_mutex_lock(&cc_typelist_lock);
144505d05c7Sgtb     if (err)
145505d05c7Sgtb 	return err;
1467c478bd9Sstevel@tonic-gate     for (t = cc_typehead;t && strcmp(t->ops->prefix,ops->prefix);t = t->next)
1477c478bd9Sstevel@tonic-gate 	;
1487c478bd9Sstevel@tonic-gate     if (t) {
1497c478bd9Sstevel@tonic-gate 	if (override) {
1507c478bd9Sstevel@tonic-gate 	    t->ops = ops;
151505d05c7Sgtb 	    k5_mutex_unlock(&cc_typelist_lock);
1527c478bd9Sstevel@tonic-gate 	    return 0;
153505d05c7Sgtb 	} else {
154505d05c7Sgtb 	    k5_mutex_unlock(&cc_typelist_lock);
1557c478bd9Sstevel@tonic-gate 	    return KRB5_CC_TYPE_EXISTS;
156505d05c7Sgtb 	}
1577c478bd9Sstevel@tonic-gate     }
158505d05c7Sgtb     if (!(t = (struct krb5_cc_typelist *) malloc(sizeof(*t)))) {
159505d05c7Sgtb 	k5_mutex_unlock(&cc_typelist_lock);
1607c478bd9Sstevel@tonic-gate 	return ENOMEM;
161505d05c7Sgtb     }
1627c478bd9Sstevel@tonic-gate     t->next = cc_typehead;
1637c478bd9Sstevel@tonic-gate     t->ops = ops;
1647c478bd9Sstevel@tonic-gate     cc_typehead = t;
165505d05c7Sgtb     k5_mutex_unlock(&cc_typelist_lock);
1667c478bd9Sstevel@tonic-gate     return 0;
1677c478bd9Sstevel@tonic-gate }
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate /*
1707c478bd9Sstevel@tonic-gate  * Resolve a credential cache name into a cred. cache object.
1717c478bd9Sstevel@tonic-gate  *
1727c478bd9Sstevel@tonic-gate  * The name is currently constrained to be of the form "type:residual";
1737c478bd9Sstevel@tonic-gate  *
1747c478bd9Sstevel@tonic-gate  * The "type" portion corresponds to one of the predefined credential
1757c478bd9Sstevel@tonic-gate  * cache types, while the "residual" portion is specific to the
1767c478bd9Sstevel@tonic-gate  * particular cache type.
1777c478bd9Sstevel@tonic-gate  */
1787c478bd9Sstevel@tonic-gate 
179505d05c7Sgtb #include <ctype.h>
180505d05c7Sgtb krb5_error_code KRB5_CALLCONV
krb5_cc_resolve(krb5_context context,const char * name,krb5_ccache * cache)181505d05c7Sgtb krb5_cc_resolve (krb5_context context, const char *name, krb5_ccache *cache)
1827c478bd9Sstevel@tonic-gate {
1837c478bd9Sstevel@tonic-gate     char *pfx, *cp;
184505d05c7Sgtb     const char *resid;
185505d05c7Sgtb     unsigned int pfxlen;
186505d05c7Sgtb     krb5_error_code err;
187159d09a2SMark Phalan     const krb5_cc_ops *ops;
188*55fea89dSDan Cross 
189d51f1d33Smp     /* Solaris Kerberos */
190d51f1d33Smp     if (!name)
191d51f1d33Smp         return KRB5_CC_BADNAME;
192d51f1d33Smp 
193159d09a2SMark Phalan     pfx = NULL;
1947c478bd9Sstevel@tonic-gate     cp = strchr (name, ':');
1957c478bd9Sstevel@tonic-gate     if (!cp) {
1967c478bd9Sstevel@tonic-gate 	if (krb5_cc_dfl_ops)
197505d05c7Sgtb 	    return (*krb5_cc_dfl_ops->resolve)(context, cache, name);
1987c478bd9Sstevel@tonic-gate 	else
1997c478bd9Sstevel@tonic-gate 	    return KRB5_CC_BADNAME;
2007c478bd9Sstevel@tonic-gate     }
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate     pfxlen = cp - name;
2037c478bd9Sstevel@tonic-gate 
204159d09a2SMark Phalan     if ( pfxlen == 1 && isalpha((unsigned char) name[0]) ) {
205159d09a2SMark Phalan         /* We found a drive letter not a prefix - use FILE */
206159d09a2SMark Phalan         pfx = strdup("FILE");
207505d05c7Sgtb         if (!pfx)
208505d05c7Sgtb             return ENOMEM;
209505d05c7Sgtb 
210505d05c7Sgtb         resid = name;
211505d05c7Sgtb     } else {
212505d05c7Sgtb         resid = name + pfxlen + 1;
213505d05c7Sgtb 
214505d05c7Sgtb         pfx = malloc (pfxlen+1);
215505d05c7Sgtb         if (!pfx)
216505d05c7Sgtb             return ENOMEM;
217505d05c7Sgtb 
218505d05c7Sgtb         memcpy (pfx, name, pfxlen);
219505d05c7Sgtb         pfx[pfxlen] = '\0';
220505d05c7Sgtb     }
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate     *cache = (krb5_ccache) 0;
2237c478bd9Sstevel@tonic-gate 
224159d09a2SMark Phalan     err = krb5int_cc_getops(context, pfx, &ops);
225159d09a2SMark Phalan     if (pfx != NULL)
226505d05c7Sgtb 	free(pfx);
227159d09a2SMark Phalan     if (err)
228505d05c7Sgtb 	return err;
229159d09a2SMark Phalan 
230159d09a2SMark Phalan     return ops->resolve(context, cache, resid);
231159d09a2SMark Phalan }
232159d09a2SMark Phalan 
233159d09a2SMark Phalan /*
234159d09a2SMark Phalan  * cc_getops
235159d09a2SMark Phalan  *
236159d09a2SMark Phalan  * Internal function to return the ops vector for a given ccache
237159d09a2SMark Phalan  * prefix string.
238159d09a2SMark Phalan  */
239159d09a2SMark Phalan static krb5_error_code
krb5int_cc_getops(krb5_context context,const char * pfx,const krb5_cc_ops ** ops)240159d09a2SMark Phalan krb5int_cc_getops(
241159d09a2SMark Phalan     krb5_context context,
242159d09a2SMark Phalan     const char *pfx,
243159d09a2SMark Phalan     const krb5_cc_ops **ops)
244159d09a2SMark Phalan {
245159d09a2SMark Phalan     krb5_error_code err;
246159d09a2SMark Phalan     struct krb5_cc_typelist *tlist;
247159d09a2SMark Phalan 
248159d09a2SMark Phalan     err = k5_mutex_lock(&cc_typelist_lock);
249159d09a2SMark Phalan     if (err)
250159d09a2SMark Phalan 	return err;
251159d09a2SMark Phalan 
2527c478bd9Sstevel@tonic-gate     for (tlist = cc_typehead; tlist; tlist = tlist->next) {
2537c478bd9Sstevel@tonic-gate 	if (strcmp (tlist->ops->prefix, pfx) == 0) {
254159d09a2SMark Phalan 	    *ops = tlist->ops;
255505d05c7Sgtb 	    k5_mutex_unlock(&cc_typelist_lock);
256159d09a2SMark Phalan 	    return 0;
2577c478bd9Sstevel@tonic-gate 	}
2587c478bd9Sstevel@tonic-gate     }
259505d05c7Sgtb     k5_mutex_unlock(&cc_typelist_lock);
2607c478bd9Sstevel@tonic-gate     if (krb5_cc_dfl_ops && !strcmp (pfx, krb5_cc_dfl_ops->prefix)) {
261159d09a2SMark Phalan 	*ops = krb5_cc_dfl_ops;
262159d09a2SMark Phalan 	return 0;
2637c478bd9Sstevel@tonic-gate     }
2647c478bd9Sstevel@tonic-gate     return KRB5_CC_UNKNOWN_TYPE;
2657c478bd9Sstevel@tonic-gate }
266159d09a2SMark Phalan 
267159d09a2SMark Phalan /*
268159d09a2SMark Phalan  * cc_new_unique
269159d09a2SMark Phalan  *
270159d09a2SMark Phalan  * Generate a new unique ccache, given a ccache type and a hint
271159d09a2SMark Phalan  * string.  Ignores the hint string for now.
272159d09a2SMark Phalan  */
273159d09a2SMark Phalan krb5_error_code KRB5_CALLCONV
krb5_cc_new_unique(krb5_context context,const char * type,const char * hint,krb5_ccache * id)274159d09a2SMark Phalan krb5_cc_new_unique(
275159d09a2SMark Phalan     krb5_context context,
276159d09a2SMark Phalan     const char *type,
277159d09a2SMark Phalan     const char *hint,
278159d09a2SMark Phalan     krb5_ccache *id)
279159d09a2SMark Phalan {
280159d09a2SMark Phalan     const krb5_cc_ops *ops;
281159d09a2SMark Phalan     krb5_error_code err;
282159d09a2SMark Phalan 
283159d09a2SMark Phalan     *id = NULL;
284159d09a2SMark Phalan 
285159d09a2SMark Phalan     err = krb5int_cc_getops(context, type, &ops);
286159d09a2SMark Phalan     if (err)
287159d09a2SMark Phalan 	return err;
288159d09a2SMark Phalan 
289159d09a2SMark Phalan     return ops->gen_new(context, id);
290159d09a2SMark Phalan }
291159d09a2SMark Phalan 
292159d09a2SMark Phalan /*
293159d09a2SMark Phalan  * cc_typecursor
294159d09a2SMark Phalan  *
295159d09a2SMark Phalan  * Note: to avoid copying the typelist at cursor creation time, among
296159d09a2SMark Phalan  * other things, we assume that the only additions ever occur to the
297159d09a2SMark Phalan  * typelist.
298159d09a2SMark Phalan  */
299159d09a2SMark Phalan krb5_error_code
krb5int_cc_typecursor_new(krb5_context context,krb5_cc_typecursor * t)300159d09a2SMark Phalan krb5int_cc_typecursor_new(krb5_context context, krb5_cc_typecursor *t)
301159d09a2SMark Phalan {
302159d09a2SMark Phalan     krb5_error_code err = 0;
303159d09a2SMark Phalan     krb5_cc_typecursor n = NULL;
304159d09a2SMark Phalan 
305159d09a2SMark Phalan     *t = NULL;
306159d09a2SMark Phalan     n = malloc(sizeof(*n));
307159d09a2SMark Phalan     if (n == NULL)
308159d09a2SMark Phalan 	return ENOMEM;
309159d09a2SMark Phalan 
310159d09a2SMark Phalan     err = k5_mutex_lock(&cc_typelist_lock);
311159d09a2SMark Phalan     if (err)
312159d09a2SMark Phalan 	goto errout;
313159d09a2SMark Phalan     n->tptr = cc_typehead;
314159d09a2SMark Phalan     err = k5_mutex_unlock(&cc_typelist_lock);
315159d09a2SMark Phalan     if (err)
316159d09a2SMark Phalan 	goto errout;
317159d09a2SMark Phalan 
318159d09a2SMark Phalan     *t = n;
319159d09a2SMark Phalan errout:
320159d09a2SMark Phalan     if (err)
321159d09a2SMark Phalan 	free(n);
322159d09a2SMark Phalan     return err;
323159d09a2SMark Phalan }
324159d09a2SMark Phalan 
325159d09a2SMark Phalan krb5_error_code
krb5int_cc_typecursor_next(krb5_context context,krb5_cc_typecursor t,const krb5_cc_ops ** ops)326159d09a2SMark Phalan krb5int_cc_typecursor_next(
327159d09a2SMark Phalan     krb5_context context,
328159d09a2SMark Phalan     krb5_cc_typecursor t,
329159d09a2SMark Phalan     const krb5_cc_ops **ops)
330159d09a2SMark Phalan {
331159d09a2SMark Phalan     krb5_error_code err = 0;
332159d09a2SMark Phalan 
333159d09a2SMark Phalan     *ops = NULL;
334159d09a2SMark Phalan     if (t->tptr == NULL)
335159d09a2SMark Phalan 	return 0;
336159d09a2SMark Phalan 
337159d09a2SMark Phalan     err = k5_mutex_lock(&cc_typelist_lock);
338159d09a2SMark Phalan     if (err)
339159d09a2SMark Phalan 	goto errout;
340159d09a2SMark Phalan     *ops = t->tptr->ops;
341159d09a2SMark Phalan     t->tptr = t->tptr->next;
342159d09a2SMark Phalan     err = k5_mutex_unlock(&cc_typelist_lock);
343159d09a2SMark Phalan     if (err)
344159d09a2SMark Phalan 	goto errout;
345159d09a2SMark Phalan 
346159d09a2SMark Phalan errout:
347159d09a2SMark Phalan     return err;
348159d09a2SMark Phalan }
349159d09a2SMark Phalan 
350159d09a2SMark Phalan krb5_error_code
krb5int_cc_typecursor_free(krb5_context context,krb5_cc_typecursor * t)351159d09a2SMark Phalan krb5int_cc_typecursor_free(krb5_context context, krb5_cc_typecursor *t)
352159d09a2SMark Phalan {
353159d09a2SMark Phalan     free(*t);
354159d09a2SMark Phalan     *t = NULL;
355159d09a2SMark Phalan     return 0;
356159d09a2SMark Phalan }
357