1226031Sstas/*-
2226031Sstas * Copyright (c) 2005 Doug Rabson
3226031Sstas * All rights reserved.
4226031Sstas *
5226031Sstas * Redistribution and use in source and binary forms, with or without
6226031Sstas * modification, are permitted provided that the following conditions
7226031Sstas * are met:
8226031Sstas * 1. Redistributions of source code must retain the above copyright
9226031Sstas *    notice, this list of conditions and the following disclaimer.
10226031Sstas * 2. Redistributions in binary form must reproduce the above copyright
11226031Sstas *    notice, this list of conditions and the following disclaimer in the
12226031Sstas *    documentation and/or other materials provided with the distribution.
13226031Sstas *
14226031Sstas * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15226031Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16226031Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17226031Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18226031Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19226031Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20226031Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21226031Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22226031Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23226031Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24226031Sstas * SUCH DAMAGE.
25226031Sstas *
26226031Sstas *	$FreeBSD: src/lib/libgssapi/gss_add_cred.c,v 1.1 2005/12/29 14:40:20 dfr Exp $
27226031Sstas */
28226031Sstas
29226031Sstas#include "mech_locl.h"
30226031Sstas
31226031Sstasstruct _gss_mechanism_cred *
32226031Sstas_gss_copy_cred(struct _gss_mechanism_cred *mc)
33226031Sstas{
34226031Sstas	struct _gss_mechanism_cred *new_mc;
35226031Sstas	gssapi_mech_interface m = mc->gmc_mech;
36226031Sstas	OM_uint32 major_status, minor_status;
37226031Sstas	gss_name_t name;
38226031Sstas	gss_cred_id_t cred;
39226031Sstas	OM_uint32 initiator_lifetime, acceptor_lifetime;
40226031Sstas	gss_cred_usage_t cred_usage;
41226031Sstas
42226031Sstas	major_status = m->gm_inquire_cred_by_mech(&minor_status,
43226031Sstas	    mc->gmc_cred, mc->gmc_mech_oid,
44226031Sstas	    &name, &initiator_lifetime, &acceptor_lifetime, &cred_usage);
45226031Sstas	if (major_status) {
46226031Sstas		_gss_mg_error(m, major_status, minor_status);
47226031Sstas		return (0);
48226031Sstas	}
49226031Sstas
50226031Sstas	major_status = m->gm_add_cred(&minor_status,
51226031Sstas	    GSS_C_NO_CREDENTIAL, name, mc->gmc_mech_oid,
52226031Sstas	    cred_usage, initiator_lifetime, acceptor_lifetime,
53226031Sstas	    &cred, 0, 0, 0);
54226031Sstas	m->gm_release_name(&minor_status, &name);
55226031Sstas
56226031Sstas	if (major_status) {
57226031Sstas		_gss_mg_error(m, major_status, minor_status);
58226031Sstas		return (0);
59226031Sstas	}
60226031Sstas
61226031Sstas	new_mc = malloc(sizeof(struct _gss_mechanism_cred));
62226031Sstas	if (!new_mc) {
63226031Sstas		m->gm_release_cred(&minor_status, &cred);
64226031Sstas		return (0);
65226031Sstas	}
66226031Sstas	new_mc->gmc_mech = m;
67226031Sstas	new_mc->gmc_mech_oid = &m->gm_mech_oid;
68226031Sstas	new_mc->gmc_cred = cred;
69226031Sstas
70226031Sstas	return (new_mc);
71226031Sstas}
72226031Sstas
73226031SstasGSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
74226031Sstasgss_add_cred(OM_uint32 *minor_status,
75226031Sstas    const gss_cred_id_t input_cred_handle,
76226031Sstas    const gss_name_t desired_name,
77226031Sstas    const gss_OID desired_mech,
78226031Sstas    gss_cred_usage_t cred_usage,
79226031Sstas    OM_uint32 initiator_time_req,
80226031Sstas    OM_uint32 acceptor_time_req,
81226031Sstas    gss_cred_id_t *output_cred_handle,
82226031Sstas    gss_OID_set *actual_mechs,
83226031Sstas    OM_uint32 *initiator_time_rec,
84226031Sstas    OM_uint32 *acceptor_time_rec)
85226031Sstas{
86226031Sstas	OM_uint32 major_status;
87226031Sstas	gssapi_mech_interface m;
88226031Sstas	struct _gss_cred *cred = (struct _gss_cred *) input_cred_handle;
89226031Sstas	struct _gss_cred *new_cred;
90226031Sstas	gss_cred_id_t release_cred;
91226031Sstas	struct _gss_mechanism_cred *mc, *target_mc, *copy_mc;
92226031Sstas	struct _gss_mechanism_name *mn;
93226031Sstas	OM_uint32 junk;
94226031Sstas
95226031Sstas	*minor_status = 0;
96226031Sstas	*output_cred_handle = GSS_C_NO_CREDENTIAL;
97226031Sstas	if (initiator_time_rec)
98226031Sstas	    *initiator_time_rec = 0;
99226031Sstas	if (acceptor_time_rec)
100226031Sstas	    *acceptor_time_rec = 0;
101226031Sstas	if (actual_mechs)
102226031Sstas	    *actual_mechs = GSS_C_NO_OID_SET;
103226031Sstas
104226031Sstas	new_cred = malloc(sizeof(struct _gss_cred));
105226031Sstas	if (!new_cred) {
106226031Sstas		*minor_status = ENOMEM;
107226031Sstas		return (GSS_S_FAILURE);
108226031Sstas	}
109226031Sstas	HEIM_SLIST_INIT(&new_cred->gc_mc);
110226031Sstas
111226031Sstas	/*
112226031Sstas	 * We go through all the mc attached to the input_cred_handle
113226031Sstas	 * and check the mechanism. If it matches, we call
114226031Sstas	 * gss_add_cred for that mechanism, otherwise we copy the mc
115226031Sstas	 * to new_cred.
116226031Sstas	 */
117226031Sstas	target_mc = 0;
118226031Sstas	if (cred) {
119226031Sstas		HEIM_SLIST_FOREACH(mc, &cred->gc_mc, gmc_link) {
120226031Sstas			if (gss_oid_equal(mc->gmc_mech_oid, desired_mech)) {
121226031Sstas				target_mc = mc;
122226031Sstas			}
123226031Sstas			copy_mc = _gss_copy_cred(mc);
124226031Sstas			if (!copy_mc) {
125226031Sstas				release_cred = (gss_cred_id_t)new_cred;
126226031Sstas				gss_release_cred(&junk, &release_cred);
127226031Sstas				*minor_status = ENOMEM;
128226031Sstas				return (GSS_S_FAILURE);
129226031Sstas			}
130226031Sstas			HEIM_SLIST_INSERT_HEAD(&new_cred->gc_mc, copy_mc, gmc_link);
131226031Sstas		}
132226031Sstas	}
133226031Sstas
134226031Sstas	/*
135226031Sstas	 * Figure out a suitable mn, if any.
136226031Sstas	 */
137226031Sstas	if (desired_name) {
138226031Sstas		major_status = _gss_find_mn(minor_status,
139226031Sstas					    (struct _gss_name *) desired_name,
140226031Sstas					    desired_mech,
141226031Sstas					    &mn);
142226031Sstas		if (major_status != GSS_S_COMPLETE) {
143226031Sstas			free(new_cred);
144226031Sstas			return major_status;
145226031Sstas		}
146226031Sstas	} else {
147226031Sstas		mn = 0;
148226031Sstas	}
149226031Sstas
150226031Sstas	m = __gss_get_mechanism(desired_mech);
151226031Sstas
152226031Sstas	mc = malloc(sizeof(struct _gss_mechanism_cred));
153226031Sstas	if (!mc) {
154226031Sstas		release_cred = (gss_cred_id_t)new_cred;
155226031Sstas		gss_release_cred(&junk, &release_cred);
156226031Sstas		*minor_status = ENOMEM;
157226031Sstas		return (GSS_S_FAILURE);
158226031Sstas	}
159226031Sstas	mc->gmc_mech = m;
160226031Sstas	mc->gmc_mech_oid = &m->gm_mech_oid;
161226031Sstas
162226031Sstas	major_status = m->gm_add_cred(minor_status,
163226031Sstas	    target_mc ? target_mc->gmc_cred : GSS_C_NO_CREDENTIAL,
164226031Sstas	    desired_name ? mn->gmn_name : GSS_C_NO_NAME,
165226031Sstas	    desired_mech,
166226031Sstas	    cred_usage,
167226031Sstas	    initiator_time_req,
168226031Sstas	    acceptor_time_req,
169226031Sstas	    &mc->gmc_cred,
170226031Sstas	    actual_mechs,
171226031Sstas	    initiator_time_rec,
172226031Sstas	    acceptor_time_rec);
173226031Sstas
174226031Sstas	if (major_status) {
175226031Sstas		_gss_mg_error(m, major_status, *minor_status);
176226031Sstas		release_cred = (gss_cred_id_t)new_cred;
177226031Sstas		gss_release_cred(&junk, &release_cred);
178226031Sstas		free(mc);
179226031Sstas		return (major_status);
180226031Sstas	}
181226031Sstas	HEIM_SLIST_INSERT_HEAD(&new_cred->gc_mc, mc, gmc_link);
182226031Sstas	*output_cred_handle = (gss_cred_id_t) new_cred;
183226031Sstas
184226031Sstas	return (GSS_S_COMPLETE);
185226031Sstas}
186226031Sstas
187