xref: /freebsd/crypto/heimdal/lib/krb5/cache.c (revision daf1cffce2e07931f27c6c6998652e90df6ba87e)
1 /*
2  * Copyright (c) 1997-1999 Kungliga Tekniska H�gskolan
3  * (Royal Institute of Technology, Stockholm, Sweden).
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of the Institute nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #include "krb5_locl.h"
35 
36 RCSID("$Id: cache.c,v 1.44 1999/12/02 17:05:08 joda Exp $");
37 
38 /*
39  * Add a new ccache type with operations `ops', overwriting any
40  * existing one if `override'.
41  * Return an error code or 0.
42  */
43 
44 krb5_error_code
45 krb5_cc_register(krb5_context context,
46 		 const krb5_cc_ops *ops,
47 		 krb5_boolean override)
48 {
49     int i;
50 
51     for(i = 0; i < context->num_cc_ops && context->cc_ops[i].prefix; i++) {
52 	if(strcmp(context->cc_ops[i].prefix, ops->prefix) == 0) {
53 	    if(override)
54 		free(context->cc_ops[i].prefix);
55 	    else
56 		return KRB5_CC_TYPE_EXISTS;
57 	}
58     }
59     if(i == context->num_cc_ops) {
60 	krb5_cc_ops *o = realloc(context->cc_ops,
61 				 (context->num_cc_ops + 1) *
62 				 sizeof(*context->cc_ops));
63 	if(o == NULL)
64 	    return KRB5_CC_NOMEM;
65 	context->num_cc_ops++;
66 	context->cc_ops = o;
67 	memset(context->cc_ops + i, 0,
68 	       (context->num_cc_ops - i) * sizeof(*context->cc_ops));
69     }
70     memcpy(&context->cc_ops[i], ops, sizeof(context->cc_ops[i]));
71     context->cc_ops[i].prefix = strdup(ops->prefix);
72     if(context->cc_ops[i].prefix == NULL)
73 	return KRB5_CC_NOMEM;
74 
75     return 0;
76 }
77 
78 /*
79  * Allocate memory for a new ccache in `id' with operations `ops'
80  * and name `residual'.
81  * Return 0 or an error code.
82  */
83 
84 static krb5_error_code
85 allocate_ccache (krb5_context context,
86 		 const krb5_cc_ops *ops,
87 		 const char *residual,
88 		 krb5_ccache *id)
89 {
90     krb5_error_code ret;
91     krb5_ccache p;
92 
93     p = malloc(sizeof(*p));
94     if(p == NULL)
95 	return KRB5_CC_NOMEM;
96     p->ops = ops;
97     *id = p;
98     ret = p->ops->resolve(context, id, residual);
99     if(ret)
100 	free(p);
101     return ret;
102 }
103 
104 /*
105  * Find and allocate a ccache in `id' from the specification in `residual'.
106  * If the ccache name doesn't contain any colon, interpret it as a file name.
107  * Return 0 or an error code.
108  */
109 
110 krb5_error_code
111 krb5_cc_resolve(krb5_context context,
112 		const char *name,
113 		krb5_ccache *id)
114 {
115     int i;
116 
117     for(i = 0; i < context->num_cc_ops && context->cc_ops[i].prefix; i++) {
118 	size_t prefix_len = strlen(context->cc_ops[i].prefix);
119 
120 	if(strncmp(context->cc_ops[i].prefix, name, prefix_len) == 0
121 	   && name[prefix_len] == ':') {
122 	    return allocate_ccache (context, &context->cc_ops[i],
123 				    name + prefix_len + 1,
124 				    id);
125 	}
126     }
127     if (strchr (name, ':') == NULL)
128 	return allocate_ccache (context, &krb5_fcc_ops, name, id);
129     else
130 	return KRB5_CC_UNKNOWN_TYPE;
131 }
132 
133 /*
134  * Generate a new ccache of type `ops' in `id'.
135  * Return 0 or an error code.
136  */
137 
138 krb5_error_code
139 krb5_cc_gen_new(krb5_context context,
140 		const krb5_cc_ops *ops,
141 		krb5_ccache *id)
142 {
143     krb5_ccache p;
144 
145     p = malloc (sizeof(*p));
146     if (p == NULL)
147 	return KRB5_CC_NOMEM;
148     p->ops = ops;
149     *id = p;
150     return p->ops->gen_new(context, id);
151 }
152 
153 /*
154  * Return the name of the ccache `id'
155  */
156 
157 const char*
158 krb5_cc_get_name(krb5_context context,
159 		 krb5_ccache id)
160 {
161     return id->ops->get_name(context, id);
162 }
163 
164 /*
165  * Return the type of the ccache `id'.
166  */
167 
168 const char*
169 krb5_cc_get_type(krb5_context context,
170 		 krb5_ccache id)
171 {
172     return id->ops->prefix;
173 }
174 
175 /*
176  * Return a pointer to a static string containing the default ccache name.
177  */
178 
179 const char*
180 krb5_cc_default_name(krb5_context context)
181 {
182     static char name[1024];
183     char *p;
184 
185     p = getenv("KRB5CCNAME");
186     if(p)
187 	strlcpy (name, p, sizeof(name));
188     else
189 	snprintf(name,
190 		 sizeof(name),
191 		 "FILE:/tmp/krb5cc_%u",
192 		 (unsigned)getuid());
193     return name;
194 }
195 
196 /*
197  * Open the default ccache in `id'.
198  * Return 0 or an error code.
199  */
200 
201 krb5_error_code
202 krb5_cc_default(krb5_context context,
203 		krb5_ccache *id)
204 {
205     return krb5_cc_resolve(context,
206 			   krb5_cc_default_name(context),
207 			   id);
208 }
209 
210 /*
211  * Create a new ccache in `id' for `primary_principal'.
212  * Return 0 or an error code.
213  */
214 
215 krb5_error_code
216 krb5_cc_initialize(krb5_context context,
217 		   krb5_ccache id,
218 		   krb5_principal primary_principal)
219 {
220     return id->ops->init(context, id, primary_principal);
221 }
222 
223 
224 /*
225  * Remove the ccache `id'.
226  * Return 0 or an error code.
227  */
228 
229 krb5_error_code
230 krb5_cc_destroy(krb5_context context,
231 		krb5_ccache id)
232 {
233     krb5_error_code ret;
234 
235     ret = id->ops->destroy(context, id);
236     krb5_cc_close (context, id);
237     return ret;
238 }
239 
240 /*
241  * Stop using the ccache `id' and free the related resources.
242  * Return 0 or an error code.
243  */
244 
245 krb5_error_code
246 krb5_cc_close(krb5_context context,
247 	      krb5_ccache id)
248 {
249     krb5_error_code ret;
250     ret = id->ops->close(context, id);
251     free(id);
252     return ret;
253 }
254 
255 /*
256  * Store `creds' in the ccache `id'.
257  * Return 0 or an error code.
258  */
259 
260 krb5_error_code
261 krb5_cc_store_cred(krb5_context context,
262 		   krb5_ccache id,
263 		   krb5_creds *creds)
264 {
265     return id->ops->store(context, id, creds);
266 }
267 
268 /*
269  * Retrieve the credential identified by `mcreds' (and `whichfields')
270  * from `id' in `creds'.
271  * Return 0 or an error code.
272  */
273 
274 krb5_error_code
275 krb5_cc_retrieve_cred(krb5_context context,
276 		      krb5_ccache id,
277 		      krb5_flags whichfields,
278 		      const krb5_creds *mcreds,
279 		      krb5_creds *creds)
280 {
281     krb5_error_code ret;
282     krb5_cc_cursor cursor;
283     krb5_cc_start_seq_get(context, id, &cursor);
284     while((ret = krb5_cc_next_cred(context, id, creds, &cursor)) == 0){
285 	if(krb5_compare_creds(context, whichfields, mcreds, creds)){
286 	    ret = 0;
287 	    break;
288 	}
289 	krb5_free_creds_contents (context, creds);
290     }
291     krb5_cc_end_seq_get(context, id, &cursor);
292     return ret;
293 }
294 
295 /*
296  * Return the principal of `id' in `principal'.
297  * Return 0 or an error code.
298  */
299 
300 krb5_error_code
301 krb5_cc_get_principal(krb5_context context,
302 		      krb5_ccache id,
303 		      krb5_principal *principal)
304 {
305     return id->ops->get_princ(context, id, principal);
306 }
307 
308 /*
309  * Start iterating over `id', `cursor' is initialized to the
310  * beginning.
311  * Return 0 or an error code.
312  */
313 
314 krb5_error_code
315 krb5_cc_start_seq_get (krb5_context context,
316 		       const krb5_ccache id,
317 		       krb5_cc_cursor *cursor)
318 {
319     return id->ops->get_first(context, id, cursor);
320 }
321 
322 /*
323  * Retrieve the next cred pointed to by (`id', `cursor') in `creds'
324  * and advance `cursor'.
325  * Return 0 or an error code.
326  */
327 
328 krb5_error_code
329 krb5_cc_next_cred (krb5_context context,
330 		   const krb5_ccache id,
331 		   krb5_creds *creds,
332 		   krb5_cc_cursor *cursor)
333 {
334     return id->ops->get_next(context, id, cursor, creds);
335 }
336 
337 /*
338  * Destroy the cursor `cursor'.
339  */
340 
341 krb5_error_code
342 krb5_cc_end_seq_get (krb5_context context,
343 		     const krb5_ccache id,
344 		     krb5_cc_cursor *cursor)
345 {
346     return id->ops->end_get(context, id, cursor);
347 }
348 
349 /*
350  * Remove the credential identified by `cred', `which' from `id'.
351  */
352 
353 krb5_error_code
354 krb5_cc_remove_cred(krb5_context context,
355 		    krb5_ccache id,
356 		    krb5_flags which,
357 		    krb5_creds *cred)
358 {
359     return id->ops->remove_cred(context, id, which, cred);
360 }
361 
362 /*
363  * Set the flags of `id' to `flags'.
364  */
365 
366 krb5_error_code
367 krb5_cc_set_flags(krb5_context context,
368 		  krb5_ccache id,
369 		  krb5_flags flags)
370 {
371     return id->ops->set_flags(context, id, flags);
372 }
373 
374 /*
375  * Copy the contents of `from' to `to'.
376  */
377 
378 krb5_error_code
379 krb5_cc_copy_cache(krb5_context context,
380 		   const krb5_ccache from,
381 		   krb5_ccache to)
382 {
383     krb5_error_code ret;
384     krb5_cc_cursor cursor;
385     krb5_creds cred;
386     krb5_principal princ;
387 
388     ret = krb5_cc_get_principal(context, from, &princ);
389     if(ret)
390 	return ret;
391     ret = krb5_cc_initialize(context, to, princ);
392     if(ret){
393 	krb5_free_principal(context, princ);
394 	return ret;
395     }
396     ret = krb5_cc_start_seq_get(context, from, &cursor);
397     if(ret){
398 	krb5_free_principal(context, princ);
399 	return ret;
400     }
401     while(ret == 0 && krb5_cc_next_cred(context, from, &cred, &cursor) == 0){
402 	ret = krb5_cc_store_cred(context, to, &cred);
403 	krb5_free_creds_contents (context, &cred);
404     }
405     krb5_cc_end_seq_get(context, from, &cursor);
406     krb5_free_principal(context, princ);
407     return ret;
408 }
409 
410 /*
411  * Return the version of `id'.
412  */
413 
414 krb5_error_code
415 krb5_cc_get_version(krb5_context context,
416 		    const krb5_ccache id)
417 {
418     if(id->ops->get_version)
419 	return id->ops->get_version(context, id);
420     else
421 	return 0;
422 }
423