mcache.c revision 78527
184260Sobrien/*
21573Srgrimes * Copyright (c) 1997-2000 Kungliga Tekniska H�gskolan
351794Smarcel * (Royal Institute of Technology, Stockholm, Sweden).
41573Srgrimes * All rights reserved.
51573Srgrimes *
684260Sobrien * Redistribution and use in source and binary forms, with or without
751794Smarcel * modification, are permitted provided that the following conditions
81573Srgrimes * are met:
926926Smsmith *
1026926Smsmith * 1. Redistributions of source code must retain the above copyright
111573Srgrimes *    notice, this list of conditions and the following disclaimer.
1251904Smarcel *
1351904Smarcel * 2. Redistributions in binary form must reproduce the above copyright
143527Sache *    notice, this list of conditions and the following disclaimer in the
1574870Sru *    documentation and/or other materials provided with the distribution.
1626926Smsmith *
1726926Smsmith * 3. Neither the name of the Institute nor the names of its contributors
1884260Sobrien *    may be used to endorse or promote products derived from this software
1926926Smsmith *    without specific prior written permission.
2026926Smsmith *
2126926Smsmith * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
2226926Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2350088Smdodd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2484260Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
2526926Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3126926Smsmith * SUCH DAMAGE.
3284260Sobrien */
3326926Smsmith
3426926Smsmith#include "krb5_locl.h"
358870Srgrimes
361573SrgrimesRCSID("$Id: mcache.c,v 1.13 2001/05/14 06:14:49 assar Exp $");
371573Srgrimes
381573Srgrimestypedef struct krb5_mcache {
398870Srgrimes    char *name;
401573Srgrimes    unsigned int refcnt;
411573Srgrimes    krb5_principal primary_principal;
421573Srgrimes    struct link {
431573Srgrimes	krb5_creds cred;
441573Srgrimes	struct link *next;
451573Srgrimes    } *creds;
461573Srgrimes    struct krb5_mcache *next;
471573Srgrimes} krb5_mcache;
481573Srgrimes
491573Srgrimesstatic struct krb5_mcache *mcc_head;
501573Srgrimes
511573Srgrimes#define	MCACHE(X)	((krb5_mcache *)(X)->data.data)
521573Srgrimes
531573Srgrimes#define MISDEAD(X)	((X)->primary_principal == NULL)
541573Srgrimes
551573Srgrimes#define MCC_CURSOR(C) ((struct link*)(C))
561573Srgrimes
578870Srgrimesstatic char*
581573Srgrimesmcc_get_name(krb5_context context,
591573Srgrimes	     krb5_ccache id)
601573Srgrimes{
611573Srgrimes    return MCACHE(id)->name;
621573Srgrimes}
6384260Sobrien
6484260Sobrienstatic krb5_mcache *
651573Srgrimesmcc_alloc(const char *name)
6684260Sobrien{
6784260Sobrien    krb5_mcache *m;
6884260Sobrien
691573Srgrimes    ALLOC(m, 1);
7084260Sobrien    if(m == NULL)
7184260Sobrien	return NULL;
722678Srgrimes    if(name == NULL)
7317929Speter	asprintf(&m->name, "%p", m);
741573Srgrimes    else
751573Srgrimes	m->name = strdup(name);
76    if(m->name == NULL) {
77	free(m);
78	return NULL;
79    }
80    m->refcnt = 1;
81    m->primary_principal = NULL;
82    m->creds = NULL;
83    m->next = mcc_head;
84    mcc_head = m;
85    return m;
86}
87
88static krb5_error_code
89mcc_resolve(krb5_context context, krb5_ccache *id, const char *res)
90{
91    krb5_mcache *m;
92
93    for (m = mcc_head; m != NULL; m = m->next)
94	if (strcmp(m->name, res) == 0)
95	    break;
96
97    if (m != NULL) {
98	m->refcnt++;
99	(*id)->data.data = m;
100	(*id)->data.length = sizeof(*m);
101	return 0;
102    }
103
104    m = mcc_alloc(res);
105    if (m == NULL) {
106	krb5_set_error_string (context, "malloc: out of memory");
107	return KRB5_CC_NOMEM;
108    }
109
110    (*id)->data.data = m;
111    (*id)->data.length = sizeof(*m);
112
113    return 0;
114}
115
116
117static krb5_error_code
118mcc_gen_new(krb5_context context, krb5_ccache *id)
119{
120    krb5_mcache *m;
121
122    m = mcc_alloc(NULL);
123
124    if (m == NULL) {
125	krb5_set_error_string (context, "malloc: out of memory");
126	return KRB5_CC_NOMEM;
127    }
128
129    (*id)->data.data = m;
130    (*id)->data.length = sizeof(*m);
131
132    return 0;
133}
134
135static krb5_error_code
136mcc_initialize(krb5_context context,
137	       krb5_ccache id,
138	       krb5_principal primary_principal)
139{
140    return krb5_copy_principal (context,
141				primary_principal,
142				&MCACHE(id)->primary_principal);
143}
144
145static krb5_error_code
146mcc_close(krb5_context context,
147	  krb5_ccache id)
148{
149    krb5_mcache *m = MCACHE(id);
150
151    if (--m->refcnt != 0)
152	return 0;
153
154    if (MISDEAD(m)) {
155	free (m->name);
156	krb5_data_free(&id->data);
157    }
158
159    return 0;
160}
161
162static krb5_error_code
163mcc_destroy(krb5_context context,
164	    krb5_ccache id)
165{
166    krb5_mcache **n, *m = MCACHE(id);
167    struct link *l;
168
169    if (m->refcnt == 0)
170	krb5_abortx(context, "mcc_destroy: refcnt already 0");
171
172    if (!MISDEAD(m)) {
173	/* if this is an active mcache, remove it from the linked
174           list, and free all data */
175	for(n = &mcc_head; n && *n; n = &(*n)->next) {
176	    if(m == *n) {
177		*n = m->next;
178		break;
179	    }
180	}
181	krb5_free_principal (context, m->primary_principal);
182	m->primary_principal = NULL;
183
184	l = m->creds;
185	while (l != NULL) {
186	    struct link *old;
187
188	    krb5_free_creds_contents (context, &l->cred);
189	    old = l;
190	    l = l->next;
191	    free (old);
192	}
193	m->creds = NULL;
194    }
195    return 0;
196}
197
198static krb5_error_code
199mcc_store_cred(krb5_context context,
200	       krb5_ccache id,
201	       krb5_creds *creds)
202{
203    krb5_mcache *m = MCACHE(id);
204    krb5_error_code ret;
205    struct link *l;
206
207    if (MISDEAD(m))
208	return ENOENT;
209
210    l = malloc (sizeof(*l));
211    if (l == NULL) {
212	krb5_set_error_string (context, "malloc: out of memory");
213	return KRB5_CC_NOMEM;
214    }
215    l->next = m->creds;
216    m->creds = l;
217    memset (&l->cred, 0, sizeof(l->cred));
218    ret = krb5_copy_creds_contents (context, creds, &l->cred);
219    if (ret) {
220	m->creds = l->next;
221	free (l);
222	return ret;
223    }
224    return 0;
225}
226
227static krb5_error_code
228mcc_get_principal(krb5_context context,
229		  krb5_ccache id,
230		  krb5_principal *principal)
231{
232    krb5_mcache *m = MCACHE(id);
233
234    if (MISDEAD(m))
235	return ENOENT;
236
237    return krb5_copy_principal (context,
238				m->primary_principal,
239				principal);
240}
241
242static krb5_error_code
243mcc_get_first (krb5_context context,
244	       krb5_ccache id,
245	       krb5_cc_cursor *cursor)
246{
247    krb5_mcache *m = MCACHE(id);
248
249    if (MISDEAD(m))
250	return ENOENT;
251
252    *cursor = m->creds;
253    return 0;
254}
255
256static krb5_error_code
257mcc_get_next (krb5_context context,
258	      krb5_ccache id,
259	      krb5_cc_cursor *cursor,
260	      krb5_creds *creds)
261{
262    krb5_mcache *m = MCACHE(id);
263    struct link *l;
264
265    if (MISDEAD(m))
266	return ENOENT;
267
268    l = *cursor;
269    if (l != NULL) {
270	*cursor = l->next;
271	return krb5_copy_creds_contents (context,
272					 &l->cred,
273					 creds);
274    } else
275	return KRB5_CC_END;
276}
277
278static krb5_error_code
279mcc_end_get (krb5_context context,
280	     krb5_ccache id,
281	     krb5_cc_cursor *cursor)
282{
283    return 0;
284}
285
286static krb5_error_code
287mcc_remove_cred(krb5_context context,
288		 krb5_ccache id,
289		 krb5_flags which,
290		 krb5_creds *mcreds)
291{
292    krb5_mcache *m = MCACHE(id);
293    struct link **q, *p;
294    for(q = &m->creds, p = *q; p; p = *q) {
295	if(krb5_compare_creds(context, which, mcreds, &p->cred)) {
296	    *q = p->next;
297	    krb5_free_cred_contents(context, &p->cred);
298	    free(p);
299	} else
300	    q = &p->next;
301    }
302    return 0;
303}
304
305static krb5_error_code
306mcc_set_flags(krb5_context context,
307	      krb5_ccache id,
308	      krb5_flags flags)
309{
310    return 0; /* XXX */
311}
312
313const krb5_cc_ops krb5_mcc_ops = {
314    "MEMORY",
315    mcc_get_name,
316    mcc_resolve,
317    mcc_gen_new,
318    mcc_initialize,
319    mcc_destroy,
320    mcc_close,
321    mcc_store_cred,
322    NULL, /* mcc_retrieve */
323    mcc_get_principal,
324    mcc_get_first,
325    mcc_get_next,
326    mcc_end_get,
327    mcc_remove_cred,
328    mcc_set_flags
329};
330