xref: /freebsd-src/crypto/heimdal/kcm/cache.c (revision cfe30d02adda7c3b5c76156ac52d50d8cab325d9)
1c19800e8SDoug Rabson /*
2c19800e8SDoug Rabson  * Copyright (c) 2005, PADL Software Pty Ltd.
3c19800e8SDoug Rabson  * All rights reserved.
4c19800e8SDoug Rabson  *
5ae771770SStanislav Sedov  * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
6ae771770SStanislav Sedov  *
7c19800e8SDoug Rabson  * Redistribution and use in source and binary forms, with or without
8c19800e8SDoug Rabson  * modification, are permitted provided that the following conditions
9c19800e8SDoug Rabson  * are met:
10c19800e8SDoug Rabson  *
11c19800e8SDoug Rabson  * 1. Redistributions of source code must retain the above copyright
12c19800e8SDoug Rabson  *    notice, this list of conditions and the following disclaimer.
13c19800e8SDoug Rabson  *
14c19800e8SDoug Rabson  * 2. Redistributions in binary form must reproduce the above copyright
15c19800e8SDoug Rabson  *    notice, this list of conditions and the following disclaimer in the
16c19800e8SDoug Rabson  *    documentation and/or other materials provided with the distribution.
17c19800e8SDoug Rabson  *
18c19800e8SDoug Rabson  * 3. Neither the name of PADL Software nor the names of its contributors
19c19800e8SDoug Rabson  *    may be used to endorse or promote products derived from this software
20c19800e8SDoug Rabson  *    without specific prior written permission.
21c19800e8SDoug Rabson  *
22c19800e8SDoug Rabson  * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
23c19800e8SDoug Rabson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24c19800e8SDoug Rabson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25c19800e8SDoug Rabson  * ARE DISCLAIMED.  IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
26c19800e8SDoug Rabson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27c19800e8SDoug Rabson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28c19800e8SDoug Rabson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29c19800e8SDoug Rabson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30c19800e8SDoug Rabson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31c19800e8SDoug Rabson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32c19800e8SDoug Rabson  * SUCH DAMAGE.
33c19800e8SDoug Rabson  */
34c19800e8SDoug Rabson 
35c19800e8SDoug Rabson #include "kcm_locl.h"
36c19800e8SDoug Rabson 
37ae771770SStanislav Sedov HEIMDAL_MUTEX ccache_mutex = HEIMDAL_MUTEX_INITIALIZER;
38ae771770SStanislav Sedov kcm_ccache_data *ccache_head = NULL;
39c19800e8SDoug Rabson static unsigned int ccache_nextid = 0;
40c19800e8SDoug Rabson 
kcm_ccache_nextid(pid_t pid,uid_t uid,gid_t gid)41c19800e8SDoug Rabson char *kcm_ccache_nextid(pid_t pid, uid_t uid, gid_t gid)
42c19800e8SDoug Rabson {
43c19800e8SDoug Rabson     unsigned n;
44c19800e8SDoug Rabson     char *name;
45c19800e8SDoug Rabson 
46c19800e8SDoug Rabson     HEIMDAL_MUTEX_lock(&ccache_mutex);
47c19800e8SDoug Rabson     n = ++ccache_nextid;
48c19800e8SDoug Rabson     HEIMDAL_MUTEX_unlock(&ccache_mutex);
49c19800e8SDoug Rabson 
50ae771770SStanislav Sedov     asprintf(&name, "%ld:%u", (long)uid, n);
51c19800e8SDoug Rabson 
52c19800e8SDoug Rabson     return name;
53c19800e8SDoug Rabson }
54c19800e8SDoug Rabson 
55ae771770SStanislav Sedov krb5_error_code
kcm_ccache_resolve(krb5_context context,const char * name,kcm_ccache * ccache)56ae771770SStanislav Sedov kcm_ccache_resolve(krb5_context context,
57c19800e8SDoug Rabson 		   const char *name,
58c19800e8SDoug Rabson 		   kcm_ccache *ccache)
59c19800e8SDoug Rabson {
60c19800e8SDoug Rabson     kcm_ccache p;
61c19800e8SDoug Rabson     krb5_error_code ret;
62c19800e8SDoug Rabson 
63c19800e8SDoug Rabson     *ccache = NULL;
64c19800e8SDoug Rabson 
65c19800e8SDoug Rabson     ret = KRB5_FCC_NOFILE;
66c19800e8SDoug Rabson 
67c19800e8SDoug Rabson     HEIMDAL_MUTEX_lock(&ccache_mutex);
68c19800e8SDoug Rabson 
69c19800e8SDoug Rabson     for (p = ccache_head; p != NULL; p = p->next) {
70c19800e8SDoug Rabson 	if ((p->flags & KCM_FLAGS_VALID) == 0)
71c19800e8SDoug Rabson 	    continue;
72c19800e8SDoug Rabson 	if (strcmp(p->name, name) == 0) {
73c19800e8SDoug Rabson 	    ret = 0;
74c19800e8SDoug Rabson 	    break;
75c19800e8SDoug Rabson 	}
76c19800e8SDoug Rabson     }
77c19800e8SDoug Rabson 
78c19800e8SDoug Rabson     if (ret == 0) {
79c19800e8SDoug Rabson 	kcm_retain_ccache(context, p);
80c19800e8SDoug Rabson 	*ccache = p;
81c19800e8SDoug Rabson     }
82c19800e8SDoug Rabson 
83c19800e8SDoug Rabson     HEIMDAL_MUTEX_unlock(&ccache_mutex);
84c19800e8SDoug Rabson 
85c19800e8SDoug Rabson     return ret;
86c19800e8SDoug Rabson }
87c19800e8SDoug Rabson 
88ae771770SStanislav Sedov krb5_error_code
kcm_ccache_resolve_by_uuid(krb5_context context,kcmuuid_t uuid,kcm_ccache * ccache)89ae771770SStanislav Sedov kcm_ccache_resolve_by_uuid(krb5_context context,
90ae771770SStanislav Sedov 			   kcmuuid_t uuid,
91ae771770SStanislav Sedov 			   kcm_ccache *ccache)
92ae771770SStanislav Sedov {
93ae771770SStanislav Sedov     kcm_ccache p;
94ae771770SStanislav Sedov     krb5_error_code ret;
95ae771770SStanislav Sedov 
96ae771770SStanislav Sedov     *ccache = NULL;
97ae771770SStanislav Sedov 
98ae771770SStanislav Sedov     ret = KRB5_FCC_NOFILE;
99ae771770SStanislav Sedov 
100ae771770SStanislav Sedov     HEIMDAL_MUTEX_lock(&ccache_mutex);
101ae771770SStanislav Sedov 
102ae771770SStanislav Sedov     for (p = ccache_head; p != NULL; p = p->next) {
103ae771770SStanislav Sedov 	if ((p->flags & KCM_FLAGS_VALID) == 0)
104ae771770SStanislav Sedov 	    continue;
105*d2a99d81SDimitry Andric 	if (memcmp(p->uuid, uuid, sizeof(kcmuuid_t)) == 0) {
106ae771770SStanislav Sedov 	    ret = 0;
107ae771770SStanislav Sedov 	    break;
108ae771770SStanislav Sedov 	}
109ae771770SStanislav Sedov     }
110ae771770SStanislav Sedov 
111ae771770SStanislav Sedov     if (ret == 0) {
112ae771770SStanislav Sedov 	kcm_retain_ccache(context, p);
113ae771770SStanislav Sedov 	*ccache = p;
114ae771770SStanislav Sedov     }
115ae771770SStanislav Sedov 
116ae771770SStanislav Sedov     HEIMDAL_MUTEX_unlock(&ccache_mutex);
117ae771770SStanislav Sedov 
118ae771770SStanislav Sedov     return ret;
119ae771770SStanislav Sedov }
120ae771770SStanislav Sedov 
121ae771770SStanislav Sedov krb5_error_code
kcm_ccache_get_uuids(krb5_context context,kcm_client * client,kcm_operation opcode,krb5_storage * sp)122ae771770SStanislav Sedov kcm_ccache_get_uuids(krb5_context context, kcm_client *client, kcm_operation opcode, krb5_storage *sp)
123ae771770SStanislav Sedov {
124ae771770SStanislav Sedov     krb5_error_code ret;
125ae771770SStanislav Sedov     kcm_ccache p;
126ae771770SStanislav Sedov 
127ae771770SStanislav Sedov     ret = KRB5_FCC_NOFILE;
128ae771770SStanislav Sedov 
129ae771770SStanislav Sedov     HEIMDAL_MUTEX_lock(&ccache_mutex);
130ae771770SStanislav Sedov 
131ae771770SStanislav Sedov     for (p = ccache_head; p != NULL; p = p->next) {
132ae771770SStanislav Sedov 	if ((p->flags & KCM_FLAGS_VALID) == 0)
133ae771770SStanislav Sedov 	    continue;
134ae771770SStanislav Sedov 	ret = kcm_access(context, client, opcode, p);
135ae771770SStanislav Sedov 	if (ret) {
136ae771770SStanislav Sedov 	    ret = 0;
137ae771770SStanislav Sedov 	    continue;
138ae771770SStanislav Sedov 	}
139ae771770SStanislav Sedov 	krb5_storage_write(sp, p->uuid, sizeof(p->uuid));
140ae771770SStanislav Sedov     }
141ae771770SStanislav Sedov 
142ae771770SStanislav Sedov     HEIMDAL_MUTEX_unlock(&ccache_mutex);
143ae771770SStanislav Sedov 
144ae771770SStanislav Sedov     return ret;
145ae771770SStanislav Sedov }
146ae771770SStanislav Sedov 
147ae771770SStanislav Sedov 
kcm_debug_ccache(krb5_context context)148c19800e8SDoug Rabson krb5_error_code kcm_debug_ccache(krb5_context context)
149c19800e8SDoug Rabson {
150c19800e8SDoug Rabson     kcm_ccache p;
151c19800e8SDoug Rabson 
152c19800e8SDoug Rabson     for (p = ccache_head; p != NULL; p = p->next) {
153c19800e8SDoug Rabson 	char *cpn = NULL, *spn = NULL;
154c19800e8SDoug Rabson 	int ncreds = 0;
155c19800e8SDoug Rabson 	struct kcm_creds *k;
156c19800e8SDoug Rabson 
157c19800e8SDoug Rabson 	if ((p->flags & KCM_FLAGS_VALID) == 0) {
158c19800e8SDoug Rabson 	    kcm_log(7, "cache %08x: empty slot");
159c19800e8SDoug Rabson 	    continue;
160c19800e8SDoug Rabson 	}
161c19800e8SDoug Rabson 
162c19800e8SDoug Rabson 	KCM_ASSERT_VALID(p);
163c19800e8SDoug Rabson 
164c19800e8SDoug Rabson 	for (k = p->creds; k != NULL; k = k->next)
165c19800e8SDoug Rabson 	    ncreds++;
166c19800e8SDoug Rabson 
167c19800e8SDoug Rabson 	if (p->client != NULL)
168c19800e8SDoug Rabson 	    krb5_unparse_name(context, p->client, &cpn);
169c19800e8SDoug Rabson 	if (p->server != NULL)
170c19800e8SDoug Rabson 	    krb5_unparse_name(context, p->server, &spn);
171c19800e8SDoug Rabson 
172c19800e8SDoug Rabson 	kcm_log(7, "cache %08x: name %s refcnt %d flags %04x mode %04o "
173c19800e8SDoug Rabson 		"uid %d gid %d client %s server %s ncreds %d",
174c19800e8SDoug Rabson 		p, p->name, p->refcnt, p->flags, p->mode, p->uid, p->gid,
175c19800e8SDoug Rabson 		(cpn == NULL) ? "<none>" : cpn,
176c19800e8SDoug Rabson 		(spn == NULL) ? "<none>" : spn,
177c19800e8SDoug Rabson 		ncreds);
178c19800e8SDoug Rabson 
179c19800e8SDoug Rabson 	if (cpn != NULL)
180c19800e8SDoug Rabson 	    free(cpn);
181c19800e8SDoug Rabson 	if (spn != NULL)
182c19800e8SDoug Rabson 	    free(spn);
183c19800e8SDoug Rabson     }
184c19800e8SDoug Rabson 
185c19800e8SDoug Rabson     return 0;
186c19800e8SDoug Rabson }
187c19800e8SDoug Rabson 
188ae771770SStanislav Sedov static void
kcm_free_ccache_data_internal(krb5_context context,kcm_ccache_data * cache)189ae771770SStanislav Sedov kcm_free_ccache_data_internal(krb5_context context,
190ae771770SStanislav Sedov 			      kcm_ccache_data *cache)
191c19800e8SDoug Rabson {
192ae771770SStanislav Sedov     KCM_ASSERT_VALID(cache);
193ae771770SStanislav Sedov 
194ae771770SStanislav Sedov     if (cache->name != NULL) {
195ae771770SStanislav Sedov 	free(cache->name);
196ae771770SStanislav Sedov 	cache->name = NULL;
197ae771770SStanislav Sedov     }
198ae771770SStanislav Sedov 
199ae771770SStanislav Sedov     if (cache->flags & KCM_FLAGS_USE_KEYTAB) {
200ae771770SStanislav Sedov 	krb5_kt_close(context, cache->key.keytab);
201ae771770SStanislav Sedov 	cache->key.keytab = NULL;
202ae771770SStanislav Sedov     } else if (cache->flags & KCM_FLAGS_USE_CACHED_KEY) {
203ae771770SStanislav Sedov 	krb5_free_keyblock_contents(context, &cache->key.keyblock);
204ae771770SStanislav Sedov 	krb5_keyblock_zero(&cache->key.keyblock);
205ae771770SStanislav Sedov     }
206ae771770SStanislav Sedov 
207ae771770SStanislav Sedov     cache->flags = 0;
208ae771770SStanislav Sedov     cache->mode = 0;
209ae771770SStanislav Sedov     cache->uid = -1;
210ae771770SStanislav Sedov     cache->gid = -1;
211ae771770SStanislav Sedov     cache->session = -1;
212ae771770SStanislav Sedov 
213ae771770SStanislav Sedov     kcm_zero_ccache_data_internal(context, cache);
214ae771770SStanislav Sedov 
215ae771770SStanislav Sedov     cache->tkt_life = 0;
216ae771770SStanislav Sedov     cache->renew_life = 0;
217ae771770SStanislav Sedov 
218ae771770SStanislav Sedov     cache->next = NULL;
219ae771770SStanislav Sedov     cache->refcnt = 0;
220ae771770SStanislav Sedov 
221ae771770SStanislav Sedov     HEIMDAL_MUTEX_unlock(&cache->mutex);
222ae771770SStanislav Sedov     HEIMDAL_MUTEX_destroy(&cache->mutex);
223ae771770SStanislav Sedov }
224ae771770SStanislav Sedov 
225ae771770SStanislav Sedov 
226ae771770SStanislav Sedov krb5_error_code
kcm_ccache_destroy(krb5_context context,const char * name)227ae771770SStanislav Sedov kcm_ccache_destroy(krb5_context context, const char *name)
228ae771770SStanislav Sedov {
229ae771770SStanislav Sedov     kcm_ccache *p, ccache;
230c19800e8SDoug Rabson     krb5_error_code ret;
231c19800e8SDoug Rabson 
232c19800e8SDoug Rabson     ret = KRB5_FCC_NOFILE;
233c19800e8SDoug Rabson 
234c19800e8SDoug Rabson     HEIMDAL_MUTEX_lock(&ccache_mutex);
235c19800e8SDoug Rabson     for (p = &ccache_head; *p != NULL; p = &(*p)->next) {
236c19800e8SDoug Rabson 	if (((*p)->flags & KCM_FLAGS_VALID) == 0)
237c19800e8SDoug Rabson 	    continue;
238c19800e8SDoug Rabson 	if (strcmp((*p)->name, name) == 0) {
239c19800e8SDoug Rabson 	    ret = 0;
240c19800e8SDoug Rabson 	    break;
241c19800e8SDoug Rabson 	}
242c19800e8SDoug Rabson     }
243c19800e8SDoug Rabson     if (ret)
244c19800e8SDoug Rabson 	goto out;
245c19800e8SDoug Rabson 
246ae771770SStanislav Sedov     if ((*p)->refcnt != 1) {
247ae771770SStanislav Sedov 	ret = EAGAIN;
248ae771770SStanislav Sedov 	goto out;
249ae771770SStanislav Sedov     }
250ae771770SStanislav Sedov 
251ae771770SStanislav Sedov     ccache = *p;
252ae771770SStanislav Sedov     *p = (*p)->next;
253ae771770SStanislav Sedov     kcm_free_ccache_data_internal(context, ccache);
254ae771770SStanislav Sedov     free(ccache);
255c19800e8SDoug Rabson 
256c19800e8SDoug Rabson out:
257c19800e8SDoug Rabson     HEIMDAL_MUTEX_unlock(&ccache_mutex);
258c19800e8SDoug Rabson 
259c19800e8SDoug Rabson     return ret;
260c19800e8SDoug Rabson }
261c19800e8SDoug Rabson 
262c19800e8SDoug Rabson static krb5_error_code
kcm_ccache_alloc(krb5_context context,const char * name,kcm_ccache * ccache)263c19800e8SDoug Rabson kcm_ccache_alloc(krb5_context context,
264c19800e8SDoug Rabson 		 const char *name,
265c19800e8SDoug Rabson 		 kcm_ccache *ccache)
266c19800e8SDoug Rabson {
267c19800e8SDoug Rabson     kcm_ccache slot = NULL, p;
268c19800e8SDoug Rabson     krb5_error_code ret;
269c19800e8SDoug Rabson     int new_slot = 0;
270c19800e8SDoug Rabson 
271c19800e8SDoug Rabson     *ccache = NULL;
272c19800e8SDoug Rabson 
273c19800e8SDoug Rabson     /* First, check for duplicates */
274c19800e8SDoug Rabson     HEIMDAL_MUTEX_lock(&ccache_mutex);
275c19800e8SDoug Rabson     ret = 0;
276c19800e8SDoug Rabson     for (p = ccache_head; p != NULL; p = p->next) {
277c19800e8SDoug Rabson 	if (p->flags & KCM_FLAGS_VALID) {
278c19800e8SDoug Rabson 	    if (strcmp(p->name, name) == 0) {
279c19800e8SDoug Rabson 		ret = KRB5_CC_WRITE;
280c19800e8SDoug Rabson 		break;
281c19800e8SDoug Rabson 	    }
282c19800e8SDoug Rabson 	} else if (slot == NULL)
283c19800e8SDoug Rabson 	    slot = p;
284c19800e8SDoug Rabson     }
285c19800e8SDoug Rabson 
286c19800e8SDoug Rabson     if (ret)
287c19800e8SDoug Rabson 	goto out;
288c19800e8SDoug Rabson 
289c19800e8SDoug Rabson     /*
290ae771770SStanislav Sedov      * Create an enpty slot for us.
291c19800e8SDoug Rabson      */
292c19800e8SDoug Rabson     if (slot == NULL) {
293c19800e8SDoug Rabson 	slot = (kcm_ccache_data *)malloc(sizeof(*slot));
294c19800e8SDoug Rabson 	if (slot == NULL) {
295c19800e8SDoug Rabson 	    ret = KRB5_CC_NOMEM;
296c19800e8SDoug Rabson 	    goto out;
297c19800e8SDoug Rabson 	}
298c19800e8SDoug Rabson 	slot->next = ccache_head;
299c19800e8SDoug Rabson 	HEIMDAL_MUTEX_init(&slot->mutex);
300c19800e8SDoug Rabson 	new_slot = 1;
301c19800e8SDoug Rabson     }
302ae771770SStanislav Sedov 
303ae771770SStanislav Sedov     RAND_bytes(slot->uuid, sizeof(slot->uuid));
304c19800e8SDoug Rabson 
305c19800e8SDoug Rabson     slot->name = strdup(name);
306c19800e8SDoug Rabson     if (slot->name == NULL) {
307c19800e8SDoug Rabson 	ret = KRB5_CC_NOMEM;
308c19800e8SDoug Rabson 	goto out;
309c19800e8SDoug Rabson     }
310c19800e8SDoug Rabson 
311c19800e8SDoug Rabson     slot->refcnt = 1;
312c19800e8SDoug Rabson     slot->flags = KCM_FLAGS_VALID;
313c19800e8SDoug Rabson     slot->mode = S_IRUSR | S_IWUSR;
314c19800e8SDoug Rabson     slot->uid = -1;
315c19800e8SDoug Rabson     slot->gid = -1;
316c19800e8SDoug Rabson     slot->client = NULL;
317c19800e8SDoug Rabson     slot->server = NULL;
318c19800e8SDoug Rabson     slot->creds = NULL;
319c19800e8SDoug Rabson     slot->key.keytab = NULL;
320c19800e8SDoug Rabson     slot->tkt_life = 0;
321c19800e8SDoug Rabson     slot->renew_life = 0;
322c19800e8SDoug Rabson 
323c19800e8SDoug Rabson     if (new_slot)
324c19800e8SDoug Rabson 	ccache_head = slot;
325c19800e8SDoug Rabson 
326c19800e8SDoug Rabson     *ccache = slot;
327c19800e8SDoug Rabson 
328c19800e8SDoug Rabson     HEIMDAL_MUTEX_unlock(&ccache_mutex);
329c19800e8SDoug Rabson     return 0;
330c19800e8SDoug Rabson 
331c19800e8SDoug Rabson out:
332c19800e8SDoug Rabson     HEIMDAL_MUTEX_unlock(&ccache_mutex);
333c19800e8SDoug Rabson     if (new_slot && slot != NULL) {
334c19800e8SDoug Rabson 	HEIMDAL_MUTEX_destroy(&slot->mutex);
335c19800e8SDoug Rabson 	free(slot);
336c19800e8SDoug Rabson     }
337c19800e8SDoug Rabson     return ret;
338c19800e8SDoug Rabson }
339c19800e8SDoug Rabson 
340c19800e8SDoug Rabson krb5_error_code
kcm_ccache_remove_creds_internal(krb5_context context,kcm_ccache ccache)341c19800e8SDoug Rabson kcm_ccache_remove_creds_internal(krb5_context context,
342c19800e8SDoug Rabson 				 kcm_ccache ccache)
343c19800e8SDoug Rabson {
344c19800e8SDoug Rabson     struct kcm_creds *k;
345c19800e8SDoug Rabson 
346c19800e8SDoug Rabson     k = ccache->creds;
347c19800e8SDoug Rabson     while (k != NULL) {
348c19800e8SDoug Rabson 	struct kcm_creds *old;
349c19800e8SDoug Rabson 
350c19800e8SDoug Rabson 	krb5_free_cred_contents(context, &k->cred);
351c19800e8SDoug Rabson 	old = k;
352c19800e8SDoug Rabson 	k = k->next;
353c19800e8SDoug Rabson 	free(old);
354c19800e8SDoug Rabson     }
355c19800e8SDoug Rabson     ccache->creds = NULL;
356c19800e8SDoug Rabson 
357c19800e8SDoug Rabson     return 0;
358c19800e8SDoug Rabson }
359c19800e8SDoug Rabson 
360c19800e8SDoug Rabson krb5_error_code
kcm_ccache_remove_creds(krb5_context context,kcm_ccache ccache)361c19800e8SDoug Rabson kcm_ccache_remove_creds(krb5_context context,
362c19800e8SDoug Rabson 			kcm_ccache ccache)
363c19800e8SDoug Rabson {
364c19800e8SDoug Rabson     krb5_error_code ret;
365c19800e8SDoug Rabson 
366c19800e8SDoug Rabson     KCM_ASSERT_VALID(ccache);
367c19800e8SDoug Rabson 
368c19800e8SDoug Rabson     HEIMDAL_MUTEX_lock(&ccache->mutex);
369c19800e8SDoug Rabson     ret = kcm_ccache_remove_creds_internal(context, ccache);
370c19800e8SDoug Rabson     HEIMDAL_MUTEX_unlock(&ccache->mutex);
371c19800e8SDoug Rabson 
372c19800e8SDoug Rabson     return ret;
373c19800e8SDoug Rabson }
374c19800e8SDoug Rabson 
375c19800e8SDoug Rabson krb5_error_code
kcm_zero_ccache_data_internal(krb5_context context,kcm_ccache_data * cache)376c19800e8SDoug Rabson kcm_zero_ccache_data_internal(krb5_context context,
377c19800e8SDoug Rabson 			      kcm_ccache_data *cache)
378c19800e8SDoug Rabson {
379c19800e8SDoug Rabson     if (cache->client != NULL) {
380c19800e8SDoug Rabson 	krb5_free_principal(context, cache->client);
381c19800e8SDoug Rabson 	cache->client = NULL;
382c19800e8SDoug Rabson     }
383c19800e8SDoug Rabson 
384c19800e8SDoug Rabson     if (cache->server != NULL) {
385c19800e8SDoug Rabson 	krb5_free_principal(context, cache->server);
386c19800e8SDoug Rabson 	cache->server = NULL;
387c19800e8SDoug Rabson     }
388c19800e8SDoug Rabson 
389c19800e8SDoug Rabson     kcm_ccache_remove_creds_internal(context, cache);
390c19800e8SDoug Rabson 
391c19800e8SDoug Rabson     return 0;
392c19800e8SDoug Rabson }
393c19800e8SDoug Rabson 
394c19800e8SDoug Rabson krb5_error_code
kcm_zero_ccache_data(krb5_context context,kcm_ccache cache)395c19800e8SDoug Rabson kcm_zero_ccache_data(krb5_context context,
396c19800e8SDoug Rabson 		     kcm_ccache cache)
397c19800e8SDoug Rabson {
398c19800e8SDoug Rabson     krb5_error_code ret;
399c19800e8SDoug Rabson 
400c19800e8SDoug Rabson     KCM_ASSERT_VALID(cache);
401c19800e8SDoug Rabson 
402c19800e8SDoug Rabson     HEIMDAL_MUTEX_lock(&cache->mutex);
403c19800e8SDoug Rabson     ret = kcm_zero_ccache_data_internal(context, cache);
404c19800e8SDoug Rabson     HEIMDAL_MUTEX_unlock(&cache->mutex);
405c19800e8SDoug Rabson 
406c19800e8SDoug Rabson     return ret;
407c19800e8SDoug Rabson }
408c19800e8SDoug Rabson 
409c19800e8SDoug Rabson krb5_error_code
kcm_retain_ccache(krb5_context context,kcm_ccache ccache)410c19800e8SDoug Rabson kcm_retain_ccache(krb5_context context,
411c19800e8SDoug Rabson 		  kcm_ccache ccache)
412c19800e8SDoug Rabson {
413c19800e8SDoug Rabson     KCM_ASSERT_VALID(ccache);
414c19800e8SDoug Rabson 
415c19800e8SDoug Rabson     HEIMDAL_MUTEX_lock(&ccache->mutex);
416c19800e8SDoug Rabson     ccache->refcnt++;
417c19800e8SDoug Rabson     HEIMDAL_MUTEX_unlock(&ccache->mutex);
418c19800e8SDoug Rabson 
419c19800e8SDoug Rabson     return 0;
420c19800e8SDoug Rabson }
421c19800e8SDoug Rabson 
422c19800e8SDoug Rabson krb5_error_code
kcm_release_ccache(krb5_context context,kcm_ccache c)423ae771770SStanislav Sedov kcm_release_ccache(krb5_context context, kcm_ccache c)
424c19800e8SDoug Rabson {
425c19800e8SDoug Rabson     krb5_error_code ret = 0;
426c19800e8SDoug Rabson 
427c19800e8SDoug Rabson     KCM_ASSERT_VALID(c);
428c19800e8SDoug Rabson 
429c19800e8SDoug Rabson     HEIMDAL_MUTEX_lock(&c->mutex);
430c19800e8SDoug Rabson     if (c->refcnt == 1) {
431ae771770SStanislav Sedov 	kcm_free_ccache_data_internal(context, c);
432c19800e8SDoug Rabson 	free(c);
433c19800e8SDoug Rabson     } else {
434c19800e8SDoug Rabson 	c->refcnt--;
435c19800e8SDoug Rabson 	HEIMDAL_MUTEX_unlock(&c->mutex);
436c19800e8SDoug Rabson     }
437c19800e8SDoug Rabson 
438c19800e8SDoug Rabson     return ret;
439c19800e8SDoug Rabson }
440c19800e8SDoug Rabson 
441c19800e8SDoug Rabson krb5_error_code
kcm_ccache_gen_new(krb5_context context,pid_t pid,uid_t uid,gid_t gid,kcm_ccache * ccache)442c19800e8SDoug Rabson kcm_ccache_gen_new(krb5_context context,
443c19800e8SDoug Rabson 		   pid_t pid,
444c19800e8SDoug Rabson 		   uid_t uid,
445c19800e8SDoug Rabson 		   gid_t gid,
446c19800e8SDoug Rabson 		   kcm_ccache *ccache)
447c19800e8SDoug Rabson {
448c19800e8SDoug Rabson     krb5_error_code ret;
449c19800e8SDoug Rabson     char *name;
450c19800e8SDoug Rabson 
451c19800e8SDoug Rabson     name = kcm_ccache_nextid(pid, uid, gid);
452c19800e8SDoug Rabson     if (name == NULL) {
453c19800e8SDoug Rabson 	return KRB5_CC_NOMEM;
454c19800e8SDoug Rabson     }
455c19800e8SDoug Rabson 
456c19800e8SDoug Rabson     ret = kcm_ccache_new(context, name, ccache);
457c19800e8SDoug Rabson 
458c19800e8SDoug Rabson     free(name);
459c19800e8SDoug Rabson     return ret;
460c19800e8SDoug Rabson }
461c19800e8SDoug Rabson 
462c19800e8SDoug Rabson krb5_error_code
kcm_ccache_new(krb5_context context,const char * name,kcm_ccache * ccache)463c19800e8SDoug Rabson kcm_ccache_new(krb5_context context,
464c19800e8SDoug Rabson 	       const char *name,
465c19800e8SDoug Rabson 	       kcm_ccache *ccache)
466c19800e8SDoug Rabson {
467c19800e8SDoug Rabson     krb5_error_code ret;
468c19800e8SDoug Rabson 
469c19800e8SDoug Rabson     ret = kcm_ccache_alloc(context, name, ccache);
470c19800e8SDoug Rabson     if (ret == 0) {
471c19800e8SDoug Rabson 	/*
472c19800e8SDoug Rabson 	 * one reference is held by the linked list,
473c19800e8SDoug Rabson 	 * one by the caller
474c19800e8SDoug Rabson 	 */
475c19800e8SDoug Rabson 	kcm_retain_ccache(context, *ccache);
476c19800e8SDoug Rabson     }
477c19800e8SDoug Rabson 
478c19800e8SDoug Rabson     return ret;
479c19800e8SDoug Rabson }
480c19800e8SDoug Rabson 
481c19800e8SDoug Rabson krb5_error_code
kcm_ccache_destroy_if_empty(krb5_context context,kcm_ccache ccache)482c19800e8SDoug Rabson kcm_ccache_destroy_if_empty(krb5_context context,
483c19800e8SDoug Rabson 			    kcm_ccache ccache)
484c19800e8SDoug Rabson {
485c19800e8SDoug Rabson     krb5_error_code ret;
486c19800e8SDoug Rabson 
487c19800e8SDoug Rabson     KCM_ASSERT_VALID(ccache);
488c19800e8SDoug Rabson 
489c19800e8SDoug Rabson     if (ccache->creds == NULL) {
490ae771770SStanislav Sedov 	ret = kcm_ccache_destroy(context, ccache->name);
491c19800e8SDoug Rabson     } else
492c19800e8SDoug Rabson 	ret = 0;
493c19800e8SDoug Rabson 
494c19800e8SDoug Rabson     return ret;
495c19800e8SDoug Rabson }
496c19800e8SDoug Rabson 
497c19800e8SDoug Rabson krb5_error_code
kcm_ccache_store_cred(krb5_context context,kcm_ccache ccache,krb5_creds * creds,int copy)498c19800e8SDoug Rabson kcm_ccache_store_cred(krb5_context context,
499c19800e8SDoug Rabson 		      kcm_ccache ccache,
500c19800e8SDoug Rabson 		      krb5_creds *creds,
501c19800e8SDoug Rabson 		      int copy)
502c19800e8SDoug Rabson {
503c19800e8SDoug Rabson     krb5_error_code ret;
504c19800e8SDoug Rabson     krb5_creds *tmp;
505c19800e8SDoug Rabson 
506c19800e8SDoug Rabson     KCM_ASSERT_VALID(ccache);
507c19800e8SDoug Rabson 
508c19800e8SDoug Rabson     HEIMDAL_MUTEX_lock(&ccache->mutex);
509c19800e8SDoug Rabson     ret = kcm_ccache_store_cred_internal(context, ccache, creds, copy, &tmp);
510c19800e8SDoug Rabson     HEIMDAL_MUTEX_unlock(&ccache->mutex);
511c19800e8SDoug Rabson 
512c19800e8SDoug Rabson     return ret;
513c19800e8SDoug Rabson }
514c19800e8SDoug Rabson 
515ae771770SStanislav Sedov struct kcm_creds *
kcm_ccache_find_cred_uuid(krb5_context context,kcm_ccache ccache,kcmuuid_t uuid)516ae771770SStanislav Sedov kcm_ccache_find_cred_uuid(krb5_context context,
517ae771770SStanislav Sedov 			  kcm_ccache ccache,
518ae771770SStanislav Sedov 			  kcmuuid_t uuid)
519ae771770SStanislav Sedov {
520ae771770SStanislav Sedov     struct kcm_creds *c;
521ae771770SStanislav Sedov 
522ae771770SStanislav Sedov     for (c = ccache->creds; c != NULL; c = c->next)
523ae771770SStanislav Sedov 	if (memcmp(c->uuid, uuid, sizeof(c->uuid)) == 0)
524ae771770SStanislav Sedov 	    return c;
525ae771770SStanislav Sedov 
526ae771770SStanislav Sedov     return NULL;
527ae771770SStanislav Sedov }
528ae771770SStanislav Sedov 
529ae771770SStanislav Sedov 
530ae771770SStanislav Sedov 
531c19800e8SDoug Rabson krb5_error_code
kcm_ccache_store_cred_internal(krb5_context context,kcm_ccache ccache,krb5_creds * creds,int copy,krb5_creds ** credp)532c19800e8SDoug Rabson kcm_ccache_store_cred_internal(krb5_context context,
533c19800e8SDoug Rabson 			       kcm_ccache ccache,
534c19800e8SDoug Rabson 			       krb5_creds *creds,
535c19800e8SDoug Rabson 			       int copy,
536c19800e8SDoug Rabson 			       krb5_creds **credp)
537c19800e8SDoug Rabson {
538c19800e8SDoug Rabson     struct kcm_creds **c;
539c19800e8SDoug Rabson     krb5_error_code ret;
540c19800e8SDoug Rabson 
541c19800e8SDoug Rabson     for (c = &ccache->creds; *c != NULL; c = &(*c)->next)
542c19800e8SDoug Rabson 	;
543c19800e8SDoug Rabson 
544ae771770SStanislav Sedov     *c = (struct kcm_creds *)calloc(1, sizeof(**c));
545ae771770SStanislav Sedov     if (*c == NULL)
546c19800e8SDoug Rabson 	return KRB5_CC_NOMEM;
547ae771770SStanislav Sedov 
548ae771770SStanislav Sedov     RAND_bytes((*c)->uuid, sizeof((*c)->uuid));
549c19800e8SDoug Rabson 
550c19800e8SDoug Rabson     *credp = &(*c)->cred;
551c19800e8SDoug Rabson 
552c19800e8SDoug Rabson     if (copy) {
553c19800e8SDoug Rabson 	ret = krb5_copy_creds_contents(context, creds, *credp);
554c19800e8SDoug Rabson 	if (ret) {
555c19800e8SDoug Rabson 	    free(*c);
556c19800e8SDoug Rabson 	    *c = NULL;
557c19800e8SDoug Rabson 	}
558c19800e8SDoug Rabson     } else {
559c19800e8SDoug Rabson 	**credp = *creds;
560c19800e8SDoug Rabson 	ret = 0;
561c19800e8SDoug Rabson     }
562c19800e8SDoug Rabson 
563c19800e8SDoug Rabson     return ret;
564c19800e8SDoug Rabson }
565c19800e8SDoug Rabson 
566c19800e8SDoug Rabson krb5_error_code
kcm_ccache_remove_cred_internal(krb5_context context,kcm_ccache ccache,krb5_flags whichfields,const krb5_creds * mcreds)567c19800e8SDoug Rabson kcm_ccache_remove_cred_internal(krb5_context context,
568c19800e8SDoug Rabson 				kcm_ccache ccache,
569c19800e8SDoug Rabson 				krb5_flags whichfields,
570c19800e8SDoug Rabson 				const krb5_creds *mcreds)
571c19800e8SDoug Rabson {
572c19800e8SDoug Rabson     krb5_error_code ret;
573c19800e8SDoug Rabson     struct kcm_creds **c;
574c19800e8SDoug Rabson 
575c19800e8SDoug Rabson     ret = KRB5_CC_NOTFOUND;
576c19800e8SDoug Rabson 
577c19800e8SDoug Rabson     for (c = &ccache->creds; *c != NULL; c = &(*c)->next) {
578c19800e8SDoug Rabson 	if (krb5_compare_creds(context, whichfields, mcreds, &(*c)->cred)) {
579ae771770SStanislav Sedov 	    struct kcm_creds *cred = *c;
580ae771770SStanislav Sedov 
581ae771770SStanislav Sedov 	    *c = cred->next;
582ae771770SStanislav Sedov 	    krb5_free_cred_contents(context, &cred->cred);
583ae771770SStanislav Sedov 	    free(cred);
584c19800e8SDoug Rabson 	    ret = 0;
585ae771770SStanislav Sedov 	    if (*c == NULL)
586ae771770SStanislav Sedov 		break;
587c19800e8SDoug Rabson 	}
588c19800e8SDoug Rabson     }
589c19800e8SDoug Rabson 
590c19800e8SDoug Rabson     return ret;
591c19800e8SDoug Rabson }
592c19800e8SDoug Rabson 
593c19800e8SDoug Rabson krb5_error_code
kcm_ccache_remove_cred(krb5_context context,kcm_ccache ccache,krb5_flags whichfields,const krb5_creds * mcreds)594c19800e8SDoug Rabson kcm_ccache_remove_cred(krb5_context context,
595c19800e8SDoug Rabson 		       kcm_ccache ccache,
596c19800e8SDoug Rabson 		       krb5_flags whichfields,
597c19800e8SDoug Rabson 		       const krb5_creds *mcreds)
598c19800e8SDoug Rabson {
599c19800e8SDoug Rabson     krb5_error_code ret;
600c19800e8SDoug Rabson 
601c19800e8SDoug Rabson     KCM_ASSERT_VALID(ccache);
602c19800e8SDoug Rabson 
603c19800e8SDoug Rabson     HEIMDAL_MUTEX_lock(&ccache->mutex);
604c19800e8SDoug Rabson     ret = kcm_ccache_remove_cred_internal(context, ccache, whichfields, mcreds);
605c19800e8SDoug Rabson     HEIMDAL_MUTEX_unlock(&ccache->mutex);
606c19800e8SDoug Rabson 
607c19800e8SDoug Rabson     return ret;
608c19800e8SDoug Rabson }
609c19800e8SDoug Rabson 
610c19800e8SDoug Rabson krb5_error_code
kcm_ccache_retrieve_cred_internal(krb5_context context,kcm_ccache ccache,krb5_flags whichfields,const krb5_creds * mcreds,krb5_creds ** creds)611c19800e8SDoug Rabson kcm_ccache_retrieve_cred_internal(krb5_context context,
612c19800e8SDoug Rabson 			 	  kcm_ccache ccache,
613c19800e8SDoug Rabson 			 	  krb5_flags whichfields,
614c19800e8SDoug Rabson 			 	  const krb5_creds *mcreds,
615c19800e8SDoug Rabson 			 	  krb5_creds **creds)
616c19800e8SDoug Rabson {
617c19800e8SDoug Rabson     krb5_boolean match;
618c19800e8SDoug Rabson     struct kcm_creds *c;
619c19800e8SDoug Rabson     krb5_error_code ret;
620c19800e8SDoug Rabson 
621c19800e8SDoug Rabson     memset(creds, 0, sizeof(*creds));
622c19800e8SDoug Rabson 
623c19800e8SDoug Rabson     ret = KRB5_CC_END;
624c19800e8SDoug Rabson 
625c19800e8SDoug Rabson     match = FALSE;
626c19800e8SDoug Rabson     for (c = ccache->creds; c != NULL; c = c->next) {
627c19800e8SDoug Rabson 	match = krb5_compare_creds(context, whichfields, mcreds, &c->cred);
628c19800e8SDoug Rabson 	if (match)
629c19800e8SDoug Rabson 	    break;
630c19800e8SDoug Rabson     }
631c19800e8SDoug Rabson 
632c19800e8SDoug Rabson     if (match) {
633c19800e8SDoug Rabson 	ret = 0;
634c19800e8SDoug Rabson 	*creds = &c->cred;
635c19800e8SDoug Rabson     }
636c19800e8SDoug Rabson 
637c19800e8SDoug Rabson     return ret;
638c19800e8SDoug Rabson }
639c19800e8SDoug Rabson 
640c19800e8SDoug Rabson krb5_error_code
kcm_ccache_retrieve_cred(krb5_context context,kcm_ccache ccache,krb5_flags whichfields,const krb5_creds * mcreds,krb5_creds ** credp)641c19800e8SDoug Rabson kcm_ccache_retrieve_cred(krb5_context context,
642c19800e8SDoug Rabson 			 kcm_ccache ccache,
643c19800e8SDoug Rabson 			 krb5_flags whichfields,
644c19800e8SDoug Rabson 			 const krb5_creds *mcreds,
645c19800e8SDoug Rabson 			 krb5_creds **credp)
646c19800e8SDoug Rabson {
647c19800e8SDoug Rabson     krb5_error_code ret;
648c19800e8SDoug Rabson 
649c19800e8SDoug Rabson     KCM_ASSERT_VALID(ccache);
650c19800e8SDoug Rabson 
651c19800e8SDoug Rabson     HEIMDAL_MUTEX_lock(&ccache->mutex);
652c19800e8SDoug Rabson     ret = kcm_ccache_retrieve_cred_internal(context, ccache,
653c19800e8SDoug Rabson 					    whichfields, mcreds, credp);
654c19800e8SDoug Rabson     HEIMDAL_MUTEX_unlock(&ccache->mutex);
655c19800e8SDoug Rabson 
656c19800e8SDoug Rabson     return ret;
657c19800e8SDoug Rabson }
658ae771770SStanislav Sedov 
659ae771770SStanislav Sedov char *
kcm_ccache_first_name(kcm_client * client)660ae771770SStanislav Sedov kcm_ccache_first_name(kcm_client *client)
661ae771770SStanislav Sedov {
662ae771770SStanislav Sedov     kcm_ccache p;
663ae771770SStanislav Sedov     char *name = NULL;
664ae771770SStanislav Sedov 
665ae771770SStanislav Sedov     HEIMDAL_MUTEX_lock(&ccache_mutex);
666ae771770SStanislav Sedov 
667ae771770SStanislav Sedov     for (p = ccache_head; p != NULL; p = p->next) {
668ae771770SStanislav Sedov 	if (kcm_is_same_session(client, p->uid, p->session))
669ae771770SStanislav Sedov 	    break;
670ae771770SStanislav Sedov     }
671ae771770SStanislav Sedov     if (p)
672ae771770SStanislav Sedov 	name = strdup(p->name);
673ae771770SStanislav Sedov     HEIMDAL_MUTEX_unlock(&ccache_mutex);
674ae771770SStanislav Sedov     return name;
675ae771770SStanislav Sedov }
676