1 /*
2  * lib/krb5/ccache/ccbase.c
3  *
4  * Copyright 1990,2004 by the Massachusetts Institute of Technology.
5  * All Rights Reserved.
6  *
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.
11  *
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.
25  *
26  *
27  * Registration functions for ccache.
28  */
29 
30 /*
31  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
32  * Use is subject to license terms.
33  */
34 
35 
36 #include "k5-int.h"
37 #include "k5-thread.h"
38 
39 #include "fcc.h"
40 #include "cc-int.h"
41 
42 struct krb5_cc_typelist {
43     const krb5_cc_ops *ops;
44     struct krb5_cc_typelist *next;
45 };
46 
47 struct krb5_cc_typecursor {
48     struct krb5_cc_typelist *tptr;
49 };
50 /* typedef krb5_cc_typecursor in k5-int.h */
51 
52 extern const krb5_cc_ops krb5_mcc_ops;
53 #ifdef USE_KEYRING_CCACHE
54 extern const krb5_cc_ops krb5_krcc_ops;
55 #endif
56 
57 #ifdef _WIN32
58 extern const krb5_cc_ops krb5_lcc_ops;
59 static struct krb5_cc_typelist cc_lcc_entry = { &krb5_lcc_ops, NULL };
60 static struct krb5_cc_typelist cc_mcc_entry = { &krb5_mcc_ops, &cc_lcc_entry };
61 #else
62 
63 #ifdef USE_CCAPI_V3
64 extern const krb5_cc_ops krb5_cc_stdcc_ops;
65 static struct krb5_cc_typelist cc_stdcc_entry = { &krb5_cc_stdcc_ops, NULL };
66 static struct krb5_cc_typelist cc_mcc_entry = { &krb5_mcc_ops, &cc_stdcc_entry };
67 #else
68 
69 static struct krb5_cc_typelist cc_mcc_entry = { &krb5_mcc_ops, NULL };
70 #endif /* USE_CCAPI_V3 */
71 
72 #ifdef USE_KEYRING_CCACHE
73 static struct krb5_cc_typelist cc_file_entry = { &krb5_cc_file_ops,
74 						 &cc_mcc_entry };
75 static struct krb5_cc_typelist cc_krcc_entry = { &krb5_krcc_ops,
76 						 &cc_file_entry };
77 #endif /* USE_KEYRING_CCACHE */
78 #endif
79 
80 static struct krb5_cc_typelist cc_fcc_entry = { &krb5_cc_file_ops,
81 						&cc_mcc_entry };
82 #ifdef USE_KEYRING_CCACHE
83 #define INITIAL_TYPEHEAD (&cc_krcc_entry)
84 #else
85 #define INITIAL_TYPEHEAD (&cc_fcc_entry)
86 #endif
87 static struct krb5_cc_typelist *cc_typehead = INITIAL_TYPEHEAD;
88 static k5_mutex_t cc_typelist_lock = K5_MUTEX_PARTIAL_INITIALIZER;
89 
90 static krb5_error_code
91 krb5int_cc_getops(krb5_context, const char *, const krb5_cc_ops **);
92 
93 int
krb5int_cc_initialize(void)94 krb5int_cc_initialize(void)
95 {
96     int err;
97 
98     err = k5_mutex_finish_init(&krb5int_mcc_mutex);
99     if (err)
100 	return err;
101     err = k5_mutex_finish_init(&cc_typelist_lock);
102     if (err)
103 	return err;
104     err = k5_mutex_finish_init(&krb5int_cc_file_mutex);
105     if (err)
106 	return err;
107 #ifdef USE_KEYRING_CCACHE
108     err = k5_mutex_finish_init(&krb5int_krcc_mutex);
109     if (err)
110 	return err;
111 #endif
112     return 0;
113 }
114 
115 void
krb5int_cc_finalize(void)116 krb5int_cc_finalize(void)
117 {
118     struct krb5_cc_typelist *t, *t_next;
119     k5_mutex_destroy(&cc_typelist_lock);
120     k5_mutex_destroy(&krb5int_cc_file_mutex);
121     k5_mutex_destroy(&krb5int_mcc_mutex);
122 #ifdef USE_KEYRING_CCACHE
123     k5_mutex_destroy(&krb5int_krcc_mutex);
124 #endif
125     for (t = cc_typehead; t != INITIAL_TYPEHEAD; t = t_next) {
126 	t_next = t->next;
127 	free(t);
128     }
129 }
130 
131 
132 /*
133  * Register a new credentials cache type
134  * If override is set, replace any existing ccache with that type tag
135  */
136 
137 krb5_error_code KRB5_CALLCONV
krb5_cc_register(krb5_context context,krb5_cc_ops * ops,krb5_boolean override)138 krb5_cc_register(krb5_context context, krb5_cc_ops *ops, krb5_boolean override)
139 {
140     struct krb5_cc_typelist *t;
141     krb5_error_code err;
142 
143     err = k5_mutex_lock(&cc_typelist_lock);
144     if (err)
145 	return err;
146     for (t = cc_typehead;t && strcmp(t->ops->prefix,ops->prefix);t = t->next)
147 	;
148     if (t) {
149 	if (override) {
150 	    t->ops = ops;
151 	    k5_mutex_unlock(&cc_typelist_lock);
152 	    return 0;
153 	} else {
154 	    k5_mutex_unlock(&cc_typelist_lock);
155 	    return KRB5_CC_TYPE_EXISTS;
156 	}
157     }
158     if (!(t = (struct krb5_cc_typelist *) malloc(sizeof(*t)))) {
159 	k5_mutex_unlock(&cc_typelist_lock);
160 	return ENOMEM;
161     }
162     t->next = cc_typehead;
163     t->ops = ops;
164     cc_typehead = t;
165     k5_mutex_unlock(&cc_typelist_lock);
166     return 0;
167 }
168 
169 /*
170  * Resolve a credential cache name into a cred. cache object.
171  *
172  * The name is currently constrained to be of the form "type:residual";
173  *
174  * The "type" portion corresponds to one of the predefined credential
175  * cache types, while the "residual" portion is specific to the
176  * particular cache type.
177  */
178 
179 #include <ctype.h>
180 krb5_error_code KRB5_CALLCONV
krb5_cc_resolve(krb5_context context,const char * name,krb5_ccache * cache)181 krb5_cc_resolve (krb5_context context, const char *name, krb5_ccache *cache)
182 {
183     char *pfx, *cp;
184     const char *resid;
185     unsigned int pfxlen;
186     krb5_error_code err;
187     const krb5_cc_ops *ops;
188 
189     /* Solaris Kerberos */
190     if (!name)
191         return KRB5_CC_BADNAME;
192 
193     pfx = NULL;
194     cp = strchr (name, ':');
195     if (!cp) {
196 	if (krb5_cc_dfl_ops)
197 	    return (*krb5_cc_dfl_ops->resolve)(context, cache, name);
198 	else
199 	    return KRB5_CC_BADNAME;
200     }
201 
202     pfxlen = cp - name;
203 
204     if ( pfxlen == 1 && isalpha((unsigned char) name[0]) ) {
205         /* We found a drive letter not a prefix - use FILE */
206         pfx = strdup("FILE");
207         if (!pfx)
208             return ENOMEM;
209 
210         resid = name;
211     } else {
212         resid = name + pfxlen + 1;
213 
214         pfx = malloc (pfxlen+1);
215         if (!pfx)
216             return ENOMEM;
217 
218         memcpy (pfx, name, pfxlen);
219         pfx[pfxlen] = '\0';
220     }
221 
222     *cache = (krb5_ccache) 0;
223 
224     err = krb5int_cc_getops(context, pfx, &ops);
225     if (pfx != NULL)
226 	free(pfx);
227     if (err)
228 	return err;
229 
230     return ops->resolve(context, cache, resid);
231 }
232 
233 /*
234  * cc_getops
235  *
236  * Internal function to return the ops vector for a given ccache
237  * prefix string.
238  */
239 static krb5_error_code
krb5int_cc_getops(krb5_context context,const char * pfx,const krb5_cc_ops ** ops)240 krb5int_cc_getops(
241     krb5_context context,
242     const char *pfx,
243     const krb5_cc_ops **ops)
244 {
245     krb5_error_code err;
246     struct krb5_cc_typelist *tlist;
247 
248     err = k5_mutex_lock(&cc_typelist_lock);
249     if (err)
250 	return err;
251 
252     for (tlist = cc_typehead; tlist; tlist = tlist->next) {
253 	if (strcmp (tlist->ops->prefix, pfx) == 0) {
254 	    *ops = tlist->ops;
255 	    k5_mutex_unlock(&cc_typelist_lock);
256 	    return 0;
257 	}
258     }
259     k5_mutex_unlock(&cc_typelist_lock);
260     if (krb5_cc_dfl_ops && !strcmp (pfx, krb5_cc_dfl_ops->prefix)) {
261 	*ops = krb5_cc_dfl_ops;
262 	return 0;
263     }
264     return KRB5_CC_UNKNOWN_TYPE;
265 }
266 
267 /*
268  * cc_new_unique
269  *
270  * Generate a new unique ccache, given a ccache type and a hint
271  * string.  Ignores the hint string for now.
272  */
273 krb5_error_code KRB5_CALLCONV
krb5_cc_new_unique(krb5_context context,const char * type,const char * hint,krb5_ccache * id)274 krb5_cc_new_unique(
275     krb5_context context,
276     const char *type,
277     const char *hint,
278     krb5_ccache *id)
279 {
280     const krb5_cc_ops *ops;
281     krb5_error_code err;
282 
283     *id = NULL;
284 
285     err = krb5int_cc_getops(context, type, &ops);
286     if (err)
287 	return err;
288 
289     return ops->gen_new(context, id);
290 }
291 
292 /*
293  * cc_typecursor
294  *
295  * Note: to avoid copying the typelist at cursor creation time, among
296  * other things, we assume that the only additions ever occur to the
297  * typelist.
298  */
299 krb5_error_code
krb5int_cc_typecursor_new(krb5_context context,krb5_cc_typecursor * t)300 krb5int_cc_typecursor_new(krb5_context context, krb5_cc_typecursor *t)
301 {
302     krb5_error_code err = 0;
303     krb5_cc_typecursor n = NULL;
304 
305     *t = NULL;
306     n = malloc(sizeof(*n));
307     if (n == NULL)
308 	return ENOMEM;
309 
310     err = k5_mutex_lock(&cc_typelist_lock);
311     if (err)
312 	goto errout;
313     n->tptr = cc_typehead;
314     err = k5_mutex_unlock(&cc_typelist_lock);
315     if (err)
316 	goto errout;
317 
318     *t = n;
319 errout:
320     if (err)
321 	free(n);
322     return err;
323 }
324 
325 krb5_error_code
krb5int_cc_typecursor_next(krb5_context context,krb5_cc_typecursor t,const krb5_cc_ops ** ops)326 krb5int_cc_typecursor_next(
327     krb5_context context,
328     krb5_cc_typecursor t,
329     const krb5_cc_ops **ops)
330 {
331     krb5_error_code err = 0;
332 
333     *ops = NULL;
334     if (t->tptr == NULL)
335 	return 0;
336 
337     err = k5_mutex_lock(&cc_typelist_lock);
338     if (err)
339 	goto errout;
340     *ops = t->tptr->ops;
341     t->tptr = t->tptr->next;
342     err = k5_mutex_unlock(&cc_typelist_lock);
343     if (err)
344 	goto errout;
345 
346 errout:
347     return err;
348 }
349 
350 krb5_error_code
krb5int_cc_typecursor_free(krb5_context context,krb5_cc_typecursor * t)351 krb5int_cc_typecursor_free(krb5_context context, krb5_cc_typecursor *t)
352 {
353     free(*t);
354     *t = NULL;
355     return 0;
356 }
357