xref: /freebsd/crypto/heimdal/lib/gssapi/krb5/creds.c (revision a5921bc3653e2e286715e6fe8d473ec0d02da38c)
1 /*
2  * Copyright (c) 2009 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 "gsskrb5_locl.h"
35 
36 OM_uint32 GSSAPI_CALLCONV
37 _gsskrb5_export_cred(OM_uint32 *minor_status,
38 		     gss_cred_id_t cred_handle,
39 		     gss_buffer_t cred_token)
40 {
41     gsskrb5_cred handle = (gsskrb5_cred)cred_handle;
42     krb5_context context;
43     krb5_error_code ret;
44     krb5_storage *sp;
45     krb5_data data, mech;
46     const char *type;
47     char *str;
48 
49     GSSAPI_KRB5_INIT (&context);
50 
51     if (handle->usage != GSS_C_INITIATE && handle->usage != GSS_C_BOTH) {
52 	*minor_status = GSS_KRB5_S_G_BAD_USAGE;
53 	return GSS_S_FAILURE;
54     }
55 
56     sp = krb5_storage_emem();
57     if (sp == NULL) {
58 	*minor_status = ENOMEM;
59 	return GSS_S_FAILURE;
60     }
61 
62     type = krb5_cc_get_type(context, handle->ccache);
63     if (strcmp(type, "MEMORY") == 0) {
64 	krb5_creds *creds;
65 	ret = krb5_store_uint32(sp, 0);
66 	if (ret) {
67 	    krb5_storage_free(sp);
68 	    *minor_status = ret;
69 	    return GSS_S_FAILURE;
70 	}
71 
72 	ret = _krb5_get_krbtgt(context, handle->ccache,
73 			       handle->principal->realm,
74 			       &creds);
75 	if (ret) {
76 	    krb5_storage_free(sp);
77 	    *minor_status = ret;
78 	    return GSS_S_FAILURE;
79 	}
80 
81 	ret = krb5_store_creds(sp, creds);
82 	krb5_free_creds(context, creds);
83 	if (ret) {
84 	    krb5_storage_free(sp);
85 	    *minor_status = ret;
86 	    return GSS_S_FAILURE;
87 	}
88 
89     } else {
90 	ret = krb5_store_uint32(sp, 1);
91 	if (ret) {
92 	    krb5_storage_free(sp);
93 	    *minor_status = ret;
94 	    return GSS_S_FAILURE;
95 	}
96 
97 	ret = krb5_cc_get_full_name(context, handle->ccache, &str);
98 	if (ret) {
99 	    krb5_storage_free(sp);
100 	    *minor_status = ret;
101 	    return GSS_S_FAILURE;
102 	}
103 
104 	ret = krb5_store_string(sp, str);
105 	free(str);
106 	if (ret) {
107 	    krb5_storage_free(sp);
108 	    *minor_status = ret;
109 	    return GSS_S_FAILURE;
110 	}
111     }
112     ret = krb5_storage_to_data(sp, &data);
113     krb5_storage_free(sp);
114     if (ret) {
115 	*minor_status = ret;
116 	return GSS_S_FAILURE;
117     }
118     sp = krb5_storage_emem();
119     if (sp == NULL) {
120 	krb5_data_free(&data);
121 	*minor_status = ENOMEM;
122 	return GSS_S_FAILURE;
123     }
124 
125     mech.data = GSS_KRB5_MECHANISM->elements;
126     mech.length = GSS_KRB5_MECHANISM->length;
127 
128     ret = krb5_store_data(sp, mech);
129     if (ret) {
130 	krb5_data_free(&data);
131 	krb5_storage_free(sp);
132 	*minor_status = ret;
133 	return GSS_S_FAILURE;
134     }
135 
136     ret = krb5_store_data(sp, data);
137     krb5_data_free(&data);
138     if (ret) {
139 	krb5_storage_free(sp);
140 	*minor_status = ret;
141 	return GSS_S_FAILURE;
142     }
143 
144     ret = krb5_storage_to_data(sp, &data);
145     krb5_storage_free(sp);
146     if (ret) {
147 	*minor_status = ret;
148 	return GSS_S_FAILURE;
149     }
150 
151     cred_token->value = data.data;
152     cred_token->length = data.length;
153 
154     return GSS_S_COMPLETE;
155 }
156 
157 OM_uint32 GSSAPI_CALLCONV
158 _gsskrb5_import_cred(OM_uint32 * minor_status,
159 		     gss_buffer_t cred_token,
160 		     gss_cred_id_t * cred_handle)
161 {
162     krb5_context context;
163     krb5_error_code ret;
164     gsskrb5_cred handle;
165     krb5_ccache id;
166     krb5_storage *sp;
167     char *str;
168     uint32_t type;
169     int flags = 0;
170 
171     *cred_handle = GSS_C_NO_CREDENTIAL;
172 
173     GSSAPI_KRB5_INIT (&context);
174 
175     sp = krb5_storage_from_mem(cred_token->value, cred_token->length);
176     if (sp == NULL) {
177 	*minor_status = ENOMEM;
178 	return GSS_S_FAILURE;
179     }
180 
181     ret = krb5_ret_uint32(sp, &type);
182     if (ret) {
183 	krb5_storage_free(sp);
184 	*minor_status = ret;
185 	return GSS_S_FAILURE;
186     }
187     switch (type) {
188     case 0: {
189 	krb5_creds creds;
190 
191 	ret = krb5_ret_creds(sp, &creds);
192 	krb5_storage_free(sp);
193 	if (ret) {
194 	    *minor_status = ret;
195 	    return GSS_S_FAILURE;
196 	}
197 
198 	ret = krb5_cc_new_unique(context, "MEMORY", NULL, &id);
199 	if (ret) {
200 	    *minor_status = ret;
201 	    return GSS_S_FAILURE;
202 	}
203 
204 	ret = krb5_cc_initialize(context, id, creds.client);
205 	if (ret) {
206 	    krb5_cc_destroy(context, id);
207 	    *minor_status = ret;
208 	    return GSS_S_FAILURE;
209 	}
210 
211 	ret = krb5_cc_store_cred(context, id, &creds);
212 	krb5_free_cred_contents(context, &creds);
213 
214 	flags |= GSS_CF_DESTROY_CRED_ON_RELEASE;
215 
216 	break;
217     }
218     case 1:
219 	ret = krb5_ret_string(sp, &str);
220 	krb5_storage_free(sp);
221 	if (ret) {
222 	    *minor_status = ret;
223 	    return GSS_S_FAILURE;
224 	}
225 
226 	ret = krb5_cc_resolve(context, str, &id);
227 	krb5_xfree(str);
228 	if (ret) {
229 	    *minor_status = ret;
230 	    return GSS_S_FAILURE;
231 	}
232 	break;
233 
234     default:
235 	krb5_storage_free(sp);
236 	*minor_status = 0;
237 	return GSS_S_NO_CRED;
238     }
239 
240     handle = calloc(1, sizeof(*handle));
241     if (handle == NULL) {
242 	krb5_cc_close(context, id);
243 	*minor_status = ENOMEM;
244 	return GSS_S_FAILURE;
245     }
246 
247     handle->usage = GSS_C_INITIATE;
248     krb5_cc_get_principal(context, id, &handle->principal);
249     handle->ccache = id;
250     handle->cred_flags = flags;
251 
252     *cred_handle = (gss_cred_id_t)handle;
253 
254     return GSS_S_COMPLETE;
255 }
256