1226031Sstas/*
2226031Sstas * Copyright (c) 2009 Kungliga Tekniska H��gskolan
3226031Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4226031Sstas * All rights reserved.
5226031Sstas *
6226031Sstas * Redistribution and use in source and binary forms, with or without
7226031Sstas * modification, are permitted provided that the following conditions
8226031Sstas * are met:
9226031Sstas *
10226031Sstas * 1. Redistributions of source code must retain the above copyright
11226031Sstas *    notice, this list of conditions and the following disclaimer.
12226031Sstas *
13226031Sstas * 2. Redistributions in binary form must reproduce the above copyright
14226031Sstas *    notice, this list of conditions and the following disclaimer in the
15226031Sstas *    documentation and/or other materials provided with the distribution.
16226031Sstas *
17226031Sstas * 3. Neither the name of KTH nor the names of its contributors may be
18226031Sstas *    used to endorse or promote products derived from this software without
19226031Sstas *    specific prior written permission.
20226031Sstas *
21226031Sstas * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY
22226031Sstas * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23226031Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24226031Sstas * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE
25226031Sstas * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26226031Sstas * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27226031Sstas * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28226031Sstas * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29226031Sstas * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30226031Sstas * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31226031Sstas * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32226031Sstas */
33226031Sstas
34226031Sstas#include "mech_locl.h"
35226031Sstas#include <krb5.h>
36226031Sstas
37226031Sstas/*
38226031Sstas * format: any number of:
39226031Sstas *     mech-len: int32
40226031Sstas *     mech-data: char * (not alligned)
41226031Sstas *     cred-len: int32
42226031Sstas *     cred-data char * (not alligned)
43226031Sstas*/
44226031Sstas
45226031SstasGSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
46226031Sstasgss_export_cred(OM_uint32 * minor_status,
47226031Sstas		gss_cred_id_t cred_handle,
48226031Sstas		gss_buffer_t token)
49226031Sstas{
50226031Sstas    struct _gss_cred *cred = (struct _gss_cred *)cred_handle;
51226031Sstas    struct _gss_mechanism_cred *mc;
52226031Sstas    gss_buffer_desc buffer;
53226031Sstas    krb5_error_code ret;
54226031Sstas    krb5_storage *sp;
55226031Sstas    OM_uint32 major;
56226031Sstas    krb5_data data;
57226031Sstas
58226031Sstas    _mg_buffer_zero(token);
59226031Sstas
60226031Sstas    if (cred == NULL) {
61226031Sstas	*minor_status = 0;
62226031Sstas	return GSS_S_NO_CRED;
63226031Sstas    }
64226031Sstas
65226031Sstas    HEIM_SLIST_FOREACH(mc, &cred->gc_mc, gmc_link) {
66226031Sstas	if (mc->gmc_mech->gm_export_cred == NULL) {
67226031Sstas	    *minor_status = 0;
68226031Sstas	    return GSS_S_NO_CRED;
69226031Sstas	}
70226031Sstas    }
71226031Sstas
72226031Sstas    sp = krb5_storage_emem();
73226031Sstas    if (sp == NULL) {
74226031Sstas	*minor_status = ENOMEM;
75226031Sstas	return GSS_S_FAILURE;
76226031Sstas    }
77226031Sstas
78226031Sstas    HEIM_SLIST_FOREACH(mc, &cred->gc_mc, gmc_link) {
79226031Sstas
80226031Sstas	major = mc->gmc_mech->gm_export_cred(minor_status,
81226031Sstas					     mc->gmc_cred, &buffer);
82226031Sstas	if (major) {
83226031Sstas	    krb5_storage_free(sp);
84226031Sstas	    return major;
85226031Sstas	}
86226031Sstas
87226031Sstas	ret = krb5_storage_write(sp, buffer.value, buffer.length);
88226031Sstas	if (ret < 0 || (size_t)ret != buffer.length) {
89226031Sstas	    gss_release_buffer(minor_status, &buffer);
90226031Sstas	    krb5_storage_free(sp);
91226031Sstas	    *minor_status = EINVAL;
92226031Sstas	    return GSS_S_FAILURE;
93226031Sstas	}
94226031Sstas	gss_release_buffer(minor_status, &buffer);
95226031Sstas    }
96226031Sstas
97226031Sstas    ret = krb5_storage_to_data(sp, &data);
98226031Sstas    krb5_storage_free(sp);
99226031Sstas    if (ret) {
100226031Sstas	*minor_status = ret;
101226031Sstas	return GSS_S_FAILURE;
102226031Sstas    }
103226031Sstas
104226031Sstas    token->value = data.data;
105226031Sstas    token->length = data.length;
106226031Sstas
107226031Sstas    return GSS_S_COMPLETE;
108226031Sstas}
109226031Sstas
110226031SstasGSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
111226031Sstasgss_import_cred(OM_uint32 * minor_status,
112226031Sstas		gss_buffer_t token,
113226031Sstas		gss_cred_id_t * cred_handle)
114226031Sstas{
115226031Sstas    gssapi_mech_interface m;
116226031Sstas    krb5_error_code ret;
117226031Sstas    struct _gss_cred *cred;
118226031Sstas    krb5_storage *sp = NULL;
119226031Sstas    OM_uint32 major, junk;
120226031Sstas    krb5_data data;
121226031Sstas
122226031Sstas    *cred_handle = GSS_C_NO_CREDENTIAL;
123226031Sstas
124226031Sstas    if (token->length == 0) {
125226031Sstas	*minor_status = ENOMEM;
126226031Sstas	return GSS_S_FAILURE;
127226031Sstas    }
128226031Sstas
129226031Sstas    sp = krb5_storage_from_readonly_mem(token->value, token->length);
130226031Sstas    if (sp == NULL) {
131226031Sstas	*minor_status = ENOMEM;
132226031Sstas	return GSS_S_FAILURE;
133226031Sstas    }
134226031Sstas
135226031Sstas    cred = calloc(1, sizeof(struct _gss_cred));
136226031Sstas    if (cred == NULL) {
137226031Sstas	krb5_storage_free(sp);
138226031Sstas	*minor_status = ENOMEM;
139226031Sstas	return GSS_S_FAILURE;
140226031Sstas    }
141226031Sstas    HEIM_SLIST_INIT(&cred->gc_mc);
142226031Sstas
143226031Sstas    *cred_handle = (gss_cred_id_t)cred;
144226031Sstas
145226031Sstas    while(1) {
146226031Sstas	struct _gss_mechanism_cred *mc;
147226031Sstas	gss_buffer_desc buffer;
148226031Sstas	gss_cred_id_t mcred;
149226031Sstas	gss_OID_desc oid;
150226031Sstas
151226031Sstas	ret = krb5_ret_data(sp, &data);
152226031Sstas	if (ret == HEIM_ERR_EOF) {
153226031Sstas	    break;
154226031Sstas	} else if (ret) {
155226031Sstas	    *minor_status = ret;
156226031Sstas	    major = GSS_S_FAILURE;
157226031Sstas	    goto out;
158226031Sstas	}
159226031Sstas	oid.elements = data.data;
160226031Sstas	oid.length = data.length;
161226031Sstas
162226031Sstas	m = __gss_get_mechanism(&oid);
163226031Sstas	krb5_data_free(&data);
164226031Sstas	if (!m) {
165226031Sstas	    *minor_status = 0;
166226031Sstas	    major = GSS_S_BAD_MECH;
167226031Sstas	    goto out;
168226031Sstas	}
169226031Sstas
170226031Sstas	if (m->gm_import_cred == NULL) {
171226031Sstas	    *minor_status = 0;
172226031Sstas	    major = GSS_S_BAD_MECH;
173226031Sstas	    goto out;
174226031Sstas	}
175226031Sstas
176226031Sstas	ret = krb5_ret_data(sp, &data);
177226031Sstas	if (ret) {
178226031Sstas	    *minor_status = ret;
179226031Sstas	    major = GSS_S_FAILURE;
180226031Sstas	    goto out;
181226031Sstas	}
182226031Sstas
183226031Sstas	buffer.value = data.data;
184226031Sstas	buffer.length = data.length;
185226031Sstas
186226031Sstas	major = m->gm_import_cred(minor_status,
187226031Sstas				  &buffer, &mcred);
188226031Sstas	krb5_data_free(&data);
189226031Sstas	if (major) {
190226031Sstas	    goto out;
191226031Sstas	}
192226031Sstas
193226031Sstas	mc = malloc(sizeof(struct _gss_mechanism_cred));
194226031Sstas	if (mc == NULL) {
195226031Sstas	    *minor_status = EINVAL;
196226031Sstas	    major = GSS_S_FAILURE;
197226031Sstas	    goto out;
198226031Sstas	}
199226031Sstas
200226031Sstas	mc->gmc_mech = m;
201226031Sstas	mc->gmc_mech_oid = &m->gm_mech_oid;
202226031Sstas	mc->gmc_cred = mcred;
203226031Sstas
204226031Sstas	HEIM_SLIST_INSERT_HEAD(&cred->gc_mc, mc, gmc_link);
205226031Sstas    }
206226031Sstas    krb5_storage_free(sp);
207226031Sstas    sp = NULL;
208226031Sstas
209226031Sstas    if (HEIM_SLIST_EMPTY(&cred->gc_mc)) {
210226031Sstas	major = GSS_S_NO_CRED;
211226031Sstas	goto out;
212226031Sstas    }
213226031Sstas
214226031Sstas    return GSS_S_COMPLETE;
215226031Sstas
216226031Sstas out:
217226031Sstas    if (sp)
218226031Sstas	krb5_storage_free(sp);
219226031Sstas
220226031Sstas    gss_release_cred(&junk, cred_handle);
221226031Sstas
222226031Sstas    return major;
223226031Sstas
224226031Sstas}
225