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