Fixes for Heimdal (macOS) builds from Stefan.
[mech_eap.git] / mech_eap / accept_sec_context.c
1 /*
2  * Copyright (c) 2011, 2013, 2015, 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 /*
34  * Establish a security context on the acceptor (server). These functions
35  * wrap around libradsec and (thus) talk to a RADIUS server or proxy.
36  */
37
38 #include "gssapiP_eap.h"
39
40 #ifdef GSSEAP_ENABLE_REAUTH
41 static OM_uint32
42 eapGssSmAcceptGssReauth(OM_uint32 *minor,
43                         gss_cred_id_t cred,
44                         gss_ctx_id_t ctx,
45                         gss_const_name_t target,
46                         gss_OID mech,
47                         OM_uint32 reqFlags,
48                         OM_uint32 timeReq,
49                         gss_channel_bindings_t chanBindings,
50                         gss_buffer_t inputToken,
51                         gss_buffer_t outputToken,
52                         OM_uint32 *smFlags);
53 #endif
54
55 /*
56  * Mark an acceptor context as ready for cryptographic operations
57  */
58 static OM_uint32
59 acceptReadyEap(OM_uint32 *minor, gss_ctx_id_t ctx, gss_cred_id_t cred)
60 {
61     OM_uint32 major, tmpMinor;
62     rs_const_avp *vp;
63     gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
64
65     /* Cache encryption type derived from selected mechanism OID */
66     major = gssEapOidToEnctype(minor, ctx->mechanismUsed,
67                                &ctx->encryptionType);
68     if (GSS_ERROR(major))
69         return major;
70
71     gssEapReleaseName(&tmpMinor, &ctx->initiatorName);
72
73     major = gssEapRadiusGetRawAvp(minor, ctx->acceptorCtx.vps,
74                                   PW_USER_NAME, 0, &vp);
75     if (major == GSS_S_COMPLETE && rs_avp_length(vp) != 0) {
76         rs_avp_octets_value_byref((rs_avp *)vp,
77                                   (unsigned char **)&nameBuf.value,
78                                   &nameBuf.length);
79     } else {
80         ctx->gssFlags |= GSS_C_ANON_FLAG;
81     }
82
83     major = gssEapImportName(minor, &nameBuf,
84                              (ctx->gssFlags & GSS_C_ANON_FLAG) ?
85                                 GSS_C_NT_ANONYMOUS : GSS_C_NT_USER_NAME,
86                              ctx->mechanismUsed,
87                              &ctx->initiatorName);
88     if (GSS_ERROR(major))
89         return major;
90
91     major = gssEapRadiusGetRawAvp(minor, ctx->acceptorCtx.vps,
92                                   PW_MS_MPPE_SEND_KEY, VENDORPEC_MICROSOFT, &vp);
93     if (GSS_ERROR(major)) {
94         *minor = GSSEAP_KEY_UNAVAILABLE;
95         return GSS_S_UNAVAILABLE;
96     }
97
98     major = gssEapDeriveRfc3961Key(minor,
99                                    rs_avp_octets_value_const_ptr(vp),
100                                    rs_avp_length(vp),
101                                    ctx->encryptionType,
102                                    &ctx->rfc3961Key);
103     if (GSS_ERROR(major))
104         return major;
105
106     major = rfc3961ChecksumTypeForKey(minor, &ctx->rfc3961Key,
107                                        &ctx->checksumType);
108     if (GSS_ERROR(major))
109         return major;
110
111     major = sequenceInit(minor,
112                          &ctx->seqState, ctx->recvSeq,
113                          ((ctx->gssFlags & GSS_C_REPLAY_FLAG) != 0),
114                          ((ctx->gssFlags & GSS_C_SEQUENCE_FLAG) != 0),
115                          TRUE);
116     if (GSS_ERROR(major))
117         return major;
118
119     major = gssEapCreateAttrContext(minor, cred, ctx,
120                                     &ctx->initiatorName->attrCtx,
121                                     &ctx->expiryTime);
122     if (GSS_ERROR(major))
123         return major;
124
125     if (ctx->expiryTime != 0 && ctx->expiryTime < time(NULL)) {
126         *minor = GSSEAP_CRED_EXPIRED;
127         return GSS_S_CREDENTIALS_EXPIRED;
128     }
129
130     *minor = 0;
131     return GSS_S_COMPLETE;
132 }
133
134 static OM_uint32
135 eapGssSmAcceptAcceptorName(OM_uint32 *minor,
136                            gss_cred_id_t cred GSSEAP_UNUSED,
137                            gss_ctx_id_t ctx,
138                            gss_const_name_t target GSSEAP_UNUSED,
139                            gss_OID mech GSSEAP_UNUSED,
140                            OM_uint32 reqFlags GSSEAP_UNUSED,
141                            OM_uint32 timeReq GSSEAP_UNUSED,
142                            gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
143                            gss_buffer_t inputToken GSSEAP_UNUSED,
144                            gss_buffer_t outputToken,
145                            OM_uint32 *smFlags GSSEAP_UNUSED)
146 {
147     OM_uint32 major;
148
149     /* XXX TODO import and validate name from inputToken */
150
151     if (ctx->acceptorName != GSS_C_NO_NAME) {
152         /* Send desired target name to acceptor */
153         major = gssEapDisplayName(minor, ctx->acceptorName,
154                                   outputToken, NULL);
155         if (GSS_ERROR(major))
156             return major;
157     }
158
159     return GSS_S_CONTINUE_NEEDED;
160 }
161
162 #ifdef GSSEAP_DEBUG
163 static OM_uint32
164 eapGssSmAcceptVendorInfo(OM_uint32 *minor,
165                          gss_cred_id_t cred GSSEAP_UNUSED,
166                          gss_ctx_id_t ctx GSSEAP_UNUSED,
167                          gss_const_name_t target GSSEAP_UNUSED,
168                          gss_OID mech GSSEAP_UNUSED,
169                          OM_uint32 reqFlags GSSEAP_UNUSED,
170                          OM_uint32 timeReq GSSEAP_UNUSED,
171                          gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
172                          gss_buffer_t inputToken,
173                          gss_buffer_t outputToken GSSEAP_UNUSED,
174                          OM_uint32 *smFlags GSSEAP_UNUSED)
175 {
176     fprintf(stderr, "GSS-EAP: vendor: %.*s\n",
177             (int)inputToken->length, (char *)inputToken->value);
178
179     *minor = 0;
180     return GSS_S_CONTINUE_NEEDED;
181 }
182 #endif
183
184
185 /*
186  * Emit a identity EAP request to force the initiator (peer) to identify
187  * itself.
188  */
189 static OM_uint32
190 eapGssSmAcceptIdentity(OM_uint32 *minor,
191                        gss_cred_id_t cred,
192                        gss_ctx_id_t ctx,
193                        gss_const_name_t target GSSEAP_UNUSED,
194                        gss_OID mech GSSEAP_UNUSED,
195                        OM_uint32 reqFlags GSSEAP_UNUSED,
196                        OM_uint32 timeReq GSSEAP_UNUSED,
197                        gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
198                        gss_buffer_t inputToken,
199                        gss_buffer_t outputToken,
200                        OM_uint32 *smFlags)
201 {
202     OM_uint32 major;
203     struct wpabuf *reqData;
204     gss_buffer_desc pktBuffer;
205
206     if (!gssEapCredAvailable(cred, ctx->mechanismUsed)) {
207         *minor = GSSEAP_CRED_MECH_MISMATCH;
208         return GSS_S_BAD_MECH;
209     }
210
211     if (inputToken != GSS_C_NO_BUFFER && inputToken->length != 0) {
212         *minor = GSSEAP_WRONG_SIZE;
213         return GSS_S_DEFECTIVE_TOKEN;
214     }
215
216     reqData = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, 0,
217                             EAP_CODE_REQUEST, 0);
218     if (reqData == NULL) {
219         *minor = ENOMEM;
220         return GSS_S_FAILURE;
221     }
222
223     pktBuffer.length = wpabuf_len(reqData);
224     pktBuffer.value = (void *)wpabuf_head(reqData);
225
226     major = duplicateBuffer(minor, &pktBuffer, outputToken);
227     if (GSS_ERROR(major))
228         return major;
229
230     wpabuf_free(reqData);
231
232     GSSEAP_SM_TRANSITION_NEXT(ctx);
233
234     *minor = 0;
235     *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL;
236
237     return GSS_S_CONTINUE_NEEDED;
238 }
239
240 /*
241  * Returns TRUE if the input token contains an EAP identity response.
242  */
243 static int
244 isIdentityResponseP(gss_buffer_t inputToken)
245 {
246     struct wpabuf respData;
247
248     wpabuf_set(&respData, inputToken->value, inputToken->length);
249
250     return (eap_get_type(&respData) == EAP_TYPE_IDENTITY);
251 }
252
253 /*
254  * Save the asserted initiator identity from the EAP identity response.
255  */
256 static OM_uint32
257 importInitiatorIdentity(OM_uint32 *minor,
258                         gss_ctx_id_t ctx,
259                         gss_buffer_t inputToken)
260 {
261     OM_uint32 tmpMinor;
262     struct wpabuf respData;
263     const unsigned char *pos;
264     size_t len;
265     gss_buffer_desc nameBuf;
266
267     wpabuf_set(&respData, inputToken->value, inputToken->length);
268
269     pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY,
270                            &respData, &len);
271     if (pos == NULL) {
272         *minor = GSSEAP_PEER_BAD_MESSAGE;
273         return GSS_S_DEFECTIVE_TOKEN;
274     }
275
276     nameBuf.value = (void *)pos;
277     nameBuf.length = len;
278
279     gssEapReleaseName(&tmpMinor, &ctx->initiatorName);
280
281     return gssEapImportName(minor, &nameBuf, GSS_C_NT_USER_NAME,
282                             ctx->mechanismUsed, &ctx->initiatorName);
283 }
284
285 /*
286  * Pass the asserted initiator identity to the authentication server.
287  */
288 static OM_uint32
289 setInitiatorIdentity(OM_uint32 *minor,
290                      gss_ctx_id_t ctx,
291                      struct rs_packet *req)
292 {
293     OM_uint32 major, tmpMinor;
294     gss_buffer_desc nameBuf;
295
296     /*
297      * We should have got an EAP identity response, but if we didn't, then
298      * we will just avoid sending User-Name. Note that radsecproxy requires
299      * User-Name to be sent on every request (presumably so it can remain
300      * stateless).
301      */
302     if (ctx->initiatorName != GSS_C_NO_NAME) {
303         major = gssEapDisplayName(minor, ctx->initiatorName, &nameBuf, NULL);
304         if (GSS_ERROR(major))
305             return major;
306
307         major = gssEapRadiusAddAvp(minor, req, PW_USER_NAME, 0, &nameBuf);
308         if (GSS_ERROR(major))
309             return major;
310
311         gss_release_buffer(&tmpMinor, &nameBuf);
312     }
313
314     *minor = 0;
315     return GSS_S_COMPLETE;
316 }
317
318 /*
319  * Pass the asserted acceptor identity to the authentication server.
320  */
321 static OM_uint32
322 setAcceptorIdentity(OM_uint32 *minor,
323                     gss_ctx_id_t ctx,
324                     struct rs_packet *req)
325 {
326     OM_uint32 major;
327     gss_buffer_desc nameBuf;
328     krb5_context krbContext = NULL;
329     krb5_principal krbPrinc;
330     struct rs_context *rc = ctx->acceptorCtx.radContext;
331
332     GSSEAP_ASSERT(rc != NULL);
333
334     if (ctx->acceptorName == GSS_C_NO_NAME) {
335         *minor = 0;
336         return GSS_S_COMPLETE;
337     }
338
339     if ((ctx->acceptorName->flags & NAME_FLAG_SERVICE) == 0) {
340         *minor = GSSEAP_BAD_SERVICE_NAME;
341         return GSS_S_BAD_NAME;
342     }
343
344     GSSEAP_KRB_INIT(&krbContext);
345
346     krbPrinc = ctx->acceptorName->krbPrincipal;
347     GSSEAP_ASSERT(krbPrinc != NULL);
348     GSSEAP_ASSERT(KRB_PRINC_LENGTH(krbPrinc) >= 1);
349
350     /* Acceptor-Service-Name */
351     krbPrincComponentToGssBuffer(krbPrinc, 0, &nameBuf);
352
353     major = gssEapRadiusAddAvp(minor, req,
354                                PW_GSS_ACCEPTOR_SERVICE_NAME,
355                                0,
356                                &nameBuf);
357     if (GSS_ERROR(major))
358         return major;
359
360     /* Acceptor-Host-Name */
361     if (KRB_PRINC_LENGTH(krbPrinc) >= 2) {
362         krbPrincComponentToGssBuffer(krbPrinc, 1, &nameBuf);
363
364         major = gssEapRadiusAddAvp(minor, req,
365                                    PW_GSS_ACCEPTOR_HOST_NAME,
366                                    0,
367                                    &nameBuf);
368         if (GSS_ERROR(major))
369             return major;
370     }
371     if (KRB_PRINC_LENGTH(krbPrinc) > 2) {
372         /* Acceptor-Service-Specific */
373         *minor = krbPrincUnparseServiceSpecifics(krbContext,
374                                                  krbPrinc, &nameBuf);
375         if (*minor != 0)
376             return GSS_S_FAILURE;
377
378         major = gssEapRadiusAddAvp(minor, req,
379                                    PW_GSS_ACCEPTOR_SERVICE_SPECIFICS,
380                                    0,
381                                    &nameBuf);
382         krbFreeUnparsedName(krbContext, &nameBuf);
383         if (GSS_ERROR(major))
384             return major;
385     }
386
387     krbPrincRealmToGssBuffer(krbPrinc, &nameBuf);
388     if (nameBuf.length != 0) {
389         /* Acceptor-Realm-Name */
390         major = gssEapRadiusAddAvp(minor, req,
391                                    PW_GSS_ACCEPTOR_REALM_NAME,
392                                    0,
393                                    &nameBuf);
394         if (GSS_ERROR(major))
395             return major;
396     }
397
398     *minor = 0;
399     return GSS_S_COMPLETE;
400 }
401
402 /*
403  * Allocate a RadSec handle
404  */
405 static OM_uint32
406 createRadiusHandle(OM_uint32 *minor,
407                    gss_cred_id_t cred,
408                    gss_ctx_id_t ctx)
409 {
410     struct gss_eap_acceptor_ctx *actx = &ctx->acceptorCtx;
411     struct rs_error *err;
412     const char *configStanza = "gss-eap";
413     OM_uint32 major;
414
415     GSSEAP_ASSERT(actx->radContext == NULL);
416     GSSEAP_ASSERT(actx->radConn == NULL);
417     GSSEAP_ASSERT(cred != GSS_C_NO_CREDENTIAL);
418
419     major = gssEapCreateRadiusContext(minor, cred, &actx->radContext);
420     if (GSS_ERROR(major))
421         return major;
422
423     if (cred->radiusConfigStanza.value != NULL)
424         configStanza = (const char *)cred->radiusConfigStanza.value;
425
426     if (rs_conn_create(actx->radContext, &actx->radConn, configStanza) != 0) {
427         err = rs_err_conn_pop(actx->radConn);
428         return gssEapRadiusMapError(minor, err);
429     }
430
431     if (actx->radServer != NULL) {
432         if (rs_conn_select_peer(actx->radConn, actx->radServer) != 0) {
433             err = rs_err_conn_pop(actx->radConn);
434             return gssEapRadiusMapError(minor, err);
435         }
436     }
437
438     *minor = 0;
439     return GSS_S_COMPLETE;
440 }
441
442 /**
443  * Choose the correct error for an access reject packet.
444  */
445 static OM_uint32
446 eapGssAcceptHandleReject(OM_uint32 *minor,
447                          struct rs_packet *response)
448 {
449     rs_avp **vps;
450     rs_const_avp *vp = NULL;
451     OM_uint32 major;
452     const char *reply_message = NULL;
453     size_t reply_length = 0;
454
455     rs_packet_avps(response, &vps);
456     major = gssEapRadiusGetRawAvp(minor, *vps,
457                                   PW_REPLY_MESSAGE, 0, &vp);
458     if (!GSS_ERROR(major)) {
459         reply_message = rs_avp_string_value(vp);
460         reply_length = rs_avp_length(vp);
461     }
462
463     major = gssEapRadiusGetRawAvp(minor, *vps,
464                                   PW_ERROR_CAUSE, 0, &vp);
465     if (!GSS_ERROR(major)) {
466         switch (rs_avp_integer_value(vp)) {
467             /* Values from http://www.iana.org/assignments/radius-types/radius-types.xhtml#radius-types-18 */
468         case 502: /* request not routable (proxy) */
469             *minor = GSSEAP_RADIUS_UNROUTABLE;
470             break;
471         case 501: /* administratively prohibited */
472             *minor = GSSEAP_RADIUS_ADMIN_PROHIBIT;
473             break;
474
475         default:
476             *minor = GSSEAP_RADIUS_AUTH_FAILURE;
477             break;
478         }
479     } else
480         *minor = GSSEAP_RADIUS_AUTH_FAILURE;
481
482     if (reply_message != NULL)
483         gssEapSaveStatusInfo(*minor, "%s: %.*s", error_message(*minor),
484                              reply_length, reply_message);
485     else
486         gssEapSaveStatusInfo(*minor, "%s", error_message(*minor));
487
488     return GSS_S_DEFECTIVE_CREDENTIAL;
489 }
490
491 /*
492  * Process a EAP response from the initiator.
493  */
494 static OM_uint32
495 eapGssSmAcceptAuthenticate(OM_uint32 *minor,
496                            gss_cred_id_t cred,
497                            gss_ctx_id_t ctx,
498                            gss_const_name_t target GSSEAP_UNUSED,
499                            gss_OID mech GSSEAP_UNUSED,
500                            OM_uint32 reqFlags GSSEAP_UNUSED,
501                            OM_uint32 timeReq GSSEAP_UNUSED,
502                            gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
503                            gss_buffer_t inputToken,
504                            gss_buffer_t outputToken,
505                            OM_uint32 *smFlags)
506 {
507     OM_uint32 major, tmpMinor;
508     struct rs_connection *rconn;
509     struct rs_request *request = NULL;
510     struct rs_packet *req = NULL, *resp = NULL;
511     int isAccessChallenge;
512
513     if (ctx->acceptorCtx.radContext == NULL) {
514         /* May be NULL from an imported partial context */
515         major = createRadiusHandle(minor, cred, ctx);
516         if (GSS_ERROR(major))
517             goto cleanup;
518     }
519
520     if (isIdentityResponseP(inputToken)) {
521         major = importInitiatorIdentity(minor, ctx, inputToken);
522         if (GSS_ERROR(major))
523             return major;
524     }
525
526     rconn = ctx->acceptorCtx.radConn;
527
528     if (rs_packet_create_authn_request(rconn, &req, NULL, NULL) != 0) {
529         major = gssEapRadiusMapError(minor, rs_err_conn_pop(rconn));
530         goto cleanup;
531     }
532
533     major = setInitiatorIdentity(minor, ctx, req);
534     if (GSS_ERROR(major))
535         goto cleanup;
536
537     major = setAcceptorIdentity(minor, ctx, req);
538     if (GSS_ERROR(major))
539         goto cleanup;
540
541     major = gssEapRadiusAddAvp(minor, req,
542                                PW_EAP_MESSAGE, 0, inputToken);
543     if (GSS_ERROR(major))
544         goto cleanup;
545
546     if (ctx->acceptorCtx.state.length != 0) {
547         major = gssEapRadiusAddAvp(minor, req, PW_STATE, 0,
548                                    &ctx->acceptorCtx.state);
549         if (GSS_ERROR(major))
550             goto cleanup;
551
552         gss_release_buffer(&tmpMinor, &ctx->acceptorCtx.state);
553     }
554
555     if (rs_request_create(rconn, &request) != 0) {
556         major = gssEapRadiusMapError(minor, rs_err_conn_pop(rconn));
557         goto cleanup;
558     }
559
560     rs_request_add_reqpkt(request, req);
561     req = NULL;
562
563     if (rs_request_send(request, &resp) != 0) {
564         major = gssEapRadiusMapError(minor, rs_err_conn_pop(rconn));
565         goto cleanup;
566     }
567
568     GSSEAP_ASSERT(resp != NULL);
569
570     isAccessChallenge = 0;
571
572     switch (rs_packet_code(resp)) {
573     case PW_ACCESS_CHALLENGE:
574         isAccessChallenge = 1;
575         break;
576     case PW_ACCESS_ACCEPT:
577         break;
578     case PW_ACCESS_REJECT:
579         major = eapGssAcceptHandleReject( minor, resp);
580         goto cleanup;
581         break;
582     default:
583         *minor = GSSEAP_UNKNOWN_RADIUS_CODE;
584         major = GSS_S_FAILURE;
585         goto cleanup;
586         break;
587     }
588
589     major = gssEapRadiusGetAvp(minor, resp, PW_EAP_MESSAGE, 0,
590                                outputToken, TRUE);
591     if (major == GSS_S_UNAVAILABLE && isAccessChallenge) {
592         *minor = GSSEAP_MISSING_EAP_REQUEST;
593         major = GSS_S_DEFECTIVE_TOKEN;
594         goto cleanup;
595     } else if (GSS_ERROR(major))
596         goto cleanup;
597
598     if (isAccessChallenge) {
599         major = gssEapRadiusGetAvp(minor, resp, PW_STATE, 0,
600                                    &ctx->acceptorCtx.state, TRUE);
601         if (GSS_ERROR(major) && *minor != GSSEAP_NO_SUCH_ATTR)
602             goto cleanup;
603     } else {
604         rs_avp **vps;
605
606         rs_packet_avps(resp, &vps);
607
608         ctx->acceptorCtx.vps = *vps;
609         *vps = NULL;
610
611         major = acceptReadyEap(minor, ctx, cred);
612         if (GSS_ERROR(major))
613             goto cleanup;
614
615         GSSEAP_SM_TRANSITION_NEXT(ctx);
616     }
617
618     major = GSS_S_CONTINUE_NEEDED;
619     *minor = 0;
620     *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL;
621
622 cleanup:
623     if (request != NULL)
624         rs_request_destroy(request);
625     if (req != NULL)
626         rs_packet_destroy(req);
627     if (resp != NULL)
628         rs_packet_destroy(resp);
629     if (GSSEAP_SM_STATE(ctx) == GSSEAP_STATE_INITIATOR_EXTS) {
630         GSSEAP_ASSERT(major == GSS_S_CONTINUE_NEEDED);
631
632         rs_conn_destroy(ctx->acceptorCtx.radConn);
633         ctx->acceptorCtx.radConn = NULL;
634     }
635
636     return major;
637 }
638
639 static OM_uint32
640 eapGssSmAcceptGssFlags(OM_uint32 *minor,
641                        gss_cred_id_t cred GSSEAP_UNUSED,
642                        gss_ctx_id_t ctx,
643                        gss_const_name_t target GSSEAP_UNUSED,
644                        gss_OID mech GSSEAP_UNUSED,
645                        OM_uint32 reqFlags GSSEAP_UNUSED,
646                        OM_uint32 timeReq GSSEAP_UNUSED,
647                        gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
648                        gss_buffer_t inputToken,
649                        gss_buffer_t outputToken GSSEAP_UNUSED,
650                        OM_uint32 *smFlags GSSEAP_UNUSED)
651 {
652     unsigned char *p;
653     OM_uint32 initiatorGssFlags;
654
655     GSSEAP_ASSERT((ctx->flags & CTX_FLAG_KRB_REAUTH) == 0);
656
657     if (inputToken->length < 4) {
658         *minor = GSSEAP_TOK_TRUNC;
659         return GSS_S_DEFECTIVE_TOKEN;
660     }
661
662     /* allow flags to grow for future expansion */
663     p = (unsigned char *)inputToken->value + inputToken->length - 4;
664
665     initiatorGssFlags = load_uint32_be(p);
666     initiatorGssFlags &= GSSEAP_WIRE_FLAGS_MASK;
667
668     ctx->gssFlags |= initiatorGssFlags;
669
670     return GSS_S_CONTINUE_NEEDED;
671 }
672
673 static OM_uint32
674 eapGssSmAcceptGssChannelBindings(OM_uint32 *minor,
675                                  gss_cred_id_t cred GSSEAP_UNUSED,
676                                  gss_ctx_id_t ctx,
677                                  gss_const_name_t target GSSEAP_UNUSED,
678                                  gss_OID mech GSSEAP_UNUSED,
679                                  OM_uint32 reqFlags GSSEAP_UNUSED,
680                                  OM_uint32 timeReq GSSEAP_UNUSED,
681                                  gss_channel_bindings_t chanBindings,
682                                  gss_buffer_t inputToken,
683                                  gss_buffer_t outputToken GSSEAP_UNUSED,
684                                  OM_uint32 *smFlags GSSEAP_UNUSED)
685 {
686     krb5_error_code code;
687     krb5_context krbContext;
688     krb5_data data;
689     krb5_checksum cksum;
690     krb5_boolean valid = FALSE;
691 #ifdef HAVE_HEIMDAL_VERSION
692     krb5_crypto krbCrypto;
693 #endif
694
695     if (chanBindings == GSS_C_NO_CHANNEL_BINDINGS ||
696         chanBindings->application_data.length == 0)
697         return GSS_S_CONTINUE_NEEDED;
698
699     GSSEAP_KRB_INIT(&krbContext);
700
701     KRB_DATA_INIT(&data);
702
703     gssBufferToKrbData(&chanBindings->application_data, &data);
704
705     KRB_CHECKSUM_INIT(&cksum, ctx->checksumType, inputToken);
706
707 #ifdef HAVE_HEIMDAL_VERSION
708     code = krb5_crypto_init(krbContext, &ctx->rfc3961Key, 0, &krbCrypto);
709     if (code != 0) {
710         *minor = code;
711         return GSS_S_FAILURE;
712     }
713
714     code = krb5_verify_checksum(krbContext, krbCrypto,
715                                 KEY_USAGE_GSSEAP_CHBIND_MIC,
716                                 data.data, data.length, &cksum);
717     if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY) {
718         code = 0;
719         valid = FALSE;
720     } else if (code == 0) {
721         valid = TRUE;
722     }
723
724     krb5_crypto_destroy(krbContext, krbCrypto);
725 #else
726     code = krb5_c_verify_checksum(krbContext, &ctx->rfc3961Key,
727                                   KEY_USAGE_GSSEAP_CHBIND_MIC,
728                                   &data, &cksum, &valid);
729 #endif /* HAVE_HEIMDAL_VERSION */
730     if (code != 0) {
731         *minor = code;
732         return GSS_S_FAILURE;
733     }
734
735     if (valid == FALSE) {
736         *minor = GSSEAP_BINDINGS_MISMATCH;
737         return GSS_S_BAD_BINDINGS;
738     }
739
740     ctx->flags |= CTX_FLAG_CHANNEL_BINDINGS_VERIFIED;
741
742     *minor = 0;
743     return GSS_S_CONTINUE_NEEDED;
744 }
745
746 static OM_uint32
747 eapGssSmAcceptInitiatorMIC(OM_uint32 *minor,
748                            gss_cred_id_t cred GSSEAP_UNUSED,
749                            gss_ctx_id_t ctx,
750                            gss_const_name_t target GSSEAP_UNUSED,
751                            gss_OID mech GSSEAP_UNUSED,
752                            OM_uint32 reqFlags GSSEAP_UNUSED,
753                            OM_uint32 timeReq GSSEAP_UNUSED,
754                            gss_channel_bindings_t chanBindings,
755                            gss_buffer_t inputToken,
756                            gss_buffer_t outputToken GSSEAP_UNUSED,
757                            OM_uint32 *smFlags GSSEAP_UNUSED)
758 {
759     OM_uint32 major;
760
761     /*
762      * The channel binding token is optional, however if the caller indicated
763      * bindings we must raise an error if it was absent.
764      *
765      * In the future, we might use a context option to allow the caller to
766      * indicate that missing bindings are acceptable.
767      */
768     if (chanBindings != NULL &&
769         chanBindings->application_data.length != 0 &&
770         (ctx->flags & CTX_FLAG_CHANNEL_BINDINGS_VERIFIED) == 0) {
771         *minor = GSSEAP_MISSING_BINDINGS;
772         return GSS_S_BAD_BINDINGS;
773     }
774
775     major = gssEapVerifyTokenMIC(minor, ctx, inputToken);
776     if (GSS_ERROR(major))
777         return major;
778
779     GSSEAP_SM_TRANSITION_NEXT(ctx);
780
781     *minor = 0;
782     return GSS_S_CONTINUE_NEEDED;
783 }
784
785 #ifdef GSSEAP_ENABLE_REAUTH
786 static OM_uint32
787 eapGssSmAcceptReauthCreds(OM_uint32 *minor,
788                           gss_cred_id_t cred,
789                           gss_ctx_id_t ctx,
790                           gss_const_name_t target GSSEAP_UNUSED,
791                           gss_OID mech GSSEAP_UNUSED,
792                           OM_uint32 reqFlags GSSEAP_UNUSED,
793                           OM_uint32 timeReq GSSEAP_UNUSED,
794                           gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
795                           gss_buffer_t inputToken GSSEAP_UNUSED,
796                           gss_buffer_t outputToken,
797                           OM_uint32 *smFlags GSSEAP_UNUSED)
798 {
799     OM_uint32 major;
800
801     /*
802      * If we're built with fast reauthentication enabled, then
803      * fabricate a ticket from the initiator to ourselves.
804      */
805     major = gssEapMakeReauthCreds(minor, ctx, cred, outputToken);
806     if (major == GSS_S_UNAVAILABLE)
807         major = GSS_S_COMPLETE;
808     if (major == GSS_S_COMPLETE)
809         major = GSS_S_CONTINUE_NEEDED;
810
811     return major;
812 }
813 #endif
814
815 static OM_uint32
816 eapGssSmAcceptAcceptorMIC(OM_uint32 *minor,
817                           gss_cred_id_t cred GSSEAP_UNUSED,
818                           gss_ctx_id_t ctx,
819                           gss_const_name_t target GSSEAP_UNUSED,
820                           gss_OID mech GSSEAP_UNUSED,
821                           OM_uint32 reqFlags GSSEAP_UNUSED,
822                           OM_uint32 timeReq GSSEAP_UNUSED,
823                           gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
824                           gss_buffer_t inputToken GSSEAP_UNUSED,
825                           gss_buffer_t outputToken,
826                           OM_uint32 *smFlags)
827 {
828     OM_uint32 major;
829
830     major = gssEapMakeTokenMIC(minor, ctx, outputToken);
831     if (GSS_ERROR(major))
832         return major;
833
834     GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_ESTABLISHED);
835
836     *minor = 0;
837     *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL;
838
839     return GSS_S_COMPLETE;
840 }
841
842 static struct gss_eap_sm eapGssAcceptorSm[] = {
843     {
844         ITOK_TYPE_ACCEPTOR_NAME_REQ,
845         ITOK_TYPE_ACCEPTOR_NAME_RESP,
846         GSSEAP_STATE_INITIAL,
847         0,
848         eapGssSmAcceptAcceptorName
849     },
850 #ifdef GSSEAP_DEBUG
851     {
852         ITOK_TYPE_VENDOR_INFO,
853         ITOK_TYPE_NONE,
854         GSSEAP_STATE_INITIAL,
855         0,
856         eapGssSmAcceptVendorInfo,
857     },
858 #endif
859 #ifdef GSSEAP_ENABLE_REAUTH
860     {
861         ITOK_TYPE_REAUTH_REQ,
862         ITOK_TYPE_REAUTH_RESP,
863         GSSEAP_STATE_INITIAL,
864         0,
865         eapGssSmAcceptGssReauth,
866     },
867 #endif
868     {
869         ITOK_TYPE_NONE,
870         ITOK_TYPE_EAP_REQ,
871         GSSEAP_STATE_INITIAL,
872         SM_ITOK_FLAG_REQUIRED,
873         eapGssSmAcceptIdentity,
874     },
875     {
876         ITOK_TYPE_EAP_RESP,
877         ITOK_TYPE_EAP_REQ,
878         GSSEAP_STATE_AUTHENTICATE,
879         SM_ITOK_FLAG_REQUIRED,
880         eapGssSmAcceptAuthenticate
881     },
882     {
883         ITOK_TYPE_GSS_FLAGS,
884         ITOK_TYPE_NONE,
885         GSSEAP_STATE_INITIATOR_EXTS,
886         0,
887         eapGssSmAcceptGssFlags
888     },
889     {
890         ITOK_TYPE_GSS_CHANNEL_BINDINGS,
891         ITOK_TYPE_NONE,
892         GSSEAP_STATE_INITIATOR_EXTS,
893         0,
894         eapGssSmAcceptGssChannelBindings,
895     },
896     {
897         ITOK_TYPE_INITIATOR_MIC,
898         ITOK_TYPE_NONE,
899         GSSEAP_STATE_INITIATOR_EXTS,
900         SM_ITOK_FLAG_REQUIRED,
901         eapGssSmAcceptInitiatorMIC,
902     },
903 #ifdef GSSEAP_ENABLE_REAUTH
904     {
905         ITOK_TYPE_NONE,
906         ITOK_TYPE_REAUTH_CREDS,
907         GSSEAP_STATE_ACCEPTOR_EXTS,
908         0,
909         eapGssSmAcceptReauthCreds,
910     },
911 #endif
912     {
913         ITOK_TYPE_NONE,
914         ITOK_TYPE_ACCEPTOR_NAME_RESP,
915         GSSEAP_STATE_ACCEPTOR_EXTS,
916         0,
917         eapGssSmAcceptAcceptorName
918     },
919     {
920         ITOK_TYPE_NONE,
921         ITOK_TYPE_ACCEPTOR_MIC,
922         GSSEAP_STATE_ACCEPTOR_EXTS,
923         0,
924         eapGssSmAcceptAcceptorMIC
925     },
926 };
927
928 OM_uint32
929 gssEapAcceptSecContext(OM_uint32 *minor,
930                        gss_ctx_id_t ctx,
931                        gss_cred_id_t cred,
932                        gss_buffer_t input_token,
933                        gss_channel_bindings_t input_chan_bindings,
934                        gss_name_t *src_name,
935                        gss_OID *mech_type,
936                        gss_buffer_t output_token,
937                        OM_uint32 *ret_flags,
938                        OM_uint32 *time_rec,
939                        gss_cred_id_t *delegated_cred_handle)
940 {
941     OM_uint32 major, tmpMinor;
942
943     if (cred == GSS_C_NO_CREDENTIAL) {
944         if (ctx->cred == GSS_C_NO_CREDENTIAL) {
945             major = gssEapAcquireCred(minor,
946                                       GSS_C_NO_NAME,
947                                       GSS_C_INDEFINITE,
948                                       GSS_C_NO_OID_SET,
949                                       GSS_C_ACCEPT,
950                                       &ctx->cred,
951                                       NULL,
952                                       NULL);
953             if (GSS_ERROR(major))
954                 goto cleanup;
955         }
956
957         cred = ctx->cred;
958     }
959
960     /*
961      * Previously we acquired the credential mutex here, but it should not be
962      * necessary as the acceptor does not access any mutable elements of the
963      * credential handle.
964      */
965
966     if (cred->name != GSS_C_NO_NAME) {
967         major = gssEapDuplicateName(minor, cred->name, &ctx->acceptorName);
968         if (GSS_ERROR(major))
969             goto cleanup;
970     }
971
972     major = gssEapSmStep(minor,
973                          cred,
974                          ctx,
975                          GSS_C_NO_NAME,
976                          GSS_C_NO_OID,
977                          0,
978                          GSS_C_INDEFINITE,
979                          input_chan_bindings,
980                          input_token,
981                          output_token,
982                          eapGssAcceptorSm,
983                          sizeof(eapGssAcceptorSm) / sizeof(eapGssAcceptorSm[0]));
984     if (GSS_ERROR(major))
985         goto cleanup;
986
987     if (mech_type != NULL) {
988         OM_uint32 tmpMajor;
989
990         tmpMajor = gssEapCanonicalizeOid(&tmpMinor, ctx->mechanismUsed, 0, mech_type);
991         if (GSS_ERROR(tmpMajor)) {
992             major = tmpMajor;
993             *minor = tmpMinor;
994             goto cleanup;
995         }
996     }
997     if (ret_flags != NULL)
998         *ret_flags = ctx->gssFlags;
999     if (delegated_cred_handle != NULL)
1000         *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
1001
1002     if (major == GSS_S_COMPLETE) {
1003         if (src_name != NULL && ctx->initiatorName != GSS_C_NO_NAME) {
1004             major = gssEapDuplicateName(&tmpMinor, ctx->initiatorName, src_name);
1005             if (GSS_ERROR(major))
1006                 goto cleanup;
1007         }
1008         if (time_rec != NULL) {
1009             major = gssEapContextTime(&tmpMinor, ctx, time_rec);
1010             if (GSS_ERROR(major))
1011                 goto cleanup;
1012         }
1013     }
1014
1015     GSSEAP_ASSERT(CTX_IS_ESTABLISHED(ctx) || major == GSS_S_CONTINUE_NEEDED);
1016
1017 cleanup:
1018     return major;
1019 }
1020
1021 #ifdef GSSEAP_ENABLE_REAUTH
1022 static OM_uint32
1023 acceptReadyKrb(OM_uint32 *minor,
1024                gss_ctx_id_t ctx,
1025                gss_cred_id_t cred,
1026                const gss_name_t initiator,
1027                const gss_OID mech,
1028                OM_uint32 timeRec)
1029 {
1030     OM_uint32 major;
1031
1032     major = gssEapGlueToMechName(minor, ctx, initiator, &ctx->initiatorName);
1033     if (GSS_ERROR(major))
1034         return major;
1035
1036     major = gssEapReauthComplete(minor, ctx, cred, mech, timeRec);
1037     if (GSS_ERROR(major))
1038         return major;
1039
1040     *minor = 0;
1041     return GSS_S_COMPLETE;
1042 }
1043
1044 static OM_uint32
1045 eapGssSmAcceptGssReauth(OM_uint32 *minor,
1046                         gss_cred_id_t cred,
1047                         gss_ctx_id_t ctx,
1048                         gss_const_name_t target GSSEAP_UNUSED,
1049                         gss_OID mech,
1050                         OM_uint32 reqFlags GSSEAP_UNUSED,
1051                         OM_uint32 timeReq GSSEAP_UNUSED,
1052                         gss_channel_bindings_t chanBindings,
1053                         gss_buffer_t inputToken,
1054                         gss_buffer_t outputToken,
1055                         OM_uint32 *smFlags)
1056 {
1057     OM_uint32 major, tmpMinor;
1058     gss_name_t krbInitiator = GSS_C_NO_NAME;
1059     OM_uint32 gssFlags, timeRec = GSS_C_INDEFINITE;
1060
1061     /*
1062      * If we're built with fast reauthentication support, it's valid
1063      * for an initiator to send a GSS reauthentication token as its
1064      * initial context token, causing us to short-circuit the state
1065      * machine and process Kerberos GSS messages instead.
1066      */
1067
1068     ctx->flags |= CTX_FLAG_KRB_REAUTH;
1069
1070     major = gssAcceptSecContext(minor,
1071                                 &ctx->reauthCtx,
1072                                 cred->reauthCred,
1073                                 inputToken,
1074                                 chanBindings,
1075                                 &krbInitiator,
1076                                 &mech,
1077                                 outputToken,
1078                                 &gssFlags,
1079                                 &timeRec,
1080                                 NULL);
1081     if (major == GSS_S_COMPLETE) {
1082         major = acceptReadyKrb(minor, ctx, cred,
1083                                krbInitiator, mech, timeRec);
1084         if (major == GSS_S_COMPLETE) {
1085             GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_ESTABLISHED);
1086         }
1087         ctx->gssFlags = gssFlags;
1088     } else if (GSS_ERROR(major) &&
1089         (*smFlags & SM_FLAG_INPUT_TOKEN_CRITICAL) == 0) {
1090         /* pretend reauthentication attempt never happened */
1091         gssDeleteSecContext(&tmpMinor, &ctx->reauthCtx, GSS_C_NO_BUFFER);
1092         ctx->flags &= ~(CTX_FLAG_KRB_REAUTH);
1093         GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_INITIAL);
1094         major = GSS_S_CONTINUE_NEEDED;
1095     }
1096
1097     gssReleaseName(&tmpMinor, &krbInitiator);
1098
1099     return major;
1100 }
1101 #endif /* GSSEAP_ENABLE_REAUTH */
1102
1103 OM_uint32 GSSAPI_CALLCONV
1104 gss_accept_sec_context(OM_uint32 *minor,
1105                        gss_ctx_id_t *context_handle,
1106 #ifdef HAVE_HEIMDAL_VERSION
1107                        gss_const_cred_id_t cred,
1108 #else
1109                        gss_cred_id_t cred,
1110 #endif
1111                        gss_buffer_t input_token,
1112                        gss_channel_bindings_t input_chan_bindings,
1113                        gss_name_t *src_name,
1114                        gss_OID *mech_type,
1115                        gss_buffer_t output_token,
1116                        OM_uint32 *ret_flags,
1117                        OM_uint32 *time_rec,
1118                        gss_cred_id_t *delegated_cred_handle)
1119 {
1120     OM_uint32 major, tmpMinor;
1121     gss_ctx_id_t ctx = *context_handle;
1122
1123     *minor = 0;
1124
1125     output_token->length = 0;
1126     output_token->value = NULL;
1127
1128     if (src_name != NULL)
1129         *src_name = GSS_C_NO_NAME;
1130
1131     if (input_token == GSS_C_NO_BUFFER || input_token->length == 0) {
1132         *minor = GSSEAP_TOK_TRUNC;
1133         return GSS_S_DEFECTIVE_TOKEN;
1134     }
1135
1136     if (ctx == GSS_C_NO_CONTEXT) {
1137         major = gssEapAllocContext(minor, &ctx);
1138         if (GSS_ERROR(major))
1139             return major;
1140
1141         *context_handle = ctx;
1142     }
1143
1144     GSSEAP_MUTEX_LOCK(&ctx->mutex);
1145
1146     major = gssEapAcceptSecContext(minor,
1147                                    ctx,
1148                                    (gss_cred_id_t)cred,
1149                                    input_token,
1150                                    input_chan_bindings,
1151                                    src_name,
1152                                    mech_type,
1153                                    output_token,
1154                                    ret_flags,
1155                                    time_rec,
1156                                    delegated_cred_handle);
1157
1158     GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
1159
1160     if (GSS_ERROR(major))
1161         gssEapReleaseContext(&tmpMinor, context_handle);
1162
1163     gssEapTraceStatus("gss_accept_sec_context", major, *minor);
1164
1165     return major;
1166 }