1178825Sdfr/*
2178825Sdfr * Copyright (c) 2005, PADL Software Pty Ltd.
3178825Sdfr * All rights reserved.
4178825Sdfr *
5233294Sstas * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
6233294Sstas *
7178825Sdfr * Redistribution and use in source and binary forms, with or without
8178825Sdfr * modification, are permitted provided that the following conditions
9178825Sdfr * are met:
10178825Sdfr *
11178825Sdfr * 1. Redistributions of source code must retain the above copyright
12178825Sdfr *    notice, this list of conditions and the following disclaimer.
13178825Sdfr *
14178825Sdfr * 2. Redistributions in binary form must reproduce the above copyright
15178825Sdfr *    notice, this list of conditions and the following disclaimer in the
16178825Sdfr *    documentation and/or other materials provided with the distribution.
17178825Sdfr *
18178825Sdfr * 3. Neither the name of PADL Software nor the names of its contributors
19178825Sdfr *    may be used to endorse or promote products derived from this software
20178825Sdfr *    without specific prior written permission.
21178825Sdfr *
22178825Sdfr * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
23178825Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24178825Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25178825Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
26178825Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27178825Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28178825Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29178825Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30178825Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31178825Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32178825Sdfr * SUCH DAMAGE.
33178825Sdfr */
34178825Sdfr
35178825Sdfr#include "kcm_locl.h"
36178825Sdfr
37233294SstasHEIMDAL_MUTEX ccache_mutex = HEIMDAL_MUTEX_INITIALIZER;
38233294Sstaskcm_ccache_data *ccache_head = NULL;
39233294Sstasstatic unsigned int ccache_nextid = 0;
40178825Sdfr
41178825Sdfrchar *kcm_ccache_nextid(pid_t pid, uid_t uid, gid_t gid)
42178825Sdfr{
43178825Sdfr    unsigned n;
44178825Sdfr    char *name;
45178825Sdfr
46178825Sdfr    HEIMDAL_MUTEX_lock(&ccache_mutex);
47178825Sdfr    n = ++ccache_nextid;
48178825Sdfr    HEIMDAL_MUTEX_unlock(&ccache_mutex);
49178825Sdfr
50233294Sstas    asprintf(&name, "%ld:%u", (long)uid, n);
51178825Sdfr
52178825Sdfr    return name;
53178825Sdfr}
54178825Sdfr
55233294Sstaskrb5_error_code
56233294Sstaskcm_ccache_resolve(krb5_context context,
57233294Sstas		   const char *name,
58233294Sstas		   kcm_ccache *ccache)
59178825Sdfr{
60178825Sdfr    kcm_ccache p;
61178825Sdfr    krb5_error_code ret;
62178825Sdfr
63178825Sdfr    *ccache = NULL;
64178825Sdfr
65178825Sdfr    ret = KRB5_FCC_NOFILE;
66178825Sdfr
67178825Sdfr    HEIMDAL_MUTEX_lock(&ccache_mutex);
68178825Sdfr
69178825Sdfr    for (p = ccache_head; p != NULL; p = p->next) {
70178825Sdfr	if ((p->flags & KCM_FLAGS_VALID) == 0)
71178825Sdfr	    continue;
72178825Sdfr	if (strcmp(p->name, name) == 0) {
73178825Sdfr	    ret = 0;
74178825Sdfr	    break;
75178825Sdfr	}
76178825Sdfr    }
77178825Sdfr
78178825Sdfr    if (ret == 0) {
79178825Sdfr	kcm_retain_ccache(context, p);
80178825Sdfr	*ccache = p;
81178825Sdfr    }
82178825Sdfr
83178825Sdfr    HEIMDAL_MUTEX_unlock(&ccache_mutex);
84178825Sdfr
85178825Sdfr    return ret;
86178825Sdfr}
87178825Sdfr
88233294Sstaskrb5_error_code
89233294Sstaskcm_ccache_resolve_by_uuid(krb5_context context,
90233294Sstas			   kcmuuid_t uuid,
91233294Sstas			   kcm_ccache *ccache)
92233294Sstas{
93233294Sstas    kcm_ccache p;
94233294Sstas    krb5_error_code ret;
95233294Sstas
96233294Sstas    *ccache = NULL;
97233294Sstas
98233294Sstas    ret = KRB5_FCC_NOFILE;
99233294Sstas
100233294Sstas    HEIMDAL_MUTEX_lock(&ccache_mutex);
101233294Sstas
102233294Sstas    for (p = ccache_head; p != NULL; p = p->next) {
103233294Sstas	if ((p->flags & KCM_FLAGS_VALID) == 0)
104233294Sstas	    continue;
105247002Sdim	if (memcmp(p->uuid, uuid, sizeof(kcmuuid_t)) == 0) {
106233294Sstas	    ret = 0;
107233294Sstas	    break;
108233294Sstas	}
109233294Sstas    }
110233294Sstas
111233294Sstas    if (ret == 0) {
112233294Sstas	kcm_retain_ccache(context, p);
113233294Sstas	*ccache = p;
114233294Sstas    }
115233294Sstas
116233294Sstas    HEIMDAL_MUTEX_unlock(&ccache_mutex);
117233294Sstas
118233294Sstas    return ret;
119233294Sstas}
120233294Sstas
121233294Sstaskrb5_error_code
122233294Sstaskcm_ccache_get_uuids(krb5_context context, kcm_client *client, kcm_operation opcode, krb5_storage *sp)
123233294Sstas{
124233294Sstas    krb5_error_code ret;
125233294Sstas    kcm_ccache p;
126233294Sstas
127233294Sstas    ret = KRB5_FCC_NOFILE;
128233294Sstas
129233294Sstas    HEIMDAL_MUTEX_lock(&ccache_mutex);
130233294Sstas
131233294Sstas    for (p = ccache_head; p != NULL; p = p->next) {
132233294Sstas	if ((p->flags & KCM_FLAGS_VALID) == 0)
133233294Sstas	    continue;
134233294Sstas	ret = kcm_access(context, client, opcode, p);
135233294Sstas	if (ret) {
136233294Sstas	    ret = 0;
137233294Sstas	    continue;
138233294Sstas	}
139233294Sstas	krb5_storage_write(sp, p->uuid, sizeof(p->uuid));
140233294Sstas    }
141233294Sstas
142233294Sstas    HEIMDAL_MUTEX_unlock(&ccache_mutex);
143233294Sstas
144233294Sstas    return ret;
145233294Sstas}
146233294Sstas
147233294Sstas
148178825Sdfrkrb5_error_code kcm_debug_ccache(krb5_context context)
149178825Sdfr{
150178825Sdfr    kcm_ccache p;
151178825Sdfr
152178825Sdfr    for (p = ccache_head; p != NULL; p = p->next) {
153178825Sdfr	char *cpn = NULL, *spn = NULL;
154178825Sdfr	int ncreds = 0;
155178825Sdfr	struct kcm_creds *k;
156178825Sdfr
157178825Sdfr	if ((p->flags & KCM_FLAGS_VALID) == 0) {
158178825Sdfr	    kcm_log(7, "cache %08x: empty slot");
159178825Sdfr	    continue;
160178825Sdfr	}
161178825Sdfr
162178825Sdfr	KCM_ASSERT_VALID(p);
163178825Sdfr
164178825Sdfr	for (k = p->creds; k != NULL; k = k->next)
165178825Sdfr	    ncreds++;
166178825Sdfr
167178825Sdfr	if (p->client != NULL)
168178825Sdfr	    krb5_unparse_name(context, p->client, &cpn);
169178825Sdfr	if (p->server != NULL)
170178825Sdfr	    krb5_unparse_name(context, p->server, &spn);
171233294Sstas
172178825Sdfr	kcm_log(7, "cache %08x: name %s refcnt %d flags %04x mode %04o "
173178825Sdfr		"uid %d gid %d client %s server %s ncreds %d",
174178825Sdfr		p, p->name, p->refcnt, p->flags, p->mode, p->uid, p->gid,
175178825Sdfr		(cpn == NULL) ? "<none>" : cpn,
176178825Sdfr		(spn == NULL) ? "<none>" : spn,
177178825Sdfr		ncreds);
178178825Sdfr
179178825Sdfr	if (cpn != NULL)
180178825Sdfr	    free(cpn);
181178825Sdfr	if (spn != NULL)
182178825Sdfr	    free(spn);
183178825Sdfr    }
184178825Sdfr
185178825Sdfr    return 0;
186178825Sdfr}
187178825Sdfr
188233294Sstasstatic void
189233294Sstaskcm_free_ccache_data_internal(krb5_context context,
190233294Sstas			      kcm_ccache_data *cache)
191178825Sdfr{
192233294Sstas    KCM_ASSERT_VALID(cache);
193233294Sstas
194233294Sstas    if (cache->name != NULL) {
195233294Sstas	free(cache->name);
196233294Sstas	cache->name = NULL;
197233294Sstas    }
198233294Sstas
199233294Sstas    if (cache->flags & KCM_FLAGS_USE_KEYTAB) {
200233294Sstas	krb5_kt_close(context, cache->key.keytab);
201233294Sstas	cache->key.keytab = NULL;
202233294Sstas    } else if (cache->flags & KCM_FLAGS_USE_CACHED_KEY) {
203233294Sstas	krb5_free_keyblock_contents(context, &cache->key.keyblock);
204233294Sstas	krb5_keyblock_zero(&cache->key.keyblock);
205233294Sstas    }
206233294Sstas
207233294Sstas    cache->flags = 0;
208233294Sstas    cache->mode = 0;
209233294Sstas    cache->uid = -1;
210233294Sstas    cache->gid = -1;
211233294Sstas    cache->session = -1;
212233294Sstas
213233294Sstas    kcm_zero_ccache_data_internal(context, cache);
214233294Sstas
215233294Sstas    cache->tkt_life = 0;
216233294Sstas    cache->renew_life = 0;
217233294Sstas
218233294Sstas    cache->next = NULL;
219233294Sstas    cache->refcnt = 0;
220233294Sstas
221233294Sstas    HEIMDAL_MUTEX_unlock(&cache->mutex);
222233294Sstas    HEIMDAL_MUTEX_destroy(&cache->mutex);
223233294Sstas}
224233294Sstas
225233294Sstas
226233294Sstaskrb5_error_code
227233294Sstaskcm_ccache_destroy(krb5_context context, const char *name)
228233294Sstas{
229233294Sstas    kcm_ccache *p, ccache;
230178825Sdfr    krb5_error_code ret;
231178825Sdfr
232178825Sdfr    ret = KRB5_FCC_NOFILE;
233178825Sdfr
234178825Sdfr    HEIMDAL_MUTEX_lock(&ccache_mutex);
235178825Sdfr    for (p = &ccache_head; *p != NULL; p = &(*p)->next) {
236178825Sdfr	if (((*p)->flags & KCM_FLAGS_VALID) == 0)
237178825Sdfr	    continue;
238178825Sdfr	if (strcmp((*p)->name, name) == 0) {
239178825Sdfr	    ret = 0;
240178825Sdfr	    break;
241178825Sdfr	}
242178825Sdfr    }
243178825Sdfr    if (ret)
244178825Sdfr	goto out;
245178825Sdfr
246233294Sstas    if ((*p)->refcnt != 1) {
247233294Sstas	ret = EAGAIN;
248233294Sstas	goto out;
249233294Sstas    }
250178825Sdfr
251233294Sstas    ccache = *p;
252233294Sstas    *p = (*p)->next;
253233294Sstas    kcm_free_ccache_data_internal(context, ccache);
254233294Sstas    free(ccache);
255233294Sstas
256178825Sdfrout:
257178825Sdfr    HEIMDAL_MUTEX_unlock(&ccache_mutex);
258178825Sdfr
259178825Sdfr    return ret;
260178825Sdfr}
261178825Sdfr
262178825Sdfrstatic krb5_error_code
263178825Sdfrkcm_ccache_alloc(krb5_context context,
264178825Sdfr		 const char *name,
265178825Sdfr		 kcm_ccache *ccache)
266178825Sdfr{
267178825Sdfr    kcm_ccache slot = NULL, p;
268178825Sdfr    krb5_error_code ret;
269178825Sdfr    int new_slot = 0;
270178825Sdfr
271178825Sdfr    *ccache = NULL;
272178825Sdfr
273178825Sdfr    /* First, check for duplicates */
274178825Sdfr    HEIMDAL_MUTEX_lock(&ccache_mutex);
275178825Sdfr    ret = 0;
276178825Sdfr    for (p = ccache_head; p != NULL; p = p->next) {
277178825Sdfr	if (p->flags & KCM_FLAGS_VALID) {
278178825Sdfr	    if (strcmp(p->name, name) == 0) {
279178825Sdfr		ret = KRB5_CC_WRITE;
280178825Sdfr		break;
281178825Sdfr	    }
282178825Sdfr	} else if (slot == NULL)
283178825Sdfr	    slot = p;
284178825Sdfr    }
285178825Sdfr
286178825Sdfr    if (ret)
287178825Sdfr	goto out;
288178825Sdfr
289178825Sdfr    /*
290233294Sstas     * Create an enpty slot for us.
291178825Sdfr     */
292178825Sdfr    if (slot == NULL) {
293233294Sstas	slot = (kcm_ccache_data *)malloc(sizeof(*slot));
294178825Sdfr	if (slot == NULL) {
295233294Sstas	    ret = KRB5_CC_NOMEM;
296233294Sstas	    goto out;
297178825Sdfr	}
298233294Sstas	slot->next = ccache_head;
299233294Sstas	HEIMDAL_MUTEX_init(&slot->mutex);
300233294Sstas	new_slot = 1;
301178825Sdfr    }
302178825Sdfr
303233294Sstas    RAND_bytes(slot->uuid, sizeof(slot->uuid));
304233294Sstas
305178825Sdfr    slot->name = strdup(name);
306178825Sdfr    if (slot->name == NULL) {
307178825Sdfr	ret = KRB5_CC_NOMEM;
308178825Sdfr	goto out;
309178825Sdfr    }
310178825Sdfr
311178825Sdfr    slot->refcnt = 1;
312178825Sdfr    slot->flags = KCM_FLAGS_VALID;
313178825Sdfr    slot->mode = S_IRUSR | S_IWUSR;
314178825Sdfr    slot->uid = -1;
315178825Sdfr    slot->gid = -1;
316178825Sdfr    slot->client = NULL;
317178825Sdfr    slot->server = NULL;
318178825Sdfr    slot->creds = NULL;
319178825Sdfr    slot->key.keytab = NULL;
320178825Sdfr    slot->tkt_life = 0;
321178825Sdfr    slot->renew_life = 0;
322178825Sdfr
323178825Sdfr    if (new_slot)
324178825Sdfr	ccache_head = slot;
325178825Sdfr
326178825Sdfr    *ccache = slot;
327178825Sdfr
328178825Sdfr    HEIMDAL_MUTEX_unlock(&ccache_mutex);
329178825Sdfr    return 0;
330178825Sdfr
331178825Sdfrout:
332178825Sdfr    HEIMDAL_MUTEX_unlock(&ccache_mutex);
333178825Sdfr    if (new_slot && slot != NULL) {
334178825Sdfr	HEIMDAL_MUTEX_destroy(&slot->mutex);
335178825Sdfr	free(slot);
336178825Sdfr    }
337178825Sdfr    return ret;
338178825Sdfr}
339178825Sdfr
340178825Sdfrkrb5_error_code
341178825Sdfrkcm_ccache_remove_creds_internal(krb5_context context,
342178825Sdfr				 kcm_ccache ccache)
343178825Sdfr{
344178825Sdfr    struct kcm_creds *k;
345178825Sdfr
346178825Sdfr    k = ccache->creds;
347178825Sdfr    while (k != NULL) {
348178825Sdfr	struct kcm_creds *old;
349178825Sdfr
350178825Sdfr	krb5_free_cred_contents(context, &k->cred);
351178825Sdfr	old = k;
352178825Sdfr	k = k->next;
353178825Sdfr	free(old);
354178825Sdfr    }
355178825Sdfr    ccache->creds = NULL;
356178825Sdfr
357178825Sdfr    return 0;
358178825Sdfr}
359178825Sdfr
360178825Sdfrkrb5_error_code
361178825Sdfrkcm_ccache_remove_creds(krb5_context context,
362178825Sdfr			kcm_ccache ccache)
363178825Sdfr{
364178825Sdfr    krb5_error_code ret;
365178825Sdfr
366178825Sdfr    KCM_ASSERT_VALID(ccache);
367178825Sdfr
368178825Sdfr    HEIMDAL_MUTEX_lock(&ccache->mutex);
369178825Sdfr    ret = kcm_ccache_remove_creds_internal(context, ccache);
370178825Sdfr    HEIMDAL_MUTEX_unlock(&ccache->mutex);
371178825Sdfr
372178825Sdfr    return ret;
373178825Sdfr}
374178825Sdfr
375178825Sdfrkrb5_error_code
376178825Sdfrkcm_zero_ccache_data_internal(krb5_context context,
377178825Sdfr			      kcm_ccache_data *cache)
378178825Sdfr{
379178825Sdfr    if (cache->client != NULL) {
380178825Sdfr	krb5_free_principal(context, cache->client);
381178825Sdfr	cache->client = NULL;
382178825Sdfr    }
383178825Sdfr
384178825Sdfr    if (cache->server != NULL) {
385178825Sdfr	krb5_free_principal(context, cache->server);
386178825Sdfr	cache->server = NULL;
387178825Sdfr    }
388178825Sdfr
389178825Sdfr    kcm_ccache_remove_creds_internal(context, cache);
390178825Sdfr
391178825Sdfr    return 0;
392178825Sdfr}
393178825Sdfr
394178825Sdfrkrb5_error_code
395178825Sdfrkcm_zero_ccache_data(krb5_context context,
396178825Sdfr		     kcm_ccache cache)
397178825Sdfr{
398178825Sdfr    krb5_error_code ret;
399178825Sdfr
400178825Sdfr    KCM_ASSERT_VALID(cache);
401178825Sdfr
402178825Sdfr    HEIMDAL_MUTEX_lock(&cache->mutex);
403178825Sdfr    ret = kcm_zero_ccache_data_internal(context, cache);
404178825Sdfr    HEIMDAL_MUTEX_unlock(&cache->mutex);
405178825Sdfr
406178825Sdfr    return ret;
407178825Sdfr}
408178825Sdfr
409178825Sdfrkrb5_error_code
410178825Sdfrkcm_retain_ccache(krb5_context context,
411178825Sdfr		  kcm_ccache ccache)
412178825Sdfr{
413178825Sdfr    KCM_ASSERT_VALID(ccache);
414178825Sdfr
415178825Sdfr    HEIMDAL_MUTEX_lock(&ccache->mutex);
416178825Sdfr    ccache->refcnt++;
417178825Sdfr    HEIMDAL_MUTEX_unlock(&ccache->mutex);
418178825Sdfr
419178825Sdfr    return 0;
420178825Sdfr}
421178825Sdfr
422178825Sdfrkrb5_error_code
423233294Sstaskcm_release_ccache(krb5_context context, kcm_ccache c)
424178825Sdfr{
425178825Sdfr    krb5_error_code ret = 0;
426178825Sdfr
427178825Sdfr    KCM_ASSERT_VALID(c);
428178825Sdfr
429178825Sdfr    HEIMDAL_MUTEX_lock(&c->mutex);
430178825Sdfr    if (c->refcnt == 1) {
431233294Sstas	kcm_free_ccache_data_internal(context, c);
432233294Sstas	free(c);
433178825Sdfr    } else {
434178825Sdfr	c->refcnt--;
435178825Sdfr	HEIMDAL_MUTEX_unlock(&c->mutex);
436178825Sdfr    }
437178825Sdfr
438178825Sdfr    return ret;
439178825Sdfr}
440178825Sdfr
441178825Sdfrkrb5_error_code
442178825Sdfrkcm_ccache_gen_new(krb5_context context,
443178825Sdfr		   pid_t pid,
444178825Sdfr		   uid_t uid,
445178825Sdfr		   gid_t gid,
446178825Sdfr		   kcm_ccache *ccache)
447178825Sdfr{
448178825Sdfr    krb5_error_code ret;
449178825Sdfr    char *name;
450178825Sdfr
451178825Sdfr    name = kcm_ccache_nextid(pid, uid, gid);
452178825Sdfr    if (name == NULL) {
453178825Sdfr	return KRB5_CC_NOMEM;
454178825Sdfr    }
455178825Sdfr
456178825Sdfr    ret = kcm_ccache_new(context, name, ccache);
457178825Sdfr
458178825Sdfr    free(name);
459178825Sdfr    return ret;
460178825Sdfr}
461178825Sdfr
462178825Sdfrkrb5_error_code
463178825Sdfrkcm_ccache_new(krb5_context context,
464178825Sdfr	       const char *name,
465178825Sdfr	       kcm_ccache *ccache)
466178825Sdfr{
467178825Sdfr    krb5_error_code ret;
468178825Sdfr
469178825Sdfr    ret = kcm_ccache_alloc(context, name, ccache);
470178825Sdfr    if (ret == 0) {
471178825Sdfr	/*
472178825Sdfr	 * one reference is held by the linked list,
473178825Sdfr	 * one by the caller
474178825Sdfr	 */
475178825Sdfr	kcm_retain_ccache(context, *ccache);
476178825Sdfr    }
477178825Sdfr
478178825Sdfr    return ret;
479178825Sdfr}
480178825Sdfr
481178825Sdfrkrb5_error_code
482178825Sdfrkcm_ccache_destroy_if_empty(krb5_context context,
483178825Sdfr			    kcm_ccache ccache)
484178825Sdfr{
485178825Sdfr    krb5_error_code ret;
486178825Sdfr
487178825Sdfr    KCM_ASSERT_VALID(ccache);
488233294Sstas
489178825Sdfr    if (ccache->creds == NULL) {
490233294Sstas	ret = kcm_ccache_destroy(context, ccache->name);
491178825Sdfr    } else
492178825Sdfr	ret = 0;
493178825Sdfr
494178825Sdfr    return ret;
495178825Sdfr}
496178825Sdfr
497178825Sdfrkrb5_error_code
498178825Sdfrkcm_ccache_store_cred(krb5_context context,
499178825Sdfr		      kcm_ccache ccache,
500178825Sdfr		      krb5_creds *creds,
501178825Sdfr		      int copy)
502178825Sdfr{
503178825Sdfr    krb5_error_code ret;
504178825Sdfr    krb5_creds *tmp;
505178825Sdfr
506178825Sdfr    KCM_ASSERT_VALID(ccache);
507233294Sstas
508178825Sdfr    HEIMDAL_MUTEX_lock(&ccache->mutex);
509178825Sdfr    ret = kcm_ccache_store_cred_internal(context, ccache, creds, copy, &tmp);
510178825Sdfr    HEIMDAL_MUTEX_unlock(&ccache->mutex);
511178825Sdfr
512178825Sdfr    return ret;
513178825Sdfr}
514178825Sdfr
515233294Sstasstruct kcm_creds *
516233294Sstaskcm_ccache_find_cred_uuid(krb5_context context,
517233294Sstas			  kcm_ccache ccache,
518233294Sstas			  kcmuuid_t uuid)
519233294Sstas{
520233294Sstas    struct kcm_creds *c;
521233294Sstas
522233294Sstas    for (c = ccache->creds; c != NULL; c = c->next)
523233294Sstas	if (memcmp(c->uuid, uuid, sizeof(c->uuid)) == 0)
524233294Sstas	    return c;
525233294Sstas
526233294Sstas    return NULL;
527233294Sstas}
528233294Sstas
529233294Sstas
530233294Sstas
531178825Sdfrkrb5_error_code
532178825Sdfrkcm_ccache_store_cred_internal(krb5_context context,
533178825Sdfr			       kcm_ccache ccache,
534178825Sdfr			       krb5_creds *creds,
535178825Sdfr			       int copy,
536178825Sdfr			       krb5_creds **credp)
537178825Sdfr{
538178825Sdfr    struct kcm_creds **c;
539178825Sdfr    krb5_error_code ret;
540178825Sdfr
541178825Sdfr    for (c = &ccache->creds; *c != NULL; c = &(*c)->next)
542178825Sdfr	;
543178825Sdfr
544233294Sstas    *c = (struct kcm_creds *)calloc(1, sizeof(**c));
545233294Sstas    if (*c == NULL)
546178825Sdfr	return KRB5_CC_NOMEM;
547178825Sdfr
548233294Sstas    RAND_bytes((*c)->uuid, sizeof((*c)->uuid));
549233294Sstas
550178825Sdfr    *credp = &(*c)->cred;
551178825Sdfr
552178825Sdfr    if (copy) {
553178825Sdfr	ret = krb5_copy_creds_contents(context, creds, *credp);
554178825Sdfr	if (ret) {
555178825Sdfr	    free(*c);
556178825Sdfr	    *c = NULL;
557178825Sdfr	}
558178825Sdfr    } else {
559178825Sdfr	**credp = *creds;
560178825Sdfr	ret = 0;
561178825Sdfr    }
562178825Sdfr
563178825Sdfr    return ret;
564178825Sdfr}
565178825Sdfr
566178825Sdfrkrb5_error_code
567178825Sdfrkcm_ccache_remove_cred_internal(krb5_context context,
568178825Sdfr				kcm_ccache ccache,
569178825Sdfr				krb5_flags whichfields,
570178825Sdfr				const krb5_creds *mcreds)
571178825Sdfr{
572178825Sdfr    krb5_error_code ret;
573178825Sdfr    struct kcm_creds **c;
574178825Sdfr
575178825Sdfr    ret = KRB5_CC_NOTFOUND;
576178825Sdfr
577178825Sdfr    for (c = &ccache->creds; *c != NULL; c = &(*c)->next) {
578178825Sdfr	if (krb5_compare_creds(context, whichfields, mcreds, &(*c)->cred)) {
579233294Sstas	    struct kcm_creds *cred = *c;
580233294Sstas
581233294Sstas	    *c = cred->next;
582233294Sstas	    krb5_free_cred_contents(context, &cred->cred);
583233294Sstas	    free(cred);
584178825Sdfr	    ret = 0;
585233294Sstas	    if (*c == NULL)
586233294Sstas		break;
587178825Sdfr	}
588178825Sdfr    }
589178825Sdfr
590178825Sdfr    return ret;
591178825Sdfr}
592178825Sdfr
593178825Sdfrkrb5_error_code
594178825Sdfrkcm_ccache_remove_cred(krb5_context context,
595178825Sdfr		       kcm_ccache ccache,
596178825Sdfr		       krb5_flags whichfields,
597178825Sdfr		       const krb5_creds *mcreds)
598178825Sdfr{
599178825Sdfr    krb5_error_code ret;
600178825Sdfr
601178825Sdfr    KCM_ASSERT_VALID(ccache);
602178825Sdfr
603178825Sdfr    HEIMDAL_MUTEX_lock(&ccache->mutex);
604178825Sdfr    ret = kcm_ccache_remove_cred_internal(context, ccache, whichfields, mcreds);
605178825Sdfr    HEIMDAL_MUTEX_unlock(&ccache->mutex);
606178825Sdfr
607178825Sdfr    return ret;
608178825Sdfr}
609178825Sdfr
610178825Sdfrkrb5_error_code
611178825Sdfrkcm_ccache_retrieve_cred_internal(krb5_context context,
612178825Sdfr			 	  kcm_ccache ccache,
613178825Sdfr			 	  krb5_flags whichfields,
614178825Sdfr			 	  const krb5_creds *mcreds,
615178825Sdfr			 	  krb5_creds **creds)
616178825Sdfr{
617178825Sdfr    krb5_boolean match;
618178825Sdfr    struct kcm_creds *c;
619178825Sdfr    krb5_error_code ret;
620178825Sdfr
621178825Sdfr    memset(creds, 0, sizeof(*creds));
622178825Sdfr
623178825Sdfr    ret = KRB5_CC_END;
624178825Sdfr
625178825Sdfr    match = FALSE;
626178825Sdfr    for (c = ccache->creds; c != NULL; c = c->next) {
627178825Sdfr	match = krb5_compare_creds(context, whichfields, mcreds, &c->cred);
628178825Sdfr	if (match)
629178825Sdfr	    break;
630178825Sdfr    }
631178825Sdfr
632178825Sdfr    if (match) {
633178825Sdfr	ret = 0;
634178825Sdfr	*creds = &c->cred;
635178825Sdfr    }
636178825Sdfr
637178825Sdfr    return ret;
638178825Sdfr}
639178825Sdfr
640178825Sdfrkrb5_error_code
641178825Sdfrkcm_ccache_retrieve_cred(krb5_context context,
642178825Sdfr			 kcm_ccache ccache,
643178825Sdfr			 krb5_flags whichfields,
644178825Sdfr			 const krb5_creds *mcreds,
645178825Sdfr			 krb5_creds **credp)
646178825Sdfr{
647178825Sdfr    krb5_error_code ret;
648178825Sdfr
649178825Sdfr    KCM_ASSERT_VALID(ccache);
650233294Sstas
651178825Sdfr    HEIMDAL_MUTEX_lock(&ccache->mutex);
652178825Sdfr    ret = kcm_ccache_retrieve_cred_internal(context, ccache,
653178825Sdfr					    whichfields, mcreds, credp);
654178825Sdfr    HEIMDAL_MUTEX_unlock(&ccache->mutex);
655178825Sdfr
656178825Sdfr    return ret;
657178825Sdfr}
658233294Sstas
659233294Sstaschar *
660233294Sstaskcm_ccache_first_name(kcm_client *client)
661233294Sstas{
662233294Sstas    kcm_ccache p;
663233294Sstas    char *name = NULL;
664233294Sstas
665233294Sstas    HEIMDAL_MUTEX_lock(&ccache_mutex);
666233294Sstas
667233294Sstas    for (p = ccache_head; p != NULL; p = p->next) {
668233294Sstas	if (kcm_is_same_session(client, p->uid, p->session))
669233294Sstas	    break;
670233294Sstas    }
671233294Sstas    if (p)
672233294Sstas	name = strdup(p->name);
673233294Sstas    HEIMDAL_MUTEX_unlock(&ccache_mutex);
674233294Sstas    return name;
675233294Sstas}
676