1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/gssapi/mechglue/g_mechattr.c */
3 /*
4 * Copyright (C) 2010 by the Massachusetts Institute of Technology.
5 * All rights reserved.
6 *
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
11 *
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. Furthermore if you modify this software you must label
20 * your software as modified software and not distribute it in such a
21 * fashion that it might be confused with the original M.I.T. software.
22 * M.I.T. makes no representations about the suitability of
23 * this software for any purpose. It is provided "as is" without express
24 * or implied warranty.
25 */
26
27 #include "mglueP.h"
28
29 static int
testMechAttr(gss_const_OID attr,gss_const_OID_set against)30 testMechAttr(gss_const_OID attr,
31 gss_const_OID_set against)
32 {
33 int present = 0;
34 OM_uint32 minor;
35
36 if (GSS_ERROR(generic_gss_test_oid_set_member(&minor, attr,
37 (gss_OID_set)against,
38 &present)))
39 return 0;
40
41 return present;
42 }
43
44 /*
45 * Return TRUE iff all the elements of desired and none of the elements
46 * of except exist in available.
47 */
48 static int
testMechAttrsOffered(gss_const_OID_set desired,gss_const_OID_set except,gss_const_OID_set available)49 testMechAttrsOffered(gss_const_OID_set desired,
50 gss_const_OID_set except,
51 gss_const_OID_set available)
52 {
53 size_t i;
54
55 if (desired != GSS_C_NO_OID_SET) {
56 for (i = 0; i < desired->count; i++) {
57 if (!testMechAttr(&desired->elements[i], available))
58 return 0;
59 }
60 }
61
62 if (except != GSS_C_NO_OID_SET) {
63 for (i = 0; i < except->count; i++) {
64 if (testMechAttr(&except->elements[i], available))
65 return 0;
66 }
67 }
68
69 return 1;
70 }
71
72 /*
73 * Return TRUE iff all the elements of critical exist in known.
74 */
75 static int
testMechAttrsKnown(gss_const_OID_set critical,gss_const_OID_set known)76 testMechAttrsKnown(gss_const_OID_set critical,
77 gss_const_OID_set known)
78 {
79 size_t i;
80
81 if (critical != GSS_C_NO_OID_SET) {
82 for (i = 0; i < critical->count; i++) {
83 if (!testMechAttr(&critical->elements[i], known))
84 return 0;
85 }
86 }
87
88 return 1;
89 }
90
91 OM_uint32 KRB5_CALLCONV
gss_indicate_mechs_by_attrs(OM_uint32 * minor,gss_const_OID_set desired_mech_attrs,gss_const_OID_set except_mech_attrs,gss_const_OID_set critical_mech_attrs,gss_OID_set * mechs)92 gss_indicate_mechs_by_attrs(
93 OM_uint32 *minor,
94 gss_const_OID_set desired_mech_attrs,
95 gss_const_OID_set except_mech_attrs,
96 gss_const_OID_set critical_mech_attrs,
97 gss_OID_set *mechs)
98 {
99 OM_uint32 status, tmpMinor;
100 gss_OID_set allMechs = GSS_C_NO_OID_SET;
101 size_t i;
102
103 if (minor != NULL)
104 *minor = 0;
105
106 if (mechs != NULL)
107 *mechs = GSS_C_NO_OID_SET;
108
109 if (minor == NULL || mechs == NULL)
110 return GSS_S_CALL_INACCESSIBLE_WRITE;
111
112 status = gss_indicate_mechs(minor, &allMechs);
113 if (GSS_ERROR(status))
114 goto cleanup;
115
116 status = generic_gss_create_empty_oid_set(minor, mechs);
117 if (GSS_ERROR(status))
118 goto cleanup;
119
120 for (i = 0; i < allMechs->count; i++) {
121 gss_OID_set supportedAttrs = GSS_C_NO_OID_SET;
122 gss_OID_set knownAttrs = GSS_C_NO_OID_SET;
123
124 status = gss_inquire_attrs_for_mech(minor, &allMechs->elements[i],
125 &supportedAttrs, &knownAttrs);
126 if (GSS_ERROR(status))
127 continue;
128
129 if (testMechAttrsOffered(desired_mech_attrs,
130 except_mech_attrs, supportedAttrs) &&
131 testMechAttrsKnown(critical_mech_attrs, knownAttrs)) {
132 status = gss_add_oid_set_member(minor, &allMechs->elements[i],
133 mechs);
134 if (GSS_ERROR(status)) {
135 gss_release_oid_set(&tmpMinor, &supportedAttrs);
136 gss_release_oid_set(&tmpMinor, &knownAttrs);
137 goto cleanup;
138 }
139 }
140
141 gss_release_oid_set(&tmpMinor, &supportedAttrs);
142 gss_release_oid_set(&tmpMinor, &knownAttrs);
143 }
144
145 *minor = 0;
146 status = GSS_S_COMPLETE;
147
148 cleanup:
149 gss_release_oid_set(&tmpMinor, &allMechs);
150
151 return status;
152 }
153
154 OM_uint32 KRB5_CALLCONV
gss_inquire_attrs_for_mech(OM_uint32 * minor,gss_const_OID mech_oid,gss_OID_set * mech_attrs,gss_OID_set * known_mech_attrs)155 gss_inquire_attrs_for_mech(
156 OM_uint32 *minor,
157 gss_const_OID mech_oid,
158 gss_OID_set *mech_attrs,
159 gss_OID_set *known_mech_attrs)
160 {
161 OM_uint32 status, tmpMinor;
162 gss_OID selected_mech, public_mech;
163 gss_mechanism mech;
164
165 if (minor != NULL)
166 *minor = 0;
167
168 if (mech_attrs != NULL)
169 *mech_attrs = GSS_C_NO_OID_SET;
170
171 if (known_mech_attrs != NULL)
172 *known_mech_attrs = GSS_C_NO_OID_SET;
173
174 if (minor == NULL)
175 return GSS_S_CALL_INACCESSIBLE_WRITE;
176
177 status = gssint_select_mech_type(minor, mech_oid, &selected_mech);
178 if (status != GSS_S_COMPLETE)
179 return status;
180
181 mech = gssint_get_mechanism(selected_mech);
182 if (mech == NULL)
183 return GSS_S_BAD_MECH;
184
185 if (mech->gss_inquire_attrs_for_mech != NULL) {
186 public_mech = gssint_get_public_oid(selected_mech);
187 status = mech->gss_inquire_attrs_for_mech(minor, public_mech,
188 mech_attrs,
189 known_mech_attrs);
190 if (GSS_ERROR(status)) {
191 map_error(minor, mech);
192 return status;
193 }
194 }
195
196 /* Make sure *mech_attrs is a proper OID set, as GSS_C_NO_OID_SET is not
197 * accepted by gss_test_oid_set_member(). */
198 if (mech_attrs != NULL && *mech_attrs == GSS_C_NO_OID_SET) {
199 status = generic_gss_create_empty_oid_set(minor, mech_attrs);
200 if (status != GSS_S_COMPLETE) {
201 if (known_mech_attrs != NULL)
202 gss_release_oid_set(&tmpMinor, known_mech_attrs);
203 return status;
204 }
205 }
206
207 if (known_mech_attrs != NULL && *known_mech_attrs == GSS_C_NO_OID_SET) {
208 if (mech->gss_inquire_attrs_for_mech != NULL) {
209 /* A mech can leave *known_mech_attrs alone as shorthand for
210 * understanding the RFC 5587 attribute set. */
211 status = generic_gss_copy_oid_set(minor,
212 gss_ma_known_attrs,
213 known_mech_attrs);
214 } else {
215 /* The mech does not implement RFC 5587. Indicate that it doesn't
216 * know about any attributes. */
217 status = generic_gss_create_empty_oid_set(minor, known_mech_attrs);
218 }
219 if (GSS_ERROR(status)) {
220 gss_release_oid_set(&tmpMinor, mech_attrs);
221 if (mech_attrs != NULL)
222 *mech_attrs = GSS_C_NO_OID_SET;
223 }
224 }
225
226 return GSS_S_COMPLETE;
227 }
228
229 OM_uint32 KRB5_CALLCONV
gss_display_mech_attr(OM_uint32 * minor,gss_const_OID mech_attr,gss_buffer_t name,gss_buffer_t short_desc,gss_buffer_t long_desc)230 gss_display_mech_attr(
231 OM_uint32 *minor,
232 gss_const_OID mech_attr,
233 gss_buffer_t name,
234 gss_buffer_t short_desc,
235 gss_buffer_t long_desc)
236 {
237 return generic_gss_display_mech_attr(minor, mech_attr,
238 name, short_desc, long_desc);
239 }
240