mcache.c revision 72445
1/*
2 * Copyright (c) 1997-2000 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
36RCSID("$Id: mcache.c,v 1.12 2000/11/15 02:12:51 assar Exp $");
37
38typedef struct krb5_mcache {
39    char *name;
40    unsigned int refcnt;
41    krb5_principal primary_principal;
42    struct link {
43	krb5_creds cred;
44	struct link *next;
45    } *creds;
46    struct krb5_mcache *next;
47} krb5_mcache;
48
49static struct krb5_mcache *mcc_head;
50
51#define	MCACHE(X)	((krb5_mcache *)(X)->data.data)
52
53#define MISDEAD(X)	((X)->primary_principal == NULL)
54
55#define MCC_CURSOR(C) ((struct link*)(C))
56
57static char*
58mcc_get_name(krb5_context context,
59	     krb5_ccache id)
60{
61    return MCACHE(id)->name;
62}
63
64static krb5_mcache *
65mcc_alloc(const char *name)
66{
67    krb5_mcache *m;
68    ALLOC(m, 1);
69    if(m == NULL)
70	return NULL;
71    if(name == NULL)
72	asprintf(&m->name, "%p", m);
73    else
74	m->name = strdup(name);
75    if(m->name == NULL) {
76	free(m);
77	return NULL;
78    }
79    m->refcnt = 1;
80    m->primary_principal = NULL;
81    m->creds = NULL;
82    m->next = mcc_head;
83    mcc_head = m;
84    return m;
85}
86
87static krb5_error_code
88mcc_resolve(krb5_context context, krb5_ccache *id, const char *res)
89{
90    krb5_mcache *m;
91
92    for (m = mcc_head; m != NULL; m = m->next)
93	if (strcmp(m->name, res) == 0)
94	    break;
95
96    if (m != NULL) {
97	m->refcnt++;
98	(*id)->data.data = m;
99	(*id)->data.length = sizeof(*m);
100	return 0;
101    }
102
103    m = mcc_alloc(res);
104    if (m == NULL)
105	return KRB5_CC_NOMEM;
106
107    (*id)->data.data = m;
108    (*id)->data.length = sizeof(*m);
109
110    return 0;
111}
112
113
114static krb5_error_code
115mcc_gen_new(krb5_context context, krb5_ccache *id)
116{
117    krb5_mcache *m;
118
119    m = mcc_alloc(NULL);
120
121    if (m == NULL)
122	return KRB5_CC_NOMEM;
123
124    (*id)->data.data = m;
125    (*id)->data.length = sizeof(*m);
126
127    return 0;
128}
129
130static krb5_error_code
131mcc_initialize(krb5_context context,
132	       krb5_ccache id,
133	       krb5_principal primary_principal)
134{
135    return krb5_copy_principal (context,
136				primary_principal,
137				&MCACHE(id)->primary_principal);
138}
139
140static krb5_error_code
141mcc_close(krb5_context context,
142	  krb5_ccache id)
143{
144    krb5_mcache *m = MCACHE(id);
145
146    if (--m->refcnt != 0)
147	return 0;
148
149    if (MISDEAD(m)) {
150	free (m->name);
151	krb5_data_free(&id->data);
152    }
153
154    return 0;
155}
156
157static krb5_error_code
158mcc_destroy(krb5_context context,
159	    krb5_ccache id)
160{
161    krb5_mcache **n, *m = MCACHE(id);
162    struct link *l;
163
164    if (m->refcnt == 0)
165	krb5_abortx(context, "mcc_destroy: refcnt already 0");
166
167    if (!MISDEAD(m)) {
168	/* if this is an active mcache, remove it from the linked
169           list, and free all data */
170	for(n = &mcc_head; n && *n; n = &(*n)->next) {
171	    if(m == *n) {
172		*n = m->next;
173		break;
174	    }
175	}
176	krb5_free_principal (context, m->primary_principal);
177	m->primary_principal = NULL;
178
179	l = m->creds;
180	while (l != NULL) {
181	    struct link *old;
182
183	    krb5_free_creds_contents (context, &l->cred);
184	    old = l;
185	    l = l->next;
186	    free (old);
187	}
188	m->creds = NULL;
189    }
190    return 0;
191}
192
193static krb5_error_code
194mcc_store_cred(krb5_context context,
195	       krb5_ccache id,
196	       krb5_creds *creds)
197{
198    krb5_mcache *m = MCACHE(id);
199    krb5_error_code ret;
200    struct link *l;
201
202    if (MISDEAD(m))
203	return ENOENT;
204
205    l = malloc (sizeof(*l));
206    if (l == NULL)
207	return KRB5_CC_NOMEM;
208    l->next = m->creds;
209    m->creds = l;
210    memset (&l->cred, 0, sizeof(l->cred));
211    ret = krb5_copy_creds_contents (context, creds, &l->cred);
212    if (ret) {
213	m->creds = l->next;
214	free (l);
215	return ret;
216    }
217    return 0;
218}
219
220static krb5_error_code
221mcc_get_principal(krb5_context context,
222		  krb5_ccache id,
223		  krb5_principal *principal)
224{
225    krb5_mcache *m = MCACHE(id);
226
227    if (MISDEAD(m))
228	return ENOENT;
229
230    return krb5_copy_principal (context,
231				m->primary_principal,
232				principal);
233}
234
235static krb5_error_code
236mcc_get_first (krb5_context context,
237	       krb5_ccache id,
238	       krb5_cc_cursor *cursor)
239{
240    krb5_mcache *m = MCACHE(id);
241
242    if (MISDEAD(m))
243	return ENOENT;
244
245    *cursor = m->creds;
246    return 0;
247}
248
249static krb5_error_code
250mcc_get_next (krb5_context context,
251	      krb5_ccache id,
252	      krb5_cc_cursor *cursor,
253	      krb5_creds *creds)
254{
255    krb5_mcache *m = MCACHE(id);
256    struct link *l;
257
258    if (MISDEAD(m))
259	return ENOENT;
260
261    l = *cursor;
262    if (l != NULL) {
263	*cursor = l->next;
264	return krb5_copy_creds_contents (context,
265					 &l->cred,
266					 creds);
267    } else
268	return KRB5_CC_END;
269}
270
271static krb5_error_code
272mcc_end_get (krb5_context context,
273	     krb5_ccache id,
274	     krb5_cc_cursor *cursor)
275{
276    return 0;
277}
278
279static krb5_error_code
280mcc_remove_cred(krb5_context context,
281		 krb5_ccache id,
282		 krb5_flags which,
283		 krb5_creds *mcreds)
284{
285    krb5_mcache *m = MCACHE(id);
286    struct link **q, *p;
287    for(q = &m->creds, p = *q; p; p = *q) {
288	if(krb5_compare_creds(context, which, mcreds, &p->cred)) {
289	    *q = p->next;
290	    krb5_free_cred_contents(context, &p->cred);
291	    free(p);
292	} else
293	    q = &p->next;
294    }
295    return 0;
296}
297
298static krb5_error_code
299mcc_set_flags(krb5_context context,
300	      krb5_ccache id,
301	      krb5_flags flags)
302{
303    return 0; /* XXX */
304}
305
306const krb5_cc_ops krb5_mcc_ops = {
307    "MEMORY",
308    mcc_get_name,
309    mcc_resolve,
310    mcc_gen_new,
311    mcc_initialize,
312    mcc_destroy,
313    mcc_close,
314    mcc_store_cred,
315    NULL, /* mcc_retrieve */
316    mcc_get_principal,
317    mcc_get_first,
318    mcc_get_next,
319    mcc_end_get,
320    mcc_remove_cred,
321    mcc_set_flags
322};
323