Avoid MIT compat API when building with Heimdal
[mech_eap.git] / mech_eap / accept_sec_context.c
index e4f1ef5..b594af0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, JANET(UK)
+ * Copyright (c) 2011, 2013, 2015, JANET(UK)
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -42,7 +42,7 @@ static OM_uint32
 eapGssSmAcceptGssReauth(OM_uint32 *minor,
                         gss_cred_id_t cred,
                         gss_ctx_id_t ctx,
-                        gss_name_t target,
+                        gss_const_name_t target,
                         gss_OID mech,
                         OM_uint32 reqFlags,
                         OM_uint32 timeReq,
@@ -135,7 +135,7 @@ static OM_uint32
 eapGssSmAcceptAcceptorName(OM_uint32 *minor,
                            gss_cred_id_t cred GSSEAP_UNUSED,
                            gss_ctx_id_t ctx,
-                           gss_name_t target GSSEAP_UNUSED,
+                           gss_const_name_t target GSSEAP_UNUSED,
                            gss_OID mech GSSEAP_UNUSED,
                            OM_uint32 reqFlags GSSEAP_UNUSED,
                            OM_uint32 timeReq GSSEAP_UNUSED,
@@ -164,7 +164,7 @@ static OM_uint32
 eapGssSmAcceptVendorInfo(OM_uint32 *minor,
                          gss_cred_id_t cred GSSEAP_UNUSED,
                          gss_ctx_id_t ctx GSSEAP_UNUSED,
-                         gss_name_t target GSSEAP_UNUSED,
+                         gss_const_name_t target GSSEAP_UNUSED,
                          gss_OID mech GSSEAP_UNUSED,
                          OM_uint32 reqFlags GSSEAP_UNUSED,
                          OM_uint32 timeReq GSSEAP_UNUSED,
@@ -190,7 +190,7 @@ static OM_uint32
 eapGssSmAcceptIdentity(OM_uint32 *minor,
                        gss_cred_id_t cred,
                        gss_ctx_id_t ctx,
-                       gss_name_t target GSSEAP_UNUSED,
+                       gss_const_name_t target GSSEAP_UNUSED,
                        gss_OID mech GSSEAP_UNUSED,
                        OM_uint32 reqFlags GSSEAP_UNUSED,
                        OM_uint32 timeReq GSSEAP_UNUSED,
@@ -345,7 +345,7 @@ setAcceptorIdentity(OM_uint32 *minor,
 
     krbPrinc = ctx->acceptorName->krbPrincipal;
     GSSEAP_ASSERT(krbPrinc != NULL);
-    GSSEAP_ASSERT(KRB_PRINC_LENGTH(krbPrinc) >= 2);
+    GSSEAP_ASSERT(KRB_PRINC_LENGTH(krbPrinc) >= 1);
 
     /* Acceptor-Service-Name */
     krbPrincComponentToGssBuffer(krbPrinc, 0, &nameBuf);
@@ -358,41 +358,30 @@ setAcceptorIdentity(OM_uint32 *minor,
         return major;
 
     /* Acceptor-Host-Name */
-    krbPrincComponentToGssBuffer(krbPrinc, 1, &nameBuf);
-
-    major = gssEapRadiusAddAvp(minor, req,
-                               PW_GSS_ACCEPTOR_HOST_NAME,
-                               0,
-                               &nameBuf);
-    if (GSS_ERROR(major))
-        return major;
-
+    if (KRB_PRINC_LENGTH(krbPrinc) >= 2) {
+       krbPrincComponentToGssBuffer(krbPrinc, 1, &nameBuf);
+
+       major = gssEapRadiusAddAvp(minor, req,
+                                  PW_GSS_ACCEPTOR_HOST_NAME,
+                                  0,
+                                  &nameBuf);
+       if (GSS_ERROR(major))
+           return major;
+    }
     if (KRB_PRINC_LENGTH(krbPrinc) > 2) {
         /* Acceptor-Service-Specific */
-        krb5_principal_data ssiPrinc = *krbPrinc;
-        char *ssi;
-
-        KRB_PRINC_LENGTH(&ssiPrinc) -= 2;
-        KRB_PRINC_NAME(&ssiPrinc) += 2;
-
-        *minor = krb5_unparse_name_flags(krbContext, &ssiPrinc,
-                                         KRB5_PRINCIPAL_UNPARSE_NO_REALM, &ssi);
+        *minor = krbPrincUnparseServiceSpecifics(krbContext,
+                                                 krbPrinc, &nameBuf);
         if (*minor != 0)
             return GSS_S_FAILURE;
 
-        nameBuf.value = ssi;
-        nameBuf.length = strlen(ssi);
-
         major = gssEapRadiusAddAvp(minor, req,
                                    PW_GSS_ACCEPTOR_SERVICE_SPECIFICS,
                                    0,
                                    &nameBuf);
-
-        if (GSS_ERROR(major)) {
-            krb5_free_unparsed_name(krbContext, ssi);
+       krbFreeUnparsedName(krbContext, &nameBuf);
+        if (GSS_ERROR(major))
             return major;
-        }
-        krb5_free_unparsed_name(krbContext, ssi);
     }
 
     krbPrincRealmToGssBuffer(krbPrinc, &nameBuf);
@@ -450,6 +439,55 @@ createRadiusHandle(OM_uint32 *minor,
     return GSS_S_COMPLETE;
 }
 
+/**
+ * Choose the correct error for an access reject packet.
+ */
+static OM_uint32
+eapGssAcceptHandleReject(OM_uint32 *minor,
+                        struct rs_packet *response)
+{
+    rs_avp **vps;
+    rs_const_avp *vp = NULL;
+    OM_uint32 major;
+    const char *reply_message = NULL;
+    size_t reply_length = 0;
+
+    rs_packet_avps(response, &vps);
+    major = gssEapRadiusGetRawAvp(minor, *vps,
+                                 PW_REPLY_MESSAGE, 0, &vp);
+    if (!GSS_ERROR(major)) {
+       reply_message = rs_avp_string_value(vp);
+       reply_length = rs_avp_length(vp);
+    }
+
+    major = gssEapRadiusGetRawAvp(minor, *vps,
+                                 PW_ERROR_CAUSE, 0, &vp);
+    if (!GSS_ERROR(major)) {
+       switch (rs_avp_integer_value(vp)) {
+           /* Values from http://www.iana.org/assignments/radius-types/radius-types.xhtml#radius-types-18 */
+       case 502: /* request not routable (proxy) */
+           *minor = GSSEAP_RADIUS_UNROUTABLE;
+           break;
+       case 501: /* administratively prohibited */
+           *minor = GSSEAP_RADIUS_ADMIN_PROHIBIT;
+           break;
+
+       default:
+           *minor = GSSEAP_RADIUS_AUTH_FAILURE;
+           break;
+       }
+    } else
+        *minor = GSSEAP_RADIUS_AUTH_FAILURE;
+
+    if (reply_message != NULL)
+       gssEapSaveStatusInfo(*minor, "%s: %.*s", error_message(*minor),
+                            reply_length, reply_message);
+    else
+        gssEapSaveStatusInfo(*minor, "%s", error_message(*minor));
+
+    return GSS_S_DEFECTIVE_CREDENTIAL;
+}
+
 /*
  * Process a EAP response from the initiator.
  */
@@ -457,7 +495,7 @@ static OM_uint32
 eapGssSmAcceptAuthenticate(OM_uint32 *minor,
                            gss_cred_id_t cred,
                            gss_ctx_id_t ctx,
-                           gss_name_t target GSSEAP_UNUSED,
+                           gss_const_name_t target GSSEAP_UNUSED,
                            gss_OID mech GSSEAP_UNUSED,
                            OM_uint32 reqFlags GSSEAP_UNUSED,
                            OM_uint32 timeReq GSSEAP_UNUSED,
@@ -538,8 +576,7 @@ eapGssSmAcceptAuthenticate(OM_uint32 *minor,
     case PW_ACCESS_ACCEPT:
         break;
     case PW_ACCESS_REJECT:
-        *minor = GSSEAP_RADIUS_AUTH_FAILURE;
-        major = GSS_S_DEFECTIVE_CREDENTIAL;
+       major = eapGssAcceptHandleReject( minor, resp);
         goto cleanup;
         break;
     default:
@@ -603,7 +640,7 @@ static OM_uint32
 eapGssSmAcceptGssFlags(OM_uint32 *minor,
                        gss_cred_id_t cred GSSEAP_UNUSED,
                        gss_ctx_id_t ctx,
-                       gss_name_t target GSSEAP_UNUSED,
+                       gss_const_name_t target GSSEAP_UNUSED,
                        gss_OID mech GSSEAP_UNUSED,
                        OM_uint32 reqFlags GSSEAP_UNUSED,
                        OM_uint32 timeReq GSSEAP_UNUSED,
@@ -637,7 +674,7 @@ static OM_uint32
 eapGssSmAcceptGssChannelBindings(OM_uint32 *minor,
                                  gss_cred_id_t cred GSSEAP_UNUSED,
                                  gss_ctx_id_t ctx,
-                                 gss_name_t target GSSEAP_UNUSED,
+                                 gss_const_name_t target GSSEAP_UNUSED,
                                  gss_OID mech GSSEAP_UNUSED,
                                  OM_uint32 reqFlags GSSEAP_UNUSED,
                                  OM_uint32 timeReq GSSEAP_UNUSED,
@@ -651,6 +688,9 @@ eapGssSmAcceptGssChannelBindings(OM_uint32 *minor,
     krb5_data data;
     krb5_checksum cksum;
     krb5_boolean valid = FALSE;
+#ifdef HAVE_HEIMDAL_VERSION
+    krb5_crypto krbCrypto;
+#endif
 
     if (chanBindings == GSS_C_NO_CHANNEL_BINDINGS ||
         chanBindings->application_data.length == 0)
@@ -664,9 +704,29 @@ eapGssSmAcceptGssChannelBindings(OM_uint32 *minor,
 
     KRB_CHECKSUM_INIT(&cksum, ctx->checksumType, inputToken);
 
+#ifdef HAVE_HEIMDAL_VERSION
+    code = krb5_crypto_init(krbContext, &ctx->rfc3961Key, 0, &krbCrypto);
+    if (code != 0) {
+        *minor = code;
+        return GSS_S_FAILURE;
+    }
+
+    code = krb5_verify_checksum(krbContext, krbCrypto,
+                                KEY_USAGE_GSSEAP_CHBIND_MIC,
+                                data.data, data.length, &cksum);
+    if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY) {
+        code = 0;
+        valid = FALSE;
+    } else if (code == 0) {
+        valid = TRUE;
+    }
+
+    krb5_crypto_destroy(krbContext, krbCrypto);
+#else
     code = krb5_c_verify_checksum(krbContext, &ctx->rfc3961Key,
                                   KEY_USAGE_GSSEAP_CHBIND_MIC,
                                   &data, &cksum, &valid);
+#endif /* HAVE_HEIMDAL_VERSION */
     if (code != 0) {
         *minor = code;
         return GSS_S_FAILURE;
@@ -687,7 +747,7 @@ static OM_uint32
 eapGssSmAcceptInitiatorMIC(OM_uint32 *minor,
                            gss_cred_id_t cred GSSEAP_UNUSED,
                            gss_ctx_id_t ctx,
-                           gss_name_t target GSSEAP_UNUSED,
+                           gss_const_name_t target GSSEAP_UNUSED,
                            gss_OID mech GSSEAP_UNUSED,
                            OM_uint32 reqFlags GSSEAP_UNUSED,
                            OM_uint32 timeReq GSSEAP_UNUSED,
@@ -727,7 +787,7 @@ static OM_uint32
 eapGssSmAcceptReauthCreds(OM_uint32 *minor,
                           gss_cred_id_t cred,
                           gss_ctx_id_t ctx,
-                          gss_name_t target GSSEAP_UNUSED,
+                          gss_const_name_t target GSSEAP_UNUSED,
                           gss_OID mech GSSEAP_UNUSED,
                           OM_uint32 reqFlags GSSEAP_UNUSED,
                           OM_uint32 timeReq GSSEAP_UNUSED,
@@ -756,7 +816,7 @@ static OM_uint32
 eapGssSmAcceptAcceptorMIC(OM_uint32 *minor,
                           gss_cred_id_t cred GSSEAP_UNUSED,
                           gss_ctx_id_t ctx,
-                          gss_name_t target GSSEAP_UNUSED,
+                          gss_const_name_t target GSSEAP_UNUSED,
                           gss_OID mech GSSEAP_UNUSED,
                           OM_uint32 reqFlags GSSEAP_UNUSED,
                           OM_uint32 timeReq GSSEAP_UNUSED,
@@ -985,7 +1045,7 @@ static OM_uint32
 eapGssSmAcceptGssReauth(OM_uint32 *minor,
                         gss_cred_id_t cred,
                         gss_ctx_id_t ctx,
-                        gss_name_t target GSSEAP_UNUSED,
+                        gss_const_name_t target GSSEAP_UNUSED,
                         gss_OID mech,
                         OM_uint32 reqFlags GSSEAP_UNUSED,
                         OM_uint32 timeReq GSSEAP_UNUSED,
@@ -1043,7 +1103,11 @@ eapGssSmAcceptGssReauth(OM_uint32 *minor,
 OM_uint32 GSSAPI_CALLCONV
 gss_accept_sec_context(OM_uint32 *minor,
                        gss_ctx_id_t *context_handle,
+#ifdef HAVE_HEIMDAL_VERSION
+                       gss_const_cred_id_t cred,
+#else
                        gss_cred_id_t cred,
+#endif
                        gss_buffer_t input_token,
                        gss_channel_bindings_t input_chan_bindings,
                        gss_name_t *src_name,
@@ -1081,7 +1145,7 @@ gss_accept_sec_context(OM_uint32 *minor,
 
     major = gssEapAcceptSecContext(minor,
                                    ctx,
-                                   cred,
+                                   (gss_cred_id_t)cred,
                                    input_token,
                                    input_chan_bindings,
                                    src_name,
@@ -1096,5 +1160,7 @@ gss_accept_sec_context(OM_uint32 *minor,
     if (GSS_ERROR(major))
         gssEapReleaseContext(&tmpMinor, context_handle);
 
+    gssEapTraceStatus("gss_accept_sec_context", major, *minor);
+
     return major;
 }