1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25/*
26 *  glue routine for gss_store_cred
27 */
28
29#include <mechglueP.h>
30#include "gssapiP_generic.h"
31#include <errno.h>
32
33static OM_uint32
34val_store_cred_args(
35        OM_uint32 *minor_status,
36        const gss_cred_id_t input_cred_handle,
37        gss_cred_usage_t cred_usage,
38	/*LINTED*/
39        const gss_OID desired_mech,
40	/*LINTED*/
41        OM_uint32 overwrite_cred,
42	/*LINTED*/
43        OM_uint32 default_cred,
44        gss_OID_set *elements_stored,
45	/*LINTED*/
46        gss_cred_usage_t *cred_usage_stored)
47{
48
49        /* Initialize outputs. */
50
51        if (minor_status != NULL)
52                *minor_status = 0;
53
54        if (elements_stored != NULL)
55                *elements_stored = GSS_C_NULL_OID_SET;
56
57       /* Validate arguments. */
58
59        if (minor_status == NULL)
60                return (GSS_S_CALL_INACCESSIBLE_WRITE);
61
62        if (input_cred_handle == GSS_C_NO_CREDENTIAL)
63                return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CRED);
64
65	if (cred_usage != GSS_C_ACCEPT
66	    && cred_usage != GSS_C_INITIATE
67	    && cred_usage != GSS_C_BOTH) {
68		if (minor_status) {
69			*minor_status = EINVAL;
70			map_errcode(minor_status);
71		}
72		return GSS_S_FAILURE;
73	}
74
75	return (GSS_S_COMPLETE);
76}
77
78OM_uint32 gss_store_cred(minor_status,
79			input_cred_handle,
80			cred_usage,
81			desired_mech,
82			overwrite_cred,
83			default_cred,
84			elements_stored,
85			cred_usage_stored)
86
87OM_uint32		*minor_status;
88const gss_cred_id_t	 input_cred_handle;
89gss_cred_usage_t	 cred_usage;
90const gss_OID		 desired_mech;
91OM_uint32		 overwrite_cred;
92OM_uint32		 default_cred;
93gss_OID_set		*elements_stored;
94gss_cred_usage_t	*cred_usage_stored;
95
96{
97	OM_uint32		major_status = GSS_S_FAILURE;
98	gss_union_cred_t	union_cred;
99	gss_cred_id_t		mech_cred;
100	gss_mechanism		mech;
101	gss_OID			dmech;
102	int			i;
103
104        major_status = val_store_cred_args(minor_status,
105                                           input_cred_handle,
106                                           cred_usage,
107                                           desired_mech,
108                                           overwrite_cred,
109                                           default_cred,
110                                           elements_stored,
111                                           cred_usage_stored);
112	if (major_status != GSS_S_COMPLETE)
113		return (major_status);
114
115	/* Initial value needed below. */
116		major_status = GSS_S_FAILURE;
117
118	if (cred_usage_stored != NULL)
119		*cred_usage_stored = GSS_C_BOTH; /* there's no GSS_C_NEITHER */
120
121	union_cred = (gss_union_cred_t)input_cred_handle;
122
123	/* desired_mech != GSS_C_NULL_OID -> store one element */
124	if (desired_mech != GSS_C_NULL_OID) {
125		mech = __gss_get_mechanism(desired_mech);
126		if (mech == NULL)
127			return (GSS_S_BAD_MECH);
128
129		if (mech->gss_store_cred == NULL)
130			return (major_status);
131
132		mech_cred = __gss_get_mechanism_cred(union_cred, desired_mech);
133		if (mech_cred == GSS_C_NO_CREDENTIAL)
134			return (GSS_S_NO_CRED);
135
136		major_status = mech->gss_store_cred(mech->context,
137						minor_status,
138						(gss_cred_id_t)mech_cred,
139						cred_usage,
140						desired_mech,
141						overwrite_cred,
142						default_cred,
143						elements_stored,
144						    cred_usage_stored);
145		if (major_status != GSS_S_COMPLETE)
146			map_error(minor_status, mech);
147		return major_status;
148	}
149
150	/* desired_mech == GSS_C_NULL_OID -> store all elements */
151
152	*minor_status = 0;
153
154	for (i = 0; i < union_cred->count; i++) {
155		/* Get mech and cred element */
156		dmech = &union_cred->mechs_array[i];
157		mech = __gss_get_mechanism(dmech);
158		if (mech == NULL)
159			continue;
160
161		if (mech->gss_store_cred == NULL)
162			continue;
163
164		mech_cred = __gss_get_mechanism_cred(union_cred, dmech);
165		if (mech_cred == GSS_C_NO_CREDENTIAL)
166			continue; /* can't happen, but safe to ignore */
167
168		major_status = mech->gss_store_cred(mech->context,
169						minor_status,
170						(gss_cred_id_t)mech_cred,
171						cred_usage,
172						dmech,
173						overwrite_cred,
174						default_cred,
175						NULL,
176						cred_usage_stored);
177		if (major_status != GSS_S_COMPLETE) {
178			map_error(minor_status, mech);
179			continue;
180		}
181
182		/* Succeeded for at least one mech */
183
184		if (elements_stored == NULL)
185			continue;
186
187		if (*elements_stored == GSS_C_NULL_OID_SET) {
188			major_status = gss_create_empty_oid_set(minor_status,
189						elements_stored);
190
191			if (GSS_ERROR(major_status))
192				return (major_status);
193		}
194
195		major_status = gss_add_oid_set_member(minor_status, dmech,
196			elements_stored);
197
198		/* The caller should clean up elements_stored */
199		if (GSS_ERROR(major_status))
200			return (major_status);
201	}
202
203	/*
204	 * Success with some mechs may mask failure with others, but
205	 * that's what elements_stored is for.
206	 */
207	return (major_status);
208}
209