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 KTH nor the names of its contributors may be
18 *    used to endorse or promote products derived from this software without
19 *    specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY
22 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include "mech_locl.h"
35#include <krb5.h>
36
37/*
38 * format: any number of:
39 *     mech-len: int32
40 *     mech-data: char * (not alligned)
41 *     cred-len: int32
42 *     cred-data char * (not alligned)
43*/
44
45GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
46gss_export_cred(OM_uint32 * minor_status,
47		gss_cred_id_t cred_handle,
48		gss_buffer_t token)
49{
50    struct _gss_cred *cred = (struct _gss_cred *)cred_handle;
51    struct _gss_mechanism_cred *mc;
52    gss_buffer_desc buffer;
53    krb5_error_code ret;
54    krb5_storage *sp;
55    OM_uint32 major;
56    krb5_data data;
57
58    _mg_buffer_zero(token);
59
60    if (cred == NULL) {
61	*minor_status = 0;
62	return GSS_S_NO_CRED;
63    }
64
65    HEIM_SLIST_FOREACH(mc, &cred->gc_mc, gmc_link) {
66	if (mc->gmc_mech->gm_export_cred == NULL) {
67	    *minor_status = 0;
68	    return GSS_S_NO_CRED;
69	}
70    }
71
72    sp = krb5_storage_emem();
73    if (sp == NULL) {
74	*minor_status = ENOMEM;
75	return GSS_S_FAILURE;
76    }
77
78    HEIM_SLIST_FOREACH(mc, &cred->gc_mc, gmc_link) {
79
80	major = mc->gmc_mech->gm_export_cred(minor_status,
81					     mc->gmc_cred, &buffer);
82	if (major) {
83	    krb5_storage_free(sp);
84	    return major;
85	}
86
87	ret = krb5_storage_write(sp, buffer.value, buffer.length);
88	if (ret < 0 || (size_t)ret != buffer.length) {
89	    gss_release_buffer(minor_status, &buffer);
90	    krb5_storage_free(sp);
91	    *minor_status = EINVAL;
92	    return GSS_S_FAILURE;
93	}
94	gss_release_buffer(minor_status, &buffer);
95    }
96
97    ret = krb5_storage_to_data(sp, &data);
98    krb5_storage_free(sp);
99    if (ret) {
100	*minor_status = ret;
101	return GSS_S_FAILURE;
102    }
103
104    token->value = data.data;
105    token->length = data.length;
106
107    return GSS_S_COMPLETE;
108}
109
110GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
111gss_import_cred(OM_uint32 * minor_status,
112		gss_buffer_t token,
113		gss_cred_id_t * cred_handle)
114{
115    gssapi_mech_interface m;
116    krb5_error_code ret;
117    struct _gss_cred *cred;
118    krb5_storage *sp = NULL;
119    OM_uint32 major, junk;
120    krb5_data data;
121
122    *cred_handle = GSS_C_NO_CREDENTIAL;
123
124    if (token->length == 0) {
125	*minor_status = ENOMEM;
126	return GSS_S_FAILURE;
127    }
128
129    sp = krb5_storage_from_readonly_mem(token->value, token->length);
130    if (sp == NULL) {
131	*minor_status = ENOMEM;
132	return GSS_S_FAILURE;
133    }
134
135    cred = calloc(1, sizeof(struct _gss_cred));
136    if (cred == NULL) {
137	krb5_storage_free(sp);
138	*minor_status = ENOMEM;
139	return GSS_S_FAILURE;
140    }
141    HEIM_SLIST_INIT(&cred->gc_mc);
142
143    *cred_handle = (gss_cred_id_t)cred;
144
145    while(1) {
146	struct _gss_mechanism_cred *mc;
147	gss_buffer_desc buffer;
148	gss_cred_id_t mcred;
149	gss_OID_desc oid;
150
151	ret = krb5_ret_data(sp, &data);
152	if (ret == HEIM_ERR_EOF) {
153	    break;
154	} else if (ret) {
155	    *minor_status = ret;
156	    major = GSS_S_FAILURE;
157	    goto out;
158	}
159	oid.elements = data.data;
160	oid.length = data.length;
161
162	m = __gss_get_mechanism(&oid);
163	krb5_data_free(&data);
164	if (!m) {
165	    *minor_status = 0;
166	    major = GSS_S_BAD_MECH;
167	    goto out;
168	}
169
170	if (m->gm_import_cred == NULL) {
171	    *minor_status = 0;
172	    major = GSS_S_BAD_MECH;
173	    goto out;
174	}
175
176	ret = krb5_ret_data(sp, &data);
177	if (ret) {
178	    *minor_status = ret;
179	    major = GSS_S_FAILURE;
180	    goto out;
181	}
182
183	buffer.value = data.data;
184	buffer.length = data.length;
185
186	major = m->gm_import_cred(minor_status,
187				  &buffer, &mcred);
188	krb5_data_free(&data);
189	if (major) {
190	    goto out;
191	}
192
193	mc = malloc(sizeof(struct _gss_mechanism_cred));
194	if (mc == NULL) {
195	    *minor_status = EINVAL;
196	    major = GSS_S_FAILURE;
197	    goto out;
198	}
199
200	mc->gmc_mech = m;
201	mc->gmc_mech_oid = &m->gm_mech_oid;
202	mc->gmc_cred = mcred;
203
204	HEIM_SLIST_INSERT_HEAD(&cred->gc_mc, mc, gmc_link);
205    }
206    krb5_storage_free(sp);
207    sp = NULL;
208
209    if (HEIM_SLIST_EMPTY(&cred->gc_mc)) {
210	major = GSS_S_NO_CRED;
211	goto out;
212    }
213
214    return GSS_S_COMPLETE;
215
216 out:
217    if (sp)
218	krb5_storage_free(sp);
219
220    gss_release_cred(&junk, cred_handle);
221
222    return major;
223
224}
225