Rearrange moonshot to have libeap as a subproject
[moonshot.git] / moonshot / mech_eap / util_adshim.c
1 /*
2  * Copyright (c) 2011, JANET(UK)
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * 3. Neither the name of JANET(UK) nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32
33 #include "gssapiP_eap.h"
34 #include "authdata_plugin.h"
35
36 /*
37  * This rubbish is necessary because MIT doesn't provide another way
38  * to access verified AD-KDCIssued elements. We can't verify them
39  * ourselves because they're signed in the ticket session key, which
40  * is destroyed immediately after the AP-REQ is processed.
41  */
42
43 struct radius_ad_context {
44     krb5_data avpdata;
45     krb5_boolean verified;
46 };
47
48 static krb5_data radius_ad_attr = {
49     KV5M_DATA, sizeof("urn:authdata-radius-avp") - 1, "urn:authdata-radius-avp" };
50
51 static krb5_error_code
52 radius_ad_init(krb5_context kcontext GSSEAP_UNUSED,
53                void **plugin_context)
54 {
55     *plugin_context = 0;
56     return 0;
57 }
58
59 static void
60 radius_ad_flags(krb5_context kcontext GSSEAP_UNUSED,
61                 void *plugin_context GSSEAP_UNUSED,
62                 krb5_authdatatype ad_type GSSEAP_UNUSED,
63                 krb5_flags *flags)
64 {
65     *flags = AD_USAGE_KDC_ISSUED | AD_INFORMATIONAL;
66 }
67
68 static void
69 radius_ad_fini(krb5_context kcontext GSSEAP_UNUSED,
70                void *plugin_context GSSEAP_UNUSED)
71 {
72     return;
73 }
74
75 static krb5_error_code
76 radius_ad_request_init(krb5_context kcontext GSSEAP_UNUSED,
77                        struct _krb5_authdata_context *context GSSEAP_UNUSED,
78                        void *plugin_context GSSEAP_UNUSED,
79                        void **request_context)
80 {
81     struct radius_ad_context *ctx;
82
83     ctx = GSSEAP_CALLOC(1, sizeof(*ctx));
84     if (ctx == NULL)
85         return ENOMEM;
86
87     *request_context = ctx;
88
89     return 0;
90 }
91
92 static krb5_error_code
93 radius_ad_export_authdata(krb5_context kcontext,
94                           struct _krb5_authdata_context *context GSSEAP_UNUSED,
95                           void *plugin_context GSSEAP_UNUSED,
96                           void *request_context,
97                           krb5_flags usage GSSEAP_UNUSED,
98                           krb5_authdata ***out_authdata)
99 {
100     struct radius_ad_context *radius_ad = (struct radius_ad_context *)request_context;
101     krb5_authdata *data[2];
102     krb5_authdata datum;
103
104     datum.ad_type = KRB5_AUTHDATA_RADIUS_AVP;
105     datum.length = radius_ad->avpdata.length;
106     datum.contents = (krb5_octet *)radius_ad->avpdata.data;
107
108     data[0] = &datum;
109     data[1] = NULL;
110
111     return krb5_copy_authdata(kcontext, data, out_authdata);
112 }
113
114 static krb5_error_code
115 radius_ad_import_authdata(krb5_context kcontext,
116                           struct _krb5_authdata_context *context GSSEAP_UNUSED,
117                           void *plugin_context GSSEAP_UNUSED,
118                           void *request_context,
119                           krb5_authdata **authdata,
120                           krb5_boolean kdc_issued_flag,
121                           krb5_const_principal issuer GSSEAP_UNUSED)
122 {
123     struct radius_ad_context *radius_ad = (struct radius_ad_context *)request_context;
124
125     krb5_free_data_contents(kcontext, &radius_ad->avpdata);
126     radius_ad->verified = FALSE;
127
128     assert(authdata[0] != NULL);
129
130     radius_ad->avpdata.data = GSSEAP_MALLOC(authdata[0]->length);
131     if (radius_ad->avpdata.data == NULL)
132         return ENOMEM;
133
134     memcpy(radius_ad->avpdata.data, authdata[0]->contents,
135            authdata[0]->length);
136     radius_ad->avpdata.length = authdata[0]->length;
137
138     radius_ad->verified = kdc_issued_flag;
139
140     return 0;
141 }
142
143 static void
144 radius_ad_request_fini(krb5_context kcontext,
145                        struct _krb5_authdata_context *context GSSEAP_UNUSED,
146                        void *plugin_context GSSEAP_UNUSED,
147                        void *request_context)
148 {
149     struct radius_ad_context *radius_ad = (struct radius_ad_context *)request_context;
150
151     if (radius_ad != NULL) {
152         krb5_free_data_contents(kcontext, &radius_ad->avpdata);
153         GSSEAP_FREE(radius_ad);
154     }
155 }
156
157 static krb5_error_code
158 radius_ad_get_attribute(krb5_context kcontext GSSEAP_UNUSED,
159                         struct _krb5_authdata_context *context GSSEAP_UNUSED,
160                         void *plugin_context GSSEAP_UNUSED,
161                         void *request_context,
162                         const krb5_data *attribute,
163                         krb5_boolean *authenticated,
164                         krb5_boolean *complete,
165                         krb5_data *value,
166                         krb5_data *display_value GSSEAP_UNUSED,
167                         int *more)
168 {
169     struct radius_ad_context *radius_ad = (struct radius_ad_context *)request_context;
170
171     if (attribute->length != radius_ad_attr.length ||
172         memcmp(attribute->data, radius_ad_attr.data,
173                radius_ad_attr.length) != 0)
174         return ENOENT;
175
176     if (radius_ad->avpdata.length == 0)
177         return ENOENT;
178
179     *authenticated = radius_ad->verified;
180     *complete = TRUE;
181     *more = 0;
182
183     value->data = GSSEAP_MALLOC(radius_ad->avpdata.length);
184     if (value->data == NULL)
185         return ENOMEM;
186
187     memcpy(value->data, radius_ad->avpdata.data, radius_ad->avpdata.length);
188     value->length = radius_ad->avpdata.length;
189
190     return 0;
191 }
192
193 static krb5_error_code
194 radius_ad_copy(krb5_context kcontext GSSEAP_UNUSED,
195                struct _krb5_authdata_context *context GSSEAP_UNUSED,
196                void *plugin_context GSSEAP_UNUSED,
197                void *request_context,
198                void *dst_plugin_context GSSEAP_UNUSED,
199                void *dst_request_context)
200 {
201     struct radius_ad_context *radius_ad_src =
202         (struct radius_ad_context *)request_context;
203     struct radius_ad_context *radius_ad_dst =
204         (struct radius_ad_context *)dst_request_context;
205
206     radius_ad_dst->avpdata.data = GSSEAP_MALLOC(radius_ad_src->avpdata.length);
207     if (radius_ad_dst->avpdata.data == NULL)
208         return ENOMEM;
209
210     memcpy(radius_ad_dst->avpdata.data, radius_ad_src->avpdata.data,
211            radius_ad_src->avpdata.length);
212     radius_ad_dst->avpdata.length = radius_ad_src->avpdata.length;
213     radius_ad_dst->verified = radius_ad_src->verified;
214
215     return 0;
216 }
217
218 static krb5_authdatatype radius_ad_ad_types[] =
219     { KRB5_AUTHDATA_RADIUS_AVP, 0 };
220
221 krb5plugin_authdata_client_ftable_v0 authdata_client_0 = {
222     "radius_ad",
223     radius_ad_ad_types,
224     radius_ad_init,
225     radius_ad_fini,
226     radius_ad_flags,
227     radius_ad_request_init,
228     radius_ad_request_fini,
229     NULL,
230     radius_ad_get_attribute,
231     NULL,
232     NULL,
233     radius_ad_export_authdata,
234     radius_ad_import_authdata,
235     NULL,
236     NULL,
237     NULL,
238     NULL,
239     NULL,
240     NULL,
241     radius_ad_copy
242 };