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
31226031SstasGSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
32226031Sstasgss_add_cred_with_password(OM_uint32 *minor_status,
33226031Sstas    const gss_cred_id_t input_cred_handle,
34226031Sstas    const gss_name_t desired_name,
35226031Sstas    const gss_OID desired_mech,
36226031Sstas    const gss_buffer_t password,
37226031Sstas    gss_cred_usage_t cred_usage,
38226031Sstas    OM_uint32 initiator_time_req,
39226031Sstas    OM_uint32 acceptor_time_req,
40226031Sstas    gss_cred_id_t *output_cred_handle,
41226031Sstas    gss_OID_set *actual_mechs,
42226031Sstas    OM_uint32 *initiator_time_rec,
43226031Sstas    OM_uint32 *acceptor_time_rec)
44226031Sstas{
45226031Sstas	OM_uint32 major_status;
46226031Sstas	gssapi_mech_interface m;
47226031Sstas	struct _gss_cred *cred = (struct _gss_cred *) input_cred_handle;
48226031Sstas	struct _gss_cred *new_cred;
49226031Sstas	struct _gss_mechanism_cred *mc;
50226031Sstas	struct _gss_mechanism_name *mn = NULL;
51226031Sstas	OM_uint32 junk, time_req;
52226031Sstas
53226031Sstas	*minor_status = 0;
54226031Sstas	*output_cred_handle = GSS_C_NO_CREDENTIAL;
55226031Sstas	if (initiator_time_rec)
56226031Sstas	    *initiator_time_rec = 0;
57226031Sstas	if (acceptor_time_rec)
58226031Sstas	    *acceptor_time_rec = 0;
59226031Sstas	if (actual_mechs)
60226031Sstas	    *actual_mechs = GSS_C_NO_OID_SET;
61226031Sstas
62226031Sstas	m = __gss_get_mechanism(desired_mech);
63226031Sstas	if (m == NULL) {
64226031Sstas		*minor_status = 0;
65226031Sstas		return (GSS_S_BAD_MECH);
66226031Sstas	}
67226031Sstas
68226031Sstas	new_cred = calloc(1, sizeof(struct _gss_cred));
69226031Sstas	if (new_cred == NULL) {
70226031Sstas		*minor_status = ENOMEM;
71226031Sstas		return (GSS_S_FAILURE);
72226031Sstas	}
73226031Sstas	HEIM_SLIST_INIT(&new_cred->gc_mc);
74226031Sstas
75226031Sstas	/*
76226031Sstas	 * Copy credentials from un-desired mechanisms to the new credential.
77226031Sstas	 */
78226031Sstas	if (cred) {
79226031Sstas		HEIM_SLIST_FOREACH(mc, &cred->gc_mc, gmc_link) {
80226031Sstas			struct _gss_mechanism_cred *copy_mc;
81226031Sstas
82226031Sstas			if (gss_oid_equal(mc->gmc_mech_oid, desired_mech)) {
83226031Sstas				continue;
84226031Sstas			}
85226031Sstas			copy_mc = _gss_copy_cred(mc);
86226031Sstas			if (copy_mc == NULL) {
87226031Sstas				gss_release_cred(&junk, (gss_cred_id_t *)&new_cred);
88226031Sstas				*minor_status = ENOMEM;
89226031Sstas				return (GSS_S_FAILURE);
90226031Sstas			}
91226031Sstas			HEIM_SLIST_INSERT_HEAD(&new_cred->gc_mc, copy_mc, gmc_link);
92226031Sstas		}
93226031Sstas	}
94226031Sstas
95226031Sstas	/*
96226031Sstas	 * Figure out a suitable mn, if any.
97226031Sstas	 */
98226031Sstas	if (desired_name != GSS_C_NO_NAME) {
99226031Sstas		major_status = _gss_find_mn(minor_status,
100226031Sstas					    (struct _gss_name *) desired_name,
101226031Sstas					    desired_mech,
102226031Sstas					    &mn);
103226031Sstas		if (major_status != GSS_S_COMPLETE) {
104226031Sstas			gss_release_cred(&junk, (gss_cred_id_t *)&new_cred);
105226031Sstas			return (major_status);
106226031Sstas		}
107226031Sstas	}
108226031Sstas
109226031Sstas	if (cred_usage == GSS_C_BOTH)
110226031Sstas		time_req = initiator_time_req > acceptor_time_req ? acceptor_time_req : initiator_time_req;
111226031Sstas	else if (cred_usage == GSS_C_INITIATE)
112226031Sstas		time_req = initiator_time_req;
113226031Sstas	else
114226031Sstas		time_req = acceptor_time_req;
115226031Sstas
116226031Sstas	major_status = _gss_acquire_mech_cred(minor_status, m, mn,
117226031Sstas					      GSS_C_CRED_PASSWORD, password,
118226031Sstas					      time_req, desired_mech,
119226031Sstas					      cred_usage, &mc);
120226031Sstas	if (major_status != GSS_S_COMPLETE) {
121226031Sstas		gss_release_cred(&junk, (gss_cred_id_t *)&new_cred);
122226031Sstas		return (major_status);
123226031Sstas	}
124226031Sstas
125226031Sstas	HEIM_SLIST_INSERT_HEAD(&new_cred->gc_mc, mc, gmc_link);
126226031Sstas
127226031Sstas	if (actual_mechs || initiator_time_rec || acceptor_time_rec) {
128226031Sstas		OM_uint32 time_rec;
129226031Sstas
130226031Sstas		major_status = gss_inquire_cred(minor_status,
131226031Sstas						(gss_cred_id_t)new_cred,
132226031Sstas						NULL,
133226031Sstas						&time_rec,
134226031Sstas						NULL,
135226031Sstas						actual_mechs);
136226031Sstas		if (GSS_ERROR(major_status)) {
137226031Sstas			gss_release_cred(&junk, (gss_cred_id_t *)&new_cred);
138226031Sstas			return (major_status);
139226031Sstas		}
140226031Sstas		if (initiator_time_rec &&
141226031Sstas		    (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH))
142226031Sstas			*initiator_time_rec = time_rec;
143226031Sstas		if (acceptor_time_rec &&
144226031Sstas		    (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH))
145226031Sstas			*acceptor_time_rec = time_rec;
146226031Sstas	}
147226031Sstas
148226031Sstas	*output_cred_handle = (gss_cred_id_t) new_cred;
149226031Sstas	return (GSS_S_COMPLETE);
150226031Sstas}
151