xref: /illumos-gate/usr/src/lib/gss_mechs/mech_krb5/krb5/ccache/cc_memory.c (revision 505d05c73a6e56769f263d4803b22eddd168ee24)
1*505d05c7Sgtb /*
2*505d05c7Sgtb  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
3*505d05c7Sgtb  * Use is subject to license terms.
4*505d05c7Sgtb  */
5*505d05c7Sgtb 
6*505d05c7Sgtb #pragma ident	"%Z%%M%	%I%	%E% SMI"
7*505d05c7Sgtb 
8*505d05c7Sgtb /*
9*505d05c7Sgtb  * lib/krb5/ccache/cc_memory.c
10*505d05c7Sgtb  *
11*505d05c7Sgtb  * Copyright 1990,1991,2000,2004 by the Massachusetts Institute of Technology.
12*505d05c7Sgtb  * All Rights Reserved.
13*505d05c7Sgtb  *
14*505d05c7Sgtb  * Export of this software from the United States of America may
15*505d05c7Sgtb  *   require a specific license from the United States Government.
16*505d05c7Sgtb  *   It is the responsibility of any person or organization contemplating
17*505d05c7Sgtb  *   export to obtain such a license before exporting.
18*505d05c7Sgtb  *
19*505d05c7Sgtb  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
20*505d05c7Sgtb  * distribute this software and its documentation for any purpose and
21*505d05c7Sgtb  * without fee is hereby granted, provided that the above copyright
22*505d05c7Sgtb  * notice appear in all copies and that both that copyright notice and
23*505d05c7Sgtb  * this permission notice appear in supporting documentation, and that
24*505d05c7Sgtb  * the name of M.I.T. not be used in advertising or publicity pertaining
25*505d05c7Sgtb  * to distribution of the software without specific, written prior
26*505d05c7Sgtb  * permission.  Furthermore if you modify this software you must label
27*505d05c7Sgtb  * your software as modified software and not distribute it in such a
28*505d05c7Sgtb  * fashion that it might be confused with the original M.I.T. software.
29*505d05c7Sgtb  * M.I.T. makes no representations about the suitability of
30*505d05c7Sgtb  * this software for any purpose.  It is provided "as is" without express
31*505d05c7Sgtb  * or implied warranty.
32*505d05c7Sgtb  *
33*505d05c7Sgtb  *
34*505d05c7Sgtb  * implementation of memory-based credentials cache
35*505d05c7Sgtb  */
36*505d05c7Sgtb #include "k5-int.h"
37*505d05c7Sgtb #include <errno.h>
38*505d05c7Sgtb 
39*505d05c7Sgtb static krb5_error_code KRB5_CALLCONV krb5_mcc_close
40*505d05c7Sgtb 	(krb5_context, krb5_ccache id );
41*505d05c7Sgtb 
42*505d05c7Sgtb static krb5_error_code KRB5_CALLCONV krb5_mcc_destroy
43*505d05c7Sgtb 	(krb5_context, krb5_ccache id );
44*505d05c7Sgtb 
45*505d05c7Sgtb static krb5_error_code KRB5_CALLCONV krb5_mcc_end_seq_get
46*505d05c7Sgtb 	(krb5_context, krb5_ccache id , krb5_cc_cursor *cursor );
47*505d05c7Sgtb 
48*505d05c7Sgtb static krb5_error_code KRB5_CALLCONV krb5_mcc_generate_new
49*505d05c7Sgtb 	(krb5_context, krb5_ccache *id );
50*505d05c7Sgtb 
51*505d05c7Sgtb static const char * KRB5_CALLCONV krb5_mcc_get_name
52*505d05c7Sgtb 	(krb5_context, krb5_ccache id );
53*505d05c7Sgtb 
54*505d05c7Sgtb static krb5_error_code KRB5_CALLCONV krb5_mcc_get_principal
55*505d05c7Sgtb 	(krb5_context, krb5_ccache id , krb5_principal *princ );
56*505d05c7Sgtb 
57*505d05c7Sgtb static krb5_error_code KRB5_CALLCONV krb5_mcc_initialize
58*505d05c7Sgtb 	(krb5_context, krb5_ccache id , krb5_principal princ );
59*505d05c7Sgtb 
60*505d05c7Sgtb static krb5_error_code KRB5_CALLCONV krb5_mcc_next_cred
61*505d05c7Sgtb 	(krb5_context,
62*505d05c7Sgtb 		   krb5_ccache id ,
63*505d05c7Sgtb 		   krb5_cc_cursor *cursor ,
64*505d05c7Sgtb 		   krb5_creds *creds );
65*505d05c7Sgtb 
66*505d05c7Sgtb static krb5_error_code KRB5_CALLCONV krb5_mcc_resolve
67*505d05c7Sgtb 	(krb5_context, krb5_ccache *id , const char *residual );
68*505d05c7Sgtb 
69*505d05c7Sgtb static krb5_error_code KRB5_CALLCONV krb5_mcc_retrieve
70*505d05c7Sgtb 	(krb5_context,
71*505d05c7Sgtb 		   krb5_ccache id ,
72*505d05c7Sgtb 		   krb5_flags whichfields ,
73*505d05c7Sgtb 		   krb5_creds *mcreds ,
74*505d05c7Sgtb 		   krb5_creds *creds );
75*505d05c7Sgtb 
76*505d05c7Sgtb static krb5_error_code KRB5_CALLCONV krb5_mcc_start_seq_get
77*505d05c7Sgtb 	(krb5_context, krb5_ccache id , krb5_cc_cursor *cursor );
78*505d05c7Sgtb 
79*505d05c7Sgtb static krb5_error_code KRB5_CALLCONV krb5_mcc_store
80*505d05c7Sgtb 	(krb5_context, krb5_ccache id , krb5_creds *creds );
81*505d05c7Sgtb 
82*505d05c7Sgtb static krb5_error_code KRB5_CALLCONV krb5_mcc_set_flags
83*505d05c7Sgtb 	(krb5_context, krb5_ccache id , krb5_flags flags );
84*505d05c7Sgtb 
85*505d05c7Sgtb extern const krb5_cc_ops krb5_mcc_ops;
86*505d05c7Sgtb extern krb5_error_code krb5_change_cache (void);
87*505d05c7Sgtb 
88*505d05c7Sgtb #define KRB5_OK 0
89*505d05c7Sgtb 
90*505d05c7Sgtb typedef struct _krb5_mcc_link {
91*505d05c7Sgtb     struct _krb5_mcc_link *next;
92*505d05c7Sgtb     krb5_creds *creds;
93*505d05c7Sgtb } krb5_mcc_link, *krb5_mcc_cursor;
94*505d05c7Sgtb 
95*505d05c7Sgtb typedef struct _krb5_mcc_data {
96*505d05c7Sgtb     char *name;
97*505d05c7Sgtb     k5_mutex_t lock;
98*505d05c7Sgtb     krb5_principal prin;
99*505d05c7Sgtb     krb5_mcc_cursor link;
100*505d05c7Sgtb } krb5_mcc_data;
101*505d05c7Sgtb 
102*505d05c7Sgtb typedef struct krb5_mcc_list_node {
103*505d05c7Sgtb     struct krb5_mcc_list_node *next;
104*505d05c7Sgtb     krb5_mcc_data *cache;
105*505d05c7Sgtb } krb5_mcc_list_node;
106*505d05c7Sgtb 
107*505d05c7Sgtb k5_mutex_t krb5int_mcc_mutex = K5_MUTEX_PARTIAL_INITIALIZER;
108*505d05c7Sgtb static krb5_mcc_list_node *mcc_head = 0;
109*505d05c7Sgtb 
110*505d05c7Sgtb /*
111*505d05c7Sgtb  * Modifies:
112*505d05c7Sgtb  * id
113*505d05c7Sgtb  *
114*505d05c7Sgtb  * Effects:
115*505d05c7Sgtb  * Creates/refreshes the file cred cache id.  If the cache exists, its
116*505d05c7Sgtb  * contents are destroyed.
117*505d05c7Sgtb  *
118*505d05c7Sgtb  * Errors:
119*505d05c7Sgtb  * system errors
120*505d05c7Sgtb  * permission errors
121*505d05c7Sgtb  */
122*505d05c7Sgtb static void krb5_mcc_free (krb5_context context, krb5_ccache id);
123*505d05c7Sgtb 
124*505d05c7Sgtb krb5_error_code KRB5_CALLCONV
125*505d05c7Sgtb krb5_mcc_initialize(krb5_context context, krb5_ccache id, krb5_principal princ)
126*505d05c7Sgtb {
127*505d05c7Sgtb     krb5_error_code ret;
128*505d05c7Sgtb 
129*505d05c7Sgtb     krb5_mcc_free(context, id);
130*505d05c7Sgtb     ret = krb5_copy_principal(context, princ,
131*505d05c7Sgtb 			      &((krb5_mcc_data *)id->data)->prin);
132*505d05c7Sgtb     if (ret == KRB5_OK)
133*505d05c7Sgtb         krb5_change_cache();
134*505d05c7Sgtb     return ret;
135*505d05c7Sgtb }
136*505d05c7Sgtb 
137*505d05c7Sgtb /*
138*505d05c7Sgtb  * Modifies:
139*505d05c7Sgtb  * id
140*505d05c7Sgtb  *
141*505d05c7Sgtb  * Effects:
142*505d05c7Sgtb  * Closes the file cache, invalidates the id, and frees any resources
143*505d05c7Sgtb  * associated with the cache.
144*505d05c7Sgtb  */
145*505d05c7Sgtb krb5_error_code KRB5_CALLCONV
146*505d05c7Sgtb krb5_mcc_close(krb5_context context, krb5_ccache id)
147*505d05c7Sgtb {
148*505d05c7Sgtb      krb5_xfree(id);
149*505d05c7Sgtb      return KRB5_OK;
150*505d05c7Sgtb }
151*505d05c7Sgtb 
152*505d05c7Sgtb void
153*505d05c7Sgtb krb5_mcc_free(krb5_context context, krb5_ccache id)
154*505d05c7Sgtb {
155*505d05c7Sgtb     krb5_mcc_cursor curr,next;
156*505d05c7Sgtb     krb5_mcc_data *d;
157*505d05c7Sgtb 
158*505d05c7Sgtb     d = (krb5_mcc_data *) id->data;
159*505d05c7Sgtb     for (curr = d->link; curr;) {
160*505d05c7Sgtb 	krb5_free_creds(context, curr->creds);
161*505d05c7Sgtb 	next = curr->next;
162*505d05c7Sgtb 	krb5_xfree(curr);
163*505d05c7Sgtb 	curr = next;
164*505d05c7Sgtb     }
165*505d05c7Sgtb     d->link = NULL;
166*505d05c7Sgtb     krb5_free_principal(context, d->prin);
167*505d05c7Sgtb }
168*505d05c7Sgtb 
169*505d05c7Sgtb /*
170*505d05c7Sgtb  * Effects:
171*505d05c7Sgtb  * Destroys the contents of id.
172*505d05c7Sgtb  *
173*505d05c7Sgtb  * Errors:
174*505d05c7Sgtb  * none
175*505d05c7Sgtb  */
176*505d05c7Sgtb krb5_error_code KRB5_CALLCONV
177*505d05c7Sgtb krb5_mcc_destroy(krb5_context context, krb5_ccache id)
178*505d05c7Sgtb {
179*505d05c7Sgtb     krb5_mcc_list_node **curr, *node;
180*505d05c7Sgtb     krb5_mcc_data *d;
181*505d05c7Sgtb     krb5_error_code err;
182*505d05c7Sgtb 
183*505d05c7Sgtb     err = k5_mutex_lock(&krb5int_mcc_mutex);
184*505d05c7Sgtb     if (err)
185*505d05c7Sgtb 	return err;
186*505d05c7Sgtb 
187*505d05c7Sgtb     d = (krb5_mcc_data *)id->data;
188*505d05c7Sgtb     for (curr = &mcc_head; *curr; curr = &(*curr)->next) {
189*505d05c7Sgtb 	if ((*curr)->cache == d) {
190*505d05c7Sgtb 	    node = *curr;
191*505d05c7Sgtb 	    *curr = node->next;
192*505d05c7Sgtb 	    free(node);
193*505d05c7Sgtb 	    break;
194*505d05c7Sgtb 	}
195*505d05c7Sgtb     }
196*505d05c7Sgtb     k5_mutex_unlock(&krb5int_mcc_mutex);
197*505d05c7Sgtb 
198*505d05c7Sgtb     krb5_mcc_free(context, id);
199*505d05c7Sgtb     krb5_xfree(d->name);
200*505d05c7Sgtb     k5_mutex_destroy(&d->lock);
201*505d05c7Sgtb     krb5_xfree(d);
202*505d05c7Sgtb     krb5_xfree(id);
203*505d05c7Sgtb 
204*505d05c7Sgtb     krb5_change_cache ();
205*505d05c7Sgtb     return KRB5_OK;
206*505d05c7Sgtb }
207*505d05c7Sgtb 
208*505d05c7Sgtb /*
209*505d05c7Sgtb  * Requires:
210*505d05c7Sgtb  * residual is a legal path name, and a null-terminated string
211*505d05c7Sgtb  *
212*505d05c7Sgtb  * Modifies:
213*505d05c7Sgtb  * id
214*505d05c7Sgtb  *
215*505d05c7Sgtb  * Effects:
216*505d05c7Sgtb  * creates a file-based cred cache that will reside in the file
217*505d05c7Sgtb  * residual.  The cache is not opened, but the filename is reserved.
218*505d05c7Sgtb  *
219*505d05c7Sgtb  * Returns:
220*505d05c7Sgtb  * A filled in krb5_ccache structure "id".
221*505d05c7Sgtb  *
222*505d05c7Sgtb  * Errors:
223*505d05c7Sgtb  * KRB5_CC_NOMEM - there was insufficient memory to allocate the
224*505d05c7Sgtb  *              krb5_ccache.  id is undefined.
225*505d05c7Sgtb  * permission errors
226*505d05c7Sgtb  */
227*505d05c7Sgtb static krb5_error_code new_mcc_data (const char *, krb5_mcc_data **);
228*505d05c7Sgtb 
229*505d05c7Sgtb krb5_error_code KRB5_CALLCONV
230*505d05c7Sgtb krb5_mcc_resolve (krb5_context context, krb5_ccache *id, const char *residual)
231*505d05c7Sgtb {
232*505d05c7Sgtb     krb5_ccache lid;
233*505d05c7Sgtb     krb5_mcc_list_node *ptr;
234*505d05c7Sgtb     krb5_error_code err;
235*505d05c7Sgtb     krb5_mcc_data *d;
236*505d05c7Sgtb 
237*505d05c7Sgtb     lid = (krb5_ccache) malloc(sizeof(struct _krb5_ccache));
238*505d05c7Sgtb     if (lid == NULL)
239*505d05c7Sgtb 	return KRB5_CC_NOMEM;
240*505d05c7Sgtb 
241*505d05c7Sgtb     lid->ops = &krb5_mcc_ops;
242*505d05c7Sgtb 
243*505d05c7Sgtb     err = k5_mutex_lock(&krb5int_mcc_mutex);
244*505d05c7Sgtb     if (err) {
245*505d05c7Sgtb         /* SUNW14resync - fix mem leak */
246*505d05c7Sgtb         krb5_xfree(lid);
247*505d05c7Sgtb 	return err;
248*505d05c7Sgtb     }
249*505d05c7Sgtb     for (ptr = mcc_head; ptr; ptr=ptr->next)
250*505d05c7Sgtb 	if (!strcmp(ptr->cache->name, residual))
251*505d05c7Sgtb 	    break;
252*505d05c7Sgtb     if (ptr)
253*505d05c7Sgtb 	d = ptr->cache;
254*505d05c7Sgtb     else {
255*505d05c7Sgtb 	err = new_mcc_data(residual, &d);
256*505d05c7Sgtb 	if (err) {
257*505d05c7Sgtb 	    k5_mutex_unlock(&krb5int_mcc_mutex);
258*505d05c7Sgtb 	    krb5_xfree(lid);
259*505d05c7Sgtb 	    return err;
260*505d05c7Sgtb 	}
261*505d05c7Sgtb     }
262*505d05c7Sgtb     k5_mutex_unlock(&krb5int_mcc_mutex);
263*505d05c7Sgtb     lid->data = d;
264*505d05c7Sgtb     *id = lid;
265*505d05c7Sgtb     return KRB5_OK;
266*505d05c7Sgtb }
267*505d05c7Sgtb 
268*505d05c7Sgtb /*
269*505d05c7Sgtb  * Effects:
270*505d05c7Sgtb  * Prepares for a sequential search of the credentials cache.
271*505d05c7Sgtb  * Returns a krb5_cc_cursor to be used with krb5_mcc_next_cred and
272*505d05c7Sgtb  * krb5_mcc_end_seq_get.
273*505d05c7Sgtb  *
274*505d05c7Sgtb  * If the cache is modified between the time of this call and the time
275*505d05c7Sgtb  * of the final krb5_mcc_end_seq_get, the results are undefined.
276*505d05c7Sgtb  *
277*505d05c7Sgtb  * Errors:
278*505d05c7Sgtb  * KRB5_CC_NOMEM
279*505d05c7Sgtb  * system errors
280*505d05c7Sgtb  */
281*505d05c7Sgtb krb5_error_code KRB5_CALLCONV
282*505d05c7Sgtb krb5_mcc_start_seq_get(krb5_context context, krb5_ccache id,
283*505d05c7Sgtb 		       krb5_cc_cursor *cursor)
284*505d05c7Sgtb {
285*505d05c7Sgtb      krb5_mcc_cursor mcursor;
286*505d05c7Sgtb      krb5_error_code err;
287*505d05c7Sgtb      krb5_mcc_data *d;
288*505d05c7Sgtb 
289*505d05c7Sgtb      d = id->data;
290*505d05c7Sgtb      err = k5_mutex_lock(&d->lock);
291*505d05c7Sgtb      if (err)
292*505d05c7Sgtb 	 return err;
293*505d05c7Sgtb      mcursor = d->link;
294*505d05c7Sgtb      k5_mutex_unlock(&d->lock);
295*505d05c7Sgtb      *cursor = (krb5_cc_cursor) mcursor;
296*505d05c7Sgtb      return KRB5_OK;
297*505d05c7Sgtb }
298*505d05c7Sgtb 
299*505d05c7Sgtb /*
300*505d05c7Sgtb  * Requires:
301*505d05c7Sgtb  * cursor is a krb5_cc_cursor originally obtained from
302*505d05c7Sgtb  * krb5_mcc_start_seq_get.
303*505d05c7Sgtb  *
304*505d05c7Sgtb  * Modifes:
305*505d05c7Sgtb  * cursor, creds
306*505d05c7Sgtb  *
307*505d05c7Sgtb  * Effects:
308*505d05c7Sgtb  * Fills in creds with the "next" credentals structure from the cache
309*505d05c7Sgtb  * id.  The actual order the creds are returned in is arbitrary.
310*505d05c7Sgtb  * Space is allocated for the variable length fields in the
311*505d05c7Sgtb  * credentials structure, so the object returned must be passed to
312*505d05c7Sgtb  * krb5_destroy_credential.
313*505d05c7Sgtb  *
314*505d05c7Sgtb  * The cursor is updated for the next call to krb5_mcc_next_cred.
315*505d05c7Sgtb  *
316*505d05c7Sgtb  * Errors:
317*505d05c7Sgtb  * system errors
318*505d05c7Sgtb  */
319*505d05c7Sgtb krb5_error_code KRB5_CALLCONV
320*505d05c7Sgtb krb5_mcc_next_cred(krb5_context context, krb5_ccache id,
321*505d05c7Sgtb 		   krb5_cc_cursor *cursor, krb5_creds *creds)
322*505d05c7Sgtb {
323*505d05c7Sgtb      krb5_mcc_cursor mcursor;
324*505d05c7Sgtb      krb5_error_code retval;
325*505d05c7Sgtb      krb5_data *scratch;
326*505d05c7Sgtb 
327*505d05c7Sgtb      /* Once the node in the linked list is created, it's never
328*505d05c7Sgtb 	modified, so we don't need to worry about locking here.  (Note
329*505d05c7Sgtb 	that we don't support _remove_cred.)  */
330*505d05c7Sgtb      mcursor = (krb5_mcc_cursor) *cursor;
331*505d05c7Sgtb      if (mcursor == NULL)
332*505d05c7Sgtb 	return KRB5_CC_END;
333*505d05c7Sgtb      memset(creds, 0, sizeof(krb5_creds));
334*505d05c7Sgtb      if (mcursor->creds) {
335*505d05c7Sgtb 	*creds = *mcursor->creds;
336*505d05c7Sgtb 	retval = krb5_copy_principal(context, mcursor->creds->client, &creds->client);
337*505d05c7Sgtb 	if (retval)
338*505d05c7Sgtb 		return retval;
339*505d05c7Sgtb 	retval = krb5_copy_principal(context, mcursor->creds->server,
340*505d05c7Sgtb 		&creds->server);
341*505d05c7Sgtb 	if (retval)
342*505d05c7Sgtb 		goto cleanclient;
343*505d05c7Sgtb 	retval = krb5_copy_keyblock_contents(context, &mcursor->creds->keyblock,
344*505d05c7Sgtb 		&creds->keyblock);
345*505d05c7Sgtb 	if (retval)
346*505d05c7Sgtb 		goto cleanserver;
347*505d05c7Sgtb 	retval = krb5_copy_addresses(context, mcursor->creds->addresses,
348*505d05c7Sgtb 		&creds->addresses);
349*505d05c7Sgtb 	if (retval)
350*505d05c7Sgtb 		goto cleanblock;
351*505d05c7Sgtb 	retval = krb5_copy_data(context, &mcursor->creds->ticket, &scratch);
352*505d05c7Sgtb 	if (retval)
353*505d05c7Sgtb 		goto cleanaddrs;
354*505d05c7Sgtb 	creds->ticket = *scratch;
355*505d05c7Sgtb 	krb5_xfree(scratch);
356*505d05c7Sgtb 	retval = krb5_copy_data(context, &mcursor->creds->second_ticket, &scratch);
357*505d05c7Sgtb 	if (retval)
358*505d05c7Sgtb 		goto cleanticket;
359*505d05c7Sgtb 	creds->second_ticket = *scratch;
360*505d05c7Sgtb 	krb5_xfree(scratch);
361*505d05c7Sgtb 	retval = krb5_copy_authdata(context, mcursor->creds->authdata,
362*505d05c7Sgtb 		&creds->authdata);
363*505d05c7Sgtb 	if (retval)
364*505d05c7Sgtb 		goto clearticket;
365*505d05c7Sgtb      }
366*505d05c7Sgtb      *cursor = (krb5_cc_cursor)mcursor->next;
367*505d05c7Sgtb      return KRB5_OK;
368*505d05c7Sgtb 
369*505d05c7Sgtb clearticket:
370*505d05c7Sgtb 	memset(creds->ticket.data,0, (unsigned) creds->ticket.length);
371*505d05c7Sgtb cleanticket:
372*505d05c7Sgtb 	krb5_xfree(creds->ticket.data);
373*505d05c7Sgtb cleanaddrs:
374*505d05c7Sgtb 	krb5_free_addresses(context, creds->addresses);
375*505d05c7Sgtb cleanblock:
376*505d05c7Sgtb 	krb5_xfree(creds->keyblock.contents);
377*505d05c7Sgtb cleanserver:
378*505d05c7Sgtb 	krb5_free_principal(context, creds->server);
379*505d05c7Sgtb cleanclient:
380*505d05c7Sgtb 	krb5_free_principal(context, creds->client);
381*505d05c7Sgtb 	return retval;
382*505d05c7Sgtb }
383*505d05c7Sgtb 
384*505d05c7Sgtb /*
385*505d05c7Sgtb  * Requires:
386*505d05c7Sgtb  * cursor is a krb5_cc_cursor originally obtained from
387*505d05c7Sgtb  * krb5_mcc_start_seq_get.
388*505d05c7Sgtb  *
389*505d05c7Sgtb  * Modifies:
390*505d05c7Sgtb  * id, cursor
391*505d05c7Sgtb  *
392*505d05c7Sgtb  * Effects:
393*505d05c7Sgtb  * Finishes sequential processing of the file credentials ccache id,
394*505d05c7Sgtb  * and invalidates the cursor (it must never be used after this call).
395*505d05c7Sgtb  */
396*505d05c7Sgtb /* ARGSUSED */
397*505d05c7Sgtb krb5_error_code KRB5_CALLCONV
398*505d05c7Sgtb krb5_mcc_end_seq_get(krb5_context context, krb5_ccache id, krb5_cc_cursor *cursor)
399*505d05c7Sgtb {
400*505d05c7Sgtb      *cursor = 0L;
401*505d05c7Sgtb      return KRB5_OK;
402*505d05c7Sgtb }
403*505d05c7Sgtb 
404*505d05c7Sgtb /* Utility routine: Creates the back-end data for a memory cache, and
405*505d05c7Sgtb    threads it into the global linked list.
406*505d05c7Sgtb 
407*505d05c7Sgtb    Call with the global list lock held.  */
408*505d05c7Sgtb static krb5_error_code
409*505d05c7Sgtb new_mcc_data (const char *name, krb5_mcc_data **dataptr)
410*505d05c7Sgtb {
411*505d05c7Sgtb     krb5_error_code err;
412*505d05c7Sgtb     krb5_mcc_data *d;
413*505d05c7Sgtb     krb5_mcc_list_node *n;
414*505d05c7Sgtb 
415*505d05c7Sgtb     d = malloc(sizeof(krb5_mcc_data));
416*505d05c7Sgtb     if (d == NULL)
417*505d05c7Sgtb 	return KRB5_CC_NOMEM;
418*505d05c7Sgtb 
419*505d05c7Sgtb     err = k5_mutex_init(&d->lock);
420*505d05c7Sgtb     if (err) {
421*505d05c7Sgtb 	krb5_xfree(d);
422*505d05c7Sgtb 	return err;
423*505d05c7Sgtb     }
424*505d05c7Sgtb 
425*505d05c7Sgtb     d->name = malloc(strlen(name) + 1);
426*505d05c7Sgtb     if (d->name == NULL) {
427*505d05c7Sgtb 	k5_mutex_destroy(&d->lock);
428*505d05c7Sgtb 	krb5_xfree(d);
429*505d05c7Sgtb 	return KRB5_CC_NOMEM;
430*505d05c7Sgtb     }
431*505d05c7Sgtb     d->link = NULL;
432*505d05c7Sgtb     d->prin = NULL;
433*505d05c7Sgtb 
434*505d05c7Sgtb     /* Set up the filename */
435*505d05c7Sgtb     strcpy(d->name, name);
436*505d05c7Sgtb 
437*505d05c7Sgtb     n = malloc(sizeof(krb5_mcc_list_node));
438*505d05c7Sgtb     if (n == NULL) {
439*505d05c7Sgtb 	free(d->name);
440*505d05c7Sgtb 	k5_mutex_destroy(&d->lock);
441*505d05c7Sgtb 	free(d);
442*505d05c7Sgtb 	return KRB5_CC_NOMEM;
443*505d05c7Sgtb     }
444*505d05c7Sgtb 
445*505d05c7Sgtb     n->cache = d;
446*505d05c7Sgtb     n->next = mcc_head;
447*505d05c7Sgtb     mcc_head = n;
448*505d05c7Sgtb 
449*505d05c7Sgtb     *dataptr = d;
450*505d05c7Sgtb     return 0;
451*505d05c7Sgtb }
452*505d05c7Sgtb 
453*505d05c7Sgtb /*
454*505d05c7Sgtb  * Effects:
455*505d05c7Sgtb  * Creates a new file cred cache whose name is guaranteed to be
456*505d05c7Sgtb  * unique.  The name begins with the string TKT_ROOT (from mcc.h).
457*505d05c7Sgtb  * The cache is not opened, but the new filename is reserved.
458*505d05c7Sgtb  *
459*505d05c7Sgtb  * Returns:
460*505d05c7Sgtb  * The filled in krb5_ccache id.
461*505d05c7Sgtb  *
462*505d05c7Sgtb  * Errors:
463*505d05c7Sgtb  * KRB5_CC_NOMEM - there was insufficient memory to allocate the
464*505d05c7Sgtb  *              krb5_ccache.  id is undefined.
465*505d05c7Sgtb  * system errors (from open)
466*505d05c7Sgtb  */
467*505d05c7Sgtb krb5_error_code KRB5_CALLCONV
468*505d05c7Sgtb krb5_mcc_generate_new (krb5_context context, krb5_ccache *id)
469*505d05c7Sgtb {
470*505d05c7Sgtb     krb5_ccache lid;
471*505d05c7Sgtb     char scratch[6+1]; /* 6 for the scratch part, +1 for NUL */
472*505d05c7Sgtb     krb5_error_code err;
473*505d05c7Sgtb     krb5_mcc_data *d;
474*505d05c7Sgtb 
475*505d05c7Sgtb     /* Allocate memory */
476*505d05c7Sgtb     lid = (krb5_ccache) malloc(sizeof(struct _krb5_ccache));
477*505d05c7Sgtb     if (lid == NULL)
478*505d05c7Sgtb 	return KRB5_CC_NOMEM;
479*505d05c7Sgtb 
480*505d05c7Sgtb     lid->ops = &krb5_mcc_ops;
481*505d05c7Sgtb 
482*505d05c7Sgtb     (void) strcpy(scratch, "XXXXXX");
483*505d05c7Sgtb     mktemp(scratch);
484*505d05c7Sgtb 
485*505d05c7Sgtb     err = k5_mutex_lock(&krb5int_mcc_mutex);
486*505d05c7Sgtb     if (err) {
487*505d05c7Sgtb 	free(lid);
488*505d05c7Sgtb 	return err;
489*505d05c7Sgtb     }
490*505d05c7Sgtb     err = new_mcc_data(scratch, &d);
491*505d05c7Sgtb     k5_mutex_unlock(&krb5int_mcc_mutex);
492*505d05c7Sgtb     if (err) {
493*505d05c7Sgtb 	krb5_xfree(lid);
494*505d05c7Sgtb 	return err;
495*505d05c7Sgtb     }
496*505d05c7Sgtb     lid->data = d;
497*505d05c7Sgtb     *id = lid; /* SUNW14resync - fix to 1.4.2 */
498*505d05c7Sgtb     krb5_change_cache ();
499*505d05c7Sgtb     return KRB5_OK;
500*505d05c7Sgtb }
501*505d05c7Sgtb 
502*505d05c7Sgtb /*
503*505d05c7Sgtb  * Requires:
504*505d05c7Sgtb  * id is a file credential cache
505*505d05c7Sgtb  *
506*505d05c7Sgtb  * Returns:
507*505d05c7Sgtb  * The name of the file cred cache id.
508*505d05c7Sgtb  */
509*505d05c7Sgtb const char * KRB5_CALLCONV
510*505d05c7Sgtb krb5_mcc_get_name (krb5_context context, krb5_ccache id)
511*505d05c7Sgtb {
512*505d05c7Sgtb      return (char *) ((krb5_mcc_data *) id->data)->name;
513*505d05c7Sgtb }
514*505d05c7Sgtb 
515*505d05c7Sgtb /*
516*505d05c7Sgtb  * Modifies:
517*505d05c7Sgtb  * id, princ
518*505d05c7Sgtb  *
519*505d05c7Sgtb  * Effects:
520*505d05c7Sgtb  * Retrieves the primary principal from id, as set with
521*505d05c7Sgtb  * krb5_mcc_initialize.  The principal is returned is allocated
522*505d05c7Sgtb  * storage that must be freed by the caller via krb5_free_principal.
523*505d05c7Sgtb  *
524*505d05c7Sgtb  * Errors:
525*505d05c7Sgtb  * system errors
526*505d05c7Sgtb  * KRB5_CC_NOMEM
527*505d05c7Sgtb  */
528*505d05c7Sgtb krb5_error_code KRB5_CALLCONV
529*505d05c7Sgtb krb5_mcc_get_principal(krb5_context context, krb5_ccache id, krb5_principal *princ)
530*505d05c7Sgtb {
531*505d05c7Sgtb      krb5_mcc_data *ptr = (krb5_mcc_data *)id->data;
532*505d05c7Sgtb      if (!ptr->prin) {
533*505d05c7Sgtb         *princ = 0L;
534*505d05c7Sgtb         return KRB5_FCC_NOFILE;
535*505d05c7Sgtb      }
536*505d05c7Sgtb      return krb5_copy_principal(context, ptr->prin, princ);
537*505d05c7Sgtb }
538*505d05c7Sgtb 
539*505d05c7Sgtb krb5_error_code KRB5_CALLCONV
540*505d05c7Sgtb krb5_mcc_retrieve(krb5_context context, krb5_ccache id, krb5_flags whichfields,
541*505d05c7Sgtb 		  krb5_creds *mcreds, krb5_creds *creds)
542*505d05c7Sgtb {
543*505d05c7Sgtb     return krb5_cc_retrieve_cred_default (context, id, whichfields,
544*505d05c7Sgtb 					  mcreds, creds);
545*505d05c7Sgtb }
546*505d05c7Sgtb 
547*505d05c7Sgtb /*
548*505d05c7Sgtb  * Non-functional stub implementation for krb5_mcc_remove
549*505d05c7Sgtb  *
550*505d05c7Sgtb  * Errors:
551*505d05c7Sgtb  *    KRB5_CC_NOSUPP - not implemented
552*505d05c7Sgtb  */
553*505d05c7Sgtb static krb5_error_code KRB5_CALLCONV
554*505d05c7Sgtb krb5_mcc_remove_cred(krb5_context context, krb5_ccache cache, krb5_flags flags,
555*505d05c7Sgtb                      krb5_creds *creds)
556*505d05c7Sgtb {
557*505d05c7Sgtb     return KRB5_CC_NOSUPP;
558*505d05c7Sgtb }
559*505d05c7Sgtb 
560*505d05c7Sgtb 
561*505d05c7Sgtb /*
562*505d05c7Sgtb  * Requires:
563*505d05c7Sgtb  * id is a cred cache returned by krb5_mcc_resolve or
564*505d05c7Sgtb  * krb5_mcc_generate_new, but has not been opened by krb5_mcc_initialize.
565*505d05c7Sgtb  *
566*505d05c7Sgtb  * Modifies:
567*505d05c7Sgtb  * id
568*505d05c7Sgtb  *
569*505d05c7Sgtb  * Effects:
570*505d05c7Sgtb  * Sets the operational flags of id to flags.
571*505d05c7Sgtb  */
572*505d05c7Sgtb krb5_error_code KRB5_CALLCONV
573*505d05c7Sgtb krb5_mcc_set_flags(krb5_context context, krb5_ccache id, krb5_flags flags)
574*505d05c7Sgtb {
575*505d05c7Sgtb     return KRB5_OK;
576*505d05c7Sgtb }
577*505d05c7Sgtb 
578*505d05c7Sgtb /* store: Save away creds in the ccache.  */
579*505d05c7Sgtb krb5_error_code KRB5_CALLCONV
580*505d05c7Sgtb krb5_mcc_store(krb5_context ctx, krb5_ccache id, krb5_creds *creds)
581*505d05c7Sgtb {
582*505d05c7Sgtb     krb5_error_code err;
583*505d05c7Sgtb     krb5_mcc_link *new_node;
584*505d05c7Sgtb     krb5_mcc_data *mptr = (krb5_mcc_data *)id->data;
585*505d05c7Sgtb 
586*505d05c7Sgtb     new_node = malloc(sizeof(krb5_mcc_link));
587*505d05c7Sgtb     if (new_node == NULL)
588*505d05c7Sgtb 	return errno;
589*505d05c7Sgtb     err = krb5_copy_creds(ctx, creds, &new_node->creds);
590*505d05c7Sgtb     if (err) {
591*505d05c7Sgtb 	free(new_node);
592*505d05c7Sgtb 	return err;
593*505d05c7Sgtb     }
594*505d05c7Sgtb     err = k5_mutex_lock(&mptr->lock);
595*505d05c7Sgtb     if (err) {
596*505d05c7Sgtb         /* SUNW14resync - fix mem leak */
597*505d05c7Sgtb 	free(new_node);
598*505d05c7Sgtb 	return err;
599*505d05c7Sgtb     }
600*505d05c7Sgtb     new_node->next = mptr->link;
601*505d05c7Sgtb     mptr->link = new_node;
602*505d05c7Sgtb     k5_mutex_unlock(&mptr->lock);
603*505d05c7Sgtb     return 0;
604*505d05c7Sgtb }
605*505d05c7Sgtb 
606*505d05c7Sgtb const krb5_cc_ops krb5_mcc_ops = {
607*505d05c7Sgtb      0,
608*505d05c7Sgtb      "MEMORY",
609*505d05c7Sgtb      krb5_mcc_get_name,
610*505d05c7Sgtb      krb5_mcc_resolve,
611*505d05c7Sgtb      krb5_mcc_generate_new,
612*505d05c7Sgtb      krb5_mcc_initialize,
613*505d05c7Sgtb      krb5_mcc_destroy,
614*505d05c7Sgtb      krb5_mcc_close,
615*505d05c7Sgtb      krb5_mcc_store,
616*505d05c7Sgtb      krb5_mcc_retrieve,
617*505d05c7Sgtb      krb5_mcc_get_principal,
618*505d05c7Sgtb      krb5_mcc_start_seq_get,
619*505d05c7Sgtb      krb5_mcc_next_cred,
620*505d05c7Sgtb      krb5_mcc_end_seq_get,
621*505d05c7Sgtb      krb5_mcc_remove_cred,
622*505d05c7Sgtb      krb5_mcc_set_flags,
623*505d05c7Sgtb };
624