xref: /freebsd/crypto/heimdal/lib/krb5/mcache.c (revision 5e9cd1ae3e10592ed70e7575551cba1bbab04d84)
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 
36 RCSID("$Id: mcache.c,v 1.12 2000/11/15 02:12:51 assar Exp $");
37 
38 typedef 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 
49 static 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 
57 static char*
58 mcc_get_name(krb5_context context,
59 	     krb5_ccache id)
60 {
61     return MCACHE(id)->name;
62 }
63 
64 static krb5_mcache *
65 mcc_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 
87 static krb5_error_code
88 mcc_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 
114 static krb5_error_code
115 mcc_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 
130 static krb5_error_code
131 mcc_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 
140 static krb5_error_code
141 mcc_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 
157 static krb5_error_code
158 mcc_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 
193 static krb5_error_code
194 mcc_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 
220 static krb5_error_code
221 mcc_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 
235 static krb5_error_code
236 mcc_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 
249 static krb5_error_code
250 mcc_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 
271 static krb5_error_code
272 mcc_end_get (krb5_context context,
273 	     krb5_ccache id,
274 	     krb5_cc_cursor *cursor)
275 {
276     return 0;
277 }
278 
279 static krb5_error_code
280 mcc_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 
298 static krb5_error_code
299 mcc_set_flags(krb5_context context,
300 	      krb5_ccache id,
301 	      krb5_flags flags)
302 {
303     return 0; /* XXX */
304 }
305 
306 const 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