xref: /freebsd/crypto/krb5/src/lib/gssapi/mechglue/g_store_cred.c (revision f1c4c3daccbaf3820f0e2224de53df12fc952fcc)
1 /*
2  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /* #pragma ident	"@(#)g_store_cred.c	1.2	04/04/05 SMI" */
7 
8 /*
9  *  glue routine for gss_store_cred
10  */
11 
12 #include <mglueP.h>
13 
14 static OM_uint32
store_cred_fallback(OM_uint32 * minor_status,gss_mechanism mech,gss_cred_id_t mech_cred,gss_cred_usage_t cred_usage,gss_OID desired_mech,OM_uint32 overwrite_cred,OM_uint32 default_cred,gss_const_key_value_set_t cred_store,gss_OID_set * elements_stored,gss_cred_usage_t * cred_usage_stored)15 store_cred_fallback(
16 	OM_uint32 *minor_status,
17 	gss_mechanism mech,
18 	gss_cred_id_t mech_cred,
19 	gss_cred_usage_t cred_usage,
20 	gss_OID desired_mech,
21 	OM_uint32 overwrite_cred,
22 	OM_uint32 default_cred,
23 	gss_const_key_value_set_t cred_store,
24 	gss_OID_set *elements_stored,
25 	gss_cred_usage_t *cred_usage_stored)
26 {
27 	gss_OID public_mech = gssint_get_public_oid(desired_mech);
28 
29 	if (mech->gss_store_cred_into != NULL) {
30 		return mech->gss_store_cred_into(minor_status, mech_cred,
31 						 cred_usage, public_mech,
32 						 overwrite_cred, default_cred,
33 						 cred_store, elements_stored,
34 						 cred_usage_stored);
35 	} else if (cred_store == GSS_C_NO_CRED_STORE) {
36 		return mech->gss_store_cred(minor_status, mech_cred,
37 					    cred_usage, public_mech,
38 					    overwrite_cred, default_cred,
39 					    elements_stored,
40 					    cred_usage_stored);
41 	} else {
42 		return GSS_S_UNAVAILABLE;
43 	}
44 }
45 
46 static OM_uint32
val_store_cred_args(OM_uint32 * minor_status,const gss_cred_id_t input_cred_handle,gss_cred_usage_t cred_usage,const gss_OID desired_mech,OM_uint32 overwrite_cred,OM_uint32 default_cred,gss_const_key_value_set_t cred_store,gss_OID_set * elements_stored,gss_cred_usage_t * cred_usage_stored)47 val_store_cred_args(
48 	OM_uint32 *minor_status,
49 	const gss_cred_id_t input_cred_handle,
50 	gss_cred_usage_t cred_usage,
51 	const gss_OID desired_mech,
52 	OM_uint32 overwrite_cred,
53 	OM_uint32 default_cred,
54 	gss_const_key_value_set_t cred_store,
55 	gss_OID_set *elements_stored,
56 	gss_cred_usage_t *cred_usage_stored)
57 {
58 
59 	/* Initialize outputs. */
60 
61 	if (minor_status != NULL)
62 		*minor_status = 0;
63 
64 	if (elements_stored != NULL)
65 		*elements_stored = GSS_C_NULL_OID_SET;
66 
67 	/* Validate arguments. */
68 
69 	if (minor_status == NULL)
70 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
71 
72 	if (input_cred_handle == GSS_C_NO_CREDENTIAL)
73 		return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CRED);
74 
75 	if (cred_usage != GSS_C_ACCEPT
76 	    && cred_usage != GSS_C_INITIATE
77 	    && cred_usage != GSS_C_BOTH) {
78 	    if (minor_status) {
79 		*minor_status = EINVAL;
80 		map_errcode(minor_status);
81 	    }
82 	    return GSS_S_FAILURE;
83 	}
84 
85 	if (cred_store != NULL && cred_store->count == 0) {
86 		*minor_status = EINVAL;
87 		map_errcode(minor_status);
88 		return GSS_S_FAILURE;
89 	}
90 
91 	return (GSS_S_COMPLETE);
92 }
93 
94 
95 OM_uint32 KRB5_CALLCONV
gss_store_cred(OM_uint32 * minor_status,gss_cred_id_t input_cred_handle,gss_cred_usage_t cred_usage,const gss_OID desired_mech,OM_uint32 overwrite_cred,OM_uint32 default_cred,gss_OID_set * elements_stored,gss_cred_usage_t * cred_usage_stored)96 gss_store_cred(OM_uint32 *minor_status, gss_cred_id_t input_cred_handle,
97 	       gss_cred_usage_t cred_usage, const gss_OID desired_mech,
98 	       OM_uint32 overwrite_cred, OM_uint32 default_cred,
99 	       gss_OID_set *elements_stored, gss_cred_usage_t *cred_usage_stored)
100 {
101 	return gss_store_cred_into(minor_status, input_cred_handle, cred_usage,
102 				   desired_mech, overwrite_cred, default_cred,
103 				   GSS_C_NO_CRED_STORE, elements_stored,
104 				   cred_usage_stored);
105 }
106 
107 OM_uint32 KRB5_CALLCONV
gss_store_cred_into(OM_uint32 * minor_status,gss_cred_id_t input_cred_handle,gss_cred_usage_t cred_usage,gss_OID desired_mech,OM_uint32 overwrite_cred,OM_uint32 default_cred,gss_const_key_value_set_t cred_store,gss_OID_set * elements_stored,gss_cred_usage_t * cred_usage_stored)108 gss_store_cred_into(OM_uint32 *minor_status, gss_cred_id_t input_cred_handle,
109 		    gss_cred_usage_t cred_usage, gss_OID desired_mech,
110 		    OM_uint32 overwrite_cred, OM_uint32 default_cred,
111 		    gss_const_key_value_set_t cred_store,
112 		    gss_OID_set *elements_stored,
113 		    gss_cred_usage_t *cred_usage_stored)
114 {
115 	OM_uint32		major_status = GSS_S_FAILURE;
116 	gss_union_cred_t	union_cred;
117 	gss_cred_id_t		mech_cred;
118 	gss_mechanism		mech;
119 	gss_OID			dmech;
120 	gss_OID			selected_mech;
121 	int			i;
122 
123 	major_status = val_store_cred_args(minor_status,
124 					   input_cred_handle,
125 					   cred_usage,
126 					   desired_mech,
127 					   overwrite_cred,
128 					   default_cred,
129 					   cred_store,
130 					   elements_stored,
131 					   cred_usage_stored);
132 	if (major_status != GSS_S_COMPLETE)
133 		return (major_status);
134 
135 	/* Initial value needed below. */
136 	major_status = GSS_S_FAILURE;
137 
138 	if (cred_usage_stored != NULL)
139 		*cred_usage_stored = GSS_C_BOTH; /* there's no GSS_C_NEITHER */
140 
141 	union_cred = (gss_union_cred_t)input_cred_handle;
142 
143 	/* desired_mech != GSS_C_NULL_OID -> store one element */
144 	if (desired_mech != GSS_C_NULL_OID) {
145 		major_status = gssint_select_mech_type(minor_status,
146 						       desired_mech,
147 						       &selected_mech);
148 		if (major_status != GSS_S_COMPLETE)
149 			return (major_status);
150 
151 		mech = gssint_get_mechanism(selected_mech);
152 		if (mech == NULL)
153 			return (GSS_S_BAD_MECH);
154 
155 		if (mech->gss_store_cred_into == NULL &&
156 		    cred_store != GSS_C_NO_CRED_STORE)
157 			return (major_status);
158 
159 		if (mech->gss_store_cred == NULL &&
160 		    mech->gss_store_cred_into == NULL)
161 			return (major_status);
162 
163 		mech_cred = gssint_get_mechanism_cred(union_cred, selected_mech);
164 		if (mech_cred == GSS_C_NO_CREDENTIAL)
165 			return (GSS_S_NO_CRED);
166 
167 		major_status = store_cred_fallback(minor_status, mech,
168 						   mech_cred, cred_usage,
169 						   selected_mech,
170 						   overwrite_cred,
171 						   default_cred, cred_store,
172 						   elements_stored,
173 						   cred_usage_stored);
174 		if (major_status != GSS_S_COMPLETE)
175 		    map_error(minor_status, mech);
176 		return major_status;
177 	}
178 
179 	/* desired_mech == GSS_C_NULL_OID -> store all elements */
180 
181 	*minor_status = 0;
182 
183 	for (i = 0; i < union_cred->count; i++) {
184 		/* Get mech and cred element */
185 		dmech = &union_cred->mechs_array[i];
186 		mech = gssint_get_mechanism(dmech);
187 		if (mech == NULL)
188 			continue;
189 
190 		if (mech->gss_store_cred_into == NULL &&
191 		    cred_store != GSS_C_NO_CRED_STORE)
192 			continue;
193 
194 		if (mech->gss_store_cred == NULL &&
195 		    mech->gss_store_cred_into == NULL)
196 			continue;
197 
198 		mech_cred = gssint_get_mechanism_cred(union_cred, dmech);
199 		if (mech_cred == GSS_C_NO_CREDENTIAL)
200 			continue; /* can't happen, but safe to ignore */
201 
202 		major_status = store_cred_fallback(minor_status, mech,
203 						   mech_cred, cred_usage,
204 						   dmech, overwrite_cred,
205 						   default_cred, cred_store,
206 						   NULL, cred_usage_stored);
207 		if (major_status != GSS_S_COMPLETE) {
208 		    map_error(minor_status, mech);
209 		    continue;
210 		}
211 
212 		/* Succeeded for at least one mech */
213 
214 		if (elements_stored == NULL)
215 			continue;
216 
217 		if (*elements_stored == GSS_C_NULL_OID_SET) {
218 			major_status = gss_create_empty_oid_set(minor_status,
219 						elements_stored);
220 
221 			if (GSS_ERROR(major_status))
222 				return (major_status);
223 		}
224 
225 		major_status = gss_add_oid_set_member(minor_status, dmech,
226 			elements_stored);
227 
228 		/* The caller should clean up elements_stored */
229 		if (GSS_ERROR(major_status))
230 			return (major_status);
231 	}
232 
233 	/*
234 	 * Success with some mechs may mask failure with others, but
235 	 * that's what elements_stored is for.
236 	 */
237 	return (major_status);
238 }
239