xref: /freebsd/crypto/krb5/src/lib/gssapi/mechglue/g_mechattr.c (revision f1c4c3daccbaf3820f0e2224de53df12fc952fcc)
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