1 #pragma ident	"%Z%%M%	%I%	%E% SMI"
2 
3 /*
4  * lib/krb5/ccache/ccbase.c
5  *
6  * Copyright 1990,2004 by the Massachusetts Institute of Technology.
7  * All Rights Reserved.
8  *
9  * Export of this software from the United States of America may
10  *   require a specific license from the United States Government.
11  *   It is the responsibility of any person or organization contemplating
12  *   export to obtain such a license before exporting.
13  *
14  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
15  * distribute this software and its documentation for any purpose and
16  * without fee is hereby granted, provided that the above copyright
17  * notice appear in all copies and that both that copyright notice and
18  * this permission notice appear in supporting documentation, and that
19  * the name of M.I.T. not be used in advertising or publicity pertaining
20  * to distribution of the software without specific, written prior
21  * permission.  Furthermore if you modify this software you must label
22  * your software as modified software and not distribute it in such a
23  * fashion that it might be confused with the original M.I.T. software.
24  * M.I.T. makes no representations about the suitability of
25  * this software for any purpose.  It is provided "as is" without express
26  * or implied warranty.
27  *
28  *
29  * Registration functions for ccache.
30  */
31 
32 #include "k5-int.h"
33 #include "k5-thread.h"
34 
35 #include "fcc.h"
36 #include "cc-int.h"
37 
38 struct krb5_cc_typelist {
39     const krb5_cc_ops *ops;
40     struct krb5_cc_typelist *next;
41 };
42 extern const krb5_cc_ops krb5_mcc_ops;
43 
44 #ifdef _WIN32
45 extern const krb5_cc_ops krb5_lcc_ops;
46 static struct krb5_cc_typelist cc_lcc_entry = { &krb5_lcc_ops, NULL };
47 static struct krb5_cc_typelist cc_mcc_entry = { &krb5_mcc_ops, &cc_lcc_entry };
48 #else
49 static struct krb5_cc_typelist cc_mcc_entry = { &krb5_mcc_ops, NULL };
50 #endif
51 
52 static struct krb5_cc_typelist cc_fcc_entry = { &krb5_cc_file_ops,
53 						&cc_mcc_entry };
54 
55 static struct krb5_cc_typelist *cc_typehead = &cc_fcc_entry;
56 static k5_mutex_t cc_typelist_lock = K5_MUTEX_PARTIAL_INITIALIZER;
57 
58 int
59 krb5int_cc_initialize(void)
60 {
61     int err;
62 
63     err = k5_mutex_finish_init(&krb5int_mcc_mutex);
64     if (err)
65 	return err;
66     err = k5_mutex_finish_init(&cc_typelist_lock);
67     if (err)
68 	return err;
69     err = k5_mutex_finish_init(&krb5int_cc_file_mutex);
70     if (err)
71 	return err;
72     return 0;
73 }
74 
75 void
76 krb5int_cc_finalize(void)
77 {
78     struct krb5_cc_typelist *t, *t_next;
79     k5_mutex_destroy(&cc_typelist_lock);
80     k5_mutex_destroy(&krb5int_cc_file_mutex);
81     k5_mutex_destroy(&krb5int_mcc_mutex);
82     for (t = cc_typehead; t != &cc_fcc_entry; t = t_next) {
83 	t_next = t->next;
84 	free(t);
85     }
86 }
87 
88 
89 /*
90  * Register a new credentials cache type
91  * If override is set, replace any existing ccache with that type tag
92  */
93 
94 krb5_error_code KRB5_CALLCONV
95 krb5_cc_register(krb5_context context, krb5_cc_ops *ops, krb5_boolean override)
96 {
97     struct krb5_cc_typelist *t;
98     krb5_error_code err;
99 
100     err = k5_mutex_lock(&cc_typelist_lock);
101     if (err)
102 	return err;
103     for (t = cc_typehead;t && strcmp(t->ops->prefix,ops->prefix);t = t->next)
104 	;
105     if (t) {
106 	if (override) {
107 	    t->ops = ops;
108 	    k5_mutex_unlock(&cc_typelist_lock);
109 	    return 0;
110 	} else {
111 	    k5_mutex_unlock(&cc_typelist_lock);
112 	    return KRB5_CC_TYPE_EXISTS;
113 	}
114     }
115     if (!(t = (struct krb5_cc_typelist *) malloc(sizeof(*t)))) {
116 	k5_mutex_unlock(&cc_typelist_lock);
117 	return ENOMEM;
118     }
119     t->next = cc_typehead;
120     t->ops = ops;
121     cc_typehead = t;
122     k5_mutex_unlock(&cc_typelist_lock);
123     return 0;
124 }
125 
126 /*
127  * Resolve a credential cache name into a cred. cache object.
128  *
129  * The name is currently constrained to be of the form "type:residual";
130  *
131  * The "type" portion corresponds to one of the predefined credential
132  * cache types, while the "residual" portion is specific to the
133  * particular cache type.
134  */
135 
136 #include <ctype.h>
137 krb5_error_code KRB5_CALLCONV
138 krb5_cc_resolve (krb5_context context, const char *name, krb5_ccache *cache)
139 {
140     struct krb5_cc_typelist *tlist;
141     char *pfx, *cp;
142     const char *resid;
143     unsigned int pfxlen;
144     krb5_error_code err;
145 
146     cp = strchr (name, ':');
147     if (!cp) {
148 	if (krb5_cc_dfl_ops)
149 	    return (*krb5_cc_dfl_ops->resolve)(context, cache, name);
150 	else
151 	    return KRB5_CC_BADNAME;
152     }
153 
154     pfxlen = cp - name;
155 
156     if ( pfxlen == 1 && isalpha(name[0]) ) {
157         /* We found a drive letter not a prefix - use FILE: */
158         pfx = strdup("FILE:");
159         if (!pfx)
160             return ENOMEM;
161 
162         resid = name;
163     } else {
164         resid = name + pfxlen + 1;
165 
166         pfx = malloc (pfxlen+1);
167         if (!pfx)
168             return ENOMEM;
169 
170         memcpy (pfx, name, pfxlen);
171         pfx[pfxlen] = '\0';
172     }
173 
174     *cache = (krb5_ccache) 0;
175 
176     err = k5_mutex_lock(&cc_typelist_lock);
177     if (err) {
178 	free(pfx);
179 	return err;
180     }
181     for (tlist = cc_typehead; tlist; tlist = tlist->next) {
182 	if (strcmp (tlist->ops->prefix, pfx) == 0) {
183 	    krb5_error_code (KRB5_CALLCONV *ccresolver)() = tlist->ops->resolve;
184 	    k5_mutex_unlock(&cc_typelist_lock);
185 	    free(pfx);
186 	    return (*ccresolver)(context, cache, resid);
187 	}
188     }
189     k5_mutex_unlock(&cc_typelist_lock);
190     if (krb5_cc_dfl_ops && !strcmp (pfx, krb5_cc_dfl_ops->prefix)) {
191 	free (pfx);
192 	return (*krb5_cc_dfl_ops->resolve)(context, cache, resid);
193     }
194     free(pfx);
195     return KRB5_CC_UNKNOWN_TYPE;
196 }
197