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 /*
33  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
34  * Use is subject to license terms.
35  */
36 
37 
38 #include "k5-int.h"
39 #include "k5-thread.h"
40 
41 #include "fcc.h"
42 #include "cc-int.h"
43 
44 struct krb5_cc_typelist {
45     const krb5_cc_ops *ops;
46     struct krb5_cc_typelist *next;
47 };
48 extern const krb5_cc_ops krb5_mcc_ops;
49 
50 #ifdef _WIN32
51 extern const krb5_cc_ops krb5_lcc_ops;
52 static struct krb5_cc_typelist cc_lcc_entry = { &krb5_lcc_ops, NULL };
53 static struct krb5_cc_typelist cc_mcc_entry = { &krb5_mcc_ops, &cc_lcc_entry };
54 #else
55 static struct krb5_cc_typelist cc_mcc_entry = { &krb5_mcc_ops, NULL };
56 #endif
57 
58 static struct krb5_cc_typelist cc_fcc_entry = { &krb5_cc_file_ops,
59 						&cc_mcc_entry };
60 
61 static struct krb5_cc_typelist *cc_typehead = &cc_fcc_entry;
62 static k5_mutex_t cc_typelist_lock = K5_MUTEX_PARTIAL_INITIALIZER;
63 
64 int
65 krb5int_cc_initialize(void)
66 {
67     int err;
68 
69     err = k5_mutex_finish_init(&krb5int_mcc_mutex);
70     if (err)
71 	return err;
72     err = k5_mutex_finish_init(&cc_typelist_lock);
73     if (err)
74 	return err;
75     err = k5_mutex_finish_init(&krb5int_cc_file_mutex);
76     if (err)
77 	return err;
78     return 0;
79 }
80 
81 void
82 krb5int_cc_finalize(void)
83 {
84     struct krb5_cc_typelist *t, *t_next;
85     k5_mutex_destroy(&cc_typelist_lock);
86     k5_mutex_destroy(&krb5int_cc_file_mutex);
87     k5_mutex_destroy(&krb5int_mcc_mutex);
88     for (t = cc_typehead; t != &cc_fcc_entry; t = t_next) {
89 	t_next = t->next;
90 	free(t);
91     }
92 }
93 
94 
95 /*
96  * Register a new credentials cache type
97  * If override is set, replace any existing ccache with that type tag
98  */
99 
100 krb5_error_code KRB5_CALLCONV
101 krb5_cc_register(krb5_context context, krb5_cc_ops *ops, krb5_boolean override)
102 {
103     struct krb5_cc_typelist *t;
104     krb5_error_code err;
105 
106     err = k5_mutex_lock(&cc_typelist_lock);
107     if (err)
108 	return err;
109     for (t = cc_typehead;t && strcmp(t->ops->prefix,ops->prefix);t = t->next)
110 	;
111     if (t) {
112 	if (override) {
113 	    t->ops = ops;
114 	    k5_mutex_unlock(&cc_typelist_lock);
115 	    return 0;
116 	} else {
117 	    k5_mutex_unlock(&cc_typelist_lock);
118 	    return KRB5_CC_TYPE_EXISTS;
119 	}
120     }
121     if (!(t = (struct krb5_cc_typelist *) malloc(sizeof(*t)))) {
122 	k5_mutex_unlock(&cc_typelist_lock);
123 	return ENOMEM;
124     }
125     t->next = cc_typehead;
126     t->ops = ops;
127     cc_typehead = t;
128     k5_mutex_unlock(&cc_typelist_lock);
129     return 0;
130 }
131 
132 /*
133  * Resolve a credential cache name into a cred. cache object.
134  *
135  * The name is currently constrained to be of the form "type:residual";
136  *
137  * The "type" portion corresponds to one of the predefined credential
138  * cache types, while the "residual" portion is specific to the
139  * particular cache type.
140  */
141 
142 #include <ctype.h>
143 krb5_error_code KRB5_CALLCONV
144 krb5_cc_resolve (krb5_context context, const char *name, krb5_ccache *cache)
145 {
146     struct krb5_cc_typelist *tlist;
147     char *pfx, *cp;
148     const char *resid;
149     unsigned int pfxlen;
150     krb5_error_code err;
151 
152     /* Solaris Kerberos */
153     if (!name)
154         return KRB5_CC_BADNAME;
155 
156     cp = strchr (name, ':');
157     if (!cp) {
158 	if (krb5_cc_dfl_ops)
159 	    return (*krb5_cc_dfl_ops->resolve)(context, cache, name);
160 	else
161 	    return KRB5_CC_BADNAME;
162     }
163 
164     pfxlen = cp - name;
165 
166     if ( pfxlen == 1 && isalpha(name[0]) ) {
167         /* We found a drive letter not a prefix - use FILE: */
168         pfx = strdup("FILE:");
169         if (!pfx)
170             return ENOMEM;
171 
172         resid = name;
173     } else {
174         resid = name + pfxlen + 1;
175 
176         pfx = malloc (pfxlen+1);
177         if (!pfx)
178             return ENOMEM;
179 
180         memcpy (pfx, name, pfxlen);
181         pfx[pfxlen] = '\0';
182     }
183 
184     *cache = (krb5_ccache) 0;
185 
186     err = k5_mutex_lock(&cc_typelist_lock);
187     if (err) {
188 	free(pfx);
189 	return err;
190     }
191     for (tlist = cc_typehead; tlist; tlist = tlist->next) {
192 	if (strcmp (tlist->ops->prefix, pfx) == 0) {
193 	    krb5_error_code (KRB5_CALLCONV *ccresolver)() = tlist->ops->resolve;
194 	    k5_mutex_unlock(&cc_typelist_lock);
195 	    free(pfx);
196 	    return (*ccresolver)(context, cache, resid);
197 	}
198     }
199     k5_mutex_unlock(&cc_typelist_lock);
200     if (krb5_cc_dfl_ops && !strcmp (pfx, krb5_cc_dfl_ops->prefix)) {
201 	free (pfx);
202 	return (*krb5_cc_dfl_ops->resolve)(context, cache, resid);
203     }
204     free(pfx);
205     return KRB5_CC_UNKNOWN_TYPE;
206 }
207