xref: /freebsd/crypto/krb5/src/lib/gssapi/mechglue/g_mechattr.c (revision b670c9bafc0e31c7609969bf374b2e80bdc00211)
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
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
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
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
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
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 the mech does not implement RFC 5587, return success with an empty
186      * mech_attrs and known_mech_attrs. */
187     if (mech->gss_inquire_attrs_for_mech == NULL)
188         return GSS_S_COMPLETE;
189 
190     public_mech = gssint_get_public_oid(selected_mech);
191     status = mech->gss_inquire_attrs_for_mech(minor, public_mech, mech_attrs,
192                                               known_mech_attrs);
193     if (GSS_ERROR(status)) {
194         map_error(minor, mech);
195         return status;
196     }
197 
198     if (known_mech_attrs != NULL && *known_mech_attrs == GSS_C_NO_OID_SET) {
199         status = generic_gss_copy_oid_set(minor,
200                                           gss_ma_known_attrs,
201                                           known_mech_attrs);
202         if (GSS_ERROR(status)) {
203             gss_release_oid_set(&tmpMinor, mech_attrs);
204             if (mech_attrs != NULL)
205                 *mech_attrs = GSS_C_NO_OID_SET;
206         }
207     }
208 
209     return GSS_S_COMPLETE;
210 }
211 
212 OM_uint32 KRB5_CALLCONV
213 gss_display_mech_attr(
214     OM_uint32         *minor,
215     gss_const_OID      mech_attr,
216     gss_buffer_t       name,
217     gss_buffer_t       short_desc,
218     gss_buffer_t       long_desc)
219 {
220     return generic_gss_display_mech_attr(minor, mech_attr,
221                                          name, short_desc, long_desc);
222 }
223