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.
11505d05c7Sgtb  *
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.
25505d05c7Sgtb  *
267c478bd9Sstevel@tonic-gate  *
277c478bd9Sstevel@tonic-gate  * Registration functions for ccache.
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate 
30d51f1d33Smp /*
31*159d09a2SMark 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 };
46*159d09a2SMark Phalan 
47*159d09a2SMark Phalan struct krb5_cc_typecursor {
48*159d09a2SMark Phalan     struct krb5_cc_typelist *tptr;
49*159d09a2SMark Phalan };
50*159d09a2SMark Phalan /* typedef krb5_cc_typecursor in k5-int.h */
51*159d09a2SMark Phalan 
52505d05c7Sgtb extern const krb5_cc_ops krb5_mcc_ops;
53*159d09a2SMark Phalan #ifdef USE_KEYRING_CCACHE
54*159d09a2SMark Phalan extern const krb5_cc_ops krb5_krcc_ops;
55*159d09a2SMark 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
62*159d09a2SMark Phalan 
63*159d09a2SMark Phalan #ifdef USE_CCAPI_V3
64*159d09a2SMark Phalan extern const krb5_cc_ops krb5_cc_stdcc_ops;
65*159d09a2SMark Phalan static struct krb5_cc_typelist cc_stdcc_entry = { &krb5_cc_stdcc_ops, NULL };
66*159d09a2SMark Phalan static struct krb5_cc_typelist cc_mcc_entry = { &krb5_mcc_ops, &cc_stdcc_entry };
67*159d09a2SMark Phalan #else
68*159d09a2SMark Phalan 
69505d05c7Sgtb static struct krb5_cc_typelist cc_mcc_entry = { &krb5_mcc_ops, NULL };
70*159d09a2SMark Phalan #endif /* USE_CCAPI_V3 */
71*159d09a2SMark Phalan 
72*159d09a2SMark Phalan #ifdef USE_KEYRING_CCACHE
73*159d09a2SMark Phalan static struct krb5_cc_typelist cc_file_entry = { &krb5_cc_file_ops,
74*159d09a2SMark Phalan 						 &cc_mcc_entry };
75*159d09a2SMark Phalan static struct krb5_cc_typelist cc_krcc_entry = { &krb5_krcc_ops,
76*159d09a2SMark Phalan 						 &cc_file_entry };
77*159d09a2SMark 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 };
82*159d09a2SMark Phalan #ifdef USE_KEYRING_CCACHE
83*159d09a2SMark Phalan #define INITIAL_TYPEHEAD (&cc_krcc_entry)
84*159d09a2SMark Phalan #else
85*159d09a2SMark Phalan #define INITIAL_TYPEHEAD (&cc_fcc_entry)
86*159d09a2SMark Phalan #endif
87*159d09a2SMark Phalan static struct krb5_cc_typelist *cc_typehead = INITIAL_TYPEHEAD;
88505d05c7Sgtb static k5_mutex_t cc_typelist_lock = K5_MUTEX_PARTIAL_INITIALIZER;
89505d05c7Sgtb 
90*159d09a2SMark Phalan static krb5_error_code
91*159d09a2SMark Phalan krb5int_cc_getops(krb5_context, const char *, const krb5_cc_ops **);
92*159d09a2SMark Phalan 
93505d05c7Sgtb int
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;
107*159d09a2SMark Phalan #ifdef USE_KEYRING_CCACHE
108*159d09a2SMark Phalan     err = k5_mutex_finish_init(&krb5int_krcc_mutex);
109*159d09a2SMark Phalan     if (err)
110*159d09a2SMark Phalan 	return err;
111*159d09a2SMark Phalan #endif
112505d05c7Sgtb     return 0;
113505d05c7Sgtb }
114505d05c7Sgtb 
115505d05c7Sgtb 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);
122*159d09a2SMark Phalan #ifdef USE_KEYRING_CCACHE
123*159d09a2SMark Phalan     k5_mutex_destroy(&krb5int_krcc_mutex);
124*159d09a2SMark Phalan #endif
125*159d09a2SMark 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
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
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;
187*159d09a2SMark Phalan     const krb5_cc_ops *ops;
188505d05c7Sgtb 
189d51f1d33Smp     /* Solaris Kerberos */
190d51f1d33Smp     if (!name)
191d51f1d33Smp         return KRB5_CC_BADNAME;
192d51f1d33Smp 
193*159d09a2SMark 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 
204*159d09a2SMark Phalan     if ( pfxlen == 1 && isalpha((unsigned char) name[0]) ) {
205*159d09a2SMark Phalan         /* We found a drive letter not a prefix - use FILE */
206*159d09a2SMark 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 
224*159d09a2SMark Phalan     err = krb5int_cc_getops(context, pfx, &ops);
225*159d09a2SMark Phalan     if (pfx != NULL)
226505d05c7Sgtb 	free(pfx);
227*159d09a2SMark Phalan     if (err)
228505d05c7Sgtb 	return err;
229*159d09a2SMark Phalan 
230*159d09a2SMark Phalan     return ops->resolve(context, cache, resid);
231*159d09a2SMark Phalan }
232*159d09a2SMark Phalan 
233*159d09a2SMark Phalan /*
234*159d09a2SMark Phalan  * cc_getops
235*159d09a2SMark Phalan  *
236*159d09a2SMark Phalan  * Internal function to return the ops vector for a given ccache
237*159d09a2SMark Phalan  * prefix string.
238*159d09a2SMark Phalan  */
239*159d09a2SMark Phalan static krb5_error_code
240*159d09a2SMark Phalan krb5int_cc_getops(
241*159d09a2SMark Phalan     krb5_context context,
242*159d09a2SMark Phalan     const char *pfx,
243*159d09a2SMark Phalan     const krb5_cc_ops **ops)
244*159d09a2SMark Phalan {
245*159d09a2SMark Phalan     krb5_error_code err;
246*159d09a2SMark Phalan     struct krb5_cc_typelist *tlist;
247*159d09a2SMark Phalan 
248*159d09a2SMark Phalan     err = k5_mutex_lock(&cc_typelist_lock);
249*159d09a2SMark Phalan     if (err)
250*159d09a2SMark Phalan 	return err;
251*159d09a2SMark Phalan 
2527c478bd9Sstevel@tonic-gate     for (tlist = cc_typehead; tlist; tlist = tlist->next) {
2537c478bd9Sstevel@tonic-gate 	if (strcmp (tlist->ops->prefix, pfx) == 0) {
254*159d09a2SMark Phalan 	    *ops = tlist->ops;
255505d05c7Sgtb 	    k5_mutex_unlock(&cc_typelist_lock);
256*159d09a2SMark 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)) {
261*159d09a2SMark Phalan 	*ops = krb5_cc_dfl_ops;
262*159d09a2SMark Phalan 	return 0;
2637c478bd9Sstevel@tonic-gate     }
2647c478bd9Sstevel@tonic-gate     return KRB5_CC_UNKNOWN_TYPE;
2657c478bd9Sstevel@tonic-gate }
266*159d09a2SMark Phalan 
267*159d09a2SMark Phalan /*
268*159d09a2SMark Phalan  * cc_new_unique
269*159d09a2SMark Phalan  *
270*159d09a2SMark Phalan  * Generate a new unique ccache, given a ccache type and a hint
271*159d09a2SMark Phalan  * string.  Ignores the hint string for now.
272*159d09a2SMark Phalan  */
273*159d09a2SMark Phalan krb5_error_code KRB5_CALLCONV
274*159d09a2SMark Phalan krb5_cc_new_unique(
275*159d09a2SMark Phalan     krb5_context context,
276*159d09a2SMark Phalan     const char *type,
277*159d09a2SMark Phalan     const char *hint,
278*159d09a2SMark Phalan     krb5_ccache *id)
279*159d09a2SMark Phalan {
280*159d09a2SMark Phalan     const krb5_cc_ops *ops;
281*159d09a2SMark Phalan     krb5_error_code err;
282*159d09a2SMark Phalan 
283*159d09a2SMark Phalan     *id = NULL;
284*159d09a2SMark Phalan 
285*159d09a2SMark Phalan     err = krb5int_cc_getops(context, type, &ops);
286*159d09a2SMark Phalan     if (err)
287*159d09a2SMark Phalan 	return err;
288*159d09a2SMark Phalan 
289*159d09a2SMark Phalan     return ops->gen_new(context, id);
290*159d09a2SMark Phalan }
291*159d09a2SMark Phalan 
292*159d09a2SMark Phalan /*
293*159d09a2SMark Phalan  * cc_typecursor
294*159d09a2SMark Phalan  *
295*159d09a2SMark Phalan  * Note: to avoid copying the typelist at cursor creation time, among
296*159d09a2SMark Phalan  * other things, we assume that the only additions ever occur to the
297*159d09a2SMark Phalan  * typelist.
298*159d09a2SMark Phalan  */
299*159d09a2SMark Phalan krb5_error_code
300*159d09a2SMark Phalan krb5int_cc_typecursor_new(krb5_context context, krb5_cc_typecursor *t)
301*159d09a2SMark Phalan {
302*159d09a2SMark Phalan     krb5_error_code err = 0;
303*159d09a2SMark Phalan     krb5_cc_typecursor n = NULL;
304*159d09a2SMark Phalan 
305*159d09a2SMark Phalan     *t = NULL;
306*159d09a2SMark Phalan     n = malloc(sizeof(*n));
307*159d09a2SMark Phalan     if (n == NULL)
308*159d09a2SMark Phalan 	return ENOMEM;
309*159d09a2SMark Phalan 
310*159d09a2SMark Phalan     err = k5_mutex_lock(&cc_typelist_lock);
311*159d09a2SMark Phalan     if (err)
312*159d09a2SMark Phalan 	goto errout;
313*159d09a2SMark Phalan     n->tptr = cc_typehead;
314*159d09a2SMark Phalan     err = k5_mutex_unlock(&cc_typelist_lock);
315*159d09a2SMark Phalan     if (err)
316*159d09a2SMark Phalan 	goto errout;
317*159d09a2SMark Phalan 
318*159d09a2SMark Phalan     *t = n;
319*159d09a2SMark Phalan errout:
320*159d09a2SMark Phalan     if (err)
321*159d09a2SMark Phalan 	free(n);
322*159d09a2SMark Phalan     return err;
323*159d09a2SMark Phalan }
324*159d09a2SMark Phalan 
325*159d09a2SMark Phalan krb5_error_code
326*159d09a2SMark Phalan krb5int_cc_typecursor_next(
327*159d09a2SMark Phalan     krb5_context context,
328*159d09a2SMark Phalan     krb5_cc_typecursor t,
329*159d09a2SMark Phalan     const krb5_cc_ops **ops)
330*159d09a2SMark Phalan {
331*159d09a2SMark Phalan     krb5_error_code err = 0;
332*159d09a2SMark Phalan 
333*159d09a2SMark Phalan     *ops = NULL;
334*159d09a2SMark Phalan     if (t->tptr == NULL)
335*159d09a2SMark Phalan 	return 0;
336*159d09a2SMark Phalan 
337*159d09a2SMark Phalan     err = k5_mutex_lock(&cc_typelist_lock);
338*159d09a2SMark Phalan     if (err)
339*159d09a2SMark Phalan 	goto errout;
340*159d09a2SMark Phalan     *ops = t->tptr->ops;
341*159d09a2SMark Phalan     t->tptr = t->tptr->next;
342*159d09a2SMark Phalan     err = k5_mutex_unlock(&cc_typelist_lock);
343*159d09a2SMark Phalan     if (err)
344*159d09a2SMark Phalan 	goto errout;
345*159d09a2SMark Phalan 
346*159d09a2SMark Phalan errout:
347*159d09a2SMark Phalan     return err;
348*159d09a2SMark Phalan }
349*159d09a2SMark Phalan 
350*159d09a2SMark Phalan krb5_error_code
351*159d09a2SMark Phalan krb5int_cc_typecursor_free(krb5_context context, krb5_cc_typecursor *t)
352*159d09a2SMark Phalan {
353*159d09a2SMark Phalan     free(*t);
354*159d09a2SMark Phalan     *t = NULL;
355*159d09a2SMark Phalan     return 0;
356*159d09a2SMark Phalan }
357