1505d05c7Sgtb /*
2159d09a2SMark Phalan * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3505d05c7Sgtb * Use is subject to license terms.
4505d05c7Sgtb */
5505d05c7Sgtb
6505d05c7Sgtb
7505d05c7Sgtb /*
8505d05c7Sgtb * lib/krb5/ccache/cc_memory.c
9505d05c7Sgtb *
10505d05c7Sgtb * Copyright 1990,1991,2000,2004 by the Massachusetts Institute of Technology.
11505d05c7Sgtb * All Rights Reserved.
12505d05c7Sgtb *
13505d05c7Sgtb * Export of this software from the United States of America may
14505d05c7Sgtb * require a specific license from the United States Government.
15505d05c7Sgtb * It is the responsibility of any person or organization contemplating
16505d05c7Sgtb * export to obtain such a license before exporting.
17*55fea89dSDan Cross *
18505d05c7Sgtb * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
19505d05c7Sgtb * distribute this software and its documentation for any purpose and
20505d05c7Sgtb * without fee is hereby granted, provided that the above copyright
21505d05c7Sgtb * notice appear in all copies and that both that copyright notice and
22505d05c7Sgtb * this permission notice appear in supporting documentation, and that
23505d05c7Sgtb * the name of M.I.T. not be used in advertising or publicity pertaining
24505d05c7Sgtb * to distribution of the software without specific, written prior
25505d05c7Sgtb * permission. Furthermore if you modify this software you must label
26505d05c7Sgtb * your software as modified software and not distribute it in such a
27505d05c7Sgtb * fashion that it might be confused with the original M.I.T. software.
28505d05c7Sgtb * M.I.T. makes no representations about the suitability of
29505d05c7Sgtb * this software for any purpose. It is provided "as is" without express
30505d05c7Sgtb * or implied warranty.
31*55fea89dSDan Cross *
32505d05c7Sgtb *
33505d05c7Sgtb * implementation of memory-based credentials cache
34505d05c7Sgtb */
35505d05c7Sgtb #include "k5-int.h"
36505d05c7Sgtb #include <errno.h>
37505d05c7Sgtb
38505d05c7Sgtb static krb5_error_code KRB5_CALLCONV krb5_mcc_close
39505d05c7Sgtb (krb5_context, krb5_ccache id );
40505d05c7Sgtb
41*55fea89dSDan Cross static krb5_error_code KRB5_CALLCONV krb5_mcc_destroy
42505d05c7Sgtb (krb5_context, krb5_ccache id );
43505d05c7Sgtb
44*55fea89dSDan Cross static krb5_error_code KRB5_CALLCONV krb5_mcc_end_seq_get
45505d05c7Sgtb (krb5_context, krb5_ccache id , krb5_cc_cursor *cursor );
46505d05c7Sgtb
47*55fea89dSDan Cross static krb5_error_code KRB5_CALLCONV krb5_mcc_generate_new
48505d05c7Sgtb (krb5_context, krb5_ccache *id );
49505d05c7Sgtb
50*55fea89dSDan Cross static const char * KRB5_CALLCONV krb5_mcc_get_name
51505d05c7Sgtb (krb5_context, krb5_ccache id );
52505d05c7Sgtb
53*55fea89dSDan Cross static krb5_error_code KRB5_CALLCONV krb5_mcc_get_principal
54505d05c7Sgtb (krb5_context, krb5_ccache id , krb5_principal *princ );
55505d05c7Sgtb
56*55fea89dSDan Cross static krb5_error_code KRB5_CALLCONV krb5_mcc_initialize
57505d05c7Sgtb (krb5_context, krb5_ccache id , krb5_principal princ );
58505d05c7Sgtb
59*55fea89dSDan Cross static krb5_error_code KRB5_CALLCONV krb5_mcc_next_cred
60*55fea89dSDan Cross (krb5_context,
61*55fea89dSDan Cross krb5_ccache id ,
62*55fea89dSDan Cross krb5_cc_cursor *cursor ,
63505d05c7Sgtb krb5_creds *creds );
64505d05c7Sgtb
65*55fea89dSDan Cross static krb5_error_code KRB5_CALLCONV krb5_mcc_resolve
66505d05c7Sgtb (krb5_context, krb5_ccache *id , const char *residual );
67505d05c7Sgtb
68*55fea89dSDan Cross static krb5_error_code KRB5_CALLCONV krb5_mcc_retrieve
69*55fea89dSDan Cross (krb5_context,
70*55fea89dSDan Cross krb5_ccache id ,
71*55fea89dSDan Cross krb5_flags whichfields ,
72*55fea89dSDan Cross krb5_creds *mcreds ,
73505d05c7Sgtb krb5_creds *creds );
74505d05c7Sgtb
75*55fea89dSDan Cross static krb5_error_code KRB5_CALLCONV krb5_mcc_start_seq_get
76505d05c7Sgtb (krb5_context, krb5_ccache id , krb5_cc_cursor *cursor );
77505d05c7Sgtb
78*55fea89dSDan Cross static krb5_error_code KRB5_CALLCONV krb5_mcc_store
79505d05c7Sgtb (krb5_context, krb5_ccache id , krb5_creds *creds );
80505d05c7Sgtb
81*55fea89dSDan Cross static krb5_error_code KRB5_CALLCONV krb5_mcc_set_flags
82505d05c7Sgtb (krb5_context, krb5_ccache id , krb5_flags flags );
83505d05c7Sgtb
84159d09a2SMark Phalan static krb5_error_code KRB5_CALLCONV krb5_mcc_ptcursor_new(
85159d09a2SMark Phalan krb5_context,
86159d09a2SMark Phalan krb5_cc_ptcursor *);
87159d09a2SMark Phalan
88159d09a2SMark Phalan static krb5_error_code KRB5_CALLCONV krb5_mcc_ptcursor_next(
89159d09a2SMark Phalan krb5_context,
90159d09a2SMark Phalan krb5_cc_ptcursor,
91159d09a2SMark Phalan krb5_ccache *);
92159d09a2SMark Phalan
93159d09a2SMark Phalan static krb5_error_code KRB5_CALLCONV krb5_mcc_ptcursor_free(
94159d09a2SMark Phalan krb5_context,
95159d09a2SMark Phalan krb5_cc_ptcursor *);
96159d09a2SMark Phalan
97505d05c7Sgtb extern const krb5_cc_ops krb5_mcc_ops;
98505d05c7Sgtb extern krb5_error_code krb5_change_cache (void);
99505d05c7Sgtb
100505d05c7Sgtb #define KRB5_OK 0
101505d05c7Sgtb
102505d05c7Sgtb typedef struct _krb5_mcc_link {
103505d05c7Sgtb struct _krb5_mcc_link *next;
104505d05c7Sgtb krb5_creds *creds;
105505d05c7Sgtb } krb5_mcc_link, *krb5_mcc_cursor;
106505d05c7Sgtb
107505d05c7Sgtb typedef struct _krb5_mcc_data {
108505d05c7Sgtb char *name;
109505d05c7Sgtb k5_mutex_t lock;
110505d05c7Sgtb krb5_principal prin;
111505d05c7Sgtb krb5_mcc_cursor link;
112505d05c7Sgtb } krb5_mcc_data;
113505d05c7Sgtb
114505d05c7Sgtb typedef struct krb5_mcc_list_node {
115505d05c7Sgtb struct krb5_mcc_list_node *next;
116505d05c7Sgtb krb5_mcc_data *cache;
117505d05c7Sgtb } krb5_mcc_list_node;
118505d05c7Sgtb
119159d09a2SMark Phalan struct krb5_mcc_ptcursor_data {
120159d09a2SMark Phalan struct krb5_mcc_list_node *cur;
121159d09a2SMark Phalan };
122159d09a2SMark Phalan
123505d05c7Sgtb k5_mutex_t krb5int_mcc_mutex = K5_MUTEX_PARTIAL_INITIALIZER;
124505d05c7Sgtb static krb5_mcc_list_node *mcc_head = 0;
125505d05c7Sgtb
126505d05c7Sgtb /*
127505d05c7Sgtb * Modifies:
128505d05c7Sgtb * id
129505d05c7Sgtb *
130505d05c7Sgtb * Effects:
131505d05c7Sgtb * Creates/refreshes the file cred cache id. If the cache exists, its
132505d05c7Sgtb * contents are destroyed.
133505d05c7Sgtb *
134505d05c7Sgtb * Errors:
135505d05c7Sgtb * system errors
136505d05c7Sgtb * permission errors
137505d05c7Sgtb */
138505d05c7Sgtb static void krb5_mcc_free (krb5_context context, krb5_ccache id);
139505d05c7Sgtb
140505d05c7Sgtb krb5_error_code KRB5_CALLCONV
krb5_mcc_initialize(krb5_context context,krb5_ccache id,krb5_principal princ)141505d05c7Sgtb krb5_mcc_initialize(krb5_context context, krb5_ccache id, krb5_principal princ)
142505d05c7Sgtb {
143*55fea89dSDan Cross krb5_error_code ret;
144505d05c7Sgtb
145505d05c7Sgtb krb5_mcc_free(context, id);
146505d05c7Sgtb ret = krb5_copy_principal(context, princ,
147505d05c7Sgtb &((krb5_mcc_data *)id->data)->prin);
148505d05c7Sgtb if (ret == KRB5_OK)
149505d05c7Sgtb krb5_change_cache();
150505d05c7Sgtb return ret;
151505d05c7Sgtb }
152505d05c7Sgtb
153505d05c7Sgtb /*
154505d05c7Sgtb * Modifies:
155505d05c7Sgtb * id
156505d05c7Sgtb *
157505d05c7Sgtb * Effects:
158505d05c7Sgtb * Closes the file cache, invalidates the id, and frees any resources
159505d05c7Sgtb * associated with the cache.
160505d05c7Sgtb */
161505d05c7Sgtb krb5_error_code KRB5_CALLCONV
krb5_mcc_close(krb5_context context,krb5_ccache id)162505d05c7Sgtb krb5_mcc_close(krb5_context context, krb5_ccache id)
163505d05c7Sgtb {
164505d05c7Sgtb krb5_xfree(id);
165505d05c7Sgtb return KRB5_OK;
166505d05c7Sgtb }
167505d05c7Sgtb
168505d05c7Sgtb void
krb5_mcc_free(krb5_context context,krb5_ccache id)169505d05c7Sgtb krb5_mcc_free(krb5_context context, krb5_ccache id)
170505d05c7Sgtb {
171505d05c7Sgtb krb5_mcc_cursor curr,next;
172505d05c7Sgtb krb5_mcc_data *d;
173505d05c7Sgtb
174505d05c7Sgtb d = (krb5_mcc_data *) id->data;
175505d05c7Sgtb for (curr = d->link; curr;) {
176505d05c7Sgtb krb5_free_creds(context, curr->creds);
177505d05c7Sgtb next = curr->next;
178505d05c7Sgtb krb5_xfree(curr);
179505d05c7Sgtb curr = next;
180505d05c7Sgtb }
181505d05c7Sgtb d->link = NULL;
182505d05c7Sgtb krb5_free_principal(context, d->prin);
183505d05c7Sgtb }
184505d05c7Sgtb
185505d05c7Sgtb /*
186505d05c7Sgtb * Effects:
187505d05c7Sgtb * Destroys the contents of id.
188505d05c7Sgtb *
189505d05c7Sgtb * Errors:
190505d05c7Sgtb * none
191505d05c7Sgtb */
192505d05c7Sgtb krb5_error_code KRB5_CALLCONV
krb5_mcc_destroy(krb5_context context,krb5_ccache id)193505d05c7Sgtb krb5_mcc_destroy(krb5_context context, krb5_ccache id)
194505d05c7Sgtb {
195505d05c7Sgtb krb5_mcc_list_node **curr, *node;
196505d05c7Sgtb krb5_mcc_data *d;
197505d05c7Sgtb krb5_error_code err;
198505d05c7Sgtb
199505d05c7Sgtb err = k5_mutex_lock(&krb5int_mcc_mutex);
200505d05c7Sgtb if (err)
201505d05c7Sgtb return err;
202505d05c7Sgtb
203505d05c7Sgtb d = (krb5_mcc_data *)id->data;
204505d05c7Sgtb for (curr = &mcc_head; *curr; curr = &(*curr)->next) {
205505d05c7Sgtb if ((*curr)->cache == d) {
206505d05c7Sgtb node = *curr;
207505d05c7Sgtb *curr = node->next;
208505d05c7Sgtb free(node);
209505d05c7Sgtb break;
210505d05c7Sgtb }
211505d05c7Sgtb }
212505d05c7Sgtb k5_mutex_unlock(&krb5int_mcc_mutex);
213505d05c7Sgtb
214505d05c7Sgtb krb5_mcc_free(context, id);
215505d05c7Sgtb krb5_xfree(d->name);
216505d05c7Sgtb k5_mutex_destroy(&d->lock);
217*55fea89dSDan Cross krb5_xfree(d);
218505d05c7Sgtb krb5_xfree(id);
219505d05c7Sgtb
220505d05c7Sgtb krb5_change_cache ();
221505d05c7Sgtb return KRB5_OK;
222505d05c7Sgtb }
223505d05c7Sgtb
224505d05c7Sgtb /*
225505d05c7Sgtb * Requires:
226505d05c7Sgtb * residual is a legal path name, and a null-terminated string
227505d05c7Sgtb *
228505d05c7Sgtb * Modifies:
229505d05c7Sgtb * id
230*55fea89dSDan Cross *
231505d05c7Sgtb * Effects:
232505d05c7Sgtb * creates a file-based cred cache that will reside in the file
233505d05c7Sgtb * residual. The cache is not opened, but the filename is reserved.
234*55fea89dSDan Cross *
235505d05c7Sgtb * Returns:
236505d05c7Sgtb * A filled in krb5_ccache structure "id".
237505d05c7Sgtb *
238505d05c7Sgtb * Errors:
239505d05c7Sgtb * KRB5_CC_NOMEM - there was insufficient memory to allocate the
240505d05c7Sgtb * krb5_ccache. id is undefined.
241505d05c7Sgtb * permission errors
242505d05c7Sgtb */
243505d05c7Sgtb static krb5_error_code new_mcc_data (const char *, krb5_mcc_data **);
244505d05c7Sgtb
245505d05c7Sgtb krb5_error_code KRB5_CALLCONV
krb5_mcc_resolve(krb5_context context,krb5_ccache * id,const char * residual)246505d05c7Sgtb krb5_mcc_resolve (krb5_context context, krb5_ccache *id, const char *residual)
247505d05c7Sgtb {
248505d05c7Sgtb krb5_ccache lid;
249505d05c7Sgtb krb5_mcc_list_node *ptr;
250505d05c7Sgtb krb5_error_code err;
251505d05c7Sgtb krb5_mcc_data *d;
252505d05c7Sgtb
253505d05c7Sgtb lid = (krb5_ccache) malloc(sizeof(struct _krb5_ccache));
254505d05c7Sgtb if (lid == NULL)
255505d05c7Sgtb return KRB5_CC_NOMEM;
256505d05c7Sgtb
257505d05c7Sgtb lid->ops = &krb5_mcc_ops;
258505d05c7Sgtb
259505d05c7Sgtb err = k5_mutex_lock(&krb5int_mcc_mutex);
260505d05c7Sgtb if (err) {
261159d09a2SMark Phalan /* Solaris Kerberos - fix mem leak */
262505d05c7Sgtb krb5_xfree(lid);
263505d05c7Sgtb return err;
264505d05c7Sgtb }
265505d05c7Sgtb for (ptr = mcc_head; ptr; ptr=ptr->next)
266505d05c7Sgtb if (!strcmp(ptr->cache->name, residual))
267505d05c7Sgtb break;
268505d05c7Sgtb if (ptr)
269505d05c7Sgtb d = ptr->cache;
270505d05c7Sgtb else {
271505d05c7Sgtb err = new_mcc_data(residual, &d);
272505d05c7Sgtb if (err) {
273505d05c7Sgtb k5_mutex_unlock(&krb5int_mcc_mutex);
274505d05c7Sgtb krb5_xfree(lid);
275505d05c7Sgtb return err;
276505d05c7Sgtb }
277505d05c7Sgtb }
278505d05c7Sgtb k5_mutex_unlock(&krb5int_mcc_mutex);
279505d05c7Sgtb lid->data = d;
280*55fea89dSDan Cross *id = lid;
281505d05c7Sgtb return KRB5_OK;
282505d05c7Sgtb }
283505d05c7Sgtb
284505d05c7Sgtb /*
285505d05c7Sgtb * Effects:
286505d05c7Sgtb * Prepares for a sequential search of the credentials cache.
287505d05c7Sgtb * Returns a krb5_cc_cursor to be used with krb5_mcc_next_cred and
288505d05c7Sgtb * krb5_mcc_end_seq_get.
289505d05c7Sgtb *
290505d05c7Sgtb * If the cache is modified between the time of this call and the time
291505d05c7Sgtb * of the final krb5_mcc_end_seq_get, the results are undefined.
292505d05c7Sgtb *
293505d05c7Sgtb * Errors:
294505d05c7Sgtb * KRB5_CC_NOMEM
295505d05c7Sgtb * system errors
296505d05c7Sgtb */
297505d05c7Sgtb krb5_error_code KRB5_CALLCONV
krb5_mcc_start_seq_get(krb5_context context,krb5_ccache id,krb5_cc_cursor * cursor)298505d05c7Sgtb krb5_mcc_start_seq_get(krb5_context context, krb5_ccache id,
299505d05c7Sgtb krb5_cc_cursor *cursor)
300505d05c7Sgtb {
301505d05c7Sgtb krb5_mcc_cursor mcursor;
302505d05c7Sgtb krb5_error_code err;
303505d05c7Sgtb krb5_mcc_data *d;
304505d05c7Sgtb
305505d05c7Sgtb d = id->data;
306505d05c7Sgtb err = k5_mutex_lock(&d->lock);
307505d05c7Sgtb if (err)
308505d05c7Sgtb return err;
309505d05c7Sgtb mcursor = d->link;
310505d05c7Sgtb k5_mutex_unlock(&d->lock);
311505d05c7Sgtb *cursor = (krb5_cc_cursor) mcursor;
312505d05c7Sgtb return KRB5_OK;
313505d05c7Sgtb }
314505d05c7Sgtb
315505d05c7Sgtb /*
316505d05c7Sgtb * Requires:
317505d05c7Sgtb * cursor is a krb5_cc_cursor originally obtained from
318505d05c7Sgtb * krb5_mcc_start_seq_get.
319505d05c7Sgtb *
320505d05c7Sgtb * Modifes:
321505d05c7Sgtb * cursor, creds
322*55fea89dSDan Cross *
323505d05c7Sgtb * Effects:
324505d05c7Sgtb * Fills in creds with the "next" credentals structure from the cache
325505d05c7Sgtb * id. The actual order the creds are returned in is arbitrary.
326505d05c7Sgtb * Space is allocated for the variable length fields in the
327505d05c7Sgtb * credentials structure, so the object returned must be passed to
328505d05c7Sgtb * krb5_destroy_credential.
329505d05c7Sgtb *
330505d05c7Sgtb * The cursor is updated for the next call to krb5_mcc_next_cred.
331505d05c7Sgtb *
332505d05c7Sgtb * Errors:
333505d05c7Sgtb * system errors
334505d05c7Sgtb */
335505d05c7Sgtb krb5_error_code KRB5_CALLCONV
krb5_mcc_next_cred(krb5_context context,krb5_ccache id,krb5_cc_cursor * cursor,krb5_creds * creds)336505d05c7Sgtb krb5_mcc_next_cred(krb5_context context, krb5_ccache id,
337505d05c7Sgtb krb5_cc_cursor *cursor, krb5_creds *creds)
338505d05c7Sgtb {
339505d05c7Sgtb krb5_mcc_cursor mcursor;
340505d05c7Sgtb krb5_error_code retval;
341505d05c7Sgtb krb5_data *scratch;
342505d05c7Sgtb
343505d05c7Sgtb /* Once the node in the linked list is created, it's never
344505d05c7Sgtb modified, so we don't need to worry about locking here. (Note
345505d05c7Sgtb that we don't support _remove_cred.) */
346505d05c7Sgtb mcursor = (krb5_mcc_cursor) *cursor;
347505d05c7Sgtb if (mcursor == NULL)
348505d05c7Sgtb return KRB5_CC_END;
349*55fea89dSDan Cross memset(creds, 0, sizeof(krb5_creds));
350505d05c7Sgtb if (mcursor->creds) {
351505d05c7Sgtb *creds = *mcursor->creds;
352505d05c7Sgtb retval = krb5_copy_principal(context, mcursor->creds->client, &creds->client);
353505d05c7Sgtb if (retval)
354505d05c7Sgtb return retval;
355505d05c7Sgtb retval = krb5_copy_principal(context, mcursor->creds->server,
356505d05c7Sgtb &creds->server);
357505d05c7Sgtb if (retval)
358505d05c7Sgtb goto cleanclient;
359505d05c7Sgtb retval = krb5_copy_keyblock_contents(context, &mcursor->creds->keyblock,
360505d05c7Sgtb &creds->keyblock);
361505d05c7Sgtb if (retval)
362505d05c7Sgtb goto cleanserver;
363505d05c7Sgtb retval = krb5_copy_addresses(context, mcursor->creds->addresses,
364505d05c7Sgtb &creds->addresses);
365505d05c7Sgtb if (retval)
366505d05c7Sgtb goto cleanblock;
367505d05c7Sgtb retval = krb5_copy_data(context, &mcursor->creds->ticket, &scratch);
368505d05c7Sgtb if (retval)
369505d05c7Sgtb goto cleanaddrs;
370505d05c7Sgtb creds->ticket = *scratch;
371505d05c7Sgtb krb5_xfree(scratch);
372505d05c7Sgtb retval = krb5_copy_data(context, &mcursor->creds->second_ticket, &scratch);
373505d05c7Sgtb if (retval)
374505d05c7Sgtb goto cleanticket;
375505d05c7Sgtb creds->second_ticket = *scratch;
376505d05c7Sgtb krb5_xfree(scratch);
377505d05c7Sgtb retval = krb5_copy_authdata(context, mcursor->creds->authdata,
378505d05c7Sgtb &creds->authdata);
379505d05c7Sgtb if (retval)
380505d05c7Sgtb goto clearticket;
381505d05c7Sgtb }
382505d05c7Sgtb *cursor = (krb5_cc_cursor)mcursor->next;
383505d05c7Sgtb return KRB5_OK;
384505d05c7Sgtb
385505d05c7Sgtb clearticket:
386505d05c7Sgtb memset(creds->ticket.data,0, (unsigned) creds->ticket.length);
387505d05c7Sgtb cleanticket:
388505d05c7Sgtb krb5_xfree(creds->ticket.data);
389505d05c7Sgtb cleanaddrs:
390505d05c7Sgtb krb5_free_addresses(context, creds->addresses);
391505d05c7Sgtb cleanblock:
392505d05c7Sgtb krb5_xfree(creds->keyblock.contents);
393505d05c7Sgtb cleanserver:
394505d05c7Sgtb krb5_free_principal(context, creds->server);
395505d05c7Sgtb cleanclient:
396505d05c7Sgtb krb5_free_principal(context, creds->client);
397505d05c7Sgtb return retval;
398505d05c7Sgtb }
399505d05c7Sgtb
400505d05c7Sgtb /*
401505d05c7Sgtb * Requires:
402505d05c7Sgtb * cursor is a krb5_cc_cursor originally obtained from
403505d05c7Sgtb * krb5_mcc_start_seq_get.
404505d05c7Sgtb *
405505d05c7Sgtb * Modifies:
406505d05c7Sgtb * id, cursor
407505d05c7Sgtb *
408505d05c7Sgtb * Effects:
409505d05c7Sgtb * Finishes sequential processing of the file credentials ccache id,
410505d05c7Sgtb * and invalidates the cursor (it must never be used after this call).
411505d05c7Sgtb */
412505d05c7Sgtb /* ARGSUSED */
413505d05c7Sgtb krb5_error_code KRB5_CALLCONV
krb5_mcc_end_seq_get(krb5_context context,krb5_ccache id,krb5_cc_cursor * cursor)414505d05c7Sgtb krb5_mcc_end_seq_get(krb5_context context, krb5_ccache id, krb5_cc_cursor *cursor)
415505d05c7Sgtb {
416505d05c7Sgtb *cursor = 0L;
417505d05c7Sgtb return KRB5_OK;
418505d05c7Sgtb }
419505d05c7Sgtb
420505d05c7Sgtb /* Utility routine: Creates the back-end data for a memory cache, and
421505d05c7Sgtb threads it into the global linked list.
422505d05c7Sgtb
423505d05c7Sgtb Call with the global list lock held. */
424505d05c7Sgtb static krb5_error_code
new_mcc_data(const char * name,krb5_mcc_data ** dataptr)425505d05c7Sgtb new_mcc_data (const char *name, krb5_mcc_data **dataptr)
426505d05c7Sgtb {
427505d05c7Sgtb krb5_error_code err;
428505d05c7Sgtb krb5_mcc_data *d;
429505d05c7Sgtb krb5_mcc_list_node *n;
430505d05c7Sgtb
431505d05c7Sgtb d = malloc(sizeof(krb5_mcc_data));
432505d05c7Sgtb if (d == NULL)
433505d05c7Sgtb return KRB5_CC_NOMEM;
434505d05c7Sgtb
435505d05c7Sgtb err = k5_mutex_init(&d->lock);
436505d05c7Sgtb if (err) {
437505d05c7Sgtb krb5_xfree(d);
438505d05c7Sgtb return err;
439505d05c7Sgtb }
440505d05c7Sgtb
441505d05c7Sgtb d->name = malloc(strlen(name) + 1);
442505d05c7Sgtb if (d->name == NULL) {
443505d05c7Sgtb k5_mutex_destroy(&d->lock);
444505d05c7Sgtb krb5_xfree(d);
445505d05c7Sgtb return KRB5_CC_NOMEM;
446505d05c7Sgtb }
447505d05c7Sgtb d->link = NULL;
448505d05c7Sgtb d->prin = NULL;
449505d05c7Sgtb
450505d05c7Sgtb /* Set up the filename */
451505d05c7Sgtb strcpy(d->name, name);
452505d05c7Sgtb
453505d05c7Sgtb n = malloc(sizeof(krb5_mcc_list_node));
454505d05c7Sgtb if (n == NULL) {
455505d05c7Sgtb free(d->name);
456505d05c7Sgtb k5_mutex_destroy(&d->lock);
457505d05c7Sgtb free(d);
458505d05c7Sgtb return KRB5_CC_NOMEM;
459505d05c7Sgtb }
460505d05c7Sgtb
461505d05c7Sgtb n->cache = d;
462505d05c7Sgtb n->next = mcc_head;
463505d05c7Sgtb mcc_head = n;
464505d05c7Sgtb
465505d05c7Sgtb *dataptr = d;
466505d05c7Sgtb return 0;
467505d05c7Sgtb }
468505d05c7Sgtb
469159d09a2SMark Phalan static krb5_error_code random_string (krb5_context, char *, unsigned int);
470*55fea89dSDan Cross
471505d05c7Sgtb /*
472505d05c7Sgtb * Effects:
473505d05c7Sgtb * Creates a new file cred cache whose name is guaranteed to be
474505d05c7Sgtb * unique. The name begins with the string TKT_ROOT (from mcc.h).
475505d05c7Sgtb * The cache is not opened, but the new filename is reserved.
476*55fea89dSDan Cross *
477505d05c7Sgtb * Returns:
478505d05c7Sgtb * The filled in krb5_ccache id.
479505d05c7Sgtb *
480505d05c7Sgtb * Errors:
481505d05c7Sgtb * KRB5_CC_NOMEM - there was insufficient memory to allocate the
482505d05c7Sgtb * krb5_ccache. id is undefined.
483505d05c7Sgtb * system errors (from open)
484505d05c7Sgtb */
485159d09a2SMark Phalan
486505d05c7Sgtb krb5_error_code KRB5_CALLCONV
krb5_mcc_generate_new(krb5_context context,krb5_ccache * id)487505d05c7Sgtb krb5_mcc_generate_new (krb5_context context, krb5_ccache *id)
488505d05c7Sgtb {
489505d05c7Sgtb krb5_ccache lid;
490159d09a2SMark Phalan char uniquename[8];
491505d05c7Sgtb krb5_error_code err;
492505d05c7Sgtb krb5_mcc_data *d;
493505d05c7Sgtb
494505d05c7Sgtb /* Allocate memory */
495505d05c7Sgtb lid = (krb5_ccache) malloc(sizeof(struct _krb5_ccache));
496505d05c7Sgtb if (lid == NULL)
497505d05c7Sgtb return KRB5_CC_NOMEM;
498505d05c7Sgtb
499505d05c7Sgtb lid->ops = &krb5_mcc_ops;
500*55fea89dSDan Cross
501505d05c7Sgtb err = k5_mutex_lock(&krb5int_mcc_mutex);
502505d05c7Sgtb if (err) {
503505d05c7Sgtb free(lid);
504505d05c7Sgtb return err;
505505d05c7Sgtb }
506*55fea89dSDan Cross
507159d09a2SMark Phalan /* Check for uniqueness with mutex locked to avoid race conditions */
508159d09a2SMark Phalan while (1) {
509159d09a2SMark Phalan krb5_mcc_list_node *ptr;
510159d09a2SMark Phalan
511159d09a2SMark Phalan random_string (context, uniquename, sizeof (uniquename));
512*55fea89dSDan Cross
513159d09a2SMark Phalan for (ptr = mcc_head; ptr; ptr=ptr->next) {
514159d09a2SMark Phalan if (!strcmp(ptr->cache->name, uniquename)) {
515159d09a2SMark Phalan break; /* got a match, loop again */
516159d09a2SMark Phalan }
517159d09a2SMark Phalan }
518159d09a2SMark Phalan if (!ptr) break; /* got to the end without finding a match */
519159d09a2SMark Phalan }
520*55fea89dSDan Cross
521159d09a2SMark Phalan err = new_mcc_data(uniquename, &d);
522159d09a2SMark Phalan
523505d05c7Sgtb k5_mutex_unlock(&krb5int_mcc_mutex);
524505d05c7Sgtb if (err) {
525505d05c7Sgtb krb5_xfree(lid);
526505d05c7Sgtb return err;
527505d05c7Sgtb }
528505d05c7Sgtb lid->data = d;
529159d09a2SMark Phalan *id = lid;
530505d05c7Sgtb krb5_change_cache ();
531505d05c7Sgtb return KRB5_OK;
532505d05c7Sgtb }
533505d05c7Sgtb
534*55fea89dSDan Cross /* Utility routine: Creates a random memory ccache name.
535*55fea89dSDan Cross * This algorithm was selected because it creates readable
536159d09a2SMark Phalan * random ccache names in a fixed size buffer. */
537159d09a2SMark Phalan
538159d09a2SMark Phalan static krb5_error_code
random_string(krb5_context context,char * string,unsigned int length)539159d09a2SMark Phalan random_string (krb5_context context, char *string, unsigned int length)
540159d09a2SMark Phalan {
541159d09a2SMark Phalan static const unsigned char charlist[] =
542159d09a2SMark Phalan "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
543159d09a2SMark Phalan krb5_error_code err = 0;
544159d09a2SMark Phalan unsigned char *bytes = NULL;
545159d09a2SMark Phalan unsigned int bytecount = length - 1;
546*55fea89dSDan Cross
547159d09a2SMark Phalan if (!err) {
548159d09a2SMark Phalan bytes = malloc (bytecount);
549159d09a2SMark Phalan if (bytes == NULL) { err = ENOMEM; }
550159d09a2SMark Phalan }
551*55fea89dSDan Cross
552159d09a2SMark Phalan if (!err) {
553159d09a2SMark Phalan krb5_data data;
554159d09a2SMark Phalan data.length = bytecount;
555159d09a2SMark Phalan data.data = (char *) bytes;
556159d09a2SMark Phalan err = krb5_c_random_make_octets (context, &data);
557159d09a2SMark Phalan }
558*55fea89dSDan Cross
559159d09a2SMark Phalan if (!err) {
560159d09a2SMark Phalan unsigned int i;
561159d09a2SMark Phalan for (i = 0; i < bytecount; i++) {
562159d09a2SMark Phalan string [i] = charlist[bytes[i] % (sizeof (charlist) - 1)];
563159d09a2SMark Phalan }
564159d09a2SMark Phalan string[length - 1] = '\0';
565159d09a2SMark Phalan }
566*55fea89dSDan Cross
567159d09a2SMark Phalan if (bytes != NULL) { free (bytes); }
568*55fea89dSDan Cross
569159d09a2SMark Phalan return err;
570159d09a2SMark Phalan }
571159d09a2SMark Phalan
572505d05c7Sgtb /*
573505d05c7Sgtb * Requires:
574505d05c7Sgtb * id is a file credential cache
575*55fea89dSDan Cross *
576505d05c7Sgtb * Returns:
577505d05c7Sgtb * The name of the file cred cache id.
578505d05c7Sgtb */
579505d05c7Sgtb const char * KRB5_CALLCONV
krb5_mcc_get_name(krb5_context context,krb5_ccache id)580505d05c7Sgtb krb5_mcc_get_name (krb5_context context, krb5_ccache id)
581505d05c7Sgtb {
582505d05c7Sgtb return (char *) ((krb5_mcc_data *) id->data)->name;
583505d05c7Sgtb }
584505d05c7Sgtb
585505d05c7Sgtb /*
586505d05c7Sgtb * Modifies:
587505d05c7Sgtb * id, princ
588505d05c7Sgtb *
589505d05c7Sgtb * Effects:
590505d05c7Sgtb * Retrieves the primary principal from id, as set with
591505d05c7Sgtb * krb5_mcc_initialize. The principal is returned is allocated
592505d05c7Sgtb * storage that must be freed by the caller via krb5_free_principal.
593505d05c7Sgtb *
594505d05c7Sgtb * Errors:
595505d05c7Sgtb * system errors
596505d05c7Sgtb * KRB5_CC_NOMEM
597505d05c7Sgtb */
598505d05c7Sgtb krb5_error_code KRB5_CALLCONV
krb5_mcc_get_principal(krb5_context context,krb5_ccache id,krb5_principal * princ)599505d05c7Sgtb krb5_mcc_get_principal(krb5_context context, krb5_ccache id, krb5_principal *princ)
600505d05c7Sgtb {
601505d05c7Sgtb krb5_mcc_data *ptr = (krb5_mcc_data *)id->data;
602505d05c7Sgtb if (!ptr->prin) {
603505d05c7Sgtb *princ = 0L;
604505d05c7Sgtb return KRB5_FCC_NOFILE;
605505d05c7Sgtb }
606505d05c7Sgtb return krb5_copy_principal(context, ptr->prin, princ);
607505d05c7Sgtb }
608505d05c7Sgtb
609505d05c7Sgtb krb5_error_code KRB5_CALLCONV
krb5_mcc_retrieve(krb5_context context,krb5_ccache id,krb5_flags whichfields,krb5_creds * mcreds,krb5_creds * creds)610505d05c7Sgtb krb5_mcc_retrieve(krb5_context context, krb5_ccache id, krb5_flags whichfields,
611505d05c7Sgtb krb5_creds *mcreds, krb5_creds *creds)
612505d05c7Sgtb {
613505d05c7Sgtb return krb5_cc_retrieve_cred_default (context, id, whichfields,
614505d05c7Sgtb mcreds, creds);
615505d05c7Sgtb }
616505d05c7Sgtb
617*55fea89dSDan Cross /*
618505d05c7Sgtb * Non-functional stub implementation for krb5_mcc_remove
619*55fea89dSDan Cross *
620505d05c7Sgtb * Errors:
621505d05c7Sgtb * KRB5_CC_NOSUPP - not implemented
622505d05c7Sgtb */
623505d05c7Sgtb static krb5_error_code KRB5_CALLCONV
krb5_mcc_remove_cred(krb5_context context,krb5_ccache cache,krb5_flags flags,krb5_creds * creds)624505d05c7Sgtb krb5_mcc_remove_cred(krb5_context context, krb5_ccache cache, krb5_flags flags,
625505d05c7Sgtb krb5_creds *creds)
626505d05c7Sgtb {
627505d05c7Sgtb return KRB5_CC_NOSUPP;
628505d05c7Sgtb }
629505d05c7Sgtb
630505d05c7Sgtb
631505d05c7Sgtb /*
632505d05c7Sgtb * Requires:
633505d05c7Sgtb * id is a cred cache returned by krb5_mcc_resolve or
634505d05c7Sgtb * krb5_mcc_generate_new, but has not been opened by krb5_mcc_initialize.
635505d05c7Sgtb *
636505d05c7Sgtb * Modifies:
637505d05c7Sgtb * id
638*55fea89dSDan Cross *
639505d05c7Sgtb * Effects:
640505d05c7Sgtb * Sets the operational flags of id to flags.
641505d05c7Sgtb */
642505d05c7Sgtb krb5_error_code KRB5_CALLCONV
krb5_mcc_set_flags(krb5_context context,krb5_ccache id,krb5_flags flags)643505d05c7Sgtb krb5_mcc_set_flags(krb5_context context, krb5_ccache id, krb5_flags flags)
644505d05c7Sgtb {
645505d05c7Sgtb return KRB5_OK;
646505d05c7Sgtb }
647505d05c7Sgtb
648159d09a2SMark Phalan static krb5_error_code KRB5_CALLCONV
krb5_mcc_get_flags(krb5_context context,krb5_ccache id,krb5_flags * flags)649159d09a2SMark Phalan krb5_mcc_get_flags(krb5_context context, krb5_ccache id, krb5_flags *flags)
650159d09a2SMark Phalan {
651159d09a2SMark Phalan *flags = 0;
652159d09a2SMark Phalan return KRB5_OK;
653159d09a2SMark Phalan }
654159d09a2SMark Phalan
655505d05c7Sgtb /* store: Save away creds in the ccache. */
656505d05c7Sgtb krb5_error_code KRB5_CALLCONV
krb5_mcc_store(krb5_context ctx,krb5_ccache id,krb5_creds * creds)657505d05c7Sgtb krb5_mcc_store(krb5_context ctx, krb5_ccache id, krb5_creds *creds)
658505d05c7Sgtb {
659505d05c7Sgtb krb5_error_code err;
660505d05c7Sgtb krb5_mcc_link *new_node;
661505d05c7Sgtb krb5_mcc_data *mptr = (krb5_mcc_data *)id->data;
662505d05c7Sgtb
663505d05c7Sgtb new_node = malloc(sizeof(krb5_mcc_link));
664505d05c7Sgtb if (new_node == NULL)
665505d05c7Sgtb return errno;
666505d05c7Sgtb err = krb5_copy_creds(ctx, creds, &new_node->creds);
667505d05c7Sgtb if (err) {
668505d05c7Sgtb free(new_node);
669505d05c7Sgtb return err;
670505d05c7Sgtb }
671505d05c7Sgtb err = k5_mutex_lock(&mptr->lock);
672505d05c7Sgtb if (err) {
673159d09a2SMark Phalan /* Solaris Kerberos - fix mem leaks */
674159d09a2SMark Phalan krb5_free_creds(ctx, new_node->creds);
675505d05c7Sgtb free(new_node);
676505d05c7Sgtb return err;
677505d05c7Sgtb }
678505d05c7Sgtb new_node->next = mptr->link;
679505d05c7Sgtb mptr->link = new_node;
680505d05c7Sgtb k5_mutex_unlock(&mptr->lock);
681505d05c7Sgtb return 0;
682505d05c7Sgtb }
683505d05c7Sgtb
684159d09a2SMark Phalan static krb5_error_code KRB5_CALLCONV
krb5_mcc_ptcursor_new(krb5_context context,krb5_cc_ptcursor * cursor)685159d09a2SMark Phalan krb5_mcc_ptcursor_new(
686159d09a2SMark Phalan krb5_context context,
687159d09a2SMark Phalan krb5_cc_ptcursor *cursor)
688159d09a2SMark Phalan {
689159d09a2SMark Phalan krb5_error_code ret = 0;
690159d09a2SMark Phalan krb5_cc_ptcursor n = NULL;
691159d09a2SMark Phalan struct krb5_mcc_ptcursor_data *cdata = NULL;
692159d09a2SMark Phalan
693159d09a2SMark Phalan *cursor = NULL;
694159d09a2SMark Phalan
695159d09a2SMark Phalan n = malloc(sizeof(*n));
696159d09a2SMark Phalan if (n == NULL)
697159d09a2SMark Phalan return ENOMEM;
698159d09a2SMark Phalan n->ops = &krb5_mcc_ops;
699159d09a2SMark Phalan cdata = malloc(sizeof(struct krb5_mcc_ptcursor_data));
700159d09a2SMark Phalan if (cdata == NULL) {
701159d09a2SMark Phalan ret = ENOMEM;
702159d09a2SMark Phalan goto errout;
703159d09a2SMark Phalan }
704159d09a2SMark Phalan n->data = cdata;
705159d09a2SMark Phalan ret = k5_mutex_lock(&krb5int_mcc_mutex);
706159d09a2SMark Phalan if (ret)
707159d09a2SMark Phalan goto errout;
708159d09a2SMark Phalan cdata->cur = mcc_head;
709159d09a2SMark Phalan ret = k5_mutex_unlock(&krb5int_mcc_mutex);
710159d09a2SMark Phalan if (ret)
711159d09a2SMark Phalan goto errout;
712159d09a2SMark Phalan
713159d09a2SMark Phalan errout:
714159d09a2SMark Phalan if (ret) {
715159d09a2SMark Phalan krb5_mcc_ptcursor_free(context, &n);
716159d09a2SMark Phalan }
717159d09a2SMark Phalan *cursor = n;
718159d09a2SMark Phalan return ret;
719159d09a2SMark Phalan }
720159d09a2SMark Phalan
721159d09a2SMark Phalan static krb5_error_code KRB5_CALLCONV
krb5_mcc_ptcursor_next(krb5_context context,krb5_cc_ptcursor cursor,krb5_ccache * ccache)722159d09a2SMark Phalan krb5_mcc_ptcursor_next(
723159d09a2SMark Phalan krb5_context context,
724159d09a2SMark Phalan krb5_cc_ptcursor cursor,
725159d09a2SMark Phalan krb5_ccache *ccache)
726159d09a2SMark Phalan {
727159d09a2SMark Phalan krb5_error_code ret = 0;
728159d09a2SMark Phalan struct krb5_mcc_ptcursor_data *cdata = NULL;
729159d09a2SMark Phalan
730159d09a2SMark Phalan *ccache = NULL;
731159d09a2SMark Phalan cdata = cursor->data;
732159d09a2SMark Phalan if (cdata->cur == NULL)
733159d09a2SMark Phalan return 0;
734159d09a2SMark Phalan
735159d09a2SMark Phalan *ccache = malloc(sizeof(**ccache));
736159d09a2SMark Phalan if (*ccache == NULL)
737159d09a2SMark Phalan return ENOMEM;
738159d09a2SMark Phalan
739159d09a2SMark Phalan (*ccache)->ops = &krb5_mcc_ops;
740159d09a2SMark Phalan (*ccache)->data = cdata->cur->cache;
741159d09a2SMark Phalan ret = k5_mutex_lock(&krb5int_mcc_mutex);
742159d09a2SMark Phalan if (ret)
743159d09a2SMark Phalan goto errout;
744159d09a2SMark Phalan cdata->cur = cdata->cur->next;
745159d09a2SMark Phalan ret = k5_mutex_unlock(&krb5int_mcc_mutex);
746159d09a2SMark Phalan if (ret)
747159d09a2SMark Phalan goto errout;
748159d09a2SMark Phalan errout:
749159d09a2SMark Phalan if (ret && *ccache != NULL) {
750159d09a2SMark Phalan free(*ccache);
751159d09a2SMark Phalan *ccache = NULL;
752159d09a2SMark Phalan }
753159d09a2SMark Phalan return ret;
754159d09a2SMark Phalan }
755159d09a2SMark Phalan
756159d09a2SMark Phalan static krb5_error_code KRB5_CALLCONV
krb5_mcc_ptcursor_free(krb5_context context,krb5_cc_ptcursor * cursor)757159d09a2SMark Phalan krb5_mcc_ptcursor_free(
758159d09a2SMark Phalan krb5_context context,
759159d09a2SMark Phalan krb5_cc_ptcursor *cursor)
760159d09a2SMark Phalan {
761159d09a2SMark Phalan if (*cursor == NULL)
762159d09a2SMark Phalan return 0;
763159d09a2SMark Phalan if ((*cursor)->data != NULL)
764159d09a2SMark Phalan free((*cursor)->data);
765159d09a2SMark Phalan free(*cursor);
766159d09a2SMark Phalan *cursor = NULL;
767159d09a2SMark Phalan return 0;
768159d09a2SMark Phalan }
769159d09a2SMark Phalan
770505d05c7Sgtb const krb5_cc_ops krb5_mcc_ops = {
771505d05c7Sgtb 0,
772505d05c7Sgtb "MEMORY",
773505d05c7Sgtb krb5_mcc_get_name,
774505d05c7Sgtb krb5_mcc_resolve,
775505d05c7Sgtb krb5_mcc_generate_new,
776505d05c7Sgtb krb5_mcc_initialize,
777505d05c7Sgtb krb5_mcc_destroy,
778505d05c7Sgtb krb5_mcc_close,
779505d05c7Sgtb krb5_mcc_store,
780505d05c7Sgtb krb5_mcc_retrieve,
781505d05c7Sgtb krb5_mcc_get_principal,
782505d05c7Sgtb krb5_mcc_start_seq_get,
783505d05c7Sgtb krb5_mcc_next_cred,
784505d05c7Sgtb krb5_mcc_end_seq_get,
785505d05c7Sgtb krb5_mcc_remove_cred,
786505d05c7Sgtb krb5_mcc_set_flags,
787159d09a2SMark Phalan krb5_mcc_get_flags,
788159d09a2SMark Phalan krb5_mcc_ptcursor_new,
789159d09a2SMark Phalan krb5_mcc_ptcursor_next,
790159d09a2SMark Phalan krb5_mcc_ptcursor_free,
791159d09a2SMark Phalan NULL,
792159d09a2SMark Phalan NULL,
793159d09a2SMark Phalan NULL,
794505d05c7Sgtb };
795