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_acquire_cred.c,v 1.1 2005/12/29 14:40:20 dfr Exp $
27226031Sstas */
28226031Sstas
29226031Sstas#include "mech_locl.h"
30226031Sstas
31226031SstasGSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
32226031Sstasgss_acquire_cred(OM_uint32 *minor_status,
33226031Sstas    const gss_name_t desired_name,
34226031Sstas    OM_uint32 time_req,
35226031Sstas    const gss_OID_set desired_mechs,
36226031Sstas    gss_cred_usage_t cred_usage,
37226031Sstas    gss_cred_id_t *output_cred_handle,
38226031Sstas    gss_OID_set *actual_mechs,
39226031Sstas    OM_uint32 *time_rec)
40226031Sstas{
41226031Sstas	OM_uint32 major_status;
42226031Sstas	gss_OID_set mechs = desired_mechs;
43226031Sstas	gss_OID_set_desc set;
44226031Sstas	struct _gss_name *name = (struct _gss_name *) desired_name;
45226031Sstas	gssapi_mech_interface m;
46226031Sstas	struct _gss_cred *cred;
47226031Sstas	struct _gss_mechanism_cred *mc;
48226031Sstas	OM_uint32 min_time, cred_time;
49226031Sstas	size_t i;
50226031Sstas
51226031Sstas	*minor_status = 0;
52226031Sstas	if (output_cred_handle == NULL)
53226031Sstas	    return GSS_S_CALL_INACCESSIBLE_READ;
54226031Sstas	if (actual_mechs)
55226031Sstas	    *actual_mechs = GSS_C_NO_OID_SET;
56226031Sstas	if (time_rec)
57226031Sstas	    *time_rec = 0;
58226031Sstas
59226031Sstas	_gss_load_mech();
60226031Sstas
61226031Sstas	/*
62226031Sstas	 * First make sure that at least one of the requested
63226031Sstas	 * mechanisms is one that we support.
64226031Sstas	 */
65226031Sstas	if (mechs) {
66226031Sstas		for (i = 0; i < mechs->count; i++) {
67226031Sstas			int t;
68226031Sstas			gss_test_oid_set_member(minor_status,
69226031Sstas			    &mechs->elements[i], _gss_mech_oids, &t);
70226031Sstas			if (t)
71226031Sstas				break;
72226031Sstas		}
73226031Sstas		if (i == mechs->count) {
74226031Sstas			*minor_status = 0;
75226031Sstas			return (GSS_S_BAD_MECH);
76226031Sstas		}
77226031Sstas	}
78226031Sstas
79226031Sstas	if (actual_mechs) {
80226031Sstas		major_status = gss_create_empty_oid_set(minor_status,
81226031Sstas		    actual_mechs);
82226031Sstas		if (major_status)
83226031Sstas			return (major_status);
84226031Sstas	}
85226031Sstas
86226031Sstas	cred = malloc(sizeof(struct _gss_cred));
87226031Sstas	if (!cred) {
88226031Sstas		if (actual_mechs)
89226031Sstas			gss_release_oid_set(minor_status, actual_mechs);
90226031Sstas		*minor_status = ENOMEM;
91226031Sstas		return (GSS_S_FAILURE);
92226031Sstas	}
93226031Sstas	HEIM_SLIST_INIT(&cred->gc_mc);
94226031Sstas
95226031Sstas	if (mechs == GSS_C_NO_OID_SET)
96226031Sstas		mechs = _gss_mech_oids;
97226031Sstas
98226031Sstas	set.count = 1;
99226031Sstas	min_time = GSS_C_INDEFINITE;
100226031Sstas	for (i = 0; i < mechs->count; i++) {
101226031Sstas		struct _gss_mechanism_name *mn = NULL;
102226031Sstas
103226031Sstas		m = __gss_get_mechanism(&mechs->elements[i]);
104226031Sstas		if (!m)
105226031Sstas			continue;
106226031Sstas
107226031Sstas		if (desired_name != GSS_C_NO_NAME) {
108226031Sstas			major_status = _gss_find_mn(minor_status, name,
109226031Sstas						    &mechs->elements[i], &mn);
110226031Sstas			if (major_status != GSS_S_COMPLETE)
111226031Sstas				continue;
112226031Sstas		}
113226031Sstas
114226031Sstas		mc = malloc(sizeof(struct _gss_mechanism_cred));
115226031Sstas		if (!mc) {
116226031Sstas			continue;
117226031Sstas		}
118226031Sstas		mc->gmc_mech = m;
119226031Sstas		mc->gmc_mech_oid = &m->gm_mech_oid;
120226031Sstas
121226031Sstas		/*
122226031Sstas		 * XXX Probably need to do something with actual_mechs.
123226031Sstas		 */
124226031Sstas		set.elements = &mechs->elements[i];
125226031Sstas		major_status = m->gm_acquire_cred(minor_status,
126226031Sstas		    (desired_name != GSS_C_NO_NAME
127226031Sstas			? mn->gmn_name : GSS_C_NO_NAME),
128226031Sstas		    time_req, &set, cred_usage,
129226031Sstas		    &mc->gmc_cred, NULL, &cred_time);
130226031Sstas		if (major_status) {
131226031Sstas			free(mc);
132226031Sstas			continue;
133226031Sstas		}
134226031Sstas		if (cred_time < min_time)
135226031Sstas			min_time = cred_time;
136226031Sstas
137226031Sstas		if (actual_mechs) {
138226031Sstas			major_status = gss_add_oid_set_member(minor_status,
139226031Sstas			    mc->gmc_mech_oid, actual_mechs);
140226031Sstas			if (major_status) {
141226031Sstas				m->gm_release_cred(minor_status,
142226031Sstas				    &mc->gmc_cred);
143226031Sstas				free(mc);
144226031Sstas				continue;
145226031Sstas			}
146226031Sstas		}
147226031Sstas
148226031Sstas		HEIM_SLIST_INSERT_HEAD(&cred->gc_mc, mc, gmc_link);
149226031Sstas	}
150226031Sstas
151226031Sstas	/*
152226031Sstas	 * If we didn't manage to create a single credential, return
153226031Sstas	 * an error.
154226031Sstas	 */
155226031Sstas	if (!HEIM_SLIST_FIRST(&cred->gc_mc)) {
156226031Sstas		free(cred);
157226031Sstas		if (actual_mechs)
158226031Sstas			gss_release_oid_set(minor_status, actual_mechs);
159226031Sstas		*minor_status = 0;
160226031Sstas		return (GSS_S_NO_CRED);
161226031Sstas	}
162226031Sstas
163226031Sstas	if (time_rec)
164226031Sstas		*time_rec = min_time;
165226031Sstas	*output_cred_handle = (gss_cred_id_t) cred;
166226031Sstas	*minor_status = 0;
167226031Sstas	return (GSS_S_COMPLETE);
168226031Sstas}
169