--- /dev/null
+/aclocal.m4
+/autom4te.cache
+/compile
+/config.guess
+/config.log
+/config.status
+/config.sub
+/config.h
+/configure
+/config.h.in
+/depcomp
+
+/libtool
+/ltmain.sh
+/missing
+
+/gsseap_err.[ch]
+/radsec_err.[ch]
+
+.DS_Store
+
+Makefile.in
+Makefile
+
+*.la
+*.lo
+*~
+
+.deps
+.libs
+.a.out.dSYM
+.dSYM
--- /dev/null
+mech_eap was written by Luek Howard <lukeh@padl.com>.
+
--- /dev/null
+Copyright (c) 2010 JANET(UK)
+
+See the LICENSE file for licensing terms.
--- /dev/null
+Note: this license becomes effective upon execution of a contract between
+PADL Software Pty Ltd and JANET(UK) for implementation of the GSS EAP
+mechanism.
+
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
--- /dev/null
+AUTOMAKE_OPTIONS = foreign
+
+gssincludedir = $(includedir)/gssapi
+gssinclude_HEADERS = gssapi_eap.h
+
+gssdir = $(libdir)/gss
+gss_LTLIBRARIES = mech_eap.la
+
+mech_eap_la_CPPFLAGS = -DBUILD_GSSEAP_LIB -DSYSCONFDIR=\"${sysconfdir}\" -DDATAROOTDIR=\"${datarootdir}\"
+mech_eap_la_CFLAGS = -g -Wall -fno-strict-aliasing \
+ @EAP_CFLAGS@ @RADSEC_CFLAGS@ @KRB5_CFLAGS@ @TARGET_CFLAGS@
+mech_eap_la_CXXFLAGS = -g -Wall \
+ @EAP_CFLAGS@ @RADSEC_CFLAGS@ @KRB5_CFLAGS@ \
+ @SHIBSP_CXXFLAGS@ @SHIBRESOLVER_CXXFLAGS@ @TARGET_CFLAGS@
+mech_eap_la_LDFLAGS = -avoid-version -module \
+ -export-symbols mech_eap.exports -no-undefined \
+ @EAP_LDFLAGS@ @RADSEC_LDFLAGS@ @TARGET_LDFLAGS@
+mech_eap_la_LIBADD = @EAP_LIBS@ @RADSEC_LIBS@ @KRB5_LIBS@ @SHIBSP_LIBS@ \
+ @SHIBRESOLVER_LIBS@
+
+mech_eap_la_SOURCES = \
+ accept_sec_context.c \
+ acquire_cred.c \
+ acquire_cred_with_password.c \
+ add_cred.c \
+ add_cred_with_password.c \
+ canonicalize_name.c \
+ compare_name.c \
+ context_time.c \
+ delete_name_attribute.c \
+ delete_sec_context.c \
+ display_name.c \
+ display_name_ext.c \
+ display_status.c \
+ duplicate_name.c \
+ eap_mech.c \
+ export_name.c \
+ export_name_composite.c \
+ export_sec_context.c \
+ get_mic.c \
+ get_name_attribute.c \
+ gsseap_err.c \
+ import_name.c \
+ import_sec_context.c \
+ indicate_mechs.c \
+ init_sec_context.c \
+ inquire_attrs_for_mech.c \
+ inquire_context.c \
+ inquire_cred.c \
+ inquire_cred_by_oid.c \
+ inquire_mech_for_saslname.c \
+ inquire_mechs_for_name.c \
+ inquire_name.c \
+ inquire_names_for_mech.c \
+ inquire_saslname_for_mech.c \
+ inquire_sec_context_by_oid.c \
+ map_name_to_any.c \
+ process_context_token.c \
+ pseudo_random.c \
+ radsec_err.c \
+ release_any_name_mapping.c \
+ release_cred.c \
+ release_name.c \
+ release_oid.c \
+ set_name_attribute.c \
+ set_cred_option.c \
+ set_sec_context_option.c \
+ store_cred.c \
+ unwrap.c \
+ unwrap_iov.c \
+ util_attr.cpp \
+ util_buffer.c \
+ util_context.c \
+ util_cksum.c \
+ util_cred.c \
+ util_crypt.c \
+ util_exts.c \
+ util_krb.c \
+ util_lucid.c \
+ util_mech.c \
+ util_name.c \
+ util_oid.c \
+ util_ordering.c \
+ util_radius.cpp \
+ util_saml.cpp \
+ util_shib.cpp \
+ util_token.c \
+ verify_mic.c \
+ wrap.c \
+ wrap_iov.c \
+ wrap_iov_length.c \
+ wrap_size_limit.c
+
+if GSSEAP_ENABLE_REAUTH
+mech_eap_la_SOURCES += util_reauth.c
+
+krb5pluginsdir = $(libdir)/krb5/plugins/authdata
+krb5plugins_LTLIBRARIES = radius_ad.la
+
+radius_ad_la_CFLAGS = -g -Wall -fno-strict-aliasing \
+ @EAP_CFLAGS@ @KRB5_CFLAGS@ @TARGET_CFLAGS@
+radius_ad_la_LDFLAGS = -avoid-version -module \
+ -export-symbols radius_ad.exports -no-undefined
+radius_ad_la_LIBADD = @KRB5_LIBS@
+radius_ad_la_SOURCES = util_adshim.c
+endif
+
+gsseap_err.h: gsseap_err.et
+ $(prefix)/bin/compile_et $<
+
+gsseap_err.c: gsseap_err.h
+
+radsec_err.h: radsec_err.et
+ $(prefix)/bin/compile_et $<
+
+radsec_err.c: radsec_err.h
+
+clean-generic:
+ rm -f gsseap_err.[ch] radsec_err.[ch]
--- /dev/null
+- gss_xxx routines acquire lock, gssXxx don't
+
--- /dev/null
+Overview
+========
+
+This is an implementation of the GSS EAP mechanism, as described in
+draft-howlett-eap-gss-xx.txt.
+
+Building
+========
+
+In order to build this, a recent Kerberos implementation (MIT or
+Heimdal), Shibboleth, and EAP libraries are required, along with
+all of their dependencies.
+
+Installing
+==========
+
+When installing, be sure to edit $prefix/etc/gss/mech to register
+the EAP mechanisms. A sample configuration file is in this directory.
+
+Make sure your RADIUS library is configured to talk to the server of
+your choice.
+
+Testing
+=======
+
+You can then test the MIT or Cyrus GSS and SASL example programs.
+Sample usage is given below. Substitute <user>, <pass> and <host>
+appropriately (<host> is the name of the host running the server,
+not the RADIUS server).
+
+% gss-client -port 5555 -spnego -mech "{1 3 6 1 4 1 5322 21 1 18}" \
+ -user <user> -pass <pass> <host> host@<host> "Testing GSS EAP"
+% gss-server -port 5555 -export host@<host>
+
+Note: for SASL you will be prompted for a username and password.
+
+% client -C -p 5556 -s host -m EAP-AES128 <host>
+% server -c -p 5556 -s host -h <host>
+
--- /dev/null
+- integration with initiator-side EAP channel bindings
+- integration with final supplicant architecture
+- port to Heimdal
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Establish a security context on the acceptor (server). These functions
+ * wrap around libradsec and (thus) talk to a RADIUS server or proxy.
+ */
+
+#include "gssapiP_eap.h"
+
+#ifdef GSSEAP_ENABLE_REAUTH
+static OM_uint32
+eapGssSmAcceptGssReauth(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ gss_cred_id_t cred,
+ gss_buffer_t inputToken,
+ gss_channel_bindings_t chanBindings,
+ gss_buffer_t outputToken);
+#endif
+
+/*
+ * Mark an acceptor context as ready for cryptographic operations
+ */
+static OM_uint32
+acceptReadyEap(OM_uint32 *minor, gss_ctx_id_t ctx, gss_cred_id_t cred)
+{
+ OM_uint32 major, tmpMinor;
+ VALUE_PAIR *vp;
+ gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
+
+ /* Cache encryption type derived from selected mechanism OID */
+ major = gssEapOidToEnctype(minor, ctx->mechanismUsed,
+ &ctx->encryptionType);
+ if (GSS_ERROR(major))
+ return major;
+
+ gssEapReleaseName(&tmpMinor, &ctx->initiatorName);
+
+ major = gssEapRadiusGetRawAvp(minor, ctx->acceptorCtx.vps,
+ PW_USER_NAME, 0, &vp);
+ if (major == GSS_S_COMPLETE) {
+ nameBuf.length = vp->length;
+ nameBuf.value = vp->vp_strvalue;
+ } else {
+ ctx->gssFlags |= GSS_C_ANON_FLAG;
+ }
+
+ major = gssEapImportName(minor, &nameBuf, GSS_C_NT_USER_NAME,
+ &ctx->initiatorName);
+ if (GSS_ERROR(major))
+ return major;
+
+ major = gssEapRadiusGetRawAvp(minor, ctx->acceptorCtx.vps,
+ PW_MS_MPPE_SEND_KEY, VENDORPEC_MS, &vp);
+ if (GSS_ERROR(major)) {
+ *minor = GSSEAP_KEY_UNAVAILABLE;
+ return GSS_S_UNAVAILABLE;
+ }
+
+ major = gssEapDeriveRfc3961Key(minor,
+ vp->vp_octets,
+ vp->length,
+ ctx->encryptionType,
+ &ctx->rfc3961Key);
+ if (GSS_ERROR(major))
+ return major;
+
+ major = rfc3961ChecksumTypeForKey(minor, &ctx->rfc3961Key,
+ &ctx->checksumType);
+ if (GSS_ERROR(major))
+ return major;
+
+ major = sequenceInit(minor,
+ &ctx->seqState, ctx->recvSeq,
+ ((ctx->gssFlags & GSS_C_REPLAY_FLAG) != 0),
+ ((ctx->gssFlags & GSS_C_SEQUENCE_FLAG) != 0),
+ TRUE);
+ if (GSS_ERROR(major))
+ return major;
+
+ ctx->initiatorName->attrCtx = gssEapCreateAttrContext(cred, ctx);
+
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
+
+/*
+ * Emit a identity EAP request to force the initiator (peer) to identify
+ * itself.
+ */
+static OM_uint32
+eapGssSmAcceptIdentity(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ gss_cred_id_t cred,
+ gss_buffer_t inputToken,
+ gss_channel_bindings_t chanBindings,
+ gss_buffer_t outputToken)
+{
+ OM_uint32 major;
+ union {
+ struct eap_hdr pdu;
+ unsigned char data[5];
+ } pkt;
+ gss_buffer_desc pktBuffer;
+
+ if (inputToken != GSS_C_NO_BUFFER && inputToken->length != 0) {
+ *minor = GSSEAP_WRONG_SIZE;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ assert(ctx->acceptorName == GSS_C_NO_NAME);
+
+ if (cred != GSS_C_NO_CREDENTIAL && cred->name != GSS_C_NO_NAME) {
+ major = gssEapDuplicateName(minor, cred->name, &ctx->acceptorName);
+ if (GSS_ERROR(major))
+ return major;
+ }
+
+ pkt.pdu.code = EAP_CODE_REQUEST;
+ pkt.pdu.identifier = 0;
+ pkt.pdu.length = htons(sizeof(pkt.data));
+ pkt.data[4] = EAP_TYPE_IDENTITY;
+
+ pktBuffer.length = sizeof(pkt.data);
+ pktBuffer.value = pkt.data;
+
+ major = duplicateBuffer(minor, &pktBuffer, outputToken);
+ if (GSS_ERROR(major))
+ return major;
+
+ ctx->state = EAP_STATE_AUTHENTICATE;
+
+ *minor = 0;
+ return GSS_S_CONTINUE_NEEDED;
+}
+
+/*
+ * Pass the asserted acceptor identity to the authentication server.
+ */
+static OM_uint32
+setAcceptorIdentity(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ VALUE_PAIR **vps)
+{
+ OM_uint32 major;
+ gss_buffer_desc nameBuf;
+ krb5_context krbContext = NULL;
+ krb5_principal krbPrinc;
+ struct rs_context *rc = ctx->acceptorCtx.radContext;
+
+ assert(rc != NULL);
+
+ if (ctx->acceptorName == GSS_C_NO_NAME) {
+ *minor = 0;
+ return GSS_S_COMPLETE;
+ }
+
+ if ((ctx->acceptorName->flags & NAME_FLAG_SERVICE) == 0) {
+ *minor = GSSEAP_BAD_SERVICE_NAME;
+ return GSS_S_BAD_NAME;
+ }
+
+ GSSEAP_KRB_INIT(&krbContext);
+
+ krbPrinc = ctx->acceptorName->krbPrincipal;
+ assert(krbPrinc != NULL);
+ assert(krb5_princ_size(krbContext, krbPrinc) >= 2);
+
+ /* Acceptor-Service-Name */
+ krbDataToGssBuffer(krb5_princ_component(krbContext, krbPrinc, 0), &nameBuf);
+
+ major = gssEapRadiusAddAvp(minor, vps,
+ PW_GSS_ACCEPTOR_SERVICE_NAME,
+ VENDORPEC_UKERNA,
+ &nameBuf);
+ if (GSS_ERROR(major))
+ return major;
+
+ /* Acceptor-Host-Name */
+ krbDataToGssBuffer(krb5_princ_component(krbContext, krbPrinc, 1), &nameBuf);
+
+ major = gssEapRadiusAddAvp(minor, vps,
+ PW_GSS_ACCEPTOR_HOST_NAME,
+ VENDORPEC_UKERNA,
+ &nameBuf);
+ if (GSS_ERROR(major))
+ return major;
+
+ if (krb5_princ_size(krbContext, krbPrinc) > 2) {
+ /* Acceptor-Service-Specific */
+ krb5_principal_data ssiPrinc = *krbPrinc;
+ char *ssi;
+
+ krb5_princ_size(krbContext, &ssiPrinc) -= 2;
+ krb5_princ_name(krbContext, &ssiPrinc) += 2;
+
+ *minor = krb5_unparse_name_flags(krbContext, &ssiPrinc,
+ KRB5_PRINCIPAL_UNPARSE_NO_REALM, &ssi);
+ if (*minor != 0)
+ return GSS_S_FAILURE;
+
+ nameBuf.value = ssi;
+ nameBuf.length = strlen(ssi);
+
+ major = gssEapRadiusAddAvp(minor, vps,
+ PW_GSS_ACCEPTOR_SERVICE_SPECIFIC,
+ VENDORPEC_UKERNA,
+ &nameBuf);
+
+ if (GSS_ERROR(major)) {
+ krb5_free_unparsed_name(krbContext, ssi);
+ return major;
+ }
+ krb5_free_unparsed_name(krbContext, ssi);
+ }
+
+ krbDataToGssBuffer(krb5_princ_realm(krbContext, krbPrinc), &nameBuf);
+ if (nameBuf.length != 0) {
+ /* Acceptor-Realm-Name */
+ major = gssEapRadiusAddAvp(minor, vps,
+ PW_GSS_ACCEPTOR_REALM_NAME,
+ VENDORPEC_UKERNA,
+ &nameBuf);
+ if (GSS_ERROR(major))
+ return major;
+ }
+
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
+
+/*
+ * Allocate a RadSec handle
+ */
+static OM_uint32
+createRadiusHandle(OM_uint32 *minor,
+ gss_cred_id_t cred,
+ gss_ctx_id_t ctx)
+{
+ struct gss_eap_acceptor_ctx *actx = &ctx->acceptorCtx;
+ const char *configFile = RS_CONFIG_FILE;
+ const char *configStanza = "gss-eap";
+ struct rs_alloc_scheme ralloc;
+ struct rs_error *err;
+
+ assert(actx->radContext == NULL);
+ assert(actx->radConn == NULL);
+
+ if (rs_context_create(&actx->radContext, RS_DICT_FILE) != 0) {
+ *minor = GSSEAP_RADSEC_CONTEXT_FAILURE;
+ return GSS_S_FAILURE;
+ }
+
+ if (cred != GSS_C_NO_CREDENTIAL) {
+ if (cred->radiusConfigFile != NULL)
+ configFile = cred->radiusConfigFile;
+ if (cred->radiusConfigStanza != NULL)
+ configStanza = cred->radiusConfigStanza;
+ }
+
+ ralloc.calloc = GSSEAP_CALLOC;
+ ralloc.malloc = GSSEAP_MALLOC;
+ ralloc.free = GSSEAP_FREE;
+ ralloc.realloc = GSSEAP_REALLOC;
+
+ rs_context_set_alloc_scheme(actx->radContext, &ralloc);
+
+ if (rs_context_read_config(actx->radContext, configFile) != 0) {
+ err = rs_err_ctx_pop(actx->radContext);
+ goto fail;
+ }
+
+ if (rs_conn_create(actx->radContext, &actx->radConn, configStanza) != 0) {
+ err = rs_err_conn_pop(actx->radConn);
+ goto fail;
+ }
+
+ /* XXX TODO rs_conn_select_server does not exist yet */
+#if 0
+ if (actx->radServer != NULL) {
+ if (rs_conn_select_server(actx->radConn, actx->radServer) != 0) {
+ err = rs_err_conn_pop(actx->radConn);
+ goto fail;
+ }
+ }
+#endif
+
+ *minor = 0;
+ return GSS_S_COMPLETE;
+
+fail:
+ return gssEapRadiusMapError(minor, err);
+}
+
+/*
+ * Process a EAP response from the initiator.
+ */
+static OM_uint32
+eapGssSmAcceptAuthenticate(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ gss_cred_id_t cred,
+ gss_buffer_t inputToken,
+ gss_channel_bindings_t chanBindings,
+ gss_buffer_t outputToken)
+{
+ OM_uint32 major, tmpMinor;
+ struct rs_connection *rconn;
+ struct rs_request *request = NULL;
+ struct rs_packet *req = NULL, *resp = NULL;
+ struct radius_packet *frreq, *frresp;
+ int sendAcceptorIdentity = 0;
+
+ if (ctx->acceptorCtx.radContext == NULL) {
+ /* May be NULL from an imported partial context */
+ major = createRadiusHandle(minor, cred, ctx);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ sendAcceptorIdentity = 1;
+ }
+
+ rconn = ctx->acceptorCtx.radConn;
+
+ if (rs_packet_create_acc_request(rconn, &req, NULL, NULL) != 0) {
+ major = gssEapRadiusMapError(minor, rs_err_conn_pop(rconn));
+ goto cleanup;
+ }
+ frreq = rs_packet_frpkt(req);
+
+ if (sendAcceptorIdentity) {
+ major = setAcceptorIdentity(minor, ctx, &frreq->vps);
+ if (GSS_ERROR(major))
+ goto cleanup;
+ }
+
+ major = gssEapRadiusAddAvp(minor, &frreq->vps,
+ PW_EAP_MESSAGE, 0, inputToken);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ if (ctx->acceptorCtx.state.length != 0) {
+ major = gssEapRadiusAddAvp(minor, &frreq->vps, PW_STATE, 0,
+ &ctx->acceptorCtx.state);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ gss_release_buffer(&tmpMinor, &ctx->acceptorCtx.state);
+ }
+
+ if (rs_request_create(rconn, &request) != 0 ||
+ rs_request_send(request, req, &resp) != 0) {
+ major = gssEapRadiusMapError(minor, rs_err_conn_pop(rconn));
+ goto cleanup;
+ }
+
+ assert(resp != NULL);
+
+ frresp = rs_packet_frpkt(resp);
+ switch (frresp->code) {
+ case PW_AUTHENTICATION_ACK:
+ case PW_ACCESS_CHALLENGE:
+ major = GSS_S_CONTINUE_NEEDED;
+ break;
+ case PW_AUTHENTICATION_REJECT:
+ *minor = GSSEAP_RADIUS_AUTH_FAILURE;
+ major = GSS_S_DEFECTIVE_CREDENTIAL;
+ goto cleanup;
+ break;
+ default:
+ *minor = GSSEAP_UNKNOWN_RADIUS_CODE;
+ major = GSS_S_FAILURE;
+ goto cleanup;
+ break;
+ }
+
+ major = gssEapRadiusGetAvp(minor, frresp->vps, PW_EAP_MESSAGE, 0,
+ outputToken, TRUE);
+ if (major == GSS_S_UNAVAILABLE && frresp->code == PW_ACCESS_CHALLENGE) {
+ *minor = GSSEAP_MISSING_EAP_REQUEST;
+ major = GSS_S_DEFECTIVE_TOKEN;
+ goto cleanup;
+ } else if (GSS_ERROR(major))
+ goto cleanup;
+
+ if (frresp->code == PW_ACCESS_CHALLENGE) {
+ major = gssEapRadiusGetAvp(minor, frresp->vps, PW_STATE, 0,
+ &ctx->acceptorCtx.state, TRUE);
+ if (GSS_ERROR(major) && *minor != GSSEAP_NO_SUCH_ATTR)
+ goto cleanup;
+ } else {
+ ctx->acceptorCtx.vps = frresp->vps;
+ frresp->vps = NULL;
+
+ rs_conn_destroy(ctx->acceptorCtx.radConn);
+ ctx->acceptorCtx.radConn = NULL;
+
+ major = acceptReadyEap(minor, ctx, cred);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ ctx->state = EAP_STATE_EXTENSIONS_REQ;
+ }
+
+ *minor = 0;
+ major = GSS_S_CONTINUE_NEEDED;
+
+cleanup:
+ rs_request_destroy(request);
+
+ return major;
+}
+
+static OM_uint32
+eapGssSmAcceptExtensionsReq(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ gss_cred_id_t cred,
+ gss_buffer_t inputToken,
+ gss_channel_bindings_t chanBindings,
+ gss_buffer_t outputToken)
+{
+ OM_uint32 major;
+
+ major = gssEapVerifyExtensions(minor, cred, ctx, chanBindings, inputToken);
+ if (GSS_ERROR(major))
+ return major;
+
+ outputToken->length = 0;
+ outputToken->value = NULL;
+
+ ctx->state = EAP_STATE_EXTENSIONS_RESP;
+
+ *minor = 0;
+ return GSS_S_CONTINUE_NEEDED;
+}
+
+static OM_uint32
+eapGssSmAcceptExtensionsResp(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ gss_cred_id_t cred,
+ gss_buffer_t inputToken,
+ gss_channel_bindings_t chanBindings,
+ gss_buffer_t outputToken)
+{
+ OM_uint32 major;
+
+ major = gssEapMakeExtensions(minor, cred, ctx, chanBindings, outputToken);
+ if (GSS_ERROR(major))
+ return major;
+
+ ctx->state = EAP_STATE_ESTABLISHED;
+
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+eapGssSmAcceptEstablished(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ gss_cred_id_t cred,
+ gss_buffer_t inputToken,
+ gss_channel_bindings_t chanBindings,
+ gss_buffer_t outputToken)
+{
+ /* Called with already established context */
+ *minor = GSSEAP_CONTEXT_ESTABLISHED;
+ return GSS_S_BAD_STATUS;
+}
+
+static OM_uint32
+makeErrorToken(OM_uint32 *minor,
+ OM_uint32 majorStatus,
+ OM_uint32 minorStatus,
+ gss_buffer_t outputToken)
+{
+ unsigned char errorData[8];
+ gss_buffer_desc errorBuffer;
+
+ assert(GSS_ERROR(majorStatus));
+
+ /*
+ * Only return error codes that the initiator could have caused,
+ * to avoid information leakage.
+ */
+ switch (minorStatus) {
+ case GSSEAP_WRONG_SIZE:
+ case GSSEAP_WRONG_MECH:
+ case GSSEAP_BAD_TOK_HEADER:
+ case GSSEAP_TOK_TRUNC:
+ case GSSEAP_BAD_DIRECTION:
+ case GSSEAP_WRONG_TOK_ID:
+ case GSSEAP_CRIT_EXT_UNAVAILABLE:
+ case GSSEAP_MISSING_REQUIRED_EXT:
+ case GSSEAP_KEY_UNAVAILABLE:
+ case GSSEAP_KEY_TOO_SHORT:
+ case GSSEAP_RADIUS_AUTH_FAILURE:
+ case GSSEAP_UNKNOWN_RADIUS_CODE:
+ case GSSEAP_MISSING_EAP_REQUEST:
+ break;
+ default:
+ if (IS_RADIUS_ERROR(minorStatus))
+ /* Squash RADIUS error codes */
+ minorStatus = GSSEAP_GENERIC_RADIUS_ERROR;
+ else
+ /* Don't return system error codes */
+ return GSS_S_COMPLETE;
+ }
+
+ minorStatus -= ERROR_TABLE_BASE_eapg;
+
+ store_uint32_be(majorStatus, &errorData[0]);
+ store_uint32_be(minorStatus, &errorData[4]);
+
+ errorBuffer.length = sizeof(errorData);
+ errorBuffer.value = errorData;
+
+ return duplicateBuffer(minor, &errorBuffer, outputToken);
+}
+
+static struct gss_eap_acceptor_sm {
+ enum gss_eap_token_type inputTokenType;
+ enum gss_eap_token_type outputTokenType;
+ OM_uint32 (*processToken)(OM_uint32 *,
+ gss_ctx_id_t,
+ gss_cred_id_t,
+ gss_buffer_t,
+ gss_channel_bindings_t,
+ gss_buffer_t);
+} eapGssAcceptorSm[] = {
+ { TOK_TYPE_EAP_RESP, TOK_TYPE_EAP_REQ, eapGssSmAcceptIdentity },
+ { TOK_TYPE_EAP_RESP, TOK_TYPE_EAP_REQ, eapGssSmAcceptAuthenticate },
+ { TOK_TYPE_EXT_REQ, TOK_TYPE_NONE, eapGssSmAcceptExtensionsReq },
+ { TOK_TYPE_NONE, TOK_TYPE_EXT_RESP, eapGssSmAcceptExtensionsResp },
+ { TOK_TYPE_NONE, TOK_TYPE_NONE, eapGssSmAcceptEstablished },
+ { TOK_TYPE_NONE, TOK_TYPE_CONTEXT_ERR, NULL },
+#ifdef GSSEAP_ENABLE_REAUTH
+ { TOK_TYPE_GSS_REAUTH, TOK_TYPE_GSS_REAUTH, eapGssSmAcceptGssReauth },
+#endif
+};
+
+OM_uint32
+gss_accept_sec_context(OM_uint32 *minor,
+ gss_ctx_id_t *context_handle,
+ gss_cred_id_t cred,
+ gss_buffer_t input_token,
+ gss_channel_bindings_t input_chan_bindings,
+ gss_name_t *src_name,
+ gss_OID *mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 *ret_flags,
+ OM_uint32 *time_rec,
+ gss_cred_id_t *delegated_cred_handle)
+{
+ OM_uint32 major;
+ OM_uint32 tmpMajor, tmpMinor;
+ gss_ctx_id_t ctx = *context_handle;
+ struct gss_eap_acceptor_sm *sm = NULL;
+ gss_buffer_desc innerInputToken = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc innerOutputToken = GSS_C_EMPTY_BUFFER;
+ enum gss_eap_token_type tokType;
+ int initialContextToken = 0;
+
+ *minor = 0;
+
+ output_token->length = 0;
+ output_token->value = NULL;
+
+ if (input_token == GSS_C_NO_BUFFER || input_token->length == 0) {
+ *minor = GSSEAP_TOK_TRUNC;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ if (ctx == GSS_C_NO_CONTEXT) {
+ major = gssEapAllocContext(minor, &ctx);
+ if (GSS_ERROR(major))
+ return major;
+
+ initialContextToken = 1;
+ *context_handle = ctx;
+ }
+
+ GSSEAP_MUTEX_LOCK(&ctx->mutex);
+
+ /* Validate and lock credentials */
+ if (cred != GSS_C_NO_CREDENTIAL) {
+ GSSEAP_MUTEX_LOCK(&cred->mutex);
+
+ if ((cred->flags & CRED_FLAG_ACCEPT) == 0) {
+ *minor = GSSEAP_CRED_USAGE_MISMATCH;
+ major = GSS_S_NO_CRED;
+ goto cleanup;
+ }
+ }
+
+ sm = &eapGssAcceptorSm[ctx->state];
+
+ major = gssEapVerifyToken(minor, ctx, input_token,
+ &tokType, &innerInputToken);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ if (!gssEapCredAvailable(cred, ctx->mechanismUsed)) {
+ *minor = GSSEAP_CRED_MECH_MISMATCH;
+ major = GSS_S_BAD_MECH;
+ goto cleanup;
+ }
+
+#ifdef GSSEAP_ENABLE_REAUTH
+ /*
+ * If we're built with fast reauthentication support, it's valid
+ * for an initiator to send a GSS reauthentication token as its
+ * initial context token, causing us to short-circuit the state
+ * machine and process Kerberos GSS messages instead.
+ */
+ if (tokType == TOK_TYPE_GSS_REAUTH && initialContextToken) {
+ ctx->state = EAP_STATE_KRB_REAUTH_GSS;
+ } else
+#endif
+ if (tokType != sm->inputTokenType) {
+ *minor = GSSEAP_WRONG_TOK_ID;
+ major = GSS_S_DEFECTIVE_TOKEN;
+ goto cleanup;
+ }
+
+ do {
+ sm = &eapGssAcceptorSm[ctx->state];
+
+ major = (sm->processToken)(minor,
+ ctx,
+ cred,
+ &innerInputToken,
+ input_chan_bindings,
+ &innerOutputToken);
+ if (GSS_ERROR(major)) {
+ /* Possibly generate an error token */
+ tmpMajor = makeErrorToken(&tmpMinor, major, *minor, &innerOutputToken);
+ if (GSS_ERROR(tmpMajor)) {
+ major = tmpMajor;
+ goto cleanup;
+ }
+
+ sm = &eapGssAcceptorSm[EAP_STATE_ERROR];
+ goto send_token;
+ }
+ } while (major == GSS_S_CONTINUE_NEEDED && innerOutputToken.length == 0);
+
+ if (mech_type != NULL) {
+ if (!gssEapInternalizeOid(ctx->mechanismUsed, mech_type))
+ duplicateOid(&tmpMinor, ctx->mechanismUsed, mech_type);
+ }
+ if (ret_flags != NULL)
+ *ret_flags = ctx->gssFlags;
+ if (delegated_cred_handle != NULL)
+ *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
+
+ if (major == GSS_S_COMPLETE) {
+ if (src_name != NULL && ctx->initiatorName != GSS_C_NO_NAME) {
+ major = gssEapDuplicateName(&tmpMinor, ctx->initiatorName, src_name);
+ if (GSS_ERROR(major))
+ goto cleanup;
+ }
+ if (time_rec != NULL) {
+ major = gssEapContextTime(&tmpMinor, ctx, time_rec);
+ if (GSS_ERROR(major))
+ goto cleanup;
+ }
+ }
+
+ assert(ctx->state == EAP_STATE_ESTABLISHED || major == GSS_S_CONTINUE_NEEDED);
+
+send_token:
+ if (innerOutputToken.value != NULL) {
+ tmpMajor = gssEapMakeToken(&tmpMinor, ctx, &innerOutputToken,
+ sm->outputTokenType, output_token);
+ if (GSS_ERROR(tmpMajor)) {
+ major = tmpMajor;
+ *minor = tmpMinor;
+ goto cleanup;
+ }
+ }
+
+cleanup:
+ if (cred != GSS_C_NO_CREDENTIAL)
+ GSSEAP_MUTEX_UNLOCK(&cred->mutex);
+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
+
+ if (GSS_ERROR(major))
+ gssEapReleaseContext(&tmpMinor, context_handle);
+
+ gss_release_buffer(&tmpMinor, &innerOutputToken);
+
+ return major;
+}
+
+#ifdef GSSEAP_ENABLE_REAUTH
+static OM_uint32
+acceptReadyKrb(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ gss_cred_id_t cred,
+ const gss_name_t initiator,
+ const gss_OID mech,
+ OM_uint32 timeRec)
+{
+ OM_uint32 major;
+
+ major = gssEapGlueToMechName(minor, initiator, &ctx->initiatorName);
+ if (GSS_ERROR(major))
+ return major;
+
+ if (cred != GSS_C_NO_CREDENTIAL && cred->name != GSS_C_NO_NAME) {
+ major = gssEapDuplicateName(minor, cred->name, &ctx->acceptorName);
+ if (GSS_ERROR(major))
+ return major;
+ }
+
+ major = gssEapReauthComplete(minor, ctx, cred, mech, timeRec);
+ if (GSS_ERROR(major))
+ return major;
+
+ ctx->state = EAP_STATE_ESTABLISHED;
+
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+eapGssSmAcceptGssReauth(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ gss_cred_id_t cred,
+ gss_buffer_t inputToken,
+ gss_channel_bindings_t chanBindings,
+ gss_buffer_t outputToken)
+{
+ OM_uint32 major, tmpMinor;
+ gss_cred_id_t krbCred = GSS_C_NO_CREDENTIAL;
+ gss_name_t krbInitiator = GSS_C_NO_NAME;
+ gss_OID mech = GSS_C_NO_OID;
+ OM_uint32 gssFlags, timeRec = GSS_C_INDEFINITE;
+
+ ctx->flags |= CTX_FLAG_KRB_REAUTH_GSS;
+
+ if (cred != GSS_C_NO_CREDENTIAL)
+ krbCred = cred->krbCred;
+
+ major = gssAcceptSecContext(minor,
+ &ctx->kerberosCtx,
+ krbCred,
+ inputToken,
+ chanBindings,
+ &krbInitiator,
+ &mech,
+ outputToken,
+ &gssFlags,
+ &timeRec,
+ NULL);
+ if (major == GSS_S_COMPLETE) {
+ major = acceptReadyKrb(minor, ctx, cred,
+ krbInitiator, mech, timeRec);
+ }
+
+ ctx->gssFlags = gssFlags;
+
+ gssReleaseName(&tmpMinor, &krbInitiator);
+
+ return major;
+}
+#endif /* GSSEAP_ENABLE_REAUTH */
--- /dev/null
+dnl Based on the one from the Boinc project by Reinhard
+
+AC_DEFUN([AX_CHECK_KRB5],
+[AC_MSG_CHECKING(for GSS-API and Kerberos implementation)
+KRB5_DIR=
+found_krb5="no"
+AC_ARG_WITH(krb5,
+ AC_HELP_STRING([--with-krb5],
+ [Use krb5 (in specified installation directory)]),
+ [check_krb5_dir="$withval"],
+ [check_krb5_dir=])
+for dir in $check_krb5_dir /usr /usr/local ; do
+ krb5dir="$dir"
+ if test -x "$dir/bin/krb5-config"; then
+ found_krb5="yes";
+ KRB5_CFLAGS=`$dir/bin/krb5-config gssapi --cflags`;
+ KRB5_LIBS=`$dir/bin/krb5-config gssapi --libs`;
+ break;
+ fi
+done
+AC_MSG_RESULT($found_krb5)
+if test x_$found_krb5 != x_yes; then
+ AC_MSG_ERROR([
+----------------------------------------------------------------------
+ Cannot find GSS-API/Kerberos libraries.
+
+ Please install MIT or Heimdal or specify installation directory with
+ --with-krb5=(dir).
+----------------------------------------------------------------------
+])
+else
+ printf "Kerberos found in $krb5dir\n";
+ AC_SUBST(KRB5_CFLAGS)
+ AC_SUBST(KRB5_LIBS)
+ AC_CHECK_LIB(gssapi_krb5, GSS_C_NT_COMPOSITE_EXPORT, [AC_DEFINE_UNQUOTED([HAVE_GSS_C_NT_COMPOSITE_EXPORT], 1, [Define if GSS-API library supports recent naming extensions draft])], [], "$KRB5_LIBS")
+ AC_CHECK_LIB(gssapi_krb5, gss_inquire_attrs_for_mech, [AC_DEFINE_UNQUOTED([HAVE_GSS_INQUIRE_ATTRS_FOR_MECH], 1, [Define if GSS-API library supports RFC 5587])], [], "$KRB5_LIBS")
+ AC_CHECK_LIB(gssapi_krb5, gss_krb5_import_cred, [AC_DEFINE_UNQUOTED([HAVE_GSS_KRB5_IMPORT_CRED], 1, [Define if GSS-API library supports gss_krb5_import_cred])], [], "$KRB5_LIBS")
+fi
+])dnl
+
+AC_DEFUN([AX_CHECK_EAP],
+[AC_MSG_CHECKING(for EAP implementation)
+EAP_DIR=
+found_eap="no"
+AC_ARG_WITH(eap,
+ AC_HELP_STRING([--with-eap],
+ [Use eap (in specified installation directory)]),
+ [check_eap_dir="$withval"],
+ [check_eap_dir=])
+for dir in $check_eap_dir /usr /usr/local ; do
+ eapdir="$dir"
+ if test -f "$dir/src/eap_peer/eap.h"; then
+ found_eap="yes";
+ EAP_DIR="${eapdir}"
+ EAP_CFLAGS="-I$eapdir/src/common -I$eapdir/src -I$eapdir/src/utils";
+ break;
+ fi
+done
+AC_MSG_RESULT($found_eap)
+if test x_$found_eap != x_yes; then
+ AC_MSG_ERROR([
+----------------------------------------------------------------------
+ Cannot find EAP libraries.
+
+ Please install wpa_supplicant or specify installation directory with
+ --with-eap=(dir).
+----------------------------------------------------------------------
+])
+else
+ printf "EAP found in $eapdir\n";
+ EAP_CFLAGS="$EAP_CFLAGS \
+-DEAP_TLS \
+-DEAP_PEAP \
+-DEAP_TTLS \
+-DEAP_MD5 \
+-DEAP_MSCHAPv2 \
+-DEAP_GTC \
+-DEAP_OTP \
+-DEAP_LEAP \
+-DEAP_PSK \
+-DEAP_PAX \
+-DEAP_SAKE \
+-DEAP_GPSK \
+-DEAP_GPSK_SHA256 \
+-DEAP_SERVER_IDENTITY \
+-DEAP_SERVER_TLS \
+-DEAP_SERVER_PEAP \
+-DEAP_SERVER_TTLS \
+-DEAP_SERVER_MD5 \
+-DEAP_SERVER_MSCHAPV2 \
+-DEAP_SERVER_GTC \
+-DEAP_SERVER_PSK \
+-DEAP_SERVER_PAX \
+-DEAP_SERVER_SAKE \
+-DEAP_SERVER_GPSK \
+-DEAP_SERVER_GPSK_SHA256 \
+-DIEEE8021X_EAPOL";
+ EAP_LIBS="-leap -lutils -lcrypto -ltls";
+ EAP_LDFLAGS="-L$eapdir/eap_example -L$eapdir/src/utils -L$eapdir/src/crypto -L$eapdir/src/tls";
+ AC_SUBST(EAP_CFLAGS)
+ AC_SUBST(EAP_LDFLAGS)
+ AC_SUBST(EAP_LIBS)
+fi
+])dnl
+
+AC_DEFUN([AX_CHECK_SHIBSP],
+[AC_MSG_CHECKING(for Shibboleth implementation)
+SHIBSP_DIR=
+found_shibsp="no"
+AC_ARG_WITH(shibsp,
+ AC_HELP_STRING([--with-shibsp],
+ [Use shibspboleth (in specified installation directory)]),
+ [check_shibsp_dir="$withval"],
+ [check_shibsp_dir=])
+for dir in $check_shibsp_dir /usr /usr/local ; do
+ shibspdir="$dir"
+ if test -f "$dir/include/shibsp/SPConfig.h"; then
+ found_shibsp="yes";
+ SHIBSP_DIR="${shibspdir}"
+ SHIBSP_CXXFLAGS="-I$shibspdir/include";
+ break;
+ fi
+done
+AC_MSG_RESULT($found_shibsp)
+if test x_$found_shibsp != x_yes; then
+ AC_MSG_ERROR([
+----------------------------------------------------------------------
+ Cannot find Shibboleth/OpenSAML libraries.
+
+ Please install Shibboleth or specify installation directory with
+ --with-shibsp=(dir).
+----------------------------------------------------------------------
+])
+else
+ printf "Shibboleth found in $shibspdir\n";
+ SHIBSP_LIBS="-lshibsp -llog4shib -lsaml -lxml-security-c -lxmltooling -lxerces-c";
+ SHIBSP_LDFLAGS="-L$shibspdir/lib";
+ AC_SUBST(SHIBSP_CXXFLAGS)
+ AC_SUBST(SHIBSP_LDFLAGS)
+ AC_SUBST(SHIBSP_LIBS)
+fi
+])dnl
+
+AC_DEFUN([AX_CHECK_SHIBRESOLVER],
+[AC_MSG_CHECKING(for Shibboleth resolver implementation)
+SHIBRESOLVER_DIR=
+found_shibresolver="no"
+AC_ARG_WITH(shibresolver,
+ AC_HELP_STRING([--with-shibresolver],
+ [Use Shibboleth resolver (in specified installation directory)]),
+ [check_shibresolver_dir="$withval"],
+ [check_shibresolver_dir=])
+for dir in $check_shibresolver_dir /usr /usr/local ; do
+ shibresolverdir="$dir"
+ if test -f "$dir/include/shibresolver/resolver.h"; then
+ found_shibresolver="yes";
+ SHIBRESOLVER_DIR="${shibresolverdir}"
+ SHIBRESOLVER_CXXFLAGS="-I$shibresolverdir/include";
+ break;
+ fi
+done
+AC_MSG_RESULT($found_shibresolver)
+if test x_$found_shibresolver != x_yes; then
+ AC_MSG_ERROR([
+----------------------------------------------------------------------
+ Cannot find Shibboleth resolver libraries.
+
+ Please install Shibboleth or specify installation directory with
+ --with-shibresolver=(dir).
+----------------------------------------------------------------------
+])
+else
+ printf "Shibboleth resolver found in $shibresolverdir\n";
+ SHIBRESOLVER_LIBS="-lshibresolver";
+ SHIBRESOLVER_LDFLAGS="-L$shibresolverdir/lib";
+ AC_SUBST(SHIBRESOLVER_CXXFLAGS)
+ AC_SUBST(SHIBRESOLVER_LDFLAGS)
+ AC_SUBST(SHIBRESOLVER_LIBS)
+fi
+])dnl
+
+AC_DEFUN([AX_CHECK_RADSEC],
+[AC_MSG_CHECKING(for radsec)
+RADSEC_DIR=
+found_radsec="no"
+AC_ARG_WITH(radsec,
+ AC_HELP_STRING([--with-radsec],
+ [Use radsec (in specified installation directory)]),
+ [check_radsec_dir="$withval"],
+ [check_radsec_dir=])
+for dir in $check_radsec_dir /usr /usr/local ; do
+ radsecdir="$dir"
+ if test -f "$dir/include/radsec/radsec.h"; then
+ found_radsec="yes";
+ RADSEC_DIR="${radsecdir}"
+ RADSEC_CFLAGS="-I$radsecdir/include";
+ break;
+ fi
+done
+AC_MSG_RESULT($found_radsec)
+if test x_$found_radsec != x_yes; then
+ AC_MSG_ERROR([
+----------------------------------------------------------------------
+ Cannot find radsec libraries.
+
+ Please install libradsec or specify installation directory with
+ --with-radsec=(dir).
+----------------------------------------------------------------------
+])
+else
+ printf "radsec found in $radsecdir\n";
+ RADSEC_LIBS="-lradsec";
+ RADSEC_LDFLAGS="-L$radsecdir/lib";
+ AC_SUBST(RADSEC_CFLAGS)
+ AC_SUBST(RADSEC_LDFLAGS)
+ AC_SUBST(RADSEC_LIBS)
+fi
+])dnl
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Wrapper for acquiring a credential handle.
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32
+gss_acquire_cred(OM_uint32 *minor,
+ gss_name_t desired_name,
+ OM_uint32 time_req,
+ gss_OID_set desired_mechs,
+ gss_cred_usage_t cred_usage,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *time_rec)
+{
+ return gssEapAcquireCred(minor, desired_name, GSS_C_NO_BUFFER,
+ time_req, desired_mechs, cred_usage,
+ output_cred_handle, actual_mechs, time_rec);
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Wrapper for acquiring a credential handle using a password.
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32
+gssspi_acquire_cred_with_password(OM_uint32 *minor,
+ const gss_name_t desired_name,
+ const gss_buffer_t password,
+ OM_uint32 time_req,
+ const gss_OID_set desired_mechs,
+ gss_cred_usage_t cred_usage,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *time_rec)
+{
+ return gssEapAcquireCred(minor, desired_name, password,
+ time_req, desired_mechs, cred_usage,
+ output_cred_handle, actual_mechs, time_rec);
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Wrapper for acquiring a credential handle.
+ */
+
+#include "gssapiP_eap.h"
+
+/*
+ * Note that this shouldn't really be required to be implemented by anything
+ * apart from the mechanism glue layer. However, Heimdal does call into the
+ * mechanism here.
+ */
+OM_uint32
+gss_add_cred(OM_uint32 *minor,
+ gss_cred_id_t input_cred_handle,
+ gss_name_t desired_name,
+ gss_OID desired_mech,
+ gss_cred_usage_t cred_usage,
+ OM_uint32 initiator_time_req,
+ OM_uint32 acceptor_time_req,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *initiator_time_rec,
+ OM_uint32 *acceptor_time_rec)
+{
+ OM_uint32 major;
+ OM_uint32 time_req, time_rec = 0;
+ gss_OID_set_desc mechs;
+
+ *minor = 0;
+ *output_cred_handle = GSS_C_NO_CREDENTIAL;
+
+ if (cred_usage == GSS_C_ACCEPT)
+ time_req = acceptor_time_req;
+ else
+ time_req = initiator_time_req;
+
+ mechs.count = 1;
+ mechs.elements = desired_mech;
+
+ major = gssEapAcquireCred(minor,
+ desired_name,
+ GSS_C_NO_BUFFER,
+ time_req,
+ &mechs,
+ cred_usage,
+ output_cred_handle,
+ actual_mechs,
+ &time_rec);
+
+ if (initiator_time_rec != NULL)
+ *initiator_time_rec = time_rec;
+ if (acceptor_time_rec != NULL)
+ *acceptor_time_rec = time_rec;
+
+ return major;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Wrapper for acquiring a credential handle using a password.
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32
+gss_add_cred_with_password(OM_uint32 *minor,
+ const gss_cred_id_t input_cred_handle,
+ const gss_name_t desired_name,
+ const gss_OID desired_mech,
+ const gss_buffer_t password,
+ gss_cred_usage_t cred_usage,
+ OM_uint32 initiator_time_req,
+ OM_uint32 acceptor_time_req,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *initiator_time_rec,
+ OM_uint32 *acceptor_time_rec)
+{
+ OM_uint32 major;
+ OM_uint32 time_req, time_rec = 0;
+ gss_OID_set_desc mechs;
+
+ *minor = 0;
+ *output_cred_handle = GSS_C_NO_CREDENTIAL;
+
+ if (cred_usage == GSS_C_ACCEPT)
+ time_req = acceptor_time_req;
+ else
+ time_req = initiator_time_req;
+
+ mechs.count = 1;
+ mechs.elements = desired_mech;
+
+ major = gssEapAcquireCred(minor,
+ desired_name,
+ password,
+ time_req,
+ &mechs,
+ cred_usage,
+ output_cred_handle,
+ actual_mechs,
+ &time_rec);
+
+ if (initiator_time_rec != NULL)
+ *initiator_time_rec = time_rec;
+ if (acceptor_time_rec != NULL)
+ *acceptor_time_rec = time_rec;
+
+ return major;
+}
--- /dev/null
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * krb5/authdata_plugin.h
+ *
+ * Copyright (C) 2007 Apple Inc. All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * AuthorizationData plugin definitions for Kerberos 5.
+ */
+
+/*
+ * This is considered an INTERNAL interface at this time.
+ *
+ * Some work is needed before exporting it:
+ *
+ * + Documentation.
+ * + Sample code.
+ * + Test cases (preferably automated testing under "make check").
+ * + Hook into TGS exchange too; will change API.
+ * + Examine memory management issues, especially for Windows; may
+ * change API.
+ *
+ * Other changes that would be nice to have, but not necessarily
+ * before making this interface public:
+ *
+ * + Library support for AD-IF-RELEVANT and similar wrappers. (We can
+ * make the plugin construct them if it wants them.)
+ * + KDC could combine/optimize wrapped AD elements provided by
+ * multiple plugins, e.g., two IF-RELEVANT sequences could be
+ * merged. (The preauth plugin API also has this bug, we're going
+ * to need a general fix.)
+ */
+
+#ifndef KRB5_AUTHDATA_PLUGIN_H_INCLUDED
+#define KRB5_AUTHDATA_PLUGIN_H_INCLUDED
+#include <krb5/krb5.h>
+
+/*
+ * While arguments of these types are passed-in, for the most part a
+ * authorization data module can treat them as opaque. If we need
+ * keying data, we can ask for it directly.
+ */
+struct _krb5_db_entry_new;
+
+/*
+ * The function table / structure which an authdata server module must export as
+ * "authdata_server_0". NOTE: replace "0" with "1" for the type and
+ * variable names if this gets picked up by upstream. If the interfaces work
+ * correctly, future versions of the table will add either more callbacks or
+ * more arguments to callbacks, and in both cases we'll be able to wrap the v0
+ * functions.
+ */
+/* extern krb5plugin_authdata_ftable_v0 authdata_server_0; */
+typedef struct krb5plugin_authdata_server_ftable_v0 {
+ /* Not-usually-visible name. */
+ char *name;
+
+ /*
+ * Per-plugin initialization/cleanup. The init function is called
+ * by the KDC when the plugin is loaded, and the fini function is
+ * called before the plugin is unloaded. Both are optional.
+ */
+ krb5_error_code (*init_proc)(krb5_context, void **);
+ void (*fini_proc)(krb5_context, void *);
+ /*
+ * Actual authorization data handling function. If this field
+ * holds a null pointer, this mechanism will be skipped, and the
+ * init/fini functions will not be run.
+ *
+ * This function should only modify the field
+ * enc_tkt_reply->authorization_data. All other values should be
+ * considered inputs only. And, it should *modify* the field, not
+ * overwrite it and assume that there are no other authdata
+ * plugins in use.
+ *
+ * Memory management: authorization_data is a malloc-allocated,
+ * null-terminated sequence of malloc-allocated pointers to
+ * authorization data structures. This plugin code currently
+ * assumes the libraries, KDC, and plugin all use the same malloc
+ * pool, which may be a problem if/when we get the KDC code
+ * running on Windows.
+ *
+ * If this function returns a non-zero error code, a message
+ * is logged, but no other action is taken. Other authdata
+ * plugins will be called, and a response will be sent to the
+ * client (barring other problems).
+ */
+ krb5_error_code (*authdata_proc)(krb5_context,
+ struct _krb5_db_entry_new *client,
+ krb5_data *req_pkt,
+ krb5_kdc_req *request,
+ krb5_enc_tkt_part *enc_tkt_reply);
+} krb5plugin_server_authdata_ftable_v0;
+
+typedef krb5plugin_server_authdata_ftable_v0 krb5plugin_authdata_ftable_v0;
+
+typedef struct krb5plugin_authdata_server_ftable_v2 {
+ /* Not-usually-visible name. */
+ char *name;
+
+ /*
+ * Per-plugin initialization/cleanup. The init function is called
+ * by the KDC when the plugin is loaded, and the fini function is
+ * called before the plugin is unloaded. Both are optional.
+ */
+ krb5_error_code (*init_proc)(krb5_context, void **);
+ void (*fini_proc)(krb5_context, void *);
+ /*
+ * Actual authorization data handling function. If this field
+ * holds a null pointer, this mechanism will be skipped, and the
+ * init/fini functions will not be run.
+ *
+ * This function should only modify the field
+ * enc_tkt_reply->authorization_data. All other values should be
+ * considered inputs only. And, it should *modify* the field, not
+ * overwrite it and assume that there are no other authdata
+ * plugins in use.
+ *
+ * Memory management: authorization_data is a malloc-allocated,
+ * null-terminated sequence of malloc-allocated pointers to
+ * authorization data structures. This plugin code currently
+ * assumes the libraries, KDC, and plugin all use the same malloc
+ * pool, which may be a problem if/when we get the KDC code
+ * running on Windows.
+ *
+ * If this function returns a non-zero error code, a message
+ * is logged, but no other action is taken. Other authdata
+ * plugins will be called, and a response will be sent to the
+ * client (barring other problems).
+ */
+ krb5_error_code (*authdata_proc)(krb5_context,
+ unsigned int flags,
+ struct _krb5_db_entry_new *client,
+ struct _krb5_db_entry_new *server,
+ struct _krb5_db_entry_new *tgs,
+ krb5_keyblock *client_key,
+ krb5_keyblock *server_key,
+ krb5_keyblock *tgs_key,
+ krb5_data *req_pkt,
+ krb5_kdc_req *request,
+ krb5_const_principal for_user_princ,
+ krb5_enc_tkt_part *enc_tkt_request,
+ krb5_enc_tkt_part *enc_tkt_reply);
+} krb5plugin_authdata_server_ftable_v2;
+
+typedef krb5plugin_authdata_server_ftable_v2 krb5plugin_authdata_ftable_v2;
+
+typedef krb5_error_code
+(*authdata_client_plugin_init_proc)(krb5_context context,
+ void **plugin_context);
+
+#define AD_USAGE_AS_REQ 0x01
+#define AD_USAGE_TGS_REQ 0x02
+#define AD_USAGE_AP_REQ 0x04
+#define AD_USAGE_KDC_ISSUED 0x08
+#define AD_USAGE_MASK 0x0F
+#define AD_INFORMATIONAL 0x10
+
+struct _krb5_authdata_context;
+
+typedef void
+(*authdata_client_plugin_flags_proc)(krb5_context kcontext,
+ void *plugin_context,
+ krb5_authdatatype ad_type,
+ krb5_flags *flags);
+
+typedef void
+(*authdata_client_plugin_fini_proc)(krb5_context kcontext,
+ void *plugin_context);
+
+typedef krb5_error_code
+(*authdata_client_request_init_proc)(krb5_context kcontext,
+ struct _krb5_authdata_context *context,
+ void *plugin_context,
+ void **request_context);
+
+typedef void
+(*authdata_client_request_fini_proc)(krb5_context kcontext,
+ struct _krb5_authdata_context *context,
+ void *plugin_context,
+ void *request_context);
+
+typedef krb5_error_code
+(*authdata_client_import_authdata_proc)(krb5_context kcontext,
+ struct _krb5_authdata_context *context,
+ void *plugin_context,
+ void *request_context,
+ krb5_authdata **authdata,
+ krb5_boolean kdc_issued_flag,
+ krb5_const_principal issuer);
+
+typedef krb5_error_code
+(*authdata_client_export_authdata_proc)(krb5_context kcontext,
+ struct _krb5_authdata_context *context,
+ void *plugin_context,
+ void *request_context,
+ krb5_flags usage,
+ krb5_authdata ***authdata);
+
+typedef krb5_error_code
+(*authdata_client_get_attribute_types_proc)(krb5_context kcontext,
+ struct _krb5_authdata_context *context,
+ void *plugin_context,
+ void *request_context,
+ krb5_data **attrs);
+
+typedef krb5_error_code
+(*authdata_client_get_attribute_proc)(krb5_context kcontext,
+ struct _krb5_authdata_context *context,
+ void *plugin_context,
+ void *request_context,
+ const krb5_data *attribute,
+ krb5_boolean *authenticated,
+ krb5_boolean *complete,
+ krb5_data *value,
+ krb5_data *display_value,
+ int *more);
+
+typedef krb5_error_code
+(*authdata_client_set_attribute_proc)(krb5_context kcontext,
+ struct _krb5_authdata_context *context,
+ void *plugin_context,
+ void *request_context,
+ krb5_boolean complete,
+ const krb5_data *attribute,
+ const krb5_data *value);
+
+typedef krb5_error_code
+(*authdata_client_delete_attribute_proc)(krb5_context kcontext,
+ struct _krb5_authdata_context *context,
+ void *plugin_context,
+ void *request_context,
+ const krb5_data *attribute);
+
+typedef krb5_error_code
+(*authdata_client_export_internal_proc)(krb5_context kcontext,
+ struct _krb5_authdata_context *context,
+ void *plugin_context,
+ void *request_context,
+ krb5_boolean restrict_authenticated,
+ void **ptr);
+
+typedef void
+(*authdata_client_free_internal_proc)(krb5_context kcontext,
+ struct _krb5_authdata_context *context,
+ void *plugin_context,
+ void *request_context,
+ void *ptr);
+
+typedef krb5_error_code
+(*authdata_client_verify_proc)(krb5_context kcontext,
+ struct _krb5_authdata_context *context,
+ void *plugin_context,
+ void *request_context,
+ const krb5_auth_context *auth_context,
+ const krb5_keyblock *key,
+ const krb5_ap_req *req);
+
+typedef krb5_error_code
+(*authdata_client_size_proc)(krb5_context kcontext,
+ struct _krb5_authdata_context *context,
+ void *plugin_context,
+ void *request_context,
+ size_t *sizep);
+
+typedef krb5_error_code
+(*authdata_client_externalize_proc)(krb5_context kcontext,
+ struct _krb5_authdata_context *context,
+ void *plugin_context,
+ void *request_context,
+ krb5_octet **buffer,
+ size_t *lenremain);
+
+typedef krb5_error_code
+(*authdata_client_internalize_proc)(krb5_context kcontext,
+ struct _krb5_authdata_context *context,
+ void *plugin_context,
+ void *request_context,
+ krb5_octet **buffer,
+ size_t *lenremain);
+
+typedef krb5_error_code
+(*authdata_client_copy_proc)(krb5_context kcontext,
+ struct _krb5_authdata_context *context,
+ void *plugin_context,
+ void *request_context,
+ void *dst_plugin_context,
+ void *dst_request_context);
+
+typedef struct krb5plugin_authdata_client_ftable_v0 {
+ char *name;
+ krb5_authdatatype *ad_type_list;
+ authdata_client_plugin_init_proc init;
+ authdata_client_plugin_fini_proc fini;
+ authdata_client_plugin_flags_proc flags;
+ authdata_client_request_init_proc request_init;
+ authdata_client_request_fini_proc request_fini;
+ authdata_client_get_attribute_types_proc get_attribute_types;
+ authdata_client_get_attribute_proc get_attribute;
+ authdata_client_set_attribute_proc set_attribute;
+ authdata_client_delete_attribute_proc delete_attribute;
+ authdata_client_export_authdata_proc export_authdata;
+ authdata_client_import_authdata_proc import_authdata;
+ authdata_client_export_internal_proc export_internal;
+ authdata_client_free_internal_proc free_internal;
+ authdata_client_verify_proc verify;
+ authdata_client_size_proc size;
+ authdata_client_externalize_proc externalize;
+ authdata_client_internalize_proc internalize;
+ authdata_client_copy_proc copy; /* optional */
+} krb5plugin_authdata_client_ftable_v0;
+
+#endif /* KRB5_AUTHDATA_PLUGIN_H_INCLUDED */
--- /dev/null
+#! /bin/sh
+
+PATH=/usr/local/bin:$PATH
+
+if [ -x "`which autoreconf 2>/dev/null`" ] ; then
+ exec autoreconf -ivf
+fi
+
+aclocal -I m4 && \
+ autoheader && \
+ libtoolize --automake -c && \
+ autoconf && \
+ automake --add-missing --copy
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Function for canonicalizing a name; presently just duplicates it.
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32
+gss_canonicalize_name(OM_uint32 *minor,
+ const gss_name_t input_name,
+ const gss_OID mech_type,
+ gss_name_t *output_name)
+{
+ OM_uint32 major;
+
+ *minor = 0;
+
+ if (!gssEapIsMechanismOid(mech_type))
+ return GSS_S_BAD_MECH;
+
+ if (input_name == GSS_C_NO_NAME) {
+ *minor = EINVAL;
+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
+ }
+
+ GSSEAP_MUTEX_LOCK(&input_name->mutex);
+
+ major = gssEapDuplicateName(minor, input_name, output_name);
+
+ GSSEAP_MUTEX_UNLOCK(&input_name->mutex);
+
+ return major;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Compare two names.
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32
+gss_compare_name(OM_uint32 *minor,
+ gss_name_t name1,
+ gss_name_t name2,
+ int *name_equal)
+{
+ krb5_context krbContext;
+
+ *minor = 0;
+
+ if (name1 == GSS_C_NO_NAME && name2 == GSS_C_NO_NAME) {
+ *name_equal = 1;
+ } else if (name1 != GSS_C_NO_NAME && name2 != GSS_C_NO_NAME) {
+ GSSEAP_KRB_INIT(&krbContext);
+
+ /* krbPrincipal is immutable, so lock not required */
+ *name_equal = krb5_principal_compare(krbContext,
+ name1->krbPrincipal,
+ name2->krbPrincipal);
+ }
+
+ return GSS_S_COMPLETE;
+}
--- /dev/null
+#! /bin/sh
+# Attempt to guess a canonical system name.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+# Free Software Foundation, Inc.
+
+timestamp='2009-11-20'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Originally written by Per Bothner. Please send patches (context
+# diff format) to <config-patches@gnu.org> and include a ChangeLog
+# entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub. If it succeeds, it prints the system name on stdout, and
+# exits with 0. Otherwise, it exits with 1.
+#
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help" >&2
+ exit 1 ;;
+ * )
+ break ;;
+ esac
+done
+
+if test $# != 0; then
+ echo "$me: too many arguments$help" >&2
+ exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,) echo "int x;" > $dummy.c ;
+ for c in cc gcc c89 c99 ; do
+ if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+ CC_FOR_BUILD="$c"; break ;
+ fi ;
+ done ;
+ if test x"$CC_FOR_BUILD" = x ; then
+ CC_FOR_BUILD=no_compiler_found ;
+ fi
+ ;;
+ ,,*) CC_FOR_BUILD=$CC ;;
+ ,*,*) CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+ *:NetBSD:*:*)
+ # NetBSD (nbsd) targets should (where applicable) match one or
+ # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+ # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
+ # switched to ELF, *-*-netbsd* would select the old
+ # object file format. This provides both forward
+ # compatibility and a consistent mechanism for selecting the
+ # object file format.
+ #
+ # Note: NetBSD doesn't particularly care about the vendor
+ # portion of the name. We always set it to "unknown".
+ sysctl="sysctl -n hw.machine_arch"
+ UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+ /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+ case "${UNAME_MACHINE_ARCH}" in
+ armeb) machine=armeb-unknown ;;
+ arm*) machine=arm-unknown ;;
+ sh3el) machine=shl-unknown ;;
+ sh3eb) machine=sh-unknown ;;
+ sh5el) machine=sh5le-unknown ;;
+ *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+ esac
+ # The Operating System including object format, if it has switched
+ # to ELF recently, or will in the future.
+ case "${UNAME_MACHINE_ARCH}" in
+ arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+ eval $set_cc_for_build
+ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ELF__
+ then
+ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+ # Return netbsd for either. FIX?
+ os=netbsd
+ else
+ os=netbsdelf
+ fi
+ ;;
+ *)
+ os=netbsd
+ ;;
+ esac
+ # The OS release
+ # Debian GNU/NetBSD machines have a different userland, and
+ # thus, need a distinct triplet. However, they do not need
+ # kernel version information, so it can be replaced with a
+ # suitable tag, in the style of linux-gnu.
+ case "${UNAME_VERSION}" in
+ Debian*)
+ release='-gnu'
+ ;;
+ *)
+ release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ ;;
+ esac
+ # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+ # contains redundant information, the shorter form:
+ # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+ echo "${machine}-${os}${release}"
+ exit ;;
+ *:OpenBSD:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+ echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+ exit ;;
+ *:ekkoBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+ exit ;;
+ *:SolidBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+ exit ;;
+ macppc:MirBSD:*:*)
+ echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ *:MirBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ alpha:OSF1:*:*)
+ case $UNAME_RELEASE in
+ *4.0)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ ;;
+ *5.*)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+ ;;
+ esac
+ # According to Compaq, /usr/sbin/psrinfo has been available on
+ # OSF/1 and Tru64 systems produced since 1995. I hope that
+ # covers most systems running today. This code pipes the CPU
+ # types through head -n 1, so we only detect the type of CPU 0.
+ ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+ case "$ALPHA_CPU_TYPE" in
+ "EV4 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "EV4.5 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "LCA4 (21066/21068)")
+ UNAME_MACHINE="alpha" ;;
+ "EV5 (21164)")
+ UNAME_MACHINE="alphaev5" ;;
+ "EV5.6 (21164A)")
+ UNAME_MACHINE="alphaev56" ;;
+ "EV5.6 (21164PC)")
+ UNAME_MACHINE="alphapca56" ;;
+ "EV5.7 (21164PC)")
+ UNAME_MACHINE="alphapca57" ;;
+ "EV6 (21264)")
+ UNAME_MACHINE="alphaev6" ;;
+ "EV6.7 (21264A)")
+ UNAME_MACHINE="alphaev67" ;;
+ "EV6.8CB (21264C)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8AL (21264B)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8CX (21264D)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.9A (21264/EV69A)")
+ UNAME_MACHINE="alphaev69" ;;
+ "EV7 (21364)")
+ UNAME_MACHINE="alphaev7" ;;
+ "EV7.9 (21364A)")
+ UNAME_MACHINE="alphaev79" ;;
+ esac
+ # A Pn.n version is a patched version.
+ # A Vn.n version is a released version.
+ # A Tn.n version is a released field test version.
+ # A Xn.n version is an unreleased experimental baselevel.
+ # 1.2 uses "1.2" for uname -r.
+ echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ exit ;;
+ Alpha\ *:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # Should we change UNAME_MACHINE based on the output of uname instead
+ # of the specific Alpha model?
+ echo alpha-pc-interix
+ exit ;;
+ 21064:Windows_NT:50:3)
+ echo alpha-dec-winnt3.5
+ exit ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-unknown-sysv4
+ exit ;;
+ *:[Aa]miga[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-amigaos
+ exit ;;
+ *:[Mm]orph[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-morphos
+ exit ;;
+ *:OS/390:*:*)
+ echo i370-ibm-openedition
+ exit ;;
+ *:z/VM:*:*)
+ echo s390-ibm-zvmoe
+ exit ;;
+ *:OS400:*:*)
+ echo powerpc-ibm-os400
+ exit ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix${UNAME_RELEASE}
+ exit ;;
+ arm:riscos:*:*|arm:RISCOS:*:*)
+ echo arm-unknown-riscos
+ exit ;;
+ SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+ echo hppa1.1-hitachi-hiuxmpp
+ exit ;;
+ Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit ;;
+ NILE*:*:*:dcosx)
+ echo pyramid-pyramid-svr4
+ exit ;;
+ DRS?6000:unix:4.0:6*)
+ echo sparc-icl-nx6
+ exit ;;
+ DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+ case `/usr/bin/uname -p` in
+ sparc) echo sparc-icl-nx7; exit ;;
+ esac ;;
+ s390x:SunOS:*:*)
+ echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4H:SunOS:5.*:*)
+ echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
+ echo i386-pc-auroraux${UNAME_RELEASE}
+ exit ;;
+ i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+ eval $set_cc_for_build
+ SUN_ARCH="i386"
+ # If there is a compiler, see if it is configured for 64-bit objects.
+ # Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+ # This test works for both compilers.
+ if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+ if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ SUN_ARCH="x86_64"
+ fi
+ fi
+ echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:6*:*)
+ # According to config.sub, this is the proper way to canonicalize
+ # SunOS6. Hard to guess exactly what SunOS6 will be like, but
+ # it's likely to be more like Solaris than SunOS4.
+ echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:*:*)
+ case "`/usr/bin/arch -k`" in
+ Series*|S4*)
+ UNAME_RELEASE=`uname -v`
+ ;;
+ esac
+ # Japanese Language versions have a version number like `4.1.3-JL'.
+ echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+ exit ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ exit ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+ case "`/bin/arch`" in
+ sun3)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ ;;
+ sun4)
+ echo sparc-sun-sunos${UNAME_RELEASE}
+ ;;
+ esac
+ exit ;;
+ aushp:SunOS:*:*)
+ echo sparc-auspex-sunos${UNAME_RELEASE}
+ exit ;;
+ # The situation for MiNT is a little confusing. The machine name
+ # can be virtually everything (everything which is not
+ # "atarist" or "atariste" at least should have a processor
+ # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
+ # to the lowercase version "mint" (or "freemint"). Finally
+ # the system name "TOS" denotes a system which is actually not
+ # MiNT. But MiNT is downward compatible to TOS, so this should
+ # be no problem.
+ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+ echo m68k-milan-mint${UNAME_RELEASE}
+ exit ;;
+ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+ echo m68k-hades-mint${UNAME_RELEASE}
+ exit ;;
+ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+ echo m68k-unknown-mint${UNAME_RELEASE}
+ exit ;;
+ m68k:machten:*:*)
+ echo m68k-apple-machten${UNAME_RELEASE}
+ exit ;;
+ powerpc:machten:*:*)
+ echo powerpc-apple-machten${UNAME_RELEASE}
+ exit ;;
+ RISC*:Mach:*:*)
+ echo mips-dec-mach_bsd4.3
+ exit ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ 2020:CLIX:*:* | 2430:CLIX:*:*)
+ echo clipper-intergraph-clix${UNAME_RELEASE}
+ exit ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h> /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c &&
+ dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+ SYSTEM_NAME=`$dummy $dummyarg` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo mips-mips-riscos${UNAME_RELEASE}
+ exit ;;
+ Motorola:PowerMAX_OS:*:*)
+ echo powerpc-motorola-powermax
+ exit ;;
+ Motorola:*:4.3:PL8-*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+ then
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+ [ ${TARGET_BINARY_INTERFACE}x = x ]
+ then
+ echo m88k-dg-dgux${UNAME_RELEASE}
+ else
+ echo m88k-dg-dguxbcs${UNAME_RELEASE}
+ fi
+ else
+ echo i586-dg-dgux${UNAME_RELEASE}
+ fi
+ exit ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+ exit ;;
+ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ exit ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i*86:AIX:*:*)
+ echo i386-ibm-aix
+ exit ;;
+ ia64:AIX:*:*)
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <sys/systemcfg.h>
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+ then
+ echo "$SYSTEM_NAME"
+ else
+ echo rs6000-ibm-aix3.2.5
+ fi
+ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+ echo rs6000-ibm-aix3.2.4
+ else
+ echo rs6000-ibm-aix3.2
+ fi
+ exit ;;
+ *:AIX:*:[456])
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+ if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit ;;
+ ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+ echo romp-ibm-bsd4.4
+ exit ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
+ echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
+ exit ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit ;;
+ 9000/[34678]??:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ case "${UNAME_MACHINE}" in
+ 9000/31? ) HP_ARCH=m68000 ;;
+ 9000/[34]?? ) HP_ARCH=m68k ;;
+ 9000/[678][0-9][0-9])
+ if [ -x /usr/bin/getconf ]; then
+ sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+ case "${sc_cpu_version}" in
+ 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+ 532) # CPU_PA_RISC2_0
+ case "${sc_kernel_bits}" in
+ 32) HP_ARCH="hppa2.0n" ;;
+ 64) HP_ARCH="hppa2.0w" ;;
+ '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
+ esac ;;
+ esac
+ fi
+ if [ "${HP_ARCH}" = "" ]; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+
+ #define _HPUX_SOURCE
+ #include <stdlib.h>
+ #include <unistd.h>
+
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
+
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
+EOF
+ (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+ test -z "$HP_ARCH" && HP_ARCH=hppa
+ fi ;;
+ esac
+ if [ ${HP_ARCH} = "hppa2.0w" ]
+ then
+ eval $set_cc_for_build
+
+ # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+ # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler
+ # generating 64-bit code. GNU and HP use different nomenclature:
+ #
+ # $ CC_FOR_BUILD=cc ./config.guess
+ # => hppa2.0w-hp-hpux11.23
+ # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+ # => hppa64-hp-hpux11.23
+
+ if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+ grep -q __LP64__
+ then
+ HP_ARCH="hppa2.0w"
+ else
+ HP_ARCH="hppa64"
+ fi
+ fi
+ echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ exit ;;
+ ia64:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ echo ia64-hp-hpux${HPUX_REV}
+ exit ;;
+ 3050*:HI-UX:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo unknown-hitachi-hiuxwe2
+ exit ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+ echo hppa1.1-hp-bsd
+ exit ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit ;;
+ *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+ echo hppa1.0-hp-mpeix
+ exit ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+ echo hppa1.1-hp-osf
+ exit ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit ;;
+ i*86:OSF1:*:*)
+ if [ -x /usr/sbin/sysversion ] ; then
+ echo ${UNAME_MACHINE}-unknown-osf1mk
+ else
+ echo ${UNAME_MACHINE}-unknown-osf1
+ fi
+ exit ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+ -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*T3E:*:*:*)
+ echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*SV1:*:*:*)
+ echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ *:UNICOS/mp:*:*)
+ echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+ FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ 5000:UNIX_System_V:4.*:*)
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+ echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+ echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+ exit ;;
+ sparc*:BSD/OS:*:*)
+ echo sparc-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:FreeBSD:*:*)
+ case ${UNAME_MACHINE} in
+ pc98)
+ echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ amd64)
+ echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ *)
+ echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ esac
+ exit ;;
+ i*:CYGWIN*:*)
+ echo ${UNAME_MACHINE}-pc-cygwin
+ exit ;;
+ *:MINGW*:*)
+ echo ${UNAME_MACHINE}-pc-mingw32
+ exit ;;
+ i*:windows32*:*)
+ # uname -m includes "-pc" on this system.
+ echo ${UNAME_MACHINE}-mingw32
+ exit ;;
+ i*:PW*:*)
+ echo ${UNAME_MACHINE}-pc-pw32
+ exit ;;
+ *:Interix*:*)
+ case ${UNAME_MACHINE} in
+ x86)
+ echo i586-pc-interix${UNAME_RELEASE}
+ exit ;;
+ authenticamd | genuineintel | EM64T)
+ echo x86_64-unknown-interix${UNAME_RELEASE}
+ exit ;;
+ IA64)
+ echo ia64-unknown-interix${UNAME_RELEASE}
+ exit ;;
+ esac ;;
+ [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+ echo i${UNAME_MACHINE}-pc-mks
+ exit ;;
+ 8664:Windows_NT:*)
+ echo x86_64-pc-mks
+ exit ;;
+ i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+ # UNAME_MACHINE based on the output of uname instead of i386?
+ echo i586-pc-interix
+ exit ;;
+ i*:UWIN*:*)
+ echo ${UNAME_MACHINE}-pc-uwin
+ exit ;;
+ amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+ echo x86_64-unknown-cygwin
+ exit ;;
+ p*:CYGWIN*:*)
+ echo powerpcle-unknown-cygwin
+ exit ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ *:GNU:*:*)
+ # the GNU system
+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ exit ;;
+ *:GNU/*:*:*)
+ # other systems with GNU libc and userland
+ echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
+ exit ;;
+ i*86:Minix:*:*)
+ echo ${UNAME_MACHINE}-pc-minix
+ exit ;;
+ alpha:Linux:*:*)
+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+ EV5) UNAME_MACHINE=alphaev5 ;;
+ EV56) UNAME_MACHINE=alphaev56 ;;
+ PCA56) UNAME_MACHINE=alphapca56 ;;
+ PCA57) UNAME_MACHINE=alphapca56 ;;
+ EV6) UNAME_MACHINE=alphaev6 ;;
+ EV67) UNAME_MACHINE=alphaev67 ;;
+ EV68*) UNAME_MACHINE=alphaev68 ;;
+ esac
+ objdump --private-headers /bin/sh | grep -q ld.so.1
+ if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+ echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+ exit ;;
+ arm*:Linux:*:*)
+ eval $set_cc_for_build
+ if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ARM_EABI__
+ then
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ else
+ echo ${UNAME_MACHINE}-unknown-linux-gnueabi
+ fi
+ exit ;;
+ avr32*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ cris:Linux:*:*)
+ echo cris-axis-linux-gnu
+ exit ;;
+ crisv32:Linux:*:*)
+ echo crisv32-axis-linux-gnu
+ exit ;;
+ frv:Linux:*:*)
+ echo frv-unknown-linux-gnu
+ exit ;;
+ i*86:Linux:*:*)
+ LIBC=gnu
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #ifdef __dietlibc__
+ LIBC=dietlibc
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
+ echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
+ exit ;;
+ ia64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ m32r*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ m68*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ mips:Linux:*:* | mips64:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef ${UNAME_MACHINE}
+ #undef ${UNAME_MACHINE}el
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=${UNAME_MACHINE}el
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=${UNAME_MACHINE}
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+ ;;
+ or32:Linux:*:*)
+ echo or32-unknown-linux-gnu
+ exit ;;
+ padre:Linux:*:*)
+ echo sparc-unknown-linux-gnu
+ exit ;;
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+ echo hppa64-unknown-linux-gnu
+ exit ;;
+ parisc:Linux:*:* | hppa:Linux:*:*)
+ # Look for CPU level
+ case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+ PA7*) echo hppa1.1-unknown-linux-gnu ;;
+ PA8*) echo hppa2.0-unknown-linux-gnu ;;
+ *) echo hppa-unknown-linux-gnu ;;
+ esac
+ exit ;;
+ ppc64:Linux:*:*)
+ echo powerpc64-unknown-linux-gnu
+ exit ;;
+ ppc:Linux:*:*)
+ echo powerpc-unknown-linux-gnu
+ exit ;;
+ s390:Linux:*:* | s390x:Linux:*:*)
+ echo ${UNAME_MACHINE}-ibm-linux
+ exit ;;
+ sh64*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ sh*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ sparc:Linux:*:* | sparc64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ vax:Linux:*:*)
+ echo ${UNAME_MACHINE}-dec-linux-gnu
+ exit ;;
+ x86_64:Linux:*:*)
+ echo x86_64-unknown-linux-gnu
+ exit ;;
+ xtensa*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ i*86:DYNIX/ptx:4*:*)
+ # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+ # earlier versions are messed up and put the nodename in both
+ # sysname and nodename.
+ echo i386-sequent-sysv4
+ exit ;;
+ i*86:UNIX_SV:4.2MP:2.*)
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+ # Use sysv4.2uw... so that sysv4* matches it.
+ echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+ exit ;;
+ i*86:OS/2:*:*)
+ # If we were able to find `uname', then EMX Unix compatibility
+ # is probably installed.
+ echo ${UNAME_MACHINE}-pc-os2-emx
+ exit ;;
+ i*86:XTS-300:*:STOP)
+ echo ${UNAME_MACHINE}-unknown-stop
+ exit ;;
+ i*86:atheos:*:*)
+ echo ${UNAME_MACHINE}-unknown-atheos
+ exit ;;
+ i*86:syllable:*:*)
+ echo ${UNAME_MACHINE}-pc-syllable
+ exit ;;
+ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
+ echo i386-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ i*86:*DOS:*:*)
+ echo ${UNAME_MACHINE}-pc-msdosdjgpp
+ exit ;;
+ i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+ UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+ else
+ echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+ fi
+ exit ;;
+ i*86:*:5:[678]*)
+ # UnixWare 7.x, OpenUNIX and OpenServer 6.
+ case `/bin/uname -X | grep "^Machine"` in
+ *486*) UNAME_MACHINE=i486 ;;
+ *Pentium) UNAME_MACHINE=i586 ;;
+ *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+ esac
+ echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+ exit ;;
+ i*86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+ elif /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+ && UNAME_MACHINE=i686
+ (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+ && UNAME_MACHINE=i686
+ echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+ else
+ echo ${UNAME_MACHINE}-pc-sysv32
+ fi
+ exit ;;
+ pc:*:*:*)
+ # Left here for compatibility:
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i586.
+ # Note: whatever this is, it MUST be the same as what config.sub
+ # prints for the "djgpp" host, or else GDB configury will decide that
+ # this is a cross-build.
+ echo i586-pc-msdosdjgpp
+ exit ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit ;;
+ i860:*:4.*:*) # i860-SVR4
+ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+ echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+ else # Add other i860-SVR4 vendors below as they are discovered.
+ echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
+ fi
+ exit ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit ;;
+ mc68k:UNIX:SYSTEM5:3.51m)
+ echo m68k-convergent-sysv
+ exit ;;
+ M680?0:D-NIX:5.3:*)
+ echo m68k-diab-dnix
+ exit ;;
+ M68*:*:R3V[5678]*:*)
+ test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+ 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4; exit; } ;;
+ NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+ OS_REL='.3'
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+ m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+ echo m68k-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit ;;
+ TSUNAMI:LynxOS:2.*:*)
+ echo sparc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ rs6000:LynxOS:2.*:*)
+ echo rs6000-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
+ echo powerpc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ SM[BE]S:UNIX_SV:*:*)
+ echo mips-dde-sysv${UNAME_RELEASE}
+ exit ;;
+ RM*:ReliantUNIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ *:SINIX-*:*:*)
+ if uname -p 2>/dev/null >/dev/null ; then
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ echo ${UNAME_MACHINE}-sni-sysv4
+ else
+ echo ns32k-sni-sysv
+ fi
+ exit ;;
+ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit ;;
+ *:*:*:FTX*)
+ # From seanf@swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit ;;
+ i*86:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo ${UNAME_MACHINE}-stratus-vos
+ exit ;;
+ *:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo hppa1.1-stratus-vos
+ exit ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux${UNAME_RELEASE}
+ exit ;;
+ news*:NEWS-OS:6*:*)
+ echo mips-sony-newsos6
+ exit ;;
+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+ if [ -d /usr/nec ]; then
+ echo mips-nec-sysv${UNAME_RELEASE}
+ else
+ echo mips-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ echo powerpc-apple-beos
+ exit ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ echo i586-pc-beos
+ exit ;;
+ BePC:Haiku:*:*) # Haiku running on Intel PC compatible.
+ echo i586-pc-haiku
+ exit ;;
+ SX-4:SUPER-UX:*:*)
+ echo sx4-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-5:SUPER-UX:*:*)
+ echo sx5-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-6:SUPER-UX:*:*)
+ echo sx6-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-7:SUPER-UX:*:*)
+ echo sx7-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-8:SUPER-UX:*:*)
+ echo sx8-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-8R:SUPER-UX:*:*)
+ echo sx8r-nec-superux${UNAME_RELEASE}
+ exit ;;
+ Power*:Rhapsody:*:*)
+ echo powerpc-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Rhapsody:*:*)
+ echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Darwin:*:*)
+ UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+ case $UNAME_PROCESSOR in
+ i386)
+ eval $set_cc_for_build
+ if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+ if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ UNAME_PROCESSOR="x86_64"
+ fi
+ fi ;;
+ unknown) UNAME_PROCESSOR=powerpc ;;
+ esac
+ echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+ exit ;;
+ *:procnto*:*:* | *:QNX:[0123456789]*:*)
+ UNAME_PROCESSOR=`uname -p`
+ if test "$UNAME_PROCESSOR" = "x86"; then
+ UNAME_PROCESSOR=i386
+ UNAME_MACHINE=pc
+ fi
+ echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+ exit ;;
+ *:QNX:*:4*)
+ echo i386-pc-qnx
+ exit ;;
+ NSE-?:NONSTOP_KERNEL:*:*)
+ echo nse-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ NSR-?:NONSTOP_KERNEL:*:*)
+ echo nsr-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ *:NonStop-UX:*:*)
+ echo mips-compaq-nonstopux
+ exit ;;
+ BS2000:POSIX*:*:*)
+ echo bs2000-siemens-sysv
+ exit ;;
+ DS/*:UNIX_System_V:*:*)
+ echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+ exit ;;
+ *:Plan9:*:*)
+ # "uname -m" is not consistent, so use $cputype instead. 386
+ # is converted to i386 for consistency with other x86
+ # operating systems.
+ if test "$cputype" = "386"; then
+ UNAME_MACHINE=i386
+ else
+ UNAME_MACHINE="$cputype"
+ fi
+ echo ${UNAME_MACHINE}-unknown-plan9
+ exit ;;
+ *:TOPS-10:*:*)
+ echo pdp10-unknown-tops10
+ exit ;;
+ *:TENEX:*:*)
+ echo pdp10-unknown-tenex
+ exit ;;
+ KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+ echo pdp10-dec-tops20
+ exit ;;
+ XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+ echo pdp10-xkl-tops20
+ exit ;;
+ *:TOPS-20:*:*)
+ echo pdp10-unknown-tops20
+ exit ;;
+ *:ITS:*:*)
+ echo pdp10-unknown-its
+ exit ;;
+ SEI:*:*:SEIUX)
+ echo mips-sei-seiux${UNAME_RELEASE}
+ exit ;;
+ *:DragonFly:*:*)
+ echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit ;;
+ *:*VMS:*:*)
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ case "${UNAME_MACHINE}" in
+ A*) echo alpha-dec-vms ; exit ;;
+ I*) echo ia64-dec-vms ; exit ;;
+ V*) echo vax-dec-vms ; exit ;;
+ esac ;;
+ *:XENIX:*:SysV)
+ echo i386-pc-xenix
+ exit ;;
+ i*86:skyos:*:*)
+ echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+ exit ;;
+ i*86:rdos:*:*)
+ echo ${UNAME_MACHINE}-pc-rdos
+ exit ;;
+ i*86:AROS:*:*)
+ echo ${UNAME_MACHINE}-pc-aros
+ exit ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
+ I don't know.... */
+ printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+ printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+ "4"
+#else
+ ""
+#endif
+ ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+ printf ("arm-acorn-riscix\n"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+ printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+ int version;
+ version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+ if (version < 4)
+ printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+ else
+ printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+ exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+ printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+ printf ("ns32k-encore-mach\n"); exit (0);
+#else
+ printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+ printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+ printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+ printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+ struct utsname un;
+
+ uname(&un);
+
+ if (strncmp(un.version, "V2", 2) == 0) {
+ printf ("i386-sequent-ptx2\n"); exit (0);
+ }
+ if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+ printf ("i386-sequent-ptx1\n"); exit (0);
+ }
+ printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+# include <sys/param.h>
+# if defined (BSD)
+# if BSD == 43
+ printf ("vax-dec-bsd4.3\n"); exit (0);
+# else
+# if BSD == 199006
+ printf ("vax-dec-bsd4.3reno\n"); exit (0);
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# endif
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# else
+ printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+ printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+ exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+ case `getsysinfo -f cpu_type` in
+ c1*)
+ echo c1-convex-bsd
+ exit ;;
+ c2*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ c34*)
+ echo c34-convex-bsd
+ exit ;;
+ c38*)
+ echo c38-convex-bsd
+ exit ;;
+ c4*)
+ echo c4-convex-bsd
+ exit ;;
+ esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+ http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+and
+ http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo = `(hostinfo) 2>/dev/null`
+/bin/universe = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
--- /dev/null
+#! /bin/sh
+# Configuration validation subroutine script.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+# Free Software Foundation, Inc.
+
+timestamp='2009-11-20'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine. It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Please send patches to <config-patches@gnu.org>. Submit a context
+# diff and a properly formatted GNU ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support. The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+ $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help"
+ exit 1 ;;
+
+ *local*)
+ # First pass through any local machine types.
+ echo $1
+ exit ;;
+
+ * )
+ break ;;
+ esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+ exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+ exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+ nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \
+ uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
+ kopensolaris*-gnu* | \
+ storm-chaos* | os2-emx* | rtmk-nova*)
+ os=-$maybe_os
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+ ;;
+ *)
+ basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+ if [ $basic_machine != $1 ]
+ then os=`echo $1 | sed 's/.*-/-/'`
+ else os=; fi
+ ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work. We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+ -sun*os*)
+ # Prevent following clause from handling this invalid input.
+ ;;
+ -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+ -apple | -axis | -knuth | -cray | -microblaze)
+ os=
+ basic_machine=$1
+ ;;
+ -bluegene*)
+ os=-cnk
+ ;;
+ -sim | -cisco | -oki | -wec | -winbond)
+ os=
+ basic_machine=$1
+ ;;
+ -scout)
+ ;;
+ -wrs)
+ os=-vxworks
+ basic_machine=$1
+ ;;
+ -chorusos*)
+ os=-chorusos
+ basic_machine=$1
+ ;;
+ -chorusrdb)
+ os=-chorusrdb
+ basic_machine=$1
+ ;;
+ -hiux*)
+ os=-hiuxwe2
+ ;;
+ -sco6)
+ os=-sco5v6
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5)
+ os=-sco3.2v5
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco4)
+ os=-sco3.2v4
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2.[4-9]*)
+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2v[4-9]*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5v6*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco*)
+ os=-sco3.2v2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -udk*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -isc)
+ os=-isc2.2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -clix*)
+ basic_machine=clipper-intergraph
+ ;;
+ -isc*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -lynx*)
+ os=-lynxos
+ ;;
+ -ptx*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+ ;;
+ -windowsnt*)
+ os=`echo $os | sed -e 's/windowsnt/winnt/'`
+ ;;
+ -psos*)
+ os=-psos
+ ;;
+ -mint | -mint[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+ # Recognize the basic CPU types without company name.
+ # Some are omitted here because they have special meanings below.
+ 1750a | 580 \
+ | a29k \
+ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+ | am33_2.0 \
+ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
+ | bfin \
+ | c4x | clipper \
+ | d10v | d30v | dlx | dsp16xx \
+ | fido | fr30 | frv \
+ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | i370 | i860 | i960 | ia64 \
+ | ip2k | iq2000 \
+ | lm32 \
+ | m32c | m32r | m32rle | m68000 | m68k | m88k \
+ | maxq | mb | microblaze | mcore | mep | metag \
+ | mips | mipsbe | mipseb | mipsel | mipsle \
+ | mips16 \
+ | mips64 | mips64el \
+ | mips64octeon | mips64octeonel \
+ | mips64orion | mips64orionel \
+ | mips64r5900 | mips64r5900el \
+ | mips64vr | mips64vrel \
+ | mips64vr4100 | mips64vr4100el \
+ | mips64vr4300 | mips64vr4300el \
+ | mips64vr5000 | mips64vr5000el \
+ | mips64vr5900 | mips64vr5900el \
+ | mipsisa32 | mipsisa32el \
+ | mipsisa32r2 | mipsisa32r2el \
+ | mipsisa64 | mipsisa64el \
+ | mipsisa64r2 | mipsisa64r2el \
+ | mipsisa64sb1 | mipsisa64sb1el \
+ | mipsisa64sr71k | mipsisa64sr71kel \
+ | mipstx39 | mipstx39el \
+ | mn10200 | mn10300 \
+ | moxie \
+ | mt \
+ | msp430 \
+ | nios | nios2 \
+ | ns16k | ns32k \
+ | or32 \
+ | pdp10 | pdp11 | pj | pjl \
+ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+ | pyramid \
+ | rx \
+ | score \
+ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+ | sh64 | sh64le \
+ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+ | spu | strongarm \
+ | tahoe | thumb | tic4x | tic80 | tron \
+ | ubicom32 \
+ | v850 | v850e \
+ | we32k \
+ | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
+ | z8k | z80)
+ basic_machine=$basic_machine-unknown
+ ;;
+ m6811 | m68hc11 | m6812 | m68hc12 | picochip)
+ # Motorola 68HC11/12.
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+ ;;
+ ms1)
+ basic_machine=mt-unknown
+ ;;
+
+ # We use `pc' rather than `unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i*86 | x86_64)
+ basic_machine=$basic_machine-pc
+ ;;
+ # Object if more than one company name word.
+ *-*-*)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+ # Recognize the basic CPU types with company name.
+ 580-* \
+ | a29k-* \
+ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \
+ | avr-* | avr32-* \
+ | bfin-* | bs2000-* \
+ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
+ | clipper-* | craynv-* | cydra-* \
+ | d10v-* | d30v-* | dlx-* \
+ | elxsi-* \
+ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+ | h8300-* | h8500-* \
+ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+ | i*86-* | i860-* | i960-* | ia64-* \
+ | ip2k-* | iq2000-* \
+ | lm32-* \
+ | m32c-* | m32r-* | m32rle-* \
+ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \
+ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+ | mips16-* \
+ | mips64-* | mips64el-* \
+ | mips64octeon-* | mips64octeonel-* \
+ | mips64orion-* | mips64orionel-* \
+ | mips64r5900-* | mips64r5900el-* \
+ | mips64vr-* | mips64vrel-* \
+ | mips64vr4100-* | mips64vr4100el-* \
+ | mips64vr4300-* | mips64vr4300el-* \
+ | mips64vr5000-* | mips64vr5000el-* \
+ | mips64vr5900-* | mips64vr5900el-* \
+ | mipsisa32-* | mipsisa32el-* \
+ | mipsisa32r2-* | mipsisa32r2el-* \
+ | mipsisa64-* | mipsisa64el-* \
+ | mipsisa64r2-* | mipsisa64r2el-* \
+ | mipsisa64sb1-* | mipsisa64sb1el-* \
+ | mipsisa64sr71k-* | mipsisa64sr71kel-* \
+ | mipstx39-* | mipstx39el-* \
+ | mmix-* \
+ | mt-* \
+ | msp430-* \
+ | nios-* | nios2-* \
+ | none-* | np1-* | ns16k-* | ns32k-* \
+ | orion-* \
+ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+ | pyramid-* \
+ | romp-* | rs6000-* | rx-* \
+ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+ | sparclite-* \
+ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \
+ | tahoe-* | thumb-* \
+ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* | tile-* \
+ | tron-* \
+ | ubicom32-* \
+ | v850-* | v850e-* | vax-* \
+ | we32k-* \
+ | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
+ | xstormy16-* | xtensa*-* \
+ | ymp-* \
+ | z8k-* | z80-*)
+ ;;
+ # Recognize the basic CPU types without company name, with glob match.
+ xtensa*)
+ basic_machine=$basic_machine-unknown
+ ;;
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 386bsd)
+ basic_machine=i386-unknown
+ os=-bsd
+ ;;
+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+ basic_machine=m68000-att
+ ;;
+ 3b*)
+ basic_machine=we32k-att
+ ;;
+ a29khif)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ abacus)
+ basic_machine=abacus-unknown
+ ;;
+ adobe68k)
+ basic_machine=m68010-adobe
+ os=-scout
+ ;;
+ alliant | fx80)
+ basic_machine=fx80-alliant
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ os=-bsd
+ ;;
+ amd64)
+ basic_machine=x86_64-pc
+ ;;
+ amd64-*)
+ basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ os=-sysv
+ ;;
+ amiga | amiga-*)
+ basic_machine=m68k-unknown
+ ;;
+ amigaos | amigados)
+ basic_machine=m68k-unknown
+ os=-amigaos
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-unknown
+ os=-sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ os=-sysv
+ ;;
+ apollo68bsd)
+ basic_machine=m68k-apollo
+ os=-bsd
+ ;;
+ aros)
+ basic_machine=i386-pc
+ os=-aros
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ os=-aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=-dynix
+ ;;
+ blackfin)
+ basic_machine=bfin-unknown
+ os=-linux
+ ;;
+ blackfin-*)
+ basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ bluegene*)
+ basic_machine=powerpc-ibm
+ os=-cnk
+ ;;
+ c90)
+ basic_machine=c90-cray
+ os=-unicos
+ ;;
+ cegcc)
+ basic_machine=arm-unknown
+ os=-cegcc
+ ;;
+ convex-c1)
+ basic_machine=c1-convex
+ os=-bsd
+ ;;
+ convex-c2)
+ basic_machine=c2-convex
+ os=-bsd
+ ;;
+ convex-c32)
+ basic_machine=c32-convex
+ os=-bsd
+ ;;
+ convex-c34)
+ basic_machine=c34-convex
+ os=-bsd
+ ;;
+ convex-c38)
+ basic_machine=c38-convex
+ os=-bsd
+ ;;
+ cray | j90)
+ basic_machine=j90-cray
+ os=-unicos
+ ;;
+ craynv)
+ basic_machine=craynv-cray
+ os=-unicosmp
+ ;;
+ cr16)
+ basic_machine=cr16-unknown
+ os=-elf
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ ;;
+ crisv32 | crisv32-* | etraxfs*)
+ basic_machine=crisv32-axis
+ ;;
+ cris | cris-* | etrax*)
+ basic_machine=cris-axis
+ ;;
+ crx)
+ basic_machine=crx-unknown
+ os=-elf
+ ;;
+ da30 | da30-*)
+ basic_machine=m68k-da30
+ ;;
+ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ ;;
+ decsystem10* | dec10*)
+ basic_machine=pdp10-dec
+ os=-tops10
+ ;;
+ decsystem20* | dec20*)
+ basic_machine=pdp10-dec
+ os=-tops20
+ ;;
+ delta | 3300 | motorola-3300 | motorola-delta \
+ | 3300-motorola | delta-motorola)
+ basic_machine=m68k-motorola
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ os=-sysv3
+ ;;
+ dicos)
+ basic_machine=i686-pc
+ os=-dicos
+ ;;
+ djgpp)
+ basic_machine=i586-pc
+ os=-msdosdjgpp
+ ;;
+ dpx20 | dpx20-*)
+ basic_machine=rs6000-bull
+ os=-bosx
+ ;;
+ dpx2* | dpx2*-bull)
+ basic_machine=m68k-bull
+ os=-sysv3
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ os=-ebmon
+ ;;
+ elxsi)
+ basic_machine=elxsi-elxsi
+ os=-bsd
+ ;;
+ encore | umax | mmax)
+ basic_machine=ns32k-encore
+ ;;
+ es1800 | OSE68k | ose68k | ose | OSE)
+ basic_machine=m68k-ericsson
+ os=-ose
+ ;;
+ fx2800)
+ basic_machine=i860-alliant
+ ;;
+ genix)
+ basic_machine=ns32k-ns
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ os=-sysv
+ ;;
+ go32)
+ basic_machine=i386-pc
+ os=-go32
+ ;;
+ h3050r* | hiux*)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ os=-hms
+ ;;
+ h8300xray)
+ basic_machine=h8300-hitachi
+ os=-xray
+ ;;
+ h8500hms)
+ basic_machine=h8500-hitachi
+ os=-hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ os=-sysv3
+ ;;
+ hp300-*)
+ basic_machine=m68k-hp
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ os=-bsd
+ ;;
+ hp300hpux)
+ basic_machine=m68k-hp
+ os=-hpux
+ ;;
+ hp3k9[0-9][0-9] | hp9[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k2[0-9][0-9] | hp9k31[0-9])
+ basic_machine=m68000-hp
+ ;;
+ hp9k3[2-9][0-9])
+ basic_machine=m68k-hp
+ ;;
+ hp9k6[0-9][0-9] | hp6[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k7[0-79][0-9] | hp7[0-79][0-9])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k78[0-9] | hp78[0-9])
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][13679] | hp8[0-9][13679])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][0-9] | hp8[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hppa-next)
+ os=-nextstep3
+ ;;
+ hppaosf)
+ basic_machine=hppa1.1-hp
+ os=-osf
+ ;;
+ hppro)
+ basic_machine=hppa1.1-hp
+ os=-proelf
+ ;;
+ i370-ibm* | ibm*)
+ basic_machine=i370-ibm
+ ;;
+# I'm not sure what "Sysv32" means. Should this be sysv3.2?
+ i*86v32)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv32
+ ;;
+ i*86v4*)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv4
+ ;;
+ i*86v)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv
+ ;;
+ i*86sol2)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-solaris2
+ ;;
+ i386mach)
+ basic_machine=i386-mach
+ os=-mach
+ ;;
+ i386-vsta | vsta)
+ basic_machine=i386-unknown
+ os=-vsta
+ ;;
+ iris | iris4d)
+ basic_machine=mips-sgi
+ case $os in
+ -irix*)
+ ;;
+ *)
+ os=-irix4
+ ;;
+ esac
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ os=-sysv
+ ;;
+ m68knommu)
+ basic_machine=m68k-unknown
+ os=-linux
+ ;;
+ m68knommu-*)
+ basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ m88k-omron*)
+ basic_machine=m88k-omron
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ os=-sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ os=-sysv
+ ;;
+ microblaze)
+ basic_machine=microblaze-xilinx
+ ;;
+ mingw32)
+ basic_machine=i386-pc
+ os=-mingw32
+ ;;
+ mingw32ce)
+ basic_machine=arm-unknown
+ os=-mingw32ce
+ ;;
+ miniframe)
+ basic_machine=m68000-convergent
+ ;;
+ *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+ mips3*-*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+ ;;
+ mips3*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+ ;;
+ monitor)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ morphos)
+ basic_machine=powerpc-unknown
+ os=-morphos
+ ;;
+ msdos)
+ basic_machine=i386-pc
+ os=-msdos
+ ;;
+ ms1-*)
+ basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+ ;;
+ mvs)
+ basic_machine=i370-ibm
+ os=-mvs
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ os=-sysv4
+ ;;
+ netbsd386)
+ basic_machine=i386-unknown
+ os=-netbsd
+ ;;
+ netwinder)
+ basic_machine=armv4l-rebel
+ os=-linux
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ os=-newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ os=-newsos
+ ;;
+ news-3600 | risc-news)
+ basic_machine=mips-sony
+ os=-newsos
+ ;;
+ necv70)
+ basic_machine=v70-nec
+ os=-sysv
+ ;;
+ next | m*-next )
+ basic_machine=m68k-next
+ case $os in
+ -nextstep* )
+ ;;
+ -ns2*)
+ os=-nextstep2
+ ;;
+ *)
+ os=-nextstep3
+ ;;
+ esac
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ os=-cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ os=-cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ os=-nindy
+ ;;
+ mon960)
+ basic_machine=i960-intel
+ os=-mon960
+ ;;
+ nonstopux)
+ basic_machine=mips-compaq
+ os=-nonstopux
+ ;;
+ np1)
+ basic_machine=np1-gould
+ ;;
+ nsr-tandem)
+ basic_machine=nsr-tandem
+ ;;
+ op50n-* | op60c-*)
+ basic_machine=hppa1.1-oki
+ os=-proelf
+ ;;
+ openrisc | openrisc-*)
+ basic_machine=or32-unknown
+ ;;
+ os400)
+ basic_machine=powerpc-ibm
+ os=-os400
+ ;;
+ OSE68000 | ose68000)
+ basic_machine=m68000-ericsson
+ os=-ose
+ ;;
+ os68k)
+ basic_machine=m68k-none
+ os=-os68k
+ ;;
+ pa-hitachi)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ os=-osf
+ ;;
+ parisc)
+ basic_machine=hppa-unknown
+ os=-linux
+ ;;
+ parisc-*)
+ basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ pbd)
+ basic_machine=sparc-tti
+ ;;
+ pbb)
+ basic_machine=m68k-tti
+ ;;
+ pc532 | pc532-*)
+ basic_machine=ns32k-pc532
+ ;;
+ pc98)
+ basic_machine=i386-pc
+ ;;
+ pc98-*)
+ basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium | p5 | k5 | k6 | nexgen | viac3)
+ basic_machine=i586-pc
+ ;;
+ pentiumpro | p6 | 6x86 | athlon | athlon_*)
+ basic_machine=i686-pc
+ ;;
+ pentiumii | pentium2 | pentiumiii | pentium3)
+ basic_machine=i686-pc
+ ;;
+ pentium4)
+ basic_machine=i786-pc
+ ;;
+ pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+ basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumpro-* | p6-* | 6x86-* | athlon-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium4-*)
+ basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pn)
+ basic_machine=pn-gould
+ ;;
+ power) basic_machine=power-ibm
+ ;;
+ ppc) basic_machine=powerpc-unknown
+ ;;
+ ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppcle | powerpclittle | ppc-le | powerpc-little)
+ basic_machine=powerpcle-unknown
+ ;;
+ ppcle-* | powerpclittle-*)
+ basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64) basic_machine=powerpc64-unknown
+ ;;
+ ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+ basic_machine=powerpc64le-unknown
+ ;;
+ ppc64le-* | powerpc64little-*)
+ basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ps2)
+ basic_machine=i386-ibm
+ ;;
+ pw32)
+ basic_machine=i586-unknown
+ os=-pw32
+ ;;
+ rdos)
+ basic_machine=i386-pc
+ os=-rdos
+ ;;
+ rom68k)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ rm[46]00)
+ basic_machine=mips-siemens
+ ;;
+ rtpc | rtpc-*)
+ basic_machine=romp-ibm
+ ;;
+ s390 | s390-*)
+ basic_machine=s390-ibm
+ ;;
+ s390x | s390x-*)
+ basic_machine=s390x-ibm
+ ;;
+ sa29200)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ sb1)
+ basic_machine=mipsisa64sb1-unknown
+ ;;
+ sb1el)
+ basic_machine=mipsisa64sb1el-unknown
+ ;;
+ sde)
+ basic_machine=mipsisa32-sde
+ os=-elf
+ ;;
+ sei)
+ basic_machine=mips-sei
+ os=-seiux
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ ;;
+ sh)
+ basic_machine=sh-hitachi
+ os=-hms
+ ;;
+ sh5el)
+ basic_machine=sh5le-unknown
+ ;;
+ sh64)
+ basic_machine=sh64-unknown
+ ;;
+ sparclite-wrs | simso-wrs)
+ basic_machine=sparclite-wrs
+ os=-vxworks
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ os=-sysv2
+ ;;
+ spur)
+ basic_machine=spur-unknown
+ ;;
+ st2000)
+ basic_machine=m68k-tandem
+ ;;
+ stratus)
+ basic_machine=i860-stratus
+ os=-sysv4
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ os=-sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ os=-sunos4
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ os=-sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ os=-sunos4
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ os=-sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ os=-sunos4
+ ;;
+ sun4sol2)
+ basic_machine=sparc-sun
+ os=-solaris2
+ ;;
+ sun3 | sun3-*)
+ basic_machine=m68k-sun
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ ;;
+ sv1)
+ basic_machine=sv1-cray
+ os=-unicos
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ os=-dynix
+ ;;
+ t3e)
+ basic_machine=alphaev5-cray
+ os=-unicos
+ ;;
+ t90)
+ basic_machine=t90-cray
+ os=-unicos
+ ;;
+ tic54x | c54x*)
+ basic_machine=tic54x-unknown
+ os=-coff
+ ;;
+ tic55x | c55x*)
+ basic_machine=tic55x-unknown
+ os=-coff
+ ;;
+ tic6x | c6x*)
+ basic_machine=tic6x-unknown
+ os=-coff
+ ;;
+ tile*)
+ basic_machine=tile-unknown
+ os=-linux-gnu
+ ;;
+ tx39)
+ basic_machine=mipstx39-unknown
+ ;;
+ tx39el)
+ basic_machine=mipstx39el-unknown
+ ;;
+ toad1)
+ basic_machine=pdp10-xkl
+ os=-tops20
+ ;;
+ tower | tower-32)
+ basic_machine=m68k-ncr
+ ;;
+ tpf)
+ basic_machine=s390x-ibm
+ os=-tpf
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ os=-sym1
+ ;;
+ v810 | necv810)
+ basic_machine=v810-nec
+ os=-none
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ os=-sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ os=-vms
+ ;;
+ vpp*|vx|vx-*)
+ basic_machine=f301-fujitsu
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ os=-vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ os=-vxworks
+ ;;
+ vxworks29k)
+ basic_machine=a29k-wrs
+ os=-vxworks
+ ;;
+ w65*)
+ basic_machine=w65-wdc
+ os=-none
+ ;;
+ w89k-*)
+ basic_machine=hppa1.1-winbond
+ os=-proelf
+ ;;
+ xbox)
+ basic_machine=i686-pc
+ os=-mingw32
+ ;;
+ xps | xps100)
+ basic_machine=xps100-honeywell
+ ;;
+ ymp)
+ basic_machine=ymp-cray
+ os=-unicos
+ ;;
+ z8k-*-coff)
+ basic_machine=z8k-unknown
+ os=-sim
+ ;;
+ z80-*-coff)
+ basic_machine=z80-unknown
+ os=-sim
+ ;;
+ none)
+ basic_machine=none-none
+ os=-none
+ ;;
+
+# Here we handle the default manufacturer of certain CPU types. It is in
+# some cases the only manufacturer, in others, it is the most popular.
+ w89k)
+ basic_machine=hppa1.1-winbond
+ ;;
+ op50n)
+ basic_machine=hppa1.1-oki
+ ;;
+ op60c)
+ basic_machine=hppa1.1-oki
+ ;;
+ romp)
+ basic_machine=romp-ibm
+ ;;
+ mmix)
+ basic_machine=mmix-knuth
+ ;;
+ rs6000)
+ basic_machine=rs6000-ibm
+ ;;
+ vax)
+ basic_machine=vax-dec
+ ;;
+ pdp10)
+ # there are many clones, so DEC is not a safe bet
+ basic_machine=pdp10-unknown
+ ;;
+ pdp11)
+ basic_machine=pdp11-dec
+ ;;
+ we32k)
+ basic_machine=we32k-att
+ ;;
+ sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
+ basic_machine=sh-unknown
+ ;;
+ sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
+ basic_machine=sparc-sun
+ ;;
+ cydra)
+ basic_machine=cydra-cydrome
+ ;;
+ orion)
+ basic_machine=orion-highlevel
+ ;;
+ orion105)
+ basic_machine=clipper-highlevel
+ ;;
+ mac | mpw | mac-mpw)
+ basic_machine=m68k-apple
+ ;;
+ pmac | pmac-mpw)
+ basic_machine=powerpc-apple
+ ;;
+ *-unknown)
+ # Make sure to match an already-canonicalized machine name.
+ ;;
+ *)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+ *-digital*)
+ basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+ ;;
+ *-commodore*)
+ basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+ ;;
+ *)
+ ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+ # First match some system type aliases
+ # that might get confused with valid system types.
+ # -solaris* is a basic system type, with this one exception.
+ -auroraux)
+ os=-auroraux
+ ;;
+ -solaris1 | -solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ ;;
+ -solaris)
+ os=-solaris2
+ ;;
+ -svr4*)
+ os=-sysv4
+ ;;
+ -unixware*)
+ os=-sysv4.2uw
+ ;;
+ -gnu/linux*)
+ os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+ ;;
+ # First accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST END IN A *, to match a version number.
+ # -sysv* is not here because it comes later, after sysvr4.
+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
+ | -sym* | -kopensolaris* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+ | -aos* | -aros* \
+ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+ | -openbsd* | -solidbsd* \
+ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+ | -chorusos* | -chorusrdb* | -cegcc* \
+ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+ | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
+ | -uxpv* | -beos* | -mpeix* | -udk* \
+ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*)
+ # Remember, each alternative MUST END IN *, to match a version number.
+ ;;
+ -qnx*)
+ case $basic_machine in
+ x86-* | i*86-*)
+ ;;
+ *)
+ os=-nto$os
+ ;;
+ esac
+ ;;
+ -nto-qnx*)
+ ;;
+ -nto*)
+ os=`echo $os | sed -e 's|nto|nto-qnx|'`
+ ;;
+ -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+ ;;
+ -mac*)
+ os=`echo $os | sed -e 's|mac|macos|'`
+ ;;
+ -linux-dietlibc)
+ os=-linux-dietlibc
+ ;;
+ -linux*)
+ os=`echo $os | sed -e 's|linux|linux-gnu|'`
+ ;;
+ -sunos5*)
+ os=`echo $os | sed -e 's|sunos5|solaris2|'`
+ ;;
+ -sunos6*)
+ os=`echo $os | sed -e 's|sunos6|solaris3|'`
+ ;;
+ -opened*)
+ os=-openedition
+ ;;
+ -os400*)
+ os=-os400
+ ;;
+ -wince*)
+ os=-wince
+ ;;
+ -osfrose*)
+ os=-osfrose
+ ;;
+ -osf*)
+ os=-osf
+ ;;
+ -utek*)
+ os=-bsd
+ ;;
+ -dynix*)
+ os=-bsd
+ ;;
+ -acis*)
+ os=-aos
+ ;;
+ -atheos*)
+ os=-atheos
+ ;;
+ -syllable*)
+ os=-syllable
+ ;;
+ -386bsd)
+ os=-bsd
+ ;;
+ -ctix* | -uts*)
+ os=-sysv
+ ;;
+ -nova*)
+ os=-rtmk-nova
+ ;;
+ -ns2 )
+ os=-nextstep2
+ ;;
+ -nsk*)
+ os=-nsk
+ ;;
+ # Preserve the version number of sinix5.
+ -sinix5.*)
+ os=`echo $os | sed -e 's|sinix|sysv|'`
+ ;;
+ -sinix*)
+ os=-sysv4
+ ;;
+ -tpf*)
+ os=-tpf
+ ;;
+ -triton*)
+ os=-sysv3
+ ;;
+ -oss*)
+ os=-sysv3
+ ;;
+ -svr4)
+ os=-sysv4
+ ;;
+ -svr3)
+ os=-sysv3
+ ;;
+ -sysvr4)
+ os=-sysv4
+ ;;
+ # This must come after -sysvr4.
+ -sysv*)
+ ;;
+ -ose*)
+ os=-ose
+ ;;
+ -es1800*)
+ os=-ose
+ ;;
+ -xenix)
+ os=-xenix
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ os=-mint
+ ;;
+ -aros*)
+ os=-aros
+ ;;
+ -kaos*)
+ os=-kaos
+ ;;
+ -zvmoe)
+ os=-zvmoe
+ ;;
+ -dicos*)
+ os=-dicos
+ ;;
+ -none)
+ ;;
+ *)
+ # Get rid of the `-' at the beginning of $os.
+ os=`echo $os | sed 's/[^-]*-//'`
+ echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system. Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+ score-*)
+ os=-elf
+ ;;
+ spu-*)
+ os=-elf
+ ;;
+ *-acorn)
+ os=-riscix1.2
+ ;;
+ arm*-rebel)
+ os=-linux
+ ;;
+ arm*-semi)
+ os=-aout
+ ;;
+ c4x-* | tic4x-*)
+ os=-coff
+ ;;
+ # This must come before the *-dec entry.
+ pdp10-*)
+ os=-tops20
+ ;;
+ pdp11-*)
+ os=-none
+ ;;
+ *-dec | vax-*)
+ os=-ultrix4.2
+ ;;
+ m68*-apollo)
+ os=-domain
+ ;;
+ i386-sun)
+ os=-sunos4.0.2
+ ;;
+ m68000-sun)
+ os=-sunos3
+ # This also exists in the configure program, but was not the
+ # default.
+ # os=-sunos4
+ ;;
+ m68*-cisco)
+ os=-aout
+ ;;
+ mep-*)
+ os=-elf
+ ;;
+ mips*-cisco)
+ os=-elf
+ ;;
+ mips*-*)
+ os=-elf
+ ;;
+ or32-*)
+ os=-coff
+ ;;
+ *-tti) # must be before sparc entry or we get the wrong os.
+ os=-sysv3
+ ;;
+ sparc-* | *-sun)
+ os=-sunos4.1.1
+ ;;
+ *-be)
+ os=-beos
+ ;;
+ *-haiku)
+ os=-haiku
+ ;;
+ *-ibm)
+ os=-aix
+ ;;
+ *-knuth)
+ os=-mmixware
+ ;;
+ *-wec)
+ os=-proelf
+ ;;
+ *-winbond)
+ os=-proelf
+ ;;
+ *-oki)
+ os=-proelf
+ ;;
+ *-hp)
+ os=-hpux
+ ;;
+ *-hitachi)
+ os=-hiux
+ ;;
+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+ os=-sysv
+ ;;
+ *-cbm)
+ os=-amigaos
+ ;;
+ *-dg)
+ os=-dgux
+ ;;
+ *-dolphin)
+ os=-sysv3
+ ;;
+ m68k-ccur)
+ os=-rtu
+ ;;
+ m88k-omron*)
+ os=-luna
+ ;;
+ *-next )
+ os=-nextstep
+ ;;
+ *-sequent)
+ os=-ptx
+ ;;
+ *-crds)
+ os=-unos
+ ;;
+ *-ns)
+ os=-genix
+ ;;
+ i370-*)
+ os=-mvs
+ ;;
+ *-next)
+ os=-nextstep3
+ ;;
+ *-gould)
+ os=-sysv
+ ;;
+ *-highlevel)
+ os=-bsd
+ ;;
+ *-encore)
+ os=-bsd
+ ;;
+ *-sgi)
+ os=-irix
+ ;;
+ *-siemens)
+ os=-sysv4
+ ;;
+ *-masscomp)
+ os=-rtu
+ ;;
+ f30[01]-fujitsu | f700-fujitsu)
+ os=-uxpv
+ ;;
+ *-rom68k)
+ os=-coff
+ ;;
+ *-*bug)
+ os=-coff
+ ;;
+ *-apple)
+ os=-macos
+ ;;
+ *-atari*)
+ os=-mint
+ ;;
+ *)
+ os=-none
+ ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer. We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+ *-unknown)
+ case $os in
+ -riscix*)
+ vendor=acorn
+ ;;
+ -sunos*)
+ vendor=sun
+ ;;
+ -cnk*|-aix*)
+ vendor=ibm
+ ;;
+ -beos*)
+ vendor=be
+ ;;
+ -hpux*)
+ vendor=hp
+ ;;
+ -mpeix*)
+ vendor=hp
+ ;;
+ -hiux*)
+ vendor=hitachi
+ ;;
+ -unos*)
+ vendor=crds
+ ;;
+ -dgux*)
+ vendor=dg
+ ;;
+ -luna*)
+ vendor=omron
+ ;;
+ -genix*)
+ vendor=ns
+ ;;
+ -mvs* | -opened*)
+ vendor=ibm
+ ;;
+ -os400*)
+ vendor=ibm
+ ;;
+ -ptx*)
+ vendor=sequent
+ ;;
+ -tpf*)
+ vendor=ibm
+ ;;
+ -vxsim* | -vxworks* | -windiss*)
+ vendor=wrs
+ ;;
+ -aux*)
+ vendor=apple
+ ;;
+ -hms*)
+ vendor=hitachi
+ ;;
+ -mpw* | -macos*)
+ vendor=apple
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ vendor=atari
+ ;;
+ -vos*)
+ vendor=stratus
+ ;;
+ esac
+ basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+ ;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
--- /dev/null
+AC_PREREQ([2.61])
+AC_INIT([mech_eap], [0.1], [bugs@project-moonshot.org])
+dnl AC_CONFIG_MACRO_DIR([m4])
+AM_INIT_AUTOMAKE
+LT_PREREQ([2.2])
+LT_INIT([dlopen disable-static])
+
+AC_PROG_CC
+AC_PROG_CXX
+AC_CONFIG_HEADERS([config.h])
+
+dnl Check if we're on Solaris and set CFLAGS accordingly
+dnl AC_CANONICAL_TARGET
+dnl case "${target_os}" in
+dnl solaris*)
+dnl TARGET_CFLAGS="-DSYS_SOLARIS9 -D_POSIX_PTHREAD_SEMANTICS"
+dnl if test "$GCC" != yes ; then
+dnl TARGET_CFLAGS="$TARGET_CFLAGS -mt"
+dnl else
+dnl TARGET_CFLAGS="$TARGET_CFLAGS -pthreads"
+dnl fi
+dnl TARGET_LDFLAGS="-lpthread -lsocket -lnsl"
+dnl ;;
+dnl *)
+dnl TARGET_CFLAGS="-Wall -pedantic -pthread"
+dnl TARGET_LDFLAGS=""
+dnl esac
+
+reauth=no
+AC_ARG_ENABLE(reauth,
+ [ --enable-reauth whether to enable fast reauthentication protocol: yes/no; default no ],
+ [ if test "x$enableval" = "xyes" -o "x$enableval" = "xno" ; then
+ reauth=$enableval
+ else
+ echo "--enable-reauth argument must be yes or no"
+ exit -1
+ fi
+ ])
+
+if test "x$reauth" = "xyes" ; then
+ echo "Fast reauthentication protocol enabled"
+ TARGET_CFLAGS="$TARGET_CFLAGS -DGSSEAP_ENABLE_REAUTH"
+fi
+AM_CONDITIONAL(GSSEAP_ENABLE_REAUTH, test "$reauth" = "yes")
+
+AC_SUBST(TARGET_CFLAGS)
+AC_SUBST(TARGET_LDFLAGS)
+AX_CHECK_KRB5
+AX_CHECK_EAP
+AX_CHECK_SHIBSP
+AX_CHECK_SHIBRESOLVER
+AX_CHECK_RADSEC
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Determine remaining lifetime of a context handle.
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32
+gss_context_time(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ OM_uint32 *time_rec)
+{
+ OM_uint32 major;
+
+ if (ctx == GSS_C_NO_CONTEXT) {
+ *minor = EINVAL;
+ return GSS_S_NO_CONTEXT;
+ }
+
+ *minor = 0;
+
+ GSSEAP_MUTEX_LOCK(&ctx->mutex);
+
+ if (!CTX_IS_ESTABLISHED(ctx)) {
+ *minor = GSSEAP_CONTEXT_INCOMPLETE;
+ major = GSS_S_NO_CONTEXT;
+ goto cleanup;
+ }
+
+ major = gssEapContextTime(minor, ctx, time_rec);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+cleanup:
+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
+
+ return major;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Wrapper for removing a name attribute.
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32
+gss_delete_name_attribute(OM_uint32 *minor,
+ gss_name_t name,
+ gss_buffer_t attr)
+{
+ OM_uint32 major;
+
+ *minor = 0;
+
+ if (name == GSS_C_NO_NAME) {
+ *minor = EINVAL;
+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
+ }
+
+ GSSEAP_MUTEX_LOCK(&name->mutex);
+
+ major = gssEapDeleteNameAttribute(minor, name, attr);
+
+ GSSEAP_MUTEX_UNLOCK(&name->mutex);
+
+ return major;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Release a context handle.
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32
+gss_delete_sec_context(OM_uint32 *minor,
+ gss_ctx_id_t *context_handle,
+ gss_buffer_t output_token)
+{
+ OM_uint32 major;
+ gss_ctx_id_t ctx = *context_handle;
+
+ *minor = 0;
+
+ if (output_token != GSS_C_NO_BUFFER) {
+ output_token->length = 0;
+ output_token->value = NULL;
+ }
+
+ if (ctx == GSS_C_NO_CONTEXT)
+ return GSS_S_COMPLETE;
+
+ GSSEAP_MUTEX_LOCK(&ctx->mutex);
+
+ if (output_token != GSS_C_NO_BUFFER) {
+ gss_iov_buffer_desc iov[2];
+
+ iov[0].type = GSS_IOV_BUFFER_TYPE_DATA;
+ iov[0].buffer.value = NULL;
+ iov[0].buffer.length = 0;
+
+ iov[1].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_FLAG_ALLOCATE;
+ iov[1].buffer.value = NULL;
+ iov[1].buffer.length = 0;
+
+ major = gssEapWrapOrGetMIC(minor, ctx, FALSE, FALSE,
+ iov, 2, TOK_TYPE_DELETE_CONTEXT);
+ if (GSS_ERROR(major)) {
+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
+ return major;
+ }
+ }
+
+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
+
+ return gssEapReleaseContext(minor, context_handle);
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Wrapper for "displaying" (returning string representation of) a name.
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32
+gss_display_name(OM_uint32 *minor,
+ gss_name_t name,
+ gss_buffer_t output_name_buffer,
+ gss_OID *output_name_type)
+{
+ /* Lock not required as long as attributes are not used */
+ return gssEapDisplayName(minor, name, output_name_buffer,
+ output_name_type);
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Parameterized version of gss_display_name(), currently unimplemented.
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32
+gss_display_name_ext(OM_uint32 *minor,
+ gss_name_t name,
+ gss_OID display_as_name_type,
+ gss_buffer_t display_name)
+{
+ *minor = 0;
+
+ display_name->length = 0;
+ display_name->value = NULL;
+
+ return GSS_S_UNAVAILABLE;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Function for converting mechanism error codes to strings.
+ */
+
+#include "gssapiP_eap.h"
+
+static GSSEAP_THREAD_ONCE gssEapStatusInfoKeyOnce = GSSEAP_ONCE_INITIALIZER;
+static GSSEAP_THREAD_KEY gssEapStatusInfoKey;
+
+struct gss_eap_status_info {
+ OM_uint32 code;
+ char *message;
+ struct gss_eap_status_info *next;
+};
+
+static void
+destroyStatusInfo(void *arg)
+{
+ struct gss_eap_status_info *p = arg, *next;
+
+ for (p = arg; p != NULL; p = next) {
+ next = p->next;
+ GSSEAP_FREE(p->message);
+ GSSEAP_FREE(p);
+ }
+}
+
+static void
+createStatusInfoKey(void)
+{
+ GSSEAP_KEY_CREATE(&gssEapStatusInfoKey, destroyStatusInfo);
+}
+
+/*
+ * Associate a message with a mechanism (minor) status code. This function
+ * takes ownership of the message regardless of success. The message must
+ * be explicitly cleared, if required, so it is suggested that a specific
+ * minor code is either always or never associated with a message, to avoid
+ * dangling (and potentially confusing) error messages.
+ */
+static void
+saveStatusInfoNoCopy(OM_uint32 minor, char *message)
+{
+ struct gss_eap_status_info **next = NULL, *p;
+
+ GSSEAP_ONCE(&gssEapStatusInfoKeyOnce, createStatusInfoKey);
+
+ p = GSSEAP_GETSPECIFIC(gssEapStatusInfoKey);
+ for (; p != NULL; p = p->next) {
+ if (p->code == minor) {
+ /* Set message in-place */
+ if (p->message != NULL)
+ GSSEAP_FREE(p->message);
+ p->message = message;
+ return;
+ }
+ next = &p->next;
+ }
+
+ p = GSSEAP_CALLOC(1, sizeof(*p));
+ if (p == NULL) {
+ if (message != NULL)
+ GSSEAP_FREE(message);
+ return;
+ }
+
+ p->code = minor;
+ p->message = message;
+
+ if (p != NULL)
+ *next = p;
+ else
+ GSSEAP_SETSPECIFIC(gssEapStatusInfoKey, p);
+}
+
+static const char *
+getStatusInfo(OM_uint32 minor)
+{
+ struct gss_eap_status_info *p;
+
+ GSSEAP_ONCE(&gssEapStatusInfoKeyOnce, createStatusInfoKey);
+
+ for (p = GSSEAP_GETSPECIFIC(gssEapStatusInfoKey);
+ p != NULL;
+ p = p->next) {
+ if (p->code == minor)
+ return p->message;
+ }
+
+ return NULL;
+}
+
+void
+gssEapSaveStatusInfo(OM_uint32 minor, const char *format, ...)
+{
+ char *s;
+ int n;
+ va_list ap;
+
+ va_start(ap, format);
+ n = vasprintf(&s, format, ap);
+ va_end(ap);
+
+ if (n >= 0)
+ saveStatusInfoNoCopy(minor, s);
+}
+
+OM_uint32
+gss_display_status(OM_uint32 *minor,
+ OM_uint32 status_value,
+ int status_type,
+ gss_OID mech_type,
+ OM_uint32 *message_context,
+ gss_buffer_t status_string)
+{
+ OM_uint32 major;
+ krb5_context krbContext = NULL;
+ const char *errMsg;
+
+ status_string->length = 0;
+ status_string->value = NULL;
+
+ if (!gssEapIsMechanismOid(mech_type)) {
+ *minor = GSSEAP_WRONG_MECH;
+ return GSS_S_BAD_MECH;
+ }
+
+ if (status_type != GSS_C_MECH_CODE) {
+ /* we rely on the mechglue for GSS_C_GSS_CODE */
+ *minor = 0;
+ return GSS_S_BAD_STATUS;
+ }
+
+ errMsg = getStatusInfo(status_value);
+ if (errMsg == NULL) {
+ GSSEAP_KRB_INIT(&krbContext);
+
+ /* Try the com_err message */
+ errMsg = krb5_get_error_message(krbContext, status_value);
+ }
+
+ if (errMsg != NULL) {
+ major = makeStringBuffer(minor, errMsg, status_string);
+ } else {
+ major = GSS_S_COMPLETE;
+ *minor = 0;
+ }
+
+ if (krbContext != NULL)
+ krb5_free_error_message(krbContext, errMsg);
+
+ return major;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Duplicate a name.
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32
+gss_duplicate_name(OM_uint32 *minor,
+ const gss_name_t input_name,
+ gss_name_t *dest_name)
+{
+ OM_uint32 major;
+
+ *minor = 0;
+
+ if (input_name == GSS_C_NO_NAME) {
+ *minor = EINVAL;
+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
+ }
+
+ GSSEAP_MUTEX_LOCK(&input_name->mutex);
+
+ major = gssEapDuplicateName(minor, input_name, dest_name);
+
+ GSSEAP_MUTEX_UNLOCK(&input_name->mutex);
+
+ return major;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Initialisation and finalise functions.
+ */
+
+#include "gssapiP_eap.h"
+
+static OM_uint32
+eapPeerRegisterMethods(OM_uint32 *minor)
+{
+ OM_uint32 ret = 0;
+
+#ifdef EAP_MD5
+ if (ret == 0)
+ ret = eap_peer_md5_register();
+#endif /* EAP_MD5 */
+
+#ifdef EAP_TLS
+ if (ret == 0)
+ ret = eap_peer_tls_register();
+#endif /* EAP_TLS */
+
+#ifdef EAP_MSCHAPv2
+ if (ret == 0)
+ ret = eap_peer_mschapv2_register();
+#endif /* EAP_MSCHAPv2 */
+
+#ifdef EAP_PEAP
+ if (ret == 0)
+ ret = eap_peer_peap_register();
+#endif /* EAP_PEAP */
+
+#ifdef EAP_TTLS
+ if (ret == 0)
+ ret = eap_peer_ttls_register();
+#endif /* EAP_TTLS */
+
+#ifdef EAP_GTC
+ if (ret == 0)
+ ret = eap_peer_gtc_register();
+#endif /* EAP_GTC */
+
+#ifdef EAP_OTP
+ if (ret == 0)
+ ret = eap_peer_otp_register();
+#endif /* EAP_OTP */
+
+#ifdef EAP_SIM
+ if (ret == 0)
+ ret = eap_peer_sim_register();
+#endif /* EAP_SIM */
+
+#ifdef EAP_LEAP
+ if (ret == 0)
+ ret = eap_peer_leap_register();
+#endif /* EAP_LEAP */
+
+#ifdef EAP_PSK
+ if (ret == 0)
+ ret = eap_peer_psk_register();
+#endif /* EAP_PSK */
+
+#ifdef EAP_AKA
+ if (ret == 0)
+ ret = eap_peer_aka_register();
+#endif /* EAP_AKA */
+
+#ifdef EAP_AKA_PRIME
+ if (ret == 0)
+ ret = eap_peer_aka_prime_register();
+#endif /* EAP_AKA_PRIME */
+
+#ifdef EAP_FAST
+ if (ret == 0)
+ ret = eap_peer_fast_register();
+#endif /* EAP_FAST */
+
+#ifdef EAP_PAX
+ if (ret == 0)
+ ret = eap_peer_pax_register();
+#endif /* EAP_PAX */
+
+#ifdef EAP_SAKE
+ if (ret == 0)
+ ret = eap_peer_sake_register();
+#endif /* EAP_SAKE */
+
+#ifdef EAP_GPSK
+ if (ret == 0)
+ ret = eap_peer_gpsk_register();
+#endif /* EAP_GPSK */
+
+#ifdef EAP_WSC
+ if (ret == 0)
+ ret = eap_peer_wsc_register();
+#endif /* EAP_WSC */
+
+#ifdef EAP_IKEV2
+ if (ret == 0)
+ ret = eap_peer_ikev2_register();
+#endif /* EAP_IKEV2 */
+
+#ifdef EAP_VENDOR_TEST
+ if (ret == 0)
+ ret = eap_peer_vendor_test_register();
+#endif /* EAP_VENDOR_TEST */
+
+#ifdef EAP_TNC
+ if (ret == 0)
+ ret = eap_peer_tnc_register();
+#endif /* EAP_TNC */
+
+ if (ret == 0)
+ return GSS_S_COMPLETE;
+
+ *minor = GSSEAP_LIBEAP_INIT_FAILURE;
+ return GSS_S_FAILURE;
+}
+
+static OM_uint32
+gssEapInitLibEap(OM_uint32 *minor)
+{
+ return eapPeerRegisterMethods(minor);
+}
+
+static OM_uint32
+gssEapInitLibRadsec(OM_uint32 *minor)
+{
+ if (0) {
+ *minor = GSSEAP_RADSEC_INIT_FAILURE;
+ return GSS_S_FAILURE;
+ }
+
+ return GSS_S_COMPLETE;
+}
+
+static void gssEapInitiatorInit(void) __attribute__((constructor));
+static void gssEapFinalize(void) __attribute__((destructor));
+
+static void
+gssEapInitiatorInit(void)
+{
+ OM_uint32 major, minor;
+
+ initialize_eapg_error_table();
+ initialize_rse_error_table();
+
+ major = gssEapInitLibEap(&minor);
+ assert(major == GSS_S_COMPLETE);
+
+ major = gssEapInitLibRadsec(&minor);
+ assert(major == GSS_S_COMPLETE);
+
+#ifdef GSSEAP_ENABLE_REAUTH
+ major = gssEapReauthInitialize(&minor);
+ assert(major == GSS_S_COMPLETE);
+#endif
+}
+
+static void
+gssEapFinalize(void)
+{
+ OM_uint32 minor;
+
+ gssEapAttrProvidersFinalize(&minor);
+ eap_peer_unregister_methods();
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Serialise a name.
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32
+gss_export_name(OM_uint32 *minor,
+ const gss_name_t input_name,
+ gss_buffer_t exported_name)
+{
+ OM_uint32 major;
+
+ *minor = 0;
+
+ if (input_name == GSS_C_NO_NAME) {
+ *minor = EINVAL;
+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
+ }
+
+ GSSEAP_MUTEX_LOCK(&input_name->mutex);
+
+ major = gssEapExportName(minor, input_name, exported_name);
+
+ GSSEAP_MUTEX_UNLOCK(&input_name->mutex);
+
+ return major;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Serialise a name and its attributes.
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32
+gss_export_name_composite(OM_uint32 *minor,
+ gss_name_t input_name,
+ gss_buffer_t exported_name)
+{
+ OM_uint32 major;
+
+ *minor = 0;
+
+ if (input_name == GSS_C_NO_NAME) {
+ *minor = EINVAL;
+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
+ }
+
+ GSSEAP_MUTEX_LOCK(&input_name->mutex);
+
+ major = gssEapExportNameInternal(minor, input_name, exported_name,
+ EXPORT_NAME_FLAG_OID |
+ EXPORT_NAME_FLAG_COMPOSITE);
+
+ GSSEAP_MUTEX_UNLOCK(&input_name->mutex);
+
+ return major;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Serialise a security context. On the acceptor, this may be partially
+ * established.
+ */
+
+#include "gssapiP_eap.h"
+
+static OM_uint32
+gssEapExportPartialContext(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ gss_buffer_t token)
+{
+ OM_uint32 major, tmpMinor;
+ size_t length, serverLen = 0;
+ unsigned char *p;
+ char serverBuf[MAXHOSTNAMELEN];
+
+ if (ctx->acceptorCtx.radConn != NULL) {
+ if (rs_conn_get_current_server(ctx->acceptorCtx.radConn,
+ serverBuf, sizeof(serverBuf)) != 0) {
+ return gssEapRadiusMapError(minor,
+ rs_err_conn_pop(ctx->acceptorCtx.radConn));
+ }
+ serverLen = strlen(serverBuf);
+ }
+
+ length = 4 + serverLen + 4 + ctx->acceptorCtx.state.length;
+
+ token->value = GSSEAP_MALLOC(length);
+ if (token->value == NULL) {
+ major = GSS_S_FAILURE;
+ *minor = ENOMEM;
+ goto cleanup;
+ }
+ token->length = length;
+
+ p = (unsigned char *)token->value;
+
+ store_uint32_be(serverLen, p);
+ p += 4;
+ if (serverLen != 0) {
+ memcpy(p, serverBuf, serverLen);
+ p += serverLen;
+ }
+
+ store_uint32_be(ctx->acceptorCtx.state.length, p);
+ p += 4;
+ if (ctx->acceptorCtx.state.length != 0) {
+ memcpy(p, ctx->acceptorCtx.state.value,
+ ctx->acceptorCtx.state.length);
+ p += ctx->acceptorCtx.state.length;
+ }
+
+ assert(p == (unsigned char *)token->value + token->length);
+
+ major = GSS_S_COMPLETE;
+ *minor = 0;
+
+cleanup:
+ if (GSS_ERROR(major))
+ gss_release_buffer(&tmpMinor, token);
+
+ return major;
+}
+
+static OM_uint32
+gssEapExportSecContext(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ gss_buffer_t token)
+{
+ OM_uint32 major, tmpMinor;
+ size_t length;
+ gss_buffer_desc initiatorName = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc acceptorName = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc partialCtx = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc key;
+ unsigned char *p;
+
+ if ((CTX_IS_INITIATOR(ctx) && !CTX_IS_ESTABLISHED(ctx)) ||
+ ctx->mechanismUsed == GSS_C_NO_OID) {
+ *minor = GSSEAP_CONTEXT_INCOMPLETE;
+ return GSS_S_NO_CONTEXT;
+ }
+
+ key.length = KRB_KEY_LENGTH(&ctx->rfc3961Key);
+ key.value = KRB_KEY_DATA(&ctx->rfc3961Key);
+
+ if (ctx->initiatorName != GSS_C_NO_NAME) {
+ major = gssEapExportNameInternal(minor, ctx->initiatorName,
+ &initiatorName,
+ EXPORT_NAME_FLAG_COMPOSITE);
+ if (GSS_ERROR(major))
+ goto cleanup;
+ }
+ if (ctx->acceptorName != GSS_C_NO_NAME) {
+ major = gssEapExportNameInternal(minor, ctx->acceptorName,
+ &acceptorName,
+ EXPORT_NAME_FLAG_COMPOSITE);
+ if (GSS_ERROR(major))
+ goto cleanup;
+ }
+
+ /*
+ * The partial context is only transmitted for unestablished acceptor
+ * contexts.
+ */
+ if (!CTX_IS_INITIATOR(ctx) && !CTX_IS_ESTABLISHED(ctx)) {
+ assert((ctx->flags & CTX_FLAG_KRB_REAUTH_GSS) == 0);
+
+ major = gssEapExportPartialContext(minor, ctx, &partialCtx);
+ if (GSS_ERROR(major))
+ goto cleanup;
+ }
+
+ length = 16; /* version, state, flags, */
+ length += 4 + ctx->mechanismUsed->length; /* mechanismUsed */
+ length += 12 + key.length; /* rfc3961Key.value */
+ length += 4 + initiatorName.length; /* initiatorName.value */
+ length += 4 + acceptorName.length; /* acceptorName.value */
+ length += 24 + sequenceSize(ctx->seqState); /* seqState */
+
+ if (partialCtx.value != NULL)
+ length += 4 + partialCtx.length; /* partialCtx.value */
+
+ token->value = GSSEAP_MALLOC(length);
+ if (token->value == NULL) {
+ major = GSS_S_FAILURE;
+ *minor = ENOMEM;
+ goto cleanup;
+ }
+ token->length = length;
+
+ p = (unsigned char *)token->value;
+
+ store_uint32_be(EAP_EXPORT_CONTEXT_V1, &p[0]); /* version */
+ store_uint32_be(ctx->state, &p[4]);
+ store_uint32_be(ctx->flags, &p[8]);
+ store_uint32_be(ctx->gssFlags, &p[12]);
+ p = store_oid(ctx->mechanismUsed, &p[16]);
+
+ store_uint32_be(ctx->checksumType, &p[0]);
+ store_uint32_be(ctx->encryptionType, &p[4]);
+ p = store_buffer(&key, &p[8], FALSE);
+
+ p = store_buffer(&initiatorName, p, FALSE);
+ p = store_buffer(&acceptorName, p, FALSE);
+
+ store_uint64_be(ctx->expiryTime, &p[0]);
+ store_uint64_be(ctx->sendSeq, &p[8]);
+ store_uint64_be(ctx->recvSeq, &p[16]);
+ p += 24;
+
+ major = sequenceExternalize(minor, ctx->seqState, &p, &length);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ if (partialCtx.value != NULL)
+ p = store_buffer(&partialCtx, p, FALSE);
+
+ assert(p == (unsigned char *)token->value + token->length);
+
+ major = GSS_S_COMPLETE;
+ *minor = 0;
+
+cleanup:
+ if (GSS_ERROR(major))
+ gss_release_buffer(&tmpMinor, token);
+ gss_release_buffer(&tmpMinor, &initiatorName);
+ gss_release_buffer(&tmpMinor, &acceptorName);
+ gss_release_buffer(&tmpMinor, &partialCtx);
+
+ return major;
+}
+
+OM_uint32
+gss_export_sec_context(OM_uint32 *minor,
+ gss_ctx_id_t *context_handle,
+ gss_buffer_t interprocess_token)
+{
+ OM_uint32 major, tmpMinor;
+ gss_ctx_id_t ctx = *context_handle;
+
+ interprocess_token->length = 0;
+ interprocess_token->value = NULL;
+
+ if (ctx == GSS_C_NO_CONTEXT) {
+ *minor = EINVAL;
+ return GSS_S_NO_CONTEXT;
+ }
+
+ *minor = 0;
+
+ GSSEAP_MUTEX_LOCK(&ctx->mutex);
+
+ major = gssEapExportSecContext(minor, ctx, interprocess_token);
+ if (GSS_ERROR(major)) {
+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
+ return major;
+ }
+
+ *context_handle = GSS_C_NO_CONTEXT;
+
+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
+
+ gssEapReleaseContext(&tmpMinor, &ctx);
+
+ return GSS_S_COMPLETE;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Message protection services: make a message integerity check.
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32
+gss_get_mic(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ gss_qop_t qop_req,
+ gss_buffer_t message_buffer,
+ gss_buffer_t message_token)
+{
+ OM_uint32 major;
+ gss_iov_buffer_desc iov[2];
+
+ if (ctx == GSS_C_NO_CONTEXT) {
+ *minor = EINVAL;
+ return GSS_S_NO_CONTEXT;
+ }
+
+ if (qop_req != GSS_C_QOP_DEFAULT) {
+ *minor = GSSEAP_UNKNOWN_QOP;
+ return GSS_S_UNAVAILABLE;
+ }
+
+ *minor = 0;
+
+ message_token->value = NULL;
+ message_token->length = 0;
+
+ GSSEAP_MUTEX_LOCK(&ctx->mutex);
+
+ if (!CTX_IS_ESTABLISHED(ctx)) {
+ major = GSS_S_NO_CONTEXT;
+ *minor = GSSEAP_CONTEXT_INCOMPLETE;
+ goto cleanup;
+ }
+
+ iov[0].type = GSS_IOV_BUFFER_TYPE_DATA;
+ iov[0].buffer = *message_buffer;
+
+ iov[1].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_FLAG_ALLOCATE;
+ iov[1].buffer.value = NULL;
+ iov[1].buffer.length = 0;
+
+ major = gssEapWrapOrGetMIC(minor, ctx, FALSE, NULL, iov, 2, TOK_TYPE_MIC);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ *message_token = iov[1].buffer;
+
+cleanup:
+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
+
+ return major;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "gssapiP_eap.h"
+
+/*
+ * Wrapper for retrieving a naming attribute.
+ */
+
+OM_uint32
+gss_get_name_attribute(OM_uint32 *minor,
+ gss_name_t name,
+ gss_buffer_t attr,
+ int *authenticated,
+ int *complete,
+ gss_buffer_t value,
+ gss_buffer_t display_value,
+ int *more)
+{
+ OM_uint32 major;
+
+ *minor = 0;
+
+ if (name == GSS_C_NO_NAME) {
+ *minor = EINVAL;
+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
+ }
+
+ GSSEAP_MUTEX_LOCK(&name->mutex);
+
+ major = gssEapGetNameAttribute(minor, name, attr,
+ authenticated, complete,
+ value, display_value, more);
+
+ GSSEAP_MUTEX_UNLOCK(&name->mutex);
+
+ return major;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _GSSAPIP_EAP_H_
+#define _GSSAPIP_EAP_H_ 1
+
+#include "config.h"
+#include <assert.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/param.h>
+
+/* GSS includes */
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_krb5.h>
+#include <gssapi/gssapi_ext.h>
+#include "gssapi_eap.h"
+
+/* Kerberos includes */
+#include <krb5.h>
+
+/* EAP includes (not C++ clean) */
+#ifndef __cplusplus
+#include <common.h>
+#include <eap_peer/eap.h>
+#include <eap_peer/eap_config.h>
+#include <crypto/tls.h>
+#include <wpabuf.h>
+#endif
+
+/* Workaround for FreeRADIUS not being C++ clean */
+#ifdef __cplusplus
+extern "C" {
+#define operator fr_operator
+#endif
+#include <freeradius/libradius.h>
+#include <freeradius/radius.h>
+#include <radsec/radsec.h>
+#include <radsec/request.h>
+#ifdef __cplusplus
+#undef operator
+}
+#endif
+
+#include "gsseap_err.h"
+#include "radsec_err.h"
+#include "util.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* These name flags are informative and not actually used by anything yet */
+#define NAME_FLAG_NAI 0x00000001
+#define NAME_FLAG_SERVICE 0x00000002
+#define NAME_FLAG_COMPOSITE 0x00000004
+
+struct gss_eap_saml_attr_ctx;
+struct gss_eap_attr_ctx;
+
+struct gss_name_struct {
+ GSSEAP_MUTEX mutex; /* mutex protects attrCtx */
+ OM_uint32 flags;
+ krb5_principal krbPrincipal; /* this is immutable */
+ struct gss_eap_attr_ctx *attrCtx;
+};
+
+#define CRED_FLAG_INITIATE 0x00010000
+#define CRED_FLAG_ACCEPT 0x00020000
+#define CRED_FLAG_DEFAULT_IDENTITY 0x00040000
+#define CRED_FLAG_PASSWORD 0x00080000
+#define CRED_FLAG_DEFAULT_CCACHE 0x00100000
+#define CRED_FLAG_PUBLIC_MASK 0x0000FFFF
+
+struct gss_cred_id_struct {
+ GSSEAP_MUTEX mutex;
+ OM_uint32 flags;
+ gss_name_t name;
+ gss_buffer_desc password;
+ gss_OID_set mechanisms;
+ time_t expiryTime;
+ char *radiusConfigFile;
+ char *radiusConfigStanza;
+#ifdef GSSEAP_ENABLE_REAUTH
+ krb5_ccache krbCredCache;
+ gss_cred_id_t krbCred;
+#endif
+};
+
+#define CTX_FLAG_INITIATOR 0x00000001
+#define CTX_FLAG_KRB_REAUTH_GSS 0x00000002
+
+#define CTX_IS_INITIATOR(ctx) (((ctx)->flags & CTX_FLAG_INITIATOR) != 0)
+
+enum gss_eap_state {
+ EAP_STATE_IDENTITY = 0,
+ EAP_STATE_AUTHENTICATE,
+ EAP_STATE_EXTENSIONS_REQ,
+ EAP_STATE_EXTENSIONS_RESP,
+ EAP_STATE_ESTABLISHED,
+ EAP_STATE_ERROR,
+#ifdef GSSEAP_ENABLE_REAUTH
+ EAP_STATE_KRB_REAUTH_GSS
+#endif
+};
+
+#define CTX_IS_ESTABLISHED(ctx) ((ctx)->state == EAP_STATE_ESTABLISHED)
+
+/* Initiator context flags */
+#define CTX_FLAG_EAP_SUCCESS 0x00010000
+#define CTX_FLAG_EAP_RESTART 0x00020000
+#define CTX_FLAG_EAP_FAIL 0x00040000
+#define CTX_FLAG_EAP_RESP 0x00080000
+#define CTX_FLAG_EAP_NO_RESP 0x00100000
+#define CTX_FLAG_EAP_REQ 0x00200000
+#define CTX_FLAG_EAP_PORT_ENABLED 0x00400000
+#define CTX_FLAG_EAP_ALT_ACCEPT 0x00800000
+#define CTX_FLAG_EAP_ALT_REJECT 0x01000000
+#define CTX_FLAG_EAP_MASK 0xFFFF0000
+
+struct gss_eap_initiator_ctx {
+ gss_cred_id_t defaultCred;
+ unsigned int idleWhile;
+#ifndef __cplusplus
+ struct eap_peer_config eapPeerConfig;
+ struct eap_sm *eap;
+ struct wpabuf reqData;
+#endif
+};
+
+struct gss_eap_acceptor_ctx {
+ struct rs_context *radContext;
+ struct rs_connection *radConn;
+ char *radServer;
+ gss_buffer_desc state;
+ VALUE_PAIR *vps;
+};
+
+struct gss_ctx_id_struct {
+ GSSEAP_MUTEX mutex;
+ enum gss_eap_state state;
+ OM_uint32 flags;
+ OM_uint32 gssFlags;
+ gss_OID mechanismUsed;
+ krb5_cksumtype checksumType;
+ krb5_enctype encryptionType;
+ krb5_keyblock rfc3961Key;
+ gss_name_t initiatorName;
+ gss_name_t acceptorName;
+ time_t expiryTime;
+ uint64_t sendSeq, recvSeq;
+ void *seqState;
+ union {
+ struct gss_eap_initiator_ctx initiator;
+ #define initiatorCtx ctxU.initiator
+ struct gss_eap_acceptor_ctx acceptor;
+ #define acceptorCtx ctxU.acceptor
+#ifdef GSSEAP_ENABLE_REAUTH
+ gss_ctx_id_t kerberos;
+ #define kerberosCtx ctxU.kerberos
+#endif
+ } ctxU;
+};
+
+#define TOK_FLAG_SENDER_IS_ACCEPTOR 0x01
+#define TOK_FLAG_WRAP_CONFIDENTIAL 0x02
+#define TOK_FLAG_ACCEPTOR_SUBKEY 0x04
+
+#define KEY_USAGE_ACCEPTOR_SEAL 22
+#define KEY_USAGE_ACCEPTOR_SIGN 23
+#define KEY_USAGE_INITIATOR_SEAL 24
+#define KEY_USAGE_INITIATOR_SIGN 25
+
+/* wrap_iov.c */
+OM_uint32
+gssEapWrapOrGetMIC(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ int conf_req_flag,
+ int *conf_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ enum gss_eap_token_type toktype);
+
+OM_uint32
+gssEapUnwrapOrVerifyMIC(OM_uint32 *minor_status,
+ gss_ctx_id_t ctx,
+ int *conf_state,
+ gss_qop_t *qop_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ enum gss_eap_token_type toktype);
+
+OM_uint32
+gssEapWrapIovLength(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ int *conf_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count);
+OM_uint32
+gssEapWrap(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ gss_buffer_t input_message_buffer,
+ int *conf_state,
+ gss_buffer_t output_message_buffer);
+
+unsigned char
+rfc4121Flags(gss_ctx_id_t ctx, int receiving);
+
+/* display_status.c */
+void
+gssEapSaveStatusInfo(OM_uint32 minor, const char *format, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GSSAPIP_EAP_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _GSSAPI_EAP_H_
+#define _GSSAPI_EAP_H_ 1
+
+#include <gssapi/gssapi.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/*
+ * GSS EAP mechanism OIDs.
+ */
+extern gss_OID GSS_EAP_AES128_CTS_HMAC_SHA1_96_MECHANISM;
+extern gss_OID GSS_EAP_AES256_CTS_HMAC_SHA1_96_MECHANISM;
+
+/*
+ * Mechanism name OID.
+ */
+extern gss_OID GSS_EAP_NT_PRINCIPAL_NAME;
+
+/*
+ * The libradsec configuration file; defaults to radsec.conf
+ * in the system configuration directory if unspecified.
+ */
+extern gss_OID GSS_EAP_CRED_SET_RADIUS_CONFIG_FILE;
+
+/*
+ * The stanza in the libradsec configuration file; defaults
+ * to "gss-eap" if unspecified.
+ */
+extern gss_OID GSS_EAP_CRED_SET_RADIUS_CONFIG_STANZA;
+
+/*
+ * Flags as a 32-bit integer in network byte order,
+ * followed by a boolean octet indicating whether to
+ * clear the specified flags (if absent, defaults to
+ * FALSE, ie. set flags).
+ */
+extern gss_OID GSS_EAP_CRED_SET_CRED_FLAG;
+
+/*
+ * Credentials flag indicating the local attributes
+ * processing should be skipped.
+ */
+#define GSS_EAP_DISABLE_LOCAL_ATTRS_FLAG 0x00000001
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _GSSAPI_EAP_H_ */
--- /dev/null
+#
+# Copyright (c) 2010, JANET(UK)
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# 3. Neither the name of JANET(UK) nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+
+error_table eapg
+
+#
+# Protocol errors that can be returned in an error token. This should match
+# up with makeErrorToken in accept_sec_context.c.
+#
+error_code GSSEAP_RESERVED, ""
+error_code GSSEAP_WRONG_SIZE, "Buffer is incorrect size"
+error_code GSSEAP_WRONG_MECH, "Mechanism OID is incorrect"
+error_code GSSEAP_BAD_TOK_HEADER, "Token header is malformed or corrupt"
+error_code GSSEAP_TOK_TRUNC, "Token is missing data"
+error_code GSSEAP_BAD_DIRECTION, "Packet was replayed in wrong direction"
+error_code GSSEAP_WRONG_TOK_ID, "Received token ID does not match expected token ID"
+error_code GSSEAP_CRIT_EXT_UNAVAILABLE, "Critical extension unavailable"
+error_code GSSEAP_MISSING_REQUIRED_EXT, "Missing required extension"
+error_code GSSEAP_KEY_UNAVAILABLE, "EAP key unavailable"
+error_code GSSEAP_KEY_TOO_SHORT, "EAP key too short"
+error_code GSSEAP_RADIUS_AUTH_FAILURE, "Authentication rejected by RADIUS server"
+error_code GSSEAP_UNKNOWN_RADIUS_CODE, "Received unknown response code from RADIUS server"
+error_code GSSEAP_MISSING_EAP_REQUEST, "RADIUS response is missing EAP request"
+error_code GSSEAP_GENERIC_RADIUS_ERROR, "Generic RADIUS error"
+
+#
+# Context errors
+#
+error_code GSSEAP_CONTEXT_ESTABLISHED, "Context is already fully established"
+error_code GSSEAP_CONTEXT_INCOMPLETE, "Attempt to use incomplete security context"
+error_code GSSEAP_BAD_CONTEXT_TOKEN, "Context token is malformed or corrupt"
+error_code GSSEAP_BAD_ERROR_TOKEN, "Error token is malformed or corrupt"
+error_code GSSEAP_BAD_CONTEXT_OPTION, "Bad context option"
+
+#
+# Name errors
+#
+error_code GSSEAP_BAD_SERVICE_NAME, "Name is not a valid service name"
+error_code GSSEAP_BAD_INITIATOR_NAME, "Initiator identity must be a valid name"
+error_code GSSEAP_NO_HOSTNAME, "Could not determine local host name"
+
+#
+# Credential errors
+#
+error_code GSSEAP_BAD_USAGE, "Credential usage type is unknown"
+error_code GSSEAP_CRED_USAGE_MISMATCH, "Credential usage does not match requested usage"
+error_code GSSEAP_CRED_MECH_MISMATCH, "Credential is not usable with this mechanism"
+error_code GSSEAP_BAD_CRED_OPTION, "Bad credential option"
+
+#
+# Wrap/unwrap/PRF errors
+#
+error_code GSSEAP_BAD_WRAP_TOKEN, "Bad RFC 4121 wrap or MIC token"
+error_code GSSEAP_MISSING_IOV, "IOV is missing required buffer"
+error_code GSSEAP_BAD_STREAM_IOV, "Stream IOV can only contain a single data buffer"
+error_code GSSEAP_BAD_PADDING_IOV, "Padding IOV is not permitted for RFC 4121 tokens"
+error_code GSSEAP_UNKNOWN_QOP, "Unknown quality of protection specified"
+error_code GSSEAP_INPUT_TOO_LONG, "PRF input too long"
+error_code GSSEAP_BAD_PRF_KEY, "PRF key usage type is unknown"
+
+#
+# libeap errors
+#
+error_code GSSEAP_LIBEAP_INIT_FAILURE, "Failed to initialise EAP library"
+error_code GSSEAP_PEER_SM_INIT_FAILURE, "Failed to create EAP state machine"
+error_code GSSEAP_PEER_AUTH_FAILURE, "EAP peer authentication failure"
+error_code GSSEAP_PEER_BAD_MESSAGE, "Received bad EAP message"
+
+#
+# RadSec initialisation errors
+#
+error_code GSSEAP_RADSEC_INIT_FAILURE, "Failed to initialise RadSec library"
+error_code GSSEAP_RADSEC_CONTEXT_FAILURE, "Failed to create RadSec context"
+
+#
+# SAML/Shibboleth/attribute errors
+#
+error_code GSSEAP_SAML_INIT_FAILURE, "Failed to initialise SAML library"
+error_code GSSEAP_SHIB_INIT_FAILURE, "Failed to initialise Shibboleth"
+error_code GSSEAP_NO_ATTR_CONTEXT, "Name has no attributes"
+error_code GSSEAP_NO_ATTR_PROVIDERS, "Failed to initialise attribute providers"
+error_code GSSEAP_NO_SUCH_ATTR, "Unknown naming attribute"
+error_code GSSEAP_BAD_ATTR_TOKEN, "Serialised attributes are malformed or corrupt"
+error_code GSSEAP_ATTR_CONTEXT_FAILURE, "Failed to initialise attribute context"
+
+#
+# Extensions
+#
+error_code GSSEAP_BINDINGS_MISMATCH, "Channel bindings do not match"
+error_code GSSEAP_NO_MECHGLUE_SYMBOL, "Could not find symbol in mechanism glue"
+error_code GSSEAP_BAD_INVOCATION, "Bad mechanism invoke OID"
+
+end
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Deserialise a name.
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32
+gss_import_name(OM_uint32 *minor,
+ gss_buffer_t import_name_buffer,
+ gss_OID input_name_type,
+ gss_name_t *output_name)
+{
+ return gssEapImportName(minor, import_name_buffer,
+ input_name_type, output_name);
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Deserialise a context handle.
+ */
+
+#include "gssapiP_eap.h"
+
+#define UPDATE_REMAIN(n) do { \
+ p += (n); \
+ remain -= (n); \
+ } while (0)
+
+#define CHECK_REMAIN(n) do { \
+ if (remain < (n)) { \
+ *minor = GSSEAP_TOK_TRUNC; \
+ return GSS_S_DEFECTIVE_TOKEN; \
+ } \
+ } while (0)
+
+static OM_uint32
+gssEapImportPartialContext(OM_uint32 *minor,
+ unsigned char **pBuf,
+ size_t *pRemain,
+ gss_ctx_id_t ctx)
+{
+ OM_uint32 major;
+ unsigned char *p = *pBuf;
+ size_t remain = *pRemain;
+ gss_buffer_desc buf;
+ size_t serverLen;
+
+ /* Selected RADIUS server */
+ CHECK_REMAIN(4);
+ serverLen = load_uint32_be(p);
+ UPDATE_REMAIN(4);
+
+ if (serverLen != 0) {
+ CHECK_REMAIN(serverLen);
+
+ ctx->acceptorCtx.radServer = GSSEAP_MALLOC(serverLen + 1);
+ if (ctx->acceptorCtx.radServer == NULL) {
+ *minor = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ memcpy(ctx->acceptorCtx.radServer, p, serverLen);
+ ctx->acceptorCtx.radServer[serverLen] = '\0';
+
+ UPDATE_REMAIN(serverLen);
+ }
+
+ /* RADIUS state blob */
+ CHECK_REMAIN(4);
+ buf.length = load_uint32_be(p);
+ UPDATE_REMAIN(4);
+
+ if (buf.length != 0) {
+ CHECK_REMAIN(buf.length);
+
+ buf.value = p;
+
+ major = duplicateBuffer(minor, &buf, &ctx->acceptorCtx.state);
+ if (GSS_ERROR(major))
+ return major;
+
+ UPDATE_REMAIN(buf.length);
+ }
+
+ *pBuf = p;
+ *pRemain = remain;
+
+ return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+importMechanismOid(OM_uint32 *minor,
+ unsigned char **pBuf,
+ size_t *pRemain,
+ gss_OID *pOid)
+{
+ OM_uint32 major;
+ unsigned char *p = *pBuf;
+ size_t remain = *pRemain;
+ gss_OID_desc oidBuf;
+
+ oidBuf.length = load_uint32_be(p);
+ if (remain < 4 + oidBuf.length || oidBuf.length == 0) {
+ *minor = GSSEAP_TOK_TRUNC;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ oidBuf.elements = &p[4];
+
+ if (!gssEapIsConcreteMechanismOid(&oidBuf)) {
+ *minor = GSSEAP_WRONG_MECH;
+ return GSS_S_BAD_MECH;
+ }
+
+ if (!gssEapInternalizeOid(&oidBuf, pOid)) {
+ major = duplicateOid(minor, &oidBuf, pOid);
+ if (GSS_ERROR(major))
+ return major;
+ }
+
+ *pBuf += 4 + oidBuf.length;
+ *pRemain -= 4 + oidBuf.length;
+
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+importKerberosKey(OM_uint32 *minor,
+ unsigned char **pBuf,
+ size_t *pRemain,
+ krb5_cksumtype *checksumType,
+ krb5_enctype *pEncryptionType,
+ krb5_keyblock *key)
+{
+ unsigned char *p = *pBuf;
+ size_t remain = *pRemain;
+ OM_uint32 encryptionType;
+ OM_uint32 length;
+ gss_buffer_desc tmp;
+
+ if (remain < 12) {
+ *minor = GSSEAP_TOK_TRUNC;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ *checksumType = load_uint32_be(&p[0]);
+ encryptionType = load_uint32_be(&p[4]);
+ length = load_uint32_be(&p[8]);
+
+ if ((length != 0) != (encryptionType != ENCTYPE_NULL)) {
+ *minor = GSSEAP_BAD_CONTEXT_TOKEN;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ if (remain - 12 < length) {
+ *minor = GSSEAP_TOK_TRUNC;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ if (load_buffer(&p[12], length, &tmp) == NULL) {
+ *minor = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ KRB_KEY_TYPE(key) = encryptionType;
+ KRB_KEY_LENGTH(key) = tmp.length;
+ KRB_KEY_DATA(key) = (unsigned char *)tmp.value;
+
+ *pBuf += 12 + length;
+ *pRemain -= 12 + length;
+ *pEncryptionType = encryptionType;
+
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+importName(OM_uint32 *minor,
+ unsigned char **pBuf,
+ size_t *pRemain,
+ gss_name_t *pName)
+{
+ OM_uint32 major;
+ unsigned char *p = *pBuf;
+ size_t remain = *pRemain;
+ gss_buffer_desc tmp;
+
+ if (remain < 4) {
+ *minor = GSSEAP_TOK_TRUNC;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ tmp.length = load_uint32_be(p);
+ if (tmp.length != 0) {
+ if (remain - 4 < tmp.length) {
+ *minor = GSSEAP_TOK_TRUNC;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ tmp.value = p + 4;
+
+ major = gssEapImportNameInternal(minor, &tmp, pName,
+ EXPORT_NAME_FLAG_COMPOSITE);
+ if (GSS_ERROR(major))
+ return major;
+ }
+
+ *pBuf += 4 + tmp.length;
+ *pRemain -= 4 + tmp.length;
+
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+gssEapImportContext(OM_uint32 *minor,
+ gss_buffer_t token,
+ gss_ctx_id_t ctx)
+{
+ OM_uint32 major;
+ unsigned char *p = (unsigned char *)token->value;
+ size_t remain = token->length;
+
+ if (remain < 16) {
+ *minor = GSSEAP_TOK_TRUNC;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+ if (load_uint32_be(&p[0]) != EAP_EXPORT_CONTEXT_V1) {
+ *minor = GSSEAP_BAD_CONTEXT_TOKEN;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+ ctx->state = load_uint32_be(&p[4]);
+ ctx->flags = load_uint32_be(&p[8]);
+ ctx->gssFlags = load_uint32_be(&p[12]);
+ p += 16;
+ remain -= 16;
+
+ /* Validate state */
+ if (ctx->state < EAP_STATE_IDENTITY ||
+ ctx->state > EAP_STATE_ESTABLISHED)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ /* Only acceptor can export partial context tokens */
+ if (CTX_IS_INITIATOR(ctx) && !CTX_IS_ESTABLISHED(ctx))
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ major = importMechanismOid(minor, &p, &remain, &ctx->mechanismUsed);
+ if (GSS_ERROR(major))
+ return major;
+
+ major = importKerberosKey(minor, &p, &remain,
+ &ctx->checksumType,
+ &ctx->encryptionType,
+ &ctx->rfc3961Key);
+ if (GSS_ERROR(major))
+ return major;
+
+ major = importName(minor, &p, &remain, &ctx->initiatorName);
+ if (GSS_ERROR(major))
+ return major;
+
+ major = importName(minor, &p, &remain, &ctx->acceptorName);
+ if (GSS_ERROR(major))
+ return major;
+
+ /* Check that, if context is established, names are valid */
+ if (CTX_IS_ESTABLISHED(ctx) &&
+ (CTX_IS_INITIATOR(ctx) ? ctx->acceptorName == GSS_C_NO_NAME
+ : ctx->initiatorName == GSS_C_NO_NAME)) {
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ if (remain < 24 + sequenceSize(ctx->seqState)) {
+ *minor = GSSEAP_TOK_TRUNC;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+ ctx->expiryTime = (time_t)load_uint64_be(&p[0]); /* XXX */
+ ctx->sendSeq = load_uint64_be(&p[8]);
+ ctx->recvSeq = load_uint64_be(&p[16]);
+ p += 24;
+ remain -= 24;
+
+ major = sequenceInternalize(minor, &ctx->seqState, &p, &remain);
+ if (GSS_ERROR(major))
+ return major;
+
+ /*
+ * The partial context should only be expected for unestablished
+ * acceptor contexts.
+ */
+ if (!CTX_IS_INITIATOR(ctx) && !CTX_IS_ESTABLISHED(ctx)) {
+ assert((ctx->flags & CTX_FLAG_KRB_REAUTH_GSS) == 0);
+
+ major = gssEapImportPartialContext(minor, &p, &remain, ctx);
+ if (GSS_ERROR(major))
+ return major;
+ }
+
+#ifdef GSSEAP_DEBUG
+ assert(remain == 0);
+#endif
+
+ major = GSS_S_COMPLETE;
+ *minor = 0;
+
+ return major;
+}
+
+OM_uint32
+gss_import_sec_context(OM_uint32 *minor,
+ gss_buffer_t interprocess_token,
+ gss_ctx_id_t *context_handle)
+{
+ OM_uint32 major, tmpMinor;
+ gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
+
+ *context_handle = GSS_C_NO_CONTEXT;
+
+ if (interprocess_token == GSS_C_NO_BUFFER ||
+ interprocess_token->length == 0) {
+ *minor = GSSEAP_TOK_TRUNC;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ major = gssEapAllocContext(minor, &ctx);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ major = gssEapImportContext(minor, interprocess_token, ctx);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ *context_handle = ctx;
+
+cleanup:
+ if (GSS_ERROR(major))
+ gssEapReleaseContext(&tmpMinor, &ctx);
+
+ return major;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Enumerate the supported mechanism OIDs.
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32
+gss_indicate_mechs(OM_uint32 *minor,
+ gss_OID_set *mech_set)
+{
+ return gssEapIndicateMechs(minor, mech_set);
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Establish a security context on the initiator (client). These functions
+ * wrap around libeap.
+ */
+
+#include "gssapiP_eap.h"
+
+#ifdef GSSEAP_ENABLE_REAUTH
+static OM_uint32
+eapGssSmInitGssReauth(OM_uint32 *minor,
+ gss_cred_id_t cred,
+ gss_ctx_id_t ctx,
+ gss_name_t target,
+ gss_OID mech,
+ OM_uint32 reqFlags,
+ OM_uint32 timeReq,
+ gss_channel_bindings_t chanBindings,
+ gss_buffer_t inputToken,
+ gss_buffer_t outputToken);
+#endif
+
+static OM_uint32
+policyVariableToFlag(enum eapol_bool_var variable)
+{
+ OM_uint32 flag = 0;
+
+ switch (variable) {
+ case EAPOL_eapSuccess:
+ flag = CTX_FLAG_EAP_SUCCESS;
+ break;
+ case EAPOL_eapRestart:
+ flag = CTX_FLAG_EAP_RESTART;
+ break;
+ case EAPOL_eapFail:
+ flag = CTX_FLAG_EAP_FAIL;
+ break;
+ case EAPOL_eapResp:
+ flag = CTX_FLAG_EAP_RESP;
+ break;
+ case EAPOL_eapNoResp:
+ flag = CTX_FLAG_EAP_NO_RESP;
+ break;
+ case EAPOL_eapReq:
+ flag = CTX_FLAG_EAP_REQ;
+ break;
+ case EAPOL_portEnabled:
+ flag = CTX_FLAG_EAP_PORT_ENABLED;
+ break;
+ case EAPOL_altAccept:
+ flag = CTX_FLAG_EAP_ALT_ACCEPT;
+ break;
+ case EAPOL_altReject:
+ flag = CTX_FLAG_EAP_ALT_REJECT;
+ break;
+ }
+
+ return flag;
+}
+
+static struct eap_peer_config *
+peerGetConfig(void *ctx)
+{
+ gss_ctx_id_t gssCtx = (gss_ctx_id_t)ctx;
+
+ return &gssCtx->initiatorCtx.eapPeerConfig;
+}
+
+static Boolean
+peerGetBool(void *data, enum eapol_bool_var variable)
+{
+ gss_ctx_id_t ctx = data;
+ OM_uint32 flag;
+
+ if (ctx == GSS_C_NO_CONTEXT)
+ return FALSE;
+
+ flag = policyVariableToFlag(variable);
+
+ return ((ctx->flags & flag) != 0);
+}
+
+static void
+peerSetBool(void *data, enum eapol_bool_var variable,
+ Boolean value)
+{
+ gss_ctx_id_t ctx = data;
+ OM_uint32 flag;
+
+ if (ctx == GSS_C_NO_CONTEXT)
+ return;
+
+ flag = policyVariableToFlag(variable);
+
+ if (value)
+ ctx->flags |= flag;
+ else
+ ctx->flags &= ~(flag);
+}
+
+static unsigned int
+peerGetInt(void *data, enum eapol_int_var variable)
+{
+ gss_ctx_id_t ctx = data;
+
+ if (ctx == GSS_C_NO_CONTEXT)
+ return FALSE;
+
+ assert(CTX_IS_INITIATOR(ctx));
+
+ switch (variable) {
+ case EAPOL_idleWhile:
+ return ctx->initiatorCtx.idleWhile;
+ break;
+ }
+
+ return 0;
+}
+
+static void
+peerSetInt(void *data, enum eapol_int_var variable,
+ unsigned int value)
+{
+ gss_ctx_id_t ctx = data;
+
+ if (ctx == GSS_C_NO_CONTEXT)
+ return;
+
+ assert(CTX_IS_INITIATOR(ctx));
+
+ switch (variable) {
+ case EAPOL_idleWhile:
+ ctx->initiatorCtx.idleWhile = value;
+ break;
+ }
+}
+
+static struct wpabuf *
+peerGetEapReqData(void *ctx)
+{
+ gss_ctx_id_t gssCtx = (gss_ctx_id_t)ctx;
+
+ return &gssCtx->initiatorCtx.reqData;
+}
+
+static void
+peerSetConfigBlob(void *ctx, struct wpa_config_blob *blob)
+{
+}
+
+static const struct wpa_config_blob *
+peerGetConfigBlob(void *ctx, const char *name)
+{
+ return NULL;
+}
+
+static void
+peerNotifyPending(void *ctx)
+{
+}
+
+static struct eapol_callbacks gssEapPolicyCallbacks = {
+ peerGetConfig,
+ peerGetBool,
+ peerSetBool,
+ peerGetInt,
+ peerSetInt,
+ peerGetEapReqData,
+ peerSetConfigBlob,
+ peerGetConfigBlob,
+ peerNotifyPending,
+};
+
+extern int wpa_debug_level;
+
+static OM_uint32
+peerConfigInit(OM_uint32 *minor,
+ gss_cred_id_t cred,
+ gss_ctx_id_t ctx)
+{
+ krb5_context krbContext;
+ struct eap_peer_config *eapPeerConfig = &ctx->initiatorCtx.eapPeerConfig;
+ krb5_error_code code;
+ char *identity;
+
+ eapPeerConfig->identity = NULL;
+ eapPeerConfig->identity_len = 0;
+ eapPeerConfig->password = NULL;
+ eapPeerConfig->password_len = 0;
+
+ assert(cred != GSS_C_NO_CREDENTIAL);
+
+ GSSEAP_KRB_INIT(&krbContext);
+
+ eapPeerConfig->fragment_size = 1024;
+ wpa_debug_level = 0;
+
+ assert(cred->name != GSS_C_NO_NAME);
+
+ if ((cred->name->flags & (NAME_FLAG_NAI | NAME_FLAG_SERVICE)) == 0) {
+ *minor = GSSEAP_BAD_INITIATOR_NAME;
+ return GSS_S_BAD_NAME;
+ }
+
+ code = krb5_unparse_name(krbContext, cred->name->krbPrincipal, &identity);
+ if (code != 0) {
+ *minor = code;
+ return GSS_S_FAILURE;
+ }
+
+ eapPeerConfig->identity = (unsigned char *)identity;
+ eapPeerConfig->identity_len = strlen(identity);
+ eapPeerConfig->password = (unsigned char *)cred->password.value;
+ eapPeerConfig->password_len = cred->password.length;
+
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+peerConfigFree(OM_uint32 *minor,
+ gss_ctx_id_t ctx)
+{
+ krb5_context krbContext;
+ struct eap_peer_config *eapPeerConfig = &ctx->initiatorCtx.eapPeerConfig;
+
+ GSSEAP_KRB_INIT(&krbContext);
+
+ krb5_free_unparsed_name(krbContext, (char *)eapPeerConfig->identity);
+
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
+
+/*
+ * Mark an initiator context as ready for cryptographic operations
+ */
+static OM_uint32
+initReady(OM_uint32 *minor, gss_ctx_id_t ctx, OM_uint32 reqFlags)
+{
+ OM_uint32 major;
+ const unsigned char *key;
+ size_t keyLength;
+
+#if 1
+ /* XXX actually check for mutual auth */
+ if (reqFlags & GSS_C_MUTUAL_FLAG)
+ ctx->gssFlags |= GSS_C_MUTUAL_FLAG;
+#endif
+
+ /* Cache encryption type derived from selected mechanism OID */
+ major = gssEapOidToEnctype(minor, ctx->mechanismUsed, &ctx->encryptionType);
+ if (GSS_ERROR(major))
+ return major;
+
+ if (!eap_key_available(ctx->initiatorCtx.eap)) {
+ *minor = GSSEAP_KEY_UNAVAILABLE;
+ return GSS_S_UNAVAILABLE;
+ }
+
+ key = eap_get_eapKeyData(ctx->initiatorCtx.eap, &keyLength);
+
+ if (keyLength < EAP_EMSK_LEN) {
+ *minor = GSSEAP_KEY_TOO_SHORT;
+ return GSS_S_UNAVAILABLE;
+ }
+
+ major = gssEapDeriveRfc3961Key(minor,
+ &key[EAP_EMSK_LEN / 2],
+ EAP_EMSK_LEN / 2,
+ ctx->encryptionType,
+ &ctx->rfc3961Key);
+ if (GSS_ERROR(major))
+ return major;
+
+ major = rfc3961ChecksumTypeForKey(minor, &ctx->rfc3961Key,
+ &ctx->checksumType);
+ if (GSS_ERROR(major))
+ return major;
+
+ major = sequenceInit(minor,
+ &ctx->seqState,
+ ctx->recvSeq,
+ ((ctx->gssFlags & GSS_C_REPLAY_FLAG) != 0),
+ ((ctx->gssFlags & GSS_C_SEQUENCE_FLAG) != 0),
+ TRUE);
+ if (GSS_ERROR(major))
+ return major;
+
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+initBegin(OM_uint32 *minor,
+ gss_cred_id_t cred,
+ gss_ctx_id_t ctx,
+ gss_name_t target,
+ gss_OID mech,
+ OM_uint32 reqFlags,
+ OM_uint32 timeReq,
+ gss_channel_bindings_t chanBindings,
+ gss_buffer_t inputToken,
+ gss_buffer_t outputToken)
+{
+ OM_uint32 major;
+
+ assert(cred != GSS_C_NO_CREDENTIAL);
+
+ if (cred->expiryTime)
+ ctx->expiryTime = cred->expiryTime;
+ else if (timeReq == 0 || timeReq == GSS_C_INDEFINITE)
+ ctx->expiryTime = 0;
+ else
+ ctx->expiryTime = time(NULL) + timeReq;
+
+ /*
+ * The credential mutex protects its name, however we need to
+ * explicitly lock the acceptor name (unlikely as it may be
+ * that it has attributes set on it).
+ */
+ major = gssEapDuplicateName(minor, cred->name, &ctx->initiatorName);
+ if (GSS_ERROR(major))
+ return major;
+
+ GSSEAP_MUTEX_LOCK(&target->mutex);
+
+ major = gssEapDuplicateName(minor, target, &ctx->acceptorName);
+ if (GSS_ERROR(major)) {
+ GSSEAP_MUTEX_UNLOCK(&target->mutex);
+ return major;
+ }
+
+ GSSEAP_MUTEX_UNLOCK(&target->mutex);
+
+ if (mech == GSS_C_NULL_OID) {
+ major = gssEapDefaultMech(minor, &ctx->mechanismUsed);
+ } else if (gssEapIsConcreteMechanismOid(mech)) {
+ if (!gssEapInternalizeOid(mech, &ctx->mechanismUsed))
+ major = duplicateOid(minor, mech, &ctx->mechanismUsed);
+ } else {
+ major = GSS_S_BAD_MECH;
+ *minor = GSSEAP_WRONG_MECH;
+ }
+ if (GSS_ERROR(major))
+ return major;
+
+ /* If credentials were provided, check they're usable with this mech */
+ if (!gssEapCredAvailable(cred, ctx->mechanismUsed)) {
+ *minor = GSSEAP_CRED_MECH_MISMATCH;
+ return GSS_S_BAD_MECH;
+ }
+
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+eapGssSmInitIdentity(OM_uint32 *minor,
+ gss_cred_id_t cred,
+ gss_ctx_id_t ctx,
+ gss_name_t target,
+ gss_OID mech,
+ OM_uint32 reqFlags,
+ OM_uint32 timeReq,
+ gss_channel_bindings_t chanBindings,
+ gss_buffer_t inputToken,
+ gss_buffer_t outputToken)
+{
+ OM_uint32 major;
+ int initialContextToken;
+
+ initialContextToken = (inputToken->length == 0);
+ if (!initialContextToken) {
+ *minor = GSSEAP_WRONG_SIZE;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ major = initBegin(minor, cred, ctx, target, mech,
+ reqFlags, timeReq, chanBindings,
+ inputToken, outputToken);
+ if (GSS_ERROR(major))
+ return major;
+
+ ctx->state = EAP_STATE_AUTHENTICATE;
+
+ *minor = 0;
+ return GSS_S_CONTINUE_NEEDED;
+}
+
+static struct wpabuf emptyWpaBuffer;
+
+static OM_uint32
+eapGssSmInitAuthenticate(OM_uint32 *minor,
+ gss_cred_id_t cred,
+ gss_ctx_id_t ctx,
+ gss_name_t target,
+ gss_OID mech,
+ OM_uint32 reqFlags,
+ OM_uint32 timeReq,
+ gss_channel_bindings_t chanBindings,
+ gss_buffer_t inputToken,
+ gss_buffer_t outputToken)
+{
+ OM_uint32 major;
+ OM_uint32 tmpMinor;
+ int code;
+ struct wpabuf *resp = NULL;
+ int initialContextToken;
+
+ *minor = 0;
+
+ initialContextToken = (inputToken == GSS_C_NO_BUFFER ||
+ inputToken->length == 0);
+
+ major = peerConfigInit(minor, cred, ctx);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ if (ctx->initiatorCtx.eap == NULL) {
+ struct eap_config eapConfig;
+
+ memset(&eapConfig, 0, sizeof(eapConfig));
+
+ ctx->initiatorCtx.eap = eap_peer_sm_init(ctx,
+ &gssEapPolicyCallbacks,
+ ctx,
+ &eapConfig);
+ if (ctx->initiatorCtx.eap == NULL) {
+ major = GSS_S_FAILURE;
+ *minor = GSSEAP_PEER_SM_INIT_FAILURE;
+ goto cleanup;
+ }
+
+ ctx->flags |= CTX_FLAG_EAP_RESTART | CTX_FLAG_EAP_PORT_ENABLED;
+ }
+
+ ctx->flags |= CTX_FLAG_EAP_REQ; /* we have a Request from the acceptor */
+
+ wpabuf_set(&ctx->initiatorCtx.reqData,
+ inputToken->value, inputToken->length);
+
+ major = GSS_S_CONTINUE_NEEDED;
+
+ code = eap_peer_sm_step(ctx->initiatorCtx.eap);
+ if (ctx->flags & CTX_FLAG_EAP_RESP) {
+ ctx->flags &= ~(CTX_FLAG_EAP_RESP);
+
+ resp = eap_get_eapRespData(ctx->initiatorCtx.eap);
+ } else if (ctx->flags & CTX_FLAG_EAP_SUCCESS) {
+ major = initReady(minor, ctx, reqFlags);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ ctx->flags &= ~(CTX_FLAG_EAP_SUCCESS);
+ major = GSS_S_CONTINUE_NEEDED;
+ ctx->state = EAP_STATE_EXTENSIONS_REQ;
+ } else if (ctx->flags & CTX_FLAG_EAP_FAIL) {
+ major = GSS_S_DEFECTIVE_CREDENTIAL;
+ *minor = GSSEAP_PEER_AUTH_FAILURE;
+ } else if (code == 0 && initialContextToken) {
+ resp = &emptyWpaBuffer;
+ major = GSS_S_CONTINUE_NEEDED;
+ } else {
+ major = GSS_S_DEFECTIVE_TOKEN;
+ *minor = GSSEAP_PEER_BAD_MESSAGE;
+ }
+
+cleanup:
+ if (resp != NULL) {
+ OM_uint32 tmpMajor;
+ gss_buffer_desc respBuf;
+
+ assert(major == GSS_S_CONTINUE_NEEDED);
+
+ respBuf.length = wpabuf_len(resp);
+ respBuf.value = (void *)wpabuf_head(resp);
+
+ tmpMajor = duplicateBuffer(&tmpMinor, &respBuf, outputToken);
+ if (GSS_ERROR(tmpMajor)) {
+ major = tmpMajor;
+ *minor = tmpMinor;
+ }
+ }
+
+ wpabuf_set(&ctx->initiatorCtx.reqData, NULL, 0);
+ peerConfigFree(&tmpMinor, ctx);
+
+ return major;
+}
+
+static OM_uint32
+eapGssSmInitExtensionsReq(OM_uint32 *minor,
+ gss_cred_id_t cred,
+ gss_ctx_id_t ctx,
+ gss_name_t target,
+ gss_OID mech,
+ OM_uint32 reqFlags,
+ OM_uint32 timeReq,
+ gss_channel_bindings_t chanBindings,
+ gss_buffer_t inputToken,
+ gss_buffer_t outputToken)
+{
+ OM_uint32 major;
+
+ major = gssEapMakeExtensions(minor, cred, ctx, chanBindings, outputToken);
+ if (GSS_ERROR(major))
+ return major;
+
+ assert(outputToken->value != NULL);
+
+ ctx->state = EAP_STATE_EXTENSIONS_RESP;
+
+ *minor = 0;
+ return GSS_S_CONTINUE_NEEDED;
+}
+
+static OM_uint32
+eapGssSmInitExtensionsResp(OM_uint32 *minor,
+ gss_cred_id_t cred,
+ gss_ctx_id_t ctx,
+ gss_name_t target,
+ gss_OID mech,
+ OM_uint32 reqFlags,
+ OM_uint32 timeReq,
+ gss_channel_bindings_t chanBindings,
+ gss_buffer_t inputToken,
+ gss_buffer_t outputToken)
+{
+ OM_uint32 major;
+
+ major = gssEapVerifyExtensions(minor, cred, ctx, chanBindings, inputToken);
+ if (GSS_ERROR(major))
+ return major;
+
+ ctx->state = EAP_STATE_ESTABLISHED;
+
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+eapGssSmInitEstablished(OM_uint32 *minor,
+ gss_cred_id_t cred,
+ gss_ctx_id_t ctx,
+ gss_name_t target,
+ gss_OID mech,
+ OM_uint32 reqFlags,
+ OM_uint32 timeReq,
+ gss_channel_bindings_t chanBindings,
+ gss_buffer_t inputToken,
+ gss_buffer_t outputToken)
+{
+ /* Called with already established context */
+ *minor = GSSEAP_CONTEXT_ESTABLISHED;
+ return GSS_S_BAD_STATUS;
+}
+
+static OM_uint32
+eapGssSmInitError(OM_uint32 *minor,
+ gss_cred_id_t cred,
+ gss_ctx_id_t ctx,
+ gss_name_t target,
+ gss_OID mech,
+ OM_uint32 reqFlags,
+ OM_uint32 timeReq,
+ gss_channel_bindings_t chanBindings,
+ gss_buffer_t inputToken,
+ gss_buffer_t outputToken)
+{
+ OM_uint32 major;
+ unsigned char *p;
+
+ if (inputToken->length < 8) {
+ *minor = GSSEAP_TOK_TRUNC;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ p = (unsigned char *)inputToken->value;
+
+ major = load_uint32_be(&p[0]);
+ *minor = ERROR_TABLE_BASE_eapg + load_uint32_be(&p[4]);
+
+ if (!GSS_ERROR(major)) {
+ major = GSS_S_FAILURE;
+ *minor = GSSEAP_BAD_ERROR_TOKEN;
+ }
+
+ return major;
+}
+
+static struct gss_eap_initiator_sm {
+ enum gss_eap_token_type inputTokenType;
+ enum gss_eap_token_type outputTokenType;
+ OM_uint32 (*processToken)(OM_uint32 *,
+ gss_cred_id_t,
+ gss_ctx_id_t,
+ gss_name_t,
+ gss_OID,
+ OM_uint32,
+ OM_uint32,
+ gss_channel_bindings_t,
+ gss_buffer_t,
+ gss_buffer_t);
+} eapGssInitiatorSm[] = {
+ { TOK_TYPE_NONE, TOK_TYPE_EAP_RESP, eapGssSmInitIdentity },
+ { TOK_TYPE_EAP_REQ, TOK_TYPE_EAP_RESP, eapGssSmInitAuthenticate },
+ { TOK_TYPE_NONE, TOK_TYPE_EXT_REQ, eapGssSmInitExtensionsReq },
+ { TOK_TYPE_EXT_RESP, TOK_TYPE_NONE, eapGssSmInitExtensionsResp },
+ { TOK_TYPE_NONE, TOK_TYPE_NONE, eapGssSmInitEstablished },
+ { TOK_TYPE_CONTEXT_ERR, TOK_TYPE_NONE, eapGssSmInitError },
+#ifdef GSSEAP_ENABLE_REAUTH
+ { TOK_TYPE_GSS_REAUTH, TOK_TYPE_GSS_REAUTH, eapGssSmInitGssReauth },
+#endif
+};
+
+OM_uint32
+gss_init_sec_context(OM_uint32 *minor,
+ gss_cred_id_t cred,
+ gss_ctx_id_t *context_handle,
+ gss_name_t target_name,
+ gss_OID mech_type,
+ OM_uint32 req_flags,
+ OM_uint32 time_req,
+ gss_channel_bindings_t input_chan_bindings,
+ gss_buffer_t input_token,
+ gss_OID *actual_mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 *ret_flags,
+ OM_uint32 *time_rec)
+{
+ OM_uint32 major;
+ OM_uint32 tmpMajor, tmpMinor;
+ gss_ctx_id_t ctx = *context_handle;
+ struct gss_eap_initiator_sm *sm = NULL;
+ gss_buffer_desc innerInputToken;
+ gss_buffer_desc innerOutputToken = GSS_C_EMPTY_BUFFER;
+ enum gss_eap_token_type tokType;
+ gss_cred_id_t defaultCred = GSS_C_NO_CREDENTIAL;
+ int initialContextToken = 0;
+
+ *minor = 0;
+
+ output_token->length = 0;
+ output_token->value = NULL;
+
+ if (ctx == GSS_C_NO_CONTEXT) {
+ if (input_token != GSS_C_NO_BUFFER && input_token->length != 0) {
+ *minor = GSSEAP_WRONG_SIZE;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ major = gssEapAllocContext(minor, &ctx);
+ if (GSS_ERROR(major))
+ return major;
+
+ ctx->flags |= CTX_FLAG_INITIATOR;
+
+ initialContextToken = 1;
+ *context_handle = ctx;
+ }
+
+ GSSEAP_MUTEX_LOCK(&ctx->mutex);
+
+ if (cred == GSS_C_NO_CREDENTIAL) {
+ if (ctx->initiatorCtx.defaultCred == GSS_C_NO_CREDENTIAL) {
+ major = gssEapAcquireCred(minor,
+ GSS_C_NO_NAME,
+ GSS_C_NO_BUFFER,
+ time_req,
+ GSS_C_NO_OID_SET,
+ GSS_C_INITIATE,
+ &defaultCred,
+ NULL,
+ NULL);
+ if (GSS_ERROR(major))
+ goto cleanup;
+ }
+
+ cred = ctx->initiatorCtx.defaultCred;
+ }
+
+ GSSEAP_MUTEX_LOCK(&cred->mutex);
+
+#ifdef GSSEAP_ENABLE_REAUTH
+ if (initialContextToken && gssEapCanReauthP(cred, target_name, time_req))
+ ctx->state = EAP_STATE_KRB_REAUTH_GSS;
+#endif
+
+ if ((cred->flags & CRED_FLAG_INITIATE) == 0) {
+ major = GSS_S_NO_CRED;
+ *minor = GSSEAP_CRED_USAGE_MISMATCH;
+ goto cleanup;
+ }
+
+ sm = &eapGssInitiatorSm[ctx->state];
+
+ if (input_token != GSS_C_NO_BUFFER) {
+ major = gssEapVerifyToken(minor, ctx, input_token,
+ &tokType, &innerInputToken);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ if (tokType == TOK_TYPE_CONTEXT_ERR) {
+ ctx->state = EAP_STATE_ERROR;
+ } else if (tokType != sm->inputTokenType) {
+ major = GSS_S_DEFECTIVE_TOKEN;
+ *minor = GSSEAP_WRONG_TOK_ID;
+ goto cleanup;
+ }
+ } else {
+ innerInputToken.length = 0;
+ innerInputToken.value = NULL;
+ }
+
+ /*
+ * Advance through state machine whilst empty tokens are emitted and
+ * the status is not GSS_S_COMPLETE or an error status.
+ */
+ do {
+ sm = &eapGssInitiatorSm[ctx->state];
+
+ major = (sm->processToken)(minor,
+ cred,
+ ctx,
+ target_name,
+ mech_type,
+ req_flags,
+ time_req,
+ input_chan_bindings,
+ &innerInputToken,
+ &innerOutputToken);
+ if (GSS_ERROR(major))
+ goto cleanup;
+ } while (major == GSS_S_CONTINUE_NEEDED && innerOutputToken.value == NULL);
+
+ if (actual_mech_type != NULL) {
+ if (!gssEapInternalizeOid(ctx->mechanismUsed, actual_mech_type))
+ duplicateOid(&tmpMinor, ctx->mechanismUsed, actual_mech_type);
+ }
+ if (innerOutputToken.value != NULL) {
+ tmpMajor = gssEapMakeToken(&tmpMinor, ctx, &innerOutputToken,
+ sm->outputTokenType, output_token);
+ if (GSS_ERROR(tmpMajor)) {
+ major = tmpMajor;
+ *minor = tmpMinor;
+ goto cleanup;
+ }
+ }
+ if (ret_flags != NULL)
+ *ret_flags = ctx->gssFlags;
+ if (time_rec != NULL)
+ gssEapContextTime(&tmpMinor, ctx, time_rec);
+
+ assert(ctx->state == EAP_STATE_ESTABLISHED || major == GSS_S_CONTINUE_NEEDED);
+
+cleanup:
+ if (cred != GSS_C_NO_CREDENTIAL)
+ GSSEAP_MUTEX_UNLOCK(&cred->mutex);
+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
+
+ if (GSS_ERROR(major))
+ gssEapReleaseContext(&tmpMinor, context_handle);
+
+ gss_release_buffer(&tmpMinor, &innerOutputToken);
+
+ return major;
+}
+
+#ifdef GSSEAP_ENABLE_REAUTH
+static OM_uint32
+eapGssSmInitGssReauth(OM_uint32 *minor,
+ gss_cred_id_t cred,
+ gss_ctx_id_t ctx,
+ gss_name_t target,
+ gss_OID mech,
+ OM_uint32 reqFlags,
+ OM_uint32 timeReq,
+ gss_channel_bindings_t chanBindings,
+ gss_buffer_t inputToken,
+ gss_buffer_t outputToken)
+{
+ OM_uint32 major, tmpMinor;
+ gss_name_t mechTarget = GSS_C_NO_NAME;
+ gss_OID actualMech = GSS_C_NO_OID;
+ OM_uint32 gssFlags, timeRec;
+
+ assert(cred != GSS_C_NO_CREDENTIAL);
+
+ ctx->flags |= CTX_FLAG_KRB_REAUTH_GSS;
+
+ if (inputToken->length == 0) {
+ major = initBegin(minor, cred, ctx, target, mech,
+ reqFlags, timeReq, chanBindings,
+ inputToken, outputToken);
+ if (GSS_ERROR(major))
+ goto cleanup;
+ }
+
+ major = gssEapMechToGlueName(minor, target, &mechTarget);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ major = gssInitSecContext(minor,
+ cred->krbCred,
+ &ctx->kerberosCtx,
+ mechTarget,
+ (gss_OID)gss_mech_krb5,
+ reqFlags, /* | GSS_C_DCE_STYLE, */
+ timeReq,
+ chanBindings,
+ inputToken,
+ &actualMech,
+ outputToken,
+ &gssFlags,
+ &timeRec);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ ctx->gssFlags = gssFlags;
+
+ if (major == GSS_S_COMPLETE) {
+ major = gssEapReauthComplete(minor, ctx, cred, actualMech, timeRec);
+ if (GSS_ERROR(major))
+ goto cleanup;
+ ctx->state = EAP_STATE_ESTABLISHED;
+ }
+
+cleanup:
+ gssReleaseName(&tmpMinor, &mechTarget);
+
+ return major;
+}
+#endif /* GSSEAP_ENABLE_REAUTH */
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Enumerate the features supported by the GSS EAP mechanism.
+ */
+
+#include "gssapiP_eap.h"
+
+#define MA_ADD(ma, set) do { \
+ major = gss_add_oid_set_member(minor, (gss_OID)(ma), (set)); \
+ if (GSS_ERROR(major)) \
+ goto cleanup; \
+ } while (0)
+
+#define MA_SUPPORTED(ma) MA_ADD((ma), mech_attrs)
+#define MA_KNOWN(ma) MA_ADD((ma), known_mech_attrs)
+
+#ifndef HAVE_GSS_INQUIRE_ATTRS_FOR_MECH
+typedef const gss_OID_desc *gss_const_OID;
+#endif
+
+OM_uint32
+gss_inquire_attrs_for_mech(OM_uint32 *minor,
+ gss_const_OID mech_oid,
+ gss_OID_set *mech_attrs,
+ gss_OID_set *known_mech_attrs)
+{
+ OM_uint32 major, tmpMinor;
+
+ if (mech_attrs != NULL)
+ *mech_attrs = GSS_C_NO_OID_SET;
+ if (known_mech_attrs != NULL)
+ *known_mech_attrs = GSS_C_NO_OID_SET;
+
+ if (!gssEapIsConcreteMechanismOid((const gss_OID)mech_oid)) {
+ *minor = GSSEAP_WRONG_MECH;
+ return GSS_S_BAD_MECH;
+ }
+
+ if (mech_attrs != NULL) {
+ major = gss_create_empty_oid_set(minor, mech_attrs);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+#ifdef HAVE_GSS_INQUIRE_ATTRS_FOR_MECH
+ if (oidEqual(mech_oid, GSS_EAP_MECHANISM))
+ MA_SUPPORTED(GSS_C_MA_MECH_PSEUDO);
+ else
+ MA_SUPPORTED(GSS_C_MA_MECH_CONCRETE);
+ MA_SUPPORTED(GSS_C_MA_ITOK_FRAMED);
+ MA_SUPPORTED(GSS_C_MA_AUTH_INIT);
+ MA_SUPPORTED(GSS_C_MA_AUTH_TARG);
+ MA_SUPPORTED(GSS_C_MA_AUTH_INIT_INIT);
+ MA_SUPPORTED(GSS_C_MA_INTEG_PROT);
+ MA_SUPPORTED(GSS_C_MA_CONF_PROT);
+ MA_SUPPORTED(GSS_C_MA_MIC);
+ MA_SUPPORTED(GSS_C_MA_WRAP);
+ MA_SUPPORTED(GSS_C_MA_REPLAY_DET);
+ MA_SUPPORTED(GSS_C_MA_OOS_DET);
+ MA_SUPPORTED(GSS_C_MA_CBINDINGS);
+ MA_SUPPORTED(GSS_C_MA_CTX_TRANS);
+#endif
+ }
+
+ if (known_mech_attrs != NULL) {
+ major = gss_create_empty_oid_set(minor, known_mech_attrs);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+#ifdef HAVE_GSS_INQUIRE_ATTRS_FOR_MECH
+ MA_KNOWN(GSS_C_MA_MECH_CONCRETE);
+ MA_KNOWN(GSS_C_MA_MECH_PSEUDO);
+ MA_KNOWN(GSS_C_MA_MECH_COMPOSITE);
+ MA_KNOWN(GSS_C_MA_MECH_NEGO);
+ MA_KNOWN(GSS_C_MA_MECH_GLUE);
+ MA_KNOWN(GSS_C_MA_NOT_MECH);
+ MA_KNOWN(GSS_C_MA_DEPRECATED);
+ MA_KNOWN(GSS_C_MA_NOT_DFLT_MECH);
+ MA_KNOWN(GSS_C_MA_ITOK_FRAMED);
+ MA_KNOWN(GSS_C_MA_AUTH_INIT);
+ MA_KNOWN(GSS_C_MA_AUTH_TARG);
+ MA_KNOWN(GSS_C_MA_AUTH_INIT_INIT);
+ MA_KNOWN(GSS_C_MA_AUTH_TARG_INIT);
+ MA_KNOWN(GSS_C_MA_AUTH_INIT_ANON);
+ MA_KNOWN(GSS_C_MA_AUTH_TARG_ANON);
+ MA_KNOWN(GSS_C_MA_DELEG_CRED);
+ MA_KNOWN(GSS_C_MA_INTEG_PROT);
+ MA_KNOWN(GSS_C_MA_CONF_PROT);
+ MA_KNOWN(GSS_C_MA_MIC);
+ MA_KNOWN(GSS_C_MA_WRAP);
+ MA_KNOWN(GSS_C_MA_PROT_READY);
+ MA_KNOWN(GSS_C_MA_REPLAY_DET);
+ MA_KNOWN(GSS_C_MA_OOS_DET);
+ MA_KNOWN(GSS_C_MA_CBINDINGS);
+ MA_KNOWN(GSS_C_MA_PFS);
+ MA_KNOWN(GSS_C_MA_COMPRESS);
+ MA_KNOWN(GSS_C_MA_CTX_TRANS);
+#endif
+ }
+
+ major = GSS_S_COMPLETE;
+ *minor = 0;
+
+cleanup:
+ if (GSS_ERROR(major)) {
+ gss_release_oid_set(&tmpMinor, mech_attrs);
+ gss_release_oid_set(&tmpMinor, known_mech_attrs);
+ }
+
+ return major;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Return context handle properties.
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32
+gss_inquire_context(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ gss_name_t *src_name,
+ gss_name_t *targ_name,
+ OM_uint32 *lifetime_rec,
+ gss_OID *mech_type,
+ OM_uint32 *ctx_flags,
+ int *locally_initiated,
+ int *open)
+{
+ OM_uint32 major, tmpMinor;
+
+ if (ctx == GSS_C_NO_CONTEXT) {
+ *minor = EINVAL;
+ return GSS_S_NO_CONTEXT;
+ }
+
+ GSSEAP_MUTEX_LOCK(&ctx->mutex);
+
+ if (src_name != NULL) {
+ major = gssEapDuplicateName(minor, ctx->initiatorName, src_name);
+ if (GSS_ERROR(major))
+ goto cleanup;
+ }
+
+ if (targ_name != NULL) {
+ major = gssEapDuplicateName(minor, ctx->acceptorName, targ_name);
+ if (GSS_ERROR(major))
+ goto cleanup;
+ }
+
+ if (lifetime_rec != NULL) {
+ time_t now, lifetime;
+
+ if (ctx->expiryTime == 0) {
+ lifetime = GSS_C_INDEFINITE;
+ } else {
+ now = time(NULL);
+ lifetime = now - ctx->expiryTime;
+ if (lifetime < 0)
+ lifetime = 0;
+ }
+
+ *lifetime_rec = lifetime;
+ }
+
+ if (mech_type != NULL) {
+ if (!gssEapInternalizeOid(ctx->mechanismUsed, mech_type)) {
+ major = duplicateOid(minor, ctx->mechanismUsed, mech_type);
+ if (GSS_ERROR(major))
+ goto cleanup;
+ }
+ }
+
+ if (ctx_flags != NULL) {
+ *ctx_flags = ctx->gssFlags;
+ }
+
+ if (locally_initiated != NULL) {
+ *locally_initiated = CTX_IS_INITIATOR(ctx);
+ }
+
+ if (open != NULL) {
+ *open = CTX_IS_ESTABLISHED(ctx);
+ }
+
+ major = GSS_S_COMPLETE;
+ *minor = 0;
+
+cleanup:
+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
+
+ if (GSS_ERROR(major)) {
+ gssEapReleaseName(&tmpMinor, src_name);
+ gssEapReleaseName(&tmpMinor, targ_name);
+ }
+
+ return major;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Return credential handle properties.
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32
+gss_inquire_cred(OM_uint32 *minor,
+ gss_cred_id_t cred,
+ gss_name_t *name,
+ OM_uint32 *pLifetime,
+ gss_cred_usage_t *cred_usage,
+ gss_OID_set *mechanisms)
+{
+ OM_uint32 major;
+
+ if (cred == NULL) {
+ *minor = EINVAL;
+ return GSS_S_NO_CRED;
+ }
+
+ GSSEAP_MUTEX_LOCK(&cred->mutex);
+
+ if (name != NULL) {
+ major = gssEapDuplicateName(minor, cred->name, name);
+ if (GSS_ERROR(major))
+ goto cleanup;
+ }
+
+ if (pLifetime != NULL) {
+ time_t now, lifetime;
+
+ if (cred->expiryTime == 0) {
+ lifetime = GSS_C_INDEFINITE;
+ } else {
+ now = time(NULL);
+ lifetime = now - cred->expiryTime;
+ if (lifetime < 0)
+ lifetime = 0;
+ }
+
+ *pLifetime = lifetime;
+ }
+
+ if (cred_usage != NULL) {
+ OM_uint32 flags = (cred->flags & (CRED_FLAG_INITIATE | CRED_FLAG_ACCEPT));
+
+ switch (flags) {
+ case CRED_FLAG_INITIATE:
+ *cred_usage = GSS_C_INITIATE;
+ break;
+ case CRED_FLAG_ACCEPT:
+ *cred_usage = GSS_C_ACCEPT;
+ break;
+ default:
+ *cred_usage = GSS_C_BOTH;
+ break;
+ }
+ }
+
+ if (mechanisms != NULL) {
+ if (cred->mechanisms != GSS_C_NO_OID_SET)
+ major = duplicateOidSet(minor, cred->mechanisms, mechanisms);
+ else
+ major = gssEapIndicateMechs(minor, mechanisms);
+ if (GSS_ERROR(major))
+ goto cleanup;
+ }
+
+ major = GSS_S_COMPLETE;
+ *minor = 0;
+
+cleanup:
+ GSSEAP_MUTEX_UNLOCK(&cred->mutex);
+
+ return major;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Return extended credential handle properties.
+ */
+
+#include "gssapiP_eap.h"
+
+static struct {
+ gss_OID_desc oid;
+ OM_uint32 (*inquire)(OM_uint32 *, const gss_cred_id_t,
+ const gss_OID, gss_buffer_set_t *);
+} inquireCredOps[] = {
+};
+
+OM_uint32
+gss_inquire_cred_by_oid(OM_uint32 *minor,
+ const gss_cred_id_t cred_handle,
+ const gss_OID desired_object,
+ gss_buffer_set_t *data_set)
+{
+ OM_uint32 major;
+ int i;
+
+ *data_set = GSS_C_NO_BUFFER_SET;
+
+ if (cred_handle == GSS_C_NO_CREDENTIAL) {
+ *minor = EINVAL;
+ return GSS_S_NO_CRED;
+ }
+
+ GSSEAP_MUTEX_LOCK(&cred_handle->mutex);
+
+ major = GSS_S_UNAVAILABLE;
+ *minor = GSSEAP_BAD_CRED_OPTION;
+
+ for (i = 0; i < sizeof(inquireCredOps) / sizeof(inquireCredOps[0]); i++) {
+ if (oidEqual(&inquireCredOps[i].oid, desired_object)) {
+ major = (*inquireCredOps[i].inquire)(minor, cred_handle,
+ desired_object, data_set);
+ break;
+ }
+ }
+
+ GSSEAP_MUTEX_UNLOCK(&cred_handle->mutex);
+
+ return major;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Map mechanism OID to a SASL mechanism name.
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32
+gss_inquire_saslname_for_mech(OM_uint32 *minor,
+ const gss_OID mech,
+ gss_buffer_t sasl_mech_name,
+ gss_buffer_t mech_name,
+ gss_buffer_t mech_description)
+{
+ OM_uint32 major;
+ gss_buffer_t name;
+ krb5_enctype etype = ENCTYPE_NULL;
+ char krbBuf[128] = "eap-";
+
+ /* Dynamically construct mechanism name from Kerberos string enctype */
+ major = gssEapOidToEnctype(minor, mech, &etype);
+ if (GSS_ERROR(major))
+ return major;
+
+ if (mech_name != GSS_C_NO_BUFFER &&
+ krb5_enctype_to_name(etype, 0, &krbBuf[4], sizeof(krbBuf) - 4) == 0) {
+ major = makeStringBuffer(minor, krbBuf, mech_name);
+ if (GSS_ERROR(major))
+ return major;
+ }
+
+ if (mech_description != GSS_C_NO_BUFFER) {
+ major = makeStringBuffer(minor,
+ "Extensible Authentication Protocol GSS-API Mechanism",
+ mech_description);
+ if (GSS_ERROR(major))
+ return major;
+ }
+
+ if (sasl_mech_name != GSS_C_NO_BUFFER) {
+ name = gssEapOidToSaslName(mech);
+ if (name == GSS_C_NO_BUFFER) {
+ major = GSS_S_BAD_MECH;
+ *minor = GSSEAP_WRONG_MECH;
+ } else {
+ major = duplicateBuffer(minor, name, sasl_mech_name);
+ }
+ }
+
+ return major;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Determine mechanism OIDs supported by name.
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32
+gss_inquire_mechs_for_name(OM_uint32 *minor,
+ const gss_name_t input_name,
+ gss_OID_set *mech_types)
+{
+ return gssEapIndicateMechs(minor, mech_types);
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Enumerate name attributes.
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32 gss_inquire_name(OM_uint32 *minor,
+ gss_name_t name,
+ int *name_is_MN,
+ gss_OID *MN_mech,
+ gss_buffer_set_t *attrs)
+{
+ OM_uint32 major, tmpMinor;
+
+ *minor = 0;
+
+ if (name_is_MN != NULL)
+ *name_is_MN = 1;
+ if (MN_mech != NULL)
+ *MN_mech = GSS_EAP_MECHANISM;
+ if (attrs != NULL)
+ *attrs = GSS_C_NO_BUFFER_SET;
+
+ if (name == GSS_C_NO_NAME) {
+ *minor = EINVAL;
+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
+ }
+
+ if (attrs == NULL)
+ return GSS_S_COMPLETE;
+
+ GSSEAP_MUTEX_LOCK(&name->mutex);
+
+ major = gssEapInquireName(minor, name, name_is_MN, MN_mech, attrs);
+
+ GSSEAP_MUTEX_UNLOCK(&name->mutex);
+
+ if (GSS_ERROR(major))
+ gss_release_buffer_set(&tmpMinor, attrs);
+
+ return major;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Return supported name OID types.
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32
+gss_inquire_names_for_mech(OM_uint32 *minor,
+ gss_OID mechanism,
+ gss_OID_set *ret_name_types)
+{
+ OM_uint32 major, tmpMinor;
+ gss_OID nameTypes[] = {
+ GSS_C_NT_USER_NAME,
+ GSS_C_NT_HOSTBASED_SERVICE,
+ GSS_C_NT_EXPORT_NAME,
+#ifdef HAVE_GSS_C_NT_COMPOSITE_EXPORT
+ GSS_C_NT_COMPOSITE_EXPORT,
+#endif
+ GSS_EAP_NT_PRINCIPAL_NAME,
+ };
+ size_t i;
+
+ if (!gssEapIsMechanismOid(mechanism)) {
+ *minor = GSSEAP_WRONG_MECH;
+ return GSS_S_BAD_MECH;
+ }
+
+ major = gss_create_empty_oid_set(minor, ret_name_types);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ for (i = 0; i < sizeof(nameTypes)/sizeof(nameTypes[0]); i++) {
+ major = gss_add_oid_set_member(minor, nameTypes[i], ret_name_types);
+ if (GSS_ERROR(major))
+ goto cleanup;
+ }
+
+cleanup:
+ if (GSS_ERROR(major))
+ gss_release_oid_set(&tmpMinor, ret_name_types);
+
+ return major;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Map SASL mechanism name to a mechanism OID.
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32
+gss_inquire_mech_for_saslname(OM_uint32 *minor,
+ const gss_buffer_t sasl_mech_name,
+ gss_OID *mech_type)
+{
+ *mech_type = gssEapSaslNameToOid(sasl_mech_name);
+ if (*mech_type == GSS_C_NO_OID) {
+ *minor = GSSEAP_WRONG_MECH;
+ return GSS_S_BAD_MECH;
+ }
+
+ return GSS_S_COMPLETE;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Return extended properties of a context handle.
+ */
+
+#include "gssapiP_eap.h"
+
+static OM_uint32
+inquireSessionKey(OM_uint32 *minor,
+ const gss_ctx_id_t ctx,
+ const gss_OID desired_object,
+ gss_buffer_set_t *dataSet)
+{
+ OM_uint32 major, tmpMinor;
+ unsigned char oidBuf[16];
+ gss_buffer_desc buf;
+ gss_OID_desc oid;
+
+ buf.length = KRB_KEY_LENGTH(&ctx->rfc3961Key);
+ buf.value = KRB_KEY_DATA(&ctx->rfc3961Key);
+
+ major = gss_add_buffer_set_member(minor, &buf, dataSet);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ oid.length = sizeof(oidBuf);
+ oid.elements = oidBuf;
+
+ major = composeOid(minor,
+ "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x04",
+ 10,
+ ctx->encryptionType,
+ &oid);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ buf.length = oid.length;
+ buf.value = oid.elements;
+
+ major = gss_add_buffer_set_member(minor, &buf, dataSet);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ major = GSS_S_COMPLETE;
+ *minor = 0;
+
+cleanup:
+ if (GSS_ERROR(major) && *dataSet != GSS_C_NO_BUFFER_SET) {
+ gss_buffer_set_t set = *dataSet;
+
+ if (set->count != 0)
+ memset(set->elements[0].value, 0, set->elements[0].length);
+ gss_release_buffer_set(&tmpMinor, dataSet);
+ }
+
+ return major;
+}
+
+static struct {
+ gss_OID_desc oid;
+ OM_uint32 (*inquire)(OM_uint32 *, const gss_ctx_id_t,
+ const gss_OID, gss_buffer_set_t *);
+} inquireCtxOps[] = {
+ {
+ /* GSS_C_INQ_SSPI_SESSION_KEY */
+ { 11, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x05" },
+ inquireSessionKey
+ },
+ {
+ /* GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT + v1 */
+ { 12, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x06\x01" },
+ gssEapExportLucidSecContext
+ },
+};
+
+OM_uint32
+gss_inquire_sec_context_by_oid(OM_uint32 *minor,
+ const gss_ctx_id_t ctx,
+ const gss_OID desired_object,
+ gss_buffer_set_t *data_set)
+{
+ OM_uint32 major;
+ int i;
+
+ *data_set = GSS_C_NO_BUFFER_SET;
+
+ GSSEAP_MUTEX_LOCK(&ctx->mutex);
+
+ if (!CTX_IS_ESTABLISHED(ctx)) {
+ *minor = GSSEAP_CONTEXT_INCOMPLETE;
+ major = GSS_S_NO_CONTEXT;
+ goto cleanup;
+ }
+
+ major = GSS_S_UNAVAILABLE;
+ *minor = GSSEAP_BAD_CONTEXT_OPTION;
+
+ for (i = 0; i < sizeof(inquireCtxOps) / sizeof(inquireCtxOps[0]); i++) {
+ if (oidEqual(&inquireCtxOps[i].oid, desired_object)) {
+ major = (*inquireCtxOps[i].inquire)(minor, ctx,
+ desired_object, data_set);
+ break;
+ }
+ }
+
+cleanup:
+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
+
+ return major;
+}
--- /dev/null
+#!/bin/sh
+# install - install a program, script, or datafile
+
+scriptversion=2009-04-28.21; # UTC
+
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+
+nl='
+'
+IFS=" "" $nl"
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit=${DOITPROG-}
+if test -z "$doit"; then
+ doit_exec=exec
+else
+ doit_exec=$doit
+fi
+
+# Put in absolute file names if you don't have them in your path;
+# or use environment vars.
+
+chgrpprog=${CHGRPPROG-chgrp}
+chmodprog=${CHMODPROG-chmod}
+chownprog=${CHOWNPROG-chown}
+cmpprog=${CMPPROG-cmp}
+cpprog=${CPPROG-cp}
+mkdirprog=${MKDIRPROG-mkdir}
+mvprog=${MVPROG-mv}
+rmprog=${RMPROG-rm}
+stripprog=${STRIPPROG-strip}
+
+posix_glob='?'
+initialize_posix_glob='
+ test "$posix_glob" != "?" || {
+ if (set -f) 2>/dev/null; then
+ posix_glob=
+ else
+ posix_glob=:
+ fi
+ }
+'
+
+posix_mkdir=
+
+# Desired mode of installed file.
+mode=0755
+
+chgrpcmd=
+chmodcmd=$chmodprog
+chowncmd=
+mvcmd=$mvprog
+rmcmd="$rmprog -f"
+stripcmd=
+
+src=
+dst=
+dir_arg=
+dst_arg=
+
+copy_on_change=false
+no_target_directory=
+
+usage="\
+Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
+ or: $0 [OPTION]... SRCFILES... DIRECTORY
+ or: $0 [OPTION]... -t DIRECTORY SRCFILES...
+ or: $0 [OPTION]... -d DIRECTORIES...
+
+In the 1st form, copy SRCFILE to DSTFILE.
+In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
+In the 4th, create DIRECTORIES.
+
+Options:
+ --help display this help and exit.
+ --version display version info and exit.
+
+ -c (ignored)
+ -C install only if different (preserve the last data modification time)
+ -d create directories instead of installing files.
+ -g GROUP $chgrpprog installed files to GROUP.
+ -m MODE $chmodprog installed files to MODE.
+ -o USER $chownprog installed files to USER.
+ -s $stripprog installed files.
+ -t DIRECTORY install into DIRECTORY.
+ -T report an error if DSTFILE is a directory.
+
+Environment variables override the default commands:
+ CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
+ RMPROG STRIPPROG
+"
+
+while test $# -ne 0; do
+ case $1 in
+ -c) ;;
+
+ -C) copy_on_change=true;;
+
+ -d) dir_arg=true;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift;;
+
+ --help) echo "$usage"; exit $?;;
+
+ -m) mode=$2
+ case $mode in
+ *' '* | *' '* | *'
+'* | *'*'* | *'?'* | *'['*)
+ echo "$0: invalid mode: $mode" >&2
+ exit 1;;
+ esac
+ shift;;
+
+ -o) chowncmd="$chownprog $2"
+ shift;;
+
+ -s) stripcmd=$stripprog;;
+
+ -t) dst_arg=$2
+ shift;;
+
+ -T) no_target_directory=true;;
+
+ --version) echo "$0 $scriptversion"; exit $?;;
+
+ --) shift
+ break;;
+
+ -*) echo "$0: invalid option: $1" >&2
+ exit 1;;
+
+ *) break;;
+ esac
+ shift
+done
+
+if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
+ # When -d is used, all remaining arguments are directories to create.
+ # When -t is used, the destination is already specified.
+ # Otherwise, the last argument is the destination. Remove it from $@.
+ for arg
+ do
+ if test -n "$dst_arg"; then
+ # $@ is not empty: it contains at least $arg.
+ set fnord "$@" "$dst_arg"
+ shift # fnord
+ fi
+ shift # arg
+ dst_arg=$arg
+ done
+fi
+
+if test $# -eq 0; then
+ if test -z "$dir_arg"; then
+ echo "$0: no input file specified." >&2
+ exit 1
+ fi
+ # It's OK to call `install-sh -d' without argument.
+ # This can happen when creating conditional directories.
+ exit 0
+fi
+
+if test -z "$dir_arg"; then
+ trap '(exit $?); exit' 1 2 13 15
+
+ # Set umask so as not to create temps with too-generous modes.
+ # However, 'strip' requires both read and write access to temps.
+ case $mode in
+ # Optimize common cases.
+ *644) cp_umask=133;;
+ *755) cp_umask=22;;
+
+ *[0-7])
+ if test -z "$stripcmd"; then
+ u_plus_rw=
+ else
+ u_plus_rw='% 200'
+ fi
+ cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
+ *)
+ if test -z "$stripcmd"; then
+ u_plus_rw=
+ else
+ u_plus_rw=,u+rw
+ fi
+ cp_umask=$mode$u_plus_rw;;
+ esac
+fi
+
+for src
+do
+ # Protect names starting with `-'.
+ case $src in
+ -*) src=./$src;;
+ esac
+
+ if test -n "$dir_arg"; then
+ dst=$src
+ dstdir=$dst
+ test -d "$dstdir"
+ dstdir_status=$?
+ else
+
+ # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
+ # might cause directories to be created, which would be especially bad
+ # if $src (and thus $dsttmp) contains '*'.
+ if test ! -f "$src" && test ! -d "$src"; then
+ echo "$0: $src does not exist." >&2
+ exit 1
+ fi
+
+ if test -z "$dst_arg"; then
+ echo "$0: no destination specified." >&2
+ exit 1
+ fi
+
+ dst=$dst_arg
+ # Protect names starting with `-'.
+ case $dst in
+ -*) dst=./$dst;;
+ esac
+
+ # If destination is a directory, append the input filename; won't work
+ # if double slashes aren't ignored.
+ if test -d "$dst"; then
+ if test -n "$no_target_directory"; then
+ echo "$0: $dst_arg: Is a directory" >&2
+ exit 1
+ fi
+ dstdir=$dst
+ dst=$dstdir/`basename "$src"`
+ dstdir_status=0
+ else
+ # Prefer dirname, but fall back on a substitute if dirname fails.
+ dstdir=`
+ (dirname "$dst") 2>/dev/null ||
+ expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$dst" : 'X\(//\)[^/]' \| \
+ X"$dst" : 'X\(//\)$' \| \
+ X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
+ echo X"$dst" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'
+ `
+
+ test -d "$dstdir"
+ dstdir_status=$?
+ fi
+ fi
+
+ obsolete_mkdir_used=false
+
+ if test $dstdir_status != 0; then
+ case $posix_mkdir in
+ '')
+ # Create intermediate dirs using mode 755 as modified by the umask.
+ # This is like FreeBSD 'install' as of 1997-10-28.
+ umask=`umask`
+ case $stripcmd.$umask in
+ # Optimize common cases.
+ *[2367][2367]) mkdir_umask=$umask;;
+ .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
+
+ *[0-7])
+ mkdir_umask=`expr $umask + 22 \
+ - $umask % 100 % 40 + $umask % 20 \
+ - $umask % 10 % 4 + $umask % 2
+ `;;
+ *) mkdir_umask=$umask,go-w;;
+ esac
+
+ # With -d, create the new directory with the user-specified mode.
+ # Otherwise, rely on $mkdir_umask.
+ if test -n "$dir_arg"; then
+ mkdir_mode=-m$mode
+ else
+ mkdir_mode=
+ fi
+
+ posix_mkdir=false
+ case $umask in
+ *[123567][0-7][0-7])
+ # POSIX mkdir -p sets u+wx bits regardless of umask, which
+ # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
+ ;;
+ *)
+ tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
+ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
+
+ if (umask $mkdir_umask &&
+ exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
+ then
+ if test -z "$dir_arg" || {
+ # Check for POSIX incompatibilities with -m.
+ # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
+ # other-writeable bit of parent directory when it shouldn't.
+ # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
+ ls_ld_tmpdir=`ls -ld "$tmpdir"`
+ case $ls_ld_tmpdir in
+ d????-?r-*) different_mode=700;;
+ d????-?--*) different_mode=755;;
+ *) false;;
+ esac &&
+ $mkdirprog -m$different_mode -p -- "$tmpdir" && {
+ ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
+ test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
+ }
+ }
+ then posix_mkdir=:
+ fi
+ rmdir "$tmpdir/d" "$tmpdir"
+ else
+ # Remove any dirs left behind by ancient mkdir implementations.
+ rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
+ fi
+ trap '' 0;;
+ esac;;
+ esac
+
+ if
+ $posix_mkdir && (
+ umask $mkdir_umask &&
+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
+ )
+ then :
+ else
+
+ # The umask is ridiculous, or mkdir does not conform to POSIX,
+ # or it failed possibly due to a race condition. Create the
+ # directory the slow way, step by step, checking for races as we go.
+
+ case $dstdir in
+ /*) prefix='/';;
+ -*) prefix='./';;
+ *) prefix='';;
+ esac
+
+ eval "$initialize_posix_glob"
+
+ oIFS=$IFS
+ IFS=/
+ $posix_glob set -f
+ set fnord $dstdir
+ shift
+ $posix_glob set +f
+ IFS=$oIFS
+
+ prefixes=
+
+ for d
+ do
+ test -z "$d" && continue
+
+ prefix=$prefix$d
+ if test -d "$prefix"; then
+ prefixes=
+ else
+ if $posix_mkdir; then
+ (umask=$mkdir_umask &&
+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
+ # Don't fail if two instances are running concurrently.
+ test -d "$prefix" || exit 1
+ else
+ case $prefix in
+ *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) qprefix=$prefix;;
+ esac
+ prefixes="$prefixes '$qprefix'"
+ fi
+ fi
+ prefix=$prefix/
+ done
+
+ if test -n "$prefixes"; then
+ # Don't fail if two instances are running concurrently.
+ (umask $mkdir_umask &&
+ eval "\$doit_exec \$mkdirprog $prefixes") ||
+ test -d "$dstdir" || exit 1
+ obsolete_mkdir_used=true
+ fi
+ fi
+ fi
+
+ if test -n "$dir_arg"; then
+ { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
+ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
+ { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
+ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
+ else
+
+ # Make a couple of temp file names in the proper directory.
+ dsttmp=$dstdir/_inst.$$_
+ rmtmp=$dstdir/_rm.$$_
+
+ # Trap to clean up those temp files at exit.
+ trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
+
+ # Copy the file name to the temp name.
+ (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
+
+ # and set any options; do chmod last to preserve setuid bits.
+ #
+ # If any of these fail, we abort the whole thing. If we want to
+ # ignore errors from any of these, just make sure not to ignore
+ # errors from the above "$doit $cpprog $src $dsttmp" command.
+ #
+ { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
+ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
+ { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
+ { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
+
+ # If -C, don't bother to copy if it wouldn't change the file.
+ if $copy_on_change &&
+ old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
+ new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
+
+ eval "$initialize_posix_glob" &&
+ $posix_glob set -f &&
+ set X $old && old=:$2:$4:$5:$6 &&
+ set X $new && new=:$2:$4:$5:$6 &&
+ $posix_glob set +f &&
+
+ test "$old" = "$new" &&
+ $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
+ then
+ rm -f "$dsttmp"
+ else
+ # Rename the file to the real destination.
+ $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
+
+ # The rename failed, perhaps because mv can't rename something else
+ # to itself, or perhaps because mv is so ancient that it does not
+ # support -f.
+ {
+ # Now remove or move aside any old file at destination location.
+ # We try this two ways since rm can't unlink itself on some
+ # systems and the destination file might be busy for other
+ # reasons. In this case, the final cleanup might fail but the new
+ # file should still install successfully.
+ {
+ test ! -f "$dst" ||
+ $doit $rmcmd -f "$dst" 2>/dev/null ||
+ { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
+ { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
+ } ||
+ { echo "$0: cannot unlink or rename $dst" >&2
+ (exit 1); exit 1
+ }
+ } &&
+
+ # Now rename the file to the real destination.
+ $doit $mvcmd "$dsttmp" "$dst"
+ }
+ fi || exit 1
+
+ trap '' 0
+ fi
+done
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32
+gss_map_name_to_any(OM_uint32 *minor,
+ gss_name_t name,
+ int authenticated,
+ gss_buffer_t type_id,
+ gss_any_t *output)
+{
+ OM_uint32 major;
+
+ *output = (gss_any_t)NULL;
+
+ if (name == GSS_C_NO_NAME) {
+ *minor = EINVAL;
+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
+ }
+
+ GSSEAP_MUTEX_LOCK(&name->mutex);
+
+ major = gssEapMapNameToAny(minor, name, authenticated, type_id, output);
+
+ GSSEAP_MUTEX_UNLOCK(&name->mutex);
+
+ return major;
+}
--- /dev/null
+#
+# Sample MIT mechanism glue configuration for EAP GSS mechanism.
+# Any encryption type supported by Kerberos can be defined as the
+# last element of the OID arc.
+#
+eap-aes128 1.3.6.1.4.1.5322.22.1.17 mech_eap.so
+eap-aes256 1.3.6.1.4.1.5322.22.1.18 mech_eap.so
--- /dev/null
+gss_accept_sec_context
+gss_acquire_cred
+gss_add_cred
+gss_add_cred_with_password
+gss_canonicalize_name
+gss_compare_name
+gss_context_time
+gss_delete_sec_context
+gss_display_name
+gss_display_name_ext
+gss_display_status
+gss_duplicate_name
+gss_export_name
+gss_export_name_composite
+gss_export_sec_context
+gss_get_mic
+gss_get_name_attribute
+gss_import_name
+gss_import_sec_context
+gss_indicate_mechs
+gss_init_sec_context
+gss_inquire_attrs_for_mech
+gss_inquire_context
+gss_inquire_cred
+gss_inquire_cred_by_oid
+gss_inquire_mechs_for_name
+gss_inquire_mech_for_saslname
+gss_inquire_name
+gss_inquire_names_for_mech
+gss_inquire_saslname_for_mech
+gss_inquire_sec_context_by_oid
+gss_map_name_to_any
+gss_process_context_token
+gss_pseudo_random
+gss_release_any_name_mapping
+gss_release_cred
+gss_release_name
+gss_internal_release_oid
+gss_set_name_attribute
+gss_set_sec_context_option
+gss_store_cred
+gss_unwrap
+gss_unwrap_iov
+gss_verify_mic
+gss_wrap
+gss_wrap_iov
+gss_wrap_iov_length
+gss_wrap_size_limit
+GSS_EAP_AES128_CTS_HMAC_SHA1_96_MECHANISM
+GSS_EAP_AES256_CTS_HMAC_SHA1_96_MECHANISM
+GSS_EAP_NT_PRINCIPAL_NAME
+gssspi_acquire_cred_with_password
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32
+gssspi_mech_invoke(OM_uint32 *minor,
+ const gss_OID desired_mech,
+ const gss_OID desired_object,
+ gss_buffer_t value)
+{
+ *minor = GSSEAP_BAD_INVOCATION;
+
+ return GSS_S_UNAVAILABLE;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32
+gss_process_context_token(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ gss_buffer_t token_buffer)
+{
+ OM_uint32 major;
+ gss_iov_buffer_desc iov[1];
+
+ *minor = 0;
+
+ if (ctx == NULL) {
+ *minor = EINVAL;
+ return GSS_S_NO_CONTEXT;
+ }
+
+ GSSEAP_MUTEX_LOCK(&ctx->mutex);
+
+ if (!CTX_IS_ESTABLISHED(ctx)) {
+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
+ *minor = GSSEAP_CONTEXT_INCOMPLETE;
+ return GSS_S_NO_CONTEXT;
+ }
+
+ iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
+ iov[0].buffer = *token_buffer;
+
+ major = gssEapUnwrapOrVerifyMIC(minor, ctx, NULL, NULL,
+ iov, 1, TOK_TYPE_DELETE_CONTEXT);
+ if (GSS_ERROR(major)) {
+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
+ return major;
+ }
+
+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
+
+ return gssEapReleaseContext(minor, &ctx);
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Copyright 2009 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+/*
+ * PRF
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32
+gss_pseudo_random(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ int prf_key,
+ const gss_buffer_t prf_in,
+ ssize_t desired_output_len,
+ gss_buffer_t prf_out)
+{
+ krb5_error_code code;
+ int i;
+ OM_uint32 tmpMinor;
+ size_t prflen;
+ krb5_data t, ns;
+ unsigned char *p;
+ krb5_context krbContext;
+
+ prf_out->length = 0;
+ prf_out->value = NULL;
+
+ if (ctx == GSS_C_NO_CONTEXT) {
+ *minor = EINVAL;
+ return GSS_S_NO_CONTEXT;
+ }
+
+ *minor = 0;
+
+ GSSEAP_MUTEX_LOCK(&ctx->mutex);
+
+ if (!CTX_IS_ESTABLISHED(ctx)) {
+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
+ *minor = GSSEAP_CONTEXT_INCOMPLETE;
+ return GSS_S_NO_CONTEXT;
+ }
+
+ GSSEAP_KRB_INIT(&krbContext);
+
+ t.length = 0;
+ t.data = NULL;
+
+ ns.length = 0;
+ ns.data = NULL;
+
+ if (prf_key != GSS_C_PRF_KEY_PARTIAL &&
+ prf_key != GSS_C_PRF_KEY_FULL) {
+ code = GSSEAP_BAD_PRF_KEY;
+ goto cleanup;
+ }
+
+ prf_out->value = GSSEAP_MALLOC(desired_output_len);
+ if (prf_out->value == NULL) {
+ code = ENOMEM;
+ goto cleanup;
+ }
+ prf_out->length = desired_output_len;
+
+ code = krb5_c_prf_length(krbContext,
+ ctx->encryptionType,
+ &prflen);
+ if (code != 0)
+ goto cleanup;
+
+ ns.length = 4 + prf_in->length;
+ ns.data = GSSEAP_MALLOC(ns.length);
+ if (ns.data == NULL) {
+ code = ENOMEM;
+ goto cleanup;
+ }
+
+ t.length = prflen;
+ t.data = GSSEAP_MALLOC(t.length);
+ if (t.data == NULL) {
+ code = ENOMEM;
+ goto cleanup;
+ }
+
+ memcpy(ns.data + 4, prf_in->value, prf_in->length);
+ i = 0;
+ p = (unsigned char *)prf_out->value;
+ while (desired_output_len > 0) {
+ store_uint32_be(i, ns.data);
+
+ code = krb5_c_prf(krbContext, &ctx->rfc3961Key, &ns, &t);
+ if (code != 0)
+ goto cleanup;
+
+ memcpy(p, t.data, MIN(t.length, desired_output_len));
+
+ p += t.length;
+ desired_output_len -= t.length;
+ i++;
+ }
+
+cleanup:
+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
+
+ if (code != 0)
+ gss_release_buffer(&tmpMinor, prf_out);
+ krb5_free_data_contents(krbContext, &ns);
+ krb5_free_data_contents(krbContext, &t);
+
+ *minor = code;
+
+ return (code == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
+}
--- /dev/null
+authdata_client_0
--- /dev/null
+config gss-eap {
+ type = UDP
+ server {
+ hostname = "localhost"
+ service = "1812"
+ secret = "testing123"
+ timeout = 1
+ tries = 10
+ }
+}
--- /dev/null
+#
+# Copyright (c) 2010, JANET(UK)
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# 3. Neither the name of JANET(UK) nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+
+# Placeholders only
+error_table rse
+
+end
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32
+gss_release_any_name_mapping(OM_uint32 *minor,
+ gss_name_t name,
+ gss_buffer_t type_id,
+ gss_any_t *input)
+{
+ OM_uint32 major;
+
+ *minor = 0;
+
+ if (name == GSS_C_NO_NAME) {
+ *minor = EINVAL;
+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
+ }
+
+ GSSEAP_MUTEX_LOCK(&name->mutex);
+
+ major = gssEapReleaseAnyNameMapping(minor, name, type_id, input);
+
+ *input = NULL;
+
+ GSSEAP_MUTEX_UNLOCK(&name->mutex);
+
+ return major;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Release a credential handle.
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32
+gss_release_cred(OM_uint32 *minor,
+ gss_cred_id_t *cred_handle)
+{
+ return gssEapReleaseCred(minor, cred_handle);
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Release a name.
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32
+gss_release_name(OM_uint32 *minor,
+ gss_name_t *name)
+{
+ return gssEapReleaseName(minor, name);
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Mark an internalized OID as not required to be released.
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32
+gss_internal_release_oid(OM_uint32 *minor,
+ gss_OID *oid)
+{
+ gss_OID internalizedOid = GSS_C_NO_OID;
+
+ *minor = 0;
+
+ if (gssEapInternalizeOid(*oid, &internalizedOid)) {
+ /* OID was internalized, so we can mark it as "freed" */
+ *oid = GSS_C_NO_OID;
+ return GSS_S_COMPLETE;
+ }
+
+ /* we don't know about this OID */
+ return GSS_S_CONTINUE_NEEDED;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Set an extended property on a credential handle.
+ */
+
+#include "gssapiP_eap.h"
+
+static OM_uint32
+setCredRadiusConfigFile(OM_uint32 *minor,
+ gss_cred_id_t cred,
+ const gss_OID oid,
+ const gss_buffer_t buffer)
+{
+ OM_uint32 major;
+ gss_buffer_desc configFileBuffer = GSS_C_EMPTY_BUFFER;
+
+ if (buffer != GSS_C_NO_BUFFER && buffer->length != 0) {
+ major = duplicateBuffer(minor, buffer, &configFileBuffer);
+ if (GSS_ERROR(major))
+ return major;
+ }
+
+ if (cred->radiusConfigFile != NULL)
+ GSSEAP_FREE(cred->radiusConfigFile);
+
+ cred->radiusConfigFile = (char *)configFileBuffer.value;
+
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+setCredRadiusConfigStanza(OM_uint32 *minor,
+ gss_cred_id_t cred,
+ const gss_OID oid,
+ const gss_buffer_t buffer)
+{
+ OM_uint32 major;
+ gss_buffer_desc configStanzaBuffer = GSS_C_EMPTY_BUFFER;
+
+ if (buffer != GSS_C_NO_BUFFER && buffer->length != 0) {
+ major = duplicateBuffer(minor, buffer, &configStanzaBuffer);
+ if (GSS_ERROR(major))
+ return major;
+ }
+
+ if (cred->radiusConfigStanza != NULL)
+ GSSEAP_FREE(cred->radiusConfigStanza);
+
+ cred->radiusConfigStanza = (char *)configStanzaBuffer.value;
+
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+setCredFlag(OM_uint32 *minor,
+ gss_cred_id_t cred,
+ const gss_OID oid,
+ const gss_buffer_t buffer)
+{
+ OM_uint32 flags;
+ unsigned char *p;
+
+ if (buffer == GSS_C_NO_BUFFER) {
+ *minor = EINVAL;
+ return GSS_S_FAILURE;
+ }
+
+ if (buffer->length < 4) {
+ *minor = GSSEAP_WRONG_SIZE;
+ return GSS_S_FAILURE;
+ }
+
+ p = (unsigned char *)buffer->value;
+
+ flags = load_uint32_be(buffer->value) & CRED_FLAG_PUBLIC_MASK;
+
+ if (buffer->length > 4 && p[4])
+ cred->flags &= ~(flags);
+ else
+ cred->flags |= flags;
+
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
+
+static struct {
+ gss_OID_desc oid;
+ OM_uint32 (*setOption)(OM_uint32 *, gss_cred_id_t cred,
+ const gss_OID, const gss_buffer_t);
+} setCredOps[] = {
+ /* 1.3.6.1.4.1.5322.22.3.3.1 */
+ {
+ { 11, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x03\x03\x01" },
+ setCredRadiusConfigFile,
+ },
+ /* 1.3.6.1.4.1.5322.22.3.3.2 */
+ {
+ { 11, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x03\x03\x02" },
+ setCredRadiusConfigStanza,
+ },
+ /* 1.3.6.1.4.1.5322.22.3.3.3 */
+ {
+ { 11, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x03\x03\x03" },
+ setCredFlag,
+ },
+};
+
+gss_OID GSS_EAP_CRED_SET_RADIUS_CONFIG_FILE = &setCredOps[0].oid;
+gss_OID GSS_EAP_CRED_SET_RADIUS_CONFIG_STANZA = &setCredOps[1].oid;
+gss_OID GSS_EAP_CRED_SET_CRED_FLAG = &setCredOps[2].oid;
+
+OM_uint32
+gssspi_set_cred_option(OM_uint32 *minor,
+ gss_cred_id_t *pCred,
+ const gss_OID desired_object,
+ const gss_buffer_t value)
+{
+ OM_uint32 major;
+ gss_cred_id_t cred = *pCred;
+ int i;
+
+ if (cred == GSS_C_NO_CREDENTIAL) {
+ *minor = EINVAL;
+ return GSS_S_UNAVAILABLE;
+ }
+
+ GSSEAP_MUTEX_LOCK(&cred->mutex);
+
+ major = GSS_S_UNAVAILABLE;
+ *minor = GSSEAP_BAD_CRED_OPTION;
+
+ for (i = 0; i < sizeof(setCredOps) / sizeof(setCredOps[0]); i++) {
+ if (oidEqual(&setCredOps[i].oid, desired_object)) {
+ major = (*setCredOps[i].setOption)(minor, cred,
+ desired_object, value);
+ break;
+ }
+ }
+
+ GSSEAP_MUTEX_UNLOCK(&cred->mutex);
+
+ return major;
+}
+
+#if 0
+OM_uint32
+gsseap_set_cred_flag(OM_uint32 *minor,
+ gss_cred_id_t cred,
+ OM_uint32 flag,
+ int clear)
+{
+ unsigned char buf[5];
+ gss_buffer_desc value;
+
+ value.length = sizeof(buf);
+ value.value = buf;
+
+ store_uint32_be(flag, buf);
+ buf[4] = (clear != 0);
+
+ return gssspi_set_cred_option(minor, cred,
+ GSS_EAP_CRED_SET_CRED_FLAG, &value);
+}
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Set an attribute on a name.
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32
+gss_set_name_attribute(OM_uint32 *minor,
+ gss_name_t name,
+ int complete,
+ gss_buffer_t attr,
+ gss_buffer_t value)
+{
+ OM_uint32 major;
+
+ if (name == GSS_C_NO_NAME) {
+ *minor = EINVAL;
+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
+ }
+
+ GSSEAP_MUTEX_LOCK(&name->mutex);
+
+ major = gssEapSetNameAttribute(minor, name, complete, attr, value);
+
+ GSSEAP_MUTEX_UNLOCK(&name->mutex);
+
+ return major;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Set an extended property on a context handle.
+ */
+
+#include "gssapiP_eap.h"
+
+static struct {
+ gss_OID_desc oid;
+ OM_uint32 (*setOption)(OM_uint32 *, gss_ctx_id_t *pCtx,
+ const gss_OID, const gss_buffer_t);
+} setCtxOps[] = {
+};
+
+OM_uint32
+gss_set_sec_context_option(OM_uint32 *minor,
+ gss_ctx_id_t *pCtx,
+ const gss_OID desired_object,
+ const gss_buffer_t value)
+{
+ OM_uint32 major;
+ gss_ctx_id_t ctx = *pCtx;
+ int i;
+
+ major = GSS_S_UNAVAILABLE;
+ *minor = GSSEAP_BAD_CONTEXT_OPTION;
+
+ if (ctx != GSS_C_NO_CONTEXT)
+ GSSEAP_MUTEX_LOCK(&ctx->mutex);
+
+ for (i = 0; i < sizeof(setCtxOps) / sizeof(setCtxOps[0]); i++) {
+ if (oidEqual(&setCtxOps[i].oid, desired_object)) {
+ major = (*setCtxOps[i].setOption)(minor, &ctx,
+ desired_object, value);
+ break;
+ }
+ }
+
+ if (*pCtx == NULL)
+ *pCtx = ctx;
+ else
+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
+
+ return major;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32
+gss_store_cred(OM_uint32 *minor,
+ const gss_cred_id_t cred,
+ gss_cred_usage_t input_usage,
+ const gss_OID desired_mech,
+ OM_uint32 overwrite_cred,
+ OM_uint32 default_cred,
+ gss_OID_set *elements_stored,
+ gss_cred_usage_t *cred_usage_stored)
+{
+ OM_uint32 major;
+
+ if (elements_stored != NULL)
+ *elements_stored = GSS_C_NO_OID_SET;
+ if (cred_usage_stored != NULL)
+ *cred_usage_stored = input_usage;
+
+ if (cred == GSS_C_NO_CREDENTIAL) {
+ *minor = EINVAL;
+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CRED;
+ }
+
+ GSSEAP_MUTEX_LOCK(&cred->mutex);
+
+ major = GSS_S_COMPLETE;
+ *minor = 0;
+
+#ifdef GSSEAP_ENABLE_REAUTH
+ if (cred->krbCred != GSS_C_NO_CREDENTIAL) {
+ major = gssStoreCred(minor,
+ cred->krbCred,
+ input_usage,
+ (gss_OID)gss_mech_krb5,
+ overwrite_cred,
+ default_cred,
+ elements_stored,
+ cred_usage_stored);
+ }
+#endif
+
+ GSSEAP_MUTEX_UNLOCK(&cred->mutex);
+
+ return major;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Message protection services: unwrap.
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32
+gss_unwrap(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ gss_buffer_t input_message_buffer,
+ gss_buffer_t output_message_buffer,
+ int *conf_state,
+ gss_qop_t *qop_state)
+{
+ OM_uint32 major, tmpMinor;
+ gss_iov_buffer_desc iov[2];
+
+ if (ctx == GSS_C_NO_CONTEXT) {
+ *minor = EINVAL;
+ return GSS_S_NO_CONTEXT;
+ }
+
+ *minor = 0;
+
+ GSSEAP_MUTEX_LOCK(&ctx->mutex);
+
+ if (!CTX_IS_ESTABLISHED(ctx)) {
+ major = GSS_S_NO_CONTEXT;
+ *minor = GSSEAP_CONTEXT_INCOMPLETE;
+ goto cleanup;
+ }
+
+ iov[0].type = GSS_IOV_BUFFER_TYPE_STREAM;
+ iov[0].buffer = *input_message_buffer;
+
+ iov[1].type = GSS_IOV_BUFFER_TYPE_DATA | GSS_IOV_BUFFER_FLAG_ALLOCATE;
+ iov[1].buffer.value = NULL;
+ iov[1].buffer.length = 0;
+
+ major = gssEapUnwrapOrVerifyMIC(minor, ctx, conf_state, qop_state,
+ iov, 2, TOK_TYPE_WRAP);
+ if (major == GSS_S_COMPLETE) {
+ *output_message_buffer = iov[1].buffer;
+ } else {
+ if (iov[1].type & GSS_IOV_BUFFER_FLAG_ALLOCATED)
+ gss_release_buffer(&tmpMinor, &iov[1].buffer);
+ }
+
+cleanup:
+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
+
+ return major;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Copyright 2008 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+/*
+ * Message protection services: unwrap with scatter-gather API.
+ */
+
+#include "gssapiP_eap.h"
+
+/*
+ * Caller must provide TOKEN | DATA | PADDING | TRAILER, except
+ * for DCE in which case it can just provide TOKEN | DATA (must
+ * guarantee that DATA is padded)
+ */
+OM_uint32
+unwrapToken(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ int *conf_state,
+ gss_qop_t *qop_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ enum gss_eap_token_type toktype)
+{
+ OM_uint32 code;
+ gss_iov_buffer_t header;
+ gss_iov_buffer_t padding;
+ gss_iov_buffer_t trailer;
+ unsigned char flags;
+ unsigned char *ptr = NULL;
+ int keyUsage;
+ size_t rrc, ec;
+ size_t dataLen, assocDataLen;
+ uint64_t seqnum;
+ int valid = 0;
+ int conf_flag = 0;
+ krb5_context krbContext;
+
+ GSSEAP_KRB_INIT(&krbContext);
+
+ *minor = 0;
+
+ if (qop_state != NULL)
+ *qop_state = GSS_C_QOP_DEFAULT;
+
+ header = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
+ assert(header != NULL);
+
+ padding = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
+ if (padding != NULL && padding->buffer.length != 0) {
+ *minor = GSSEAP_BAD_PADDING_IOV;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ trailer = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
+
+ flags = rfc4121Flags(ctx, TRUE);
+
+ if (toktype == TOK_TYPE_WRAP) {
+ keyUsage = !CTX_IS_INITIATOR(ctx)
+ ? KEY_USAGE_INITIATOR_SEAL
+ : KEY_USAGE_ACCEPTOR_SEAL;
+ } else {
+ keyUsage = !CTX_IS_INITIATOR(ctx)
+ ? KEY_USAGE_INITIATOR_SIGN
+ : KEY_USAGE_ACCEPTOR_SIGN;
+ }
+
+ gssEapIovMessageLength(iov, iov_count, &dataLen, &assocDataLen);
+
+ ptr = (unsigned char *)header->buffer.value;
+
+ if (header->buffer.length < 16) {
+ *minor = GSSEAP_TOK_TRUNC;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ if ((ptr[2] & flags) != flags) {
+ *minor = GSSEAP_BAD_DIRECTION;
+ return GSS_S_BAD_SIG;
+ }
+
+ if (toktype == TOK_TYPE_WRAP) {
+ unsigned int krbTrailerLen;
+
+ if (load_uint16_be(ptr) != TOK_TYPE_WRAP)
+ goto defective;
+ conf_flag = ((ptr[2] & TOK_FLAG_WRAP_CONFIDENTIAL) != 0);
+ if (ptr[3] != 0xFF)
+ goto defective;
+ ec = load_uint16_be(ptr + 4);
+ rrc = load_uint16_be(ptr + 6);
+ seqnum = load_uint64_be(ptr + 8);
+
+ code = krb5_c_crypto_length(krbContext,
+ ctx->encryptionType,
+ conf_flag ? KRB5_CRYPTO_TYPE_TRAILER :
+ KRB5_CRYPTO_TYPE_CHECKSUM,
+ &krbTrailerLen);
+ if (code != 0) {
+ *minor = code;
+ return GSS_S_FAILURE;
+ }
+
+ /* Deal with RRC */
+ if (trailer == NULL) {
+ size_t desired_rrc = krbTrailerLen;
+
+ if (conf_flag) {
+ desired_rrc += 16; /* E(Header) */
+
+ if ((ctx->gssFlags & GSS_C_DCE_STYLE) == 0)
+ desired_rrc += ec;
+ }
+
+ /* According to MS, we only need to deal with a fixed RRC for DCE */
+ if (rrc != desired_rrc)
+ goto defective;
+ } else if (rrc != 0) {
+ goto defective;
+ }
+
+ if (conf_flag) {
+ unsigned char *althdr;
+
+ /* Decrypt */
+ code = gssEapDecrypt(krbContext,
+ ((ctx->gssFlags & GSS_C_DCE_STYLE) != 0),
+ ec, rrc, &ctx->rfc3961Key,
+ keyUsage, 0, iov, iov_count);
+ if (code != 0) {
+ *minor = code;
+ return GSS_S_BAD_SIG;
+ }
+
+ /* Validate header integrity */
+ if (trailer == NULL)
+ althdr = (unsigned char *)header->buffer.value + 16 + ec;
+ else
+ althdr = (unsigned char *)trailer->buffer.value + ec;
+
+ if (load_uint16_be(althdr) != TOK_TYPE_WRAP
+ || althdr[2] != ptr[2]
+ || althdr[3] != ptr[3]
+ || memcmp(althdr + 8, ptr + 8, 8) != 0) {
+ *minor = GSSEAP_BAD_WRAP_TOKEN;
+ return GSS_S_BAD_SIG;
+ }
+ } else {
+ /* Verify checksum: note EC is checksum size here, not padding */
+ if (ec != krbTrailerLen)
+ goto defective;
+
+ /* Zero EC, RRC before computing checksum */
+ store_uint16_be(0, ptr + 4);
+ store_uint16_be(0, ptr + 6);
+
+ code = gssEapVerify(krbContext, ctx->checksumType, rrc,
+ &ctx->rfc3961Key, keyUsage,
+ iov, iov_count, &valid);
+ if (code != 0 || valid == FALSE) {
+ *minor = code;
+ return GSS_S_BAD_SIG;
+ }
+ }
+
+ code = sequenceCheck(minor, &ctx->seqState, seqnum);
+ } else if (toktype == TOK_TYPE_MIC) {
+ if (load_uint16_be(ptr) != toktype)
+ goto defective;
+
+ verify_mic_1:
+ if (ptr[3] != 0xFF)
+ goto defective;
+ seqnum = load_uint64_be(ptr + 8);
+
+ code = gssEapVerify(krbContext, ctx->checksumType, 0,
+ &ctx->rfc3961Key, keyUsage,
+ iov, iov_count, &valid);
+ if (code != 0 || valid == FALSE) {
+ *minor = code;
+ return GSS_S_BAD_SIG;
+ }
+ code = sequenceCheck(minor, &ctx->seqState, seqnum);
+ } else if (toktype == TOK_TYPE_DELETE_CONTEXT) {
+ if (load_uint16_be(ptr) != TOK_TYPE_DELETE_CONTEXT)
+ goto defective;
+ goto verify_mic_1;
+ } else {
+ goto defective;
+ }
+
+ *minor = 0;
+
+ if (conf_state != NULL)
+ *conf_state = conf_flag;
+
+ return code;
+
+defective:
+ *minor = GSSEAP_BAD_WRAP_TOKEN;
+
+ return GSS_S_DEFECTIVE_TOKEN;
+}
+
+int
+rotateLeft(void *ptr, size_t bufsiz, size_t rc)
+{
+ void *tbuf;
+
+ if (bufsiz == 0)
+ return 0;
+ rc = rc % bufsiz;
+ if (rc == 0)
+ return 0;
+
+ tbuf = GSSEAP_MALLOC(rc);
+ if (tbuf == NULL)
+ return ENOMEM;
+
+ memcpy(tbuf, ptr, rc);
+ memmove(ptr, (char *)ptr + rc, bufsiz - rc);
+ memcpy((char *)ptr + bufsiz - rc, tbuf, rc);
+ GSSEAP_FREE(tbuf);
+
+ return 0;
+}
+
+/*
+ * Split a STREAM | SIGN_DATA | DATA into
+ * HEADER | SIGN_DATA | DATA | PADDING | TRAILER
+ */
+static OM_uint32
+unwrapStream(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ int *conf_state,
+ gss_qop_t *qop_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ enum gss_eap_token_type toktype)
+{
+ unsigned char *ptr;
+ OM_uint32 code = 0, major = GSS_S_FAILURE;
+ krb5_context krbContext;
+ int conf_req_flag, toktype2;
+ int i = 0, j;
+ gss_iov_buffer_desc *tiov = NULL;
+ gss_iov_buffer_t stream, data = NULL;
+ gss_iov_buffer_t theader, tdata = NULL, tpadding, ttrailer;
+
+ GSSEAP_KRB_INIT(&krbContext);
+
+ assert(toktype == TOK_TYPE_WRAP);
+
+ if (toktype != TOK_TYPE_WRAP) {
+ code = GSSEAP_WRONG_TOK_ID;
+ goto cleanup;
+ }
+
+ stream = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_STREAM);
+ assert(stream != NULL);
+
+ if (stream->buffer.length < 16) {
+ major = GSS_S_DEFECTIVE_TOKEN;
+ goto cleanup;
+ }
+
+ ptr = (unsigned char *)stream->buffer.value;
+ toktype2 = load_uint16_be(ptr);
+ ptr += 2;
+
+ tiov = (gss_iov_buffer_desc *)GSSEAP_CALLOC((size_t)iov_count + 2,
+ sizeof(gss_iov_buffer_desc));
+ if (tiov == NULL) {
+ code = ENOMEM;
+ goto cleanup;
+ }
+
+ /* HEADER */
+ theader = &tiov[i++];
+ theader->type = GSS_IOV_BUFFER_TYPE_HEADER;
+ theader->buffer.value = stream->buffer.value;
+ theader->buffer.length = 16;
+
+ /* n[SIGN_DATA] | DATA | m[SIGN_DATA] */
+ for (j = 0; j < iov_count; j++) {
+ OM_uint32 type = GSS_IOV_BUFFER_TYPE(iov[j].type);
+
+ if (type == GSS_IOV_BUFFER_TYPE_DATA) {
+ if (data != NULL) {
+ /* only a single DATA buffer can appear */
+ code = GSSEAP_BAD_STREAM_IOV;
+ goto cleanup;
+ }
+
+ data = &iov[j];
+ tdata = &tiov[i];
+ }
+ if (type == GSS_IOV_BUFFER_TYPE_DATA ||
+ type == GSS_IOV_BUFFER_TYPE_SIGN_ONLY)
+ tiov[i++] = iov[j];
+ }
+
+ if (data == NULL) {
+ /* a single DATA buffer must be present */
+ code = GSSEAP_BAD_STREAM_IOV;
+ goto cleanup;
+ }
+
+ /* PADDING | TRAILER */
+ tpadding = &tiov[i++];
+ tpadding->type = GSS_IOV_BUFFER_TYPE_PADDING;
+ tpadding->buffer.length = 0;
+ tpadding->buffer.value = NULL;
+
+ ttrailer = &tiov[i++];
+ ttrailer->type = GSS_IOV_BUFFER_TYPE_TRAILER;
+
+ {
+ size_t ec, rrc;
+ unsigned int krbHeaderLen = 0;
+ unsigned int krbTrailerLen = 0;
+
+ conf_req_flag = ((ptr[0] & TOK_FLAG_WRAP_CONFIDENTIAL) != 0);
+ ec = conf_req_flag ? load_uint16_be(ptr + 2) : 0;
+ rrc = load_uint16_be(ptr + 4);
+
+ if (rrc != 0) {
+ code = rotateLeft((unsigned char *)stream->buffer.value + 16,
+ stream->buffer.length - 16, rrc);
+ if (code != 0)
+ goto cleanup;
+ store_uint16_be(0, ptr + 4); /* set RRC to zero */
+ }
+
+ if (conf_req_flag) {
+ code = krb5_c_crypto_length(krbContext, ctx->encryptionType,
+ KRB5_CRYPTO_TYPE_HEADER, &krbHeaderLen);
+ if (code != 0)
+ goto cleanup;
+ theader->buffer.length += krbHeaderLen; /* length validated later */
+ }
+
+ /* no PADDING for CFX, EC is used instead */
+ code = krb5_c_crypto_length(krbContext, ctx->encryptionType,
+ conf_req_flag
+ ? KRB5_CRYPTO_TYPE_TRAILER
+ : KRB5_CRYPTO_TYPE_CHECKSUM,
+ &krbTrailerLen);
+ if (code != 0)
+ goto cleanup;
+
+ ttrailer->buffer.length = ec + (conf_req_flag ? 16 : 0 /* E(Header) */) +
+ krbTrailerLen;
+ ttrailer->buffer.value = (unsigned char *)stream->buffer.value +
+ stream->buffer.length - ttrailer->buffer.length;
+ }
+
+ /* IOV: -----------0-------------+---1---+--2--+----------------3--------------*/
+ /* CFX: GSS-Header | Kerb-Header | Data | | EC | E(Header) | Kerb-Trailer */
+ /* GSS: -------GSS-HEADER--------+-DATA--+-PAD-+----------GSS-TRAILER----------*/
+
+ /* validate lengths */
+ if (stream->buffer.length < theader->buffer.length +
+ tpadding->buffer.length +
+ ttrailer->buffer.length) {
+ major = GSS_S_DEFECTIVE_TOKEN;
+ code = GSSEAP_TOK_TRUNC;
+ goto cleanup;
+ }
+
+ /* setup data */
+ tdata->buffer.length = stream->buffer.length - ttrailer->buffer.length -
+ tpadding->buffer.length - theader->buffer.length;
+
+ assert(data != NULL);
+
+ if (data->type & GSS_IOV_BUFFER_FLAG_ALLOCATE) {
+ code = gssEapAllocIov(tdata, tdata->buffer.length);
+ if (code != 0)
+ goto cleanup;
+
+ memcpy(tdata->buffer.value,
+ (unsigned char *)stream->buffer.value + theader->buffer.length,
+ tdata->buffer.length);
+ } else {
+ tdata->buffer.value = (unsigned char *)stream->buffer.value +
+ theader->buffer.length;
+ }
+
+ assert(i <= iov_count + 2);
+
+ major = unwrapToken(&code, ctx, conf_state, qop_state,
+ tiov, i, toktype);
+ if (major == GSS_S_COMPLETE) {
+ *data = *tdata;
+ } else if (tdata->type & GSS_IOV_BUFFER_FLAG_ALLOCATED) {
+ OM_uint32 tmp;
+
+ gss_release_buffer(&tmp, &tdata->buffer);
+ tdata->type &= ~(GSS_IOV_BUFFER_FLAG_ALLOCATED);
+ }
+
+cleanup:
+ if (tiov != NULL)
+ GSSEAP_FREE(tiov);
+
+ *minor = code;
+
+ return major;
+}
+
+OM_uint32
+gssEapUnwrapOrVerifyMIC(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ int *conf_state,
+ gss_qop_t *qop_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ enum gss_eap_token_type toktype)
+{
+ OM_uint32 major;
+
+ if (ctx->encryptionType == ENCTYPE_NULL) {
+ *minor = GSSEAP_KEY_UNAVAILABLE;
+ return GSS_S_UNAVAILABLE;
+ }
+
+ if (gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_STREAM) != NULL) {
+ major = unwrapStream(minor, ctx, conf_state, qop_state,
+ iov, iov_count, toktype);
+ } else {
+ major = unwrapToken(minor, ctx, conf_state, qop_state,
+ iov, iov_count, toktype);
+ }
+
+ return major;
+}
+
+OM_uint32
+gss_unwrap_iov(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ int *conf_state,
+ gss_qop_t *qop_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count)
+{
+ OM_uint32 major;
+
+ if (ctx == GSS_C_NO_CONTEXT) {
+ *minor = EINVAL;
+ return GSS_S_NO_CONTEXT;
+ }
+
+ *minor = 0;
+
+ GSSEAP_MUTEX_LOCK(&ctx->mutex);
+
+ if (!CTX_IS_ESTABLISHED(ctx)) {
+ major = GSS_S_NO_CONTEXT;
+ *minor = GSSEAP_CONTEXT_INCOMPLETE;
+ goto cleanup;
+ }
+
+ major = gssEapUnwrapOrVerifyMIC(minor, ctx, conf_state, qop_state,
+ iov, iov_count, TOK_TYPE_WRAP);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+cleanup:
+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
+
+ return major;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Portions Copyright 2003-2010 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+/*
+ * Utility functions.
+ */
+
+#ifndef _UTIL_H_
+#define _UTIL_H_ 1
+
+#include <sys/param.h>
+#include <string.h>
+#include <errno.h>
+
+#include <krb5.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef MIN
+#define MIN(_a,_b) ((_a)<(_b)?(_a):(_b))
+#endif
+
+/* util_buffer.c */
+OM_uint32
+makeStringBuffer(OM_uint32 *minor,
+ const char *string,
+ gss_buffer_t buffer);
+
+OM_uint32
+bufferToString(OM_uint32 *minor,
+ const gss_buffer_t buffer,
+ char **pString);
+
+OM_uint32
+duplicateBuffer(OM_uint32 *minor,
+ const gss_buffer_t src,
+ gss_buffer_t dst);
+
+static inline int
+bufferEqual(const gss_buffer_t b1, const gss_buffer_t b2)
+{
+ return (b1->length == b2->length &&
+ memcmp(b1->value, b2->value, b2->length) == 0);
+}
+
+static inline int
+bufferEqualString(const gss_buffer_t b1, const char *s)
+{
+ gss_buffer_desc b2;
+
+ b2.length = strlen(s);
+ b2.value = (char *)s;
+
+ return bufferEqual(b1, &b2);
+}
+
+/* util_cksum.c */
+int
+gssEapSign(krb5_context context,
+ krb5_cksumtype type,
+ size_t rrc,
+ krb5_keyblock *key,
+ krb5_keyusage sign_usage,
+ gss_iov_buffer_desc *iov,
+ int iov_count);
+
+int
+gssEapVerify(krb5_context context,
+ krb5_cksumtype type,
+ size_t rrc,
+ krb5_keyblock *key,
+ krb5_keyusage sign_usage,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int *valid);
+
+#if 0
+OM_uint32
+gssEapEncodeGssChannelBindings(OM_uint32 *minor,
+ gss_channel_bindings_t chanBindings,
+ gss_buffer_t encodedBindings);
+#endif
+
+/* util_context.c */
+#define EAP_EXPORT_CONTEXT_V1 1
+
+enum gss_eap_token_type {
+ TOK_TYPE_NONE = 0x0000, /* no token */
+ TOK_TYPE_MIC = 0x0404, /* RFC 4121 MIC token */
+ TOK_TYPE_WRAP = 0x0504, /* RFC 4121 wrap token */
+ TOK_TYPE_EXPORT_NAME = 0x0401, /* RFC 2743 exported name */
+ TOK_TYPE_EXPORT_NAME_COMPOSITE = 0x0402, /* exported composite name */
+ TOK_TYPE_DELETE_CONTEXT = 0x0405, /* RFC 2743 delete context */
+ TOK_TYPE_EAP_RESP = 0x0601, /* EAP response */
+ TOK_TYPE_EAP_REQ = 0x0602, /* EAP request */
+ TOK_TYPE_EXT_REQ = 0x0603, /* GSS EAP extensions request */
+ TOK_TYPE_EXT_RESP = 0x0604, /* GSS EAP extensions response */
+ TOK_TYPE_GSS_REAUTH = 0x0605, /* GSS EAP fast reauthentication token */
+ TOK_TYPE_CONTEXT_ERR = 0x0606, /* context error */
+};
+
+OM_uint32 gssEapAllocContext(OM_uint32 *minor, gss_ctx_id_t *pCtx);
+OM_uint32 gssEapReleaseContext(OM_uint32 *minor, gss_ctx_id_t *pCtx);
+
+OM_uint32
+gssEapMakeToken(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ const gss_buffer_t innerToken,
+ enum gss_eap_token_type tokenType,
+ gss_buffer_t outputToken);
+
+OM_uint32
+gssEapVerifyToken(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ const gss_buffer_t inputToken,
+ enum gss_eap_token_type *tokenType,
+ gss_buffer_t innerInputToken);
+
+OM_uint32
+gssEapContextTime(OM_uint32 *minor,
+ gss_ctx_id_t context_handle,
+ OM_uint32 *time_rec);
+
+OM_uint32
+gssEapDisplayName(OM_uint32 *minor,
+ gss_name_t name,
+ gss_buffer_t output_name_buffer,
+ gss_OID *output_name_type);
+
+/* util_cred.c */
+OM_uint32 gssEapAllocCred(OM_uint32 *minor, gss_cred_id_t *pCred);
+OM_uint32 gssEapReleaseCred(OM_uint32 *minor, gss_cred_id_t *pCred);
+
+OM_uint32
+gssEapAcquireCred(OM_uint32 *minor,
+ const gss_name_t desiredName,
+ const gss_buffer_t password,
+ OM_uint32 timeReq,
+ const gss_OID_set desiredMechs,
+ int cred_usage,
+ gss_cred_id_t *pCred,
+ gss_OID_set *pActualMechs,
+ OM_uint32 *timeRec);
+
+int gssEapCredAvailable(gss_cred_id_t cred, gss_OID mech);
+
+/* util_crypt.c */
+int
+gssEapEncrypt(krb5_context context, int dce_style, size_t ec,
+ size_t rrc, krb5_keyblock *key, int usage, krb5_pointer iv,
+ gss_iov_buffer_desc *iov, int iov_count);
+
+int
+gssEapDecrypt(krb5_context context, int dce_style, size_t ec,
+ size_t rrc, krb5_keyblock *key, int usage, krb5_pointer iv,
+ gss_iov_buffer_desc *iov, int iov_count);
+
+krb5_cryptotype
+gssEapMapCryptoFlag(OM_uint32 type);
+
+gss_iov_buffer_t
+gssEapLocateIov(gss_iov_buffer_desc *iov,
+ int iov_count,
+ OM_uint32 type);
+
+void
+gssEapIovMessageLength(gss_iov_buffer_desc *iov,
+ int iov_count,
+ size_t *data_length,
+ size_t *assoc_data_length);
+
+void
+gssEapReleaseIov(gss_iov_buffer_desc *iov, int iov_count);
+
+int
+gssEapIsIntegrityOnly(gss_iov_buffer_desc *iov, int iov_count);
+
+int
+gssEapAllocIov(gss_iov_buffer_t iov, size_t size);
+
+OM_uint32
+gssEapDeriveRfc3961Key(OM_uint32 *minor,
+ const unsigned char *key,
+ size_t keyLength,
+ krb5_enctype enctype,
+ krb5_keyblock *pKey);
+
+/* util_exts.c */
+#define EXT_FLAG_CRITICAL 0x80000000 /* critical, wire flag */
+#define EXT_FLAG_VERIFIED 0x40000000 /* verified, API flag */
+
+#define EXT_TYPE_GSS_CHANNEL_BINDINGS 0x00000000
+#define EXT_TYPE_REAUTH_CREDS 0x00000001
+#define EXT_TYPE_MASK (~(EXT_FLAG_CRITICAL | EXT_FLAG_VERIFIED))
+
+struct gss_eap_extension_provider {
+ OM_uint32 type;
+ int critical; /* client */
+ int required; /* server */
+ OM_uint32 (*make)(OM_uint32 *,
+ gss_cred_id_t,
+ gss_ctx_id_t,
+ gss_channel_bindings_t,
+ gss_buffer_t);
+ OM_uint32 (*verify)(OM_uint32 *,
+ gss_cred_id_t,
+ gss_ctx_id_t,
+ gss_channel_bindings_t,
+ const gss_buffer_t);
+};
+
+OM_uint32
+gssEapMakeExtensions(OM_uint32 *minor,
+ gss_cred_id_t cred,
+ gss_ctx_id_t ctx,
+ gss_channel_bindings_t chanBindings,
+ gss_buffer_t buffer);
+
+OM_uint32
+gssEapVerifyExtensions(OM_uint32 *minor,
+ gss_cred_id_t cred,
+ gss_ctx_id_t ctx,
+ gss_channel_bindings_t chanBindings,
+ const gss_buffer_t buffer);
+
+/* util_krb.c */
+#define KRB_KEY_TYPE(key) ((key)->enctype)
+#define KRB_KEY_DATA(key) ((key)->contents)
+#define KRB_KEY_LENGTH(key) ((key)->length)
+#define KRB_KEY_INIT(key) do { \
+ KRB_KEY_TYPE(key) = ENCTYPE_NULL; \
+ KRB_KEY_DATA(key) = NULL; \
+ KRB_KEY_LENGTH(key) = 0; \
+ } while (0)
+
+#define GSSEAP_KRB_INIT(ctx) do { \
+ OM_uint32 tmpMajor; \
+ \
+ tmpMajor = gssEapKerberosInit(minor, ctx); \
+ if (GSS_ERROR(tmpMajor)) { \
+ return tmpMajor; \
+ } \
+ } while (0)
+
+OM_uint32
+gssEapKerberosInit(OM_uint32 *minor, krb5_context *context);
+
+OM_uint32
+rfc3961ChecksumTypeForKey(OM_uint32 *minor,
+ krb5_keyblock *key,
+ krb5_cksumtype *cksumtype);
+
+/* util_lucid.c */
+OM_uint32
+gssEapExportLucidSecContext(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ const gss_OID desiredObject,
+ gss_buffer_set_t *data_set);
+
+/* util_mech.c */
+extern gss_OID GSS_EAP_MECHANISM;
+
+int
+gssEapInternalizeOid(const gss_OID oid,
+ gss_OID *const pInternalizedOid);
+
+OM_uint32
+gssEapDefaultMech(OM_uint32 *minor,
+ gss_OID *oid);
+
+OM_uint32
+gssEapIndicateMechs(OM_uint32 *minor,
+ gss_OID_set *mechs);
+
+OM_uint32
+gssEapEnctypeToOid(OM_uint32 *minor,
+ krb5_enctype enctype,
+ gss_OID *pOid);
+
+OM_uint32
+gssEapOidToEnctype(OM_uint32 *minor,
+ const gss_OID oid,
+ krb5_enctype *enctype);
+
+int
+gssEapIsMechanismOid(const gss_OID oid);
+
+int
+gssEapIsConcreteMechanismOid(const gss_OID oid);
+
+OM_uint32
+gssEapValidateMechs(OM_uint32 *minor,
+ const gss_OID_set mechs);
+
+gss_buffer_t
+gssEapOidToSaslName(const gss_OID oid);
+
+gss_OID
+gssEapSaslNameToOid(const gss_buffer_t name);
+
+/* util_name.c */
+#define EXPORT_NAME_FLAG_OID 0x1
+#define EXPORT_NAME_FLAG_COMPOSITE 0x2
+
+OM_uint32 gssEapAllocName(OM_uint32 *minor, gss_name_t *pName);
+OM_uint32 gssEapReleaseName(OM_uint32 *minor, gss_name_t *pName);
+OM_uint32 gssEapExportName(OM_uint32 *minor,
+ const gss_name_t name,
+ gss_buffer_t exportedName);
+OM_uint32 gssEapExportNameInternal(OM_uint32 *minor,
+ const gss_name_t name,
+ gss_buffer_t exportedName,
+ unsigned int flags);
+OM_uint32 gssEapImportName(OM_uint32 *minor,
+ const gss_buffer_t input_name_buffer,
+ gss_OID input_name_type,
+ gss_name_t *output_name);
+OM_uint32 gssEapImportNameInternal(OM_uint32 *minor,
+ const gss_buffer_t input_name_buffer,
+ gss_name_t *output_name,
+ unsigned int flags);
+OM_uint32
+gssEapDuplicateName(OM_uint32 *minor,
+ const gss_name_t input_name,
+ gss_name_t *dest_name);
+
+/* util_oid.c */
+OM_uint32
+composeOid(OM_uint32 *minor_status,
+ const char *prefix,
+ size_t prefix_len,
+ int suffix,
+ gss_OID_desc *oid);
+
+OM_uint32
+decomposeOid(OM_uint32 *minor_status,
+ const char *prefix,
+ size_t prefix_len,
+ gss_OID_desc *oid,
+ int *suffix) ;
+
+OM_uint32
+duplicateOid(OM_uint32 *minor_status,
+ const gss_OID_desc * const oid,
+ gss_OID *new_oid);
+
+OM_uint32
+duplicateOidSet(OM_uint32 *minor,
+ const gss_OID_set src,
+ gss_OID_set *dst);
+
+static inline int
+oidEqual(const gss_OID_desc *o1, const gss_OID_desc *o2)
+{
+ if (o1 == GSS_C_NO_OID)
+ return (o2 == GSS_C_NO_OID);
+ else if (o2 == GSS_C_NO_OID)
+ return (o1 == GSS_C_NO_OID);
+ else
+ return (o1->length == o2->length &&
+ memcmp(o1->elements, o2->elements, o1->length) == 0);
+}
+
+/* util_ordering.c */
+OM_uint32
+sequenceInternalize(OM_uint32 *minor,
+ void **vqueue,
+ unsigned char **buf,
+ size_t *lenremain);
+
+OM_uint32
+sequenceExternalize(OM_uint32 *minor,
+ void *vqueue,
+ unsigned char **buf,
+ size_t *lenremain);
+
+size_t
+sequenceSize(void *vqueue);
+
+OM_uint32
+sequenceFree(OM_uint32 *minor, void **vqueue);
+
+OM_uint32
+sequenceCheck(OM_uint32 *minor, void **vqueue, uint64_t seqnum);
+
+OM_uint32
+sequenceInit(OM_uint32 *minor, void **vqueue, uint64_t seqnum,
+ int do_replay, int do_sequence, int wide_nums);
+
+/* util_token.c */
+size_t
+tokenSize(const gss_OID_desc *mech, size_t body_size);
+
+void
+makeTokenHeader(const gss_OID_desc *mech,
+ size_t body_size,
+ unsigned char **buf,
+ enum gss_eap_token_type tok_type);
+
+OM_uint32
+verifyTokenHeader(OM_uint32 *minor,
+ gss_OID mech,
+ size_t *body_size,
+ unsigned char **buf_in,
+ size_t toksize_in,
+ enum gss_eap_token_type *ret_tok_type);
+
+/* Helper macros */
+
+#define GSSEAP_CALLOC calloc
+#define GSSEAP_MALLOC malloc
+#define GSSEAP_FREE free
+#define GSSEAP_REALLOC realloc
+
+#define GSSEAP_NOT_IMPLEMENTED do { \
+ assert(0 && "not implemented"); \
+ *minor = ENOSYS; \
+ return GSS_S_FAILURE; \
+ } while (0)
+
+#include <pthread.h>
+
+#define GSSEAP_MUTEX pthread_mutex_t
+#define GSSEAP_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
+
+#define GSSEAP_MUTEX_INIT(m) pthread_mutex_init((m), NULL)
+#define GSSEAP_MUTEX_DESTROY(m) pthread_mutex_destroy((m))
+#define GSSEAP_MUTEX_LOCK(m) pthread_mutex_lock((m))
+#define GSSEAP_MUTEX_UNLOCK(m) pthread_mutex_unlock((m))
+
+#define GSSEAP_THREAD_KEY pthread_key_t
+#define GSSEAP_KEY_CREATE(k, d) pthread_key_create((k), (d))
+#define GSSEAP_GETSPECIFIC(k) pthread_getspecific((k))
+#define GSSEAP_SETSPECIFIC(k, d) pthread_setspecific((k), (d))
+
+#define GSSEAP_THREAD_ONCE pthread_once_t
+#define GSSEAP_ONCE(o, i) pthread_once((o), (i))
+#define GSSEAP_ONCE_INITIALIZER PTHREAD_ONCE_INIT
+
+/* Helper functions */
+static inline void
+store_uint16_be(uint16_t val, void *vp)
+{
+ unsigned char *p = (unsigned char *)vp;
+
+ p[0] = (val >> 8) & 0xff;
+ p[1] = (val ) & 0xff;
+}
+
+static inline uint16_t
+load_uint16_be(const void *cvp)
+{
+ const unsigned char *p = (const unsigned char *)cvp;
+
+ return (p[1] | (p[0] << 8));
+}
+
+static inline void
+store_uint32_be(uint32_t val, void *vp)
+{
+ unsigned char *p = (unsigned char *)vp;
+
+ p[0] = (val >> 24) & 0xff;
+ p[1] = (val >> 16) & 0xff;
+ p[2] = (val >> 8) & 0xff;
+ p[3] = (val ) & 0xff;
+}
+
+static inline uint32_t
+load_uint32_be(const void *cvp)
+{
+ const unsigned char *p = (const unsigned char *)cvp;
+
+ return (p[3] | (p[2] << 8)
+ | ((uint32_t) p[1] << 16)
+ | ((uint32_t) p[0] << 24));
+}
+
+static inline void
+store_uint64_be(uint64_t val, void *vp)
+{
+ unsigned char *p = (unsigned char *)vp;
+
+ p[0] = (unsigned char)((val >> 56) & 0xff);
+ p[1] = (unsigned char)((val >> 48) & 0xff);
+ p[2] = (unsigned char)((val >> 40) & 0xff);
+ p[3] = (unsigned char)((val >> 32) & 0xff);
+ p[4] = (unsigned char)((val >> 24) & 0xff);
+ p[5] = (unsigned char)((val >> 16) & 0xff);
+ p[6] = (unsigned char)((val >> 8) & 0xff);
+ p[7] = (unsigned char)((val ) & 0xff);
+}
+
+static inline uint64_t
+load_uint64_be(const void *cvp)
+{
+ const unsigned char *p = (const unsigned char *)cvp;
+
+ return ((uint64_t)load_uint32_be(p) << 32) | load_uint32_be(p + 4);
+}
+
+static inline unsigned char *
+store_buffer(gss_buffer_t buffer, void *vp, int wide_nums)
+{
+ unsigned char *p = (unsigned char *)vp;
+
+ if (wide_nums) {
+ store_uint64_be(buffer->length, p);
+ p += 8;
+ } else {
+ store_uint32_be(buffer->length, p);
+ p += 4;
+ }
+
+ if (buffer->value != NULL) {
+ memcpy(p, buffer->value, buffer->length);
+ p += buffer->length;
+ }
+
+ return p;
+}
+
+static inline unsigned char *
+load_buffer(const void *cvp, size_t length, gss_buffer_t buffer)
+{
+ buffer->length = 0;
+ buffer->value = GSSEAP_MALLOC(length);
+ if (buffer->value == NULL)
+ return NULL;
+ buffer->length = length;
+ memcpy(buffer->value, cvp, length);
+ return (unsigned char *)cvp + length;
+}
+
+static inline unsigned char *
+store_oid(gss_OID oid, void *vp)
+{
+ gss_buffer_desc buf;
+
+ if (oid != GSS_C_NO_OID) {
+ buf.length = oid->length;
+ buf.value = oid->elements;
+ } else {
+ buf.length = 0;
+ buf.value = NULL;
+ }
+
+ return store_buffer(&buf, vp, FALSE);
+}
+
+static inline void
+krbDataToGssBuffer(krb5_data *data, gss_buffer_t buffer)
+{
+ buffer->value = (void *)data->data;
+ buffer->length = data->length;
+}
+
+static inline void
+gssBufferToKrbData(gss_buffer_t buffer, krb5_data *data)
+{
+ data->data = (char *)buffer->value;
+ data->length = buffer->length;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#include "util_attr.h"
+#ifdef GSSEAP_ENABLE_REAUTH
+#include "util_reauth.h"
+#endif
+
+#endif /* _UTIL_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "gssapiP_eap.h"
+#include "authdata_plugin.h"
+
+/*
+ * This rubbish is necessary because MIT doesn't provide another way
+ * to access verified AD-KDCIssued elements. We can't verify them
+ * ourselves because they're signed in the ticket session key, which
+ * is destroyed immediately after the AP-REQ is processed.
+ */
+
+struct radius_ad_context {
+ krb5_data avpdata;
+ krb5_boolean verified;
+};
+
+static krb5_data radius_ad_attr = {
+ KV5M_DATA, sizeof("urn:authdata-radius-avp") - 1, "urn:authdata-radius-avp" };
+
+static krb5_error_code
+radius_ad_init(krb5_context kcontext, void **plugin_context)
+{
+ *plugin_context = 0;
+ return 0;
+}
+
+static void
+radius_ad_flags(krb5_context kcontext,
+ void *plugin_context,
+ krb5_authdatatype ad_type,
+ krb5_flags *flags)
+{
+ *flags = AD_USAGE_KDC_ISSUED | AD_INFORMATIONAL;
+}
+
+static void
+radius_ad_fini(krb5_context kcontext, void *plugin_context)
+{
+ return;
+}
+
+static krb5_error_code
+radius_ad_request_init(krb5_context kcontext,
+ struct _krb5_authdata_context *context,
+ void *plugin_context,
+ void **request_context)
+{
+ struct radius_ad_context *ctx;
+
+ ctx = GSSEAP_CALLOC(1, sizeof(*ctx));
+ if (ctx == NULL)
+ return ENOMEM;
+
+ *request_context = ctx;
+
+ return 0;
+}
+
+static krb5_error_code
+radius_ad_export_authdata(krb5_context kcontext,
+ struct _krb5_authdata_context *context,
+ void *plugin_context,
+ void *request_context,
+ krb5_flags usage,
+ krb5_authdata ***out_authdata)
+{
+ struct radius_ad_context *radius_ad = (struct radius_ad_context *)request_context;
+ krb5_authdata *data[2];
+ krb5_authdata datum;
+
+ datum.ad_type = KRB5_AUTHDATA_RADIUS_AVP;
+ datum.length = radius_ad->avpdata.length;
+ datum.contents = (krb5_octet *)radius_ad->avpdata.data;
+
+ data[0] = &datum;
+ data[1] = NULL;
+
+ return krb5_copy_authdata(kcontext, data, out_authdata);
+}
+
+static krb5_error_code
+radius_ad_import_authdata(krb5_context kcontext,
+ struct _krb5_authdata_context *context,
+ void *plugin_context,
+ void *request_context,
+ krb5_authdata **authdata,
+ krb5_boolean kdc_issued_flag,
+ krb5_const_principal issuer)
+{
+ struct radius_ad_context *radius_ad = (struct radius_ad_context *)request_context;
+
+ krb5_free_data_contents(kcontext, &radius_ad->avpdata);
+ radius_ad->verified = FALSE;
+
+ assert(authdata[0] != NULL);
+
+ radius_ad->avpdata.data = GSSEAP_MALLOC(authdata[0]->length);
+ if (radius_ad->avpdata.data == NULL)
+ return ENOMEM;
+
+ memcpy(radius_ad->avpdata.data, authdata[0]->contents,
+ authdata[0]->length);
+ radius_ad->avpdata.length = authdata[0]->length;
+
+ radius_ad->verified = kdc_issued_flag;
+
+ return 0;
+}
+
+static void
+radius_ad_request_fini(krb5_context kcontext,
+ struct _krb5_authdata_context *context,
+ void *plugin_context,
+ void *request_context)
+{
+ struct radius_ad_context *radius_ad = (struct radius_ad_context *)request_context;
+
+ if (radius_ad != NULL) {
+ krb5_free_data_contents(kcontext, &radius_ad->avpdata);
+ GSSEAP_FREE(radius_ad);
+ }
+}
+
+static krb5_error_code
+radius_ad_get_attribute(krb5_context kcontext,
+ struct _krb5_authdata_context *context,
+ void *plugin_context,
+ void *request_context,
+ const krb5_data *attribute,
+ krb5_boolean *authenticated,
+ krb5_boolean *complete,
+ krb5_data *value,
+ krb5_data *display_value,
+ int *more)
+{
+ struct radius_ad_context *radius_ad = (struct radius_ad_context *)request_context;
+
+ if (attribute->length != radius_ad_attr.length ||
+ memcmp(attribute->data, radius_ad_attr.data,
+ radius_ad_attr.length) != 0)
+ return ENOENT;
+
+ if (radius_ad->avpdata.length == 0)
+ return ENOENT;
+
+ *authenticated = radius_ad->verified;
+ *complete = TRUE;
+ *more = 0;
+
+ value->data = GSSEAP_MALLOC(radius_ad->avpdata.length);
+ if (value->data == NULL)
+ return ENOMEM;
+
+ memcpy(value->data, radius_ad->avpdata.data, radius_ad->avpdata.length);
+ value->length = radius_ad->avpdata.length;
+
+ return 0;
+}
+
+static krb5_error_code
+radius_ad_copy(krb5_context kcontext,
+ struct _krb5_authdata_context *context,
+ void *plugin_context,
+ void *request_context,
+ void *dst_plugin_context,
+ void *dst_request_context)
+{
+ struct radius_ad_context *radius_ad_src =
+ (struct radius_ad_context *)request_context;
+ struct radius_ad_context *radius_ad_dst =
+ (struct radius_ad_context *)dst_request_context;
+
+ radius_ad_dst->avpdata.data = GSSEAP_MALLOC(radius_ad_src->avpdata.length);
+ if (radius_ad_dst->avpdata.data == NULL)
+ return ENOMEM;
+
+ memcpy(radius_ad_dst->avpdata.data, radius_ad_src->avpdata.data,
+ radius_ad_src->avpdata.length);
+ radius_ad_dst->avpdata.length = radius_ad_src->avpdata.length;
+ radius_ad_dst->verified = radius_ad_src->verified;
+
+ return 0;
+}
+
+static krb5_authdatatype radius_ad_ad_types[] =
+ { KRB5_AUTHDATA_RADIUS_AVP, 0 };
+
+krb5plugin_authdata_client_ftable_v0 authdata_client_0 = {
+ "radius_ad",
+ radius_ad_ad_types,
+ radius_ad_init,
+ radius_ad_fini,
+ radius_ad_flags,
+ radius_ad_request_init,
+ radius_ad_request_fini,
+ NULL,
+ radius_ad_get_attribute,
+ NULL,
+ NULL,
+ radius_ad_export_authdata,
+ radius_ad_import_authdata,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ radius_ad_copy
+};
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Attribute provider mechanism.
+ */
+
+#include "gssapiP_eap.h"
+
+#include <typeinfo>
+#include <string>
+#include <exception>
+#include <new>
+
+/* lazy initialisation */
+static GSSEAP_THREAD_ONCE gssEapAttrProvidersInitOnce = GSSEAP_ONCE_INITIALIZER;
+static OM_uint32 gssEapAttrProvidersInitStatus = GSS_S_UNAVAILABLE;
+
+static void
+gssEapAttrProvidersInitInternal(void)
+{
+ OM_uint32 major, minor;
+
+ assert(gssEapAttrProvidersInitStatus == GSS_S_UNAVAILABLE);
+
+ major = gssEapRadiusAttrProviderInit(&minor);
+ if (major == GSS_S_COMPLETE)
+ major = gssEapSamlAttrProvidersInit(&minor);
+ if (major == GSS_S_COMPLETE)
+ major = gssEapLocalAttrProviderInit(&minor);
+
+#ifdef GSSEAP_DEBUG
+ assert(major == GSS_S_COMPLETE);
+#endif
+
+ gssEapAttrProvidersInitStatus = major;
+}
+
+static OM_uint32
+gssEapAttrProvidersInit(OM_uint32 *minor)
+{
+ GSSEAP_ONCE(&gssEapAttrProvidersInitOnce, gssEapAttrProvidersInitInternal);
+
+ if (GSS_ERROR(gssEapAttrProvidersInitStatus))
+ *minor = GSSEAP_NO_ATTR_PROVIDERS;
+
+ return gssEapAttrProvidersInitStatus;
+}
+
+OM_uint32
+gssEapAttrProvidersFinalize(OM_uint32 *minor)
+{
+ OM_uint32 major = GSS_S_COMPLETE;
+
+ if (gssEapAttrProvidersInitStatus == GSS_S_COMPLETE) {
+ major = gssEapLocalAttrProviderFinalize(minor);
+ if (major == GSS_S_COMPLETE)
+ major = gssEapSamlAttrProvidersFinalize(minor);
+ if (major == GSS_S_COMPLETE)
+ major = gssEapRadiusAttrProviderFinalize(minor);
+
+ gssEapAttrProvidersInitStatus = GSS_S_UNAVAILABLE;
+ }
+
+ return major;
+}
+
+static gss_eap_attr_create_provider gssEapAttrFactories[ATTR_TYPE_MAX + 1];
+static gss_buffer_desc gssEapAttrPrefixes[ATTR_TYPE_MAX + 1];
+
+/*
+ * Register a provider for a particular type and prefix
+ */
+void
+gss_eap_attr_ctx::registerProvider(unsigned int type,
+ const char *prefix,
+ gss_eap_attr_create_provider factory)
+{
+ assert(type <= ATTR_TYPE_MAX);
+
+ assert(gssEapAttrFactories[type] == NULL);
+
+ gssEapAttrFactories[type] = factory;
+ if (prefix != NULL) {
+ gssEapAttrPrefixes[type].value = (void *)prefix;
+ gssEapAttrPrefixes[type].length = strlen(prefix);
+ } else {
+ gssEapAttrPrefixes[type].value = NULL;
+ gssEapAttrPrefixes[type].length = 0;
+ }
+}
+
+/*
+ * Unregister a provider
+ */
+void
+gss_eap_attr_ctx::unregisterProvider(unsigned int type)
+{
+ assert(type <= ATTR_TYPE_MAX);
+
+ gssEapAttrFactories[type] = NULL;
+ gssEapAttrPrefixes[type].value = NULL;
+ gssEapAttrPrefixes[type].length = 0;
+}
+
+/*
+ * Create an attribute context, that manages instances of providers
+ */
+gss_eap_attr_ctx::gss_eap_attr_ctx(void)
+{
+ m_flags = 0;
+
+ for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
+ gss_eap_attr_provider *provider;
+
+ if (gssEapAttrFactories[i] != NULL) {
+ provider = (gssEapAttrFactories[i])();
+ } else {
+ provider = NULL;
+ }
+
+ m_providers[i] = provider;
+ }
+}
+
+/*
+ * Convert an attribute prefix to a type
+ */
+unsigned int
+gss_eap_attr_ctx::attributePrefixToType(const gss_buffer_t prefix)
+{
+ unsigned int i;
+
+ for (i = ATTR_TYPE_MIN; i < ATTR_TYPE_MAX; i++) {
+ if (bufferEqual(&gssEapAttrPrefixes[i], prefix))
+ return i;
+ }
+
+ return ATTR_TYPE_LOCAL;
+}
+
+/*
+ * Convert a type to an attribute prefix
+ */
+const gss_buffer_t
+gss_eap_attr_ctx::attributeTypeToPrefix(unsigned int type)
+{
+ if (type < ATTR_TYPE_MIN || type >= ATTR_TYPE_MAX)
+ return GSS_C_NO_BUFFER;
+
+ return &gssEapAttrPrefixes[type];
+}
+
+bool
+gss_eap_attr_ctx::providerEnabled(unsigned int type) const
+{
+ if (type == ATTR_TYPE_LOCAL &&
+ (m_flags & ATTR_FLAG_DISABLE_LOCAL))
+ return false;
+
+ if (m_providers[type] == NULL)
+ return false;
+
+ return true;
+}
+
+void
+gss_eap_attr_ctx::releaseProvider(unsigned int type)
+{
+ delete m_providers[type];
+ m_providers[type] = NULL;
+}
+
+/*
+ * Initialize a context from an existing context.
+ */
+bool
+gss_eap_attr_ctx::initFromExistingContext(const gss_eap_attr_ctx *manager)
+{
+ bool ret = true;
+
+ m_flags = manager->m_flags;
+
+ for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
+ gss_eap_attr_provider *provider;
+
+ if (!providerEnabled(i)) {
+ releaseProvider(i);
+ continue;
+ }
+
+ provider = m_providers[i];
+
+ ret = provider->initFromExistingContext(this,
+ manager->m_providers[i]);
+ if (ret == false) {
+ releaseProvider(i);
+ break;
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * Initialize a context from a GSS credential and context.
+ */
+bool
+gss_eap_attr_ctx::initFromGssContext(const gss_cred_id_t cred,
+ const gss_ctx_id_t ctx)
+{
+ bool ret = true;
+
+ if (cred != GSS_C_NO_CREDENTIAL &&
+ (cred->flags & GSS_EAP_DISABLE_LOCAL_ATTRS_FLAG)) {
+ m_flags |= ATTR_FLAG_DISABLE_LOCAL;
+ }
+
+ for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
+ gss_eap_attr_provider *provider;
+
+ if (!providerEnabled(i)) {
+ releaseProvider(i);
+ continue;
+ }
+
+ provider = m_providers[i];
+
+ ret = provider->initFromGssContext(this, cred, ctx);
+ if (ret == false) {
+ releaseProvider(i);
+ break;
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * Initialize a context from an exported context or name token
+ */
+bool
+gss_eap_attr_ctx::initFromBuffer(const gss_buffer_t buffer)
+{
+ bool ret;
+ gss_eap_attr_provider *primaryProvider = getPrimaryProvider();
+ gss_buffer_desc primaryBuf;
+
+ if (buffer->length < 4)
+ return false;
+
+ m_flags = load_uint32_be(buffer->value);
+
+ primaryBuf.length = buffer->length - 4;
+ primaryBuf.value = (char *)buffer->value + 4;
+
+ ret = primaryProvider->initFromBuffer(this, &primaryBuf);
+ if (ret == false)
+ return ret;
+
+ for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
+ gss_eap_attr_provider *provider;
+
+ if (!providerEnabled(i)) {
+ releaseProvider(i);
+ continue;
+ }
+
+ provider = m_providers[i];
+ if (provider == primaryProvider)
+ continue;
+
+ ret = provider->initFromGssContext(this,
+ GSS_C_NO_CREDENTIAL,
+ GSS_C_NO_CONTEXT);
+ if (ret == false) {
+ releaseProvider(i);
+ break;
+ }
+ }
+
+ return ret;
+}
+
+gss_eap_attr_ctx::~gss_eap_attr_ctx(void)
+{
+ for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++)
+ delete m_providers[i];
+}
+
+/*
+ * Locate provider for a given type
+ */
+gss_eap_attr_provider *
+gss_eap_attr_ctx::getProvider(unsigned int type) const
+{
+ assert(type >= ATTR_TYPE_MIN && type <= ATTR_TYPE_MAX);
+ return m_providers[type];
+}
+
+/*
+ * Locate provider for a given prefix
+ */
+gss_eap_attr_provider *
+gss_eap_attr_ctx::getProvider(const gss_buffer_t prefix) const
+{
+ unsigned int type;
+
+ type = attributePrefixToType(prefix);
+
+ return m_providers[type];
+}
+
+/*
+ * Get primary provider. Only the primary provider is serialised when
+ * gss_export_sec_context() or gss_export_name_composite() is called.
+ */
+gss_eap_attr_provider *
+gss_eap_attr_ctx::getPrimaryProvider(void) const
+{
+ return m_providers[ATTR_TYPE_MIN];
+}
+
+/*
+ * Set an attribute
+ */
+bool
+gss_eap_attr_ctx::setAttribute(int complete,
+ const gss_buffer_t attr,
+ const gss_buffer_t value)
+{
+ gss_buffer_desc suffix = GSS_C_EMPTY_BUFFER;
+ unsigned int type;
+ gss_eap_attr_provider *provider;
+ bool ret = false;
+
+ decomposeAttributeName(attr, &type, &suffix);
+
+ provider = m_providers[type];
+ if (provider != NULL) {
+ ret = provider->setAttribute(complete,
+ (type == ATTR_TYPE_LOCAL) ? attr : &suffix,
+ value);
+ }
+
+ return ret;
+}
+
+/*
+ * Delete an attrbiute
+ */
+bool
+gss_eap_attr_ctx::deleteAttribute(const gss_buffer_t attr)
+{
+ gss_buffer_desc suffix = GSS_C_EMPTY_BUFFER;
+ unsigned int type;
+ gss_eap_attr_provider *provider;
+ bool ret = false;
+
+ decomposeAttributeName(attr, &type, &suffix);
+
+ provider = m_providers[type];
+ if (provider != NULL) {
+ ret = provider->deleteAttribute(type == ATTR_TYPE_LOCAL ? attr : &suffix);
+ }
+
+ return ret;
+}
+
+/*
+ * Enumerate attribute types with callback
+ */
+bool
+gss_eap_attr_ctx::getAttributeTypes(gss_eap_attr_enumeration_cb cb, void *data) const
+{
+ bool ret = false;
+ size_t i;
+
+ for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
+ gss_eap_attr_provider *provider = m_providers[i];
+
+ if (provider == NULL)
+ continue;
+
+ ret = provider->getAttributeTypes(cb, data);
+ if (ret == false)
+ break;
+ }
+
+ return ret;
+}
+
+struct eap_gss_get_attr_types_args {
+ unsigned int type;
+ gss_buffer_set_t attrs;
+};
+
+static bool
+addAttribute(const gss_eap_attr_provider *provider,
+ const gss_buffer_t attribute,
+ void *data)
+{
+ eap_gss_get_attr_types_args *args = (eap_gss_get_attr_types_args *)data;
+ gss_buffer_desc qualified;
+ OM_uint32 major, minor;
+
+ if (args->type != ATTR_TYPE_LOCAL) {
+ gss_eap_attr_ctx::composeAttributeName(args->type, attribute, &qualified);
+ major = gss_add_buffer_set_member(&minor, &qualified, &args->attrs);
+ gss_release_buffer(&minor, &qualified);
+ } else {
+ major = gss_add_buffer_set_member(&minor, attribute, &args->attrs);
+ }
+
+ return GSS_ERROR(major) == false;
+}
+
+/*
+ * Enumerate attribute types, output is buffer set
+ */
+bool
+gss_eap_attr_ctx::getAttributeTypes(gss_buffer_set_t *attrs)
+{
+ eap_gss_get_attr_types_args args;
+ OM_uint32 major, minor;
+ bool ret = false;
+ unsigned int i;
+
+ major = gss_create_empty_buffer_set(&minor, attrs);
+ if (GSS_ERROR(major)) {
+ throw new std::bad_alloc;
+ return false;
+ }
+
+ args.attrs = *attrs;
+
+ for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
+ gss_eap_attr_provider *provider = m_providers[i];
+
+ args.type = i;
+
+ if (provider == NULL)
+ continue;
+
+ ret = provider->getAttributeTypes(addAttribute, (void *)&args);
+ if (ret == false)
+ break;
+ }
+
+ if (ret == false)
+ gss_release_buffer_set(&minor, attrs);
+
+ return ret;
+}
+
+/*
+ * Get attribute with given name
+ */
+bool
+gss_eap_attr_ctx::getAttribute(const gss_buffer_t attr,
+ int *authenticated,
+ int *complete,
+ gss_buffer_t value,
+ gss_buffer_t display_value,
+ int *more) const
+{
+ gss_buffer_desc suffix = GSS_C_EMPTY_BUFFER;
+ unsigned int type;
+ gss_eap_attr_provider *provider;
+ bool ret;
+
+ decomposeAttributeName(attr, &type, &suffix);
+
+ provider = m_providers[type];
+ if (provider == NULL)
+ return false;
+
+ ret = provider->getAttribute(type == ATTR_TYPE_LOCAL ? attr : &suffix,
+ authenticated, complete,
+ value, display_value, more);
+
+ return ret;
+}
+
+/*
+ * Map attribute context to C++ object
+ */
+gss_any_t
+gss_eap_attr_ctx::mapToAny(int authenticated,
+ gss_buffer_t type_id) const
+{
+ unsigned int type;
+ gss_eap_attr_provider *provider;
+ gss_buffer_desc suffix;
+
+ decomposeAttributeName(type_id, &type, &suffix);
+
+ provider = m_providers[type];
+ if (provider == NULL)
+ return (gss_any_t)NULL;
+
+ return provider->mapToAny(authenticated, &suffix);
+}
+
+/*
+ * Release mapped context
+ */
+void
+gss_eap_attr_ctx::releaseAnyNameMapping(gss_buffer_t type_id,
+ gss_any_t input) const
+{
+ unsigned int type;
+ gss_eap_attr_provider *provider;
+ gss_buffer_desc suffix;
+
+ decomposeAttributeName(type_id, &type, &suffix);
+
+ provider = m_providers[type];
+ if (provider != NULL)
+ provider->releaseAnyNameMapping(&suffix, input);
+}
+
+/*
+ * Export attribute context to buffer
+ */
+void
+gss_eap_attr_ctx::exportToBuffer(gss_buffer_t buffer) const
+{
+ const gss_eap_attr_provider *primaryProvider = getPrimaryProvider();
+ gss_buffer_desc tmp;
+ unsigned char *p;
+ OM_uint32 tmpMinor;
+
+ primaryProvider->exportToBuffer(&tmp);
+
+ buffer->length = 4 + tmp.length;
+ buffer->value = GSSEAP_MALLOC(buffer->length);
+ if (buffer->value == NULL)
+ throw new std::bad_alloc;
+
+ p = (unsigned char *)buffer->value;
+ store_uint32_be(m_flags, p);
+ memcpy(p + 4, tmp.value, tmp.length);
+
+ gss_release_buffer(&tmpMinor, &tmp);
+}
+
+/*
+ * Return soonest expiry time of providers
+ */
+time_t
+gss_eap_attr_ctx::getExpiryTime(void) const
+{
+ unsigned int i;
+ time_t expiryTime = 0;
+
+ for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
+ gss_eap_attr_provider *provider = m_providers[i];
+ time_t providerExpiryTime;
+
+ if (provider == NULL)
+ continue;
+
+ providerExpiryTime = provider->getExpiryTime();
+ if (providerExpiryTime == 0)
+ continue;
+
+ if (expiryTime == 0 || providerExpiryTime < expiryTime)
+ expiryTime = providerExpiryTime;
+ }
+
+ return expiryTime;
+}
+
+/*
+ * Map C++ exception to GSS status
+ */
+static OM_uint32
+mapException(OM_uint32 *minor, std::exception &e)
+{
+ OM_uint32 major = GSS_S_FAILURE;
+
+ /* XXX TODO implement other mappings */
+ if (typeid(e) == typeid(std::bad_alloc))
+ *minor = ENOMEM;
+ else
+ *minor = 0;
+
+#ifdef GSSEAP_DEBUG
+ /* rethrow for now for debugging */
+ throw e;
+#endif
+
+ return major;
+}
+
+/*
+ * Decompose attribute name into prefix and suffix
+ */
+void
+gss_eap_attr_ctx::decomposeAttributeName(const gss_buffer_t attribute,
+ gss_buffer_t prefix,
+ gss_buffer_t suffix)
+{
+ char *p = NULL;
+ size_t i;
+
+ for (i = 0; i < attribute->length; i++) {
+ if (((char *)attribute->value)[i] == ' ') {
+ p = (char *)attribute->value + i + 1;
+ break;
+ }
+ }
+
+ prefix->value = attribute->value;
+ prefix->length = i;
+
+ if (p != NULL && *p != '\0') {
+ suffix->length = attribute->length - 1 - prefix->length;
+ suffix->value = p;
+ } else {
+ suffix->length = 0;
+ suffix->value = NULL;
+ }
+}
+
+/*
+ * Decompose attribute name into type and suffix
+ */
+void
+gss_eap_attr_ctx::decomposeAttributeName(const gss_buffer_t attribute,
+ unsigned int *type,
+ gss_buffer_t suffix)
+{
+ gss_buffer_desc prefix = GSS_C_EMPTY_BUFFER;
+
+ decomposeAttributeName(attribute, &prefix, suffix);
+ *type = attributePrefixToType(&prefix);
+}
+
+/*
+ * Compose attribute name from prefix, suffix; returns C++ string
+ */
+std::string
+gss_eap_attr_ctx::composeAttributeName(const gss_buffer_t prefix,
+ const gss_buffer_t suffix)
+{
+ std::string str;
+
+ if (prefix == GSS_C_NO_BUFFER || prefix->length == 0)
+ return str;
+
+ str.append((const char *)prefix->value, prefix->length);
+
+ if (suffix != GSS_C_NO_BUFFER) {
+ str.append(" ");
+ str.append((const char *)suffix->value, suffix->length);
+ }
+
+ return str;
+}
+
+/*
+ * Compose attribute name from type, suffix; returns C++ string
+ */
+std::string
+gss_eap_attr_ctx::composeAttributeName(unsigned int type,
+ const gss_buffer_t suffix)
+{
+ const gss_buffer_t prefix = attributeTypeToPrefix(type);
+
+ return composeAttributeName(prefix, suffix);
+}
+
+/*
+ * Compose attribute name from prefix, suffix; returns GSS buffer
+ */
+void
+gss_eap_attr_ctx::composeAttributeName(const gss_buffer_t prefix,
+ const gss_buffer_t suffix,
+ gss_buffer_t attribute)
+{
+ std::string str = composeAttributeName(prefix, suffix);
+
+ if (str.length() != 0) {
+ return duplicateBuffer(str, attribute);
+ } else {
+ attribute->length = 0;
+ attribute->value = NULL;
+ }
+}
+
+/*
+ * Compose attribute name from type, suffix; returns GSS buffer
+ */
+void
+gss_eap_attr_ctx::composeAttributeName(unsigned int type,
+ const gss_buffer_t suffix,
+ gss_buffer_t attribute)
+{
+ gss_buffer_t prefix = attributeTypeToPrefix(type);
+
+ return composeAttributeName(prefix, suffix, attribute);
+}
+
+/*
+ * C wrappers
+ */
+OM_uint32
+gssEapInquireName(OM_uint32 *minor,
+ gss_name_t name,
+ int *name_is_MN,
+ gss_OID *MN_mech,
+ gss_buffer_set_t *attrs)
+{
+ if (name->attrCtx == NULL) {
+ *minor = GSSEAP_NO_ATTR_CONTEXT;
+ return GSS_S_UNAVAILABLE;
+ }
+
+ if (GSS_ERROR(gssEapAttrProvidersInit(minor))) {
+ return GSS_S_UNAVAILABLE;
+ }
+
+ try {
+ if (!name->attrCtx->getAttributeTypes(attrs)) {
+ *minor = GSSEAP_NO_ATTR_CONTEXT;
+ return GSS_S_UNAVAILABLE;
+ }
+ } catch (std::exception &e) {
+ return mapException(minor, e);
+ }
+
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gssEapGetNameAttribute(OM_uint32 *minor,
+ gss_name_t name,
+ gss_buffer_t attr,
+ int *authenticated,
+ int *complete,
+ gss_buffer_t value,
+ gss_buffer_t display_value,
+ int *more)
+{
+ *authenticated = 0;
+ *complete = 0;
+
+ if (value != NULL) {
+ value->length = 0;
+ value->value = NULL;
+ }
+
+ if (display_value != NULL) {
+ display_value->length = 0;
+ display_value->value = NULL;
+ }
+
+ if (name->attrCtx == NULL) {
+ *minor = GSSEAP_NO_ATTR_CONTEXT;
+ return GSS_S_UNAVAILABLE;
+ }
+
+ if (GSS_ERROR(gssEapAttrProvidersInit(minor))) {
+ return GSS_S_UNAVAILABLE;
+ }
+
+ try {
+ if (!name->attrCtx->getAttribute(attr, authenticated, complete,
+ value, display_value, more)) {
+ *minor = GSSEAP_NO_SUCH_ATTR;
+ gssEapSaveStatusInfo(*minor, "Unknown naming attribute %.*s",
+ (int)attr->length, (char *)attr->value);
+ return GSS_S_UNAVAILABLE;
+ }
+ } catch (std::exception &e) {
+ return mapException(minor, e);
+ }
+
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gssEapDeleteNameAttribute(OM_uint32 *minor,
+ gss_name_t name,
+ gss_buffer_t attr)
+{
+ if (name->attrCtx == NULL) {
+ *minor = GSSEAP_NO_ATTR_CONTEXT;
+ return GSS_S_UNAVAILABLE;
+ }
+
+ if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
+ return GSS_S_UNAVAILABLE;
+
+ try {
+ if (!name->attrCtx->deleteAttribute(attr)) {
+ *minor = GSSEAP_NO_SUCH_ATTR;
+ gssEapSaveStatusInfo(*minor, "Unknown naming attribute %.*s",
+ (int)attr->length, (char *)attr->value);
+ return GSS_S_UNAVAILABLE;
+ }
+ } catch (std::exception &ex) {
+ return mapException(minor, ex);
+ }
+
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gssEapSetNameAttribute(OM_uint32 *minor,
+ gss_name_t name,
+ int complete,
+ gss_buffer_t attr,
+ gss_buffer_t value)
+{
+ if (name->attrCtx == NULL) {
+ *minor = GSSEAP_NO_ATTR_CONTEXT;
+ return GSS_S_UNAVAILABLE;
+ }
+
+ if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
+ return GSS_S_UNAVAILABLE;
+
+ try {
+ if (!name->attrCtx->setAttribute(complete, attr, value)) {
+ *minor = GSSEAP_NO_SUCH_ATTR;
+ gssEapSaveStatusInfo(*minor, "Unknown naming attribute %.*s",
+ (int)attr->length, (char *)attr->value);
+ return GSS_S_UNAVAILABLE;
+ }
+ } catch (std::exception &ex) {
+ return mapException(minor, ex);
+ }
+
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gssEapExportAttrContext(OM_uint32 *minor,
+ gss_name_t name,
+ gss_buffer_t buffer)
+{
+ if (name->attrCtx == NULL) {
+ buffer->length = 0;
+ buffer->value = NULL;
+
+ return GSS_S_COMPLETE;
+ }
+
+ if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
+ return GSS_S_UNAVAILABLE;
+
+ try {
+ name->attrCtx->exportToBuffer(buffer);
+ } catch (std::exception &e) {
+ return mapException(minor, e);
+ }
+
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gssEapImportAttrContext(OM_uint32 *minor,
+ gss_buffer_t buffer,
+ gss_name_t name)
+{
+ gss_eap_attr_ctx *ctx = NULL;
+
+ assert(name->attrCtx == NULL);
+
+ if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
+ return GSS_S_UNAVAILABLE;
+
+ if (buffer->length != 0) {
+ try {
+ ctx = new gss_eap_attr_ctx();
+
+ if (!ctx->initFromBuffer(buffer)) {
+ delete ctx;
+ *minor = GSSEAP_BAD_ATTR_TOKEN;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+ name->attrCtx = ctx;
+ } catch (std::exception &e) {
+ delete ctx;
+ return mapException(minor, e);
+ }
+ }
+
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gssEapDuplicateAttrContext(OM_uint32 *minor,
+ gss_name_t in,
+ gss_name_t out)
+{
+ gss_eap_attr_ctx *ctx = NULL;
+
+ assert(out->attrCtx == NULL);
+
+ if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
+ return GSS_S_UNAVAILABLE;
+
+ try {
+ if (in->attrCtx != NULL) {
+ ctx = new gss_eap_attr_ctx();
+ if (!ctx->initFromExistingContext(in->attrCtx)) {
+ delete ctx;
+ *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
+ return GSS_S_FAILURE;
+ }
+ out->attrCtx = ctx;
+ }
+ } catch (std::exception &e) {
+ delete ctx;
+ return mapException(minor, e);
+ }
+
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gssEapMapNameToAny(OM_uint32 *minor,
+ gss_name_t name,
+ int authenticated,
+ gss_buffer_t type_id,
+ gss_any_t *output)
+{
+ if (name->attrCtx == NULL) {
+ *minor = GSSEAP_NO_ATTR_CONTEXT;
+ return GSS_S_UNAVAILABLE;
+ }
+
+ if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
+ return GSS_S_UNAVAILABLE;
+
+ try {
+ *output = name->attrCtx->mapToAny(authenticated, type_id);
+ } catch (std::exception &e) {
+ return mapException(minor, e);
+ }
+
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gssEapReleaseAnyNameMapping(OM_uint32 *minor,
+ gss_name_t name,
+ gss_buffer_t type_id,
+ gss_any_t *input)
+{
+ if (name->attrCtx == NULL) {
+ *minor = GSSEAP_NO_ATTR_CONTEXT;
+ return GSS_S_UNAVAILABLE;
+ }
+
+ if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
+ return GSS_S_UNAVAILABLE;
+
+ try {
+ if (*input != NULL)
+ name->attrCtx->releaseAnyNameMapping(type_id, *input);
+ *input = NULL;
+ } catch (std::exception &e) {
+ return mapException(minor, e);
+ }
+
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gssEapReleaseAttrContext(OM_uint32 *minor,
+ gss_name_t name)
+{
+ if (name->attrCtx != NULL)
+ delete name->attrCtx;
+
+ return GSS_S_COMPLETE;
+}
+
+/*
+ * Public accessor for initialisng a context from a GSS context. Also
+ * sets expiry time on GSS context as a side-effect.
+ */
+struct gss_eap_attr_ctx *
+gssEapCreateAttrContext(gss_cred_id_t gssCred,
+ gss_ctx_id_t gssCtx)
+{
+ gss_eap_attr_ctx *ctx;
+ OM_uint32 tmpMinor;
+
+ assert(gssCtx != GSS_C_NO_CONTEXT);
+
+ if (GSS_ERROR(gssEapAttrProvidersInit(&tmpMinor)))
+ return NULL;
+
+ ctx = new gss_eap_attr_ctx();
+ if (!ctx->initFromGssContext(gssCred, gssCtx)) {
+ delete ctx;
+ return NULL;
+ }
+
+ gssCtx->expiryTime = ctx->getExpiryTime();
+
+ return ctx;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Attribute provider interface.
+ */
+
+#ifndef _UTIL_ATTR_H_
+#define _UTIL_ATTR_H_ 1
+
+#ifdef __cplusplus
+#include <string>
+
+struct gss_eap_attr_provider;
+struct gss_eap_attr_ctx;
+
+typedef bool
+(*gss_eap_attr_enumeration_cb)(const gss_eap_attr_provider *source,
+ const gss_buffer_t attribute,
+ void *data);
+
+#define ATTR_TYPE_RADIUS 0U /* RADIUS AVPs */
+#define ATTR_TYPE_SAML_ASSERTION 1U /* SAML assertion */
+#define ATTR_TYPE_SAML 2U /* SAML attributes */
+#define ATTR_TYPE_LOCAL 3U /* Local attributes */
+#define ATTR_TYPE_MIN ATTR_TYPE_RADIUS
+#define ATTR_TYPE_MAX ATTR_TYPE_LOCAL
+
+#define ATTR_FLAG_DISABLE_LOCAL 0x00000001
+
+/*
+ * Attribute provider: this represents a source of attributes derived
+ * from the security context.
+ */
+struct gss_eap_attr_provider
+{
+public:
+ gss_eap_attr_provider(void) {}
+ virtual ~gss_eap_attr_provider(void) {}
+
+ bool initWithManager(const gss_eap_attr_ctx *manager)
+ {
+ m_manager = manager;
+ return true;
+ }
+
+ virtual bool initFromExistingContext(const gss_eap_attr_ctx *manager,
+ const gss_eap_attr_provider *ctx)
+ {
+ return initWithManager(manager);
+ }
+
+ virtual bool initFromGssContext(const gss_eap_attr_ctx *manager,
+ const gss_cred_id_t cred,
+ const gss_ctx_id_t ctx)
+ {
+ return initWithManager(manager);
+ }
+
+ virtual bool getAttributeTypes(gss_eap_attr_enumeration_cb, void *data) const
+ {
+ return false;
+ }
+
+ virtual bool setAttribute(int complete,
+ const gss_buffer_t attr,
+ const gss_buffer_t value) { return false; }
+ virtual bool deleteAttribute(const gss_buffer_t value) { return false; }
+ virtual bool getAttribute(const gss_buffer_t attr,
+ int *authenticated,
+ int *complete,
+ gss_buffer_t value,
+ gss_buffer_t display_value,
+ int *more) const { return false; }
+
+ virtual gss_any_t mapToAny(int authenticated,
+ gss_buffer_t type_id) const { return NULL; }
+ virtual void releaseAnyNameMapping(gss_buffer_t type_id,
+ gss_any_t input) const {}
+
+ virtual void exportToBuffer(gss_buffer_t buffer) const {}
+ virtual bool initFromBuffer(const gss_eap_attr_ctx *manager,
+ const gss_buffer_t buffer)
+ {
+ return initWithManager(manager);
+ }
+
+ virtual time_t getExpiryTime(void) const { return 0; }
+
+ static bool init(void) { return true; }
+ static void finalize(void) {}
+
+ static gss_eap_attr_provider *createAttrContext(void) { return NULL; }
+
+protected:
+ const gss_eap_attr_ctx *m_manager;
+
+private:
+ /* make non-copyable */
+ gss_eap_attr_provider(const gss_eap_attr_provider&);
+ gss_eap_attr_provider& operator=(const gss_eap_attr_provider&);
+};
+
+typedef gss_eap_attr_provider *(*gss_eap_attr_create_provider)(void);
+
+/*
+ * Attribute context: this manages a set of providers for a given
+ * security context.
+ */
+struct gss_eap_attr_ctx
+{
+public:
+ gss_eap_attr_ctx(void);
+ ~gss_eap_attr_ctx(void);
+
+ bool initFromExistingContext(const gss_eap_attr_ctx *manager);
+ bool initFromGssContext(const gss_cred_id_t cred,
+ const gss_ctx_id_t ctx);
+
+ bool getAttributeTypes(gss_eap_attr_enumeration_cb, void *data) const;
+ bool getAttributeTypes(gss_buffer_set_t *attrs);
+
+ bool setAttribute(int complete,
+ const gss_buffer_t attr,
+ const gss_buffer_t value);
+ bool deleteAttribute(const gss_buffer_t value);
+ bool getAttribute(const gss_buffer_t attr,
+ int *authenticated,
+ int *complete,
+ gss_buffer_t value,
+ gss_buffer_t display_value,
+ int *more) const;
+ gss_any_t mapToAny(int authenticated,
+ gss_buffer_t type_id) const;
+ void releaseAnyNameMapping(gss_buffer_t type_id,
+ gss_any_t input) const;
+
+ void exportToBuffer(gss_buffer_t buffer) const;
+ bool initFromBuffer(const gss_buffer_t buffer);
+
+ static unsigned int
+ attributePrefixToType(const gss_buffer_t prefix);
+
+ static const gss_buffer_t
+ attributeTypeToPrefix(unsigned int type);
+
+ static void
+ decomposeAttributeName(const gss_buffer_t attribute,
+ gss_buffer_t prefix,
+ gss_buffer_t suffix);
+ static void
+ composeAttributeName(const gss_buffer_t prefix,
+ const gss_buffer_t suffix,
+ gss_buffer_t attribute);
+ static void
+ decomposeAttributeName(const gss_buffer_t attribute,
+ unsigned int *type,
+ gss_buffer_t suffix);
+ static void
+ composeAttributeName(unsigned int type,
+ const gss_buffer_t suffix,
+ gss_buffer_t attribute);
+
+ static std::string
+ composeAttributeName(const gss_buffer_t prefix,
+ const gss_buffer_t suffix);
+ static std::string
+ composeAttributeName(unsigned int type,
+ const gss_buffer_t suffix);
+
+ gss_eap_attr_provider *getProvider(unsigned int type) const;
+ gss_eap_attr_provider *getProvider(const gss_buffer_t prefix) const;
+
+ static void
+ registerProvider(unsigned int type,
+ const char *prefix,
+ gss_eap_attr_create_provider factory);
+ static void
+ unregisterProvider(unsigned int type);
+
+ time_t getExpiryTime(void) const;
+
+private:
+ bool providerEnabled(unsigned int type) const;
+ void releaseProvider(unsigned int type);
+
+ gss_eap_attr_provider *getPrimaryProvider(void) const;
+
+ /* make non-copyable */
+ gss_eap_attr_ctx(const gss_eap_attr_ctx&);
+ gss_eap_attr_ctx& operator=(const gss_eap_attr_ctx&);
+
+ uint32_t m_flags;
+ gss_eap_attr_provider *m_providers[ATTR_TYPE_MAX + 1];
+};
+
+#endif /* __cplusplus */
+
+#include "util_radius.h"
+#include "util_saml.h"
+#include "util_shib.h"
+
+#ifdef __cplusplus
+
+#include <string>
+#include <new>
+
+static inline void
+duplicateBuffer(gss_buffer_desc &src, gss_buffer_t dst)
+{
+ OM_uint32 minor;
+
+ if (GSS_ERROR(duplicateBuffer(&minor, &src, dst)))
+ throw new std::bad_alloc();
+}
+
+static inline void
+duplicateBuffer(std::string &str, gss_buffer_t buffer)
+{
+ gss_buffer_desc tmp;
+
+ tmp.length = str.length();
+ tmp.value = (char *)str.c_str();
+
+ duplicateBuffer(tmp, buffer);
+}
+
+#else
+struct gss_eap_attr_ctx;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * C wrappers for attribute context functions. These match their
+ * GSS naming extension equivalents. The caller is required to
+ * obtain the name mutex.
+ */
+
+struct gss_eap_attr_ctx *
+gssEapCreateAttrContext(gss_cred_id_t acceptorCred,
+ gss_ctx_id_t acceptorCtx);
+
+OM_uint32
+gssEapInquireName(OM_uint32 *minor,
+ gss_name_t name,
+ int *name_is_MN,
+ gss_OID *MN_mech,
+ gss_buffer_set_t *attrs);
+
+OM_uint32
+gssEapGetNameAttribute(OM_uint32 *minor,
+ gss_name_t name,
+ gss_buffer_t attr,
+ int *authenticated,
+ int *complete,
+ gss_buffer_t value,
+ gss_buffer_t display_value,
+ int *more);
+
+OM_uint32
+gssEapDeleteNameAttribute(OM_uint32 *minor,
+ gss_name_t name,
+ gss_buffer_t attr);
+
+OM_uint32
+gssEapSetNameAttribute(OM_uint32 *minor,
+ gss_name_t name,
+ int complete,
+ gss_buffer_t attr,
+ gss_buffer_t value);
+
+OM_uint32
+gssEapExportAttrContext(OM_uint32 *minor,
+ gss_name_t name,
+ gss_buffer_t buffer);
+
+OM_uint32
+gssEapImportAttrContext(OM_uint32 *minor,
+ gss_buffer_t buffer,
+ gss_name_t name);
+
+OM_uint32
+gssEapDuplicateAttrContext(OM_uint32 *minor,
+ gss_name_t in,
+ gss_name_t out);
+
+OM_uint32
+gssEapMapNameToAny(OM_uint32 *minor,
+ gss_name_t name,
+ int authenticated,
+ gss_buffer_t type_id,
+ gss_any_t *output);
+
+OM_uint32
+gssEapReleaseAnyNameMapping(OM_uint32 *minor,
+ gss_name_t name,
+ gss_buffer_t type_id,
+ gss_any_t *input);
+
+OM_uint32
+gssEapReleaseAttrContext(OM_uint32 *minor,
+ gss_name_t name);
+
+OM_uint32
+gssEapAttrProvidersFinalize(OM_uint32 *minor);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _UTIL_ATTR_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Buffer handling helpers.
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32
+makeStringBuffer(OM_uint32 *minor,
+ const char *string,
+ gss_buffer_t buffer)
+{
+ size_t len = strlen(string);
+
+ buffer->value = GSSEAP_MALLOC(len + 1);
+ if (buffer->value == NULL) {
+ *minor = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ memcpy(buffer->value, string, len + 1);
+ buffer->length = len;
+
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+bufferToString(OM_uint32 *minor,
+ const gss_buffer_t buffer,
+ char **pString)
+{
+ char *s;
+
+ s = GSSEAP_MALLOC(buffer->length + 1);
+ if (s == NULL) {
+ *minor = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ memcpy(s, buffer->value, buffer->length);
+ s[buffer->length] = '\0';
+
+ *pString = s;
+
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+duplicateBuffer(OM_uint32 *minor,
+ const gss_buffer_t src,
+ gss_buffer_t dst)
+{
+ dst->length = 0;
+ dst->value = NULL;
+
+ if (src == GSS_C_NO_BUFFER)
+ return GSS_S_COMPLETE;
+
+ dst->value = GSSEAP_MALLOC(src->length + 1);
+ if (dst->value == NULL) {
+ *minor = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ dst->length = src->length;
+ memcpy(dst->value, src->value, dst->length);
+
+ ((unsigned char *)dst->value)[dst->length] = '\0';
+
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Message protection services: checksum helpers.
+ */
+
+#include "gssapiP_eap.h"
+
+static int
+gssEapChecksum(krb5_context context,
+ krb5_cksumtype type,
+ size_t rrc,
+ krb5_keyblock *key,
+ krb5_keyusage sign_usage,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int verify,
+ int *valid)
+{
+ krb5_error_code code;
+ gss_iov_buffer_desc *header;
+ gss_iov_buffer_desc *trailer;
+ krb5_crypto_iov *kiov;
+ size_t kiov_count;
+ int i = 0, j;
+ unsigned int k5_checksumlen;
+
+ if (verify)
+ *valid = FALSE;
+
+ code = krb5_c_crypto_length(context, KRB_KEY_TYPE(key),
+ KRB5_CRYPTO_TYPE_CHECKSUM, &k5_checksumlen);
+ if (code != 0)
+ return code;
+
+ header = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
+ assert(header != NULL);
+
+ trailer = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
+ assert(rrc != 0 || trailer != NULL);
+
+ if (trailer == NULL) {
+ if (rrc != k5_checksumlen)
+ return KRB5_BAD_MSIZE;
+ if (header->buffer.length != 16 + k5_checksumlen)
+ return KRB5_BAD_MSIZE;
+ } else if (trailer->buffer.length != k5_checksumlen)
+ return KRB5_BAD_MSIZE;
+
+ kiov_count = 2 + iov_count;
+ kiov = (krb5_crypto_iov *)GSSEAP_MALLOC(kiov_count * sizeof(krb5_crypto_iov));
+ if (kiov == NULL)
+ return ENOMEM;
+
+ /* Checksum over ( Data | Header ) */
+
+ /* Data */
+ for (j = 0; j < iov_count; j++) {
+ kiov[i].flags = gssEapMapCryptoFlag(iov[j].type);
+ kiov[i].data.length = iov[j].buffer.length;
+ kiov[i].data.data = (char *)iov[j].buffer.value;
+ i++;
+ }
+
+ /* Header */
+ kiov[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
+ kiov[i].data.length = 16;
+ kiov[i].data.data = (char *)header->buffer.value;
+ i++;
+
+ /* Checksum */
+ kiov[i].flags = KRB5_CRYPTO_TYPE_CHECKSUM;
+ if (trailer == NULL) {
+ kiov[i].data.length = header->buffer.length - 16;
+ kiov[i].data.data = (char *)header->buffer.value + 16;
+ } else {
+ kiov[i].data.length = trailer->buffer.length;
+ kiov[i].data.data = (char *)trailer->buffer.value;
+ }
+ i++;
+
+ if (verify) {
+ krb5_boolean kvalid = FALSE;
+
+ code = krb5_c_verify_checksum_iov(context, type, key,
+ sign_usage, kiov, kiov_count, &kvalid);
+
+ *valid = kvalid;
+ } else {
+ code = krb5_c_make_checksum_iov(context, type, key,
+ sign_usage, kiov, kiov_count);
+ }
+
+ GSSEAP_FREE(kiov);
+
+ return code;
+}
+
+int
+gssEapSign(krb5_context context,
+ krb5_cksumtype type,
+ size_t rrc,
+ krb5_keyblock *key,
+ krb5_keyusage sign_usage,
+ gss_iov_buffer_desc *iov,
+ int iov_count)
+{
+ return gssEapChecksum(context, type, rrc, key,
+ sign_usage, iov, iov_count, 0, NULL);
+}
+
+int
+gssEapVerify(krb5_context context,
+ krb5_cksumtype type,
+ size_t rrc,
+ krb5_keyblock *key,
+ krb5_keyusage sign_usage,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int *valid)
+{
+ return gssEapChecksum(context, type, rrc, key,
+ sign_usage, iov, iov_count, 1, valid);
+}
+
+#if 0
+OM_uint32
+gssEapEncodeGssChannelBindings(OM_uint32 *minor,
+ gss_channel_bindings_t chanBindings,
+ gss_buffer_t encodedBindings)
+{
+ OM_uint32 major, tmpMinor;
+ size_t length;
+ unsigned char *p;
+
+ if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS) {
+ length = 24;
+ length += chanBindings->initiator_address.length;
+ length += chanBindings->acceptor_address.length;
+ length += chanBindings->application_data.length;
+
+ encodedBindings->value = GSSEAP_MALLOC(length);
+ if (encodedBindings->value == NULL) {
+ *minor = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ encodedBindings->length = length;
+ p = (unsigned char *)encodedBindings->value;
+
+ store_uint32_be(chanBindings->initiator_addrtype, p);
+ store_buffer(&chanBindings->initiator_address, p + 4, 0);
+ p += 4 + chanBindings->initiator_address.length;
+
+ store_uint32_be(chanBindings->acceptor_addrtype, p);
+ store_buffer(&chanBindings->acceptor_address, p + 4, 0);
+ p += 4 + chanBindings->acceptor_address.length;
+
+ store_buffer(&chanBindings->application_data, p, 1);
+ p += chanBindings->application_data.length;
+ } else {
+ encodedBindings->length = 0;
+ encodedBindings->value = NULL;
+ }
+
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Utility routines for context handles.
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32
+gssEapAllocContext(OM_uint32 *minor,
+ gss_ctx_id_t *pCtx)
+{
+ OM_uint32 tmpMinor;
+ gss_ctx_id_t ctx;
+
+ assert(*pCtx == GSS_C_NO_CONTEXT);
+
+ ctx = (gss_ctx_id_t)GSSEAP_CALLOC(1, sizeof(*ctx));
+ if (ctx == NULL) {
+ *minor = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ if (GSSEAP_MUTEX_INIT(&ctx->mutex) != 0) {
+ *minor = errno;
+ gssEapReleaseContext(&tmpMinor, &ctx);
+ return GSS_S_FAILURE;
+ }
+
+ ctx->state = EAP_STATE_IDENTITY;
+
+ /*
+ * Integrity, confidentiality, sequencing and replay detection are
+ * always available. Regardless of what flags are requested in
+ * GSS_Init_sec_context, implementations MUST set the flag corresponding
+ * to these services in the output of GSS_Init_sec_context and
+ * GSS_Accept_sec_context.
+ */
+ ctx->gssFlags = GSS_C_TRANS_FLAG | /* exporting contexts */
+ GSS_C_INTEG_FLAG | /* integrity */
+ GSS_C_CONF_FLAG | /* confidentiality */
+ GSS_C_SEQUENCE_FLAG | /* sequencing */
+ GSS_C_REPLAY_FLAG; /* replay detection */
+
+ *pCtx = ctx;
+
+ return GSS_S_COMPLETE;
+}
+
+static void
+releaseInitiatorContext(struct gss_eap_initiator_ctx *ctx)
+{
+ OM_uint32 minor;
+
+ gssEapReleaseCred(&minor, &ctx->defaultCred);
+ eap_peer_sm_deinit(ctx->eap);
+}
+
+static void
+releaseAcceptorContext(struct gss_eap_acceptor_ctx *ctx)
+{
+ OM_uint32 tmpMinor;
+
+ if (ctx->radConn != NULL)
+ rs_conn_destroy(ctx->radConn);
+ if (ctx->radContext != NULL)
+ rs_context_destroy(ctx->radContext);
+ if (ctx->radServer != NULL)
+ GSSEAP_FREE(ctx->radServer);
+ gss_release_buffer(&tmpMinor, &ctx->state);
+ if (ctx->vps != NULL)
+ gssEapRadiusFreeAvps(&tmpMinor, &ctx->vps);
+}
+
+OM_uint32
+gssEapReleaseContext(OM_uint32 *minor,
+ gss_ctx_id_t *pCtx)
+{
+ OM_uint32 tmpMinor;
+ gss_ctx_id_t ctx = *pCtx;
+ krb5_context krbContext = NULL;
+
+ if (ctx == GSS_C_NO_CONTEXT) {
+ return GSS_S_COMPLETE;
+ }
+
+ gssEapKerberosInit(&tmpMinor, &krbContext);
+
+#ifdef GSSEAP_ENABLE_REAUTH
+ if (ctx->flags & CTX_FLAG_KRB_REAUTH_GSS) {
+ gssDeleteSecContext(&tmpMinor, &ctx->kerberosCtx, GSS_C_NO_BUFFER);
+ } else
+#endif
+ if (CTX_IS_INITIATOR(ctx)) {
+ releaseInitiatorContext(&ctx->initiatorCtx);
+ } else {
+ releaseAcceptorContext(&ctx->acceptorCtx);
+ }
+
+ krb5_free_keyblock_contents(krbContext, &ctx->rfc3961Key);
+ gssEapReleaseName(&tmpMinor, &ctx->initiatorName);
+ gssEapReleaseName(&tmpMinor, &ctx->acceptorName);
+ gss_release_oid(&tmpMinor, &ctx->mechanismUsed);
+ sequenceFree(&tmpMinor, &ctx->seqState);
+
+ GSSEAP_MUTEX_DESTROY(&ctx->mutex);
+
+ memset(ctx, 0, sizeof(*ctx));
+ GSSEAP_FREE(ctx);
+ *pCtx = GSS_C_NO_CONTEXT;
+
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gssEapMakeToken(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ const gss_buffer_t innerToken,
+ enum gss_eap_token_type tokenType,
+ gss_buffer_t outputToken)
+{
+ unsigned char *p;
+
+ outputToken->length = tokenSize(ctx->mechanismUsed, innerToken->length);
+ outputToken->value = GSSEAP_MALLOC(outputToken->length);
+ if (outputToken->value == NULL) {
+ *minor = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ p = (unsigned char *)outputToken->value;
+ makeTokenHeader(ctx->mechanismUsed, innerToken->length, &p, tokenType);
+ memcpy(p, innerToken->value, innerToken->length);
+
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gssEapVerifyToken(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ const gss_buffer_t inputToken,
+ enum gss_eap_token_type *actualToken,
+ gss_buffer_t innerInputToken)
+{
+ OM_uint32 major;
+ size_t bodySize;
+ unsigned char *p = (unsigned char *)inputToken->value;
+ gss_OID_desc oidBuf;
+ gss_OID oid;
+
+ if (ctx->mechanismUsed != GSS_C_NO_OID) {
+ oid = ctx->mechanismUsed;
+ } else {
+ oidBuf.elements = NULL;
+ oidBuf.length = 0;
+ oid = &oidBuf;
+ }
+
+ major = verifyTokenHeader(minor, oid, &bodySize, &p,
+ inputToken->length, actualToken);
+ if (GSS_ERROR(major))
+ return major;
+
+ if (ctx->mechanismUsed == GSS_C_NO_OID) {
+ if (!gssEapIsConcreteMechanismOid(oid)) {
+ *minor = GSSEAP_WRONG_MECH;
+ return GSS_S_BAD_MECH;
+ }
+
+ if (!gssEapInternalizeOid(oid, &ctx->mechanismUsed)) {
+ major = duplicateOid(minor, oid, &ctx->mechanismUsed);
+ if (GSS_ERROR(major))
+ return major;
+ }
+ }
+
+ innerInputToken->length = bodySize;
+ innerInputToken->value = p;
+
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gssEapContextTime(OM_uint32 *minor,
+ gss_ctx_id_t context_handle,
+ OM_uint32 *time_rec)
+{
+ if (context_handle->expiryTime == 0) {
+ *time_rec = GSS_C_INDEFINITE;
+ } else {
+ time_t now, lifetime;
+
+ time(&now);
+ lifetime = context_handle->expiryTime - now;
+ if (lifetime <= 0) {
+ *time_rec = 0;
+ return GSS_S_CONTEXT_EXPIRED;
+ }
+ *time_rec = lifetime;
+ }
+
+ return GSS_S_COMPLETE;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Utility routines for credential handles.
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32
+gssEapAllocCred(OM_uint32 *minor, gss_cred_id_t *pCred)
+{
+ OM_uint32 tmpMinor;
+ gss_cred_id_t cred;
+
+ *pCred = GSS_C_NO_CREDENTIAL;
+
+ cred = (gss_cred_id_t)GSSEAP_CALLOC(1, sizeof(*cred));
+ if (cred == NULL) {
+ *minor = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ if (GSSEAP_MUTEX_INIT(&cred->mutex) != 0) {
+ *minor = errno;
+ gssEapReleaseCred(&tmpMinor, &cred);
+ return GSS_S_FAILURE;
+ }
+
+ *pCred = cred;
+
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gssEapReleaseCred(OM_uint32 *minor, gss_cred_id_t *pCred)
+{
+ OM_uint32 tmpMinor;
+ gss_cred_id_t cred = *pCred;
+ krb5_context krbContext = NULL;
+
+ if (cred == GSS_C_NO_CREDENTIAL) {
+ return GSS_S_COMPLETE;
+ }
+
+ GSSEAP_KRB_INIT(&krbContext);
+
+ gssEapReleaseName(&tmpMinor, &cred->name);
+
+ if (cred->password.value != NULL) {
+ memset(cred->password.value, 0, cred->password.length);
+ GSSEAP_FREE(cred->password.value);
+ }
+
+ if (cred->radiusConfigFile != NULL)
+ GSSEAP_FREE(cred->radiusConfigFile);
+ if (cred->radiusConfigStanza != NULL)
+ GSSEAP_FREE(cred->radiusConfigStanza);
+
+#ifdef GSSEAP_ENABLE_REAUTH
+ if (cred->krbCredCache != NULL) {
+ if (cred->flags & CRED_FLAG_DEFAULT_CCACHE)
+ krb5_cc_close(krbContext, cred->krbCredCache);
+ else
+ krb5_cc_destroy(krbContext, cred->krbCredCache);
+ }
+ if (cred->krbCred != GSS_C_NO_CREDENTIAL)
+ gssReleaseCred(&tmpMinor, &cred->krbCred);
+#endif
+
+ GSSEAP_MUTEX_DESTROY(&cred->mutex);
+ memset(cred, 0, sizeof(*cred));
+ GSSEAP_FREE(cred);
+ *pCred = NULL;
+
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gssEapAcquireCred(OM_uint32 *minor,
+ const gss_name_t desiredName,
+ const gss_buffer_t password,
+ OM_uint32 timeReq,
+ const gss_OID_set desiredMechs,
+ int credUsage,
+ gss_cred_id_t *pCred,
+ gss_OID_set *pActualMechs,
+ OM_uint32 *timeRec)
+{
+ OM_uint32 major, tmpMinor;
+ gss_cred_id_t cred;
+
+ /* XXX TODO validate with changed set_cred_option API */
+ *pCred = GSS_C_NO_CREDENTIAL;
+
+ major = gssEapAllocCred(minor, &cred);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ if (desiredName != GSS_C_NO_NAME) {
+ GSSEAP_MUTEX_LOCK(&desiredName->mutex);
+
+ major = gssEapDuplicateName(minor, desiredName, &cred->name);
+ if (GSS_ERROR(major)) {
+ GSSEAP_MUTEX_UNLOCK(&desiredName->mutex);
+ goto cleanup;
+ }
+
+ GSSEAP_MUTEX_UNLOCK(&desiredName->mutex);
+ } else {
+ gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
+ gss_OID nameType = GSS_C_NO_OID;
+
+ if (cred->flags & CRED_FLAG_ACCEPT) {
+ char serviceName[5 + MAXHOSTNAMELEN] = "host@";
+
+ /* default host-based service is host@localhost */
+ if (gethostname(&serviceName[5], MAXHOSTNAMELEN) != 0) {
+ major = GSS_S_FAILURE;
+ *minor = GSSEAP_NO_HOSTNAME;
+ goto cleanup;
+ }
+
+ nameBuf.value = serviceName;
+ nameBuf.length = strlen((char *)nameBuf.value);
+
+ nameType = GSS_C_NT_HOSTBASED_SERVICE;
+ } else if (cred->flags & CRED_FLAG_INITIATE) {
+ nameBuf.value = getlogin(); /* XXX */
+ nameBuf.length = strlen((char *)nameBuf.value);
+
+ nameType = GSS_C_NT_USER_NAME;
+ }
+
+ if (nameBuf.length != 0) {
+ major = gssEapImportName(minor, &nameBuf, nameType, &cred->name);
+ if (GSS_ERROR(major))
+ goto cleanup;
+ }
+
+ cred->flags |= CRED_FLAG_DEFAULT_IDENTITY;
+ }
+
+ if (password != GSS_C_NO_BUFFER) {
+ major = duplicateBuffer(minor, password, &cred->password);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ cred->flags |= CRED_FLAG_PASSWORD;
+ } else if (credUsage == GSS_C_INITIATE) {
+ /*
+ * OK, here we need to ask the supplicant if we have creds or it
+ * will acquire them, so GS2 can know whether to prompt for a
+ * password or not.
+ */
+#if 0
+ && !gssEapCanReauthP(cred, GSS_C_NO_NAME, timeReq)
+#endif
+ major = GSS_S_CRED_UNAVAIL;
+ goto cleanup;
+ }
+
+ switch (credUsage) {
+ case GSS_C_BOTH:
+ cred->flags |= CRED_FLAG_INITIATE | CRED_FLAG_ACCEPT;
+ break;
+ case GSS_C_INITIATE:
+ cred->flags |= CRED_FLAG_INITIATE;
+ break;
+ case GSS_C_ACCEPT:
+ cred->flags |= CRED_FLAG_ACCEPT;
+ break;
+ default:
+ major = GSS_S_FAILURE;
+ *minor = GSSEAP_BAD_USAGE;
+ goto cleanup;
+ break;
+ }
+
+ major = gssEapValidateMechs(minor, desiredMechs);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ major = duplicateOidSet(minor, desiredMechs, &cred->mechanisms);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ if (pActualMechs != NULL) {
+ major = duplicateOidSet(minor, cred->mechanisms, pActualMechs);
+ if (GSS_ERROR(major))
+ goto cleanup;
+ }
+
+ if (timeRec != NULL)
+ *timeRec = GSS_C_INDEFINITE;
+
+ *pCred = cred;
+
+ major = GSS_S_COMPLETE;
+ *minor = 0;
+
+cleanup:
+ if (GSS_ERROR(major))
+ gssEapReleaseCred(&tmpMinor, &cred);
+
+ return major;
+}
+
+/*
+ * Return TRUE if cred available for mechanism. Caller need no acquire
+ * lock because mechanisms list is immutable.
+ */
+int
+gssEapCredAvailable(gss_cred_id_t cred, gss_OID mech)
+{
+ OM_uint32 minor;
+ int present = 0;
+
+ assert(mech != GSS_C_NO_OID);
+
+ if (cred == GSS_C_NO_CREDENTIAL || cred->mechanisms == GSS_C_NO_OID_SET)
+ return TRUE;
+
+ gss_test_oid_set_member(&minor, mech, cred->mechanisms, &present);
+
+ return present;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Copyright 2001, 2008 by the Massachusetts Institute of Technology.
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * Message protection services: cryptography helpers.
+ */
+
+#include "gssapiP_eap.h"
+
+/*
+ * DCE_STYLE indicates actual RRC is EC + RRC
+ * EC is extra rotate count for DCE_STYLE, pad length otherwise
+ * RRC is rotate count.
+ */
+static krb5_error_code
+mapIov(krb5_context context, int dce_style, size_t ec, size_t rrc,
+ krb5_enctype enctype, gss_iov_buffer_desc *iov,
+ int iov_count, krb5_crypto_iov **pkiov,
+ size_t *pkiov_count)
+{
+ gss_iov_buffer_t header;
+ gss_iov_buffer_t trailer;
+ int i = 0, j;
+ size_t kiov_count;
+ krb5_crypto_iov *kiov;
+ unsigned int k5_headerlen = 0, k5_trailerlen = 0;
+ size_t gss_headerlen, gss_trailerlen;
+ krb5_error_code code;
+
+ *pkiov = NULL;
+ *pkiov_count = 0;
+
+ header = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
+ assert(header != NULL);
+
+ trailer = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
+ assert(trailer == NULL || rrc == 0);
+
+ code = krb5_c_crypto_length(context, enctype, KRB5_CRYPTO_TYPE_HEADER,
+ &k5_headerlen);
+ if (code != 0)
+ return code;
+
+ code = krb5_c_crypto_length(context, enctype, KRB5_CRYPTO_TYPE_TRAILER,
+ &k5_trailerlen);
+ if (code != 0)
+ return code;
+
+ /* Check header and trailer sizes */
+ gss_headerlen = 16 /* GSS-Header */ + k5_headerlen; /* Kerb-Header */
+ gss_trailerlen = ec + 16 /* E(GSS-Header) */ + k5_trailerlen; /* Kerb-Trailer */
+
+ /* If we're caller without a trailer, we must rotate by trailer length */
+ if (trailer == NULL) {
+ size_t actual_rrc = rrc;
+
+ if (dce_style)
+ actual_rrc += ec; /* compensate for Windows bug */
+
+ if (actual_rrc != gss_trailerlen)
+ return KRB5_BAD_MSIZE;
+
+ gss_headerlen += gss_trailerlen;
+ gss_trailerlen = 0;
+ } else {
+ if (trailer->buffer.length != gss_trailerlen)
+ return KRB5_BAD_MSIZE;
+ }
+
+ if (header->buffer.length != gss_headerlen)
+ return KRB5_BAD_MSIZE;
+
+ kiov_count = 3 + iov_count;
+ kiov = (krb5_crypto_iov *)GSSEAP_MALLOC(kiov_count * sizeof(krb5_crypto_iov));
+ if (kiov == NULL)
+ return ENOMEM;
+
+ /*
+ * The krb5 header is located at the end of the GSS header.
+ */
+ kiov[i].flags = KRB5_CRYPTO_TYPE_HEADER;
+ kiov[i].data.length = k5_headerlen;
+ kiov[i].data.data = (char *)header->buffer.value + header->buffer.length - k5_headerlen;
+ i++;
+
+ for (j = 0; j < iov_count; j++) {
+ kiov[i].flags = gssEapMapCryptoFlag(iov[j].type);
+ if (kiov[i].flags == KRB5_CRYPTO_TYPE_EMPTY)
+ continue;
+
+ kiov[i].data.length = iov[j].buffer.length;
+ kiov[i].data.data = (char *)iov[j].buffer.value;
+ i++;
+ }
+
+ /*
+ * The EC and encrypted GSS header are placed in the trailer, which may
+ * be rotated directly after the plaintext header if no trailer buffer
+ * is provided.
+ */
+ kiov[i].flags = KRB5_CRYPTO_TYPE_DATA;
+ kiov[i].data.length = ec + 16; /* E(Header) */
+ if (trailer == NULL)
+ kiov[i].data.data = (char *)header->buffer.value + 16;
+ else
+ kiov[i].data.data = (char *)trailer->buffer.value;
+ i++;
+
+ /*
+ * The krb5 trailer is placed after the encrypted copy of the
+ * krb5 header (which may be in the GSS header or trailer).
+ */
+ kiov[i].flags = KRB5_CRYPTO_TYPE_TRAILER;
+ kiov[i].data.length = k5_trailerlen;
+ kiov[i].data.data = kiov[i - 1].data.data + ec + 16; /* E(Header) */
+ i++;
+
+ *pkiov = kiov;
+ *pkiov_count = i;
+
+ return 0;
+}
+
+int
+gssEapEncrypt(krb5_context context, int dce_style, size_t ec,
+ size_t rrc, krb5_keyblock *key, int usage, krb5_pointer iv,
+ gss_iov_buffer_desc *iov, int iov_count)
+{
+ krb5_error_code code;
+ size_t blocksize;
+ krb5_data ivd, *pivd;
+ size_t kiov_count;
+ krb5_crypto_iov *kiov;
+
+ if (iv) {
+ code = krb5_c_block_size(context, KRB_KEY_TYPE(key), &blocksize);
+ if (code)
+ return(code);
+
+ ivd.length = blocksize;
+ ivd.data = GSSEAP_MALLOC(ivd.length);
+ if (ivd.data == NULL)
+ return ENOMEM;
+ memcpy(ivd.data, iv, ivd.length);
+ pivd = &ivd;
+ } else {
+ pivd = NULL;
+ }
+
+ code = mapIov(context, dce_style, ec, rrc,
+ KRB_KEY_TYPE(key), iov, iov_count,
+ &kiov, &kiov_count);
+ if (code == 0) {
+ code = krb5_c_encrypt_iov(context, key, usage, pivd, kiov, kiov_count);
+ GSSEAP_FREE(kiov);
+ }
+
+ if (pivd != NULL)
+ GSSEAP_FREE(pivd->data);
+
+ return code;
+}
+
+int
+gssEapDecrypt(krb5_context context, int dce_style, size_t ec,
+ size_t rrc, krb5_keyblock *key, int usage, krb5_pointer iv,
+ gss_iov_buffer_desc *iov, int iov_count)
+{
+ krb5_error_code code;
+ size_t blocksize;
+ krb5_data ivd, *pivd;
+ size_t kiov_count;
+ krb5_crypto_iov *kiov;
+
+ if (iv) {
+ code = krb5_c_block_size(context, KRB_KEY_TYPE(key), &blocksize);
+ if (code)
+ return(code);
+
+ ivd.length = blocksize;
+ ivd.data = GSSEAP_MALLOC(ivd.length);
+ if (ivd.data == NULL)
+ return ENOMEM;
+ memcpy(ivd.data, iv, ivd.length);
+ pivd = &ivd;
+ } else {
+ pivd = NULL;
+ }
+
+ code = mapIov(context, dce_style, ec, rrc,
+ KRB_KEY_TYPE(key), iov, iov_count,
+ &kiov, &kiov_count);
+ if (code == 0) {
+ code = krb5_c_decrypt_iov(context, key, usage, pivd, kiov, kiov_count);
+ GSSEAP_FREE(kiov);
+ }
+
+ if (pivd != NULL)
+ GSSEAP_FREE(pivd->data);
+
+ return code;
+}
+
+krb5_cryptotype
+gssEapMapCryptoFlag(OM_uint32 type)
+{
+ krb5_cryptotype ktype;
+
+ switch (GSS_IOV_BUFFER_TYPE(type)) {
+ case GSS_IOV_BUFFER_TYPE_DATA:
+ case GSS_IOV_BUFFER_TYPE_PADDING:
+ ktype = KRB5_CRYPTO_TYPE_DATA;
+ break;
+ case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
+ ktype = KRB5_CRYPTO_TYPE_SIGN_ONLY;
+ break;
+ default:
+ ktype = KRB5_CRYPTO_TYPE_EMPTY;
+ break;
+ }
+
+ return ktype;
+}
+
+gss_iov_buffer_t
+gssEapLocateIov(gss_iov_buffer_desc *iov, int iov_count, OM_uint32 type)
+{
+ int i;
+ gss_iov_buffer_t p = GSS_C_NO_IOV_BUFFER;
+
+ if (iov == GSS_C_NO_IOV_BUFFER)
+ return GSS_C_NO_IOV_BUFFER;
+
+ for (i = iov_count - 1; i >= 0; i--) {
+ if (GSS_IOV_BUFFER_TYPE(iov[i].type) == type) {
+ if (p == GSS_C_NO_IOV_BUFFER)
+ p = &iov[i];
+ else
+ return GSS_C_NO_IOV_BUFFER;
+ }
+ }
+
+ return p;
+}
+
+void
+gssEapIovMessageLength(gss_iov_buffer_desc *iov,
+ int iov_count,
+ size_t *data_length_p,
+ size_t *assoc_data_length_p)
+{
+ int i;
+ size_t data_length = 0, assoc_data_length = 0;
+
+ assert(iov != GSS_C_NO_IOV_BUFFER);
+
+ *data_length_p = *assoc_data_length_p = 0;
+
+ for (i = 0; i < iov_count; i++) {
+ OM_uint32 type = GSS_IOV_BUFFER_TYPE(iov[i].type);
+
+ if (type == GSS_IOV_BUFFER_TYPE_SIGN_ONLY)
+ assoc_data_length += iov[i].buffer.length;
+
+ if (type == GSS_IOV_BUFFER_TYPE_DATA ||
+ type == GSS_IOV_BUFFER_TYPE_SIGN_ONLY)
+ data_length += iov[i].buffer.length;
+ }
+
+ *data_length_p = data_length;
+ *assoc_data_length_p = assoc_data_length;
+}
+
+void
+gssEapReleaseIov(gss_iov_buffer_desc *iov, int iov_count)
+{
+ int i;
+ OM_uint32 min_stat;
+
+ assert(iov != GSS_C_NO_IOV_BUFFER);
+
+ for (i = 0; i < iov_count; i++) {
+ if (iov[i].type & GSS_IOV_BUFFER_FLAG_ALLOCATED) {
+ gss_release_buffer(&min_stat, &iov[i].buffer);
+ iov[i].type &= ~(GSS_IOV_BUFFER_FLAG_ALLOCATED);
+ }
+ }
+}
+
+int
+gssEapIsIntegrityOnly(gss_iov_buffer_desc *iov, int iov_count)
+{
+ int i;
+ krb5_boolean has_conf_data = FALSE;
+
+ assert(iov != GSS_C_NO_IOV_BUFFER);
+
+ for (i = 0; i < iov_count; i++) {
+ if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA) {
+ has_conf_data = TRUE;
+ break;
+ }
+ }
+
+ return (has_conf_data == FALSE);
+}
+
+int
+gssEapAllocIov(gss_iov_buffer_t iov, size_t size)
+{
+ assert(iov != GSS_C_NO_IOV_BUFFER);
+ assert(iov->type & GSS_IOV_BUFFER_FLAG_ALLOCATE);
+
+ iov->buffer.length = size;
+ iov->buffer.value = GSSEAP_MALLOC(size);
+ if (iov->buffer.value == NULL) {
+ iov->buffer.length = 0;
+ return ENOMEM;
+ }
+
+ iov->type |= GSS_IOV_BUFFER_FLAG_ALLOCATED;
+
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Extension token support.
+ */
+
+#include "gssapiP_eap.h"
+
+static OM_uint32
+encodeExtensions(OM_uint32 *minor,
+ gss_buffer_set_t extensions,
+ OM_uint32 *types,
+ gss_buffer_t buffer);
+
+static OM_uint32
+decodeExtensions(OM_uint32 *minor,
+ const gss_buffer_t buffer,
+ gss_buffer_set_t *pExtensions,
+ OM_uint32 **pTypes);
+
+/*
+ * Initiator extensions
+ */
+static OM_uint32
+makeGssChannelBindings(OM_uint32 *minor,
+ gss_cred_id_t cred,
+ gss_ctx_id_t ctx,
+ gss_channel_bindings_t chanBindings,
+ gss_buffer_t outputToken)
+{
+ OM_uint32 major;
+ gss_buffer_desc buffer = GSS_C_EMPTY_BUFFER;
+
+ if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS)
+ buffer = chanBindings->application_data;
+
+ major = gssEapWrap(minor, ctx, TRUE, GSS_C_QOP_DEFAULT,
+ &buffer, NULL, outputToken);
+ if (GSS_ERROR(major))
+ return major;
+
+ return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+verifyGssChannelBindings(OM_uint32 *minor,
+ gss_cred_id_t cred,
+ gss_ctx_id_t ctx,
+ gss_channel_bindings_t chanBindings,
+ gss_buffer_t inputToken)
+{
+ OM_uint32 major, tmpMinor;
+ gss_iov_buffer_desc iov[2];
+
+ iov[0].type = GSS_IOV_BUFFER_TYPE_DATA | GSS_IOV_BUFFER_FLAG_ALLOCATE;
+ iov[0].buffer.length = 0;
+ iov[0].buffer.value = NULL;
+
+ iov[1].type = GSS_IOV_BUFFER_TYPE_STREAM;
+ iov[1].buffer = *inputToken;
+
+ major = gssEapUnwrapOrVerifyMIC(minor, ctx, NULL, NULL,
+ iov, 2, TOK_TYPE_WRAP);
+ if (GSS_ERROR(major))
+ return GSS_S_BAD_BINDINGS;
+
+ if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS &&
+ !bufferEqual(&iov[0].buffer, &chanBindings->application_data)) {
+ major = GSS_S_BAD_BINDINGS;
+ *minor = GSSEAP_BINDINGS_MISMATCH;
+ } else {
+ major = GSS_S_COMPLETE;
+ }
+
+ gss_release_buffer(&tmpMinor, &iov[0].buffer);
+
+ return major;
+}
+
+static struct gss_eap_extension_provider
+eapGssInitExtensions[] = {
+ {
+ EXT_TYPE_GSS_CHANNEL_BINDINGS,
+ 1, /* critical */
+ 1, /* required */
+ makeGssChannelBindings,
+ verifyGssChannelBindings
+ },
+};
+
+/*
+ * Acceptor extensions
+ */
+static OM_uint32
+makeReauthCreds(OM_uint32 *minor,
+ gss_cred_id_t cred,
+ gss_ctx_id_t ctx,
+ gss_channel_bindings_t chanBindings,
+ gss_buffer_t outputToken)
+{
+ OM_uint32 major = GSS_S_UNAVAILABLE;
+
+#ifdef GSSEAP_ENABLE_REAUTH
+ /*
+ * If we're built with fast reauthentication enabled, then
+ * fabricate a ticket from the initiator to ourselves.
+ */
+ major = gssEapMakeReauthCreds(minor, ctx, cred, outputToken);
+#endif
+
+ return major;
+}
+
+static OM_uint32
+verifyReauthCreds(OM_uint32 *minor,
+ gss_cred_id_t cred,
+ gss_ctx_id_t ctx,
+ gss_channel_bindings_t chanBindings,
+ gss_buffer_t inputToken)
+{
+ OM_uint32 major = GSS_S_UNAVAILABLE;
+
+#ifdef GSSEAP_ENABLE_REAUTH
+ major = gssEapStoreReauthCreds(minor, ctx, cred, inputToken);
+#endif
+
+ return major;
+}
+
+static struct gss_eap_extension_provider
+eapGssAcceptExtensions[] = {
+ {
+ EXT_TYPE_REAUTH_CREDS,
+ 0, /* critical */
+ 0, /* required */
+ makeReauthCreds,
+ verifyReauthCreds
+ },
+};
+
+OM_uint32
+makeExtensions(OM_uint32 *minor,
+ gss_cred_id_t cred,
+ gss_ctx_id_t ctx,
+ const struct gss_eap_extension_provider *exts,
+ size_t nexts,
+ gss_channel_bindings_t chanBindings,
+ gss_buffer_t buffer)
+{
+ OM_uint32 major, tmpMinor;
+ size_t i, j;
+ gss_buffer_set_t extensions = GSS_C_NO_BUFFER_SET;
+ OM_uint32 *types;
+
+ assert(buffer != GSS_C_NO_BUFFER);
+
+ buffer->length = 0;
+ buffer->value = NULL;
+
+ types = GSSEAP_CALLOC(nexts, sizeof(OM_uint32));
+ if (types == NULL) {
+ major = GSS_S_FAILURE;
+ *minor = ENOMEM;
+ goto cleanup;
+ }
+
+ for (i = 0, j = 0; i < nexts; i++) {
+ const struct gss_eap_extension_provider *ext = &exts[i];
+ gss_buffer_desc extension = GSS_C_EMPTY_BUFFER;
+
+ types[j] = ext->type;
+ if (ext->critical)
+ types[j] |= EXT_FLAG_CRITICAL;
+
+ major = ext->make(minor, cred, ctx, chanBindings, &extension);
+ if (GSS_ERROR(major)) {
+ if (ext->critical)
+ goto cleanup;
+ else
+ continue;
+ }
+
+ major = gss_add_buffer_set_member(minor, &extension, &extensions);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ j++;
+ }
+
+ assert(j == (extensions == GSS_C_NO_BUFFER_SET ? 0 : extensions->count));
+
+ major = encodeExtensions(minor, extensions, types, buffer);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+cleanup:
+ gss_release_buffer_set(&tmpMinor, &extensions);
+ if (types != NULL)
+ GSSEAP_FREE(types);
+
+ return major;
+}
+
+OM_uint32
+gssEapMakeExtensions(OM_uint32 *minor,
+ gss_cred_id_t cred,
+ gss_ctx_id_t ctx,
+ gss_channel_bindings_t chanBindings,
+ gss_buffer_t buffer)
+{
+ size_t nexts;
+ const struct gss_eap_extension_provider *exts;
+
+ if (CTX_IS_INITIATOR(ctx)) {
+ exts = eapGssInitExtensions;
+ nexts = sizeof(eapGssInitExtensions) / sizeof(eapGssInitExtensions[0]);
+ } else {
+ exts = eapGssAcceptExtensions;
+ nexts = sizeof(eapGssAcceptExtensions) / sizeof(eapGssAcceptExtensions[0]);
+ }
+
+ return makeExtensions(minor, cred, ctx, exts, nexts, chanBindings, buffer);
+}
+
+static OM_uint32
+verifyExtensions(OM_uint32 *minor,
+ gss_cred_id_t cred,
+ gss_ctx_id_t ctx,
+ const struct gss_eap_extension_provider *exts,
+ size_t nexts,
+ gss_channel_bindings_t chanBindings,
+ const gss_buffer_t buffer)
+{
+ OM_uint32 major, tmpMinor;
+ gss_buffer_set_t extensions = GSS_C_NO_BUFFER_SET;
+ OM_uint32 *types = NULL;
+ size_t i;
+
+ major = decodeExtensions(minor, buffer, &extensions, &types);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ for (i = 0; i < nexts; i++) {
+ const struct gss_eap_extension_provider *ext = &exts[i];
+ gss_buffer_t extension = GSS_C_NO_BUFFER;
+ size_t j;
+
+ for (j = 0; j < extensions->count; j++) {
+ if ((types[j] & EXT_TYPE_MASK) == ext->type) {
+ extension = &extensions->elements[j];
+ break;
+ }
+ }
+
+ if (extension != GSS_C_NO_BUFFER) {
+ /* Process extension and mark as verified */
+ major = ext->verify(minor, cred, ctx, chanBindings,
+ &extensions->elements[j]);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ types[j] |= EXT_FLAG_VERIFIED;
+ } else if (ext->required) {
+ /* Required extension missing */
+ major = GSS_S_UNAVAILABLE;
+ *minor = GSSEAP_MISSING_REQUIRED_EXT;
+ goto cleanup;
+ }
+ }
+
+ /* Check we processed all critical extensions */
+ for (i = 0; i < extensions->count; i++) {
+ if ((types[i] & EXT_FLAG_CRITICAL) &&
+ (types[i] & EXT_FLAG_VERIFIED) == 0) {
+ major = GSS_S_UNAVAILABLE;
+ *minor = GSSEAP_CRIT_EXT_UNAVAILABLE;
+ goto cleanup;
+ }
+ }
+
+ major = GSS_S_COMPLETE;
+ *minor = 0;
+
+cleanup:
+ gss_release_buffer_set(&tmpMinor, &extensions);
+ if (types != NULL)
+ GSSEAP_FREE(types);
+
+ return major;
+}
+
+OM_uint32
+gssEapVerifyExtensions(OM_uint32 *minor,
+ gss_cred_id_t cred,
+ gss_ctx_id_t ctx,
+ gss_channel_bindings_t chanBindings,
+ const gss_buffer_t buffer)
+{
+ size_t nexts;
+ const struct gss_eap_extension_provider *exts;
+
+ if (CTX_IS_INITIATOR(ctx)) {
+ exts = eapGssAcceptExtensions;
+ nexts = sizeof(eapGssAcceptExtensions) / sizeof(eapGssAcceptExtensions[0]);
+ } else {
+ exts = eapGssInitExtensions;
+ nexts = sizeof(eapGssInitExtensions) / sizeof(eapGssInitExtensions[0]);
+ }
+
+ return verifyExtensions(minor, cred, ctx, exts, nexts, chanBindings, buffer);
+}
+
+static OM_uint32
+encodeExtensions(OM_uint32 *minor,
+ gss_buffer_set_t extensions,
+ OM_uint32 *types,
+ gss_buffer_t buffer)
+{
+ OM_uint32 major, tmpMinor;
+ size_t required = 0, i;
+ unsigned char *p;
+
+ buffer->value = NULL;
+ buffer->length = 0;
+
+ if (extensions != GSS_C_NO_BUFFER_SET) {
+ for (i = 0; i < extensions->count; i++) {
+ required += 8 + extensions->elements[i].length;
+ }
+ }
+
+ /*
+ * We must always return a non-NULL token otherwise the calling state
+ * machine assumes we are finished. Hence care in case malloc(0) does
+ * return NULL.
+ */
+ buffer->value = GSSEAP_MALLOC(required ? required : 1);
+ if (buffer->value == NULL) {
+ major = GSS_S_FAILURE;
+ *minor = ENOMEM;
+ goto cleanup;
+ }
+
+ buffer->length = required;
+ p = (unsigned char *)buffer->value;
+
+ if (extensions != GSS_C_NO_BUFFER_SET) {
+ for (i = 0; i < extensions->count; i++) {
+ gss_buffer_t extension = &extensions->elements[i];
+
+ assert((types[i] & EXT_FLAG_VERIFIED) == 0); /* private flag */
+
+ /*
+ * Extensions are encoded as type-length-value, where the upper
+ * bit of the type indicates criticality.
+ */
+ store_uint32_be(types[i], &p[0]);
+ store_uint32_be(extension->length, &p[4]);
+ memcpy(&p[8], extension->value, extension->length);
+
+ p += 8 + extension->length;
+ }
+ }
+
+ assert(p == (unsigned char *)buffer->value + required);
+ assert(buffer->value != NULL);
+
+ major = GSS_S_COMPLETE;
+ *minor = 0;
+
+cleanup:
+ if (GSS_ERROR(major)) {
+ gss_release_buffer(&tmpMinor, buffer);
+ }
+
+ return major;
+}
+
+static OM_uint32
+decodeExtensions(OM_uint32 *minor,
+ const gss_buffer_t buffer,
+ gss_buffer_set_t *pExtensions,
+ OM_uint32 **pTypes)
+{
+ OM_uint32 major, tmpMinor;
+ gss_buffer_set_t extensions = GSS_C_NO_BUFFER_SET;
+ OM_uint32 *types = NULL;
+ unsigned char *p;
+ size_t remain;
+
+ *pExtensions = GSS_C_NO_BUFFER_SET;
+ *pTypes = NULL;
+
+ major = gss_create_empty_buffer_set(minor, &extensions);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ if (buffer->length == 0) {
+ major = GSS_S_COMPLETE;
+ goto cleanup;
+ }
+
+ p = (unsigned char *)buffer->value;
+ remain = buffer->length;
+
+ do {
+ OM_uint32 *ntypes;
+ gss_buffer_desc extension;
+
+ if (remain < 8) {
+ major = GSS_S_DEFECTIVE_TOKEN;
+ *minor = GSSEAP_TOK_TRUNC;
+ goto cleanup;
+ }
+
+ ntypes = GSSEAP_REALLOC(types,
+ (extensions->count + 1) * sizeof(OM_uint32));
+ if (ntypes == NULL) {
+ major = GSS_S_FAILURE;
+ *minor = ENOMEM;
+ goto cleanup;
+ }
+ types = ntypes;
+
+ types[extensions->count] = load_uint32_be(&p[0]);
+ extension.length = load_uint32_be(&p[4]);
+
+ if (remain < 8 + extension.length) {
+ major = GSS_S_DEFECTIVE_TOKEN;
+ *minor = GSSEAP_TOK_TRUNC;
+ goto cleanup;
+ }
+ extension.value = &p[8];
+
+ major = gss_add_buffer_set_member(minor, &extension, &extensions);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ p += 8 + extension.length;
+ remain -= 8 + extension.length;
+ } while (remain != 0);
+
+cleanup:
+ if (GSS_ERROR(major)) {
+ gss_release_buffer_set(&tmpMinor, &extensions);
+ if (types != NULL)
+ GSSEAP_FREE(types);
+ } else {
+ *pExtensions = extensions;
+ *pTypes = types;
+ }
+
+ return major;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Kerberos 5 helpers.
+ */
+
+#include "gssapiP_eap.h"
+
+static GSSEAP_THREAD_ONCE krbContextKeyOnce = GSSEAP_ONCE_INITIALIZER;
+static GSSEAP_THREAD_KEY krbContextKey;
+
+static void
+destroyKrbContext(void *arg)
+{
+ krb5_context context = (krb5_context)arg;
+
+ if (context != NULL)
+ krb5_free_context(context);
+}
+
+static void
+createKrbContextKey(void)
+{
+ GSSEAP_KEY_CREATE(&krbContextKey, destroyKrbContext);
+}
+
+OM_uint32
+gssEapKerberosInit(OM_uint32 *minor, krb5_context *context)
+{
+ *minor = 0;
+
+ GSSEAP_ONCE(&krbContextKeyOnce, createKrbContextKey);
+
+ *context = GSSEAP_GETSPECIFIC(krbContextKey);
+ if (*context == NULL) {
+ *minor = krb5_init_context(context);
+ if (*minor == 0) {
+ if (GSSEAP_SETSPECIFIC(krbContextKey, *context) != 0) {
+ *minor = errno;
+ krb5_free_context(*context);
+ *context = NULL;
+ }
+ }
+ }
+
+ return *minor == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE;
+}
+
+/*
+ * Derive a key K for RFC 4121 use by using the following
+ * derivation function (based on RFC 4402);
+ *
+ * KMSK = random-to-key(MSK)
+ * Tn = pseudo-random(KMSK, n || "rfc4121-gss-eap")
+ * L = output key size
+ * K = truncate(L, T1 || T2 || .. || Tn)
+ */
+OM_uint32
+gssEapDeriveRfc3961Key(OM_uint32 *minor,
+ const unsigned char *inputKey,
+ size_t inputKeyLength,
+ krb5_enctype encryptionType,
+ krb5_keyblock *pKey)
+{
+ krb5_context krbContext;
+ krb5_data data, ns, t, prfOut;
+ krb5_keyblock kd;
+ krb5_error_code code;
+ size_t randomLength, keyLength, prfLength;
+ unsigned char constant[4 + sizeof("rfc4121-gss-eap") - 1], *p;
+ ssize_t i, remain;
+
+ assert(encryptionType != ENCTYPE_NULL);
+
+ memset(pKey, 0, sizeof(*pKey));
+
+ GSSEAP_KRB_INIT(&krbContext);
+
+ KRB_KEY_INIT(&kd);
+ KRB_KEY_TYPE(&kd) = encryptionType;
+
+ t.data = NULL;
+ t.length = 0;
+
+ prfOut.data = NULL;
+ prfOut.length = 0;
+
+ code = krb5_c_keylengths(krbContext, encryptionType,
+ &randomLength, &keyLength);
+ if (code != 0)
+ goto cleanup;
+
+ data.length = MIN(inputKeyLength, randomLength);
+ data.data = (char *)inputKey;
+
+ KRB_KEY_DATA(&kd) = GSSEAP_MALLOC(keyLength);
+ if (KRB_KEY_DATA(&kd) == NULL) {
+ code = ENOMEM;
+ goto cleanup;
+ }
+ KRB_KEY_LENGTH(&kd) = keyLength;
+
+ /* Convert MSK into a Kerberos key */
+ code = krb5_c_random_to_key(krbContext, encryptionType, &data, &kd);
+ if (code != 0)
+ goto cleanup;
+
+ memset(&constant[0], 0, 4);
+ memcpy(&constant[4], "rfc4121-gss-eap", sizeof("rfc4121-gss-eap") - 1);
+
+ ns.length = sizeof(constant);
+ ns.data = (char *)constant;
+
+ /* Plug derivation constant and key into PRF */
+ code = krb5_c_prf_length(krbContext, encryptionType, &prfLength);
+ if (code != 0)
+ goto cleanup;
+
+ t.length = prfLength;
+ t.data = GSSEAP_MALLOC(t.length);
+ if (t.data == NULL) {
+ code = ENOMEM;
+ goto cleanup;
+ }
+
+ prfOut.length = randomLength;
+ prfOut.data = GSSEAP_MALLOC(prfOut.length);
+ if (prfOut.data == NULL) {
+ code = ENOMEM;
+ goto cleanup;
+ }
+
+ for (i = 0, p = (unsigned char *)prfOut.data, remain = randomLength;
+ remain > 0;
+ p += t.length, remain -= t.length, i++)
+ {
+ store_uint32_be(i, ns.data);
+
+ code = krb5_c_prf(krbContext, &kd, &ns, &t);
+ if (code != 0)
+ goto cleanup;
+
+ memcpy(p, t.data, MIN(t.length, remain));
+ }
+
+ /* Finally, convert PRF output into a new key which we will return */
+ code = krb5_c_random_to_key(krbContext, encryptionType, &prfOut, &kd);
+ if (code != 0)
+ goto cleanup;
+
+ *pKey = kd;
+ KRB_KEY_DATA(&kd) = NULL;
+
+cleanup:
+ if (KRB_KEY_DATA(&kd) != NULL) {
+ memset(KRB_KEY_DATA(&kd), 0, KRB_KEY_LENGTH(&kd));
+ GSSEAP_FREE(KRB_KEY_DATA(&kd));
+ }
+ if (t.data != NULL) {
+ memset(t.data, 0, t.length);
+ GSSEAP_FREE(t.data);
+ }
+ if (prfOut.data != NULL) {
+ memset(prfOut.data, 0, prfOut.length);
+ GSSEAP_FREE(prfOut.data);
+ }
+ *minor = code;
+ return (code == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
+}
+
+#ifdef HAVE_KRB5INT_C_MANDATORY_CKSUMTYPE
+extern krb5_error_code
+krb5int_c_mandatory_cksumtype(krb5_context, krb5_enctype, krb5_cksumtype *);
+#endif
+
+OM_uint32
+rfc3961ChecksumTypeForKey(OM_uint32 *minor,
+ krb5_keyblock *key,
+ krb5_cksumtype *cksumtype)
+{
+ krb5_context krbContext;
+#ifndef HAVE_KRB5INT_C_MANDATORY_CKSUMTYPE
+ krb5_data data;
+ krb5_checksum cksum;
+#endif
+
+ GSSEAP_KRB_INIT(&krbContext);
+
+#ifdef HAVE_KRB5INT_C_MANDATORY_CKSUMTYPE
+ *minor = krb5int_c_mandatory_cksumtype(krbContext, KRB_KEY_TYPE(key),
+ cksumtype);
+ if (*minor != 0)
+ return GSS_S_FAILURE;
+#else
+ data.length = 0;
+ data.data = NULL;
+
+ memset(&cksum, 0, sizeof(cksum));
+
+ /*
+ * This is a complete hack but it's the only way to work with
+ * MIT Kerberos pre-1.9 without using private API, as it does
+ * not support passing in zero as the checksum type.
+ */
+ *minor = krb5_c_make_checksum(krbContext, 0, key, 0, &data, &cksum);
+ if (*minor != 0)
+ return GSS_S_FAILURE;
+
+ *cksumtype = cksum.checksum_type;
+
+ krb5_free_checksum_contents(krbContext, &cksum);
+#endif /* HAVE_KRB5INT_C_MANDATORY_CKSUMTYPE */
+
+ return GSS_S_COMPLETE;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * "Lucid" security context export routine (called by MIT Kerberos mechanism).
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32
+gssEapExportLucidSecContext(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ const gss_OID desiredObject,
+ gss_buffer_set_t *data_set)
+{
+ gss_krb5_lucid_context_v1_t *lctx;
+ gss_krb5_lucid_key_t *lkey = NULL;
+ OM_uint32 major;
+ gss_buffer_desc rep;
+
+ lctx = (gss_krb5_lucid_context_v1_t *)GSSEAP_CALLOC(1, sizeof(*lctx));
+ if (lctx == NULL) {
+ major = GSS_S_FAILURE;
+ *minor = ENOMEM;
+ goto cleanup;
+ }
+
+ lctx->version = 1;
+ lctx->initiate = CTX_IS_INITIATOR(ctx);
+ lctx->endtime = ctx->expiryTime;
+ lctx->send_seq = ctx->sendSeq;
+ lctx->recv_seq = ctx->recvSeq;
+ lctx->protocol = 1;
+
+ lctx->cfx_kd.have_acceptor_subkey =
+ ((rfc4121Flags(ctx, 0) & TOK_FLAG_ACCEPTOR_SUBKEY) != 0);
+
+ lkey = lctx->cfx_kd.have_acceptor_subkey
+ ? &lctx->cfx_kd.ctx_key
+ : &lctx->cfx_kd.acceptor_subkey;
+
+ lkey->type = KRB_KEY_TYPE(&ctx->rfc3961Key);
+ lkey->data = GSSEAP_MALLOC(KRB_KEY_LENGTH(&ctx->rfc3961Key));
+ if (lkey->data == NULL) {
+ major = GSS_S_FAILURE;
+ *minor = ENOMEM;
+ goto cleanup;
+ }
+ lkey->length = KRB_KEY_LENGTH(&ctx->rfc3961Key);
+ memcpy(lkey->data, KRB_KEY_DATA(&ctx->rfc3961Key), lkey->length);
+
+ rep.value = &lctx;
+ rep.length = sizeof(void *);
+
+ major = gss_add_buffer_set_member(minor, &rep, data_set);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+cleanup:
+ if (GSS_ERROR(major)) {
+ if (lctx != NULL) {
+ if (lkey != NULL && lkey->data != NULL) {
+ memset(lkey->data, 0, lkey->length);
+ GSSEAP_FREE(lkey->data);
+ }
+ GSSEAP_FREE(lctx);
+ }
+ }
+
+ return major;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * General mechanism utility routines.
+ */
+
+#include "gssapiP_eap.h"
+
+/*
+ * 1.3.6.1.4.1.5322(padl)
+ * gssEap(22)
+ * mechanisms(1)
+ * eap-aes128-cts-hmac-sha1-96(17)
+ * eap-aes256-cts-hmac-sha1-96(18)
+ * nameTypes(2)
+ * apiExtensions(3)
+ * inquireSecContextByOid(1)
+ * inquireCredByOid(2)
+ * setSecContextOption(3)
+ * setCredOption(4)
+ * mechInvoke(5)
+ */
+
+/*
+ * Note: the enctype-less OID is used as the mechanism OID in exported
+ * names. There is no public symbol for it. This is consistent with
+ * the krb5 mechanism which, whilst known by many OIDs, always uses a
+ * canonical OID for exported names. (This OID is also returned by
+ * gss_inquire_name.)
+ */
+static gss_OID_desc gssEapMechOids[] = {
+ /* 1.3.6.1.4.1.5322.22.1 */
+ { 9, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x01" },
+ /* 1.3.6.1.4.1.5322.22.1.17 */
+ { 10, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x01\x11" },
+ /* 1.3.6.1.4.1.5322.22.1.18 */
+ { 10, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x01\x12" }
+};
+
+gss_OID GSS_EAP_MECHANISM = &gssEapMechOids[0];
+gss_OID GSS_EAP_AES128_CTS_HMAC_SHA1_96_MECHANISM = &gssEapMechOids[1];
+gss_OID GSS_EAP_AES256_CTS_HMAC_SHA1_96_MECHANISM = &gssEapMechOids[2];
+
+/*
+ * Returns TRUE is the OID is a concrete mechanism OID, that is, one
+ * with a Kerberos enctype as the last element.
+ */
+int
+gssEapIsConcreteMechanismOid(const gss_OID oid)
+{
+ return oid->length > GSS_EAP_MECHANISM->length &&
+ memcmp(oid->elements, GSS_EAP_MECHANISM->elements,
+ GSS_EAP_MECHANISM->length) == 0;
+}
+
+int
+gssEapIsMechanismOid(const gss_OID oid)
+{
+ return oid == GSS_C_NO_OID ||
+ oidEqual(oid, GSS_EAP_MECHANISM) ||
+ gssEapIsConcreteMechanismOid(oid);
+}
+
+/*
+ * Validate that all elements are concrete mechanism OIDs.
+ */
+OM_uint32
+gssEapValidateMechs(OM_uint32 *minor,
+ const gss_OID_set mechs)
+{
+ int i;
+
+ *minor = 0;
+
+ if (mechs == GSS_C_NO_OID_SET) {
+ return GSS_S_COMPLETE;
+ }
+
+ for (i = 0; i < mechs->count; i++) {
+ gss_OID oid = &mechs->elements[i];
+
+ if (!gssEapIsConcreteMechanismOid(oid)) {
+ *minor = GSSEAP_WRONG_MECH;
+ return GSS_S_BAD_MECH;
+ }
+ }
+
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gssEapOidToEnctype(OM_uint32 *minor,
+ const gss_OID oid,
+ krb5_enctype *enctype)
+{
+ OM_uint32 major;
+ int suffix;
+
+ major = decomposeOid(minor,
+ GSS_EAP_MECHANISM->elements,
+ GSS_EAP_MECHANISM->length,
+ oid,
+ &suffix);
+ if (major == GSS_S_COMPLETE)
+ *enctype = suffix;
+
+ return major;
+}
+
+OM_uint32
+gssEapEnctypeToOid(OM_uint32 *minor,
+ krb5_enctype enctype,
+ gss_OID *pOid)
+{
+ OM_uint32 major;
+ gss_OID oid;
+
+ *pOid = NULL;
+
+ oid = (gss_OID)GSSEAP_MALLOC(sizeof(*oid));
+ if (oid == NULL) {
+ *minor = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ oid->length = GSS_EAP_MECHANISM->length + 1;
+ oid->elements = GSSEAP_MALLOC(oid->length);
+ if (oid->elements == NULL) {
+ *minor = ENOMEM;
+ GSSEAP_FREE(oid);
+ return GSS_S_FAILURE;
+ }
+
+ major = composeOid(minor,
+ GSS_EAP_MECHANISM->elements,
+ GSS_EAP_MECHANISM->length,
+ enctype,
+ oid);
+ if (major == GSS_S_COMPLETE) {
+ gssEapInternalizeOid(oid, pOid);
+ *pOid = oid;
+ } else {
+ GSSEAP_FREE(oid->elements);
+ GSSEAP_FREE(oid);
+ }
+
+ return major;
+}
+
+OM_uint32
+gssEapIndicateMechs(OM_uint32 *minor,
+ gss_OID_set *mechs)
+{
+ krb5_context krbContext;
+ OM_uint32 major, tmpMinor;
+ krb5_enctype *etypes;
+ int i;
+
+ GSSEAP_KRB_INIT(&krbContext);
+
+ *minor = krb5_get_permitted_enctypes(krbContext, &etypes);
+ if (*minor != 0) {
+ return GSS_S_FAILURE;
+ }
+
+ major = gss_create_empty_oid_set(minor, mechs);
+ if (GSS_ERROR(major)) {
+ GSSEAP_FREE(etypes); /* XXX */
+ return major;
+ }
+
+ for (i = 0; etypes[i] != ENCTYPE_NULL; i++) {
+ gss_OID mechOid;
+
+ /* XXX currently we aren't equipped to encode these enctypes */
+ if (etypes[i] < 0 || etypes[i] > 127)
+ continue;
+
+ major = gssEapEnctypeToOid(minor, etypes[i], &mechOid);
+ if (GSS_ERROR(major))
+ break;
+
+ major = gss_add_oid_set_member(minor, mechOid, mechs);
+ if (GSS_ERROR(major))
+ break;
+
+ gss_release_oid(&tmpMinor, &mechOid);
+ }
+
+ GSSEAP_FREE(etypes); /* XXX */
+
+ *minor = 0;
+ return major;
+}
+
+OM_uint32
+gssEapDefaultMech(OM_uint32 *minor,
+ gss_OID *oid)
+{
+ gss_OID_set mechs;
+ OM_uint32 major, tmpMinor;
+
+ major = gssEapIndicateMechs(minor, &mechs);
+ if (GSS_ERROR(major)) {
+ return major;
+ }
+
+ if (mechs->count == 0) {
+ gss_release_oid_set(&tmpMinor, &mechs);
+ return GSS_S_BAD_MECH;
+ }
+
+ if (!gssEapInternalizeOid(&mechs->elements[0], oid)) {
+ /* don't double-free if we didn't internalize it */
+ mechs->elements[0].length = 0;
+ mechs->elements[0].elements = NULL;
+ }
+
+ gss_release_oid_set(&tmpMinor, &mechs);
+
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
+
+int
+gssEapInternalizeOid(const gss_OID oid,
+ gss_OID *const pInternalizedOid)
+{
+ int i;
+
+ *pInternalizedOid = GSS_C_NO_OID;
+
+ for (i = 0;
+ i < sizeof(gssEapMechOids) / sizeof(gssEapMechOids[0]);
+ i++) {
+ if (oidEqual(oid, &gssEapMechOids[i])) {
+ *pInternalizedOid = (const gss_OID)&gssEapMechOids[i];
+ break;
+ }
+ }
+
+ if (*pInternalizedOid == GSS_C_NO_OID) {
+ if (oidEqual(oid, GSS_EAP_NT_PRINCIPAL_NAME))
+ *pInternalizedOid = (const gss_OID)GSS_EAP_NT_PRINCIPAL_NAME;
+ }
+
+ if (*pInternalizedOid == GSS_C_NO_OID) {
+ *pInternalizedOid = oid;
+ return 0;
+ }
+
+ return 1;
+}
+
+static gss_buffer_desc gssEapSaslMechs[] = {
+ { sizeof("EAP") - 1, "EAP", }, /* not used */
+ { sizeof("EAP-AES128") - 1, "EAP-AES128" },
+ { sizeof("EAP-AES256") - 1, "EAP-AES256" },
+};
+
+gss_buffer_t
+gssEapOidToSaslName(const gss_OID oid)
+{
+ size_t i;
+
+ for (i = 1; i < sizeof(gssEapMechOids)/sizeof(gssEapMechOids[0]); i++) {
+ if (oidEqual(&gssEapMechOids[i], oid))
+ return &gssEapSaslMechs[i];
+ }
+
+ return GSS_C_NO_BUFFER;
+}
+
+gss_OID
+gssEapSaslNameToOid(const gss_buffer_t name)
+{
+ size_t i;
+
+ for (i = 1; i < sizeof(gssEapSaslMechs)/sizeof(gssEapSaslMechs[0]); i++) {
+ if (bufferEqual(&gssEapSaslMechs[i], name))
+ return &gssEapMechOids[i];
+ }
+
+ return GSS_C_NO_OID;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Portions Copyright 2009 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+/*
+ * Name utility routines.
+ */
+
+#include "gssapiP_eap.h"
+
+static gss_OID_desc gssEapNtPrincipalName = {
+ /* 1.3.6.1.4.1.5322.22.2.1 */
+ 10, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x02\x01"
+};
+
+gss_OID GSS_EAP_NT_PRINCIPAL_NAME = &gssEapNtPrincipalName;
+
+OM_uint32
+gssEapAllocName(OM_uint32 *minor, gss_name_t *pName)
+{
+ OM_uint32 tmpMinor;
+ gss_name_t name;
+
+ *pName = GSS_C_NO_NAME;
+
+ name = (gss_name_t)GSSEAP_CALLOC(1, sizeof(*name));
+ if (name == NULL) {
+ *minor = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ if (GSSEAP_MUTEX_INIT(&name->mutex) != 0) {
+ *minor = errno;
+ gssEapReleaseName(&tmpMinor, &name);
+ return GSS_S_FAILURE;
+ }
+
+ *pName = name;
+
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gssEapReleaseName(OM_uint32 *minor, gss_name_t *pName)
+{
+ gss_name_t name;
+ krb5_context krbContext = NULL;
+ OM_uint32 tmpMinor;
+
+ *minor = 0;
+
+ if (pName == NULL) {
+ return GSS_S_COMPLETE;
+ }
+
+ name = *pName;
+ if (name == GSS_C_NO_NAME) {
+ return GSS_S_COMPLETE;
+ }
+
+ GSSEAP_KRB_INIT(&krbContext);
+ krb5_free_principal(krbContext, name->krbPrincipal);
+
+ gssEapReleaseAttrContext(&tmpMinor, name);
+
+ GSSEAP_MUTEX_DESTROY(&name->mutex);
+ GSSEAP_FREE(name);
+ *pName = NULL;
+
+ return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+krbPrincipalToName(OM_uint32 *minor,
+ krb5_principal *principal,
+ gss_name_t *pName)
+{
+ OM_uint32 major;
+ gss_name_t name;
+
+ major = gssEapAllocName(minor, &name);
+ if (GSS_ERROR(major))
+ return major;
+
+ name->krbPrincipal = *principal;
+ *principal = NULL;
+
+ if (name->krbPrincipal->length > 1) {
+ name->flags |= NAME_FLAG_SERVICE;
+ } else {
+ name->flags |= NAME_FLAG_NAI;
+ }
+
+ *pName = name;
+ *minor = 0;
+
+ return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+importServiceName(OM_uint32 *minor,
+ const gss_buffer_t nameBuffer,
+ gss_name_t *pName)
+{
+ OM_uint32 major;
+ krb5_context krbContext;
+ krb5_principal krbPrinc;
+ char *service, *host;
+
+ GSSEAP_KRB_INIT(&krbContext);
+
+ major = bufferToString(minor, nameBuffer, &service);
+ if (GSS_ERROR(major))
+ return major;
+
+ host = strchr(service, '@');
+ if (host != NULL) {
+ *host = '\0';
+ host++;
+ }
+
+ /* XXX this is probably NOT what we want to be doing */
+ if (krb5_sname_to_principal(krbContext, host, service,
+ KRB5_NT_SRV_HST, &krbPrinc) != 0) {
+ GSSEAP_FREE(service);
+ *minor = GSSEAP_BAD_SERVICE_NAME;
+ return GSS_S_FAILURE;
+ }
+
+ major = krbPrincipalToName(minor, &krbPrinc, pName);
+ if (GSS_ERROR(major)) {
+ krb5_free_principal(krbContext, krbPrinc);
+ }
+
+ GSSEAP_FREE(service);
+ return major;
+}
+
+static OM_uint32
+importUserName(OM_uint32 *minor,
+ const gss_buffer_t nameBuffer,
+ gss_name_t *pName)
+{
+ OM_uint32 major;
+ krb5_context krbContext;
+ krb5_principal krbPrinc;
+ char *nameString;
+
+ GSSEAP_KRB_INIT(&krbContext);
+
+ if (nameBuffer == GSS_C_NO_BUFFER) {
+ *minor = krb5_copy_principal(krbContext,
+ krb5_anonymous_principal(), &krbPrinc);
+ if (*minor != 0)
+ return GSS_S_FAILURE;
+ } else {
+ major = bufferToString(minor, nameBuffer, &nameString);
+ if (GSS_ERROR(major))
+ return major;
+
+ *minor = krb5_parse_name(krbContext, nameString, &krbPrinc);
+ if (*minor != 0) {
+ GSSEAP_FREE(nameString);
+ return GSS_S_FAILURE;
+ }
+ }
+
+ major = krbPrincipalToName(minor, &krbPrinc, pName);
+ if (GSS_ERROR(major)) {
+ krb5_free_principal(krbContext, krbPrinc);
+ }
+
+ GSSEAP_FREE(nameString);
+ return major;
+}
+
+#define UPDATE_REMAIN(n) do { \
+ p += (n); \
+ remain -= (n); \
+ } while (0)
+
+#define CHECK_REMAIN(n) do { \
+ if (remain < (n)) { \
+ major = GSS_S_BAD_NAME; \
+ *minor = GSSEAP_TOK_TRUNC; \
+ goto cleanup; \
+ } \
+ } while (0)
+
+OM_uint32
+gssEapImportNameInternal(OM_uint32 *minor,
+ const gss_buffer_t nameBuffer,
+ gss_name_t *pName,
+ unsigned int flags)
+{
+ OM_uint32 major, tmpMinor;
+ krb5_context krbContext;
+ unsigned char *p;
+ size_t len, remain;
+ gss_buffer_desc buf;
+ enum gss_eap_token_type tokType;
+ gss_name_t name = GSS_C_NO_NAME;
+
+ GSSEAP_KRB_INIT(&krbContext);
+
+ p = (unsigned char *)nameBuffer->value;
+ remain = nameBuffer->length;
+
+ if (flags & EXPORT_NAME_FLAG_OID) {
+ if (remain < 6 + GSS_EAP_MECHANISM->length + 4)
+ return GSS_S_BAD_NAME;
+
+ if (flags & EXPORT_NAME_FLAG_COMPOSITE)
+ tokType = TOK_TYPE_EXPORT_NAME_COMPOSITE;
+ else
+ tokType = TOK_TYPE_EXPORT_NAME;
+
+ /* TOK_ID */
+ if (load_uint16_be(p) != tokType)
+ return GSS_S_BAD_NAME;
+ UPDATE_REMAIN(2);
+
+ /* MECH_OID_LEN */
+ len = load_uint16_be(p);
+ if (len != 2 + GSS_EAP_MECHANISM->length)
+ return GSS_S_BAD_NAME;
+ UPDATE_REMAIN(2);
+
+ /* MECH_OID */
+ if (p[0] != 0x06)
+ return GSS_S_BAD_NAME;
+ if (p[1] != GSS_EAP_MECHANISM->length)
+ return GSS_S_BAD_MECH;
+ if (memcmp(&p[2], GSS_EAP_MECHANISM->elements, GSS_EAP_MECHANISM->length))
+ return GSS_S_BAD_MECH;
+ UPDATE_REMAIN(2 + GSS_EAP_MECHANISM->length);
+ }
+
+ /* NAME_LEN */
+ len = load_uint32_be(p);
+ UPDATE_REMAIN(4);
+
+ /* NAME */
+ CHECK_REMAIN(len);
+ buf.length = len;
+ buf.value = p;
+ UPDATE_REMAIN(len);
+
+ major = importUserName(minor, &buf, &name);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ if (flags & EXPORT_NAME_FLAG_COMPOSITE) {
+ gss_buffer_desc buf;
+
+ buf.length = remain;
+ buf.value = p;
+
+ major = gssEapImportAttrContext(minor, &buf, name);
+ if (GSS_ERROR(major))
+ goto cleanup;
+ }
+
+ major = GSS_S_COMPLETE;
+ *minor = 0;
+
+cleanup:
+ if (GSS_ERROR(major))
+ gssEapReleaseName(&tmpMinor, &name);
+ else
+ *pName = name;
+
+ return major;
+}
+
+static OM_uint32
+importExportName(OM_uint32 *minor,
+ const gss_buffer_t nameBuffer,
+ gss_name_t *name)
+{
+ return gssEapImportNameInternal(minor, nameBuffer, name,
+ EXPORT_NAME_FLAG_OID);
+}
+
+#ifdef HAVE_GSS_C_NT_COMPOSITE_EXPORT
+static OM_uint32
+importCompositeExportName(OM_uint32 *minor,
+ const gss_buffer_t nameBuffer,
+ gss_name_t *name)
+{
+ return gssEapImportNameInternal(minor, nameBuffer, name,
+ EXPORT_NAME_FLAG_OID |
+ EXPORT_NAME_FLAG_COMPOSITE);
+}
+#endif
+
+struct gss_eap_name_import_provider {
+ gss_OID oid;
+ OM_uint32 (*import)(OM_uint32 *, const gss_buffer_t, gss_name_t *);
+};
+
+OM_uint32
+gssEapImportName(OM_uint32 *minor,
+ const gss_buffer_t nameBuffer,
+ gss_OID nameType,
+ gss_name_t *name)
+{
+ struct gss_eap_name_import_provider nameTypes[] = {
+ { GSS_C_NT_USER_NAME, importUserName },
+ { GSS_EAP_NT_PRINCIPAL_NAME, importUserName },
+ { GSS_C_NT_HOSTBASED_SERVICE, importServiceName },
+ { GSS_C_NT_HOSTBASED_SERVICE_X, importServiceName },
+ { GSS_C_NT_EXPORT_NAME, importExportName },
+#ifdef HAVE_GSS_C_NT_COMPOSITE_EXPORT
+ { GSS_C_NT_COMPOSITE_EXPORT, importCompositeExportName },
+#endif
+ };
+ size_t i;
+
+ *name = GSS_C_NO_NAME;
+
+ if (nameType == GSS_C_NO_OID)
+ nameType = nameTypes[0].oid;
+
+ for (i = 0; i < sizeof(nameTypes) / sizeof(nameTypes[0]); i++) {
+ if (oidEqual(nameTypes[i].oid, nameType))
+ return nameTypes[i].import(minor, nameBuffer, name);
+ }
+
+ return GSS_S_BAD_NAMETYPE;
+}
+
+OM_uint32
+gssEapExportName(OM_uint32 *minor,
+ const gss_name_t name,
+ gss_buffer_t exportedName)
+{
+ return gssEapExportNameInternal(minor, name, exportedName,
+ EXPORT_NAME_FLAG_OID);
+}
+
+OM_uint32
+gssEapExportNameInternal(OM_uint32 *minor,
+ const gss_name_t name,
+ gss_buffer_t exportedName,
+ unsigned int flags)
+{
+ OM_uint32 major = GSS_S_FAILURE, tmpMinor;
+ krb5_context krbContext;
+ char *krbName = NULL;
+ size_t krbNameLen, exportedNameLen;
+ unsigned char *p;
+ gss_buffer_desc attrs = GSS_C_EMPTY_BUFFER;
+
+ exportedName->length = 0;
+ exportedName->value = NULL;
+
+ GSSEAP_KRB_INIT(&krbContext);
+
+ *minor = krb5_unparse_name(krbContext, name->krbPrincipal, &krbName);
+ if (*minor != 0) {
+ major = GSS_S_FAILURE;
+ goto cleanup;
+ }
+ krbNameLen = strlen(krbName);
+
+ exportedNameLen = 0;
+ if (flags & EXPORT_NAME_FLAG_OID) {
+ exportedNameLen += 6 + GSS_EAP_MECHANISM->length;
+ }
+ exportedNameLen += 4 + krbNameLen;
+ if (flags & EXPORT_NAME_FLAG_COMPOSITE) {
+ major = gssEapExportAttrContext(minor, name, &attrs);
+ if (GSS_ERROR(major))
+ goto cleanup;
+ exportedNameLen += attrs.length;
+ }
+
+ exportedName->value = GSSEAP_MALLOC(exportedNameLen);
+ if (exportedName->value == NULL) {
+ major = GSS_S_FAILURE;
+ *minor = ENOMEM;
+ goto cleanup;
+ }
+ exportedName->length = exportedNameLen;
+
+ p = (unsigned char *)exportedName->value;
+
+ if (flags & EXPORT_NAME_FLAG_OID) {
+ /* TOK | MECH_OID_LEN */
+ store_uint16_be((flags & EXPORT_NAME_FLAG_COMPOSITE)
+ ? TOK_TYPE_EXPORT_NAME_COMPOSITE
+ : TOK_TYPE_EXPORT_NAME,
+ p);
+ p += 2;
+ store_uint16_be(GSS_EAP_MECHANISM->length + 2, p);
+ p += 2;
+
+ /* MECH_OID */
+ *p++ = 0x06;
+ *p++ = GSS_EAP_MECHANISM->length & 0xff;
+ memcpy(p, GSS_EAP_MECHANISM->elements, GSS_EAP_MECHANISM->length);
+ p += GSS_EAP_MECHANISM->length;
+ }
+
+ /* NAME_LEN */
+ store_uint32_be(krbNameLen, p);
+ p += 4;
+
+ /* NAME */
+ memcpy(p, krbName, krbNameLen);
+ p += krbNameLen;
+
+ if (flags & EXPORT_NAME_FLAG_COMPOSITE) {
+ memcpy(p, attrs.value, attrs.length);
+ p += attrs.length;
+ }
+
+ assert(p == (unsigned char *)exportedName->value + exportedNameLen);
+
+ major = GSS_S_COMPLETE;
+ *minor = 0;
+
+cleanup:
+ gss_release_buffer(&tmpMinor, &attrs);
+ if (GSS_ERROR(major))
+ gss_release_buffer(&tmpMinor, exportedName);
+ krb5_free_unparsed_name(krbContext, krbName);
+
+ return major;
+}
+
+OM_uint32
+gssEapDuplicateName(OM_uint32 *minor,
+ const gss_name_t input_name,
+ gss_name_t *dest_name)
+{
+ OM_uint32 major, tmpMinor;
+ krb5_context krbContext;
+ gss_name_t name;
+
+ if (input_name == GSS_C_NO_NAME) {
+ *minor = EINVAL;
+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
+ }
+
+ GSSEAP_KRB_INIT(&krbContext);
+
+ major = gssEapAllocName(minor, &name);
+ if (GSS_ERROR(major)) {
+ return major;
+ }
+
+ name->flags = input_name->flags;
+
+ *minor = krb5_copy_principal(krbContext, input_name->krbPrincipal,
+ &name->krbPrincipal);
+ if (*minor != 0) {
+ major = GSS_S_FAILURE;
+ goto cleanup;
+ }
+
+ if (input_name->attrCtx != NULL) {
+ major = gssEapDuplicateAttrContext(minor, input_name, name);
+ if (GSS_ERROR(major))
+ goto cleanup;
+ }
+
+ *dest_name = name;
+
+cleanup:
+ if (GSS_ERROR(major)) {
+ gssEapReleaseName(&tmpMinor, &name);
+ }
+
+ return major;
+}
+
+OM_uint32
+gssEapDisplayName(OM_uint32 *minor,
+ gss_name_t name,
+ gss_buffer_t output_name_buffer,
+ gss_OID *output_name_type)
+{
+ OM_uint32 major;
+ krb5_context krbContext;
+ char *krbName;
+
+ GSSEAP_KRB_INIT(&krbContext);
+
+ output_name_buffer->length = 0;
+ output_name_buffer->value = NULL;
+
+ if (name == GSS_C_NO_NAME) {
+ *minor = EINVAL;
+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
+ }
+
+ *minor = krb5_unparse_name(krbContext, name->krbPrincipal, &krbName);
+ if (*minor != 0) {
+ return GSS_S_FAILURE;
+ }
+
+ major = makeStringBuffer(minor, krbName, output_name_buffer);
+ if (GSS_ERROR(major)) {
+ krb5_free_unparsed_name(krbContext, krbName);
+ return major;
+ }
+
+ krb5_free_unparsed_name(krbContext, krbName);
+
+ if (output_name_type != NULL)
+ *output_name_type = GSS_EAP_NT_PRINCIPAL_NAME;
+
+ return GSS_S_COMPLETE;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Copyright 1995-2010 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+/*
+ * OID utility routines.
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32
+duplicateOid(OM_uint32 *minor,
+ const gss_OID_desc * const oid,
+ gss_OID *newOid)
+{
+ gss_OID p;
+
+ *newOid = GSS_C_NO_OID;
+
+ p = (gss_OID)GSSEAP_MALLOC(sizeof(*p));
+ if (p == NULL) {
+ *minor = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ p->length = oid->length;
+ p->elements = GSSEAP_MALLOC(p->length);
+ if (p->elements == NULL) {
+ GSSEAP_FREE(p);
+ *minor = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ memcpy(p->elements, oid->elements, p->length);
+ *newOid = p;
+
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
+
+/* Compose an OID of a prefix and an integer suffix */
+OM_uint32
+composeOid(OM_uint32 *minor,
+ const char *prefix,
+ size_t prefix_len,
+ int suffix,
+ gss_OID_desc *oid)
+{
+ int osuffix, i;
+ size_t nbytes;
+ unsigned char *op;
+
+ if (oid == GSS_C_NO_OID) {
+ *minor = EINVAL;
+ return GSS_S_FAILURE;
+ }
+ if (oid->length < prefix_len) {
+ *minor = GSSEAP_WRONG_SIZE;
+ return GSS_S_FAILURE;
+ }
+
+ memcpy(oid->elements, prefix, prefix_len);
+
+ nbytes = 0;
+ osuffix = suffix;
+ while (suffix) {
+ nbytes++;
+ suffix >>= 7;
+ }
+ suffix = osuffix;
+
+ if (oid->length < prefix_len + nbytes) {
+ *minor = GSSEAP_WRONG_SIZE;
+ return GSS_S_FAILURE;
+ }
+
+ op = (unsigned char *) oid->elements + prefix_len + nbytes;
+ i = -1;
+ while (suffix) {
+ op[i] = (unsigned char)suffix & 0x7f;
+ if (i != -1)
+ op[i] |= 0x80;
+ i--;
+ suffix >>= 7;
+ }
+
+ oid->length = prefix_len + nbytes;
+
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+decomposeOid(OM_uint32 *minor,
+ const char *prefix,
+ size_t prefix_len,
+ gss_OID_desc *oid,
+ int *suffix)
+{
+ size_t i, slen;
+ unsigned char *op;
+
+ if (oid->length < prefix_len ||
+ memcmp(oid->elements, prefix, prefix_len) != 0) {
+ return GSS_S_BAD_MECH;
+ }
+
+ op = (unsigned char *) oid->elements + prefix_len;
+
+ *suffix = 0;
+
+ slen = oid->length - prefix_len;
+
+ for (i = 0; i < slen; i++) {
+ *suffix = (*suffix << 7) | (op[i] & 0x7f);
+ if (i + 1 != slen && (op[i] & 0x80) == 0) {
+ *minor = GSSEAP_WRONG_SIZE;
+ return GSS_S_FAILURE;
+ }
+ }
+
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+duplicateOidSet(OM_uint32 *minor,
+ const gss_OID_set src,
+ gss_OID_set *dst)
+{
+ OM_uint32 major, tmpMinor;
+ int i;
+
+ if (src == GSS_C_NO_OID_SET) {
+ *dst = GSS_C_NO_OID_SET;
+ return GSS_S_COMPLETE;
+ }
+
+ major = gss_create_empty_oid_set(minor, dst);
+ if (GSS_ERROR(major))
+ return major;
+
+ for (i = 0; i < src->count; i++) {
+ gss_OID oid = &src->elements[i];
+
+ major = gss_add_oid_set_member(minor, oid, dst);
+ if (GSS_ERROR(major))
+ break;
+ }
+
+ if (GSS_ERROR(major))
+ gss_release_oid_set(&tmpMinor, dst);
+
+ return major;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Functions to check sequence numbers for replay and sequencing
+ */
+
+#include "gssapiP_eap.h"
+
+#define QUEUE_LENGTH 20
+
+typedef struct _queue {
+ int do_replay;
+ int do_sequence;
+ int start;
+ int length;
+ uint64_t firstnum;
+ /* Stored as deltas from firstnum. This way, the high bit won't
+ overflow unless we've actually gone through 2**n messages, or
+ gotten something *way* out of sequence. */
+ uint64_t elem[QUEUE_LENGTH];
+ /* All ones for 64-bit sequence numbers; 32 ones for 32-bit
+ sequence numbers. */
+ uint64_t mask;
+} queue;
+
+/* rep invariant:
+ * - the queue is a circular queue. The first element (q->elem[q->start])
+ * is the oldest. The last element is the newest.
+ */
+
+#define QSIZE(q) (sizeof((q)->elem)/sizeof((q)->elem[0]))
+#define QELEM(q,i) ((q)->elem[(i)%QSIZE(q)])
+
+static void
+queue_insert(queue *q, int after, uint64_t seqnum)
+{
+ /* insert. this is not the fastest way, but it's easy, and it's
+ optimized for insert at end, which is the common case */
+ int i;
+
+ /* common case: at end, after == q->start+q->length-1 */
+
+ /* move all the elements (after,last] up one slot */
+
+ for (i = q->start + q->length - 1; i > after; i--)
+ QELEM(q,i+1) = QELEM(q,i);
+
+ /* fill in slot after+1 */
+
+ QELEM(q,after+1) = seqnum;
+
+ /* Either increase the length by one, or move the starting point up
+ one (deleting the first element, which got bashed above), as
+ appropriate. */
+
+ if (q->length == QSIZE(q)) {
+ q->start++;
+ if (q->start == QSIZE(q))
+ q->start = 0;
+ } else {
+ q->length++;
+ }
+}
+
+OM_uint32
+sequenceInit(OM_uint32 *minor,
+ void **vqueue,
+ uint64_t seqnum,
+ int do_replay,
+ int do_sequence,
+ int wide_nums)
+{
+ queue *q;
+
+ q = (queue *)GSSEAP_CALLOC(1, sizeof(queue));
+ if (q == NULL) {
+ *minor = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ q->do_replay = do_replay;
+ q->do_sequence = do_sequence;
+ q->mask = wide_nums ? ~(uint64_t)0 : 0xffffffffUL;
+
+ q->start = 0;
+ q->length = 1;
+ q->firstnum = seqnum;
+ q->elem[q->start] = ((uint64_t)0 - 1) & q->mask;
+
+ *vqueue = (void *)q;
+
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+sequenceCheck(OM_uint32 *minor,
+ void **vqueue,
+ uint64_t seqnum)
+{
+ queue *q;
+ int i;
+ uint64_t expected;
+
+ q = (queue *) (*vqueue);
+
+ if (!q->do_replay && !q->do_sequence)
+ return GSS_S_COMPLETE;
+
+ /* All checks are done relative to the initial sequence number, to
+ avoid (or at least put off) the pain of wrapping. */
+ seqnum -= q->firstnum;
+ /* If we're only doing 32-bit values, adjust for that again.
+
+ Note that this will probably be the wrong thing to if we get
+ 2**32 messages sent with 32-bit sequence numbers. */
+ seqnum &= q->mask;
+
+ /* rule 1: expected sequence number */
+
+ expected = (QELEM(q,q->start+q->length-1)+1) & q->mask;
+ if (seqnum == expected) {
+ queue_insert(q, q->start+q->length-1, seqnum);
+ return GSS_S_COMPLETE;
+ }
+
+ /* rule 2: > expected sequence number */
+
+ if ((seqnum > expected)) {
+ queue_insert(q, q->start+q->length-1, seqnum);
+ if (q->do_replay && !q->do_sequence)
+ return GSS_S_COMPLETE;
+ else
+ return GSS_S_GAP_TOKEN;
+ }
+
+ /* rule 3: seqnum < seqnum(first) */
+
+ if ((seqnum < QELEM(q,q->start)) &&
+ /* Is top bit of whatever width we're using set?
+
+ We used to check for greater than or equal to firstnum, but
+ (1) we've since switched to compute values relative to
+ firstnum, so the lowest we can have is 0, and (2) the effect
+ of the original scheme was highly dependent on whether
+ firstnum was close to either side of 0. (Consider
+ firstnum==0xFFFFFFFE and we miss three packets; the next
+ packet is *new* but would look old.)
+
+ This check should give us 2**31 or 2**63 messages "new", and
+ just as many "old". That's not quite right either. */
+ (seqnum & (1 + (q->mask >> 1)))
+ ) {
+ if (q->do_replay && !q->do_sequence)
+ return GSS_S_OLD_TOKEN;
+ else
+ return GSS_S_UNSEQ_TOKEN;
+ }
+
+ /* rule 4+5: seqnum in [seqnum(first),seqnum(last)] */
+
+ else {
+ if (seqnum == QELEM(q,q->start+q->length - 1))
+ return GSS_S_DUPLICATE_TOKEN;
+
+ for (i = q->start; i < q->start + q->length - 1; i++) {
+ if (seqnum == QELEM(q,i))
+ return GSS_S_DUPLICATE_TOKEN;
+ if ((seqnum > QELEM(q,i)) && (seqnum < QELEM(q,i+1))) {
+ queue_insert(q, i, seqnum);
+ if (q->do_replay && !q->do_sequence)
+ return GSS_S_COMPLETE;
+ else
+ return GSS_S_UNSEQ_TOKEN;
+ }
+ }
+ }
+
+ /* this should never happen */
+ return GSS_S_FAILURE;
+}
+
+OM_uint32
+sequenceFree(OM_uint32 *minor, void **vqueue)
+{
+ queue *q;
+
+ q = (queue *) (*vqueue);
+
+ GSSEAP_FREE(q);
+
+ *vqueue = NULL;
+
+ return GSS_S_COMPLETE;
+}
+
+/*
+ * These support functions are for the serialization routines
+ */
+size_t
+sequenceSize(void *vqueue)
+{
+ return sizeof(queue);
+}
+
+OM_uint32
+sequenceExternalize(OM_uint32 *minor,
+ void *vqueue,
+ unsigned char **buf,
+ size_t *lenremain)
+{
+ if (*lenremain < sizeof(queue)) {
+ *minor = GSSEAP_WRONG_SIZE;
+ return GSS_S_FAILURE;
+ }
+ memcpy(*buf, vqueue, sizeof(queue));
+ *buf += sizeof(queue);
+ *lenremain -= sizeof(queue);
+
+ return 0;
+}
+
+OM_uint32
+sequenceInternalize(OM_uint32 *minor,
+ void **vqueue,
+ unsigned char **buf,
+ size_t *lenremain)
+{
+ void *q;
+
+ if (*lenremain < sizeof(queue)) {
+ *minor = GSSEAP_TOK_TRUNC;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ q = GSSEAP_MALLOC(sizeof(queue));
+ if (q == NULL) {
+ *minor = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ memcpy(q, *buf, sizeof(queue));
+ *buf += sizeof(queue);
+ *lenremain -= sizeof(queue);
+ *vqueue = q;
+
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * RADIUS attribute provider implementation.
+ */
+
+#include "gssapiP_eap.h"
+
+/* stuff that should be provided by libradsec/libfreeradius-radius */
+#define VENDORATTR(vendor, attr) (((vendor) << 16) | (attr))
+
+#ifndef ATTRID
+#define ATTRID(attr) ((attr) & 0xFFFF)
+#endif
+
+static gss_buffer_desc radiusUrnPrefix = {
+ sizeof("urn:x-radius:") - 1,
+ (void *)"urn:x-radius:"
+};
+
+static VALUE_PAIR *copyAvps(const VALUE_PAIR *src);
+
+gss_eap_radius_attr_provider::gss_eap_radius_attr_provider(void)
+{
+ m_vps = NULL;
+ m_authenticated = false;
+}
+
+gss_eap_radius_attr_provider::~gss_eap_radius_attr_provider(void)
+{
+ if (m_vps != NULL)
+ pairfree(&m_vps);
+}
+
+bool
+gss_eap_radius_attr_provider::initFromExistingContext(const gss_eap_attr_ctx *manager,
+ const gss_eap_attr_provider *ctx)
+{
+ const gss_eap_radius_attr_provider *radius;
+
+ if (!gss_eap_attr_provider::initFromExistingContext(manager, ctx))
+ return false;
+
+ radius = static_cast<const gss_eap_radius_attr_provider *>(ctx);
+
+ if (radius->m_vps != NULL)
+ m_vps = copyAvps(const_cast<VALUE_PAIR *>(radius->getAvps()));
+
+ m_authenticated = radius->m_authenticated;
+
+ return true;
+}
+
+bool
+gss_eap_radius_attr_provider::initFromGssContext(const gss_eap_attr_ctx *manager,
+ const gss_cred_id_t gssCred,
+ const gss_ctx_id_t gssCtx)
+{
+ if (!gss_eap_attr_provider::initFromGssContext(manager, gssCred, gssCtx))
+ return false;
+
+ if (gssCtx != GSS_C_NO_CONTEXT) {
+ if (gssCtx->acceptorCtx.vps != NULL) {
+ m_vps = copyAvps(gssCtx->acceptorCtx.vps);
+ if (m_vps == NULL)
+ return false;
+
+ /* We assume libradsec validated this for us */
+ assert(pairfind(m_vps, PW_MESSAGE_AUTHENTICATOR) != NULL);
+ m_authenticated = true;
+ }
+ }
+
+ return true;
+}
+
+static bool
+alreadyAddedAttributeP(std::vector <std::string> &attrs, VALUE_PAIR *vp)
+{
+ for (std::vector<std::string>::const_iterator a = attrs.begin();
+ a != attrs.end();
+ ++a) {
+ if (strcmp(vp->name, (*a).c_str()) == 0)
+ return true;
+ }
+
+ return false;
+}
+
+static bool
+isSecretAttributeP(uint16_t attrid, uint16_t vendor)
+{
+ bool ret = false;
+
+ switch (vendor) {
+ case VENDORPEC_MS:
+ switch (attrid) {
+ case PW_MS_MPPE_SEND_KEY:
+ case PW_MS_MPPE_RECV_KEY:
+ ret = true;
+ break;
+ default:
+ break;
+ }
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+static bool
+isSecretAttributeP(uint32_t attribute)
+{
+ return isSecretAttributeP(ATTRID(attribute), VENDOR(attribute));
+}
+
+static bool
+isInternalAttributeP(uint16_t attrid, uint16_t vendor)
+{
+ bool ret = false;
+
+ /* should have been filtered */
+ assert(!isSecretAttributeP(attrid, vendor));
+
+ switch (vendor) {
+ case VENDORPEC_UKERNA:
+ ret = true;
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+static bool
+isInternalAttributeP(uint32_t attribute)
+{
+ return isInternalAttributeP(ATTRID(attribute), VENDOR(attribute));
+}
+
+/*
+ * Copy AVP list, same as paircopy except it filters out attributes
+ * containing keys.
+ */
+static VALUE_PAIR *
+copyAvps(const VALUE_PAIR *src)
+{
+ const VALUE_PAIR *vp;
+ VALUE_PAIR *dst = NULL, **pDst = &dst;
+
+ for (vp = src; vp != NULL; vp = vp->next) {
+ VALUE_PAIR *vpcopy;
+
+ if (isSecretAttributeP(vp->attribute))
+ continue;
+
+ vpcopy = paircopyvp(vp);
+ if (vpcopy == NULL) {
+ pairfree(&dst);
+ throw new std::bad_alloc;
+ return NULL;
+ }
+ *pDst = vpcopy;
+ pDst = &vpcopy->next;
+ }
+
+ return dst;
+}
+
+bool
+gss_eap_radius_attr_provider::getAttributeTypes(gss_eap_attr_enumeration_cb addAttribute,
+ void *data) const
+{
+ VALUE_PAIR *vp;
+ std::vector <std::string> seen;
+
+ for (vp = m_vps; vp != NULL; vp = vp->next) {
+ gss_buffer_desc attribute;
+ char attrid[64];
+
+ /* Don't advertise attributes that are internal to the GSS-EAP mechanism */
+ if (isInternalAttributeP(vp->attribute))
+ continue;
+
+ if (alreadyAddedAttributeP(seen, vp))
+ continue;
+
+ snprintf(attrid, sizeof(attrid), "%s%d",
+ (char *)radiusUrnPrefix.value, vp->attribute);
+
+ attribute.value = attrid;
+ attribute.length = strlen(attrid);
+
+ if (!addAttribute(this, &attribute, data))
+ return false;
+
+ seen.push_back(std::string(vp->name));
+ }
+
+ return true;
+}
+
+uint32_t
+getAttributeId(const gss_buffer_t attr)
+{
+ OM_uint32 tmpMinor;
+ gss_buffer_desc strAttr = GSS_C_EMPTY_BUFFER;
+ DICT_ATTR *da;
+ char *s;
+ uint32_t attrid = 0;
+
+ if (attr->length < radiusUrnPrefix.length ||
+ memcmp(attr->value, radiusUrnPrefix.value, radiusUrnPrefix.length) != 0)
+ return 0;
+
+ /* need to duplicate because attr may not be NUL terminated */
+ duplicateBuffer(*attr, &strAttr);
+ s = (char *)strAttr.value + radiusUrnPrefix.length;
+
+ if (isdigit(*s)) {
+ attrid = strtoul(s, NULL, 10);
+ } else {
+ da = dict_attrbyname(s);
+ if (da != NULL)
+ attrid = da->attr;
+ }
+
+ gss_release_buffer(&tmpMinor, &strAttr);
+
+ return attrid;
+}
+
+bool
+gss_eap_radius_attr_provider::setAttribute(int complete,
+ uint32_t attrid,
+ const gss_buffer_t value)
+{
+ OM_uint32 major = GSS_S_UNAVAILABLE, minor;
+
+ if (!isSecretAttributeP(attrid) &&
+ !isInternalAttributeP(attrid)) {
+ deleteAttribute(attrid);
+
+ major = gssEapRadiusAddAvp(&minor, &m_vps,
+ ATTRID(attrid), VENDOR(attrid),
+ value);
+ }
+
+ return !GSS_ERROR(major);
+}
+
+bool
+gss_eap_radius_attr_provider::setAttribute(int complete,
+ const gss_buffer_t attr,
+ const gss_buffer_t value)
+{
+ uint32_t attrid = getAttributeId(attr);
+
+ if (!attrid)
+ return false;
+
+ return setAttribute(complete, attrid, value);
+}
+
+bool
+gss_eap_radius_attr_provider::deleteAttribute(uint32_t attrid)
+{
+ if (isSecretAttributeP(attrid) || isInternalAttributeP(attrid) ||
+ pairfind(m_vps, attrid) == NULL)
+ return false;
+
+ pairdelete(&m_vps, attrid);
+
+ return true;
+}
+
+bool
+gss_eap_radius_attr_provider::deleteAttribute(const gss_buffer_t attr)
+{
+ uint32_t attrid = getAttributeId(attr);
+
+ if (!attrid)
+ return false;
+
+ return deleteAttribute(attrid);
+}
+
+bool
+gss_eap_radius_attr_provider::getAttribute(const gss_buffer_t attr,
+ int *authenticated,
+ int *complete,
+ gss_buffer_t value,
+ gss_buffer_t display_value,
+ int *more) const
+{
+ uint32_t attrid;
+
+ attrid = getAttributeId(attr);
+ if (!attrid)
+ return false;
+
+ return getAttribute(attrid, authenticated, complete,
+ value, display_value, more);
+}
+
+bool
+gss_eap_radius_attr_provider::getAttribute(uint32_t attrid,
+ int *authenticated,
+ int *complete,
+ gss_buffer_t value,
+ gss_buffer_t display_value,
+ int *more) const
+{
+ VALUE_PAIR *vp;
+ int i = *more, count = 0;
+
+ *more = 0;
+
+ if (i == -1)
+ i = 0;
+
+ for (vp = pairfind(m_vps, attrid);
+ vp != NULL;
+ vp = pairfind(vp->next, attrid)) {
+ if (count++ == i) {
+ if (pairfind(vp->next, attrid) != NULL)
+ *more = count;
+ break;
+ }
+ }
+
+ if (vp == NULL && *more == 0)
+ return false;
+
+ if (value != GSS_C_NO_BUFFER) {
+ gss_buffer_desc valueBuf;
+
+ valueBuf.value = (void *)vp->vp_octets;
+ valueBuf.length = vp->length;
+
+ duplicateBuffer(valueBuf, value);
+ }
+
+ if (display_value != GSS_C_NO_BUFFER) {
+ char displayString[MAX_STRING_LEN];
+ gss_buffer_desc displayBuf;
+
+ displayBuf.length = vp_prints_value(displayString,
+ sizeof(displayString), vp, 0);
+ displayBuf.value = (void *)displayString;
+
+ duplicateBuffer(displayBuf, display_value);
+ }
+
+ if (authenticated != NULL)
+ *authenticated = m_authenticated;
+ if (complete != NULL)
+ *complete = true;
+
+ return true;
+}
+
+bool
+gss_eap_radius_attr_provider::getFragmentedAttribute(uint16_t attribute,
+ uint16_t vendor,
+ int *authenticated,
+ int *complete,
+ gss_buffer_t value) const
+{
+ OM_uint32 major, minor;
+
+ major = gssEapRadiusGetAvp(&minor, m_vps, attribute, vendor, value, TRUE);
+
+ if (authenticated != NULL)
+ *authenticated = m_authenticated;
+ if (complete != NULL)
+ *complete = true;
+
+ return !GSS_ERROR(major);
+}
+
+bool
+gss_eap_radius_attr_provider::getAttribute(uint16_t attribute,
+ uint16_t vendor,
+ int *authenticated,
+ int *complete,
+ gss_buffer_t value,
+ gss_buffer_t display_value,
+ int *more) const
+{
+
+ return getAttribute(VENDORATTR(attribute, vendor),
+ authenticated, complete,
+ value, display_value, more);
+}
+
+gss_any_t
+gss_eap_radius_attr_provider::mapToAny(int authenticated,
+ gss_buffer_t type_id) const
+{
+ if (authenticated && !m_authenticated)
+ return (gss_any_t)NULL;
+
+ return (gss_any_t)copyAvps(m_vps);
+}
+
+void
+gss_eap_radius_attr_provider::releaseAnyNameMapping(gss_buffer_t type_id,
+ gss_any_t input) const
+{
+ pairfree((VALUE_PAIR **)&input);
+}
+
+bool
+gss_eap_radius_attr_provider::init(void)
+{
+ gss_eap_attr_ctx::registerProvider(ATTR_TYPE_RADIUS,
+ "urn:ietf:params:gss-eap:radius-avp",
+ gss_eap_radius_attr_provider::createAttrContext);
+ return true;
+}
+
+void
+gss_eap_radius_attr_provider::finalize(void)
+{
+ gss_eap_attr_ctx::unregisterProvider(ATTR_TYPE_RADIUS);
+}
+
+gss_eap_attr_provider *
+gss_eap_radius_attr_provider::createAttrContext(void)
+{
+ return new gss_eap_radius_attr_provider;
+}
+
+OM_uint32
+gssEapRadiusAddAvp(OM_uint32 *minor,
+ VALUE_PAIR **vps,
+ uint16_t attribute,
+ uint16_t vendor,
+ const gss_buffer_t buffer)
+{
+ uint32_t attrid = VENDORATTR(vendor, attribute);
+ unsigned char *p = (unsigned char *)buffer->value;
+ size_t remain = buffer->length;
+
+ do {
+ VALUE_PAIR *vp;
+ size_t n = remain;
+
+ if (n > MAX_STRING_LEN)
+ n = MAX_STRING_LEN;
+
+ vp = paircreate(attrid, PW_TYPE_OCTETS);
+ if (vp == NULL) {
+ *minor = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ memcpy(vp->vp_octets, p, n);
+ vp->length = n;
+
+ pairadd(vps, vp);
+
+ p += n;
+ remain -= n;
+ } while (remain != 0);
+
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gssEapRadiusGetRawAvp(OM_uint32 *minor,
+ VALUE_PAIR *vps,
+ uint16_t attribute,
+ uint16_t vendor,
+ VALUE_PAIR **vp)
+{
+ uint32_t attr = VENDORATTR(vendor, attribute);
+
+ *vp = pairfind(vps, attr);
+ if (*vp == NULL) {
+ *minor = GSSEAP_NO_SUCH_ATTR;
+ return GSS_S_UNAVAILABLE;
+ }
+
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gssEapRadiusGetAvp(OM_uint32 *minor,
+ VALUE_PAIR *vps,
+ uint16_t attribute,
+ uint16_t vendor,
+ gss_buffer_t buffer,
+ int concat)
+{
+ VALUE_PAIR *vp;
+ unsigned char *p;
+ uint32_t attr = VENDORATTR(vendor, attribute);
+
+ buffer->length = 0;
+ buffer->value = NULL;
+
+ vp = pairfind(vps, attr);
+ if (vp == NULL) {
+ *minor = GSSEAP_NO_SUCH_ATTR;
+ return GSS_S_UNAVAILABLE;
+ }
+
+ do {
+ buffer->length += vp->length;
+ } while (concat && (vp = pairfind(vp->next, attr)) != NULL);
+
+ buffer->value = GSSEAP_MALLOC(buffer->length);
+ if (buffer->value == NULL) {
+ *minor = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ p = (unsigned char *)buffer->value;
+
+ for (vp = pairfind(vps, attr);
+ concat && vp != NULL;
+ vp = pairfind(vp->next, attr)) {
+ memcpy(p, vp->vp_octets, vp->length);
+ p += vp->length;
+ }
+
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gssEapRadiusFreeAvps(OM_uint32 *minor,
+ VALUE_PAIR **vps)
+{
+ pairfree(vps);
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gssEapRadiusAttrProviderInit(OM_uint32 *minor)
+{
+ if (!gss_eap_radius_attr_provider::init()) {
+ *minor = GSSEAP_RADSEC_INIT_FAILURE;
+ return GSS_S_FAILURE;
+ }
+
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gssEapRadiusAttrProviderFinalize(OM_uint32 *minor)
+{
+ gss_eap_radius_attr_provider::finalize();
+ return GSS_S_COMPLETE;
+}
+
+/*
+ * Encoding is:
+ * 4 octet NBO attribute ID | 4 octet attribute length | attribute data
+ */
+static size_t
+avpSize(const VALUE_PAIR *vp)
+{
+ size_t size = 4 + 1;
+
+ if (vp != NULL)
+ size += vp->length;
+
+ return size;
+}
+
+static bool
+avpExport(const VALUE_PAIR *vp,
+ unsigned char **pBuffer,
+ size_t *pRemain)
+{
+ unsigned char *p = *pBuffer;
+ size_t remain = *pRemain;
+
+ assert(remain >= avpSize(vp));
+
+ store_uint32_be(vp->attribute, p);
+
+ switch (vp->type) {
+ case PW_TYPE_INTEGER:
+ case PW_TYPE_IPADDR:
+ case PW_TYPE_DATE:
+ p[4] = 4;
+ store_uint32_be(vp->lvalue, p + 5);
+ break;
+ default:
+ assert(vp->length <= MAX_STRING_LEN);
+ p[4] = (uint8_t)vp->length;
+ memcpy(p + 5, vp->vp_octets, vp->length);
+ break;
+ }
+
+ *pBuffer += 5 + p[4];
+ *pRemain -= 5 + p[4];
+
+ return true;
+
+}
+
+static bool
+avpImport(VALUE_PAIR **pVp,
+ unsigned char **pBuffer,
+ size_t *pRemain)
+{
+ unsigned char *p = *pBuffer;
+ size_t remain = *pRemain;
+ VALUE_PAIR *vp = NULL;
+ DICT_ATTR *da;
+ uint32_t attrid;
+
+ if (remain < avpSize(NULL))
+ goto fail;
+
+ attrid = load_uint32_be(p);
+ p += 4;
+ remain -= 4;
+
+ da = dict_attrbyvalue(attrid);
+ if (da == NULL)
+ goto fail;
+
+ vp = pairalloc(da);
+ if (vp == NULL) {
+ throw new std::bad_alloc;
+ goto fail;
+ }
+
+ if (remain < p[0])
+ goto fail;
+
+ switch (vp->type) {
+ case PW_TYPE_INTEGER:
+ case PW_TYPE_IPADDR:
+ case PW_TYPE_DATE:
+ if (p[0] != 4)
+ goto fail;
+
+ vp->length = 4;
+ vp->lvalue = load_uint32_be(p + 1);
+ p += 5;
+ remain -= 5;
+ break;
+ case PW_TYPE_STRING:
+ /* check enough room to NUL terminate */
+ if (p[0] == MAX_STRING_LEN)
+ goto fail;
+ else
+ /* fallthrough */
+ default:
+ if (p[0] > MAX_STRING_LEN)
+ goto fail;
+
+ vp->length = (uint32_t)p[0];
+ memcpy(vp->vp_octets, p + 1, vp->length);
+
+ if (vp->type == PW_TYPE_STRING)
+ vp->vp_strvalue[vp->length] = '\0';
+
+ p += 1 + vp->length;
+ remain -= 1 + vp->length;
+ break;
+ }
+
+ *pVp = vp;
+ *pBuffer = p;
+ *pRemain = remain;
+
+ return true;
+
+fail:
+ pairbasicfree(vp);
+ return false;
+}
+
+bool
+gss_eap_radius_attr_provider::initFromBuffer(const gss_eap_attr_ctx *ctx,
+ const gss_buffer_t buffer)
+{
+ unsigned char *p = (unsigned char *)buffer->value;
+ size_t remain = buffer->length;
+ VALUE_PAIR **pNext = &m_vps;
+
+ if (!gss_eap_attr_provider::initFromBuffer(ctx, buffer))
+ return false;
+
+ do {
+ VALUE_PAIR *attr;
+
+ if (!avpImport(&attr, &p, &remain))
+ return false;
+
+ *pNext = attr;
+ pNext = &attr->next;
+ } while (remain != 0);
+
+ return true;
+}
+
+void
+gss_eap_radius_attr_provider::exportToBuffer(gss_buffer_t buffer) const
+{
+ VALUE_PAIR *vp;
+ unsigned char *p;
+ size_t remain = 0;
+
+ for (vp = m_vps; vp != NULL; vp = vp->next) {
+ remain += avpSize(vp);
+ }
+
+ buffer->value = GSSEAP_MALLOC(remain);
+ if (buffer->value == NULL) {
+ throw new std::bad_alloc;
+ return;
+ }
+ buffer->length = remain;
+
+ p = (unsigned char *)buffer->value;
+
+ for (vp = m_vps; vp != NULL; vp = vp->next) {
+ avpExport(vp, &p, &remain);
+ }
+
+ assert(remain == 0);
+}
+
+time_t
+gss_eap_radius_attr_provider::getExpiryTime(void) const
+{
+ VALUE_PAIR *vp;
+
+ vp = pairfind(m_vps, PW_SESSION_TIMEOUT);
+ if (vp == NULL || vp->lvalue == 0)
+ return 0;
+
+ return time(NULL) + vp->lvalue;
+}
+
+OM_uint32
+gssEapRadiusMapError(OM_uint32 *minor,
+ struct rs_error *err)
+{
+ int code;
+
+ assert(err != NULL);
+
+ code = rs_err_code(err, 0);
+
+ if (code == RSE_OK) {
+ *minor = 0;
+ return GSS_S_COMPLETE;
+ }
+
+ *minor = ERROR_TABLE_BASE_rse + code;
+
+ gssEapSaveStatusInfo(*minor, "%s", rs_err_msg(err, 0));
+ rs_err_free(err);
+
+ return GSS_S_FAILURE;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * RADIUS attribute provider.
+ */
+
+#ifndef _UTIL_RADIUS_H_
+#define _UTIL_RADIUS_H_ 1
+
+#ifdef __cplusplus
+
+struct gss_eap_radius_attr_provider : gss_eap_attr_provider {
+public:
+ gss_eap_radius_attr_provider(void);
+ ~gss_eap_radius_attr_provider(void);
+
+ bool initFromExistingContext(const gss_eap_attr_ctx *source,
+ const gss_eap_attr_provider *ctx);
+ bool initFromGssContext(const gss_eap_attr_ctx *source,
+ const gss_cred_id_t cred,
+ const gss_ctx_id_t ctx);
+
+ bool getAttributeTypes(gss_eap_attr_enumeration_cb, void *data) const;
+ bool setAttribute(int complete,
+ const gss_buffer_t attr,
+ const gss_buffer_t value);
+ bool deleteAttribute(const gss_buffer_t attr);
+ bool getAttribute(const gss_buffer_t attr,
+ int *authenticated,
+ int *complete,
+ gss_buffer_t value,
+ gss_buffer_t display_value,
+ int *more) const;
+ gss_any_t mapToAny(int authenticated,
+ gss_buffer_t type_id) const;
+ void releaseAnyNameMapping(gss_buffer_t type_id,
+ gss_any_t input) const;
+
+ void exportToBuffer(gss_buffer_t buffer) const;
+ bool initFromBuffer(const gss_eap_attr_ctx *ctx,
+ const gss_buffer_t buffer);
+
+ bool getAttribute(uint32_t attribute,
+ int *authenticated,
+ int *complete,
+ gss_buffer_t value,
+ gss_buffer_t display_value,
+ int *more) const;
+ bool getAttribute(uint16_t attribute,
+ uint16_t vendor,
+ int *authenticated,
+ int *complete,
+ gss_buffer_t value,
+ gss_buffer_t display_value,
+ int *more) const;
+ bool setAttribute(int complete,
+ uint32_t attribute,
+ const gss_buffer_t value);
+ bool deleteAttribute(uint32_t attribute);
+
+ bool getFragmentedAttribute(uint16_t attribute,
+ uint16_t vendor,
+ int *authenticated,
+ int *complete,
+ gss_buffer_t value) const;
+
+ bool authenticated(void) const { return m_authenticated; }
+
+ time_t getExpiryTime(void) const;
+
+ static bool init(void);
+ static void finalize(void);
+
+ static gss_eap_attr_provider *createAttrContext(void);
+
+private:
+ const VALUE_PAIR *getAvps(void) const {
+ return m_vps;
+ }
+
+ VALUE_PAIR *m_vps;
+ bool m_authenticated;
+};
+
+/* For now */
+extern "C" {
+#endif
+
+OM_uint32
+gssEapRadiusAddAvp(OM_uint32 *minor,
+ VALUE_PAIR **vp,
+ uint16_t type,
+ uint16_t vendor,
+ const gss_buffer_t buffer);
+
+OM_uint32
+gssEapRadiusGetAvp(OM_uint32 *minor,
+ VALUE_PAIR *vps,
+ uint16_t type,
+ uint16_t vendor,
+ gss_buffer_t buffer,
+ int concat);
+
+OM_uint32
+gssEapRadiusGetRawAvp(OM_uint32 *minor,
+ VALUE_PAIR *vps,
+ uint16_t type,
+ uint16_t vendor,
+ VALUE_PAIR **vp);
+OM_uint32
+gssEapRadiusFreeAvps(OM_uint32 *minor,
+ VALUE_PAIR **vps);
+
+OM_uint32 gssEapRadiusAttrProviderInit(OM_uint32 *minor);
+OM_uint32 gssEapRadiusAttrProviderFinalize(OM_uint32 *minor);
+
+OM_uint32
+gssEapRadiusMapError(OM_uint32 *minor,
+ struct rs_error *err);
+
+#define RS_CONFIG_FILE SYSCONFDIR "/radsec.conf"
+#define RS_DICT_FILE DATAROOTDIR "/freeradius/dictionary"
+
+#define VENDORPEC_MS 311 /* RFC 2548 */
+
+#define PW_MS_MPPE_SEND_KEY 16
+#define PW_MS_MPPE_RECV_KEY 17
+
+#define VENDORPEC_UKERNA 25622
+
+#define PW_GSS_ACCEPTOR_SERVICE_NAME 128
+#define PW_GSS_ACCEPTOR_HOST_NAME 129
+#define PW_GSS_ACCEPTOR_SERVICE_SPECIFIC 130
+#define PW_GSS_ACCEPTOR_REALM_NAME 131
+#define PW_SAML_AAA_ASSERTION 132
+
+#define IS_RADIUS_ERROR(code) ((code) >= ERROR_TABLE_BASE_rse && \
+ (code) <= ERROR_TABLE_BASE_rse + RSE_SOME_ERROR)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _UTIL_RADIUS_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Fast reauthentication support.
+ */
+
+#include "gssapiP_eap.h"
+
+#include <dlfcn.h>
+
+/*
+ * Fast reauthentication support for EAP GSS.
+ */
+
+krb5_error_code
+krb5_encrypt_tkt_part(krb5_context, const krb5_keyblock *, krb5_ticket *);
+
+krb5_error_code
+encode_krb5_ticket(const krb5_ticket *rep, krb5_data **code);
+
+static OM_uint32
+gssDisplayName(OM_uint32 *minor,
+ gss_name_t name,
+ gss_buffer_t buffer,
+ gss_OID *name_type);
+
+static OM_uint32
+gssImportName(OM_uint32 *minor,
+ gss_buffer_t buffer,
+ gss_OID name_type,
+ gss_name_t *name);
+
+static krb5_error_code
+getAcceptorKey(krb5_context krbContext,
+ gss_ctx_id_t ctx,
+ gss_cred_id_t cred,
+ krb5_principal *princ,
+ krb5_keyblock *key)
+{
+ krb5_error_code code;
+ krb5_keytab keytab = NULL;
+ krb5_keytab_entry ktent = { 0 };
+ krb5_kt_cursor cursor = NULL;
+
+ *princ = NULL;
+ memset(key, 0, sizeof(*key));
+
+ code = krb5_kt_default(krbContext, &keytab);
+ if (code != 0)
+ goto cleanup;
+
+ if (cred != GSS_C_NO_CREDENTIAL && cred->name != GSS_C_NO_NAME) {
+ code = krb5_kt_get_entry(krbContext, keytab,
+ cred->name->krbPrincipal, 0,
+ ctx->encryptionType, &ktent);
+ if (code != 0)
+ goto cleanup;
+ } else {
+ /*
+ * It's not clear that looking encrypting the ticket in the
+ * requested EAP enctype provides any value.
+ */
+ code = krb5_kt_start_seq_get(krbContext, keytab, &cursor);
+ if (code != 0)
+ goto cleanup;
+
+ while ((code = krb5_kt_next_entry(krbContext, keytab,
+ &ktent, &cursor)) == 0) {
+ if (ktent.key.enctype == ctx->encryptionType)
+ break;
+ else
+ krb5_free_keytab_entry_contents(krbContext, &ktent);
+ }
+ }
+
+ if (code == 0) {
+ *princ = ktent.principal;
+ *key = ktent.key;
+ }
+
+cleanup:
+ if (cred == GSS_C_NO_CREDENTIAL || cred->name == GSS_C_NO_NAME)
+ krb5_kt_end_seq_get(krbContext, keytab, &cursor);
+ krb5_kt_close(krbContext, keytab);
+
+ if (code != 0)
+ krb5_free_keytab_entry_contents(krbContext, &ktent);
+
+ return code;
+}
+
+static OM_uint32
+freezeAttrContext(OM_uint32 *minor,
+ gss_name_t initiatorName,
+ krb5_const_principal acceptorPrinc,
+ krb5_keyblock *session,
+ krb5_authdata ***authdata)
+{
+ OM_uint32 major, tmpMinor;
+ krb5_error_code code;
+ gss_buffer_desc attrBuf = GSS_C_EMPTY_BUFFER;
+ krb5_authdata *authData[2], authDatum = { 0 };
+ krb5_context krbContext;
+
+ GSSEAP_KRB_INIT(&krbContext);
+
+ major = gssEapExportAttrContext(minor, initiatorName, &attrBuf);
+ if (GSS_ERROR(major))
+ return major;
+
+ authDatum.ad_type = KRB5_AUTHDATA_RADIUS_AVP;
+ authDatum.length = attrBuf.length;
+ authDatum.contents = attrBuf.value;
+ authData[0] = &authDatum;
+ authData[1] = NULL;
+
+ code = krb5_make_authdata_kdc_issued(krbContext, session, acceptorPrinc,
+ authData, authdata);
+ if (code != 0) {
+ major = GSS_S_FAILURE;
+ *minor = code;
+ } else {
+ major = GSS_S_COMPLETE;
+ }
+
+ gss_release_buffer(&tmpMinor, &attrBuf);
+
+ return major;
+}
+
+/*
+ * Fabricate a ticket to ourselves given a GSS EAP context.
+ */
+OM_uint32
+gssEapMakeReauthCreds(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ gss_cred_id_t cred,
+ gss_buffer_t credBuf)
+{
+ OM_uint32 major = GSS_S_COMPLETE;
+ krb5_error_code code;
+ krb5_context krbContext = NULL;
+ krb5_ticket ticket = { 0 };
+ krb5_keyblock session = { 0 }, acceptorKey = { 0 };
+ krb5_enc_tkt_part enc_part = { 0 };
+ krb5_data *ticketData = NULL, *credsData = NULL;
+ krb5_creds creds = { 0 };
+ krb5_auth_context authContext = NULL;
+
+ credBuf->length = 0;
+ credBuf->value = NULL;
+
+ GSSEAP_KRB_INIT(&krbContext);
+
+ code = getAcceptorKey(krbContext, ctx, cred,
+ &ticket.server, &acceptorKey);
+ if (code == KRB5_KT_NOTFOUND) {
+ gss_buffer_desc emptyToken = { 0, "" };
+
+ /*
+ * If we can't produce the KRB-CRED message, we need to
+ * return an empty (not NULL) token to the caller so we
+ * don't change the number of authentication legs.
+ */
+ return duplicateBuffer(minor, &emptyToken, credBuf);
+ } else if (code != 0)
+ goto cleanup;
+
+ enc_part.flags = TKT_FLG_INITIAL;
+
+ /*
+ * Generate a random session key to place in the ticket and
+ * sign the "KDC-Issued" authorization data element.
+ */
+ code = krb5_c_make_random_key(krbContext, ctx->encryptionType,
+ &session);
+ if (code != 0)
+ goto cleanup;
+
+ enc_part.session = &session;
+ enc_part.client = ctx->initiatorName->krbPrincipal;
+ enc_part.times.authtime = time(NULL);
+ enc_part.times.starttime = enc_part.times.authtime;
+ enc_part.times.endtime = (ctx->expiryTime != 0)
+ ? ctx->expiryTime
+ : KRB5_INT32_MAX;
+ enc_part.times.renew_till = 0;
+
+ major = freezeAttrContext(minor, ctx->initiatorName, ticket.server,
+ &session, &enc_part.authorization_data);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ ticket.enc_part2 = &enc_part;
+
+ code = krb5_encrypt_tkt_part(krbContext, &acceptorKey, &ticket);
+ if (code != 0)
+ goto cleanup;
+
+ code = encode_krb5_ticket(&ticket, &ticketData);
+ if (code != 0)
+ goto cleanup;
+
+ creds.client = enc_part.client;
+ creds.server = ticket.server;
+ creds.keyblock = session;
+ creds.times = enc_part.times;
+ creds.ticket_flags = enc_part.flags;
+ creds.ticket = *ticketData;
+ creds.authdata = enc_part.authorization_data;
+
+ code = krb5_auth_con_init(krbContext, &authContext);
+ if (code != 0)
+ goto cleanup;
+
+ code = krb5_auth_con_setflags(krbContext, authContext, 0);
+ if (code != 0)
+ goto cleanup;
+
+ code = krb5_auth_con_setsendsubkey(krbContext, authContext,
+ &ctx->rfc3961Key);
+ if (code != 0)
+ goto cleanup;
+
+ code = krb5_mk_1cred(krbContext, authContext, &creds, &credsData, NULL);
+ if (code != 0)
+ goto cleanup;
+
+ krbDataToGssBuffer(credsData, credBuf);
+
+cleanup:
+ if (ticket.enc_part.ciphertext.data != NULL)
+ GSSEAP_FREE(ticket.enc_part.ciphertext.data);
+ krb5_free_keyblock_contents(krbContext, &session);
+ krb5_free_keyblock_contents(krbContext, &acceptorKey);
+ krb5_free_data(krbContext, ticketData);
+ krb5_auth_con_free(krbContext, authContext);
+ krb5_free_authdata(krbContext, enc_part.authorization_data);
+ if (credsData != NULL)
+ GSSEAP_FREE(credsData);
+
+ if (major == GSS_S_COMPLETE) {
+ *minor = code;
+ major = code != 0 ? GSS_S_FAILURE : GSS_S_COMPLETE;
+ }
+
+ return major;
+}
+
+static int
+isTicketGrantingServiceP(krb5_context krbContext,
+ krb5_const_principal principal)
+{
+ if (krb5_princ_size(krbContext, principal) == 2 &&
+ krb5_princ_component(krbContext, principal, 0)->length == 6 &&
+ memcmp(krb5_princ_component(krbContext,
+ principal, 0)->data, "krbtgt", 6) == 0)
+ return TRUE;
+
+ return FALSE;
+}
+
+/*
+ * Returns TRUE if the configuration variable reauth_use_ccache is
+ * set in krb5.conf for the eap_gss application and the client realm.
+ */
+static int
+reauthUseCredsCache(krb5_context krbContext,
+ krb5_principal principal)
+{
+ int reauthUseCCache;
+
+ /* if reauth_use_ccache, use default credentials cache if ticket is for us */
+ krb5_appdefault_boolean(krbContext, "eap_gss",
+ krb5_princ_realm(krbContext, principal),
+ "reauth_use_ccache", 0, &reauthUseCCache);
+
+ return reauthUseCCache;
+}
+
+/*
+ * Look in default credentials cache for reauthentication credentials,
+ * if policy allows.
+ */
+static OM_uint32
+getDefaultReauthCredentials(OM_uint32 *minor,
+ gss_cred_id_t cred,
+ gss_name_t target,
+ time_t now,
+ OM_uint32 timeReq)
+{
+ OM_uint32 major = GSS_S_CRED_UNAVAIL;
+ krb5_context krbContext = NULL;
+ krb5_error_code code = 0;
+ krb5_ccache ccache = NULL;
+ krb5_creds match = { 0 };
+ krb5_creds creds = { 0 };
+
+ GSSEAP_KRB_INIT(&krbContext);
+
+ assert(cred != GSS_C_NO_CREDENTIAL);
+ assert(target != GSS_C_NO_NAME);
+
+ if (cred->name == GSS_C_NO_NAME ||
+ !reauthUseCredsCache(krbContext, cred->name->krbPrincipal))
+ goto cleanup;
+
+ match.client = cred->name->krbPrincipal;
+ match.server = target->krbPrincipal;
+ if (timeReq != 0 && timeReq != GSS_C_INDEFINITE)
+ match.times.endtime = now + timeReq;
+
+ code = krb5_cc_default(krbContext, &ccache);
+ if (code != 0)
+ goto cleanup;
+
+ code = krb5_cc_retrieve_cred(krbContext, ccache, 0, &match, &creds);
+ if (code != 0)
+ goto cleanup;
+
+ cred->flags |= CRED_FLAG_DEFAULT_CCACHE;
+ cred->krbCredCache = ccache;
+ ccache = NULL;
+
+ major = gss_krb5_import_cred(minor, cred->krbCredCache, NULL, NULL,
+ &cred->krbCred);
+
+cleanup:
+ if (major == GSS_S_CRED_UNAVAIL)
+ *minor = code;
+
+ if (ccache != NULL)
+ krb5_cc_close(krbContext, ccache);
+ krb5_free_cred_contents(krbContext, &creds);
+
+ return major;
+}
+
+/*
+ * Returns TRUE if the credential handle's reauth credentials are
+ * valid or if we can use the default credentials cache. Credentials
+ * handle must be locked.
+ */
+int
+gssEapCanReauthP(gss_cred_id_t cred,
+ gss_name_t target,
+ OM_uint32 timeReq)
+{
+ time_t now, expiryReq;
+ OM_uint32 minor;
+
+ assert(cred != GSS_C_NO_CREDENTIAL);
+
+ now = time(NULL);
+ expiryReq = now;
+ if (timeReq != GSS_C_INDEFINITE)
+ expiryReq += timeReq;
+
+ if (cred->krbCredCache != NULL && cred->expiryTime > expiryReq)
+ return TRUE;
+
+ if (getDefaultReauthCredentials(&minor, cred, target,
+ now, timeReq) == GSS_S_COMPLETE)
+ return TRUE;
+
+ return FALSE;
+}
+
+/*
+ * Store re-authentication (Kerberos) credentials in a credential handle.
+ * Credentials handle must be locked.
+ */
+OM_uint32
+gssEapStoreReauthCreds(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ gss_cred_id_t cred,
+ gss_buffer_t credBuf)
+{
+ OM_uint32 major = GSS_S_COMPLETE;
+ krb5_error_code code;
+ krb5_context krbContext = NULL;
+ krb5_auth_context authContext = NULL;
+ krb5_data credData = { 0 };
+ krb5_creds **creds = NULL;
+ krb5_principal canonPrinc;
+ krb5_principal ccPrinc = NULL;
+ int i;
+
+ if (credBuf->length == 0 || cred == GSS_C_NO_CREDENTIAL)
+ return GSS_S_COMPLETE;
+
+ GSSEAP_KRB_INIT(&krbContext);
+
+ code = krb5_auth_con_init(krbContext, &authContext);
+ if (code != 0)
+ goto cleanup;
+
+ code = krb5_auth_con_setflags(krbContext, authContext, 0);
+ if (code != 0)
+ goto cleanup;
+
+ code = krb5_auth_con_setrecvsubkey(krbContext, authContext,
+ &ctx->rfc3961Key);
+ if (code != 0)
+ goto cleanup;
+
+ gssBufferToKrbData(credBuf, &credData);
+
+ code = krb5_rd_cred(krbContext, authContext, &credData, &creds, NULL);
+ if (code != 0)
+ goto cleanup;
+
+ if (creds == NULL || creds[0] == NULL)
+ goto cleanup;
+
+ code = krb5_copy_principal(krbContext, creds[0]->client, &canonPrinc);
+ if (code != 0)
+ goto cleanup;
+
+ krb5_free_principal(krbContext, cred->name->krbPrincipal);
+ cred->name->krbPrincipal = canonPrinc;
+
+ if (creds[0]->times.endtime == KRB5_INT32_MAX)
+ cred->expiryTime = 0;
+ else
+ cred->expiryTime = creds[0]->times.endtime;
+
+ if (cred->krbCredCache == NULL) {
+ if (reauthUseCredsCache(krbContext, creds[0]->client) &&
+ krb5_cc_default(krbContext, &cred->krbCredCache) == 0)
+ cred->flags |= CRED_FLAG_DEFAULT_CCACHE;
+ } else {
+ /*
+ * If we already have an associated credentials cache, possibly from
+ * the last time we stored a reauthentication credential, then we
+ * need to clear it out and release the associated GSS credential.
+ */
+ if (cred->flags & CRED_FLAG_DEFAULT_CCACHE) {
+ krb5_cc_remove_cred(krbContext, cred->krbCredCache, 0, creds[0]);
+ } else {
+ krb5_cc_destroy(krbContext, cred->krbCredCache);
+ cred->krbCredCache = NULL;
+ }
+ gssReleaseCred(minor, &cred->krbCred);
+ }
+
+ if (cred->krbCredCache == NULL) {
+ code = krb5_cc_new_unique(krbContext, "MEMORY", NULL, &cred->krbCredCache);
+ if (code != 0)
+ goto cleanup;
+ }
+
+ if ((cred->flags & CRED_FLAG_DEFAULT_CCACHE) == 0 ||
+ krb5_cc_get_principal(krbContext, cred->krbCredCache, &ccPrinc) != 0) {
+ code = krb5_cc_initialize(krbContext, cred->krbCredCache,
+ creds[0]->client);
+ if (code != 0)
+ goto cleanup;
+ }
+
+ for (i = 0; creds[i] != NULL; i++) {
+ krb5_creds kcred = *(creds[i]);
+
+ /*
+ * Swap in the acceptor name the client asked for so
+ * get_credentials() works. We're making the assumption that
+ * any service tickets returned are for us. We'll need to
+ * reflect some more on whether that is a safe assumption.
+ */
+ if (!isTicketGrantingServiceP(krbContext, kcred.server))
+ kcred.server = ctx->acceptorName->krbPrincipal;
+
+ code = krb5_cc_store_cred(krbContext, cred->krbCredCache, &kcred);
+ if (code != 0)
+ goto cleanup;
+ }
+
+ major = gss_krb5_import_cred(minor, cred->krbCredCache, NULL, NULL,
+ &cred->krbCred);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+cleanup:
+ *minor = code;
+
+ krb5_free_principal(krbContext, ccPrinc);
+ krb5_auth_con_free(krbContext, authContext);
+ if (creds != NULL) {
+ for (i = 0; creds[i] != NULL; i++)
+ krb5_free_creds(krbContext, creds[i]);
+ GSSEAP_FREE(creds);
+ }
+ if (major == GSS_S_COMPLETE)
+ major = *minor ? GSS_S_FAILURE : GSS_S_COMPLETE;
+
+ return major;
+}
+
+static gss_buffer_desc radiusAvpKrbAttr = {
+ sizeof("urn:authdata-radius-avp") - 1, "urn:authdata-radius-avp"
+};
+
+/*
+ * Unfortunately extracting an AD-KDCIssued authorization data element
+ * is pretty implementation-dependent. It's not possible to verify the
+ * signature ourselves because the ticket session key is not exposed
+ * outside GSS. In an ideal world, all AD-KDCIssued elements would be
+ * verified by the Kerberos library and authentication would fail if
+ * verification failed. We're not quite there yet and as a result have
+ * to go through some hoops to get this to work. The alternative would
+ * be to sign the authorization data with our long-term key, but it
+ * seems a pity to compromise the design because of current implementation
+ * limitations.
+ *
+ * (Specifically, the hoops involve a libkrb5 authorisation data plugin
+ * that exposes the verified and serialised attribute context through
+ * the Kerberos GSS mechanism's naming extensions API.)
+ */
+static OM_uint32
+defrostAttrContext(OM_uint32 *minor,
+ gss_name_t glueName,
+ gss_name_t mechName)
+{
+ OM_uint32 major, tmpMinor;
+ gss_buffer_desc authData = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc authDataDisplay = GSS_C_EMPTY_BUFFER;
+ int more = -1;
+ int authenticated, complete;
+
+ major = gssGetNameAttribute(minor, glueName, &radiusAvpKrbAttr,
+ &authenticated, &complete,
+ &authData, &authDataDisplay, &more);
+ if (major == GSS_S_COMPLETE) {
+ if (authenticated == 0)
+ major = GSS_S_BAD_NAME;
+ else
+ major = gssEapImportAttrContext(minor, &authData, mechName);
+ } else if (major == GSS_S_UNAVAILABLE) {
+ major = GSS_S_COMPLETE;
+ }
+
+ gss_release_buffer(&tmpMinor, &authData);
+ gss_release_buffer(&tmpMinor, &authDataDisplay);
+
+ return major;
+}
+
+/*
+ * Convert a mechanism glue to an EAP mechanism name by displaying and
+ * importing it. This also handles the RADIUS attributes.
+ */
+OM_uint32
+gssEapGlueToMechName(OM_uint32 *minor,
+ gss_name_t glueName,
+ gss_name_t *pMechName)
+{
+ OM_uint32 major, tmpMinor;
+ gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
+
+ *pMechName = GSS_C_NO_NAME;
+
+ major = gssDisplayName(minor, glueName, &nameBuf, NULL);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ major = gssEapImportName(minor, &nameBuf, GSS_C_NT_USER_NAME,
+ pMechName);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ major = defrostAttrContext(minor, glueName, *pMechName);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+cleanup:
+ if (GSS_ERROR(major)) {
+ gssReleaseName(&tmpMinor, pMechName);
+ *pMechName = GSS_C_NO_NAME;
+ }
+
+ gss_release_buffer(&tmpMinor, &nameBuf);
+
+ return major;
+}
+
+/*
+ * Convert an EAP mechanism name to a mechanism glue name by displaying
+ * and importing it.
+ */
+OM_uint32
+gssEapMechToGlueName(OM_uint32 *minor,
+ gss_name_t mechName,
+ gss_name_t *pGlueName)
+{
+ OM_uint32 major, tmpMinor;
+ gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
+
+ *pGlueName = GSS_C_NO_NAME;
+
+ major = gssEapDisplayName(minor, mechName, &nameBuf, NULL);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ major = gssImportName(minor, &nameBuf, GSS_C_NT_USER_NAME,
+ pGlueName);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+cleanup:
+ gss_release_buffer(&tmpMinor, &nameBuf);
+
+ return major;
+}
+
+/*
+ * Suck out the analgous elements of a Kerberos GSS context into an EAP
+ * one so that the application doesn't know the difference.
+ */
+OM_uint32
+gssEapReauthComplete(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ gss_cred_id_t cred,
+ const gss_OID mech,
+ OM_uint32 timeRec)
+{
+ OM_uint32 major, tmpMinor;
+ gss_buffer_set_t keyData = GSS_C_NO_BUFFER_SET;
+
+ if (!oidEqual(mech, gss_mech_krb5)) {
+ major = GSS_S_BAD_MECH;
+ goto cleanup;
+ }
+
+ /* Get the raw subsession key and encryption type*/
+ major = gssInquireSecContextByOid(minor, ctx->kerberosCtx,
+ GSS_C_INQ_SSPI_SESSION_KEY, &keyData);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ {
+ gss_OID_desc oid;
+ int suffix;
+
+ oid.length = keyData->elements[1].length;
+ oid.elements = keyData->elements[1].value;
+
+ /* GSS_KRB5_SESSION_KEY_ENCTYPE_OID */
+ major = decomposeOid(minor,
+ "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x04",
+ 10, &oid, &suffix);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ ctx->encryptionType = suffix;
+ }
+
+ {
+ krb5_context krbContext = NULL;
+ krb5_keyblock key;
+
+ GSSEAP_KRB_INIT(&krbContext);
+
+ KRB_KEY_LENGTH(&key) = keyData->elements[0].length;
+ KRB_KEY_DATA(&key) = keyData->elements[0].value;
+ KRB_KEY_TYPE(&key) = ctx->encryptionType;
+
+ *minor = krb5_copy_keyblock_contents(krbContext,
+ &key, &ctx->rfc3961Key);
+ if (*minor != 0) {
+ major = GSS_S_FAILURE;
+ goto cleanup;
+ }
+ }
+
+ major = rfc3961ChecksumTypeForKey(minor, &ctx->rfc3961Key,
+ &ctx->checksumType);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ if (timeRec != GSS_C_INDEFINITE)
+ ctx->expiryTime = time(NULL) + timeRec;
+
+ /* Initialize our sequence state */
+ major = sequenceInit(minor,
+ &ctx->seqState, ctx->recvSeq,
+ ((ctx->gssFlags & GSS_C_REPLAY_FLAG) != 0),
+ ((ctx->gssFlags & GSS_C_SEQUENCE_FLAG) != 0),
+ TRUE);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ major = GSS_S_COMPLETE;
+
+cleanup:
+ gss_release_buffer_set(&tmpMinor, &keyData);
+
+ return major;
+}
+
+/*
+ * The remainder of this file consists of wrappers so we can call into the
+ * mechanism glue without calling ourselves.
+ */
+static OM_uint32
+(*gssInitSecContextNext)(OM_uint32 *,
+ gss_cred_id_t,
+ gss_ctx_id_t *,
+ gss_name_t,
+ gss_OID,
+ OM_uint32,
+ OM_uint32,
+ gss_channel_bindings_t,
+ gss_buffer_t,
+ gss_OID *,
+ gss_buffer_t,
+ OM_uint32 *,
+ OM_uint32 *);
+
+static OM_uint32
+(*gssAcceptSecContextNext)(OM_uint32 *,
+ gss_ctx_id_t *,
+ gss_cred_id_t,
+ gss_buffer_t,
+ gss_channel_bindings_t,
+ gss_name_t *,
+ gss_OID *,
+ gss_buffer_t,
+ OM_uint32 *,
+ OM_uint32 *,
+ gss_cred_id_t *);
+
+static OM_uint32
+(*gssReleaseCredNext)(OM_uint32 *, gss_cred_id_t *);
+
+static OM_uint32
+(*gssReleaseNameNext)(OM_uint32 *, gss_name_t *);
+
+static OM_uint32
+(*gssInquireSecContextByOidNext)(OM_uint32 *,
+ const gss_ctx_id_t,
+ const gss_OID,
+ gss_buffer_set_t *);
+
+static OM_uint32
+(*gssDeleteSecContextNext)(OM_uint32 *,
+ gss_ctx_id_t *,
+ gss_buffer_t);
+
+static OM_uint32
+(*gssDisplayNameNext)(OM_uint32 *,
+ gss_name_t,
+ gss_buffer_t,
+ gss_OID *);
+
+static OM_uint32
+(*gssImportNameNext)(OM_uint32 *,
+ gss_buffer_t,
+ gss_OID,
+ gss_name_t *);
+
+static OM_uint32
+(*gssStoreCredNext)(OM_uint32 *,
+ const gss_cred_id_t,
+ gss_cred_usage_t,
+ const gss_OID,
+ OM_uint32,
+ OM_uint32,
+ gss_OID_set *,
+ gss_cred_usage_t *);
+
+static OM_uint32
+(*gssGetNameAttributeNext)(OM_uint32 *,
+ gss_name_t,
+ gss_buffer_t,
+ int *,
+ int *,
+ gss_buffer_t,
+ gss_buffer_t,
+ int *);
+
+#define NEXT_SYMBOL(local, global) do { \
+ ((local) = dlsym(RTLD_NEXT, (global))); \
+ if ((local) == NULL) { \
+ *minor = GSSEAP_NO_MECHGLUE_SYMBOL; \
+ major = GSS_S_UNAVAILABLE; \
+ /* but continue */ \
+ } \
+ } while (0)
+
+OM_uint32
+gssEapReauthInitialize(OM_uint32 *minor)
+{
+ OM_uint32 major = GSS_S_COMPLETE;
+
+ NEXT_SYMBOL(gssInitSecContextNext, "gss_init_sec_context");
+ NEXT_SYMBOL(gssAcceptSecContextNext, "gss_accept_sec_context");
+ NEXT_SYMBOL(gssReleaseCredNext, "gss_release_cred");
+ NEXT_SYMBOL(gssReleaseNameNext, "gss_release_name");
+ NEXT_SYMBOL(gssInquireSecContextByOidNext, "gss_inquire_sec_context_by_oid");
+ NEXT_SYMBOL(gssDeleteSecContextNext, "gss_delete_sec_context");
+ NEXT_SYMBOL(gssDisplayNameNext, "gss_display_name");
+ NEXT_SYMBOL(gssImportNameNext, "gss_import_name");
+ NEXT_SYMBOL(gssStoreCredNext, "gss_store_cred");
+ NEXT_SYMBOL(gssGetNameAttributeNext, "gss_get_name_attribute");
+
+ return major;
+}
+
+OM_uint32
+gssInitSecContext(OM_uint32 *minor,
+ gss_cred_id_t cred,
+ gss_ctx_id_t *context_handle,
+ gss_name_t target_name,
+ gss_OID mech_type,
+ OM_uint32 req_flags,
+ OM_uint32 time_req,
+ gss_channel_bindings_t input_chan_bindings,
+ gss_buffer_t input_token,
+ gss_OID *actual_mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 *ret_flags,
+ OM_uint32 *time_rec)
+{
+ if (gssInitSecContextNext == NULL) {
+ *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
+ return GSS_S_UNAVAILABLE;
+ }
+
+ return gssInitSecContextNext(minor, cred, context_handle,
+ target_name, mech_type, req_flags,
+ time_req, input_chan_bindings,
+ input_token, actual_mech_type,
+ output_token, ret_flags, time_rec);
+}
+
+OM_uint32
+gssAcceptSecContext(OM_uint32 *minor,
+ gss_ctx_id_t *context_handle,
+ gss_cred_id_t cred,
+ gss_buffer_t input_token,
+ gss_channel_bindings_t input_chan_bindings,
+ gss_name_t *src_name,
+ gss_OID *mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 *ret_flags,
+ OM_uint32 *time_rec,
+ gss_cred_id_t *delegated_cred_handle)
+{
+ if (gssAcceptSecContextNext == NULL) {
+ *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
+ return GSS_S_UNAVAILABLE;
+ }
+
+ return gssAcceptSecContextNext(minor, context_handle, cred,
+ input_token, input_chan_bindings,
+ src_name, mech_type, output_token,
+ ret_flags, time_rec, delegated_cred_handle);
+}
+
+OM_uint32
+gssReleaseCred(OM_uint32 *minor,
+ gss_cred_id_t *cred_handle)
+{
+ if (gssReleaseCredNext == NULL) {
+ *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
+ return GSS_S_UNAVAILABLE;
+ }
+
+ return gssReleaseCredNext(minor, cred_handle);
+}
+
+OM_uint32
+gssReleaseName(OM_uint32 *minor,
+ gss_name_t *name)
+{
+ if (gssReleaseName == NULL) {
+ *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
+ return GSS_S_UNAVAILABLE;
+ }
+
+ return gssReleaseNameNext(minor, name);
+}
+
+OM_uint32
+gssDeleteSecContext(OM_uint32 *minor,
+ gss_ctx_id_t *context_handle,
+ gss_buffer_t output_token)
+{
+ if (gssDeleteSecContextNext == NULL) {
+ *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
+ return GSS_S_UNAVAILABLE;
+ }
+
+ return gssDeleteSecContextNext(minor, context_handle, output_token);
+}
+
+static OM_uint32
+gssDisplayName(OM_uint32 *minor,
+ gss_name_t name,
+ gss_buffer_t buffer,
+ gss_OID *name_type)
+{
+ if (gssDisplayNameNext == NULL) {
+ *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
+ return GSS_S_UNAVAILABLE;
+ }
+
+ return gssDisplayNameNext(minor, name, buffer, name_type);
+}
+
+static OM_uint32
+gssImportName(OM_uint32 *minor,
+ gss_buffer_t buffer,
+ gss_OID name_type,
+ gss_name_t *name)
+{
+ if (gssImportNameNext == NULL) {
+ *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
+ return GSS_S_UNAVAILABLE;
+ }
+
+ return gssImportNameNext(minor, buffer, name_type, name);
+}
+
+OM_uint32
+gssInquireSecContextByOid(OM_uint32 *minor,
+ const gss_ctx_id_t context_handle,
+ const gss_OID desired_object,
+ gss_buffer_set_t *data_set)
+{
+ if (gssInquireSecContextByOidNext == NULL) {
+ *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
+ return GSS_S_UNAVAILABLE;
+ }
+
+ return gssInquireSecContextByOidNext(minor, context_handle,
+ desired_object, data_set);
+}
+
+OM_uint32
+gssStoreCred(OM_uint32 *minor,
+ const gss_cred_id_t input_cred_handle,
+ gss_cred_usage_t input_usage,
+ const gss_OID desired_mech,
+ OM_uint32 overwrite_cred,
+ OM_uint32 default_cred,
+ gss_OID_set *elements_stored,
+ gss_cred_usage_t *cred_usage_stored)
+{
+ if (gssStoreCredNext == NULL) {
+ *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
+ return GSS_S_UNAVAILABLE;
+ }
+
+ return gssStoreCredNext(minor, input_cred_handle, input_usage,
+ desired_mech, overwrite_cred, default_cred,
+ elements_stored, cred_usage_stored);
+}
+
+OM_uint32
+gssGetNameAttribute(OM_uint32 *minor,
+ gss_name_t name,
+ gss_buffer_t attr,
+ int *authenticated,
+ int *complete,
+ gss_buffer_t value,
+ gss_buffer_t display_value,
+ int *more)
+{
+ if (gssGetNameAttributeNext == NULL) {
+ *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
+ return GSS_S_UNAVAILABLE;
+ }
+
+ return gssGetNameAttributeNext(minor, name, attr, authenticated, complete,
+ value, display_value, more);
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Fast reauthentication support.
+ */
+
+#include "gssapiP_eap.h"
+
+#ifndef _UTIL_REAUTH_H_
+#define _UTIL_REAUTH_H_ 1
+
+/* AD element containing serialised AVPs. */
+#define KRB5_AUTHDATA_RADIUS_AVP 513
+
+OM_uint32
+gssInitSecContext(OM_uint32 *minor,
+ gss_cred_id_t cred,
+ gss_ctx_id_t *context_handle,
+ gss_name_t target_name,
+ gss_OID mech_type,
+ OM_uint32 req_flags,
+ OM_uint32 time_req,
+ gss_channel_bindings_t input_chan_bindings,
+ gss_buffer_t input_token,
+ gss_OID *actual_mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 *ret_flags,
+ OM_uint32 *time_rec);
+
+OM_uint32
+gssAcceptSecContext(OM_uint32 *minor,
+ gss_ctx_id_t *context_handle,
+ gss_cred_id_t cred,
+ gss_buffer_t input_token,
+ gss_channel_bindings_t input_chan_bindings,
+ gss_name_t *src_name,
+ gss_OID *mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 *ret_flags,
+ OM_uint32 *time_rec,
+ gss_cred_id_t *delegated_cred_handle);
+
+OM_uint32
+gssReleaseCred(OM_uint32 *minor,
+ gss_cred_id_t *cred_handle);
+
+OM_uint32
+gssReleaseName(OM_uint32 *minor,
+ gss_name_t *name);
+
+OM_uint32
+gssDeleteSecContext(OM_uint32 *minor,
+ gss_ctx_id_t *context_handle,
+ gss_buffer_t output_token);
+
+OM_uint32
+gssInquireSecContextByOid(OM_uint32 *minor,
+ const gss_ctx_id_t context_handle,
+ const gss_OID desired_object,
+ gss_buffer_set_t *data_set);
+
+OM_uint32
+gssStoreCred(OM_uint32 *minor,
+ const gss_cred_id_t input_cred_handle,
+ gss_cred_usage_t input_usage,
+ const gss_OID desired_mech,
+ OM_uint32 overwrite_cred,
+ OM_uint32 default_cred,
+ gss_OID_set *elements_stored,
+ gss_cred_usage_t *cred_usage_stored);
+
+OM_uint32
+gssGetNameAttribute(OM_uint32 *minor,
+ gss_name_t name,
+ gss_buffer_t attr,
+ int *authenticated,
+ int *complete,
+ gss_buffer_t value,
+ gss_buffer_t display_value,
+ int *more);
+
+OM_uint32
+gssEapMakeReauthCreds(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ gss_cred_id_t cred,
+ gss_buffer_t credBuf);
+
+OM_uint32
+gssEapStoreReauthCreds(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ gss_cred_id_t cred,
+ gss_buffer_t credBuf);
+
+
+OM_uint32
+gssEapGlueToMechName(OM_uint32 *minor,
+ gss_name_t glueName,
+ gss_name_t *pMechName);
+
+OM_uint32
+gssEapMechToGlueName(OM_uint32 *minor,
+ gss_name_t mechName,
+ gss_name_t *pGlueName);
+
+OM_uint32
+gssEapReauthComplete(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ gss_cred_id_t cred,
+ const gss_OID mech,
+ OM_uint32 timeRec);
+
+OM_uint32
+gssEapReauthInitialize(OM_uint32 *minor);
+
+int
+gssEapCanReauthP(gss_cred_id_t cred,
+ gss_name_t target,
+ OM_uint32 timeReq);
+
+#endif /* _UTIL_REAUTH_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * SAML attribute provider implementation.
+ */
+
+#include "gssapiP_eap.h"
+
+#include <sstream>
+
+#include <xercesc/util/XMLUniDefs.hpp>
+#include <xmltooling/unicode.h>
+#include <xmltooling/XMLToolingConfig.h>
+#include <xmltooling/util/XMLHelper.h>
+#include <xmltooling/util/ParserPool.h>
+#include <xmltooling/util/DateTime.h>
+
+#include <saml/saml1/core/Assertions.h>
+#include <saml/saml2/core/Assertions.h>
+#include <saml/saml2/metadata/Metadata.h>
+
+using namespace xmltooling;
+using namespace opensaml::saml2md;
+using namespace opensaml;
+using namespace xercesc;
+using namespace std;
+
+/*
+ * gss_eap_saml_assertion_provider is for retrieving the underlying
+ * assertion.
+ */
+gss_eap_saml_assertion_provider::gss_eap_saml_assertion_provider(void)
+{
+ m_assertion = NULL;
+ m_authenticated = false;
+}
+
+gss_eap_saml_assertion_provider::~gss_eap_saml_assertion_provider(void)
+{
+ delete m_assertion;
+}
+
+bool
+gss_eap_saml_assertion_provider::initFromExistingContext(const gss_eap_attr_ctx *manager,
+ const gss_eap_attr_provider *ctx)
+{
+ /* Then we may be creating from an existing attribute context */
+ const gss_eap_saml_assertion_provider *saml;
+
+ assert(m_assertion == NULL);
+
+ if (!gss_eap_attr_provider::initFromExistingContext(manager, ctx))
+ return false;
+
+ saml = static_cast<const gss_eap_saml_assertion_provider *>(ctx);
+ setAssertion(saml->getAssertion(), saml->authenticated());
+
+ return true;
+}
+
+bool
+gss_eap_saml_assertion_provider::initFromGssContext(const gss_eap_attr_ctx *manager,
+ const gss_cred_id_t gssCred,
+ const gss_ctx_id_t gssCtx)
+{
+ const gss_eap_radius_attr_provider *radius;
+ gss_buffer_desc value = GSS_C_EMPTY_BUFFER;
+ int authenticated, complete;
+ OM_uint32 minor;
+
+ assert(m_assertion == NULL);
+
+ if (!gss_eap_attr_provider::initFromGssContext(manager, gssCred, gssCtx))
+ return false;
+
+ /*
+ * XXX TODO we need to support draft-howlett-radius-saml-attr-00
+ */
+ radius = static_cast<const gss_eap_radius_attr_provider *>
+ (m_manager->getProvider(ATTR_TYPE_RADIUS));
+ if (radius != NULL &&
+ radius->getFragmentedAttribute(PW_SAML_AAA_ASSERTION,
+ VENDORPEC_UKERNA,
+ &authenticated, &complete, &value)) {
+ setAssertion(&value, authenticated);
+ gss_release_buffer(&minor, &value);
+ } else {
+ m_assertion = NULL;
+ }
+
+ return true;
+}
+
+void
+gss_eap_saml_assertion_provider::setAssertion(const saml2::Assertion *assertion,
+ bool authenticated)
+{
+
+ delete m_assertion;
+
+ if (assertion != NULL) {
+#ifdef __APPLE__
+ m_assertion = (saml2::Assertion *)((void *)assertion->clone());
+#else
+ m_assertion = dynamic_cast<saml2::Assertion *>(assertion->clone());
+#endif
+ m_authenticated = authenticated;
+ } else {
+ m_assertion = NULL;
+ m_authenticated = false;
+ }
+}
+
+void
+gss_eap_saml_assertion_provider::setAssertion(const gss_buffer_t buffer,
+ bool authenticated)
+{
+ delete m_assertion;
+
+ m_assertion = parseAssertion(buffer);
+ m_authenticated = (m_assertion != NULL && authenticated);
+}
+
+saml2::Assertion *
+gss_eap_saml_assertion_provider::parseAssertion(const gss_buffer_t buffer)
+{
+ string str((char *)buffer->value, buffer->length);
+ istringstream istream(str);
+ DOMDocument *doc;
+ const XMLObjectBuilder *b;
+
+ doc = XMLToolingConfig::getConfig().getParser().parse(istream);
+ if (doc == NULL)
+ return NULL;
+
+ b = XMLObjectBuilder::getBuilder(doc->getDocumentElement());
+
+#ifdef __APPLE__
+ return (saml2::Assertion *)((void *)b->buildFromDocument(doc));
+#else
+ return dynamic_cast<saml2::Assertion *>(b->buildFromDocument(doc));
+#endif
+}
+
+bool
+gss_eap_saml_assertion_provider::getAttributeTypes(gss_eap_attr_enumeration_cb addAttribute,
+ void *data) const
+{
+ bool ret;
+
+ /* just add the prefix */
+ if (m_assertion != NULL)
+ ret = addAttribute(this, GSS_C_NO_BUFFER, data);
+ else
+ ret = true;
+
+ return ret;
+}
+
+bool
+gss_eap_saml_assertion_provider::setAttribute(int complete,
+ const gss_buffer_t attr,
+ const gss_buffer_t value)
+{
+ if (attr == GSS_C_NO_BUFFER || attr->length == 0) {
+ setAssertion(value);
+ return true;
+ }
+
+ return false;
+}
+
+bool
+gss_eap_saml_assertion_provider::deleteAttribute(const gss_buffer_t value)
+{
+ delete m_assertion;
+ m_assertion = NULL;
+ m_authenticated = false;
+
+ return true;
+}
+
+time_t
+gss_eap_saml_assertion_provider::getExpiryTime(void) const
+{
+ saml2::Conditions *conditions;
+ time_t expiryTime = 0;
+
+ if (m_assertion == NULL)
+ return 0;
+
+ conditions = m_assertion->getConditions();
+
+ if (conditions != NULL && conditions->getNotOnOrAfter() != NULL)
+ expiryTime = conditions->getNotOnOrAfter()->getEpoch();
+
+ return expiryTime;
+}
+
+bool
+gss_eap_saml_assertion_provider::getAttribute(const gss_buffer_t attr,
+ int *authenticated,
+ int *complete,
+ gss_buffer_t value,
+ gss_buffer_t display_value,
+ int *more) const
+{
+ string str;
+
+ if (attr != GSS_C_NO_BUFFER && attr->length != 0)
+ return false;
+
+ if (m_assertion == NULL)
+ return false;
+
+ if (*more != -1)
+ return false;
+
+ if (authenticated != NULL)
+ *authenticated = m_authenticated;
+ if (complete != NULL)
+ *complete = true;
+
+ XMLHelper::serialize(m_assertion->marshall((DOMDocument *)NULL), str);
+
+ duplicateBuffer(str, value);
+ *more = 0;
+
+ return true;
+}
+
+gss_any_t
+gss_eap_saml_assertion_provider::mapToAny(int authenticated,
+ gss_buffer_t type_id) const
+{
+ if (authenticated && !m_authenticated)
+ return (gss_any_t)NULL;
+
+ return (gss_any_t)m_assertion;
+}
+
+void
+gss_eap_saml_assertion_provider::releaseAnyNameMapping(gss_buffer_t type_id,
+ gss_any_t input) const
+{
+ delete ((saml2::Assertion *)input);
+}
+
+void
+gss_eap_saml_assertion_provider::exportToBuffer(gss_buffer_t buffer) const
+{
+ ostringstream sink;
+ string str;
+
+ buffer->length = 0;
+ buffer->value = NULL;
+
+ if (m_assertion == NULL)
+ return;
+
+ sink << *m_assertion;
+ str = sink.str();
+
+ duplicateBuffer(str, buffer);
+}
+
+bool
+gss_eap_saml_assertion_provider::initFromBuffer(const gss_eap_attr_ctx *ctx,
+ const gss_buffer_t buffer)
+{
+ if (!gss_eap_attr_provider::initFromBuffer(ctx, buffer))
+ return false;
+
+ if (buffer->length == 0)
+ return true;
+
+ assert(m_assertion == NULL);
+
+ setAssertion(buffer);
+ /* TODO XXX how to propagate authenticated flag? */
+
+ return true;
+}
+
+bool
+gss_eap_saml_assertion_provider::init(void)
+{
+ gss_eap_attr_ctx::registerProvider(ATTR_TYPE_SAML_ASSERTION,
+ "urn:ietf:params:gss-eap:saml-aaa-assertion",
+ gss_eap_saml_assertion_provider::createAttrContext);
+ return true;
+}
+
+void
+gss_eap_saml_assertion_provider::finalize(void)
+{
+ gss_eap_attr_ctx::unregisterProvider(ATTR_TYPE_SAML_ASSERTION);
+}
+
+gss_eap_attr_provider *
+gss_eap_saml_assertion_provider::createAttrContext(void)
+{
+ return new gss_eap_saml_assertion_provider;
+}
+
+saml2::Assertion *
+gss_eap_saml_assertion_provider::initAssertion(void)
+{
+ delete m_assertion;
+ m_assertion = saml2::AssertionBuilder::buildAssertion();
+ m_authenticated = false;
+
+ return m_assertion;
+}
+
+/*
+ * gss_eap_saml_attr_provider is for retrieving the underlying attributes.
+ */
+bool
+gss_eap_saml_attr_provider::getAssertion(int *authenticated,
+ saml2::Assertion **pAssertion,
+ bool createIfAbsent) const
+{
+ gss_eap_saml_assertion_provider *saml;
+
+ if (authenticated != NULL)
+ *authenticated = false;
+ if (pAssertion != NULL)
+ *pAssertion = NULL;
+
+ saml = static_cast<const gss_eap_saml_assertion_provider *>
+ (m_manager->getProvider(ATTR_TYPE_SAML_ASSERTION));
+ if (saml == NULL)
+ return false;
+
+ if (authenticated != NULL)
+ *authenticated = saml->authenticated();
+ if (pAssertion != NULL)
+ *pAssertion = saml->getAssertion();
+
+ if (saml->getAssertion() == NULL) {
+ if (createIfAbsent) {
+ if (authenticated != NULL)
+ *authenticated = false;
+ if (pAssertion != NULL)
+ *pAssertion = saml->initAssertion();
+ } else
+ return false;
+ }
+
+ return true;
+}
+
+bool
+gss_eap_saml_attr_provider::getAttributeTypes(gss_eap_attr_enumeration_cb addAttribute,
+ void *data) const
+{
+ saml2::Assertion *assertion;
+ int authenticated;
+
+ if (!getAssertion(&authenticated, &assertion))
+ return true;
+
+ /*
+ * Note: the first prefix is added by the attribute provider manager
+ *
+ * From draft-hartman-gss-eap-naming-00:
+ *
+ * Each attribute carried in the assertion SHOULD also be a GSS name
+ * attribute. The name of this attribute has three parts, all separated
+ * by an ASCII space character. The first part is
+ * urn:ietf:params:gss-eap:saml-attr. The second part is the URI for
+ * the SAML attribute name format. The final part is the name of the
+ * SAML attribute. If the mechanism performs an additional attribute
+ * query, the retrieved attributes SHOULD be GSS-API name attributes
+ * using the same name syntax.
+ */
+ /* For each attribute statement, look for an attribute match */
+ const vector <saml2::AttributeStatement *> &statements =
+ const_cast<const saml2::Assertion *>(assertion)->getAttributeStatements();
+
+ for (vector<saml2::AttributeStatement *>::const_iterator s = statements.begin();
+ s != statements.end();
+ ++s) {
+ const vector<saml2::Attribute*> &attrs =
+ const_cast<const saml2::AttributeStatement*>(*s)->getAttributes();
+
+ for (vector<saml2::Attribute*>::const_iterator a = attrs.begin(); a != attrs.end(); ++a) {
+ const XMLCh *attributeName = (*a)->getName();
+ const XMLCh *attributeNameFormat = (*a)->getNameFormat();
+ XMLCh *qualifiedName;
+ XMLCh space[2] = { ' ', 0 };
+ gss_buffer_desc utf8;
+ bool ret;
+
+ qualifiedName = new XMLCh[XMLString::stringLen(attributeNameFormat) + 1 +
+ XMLString::stringLen(attributeName) + 1];
+ XMLString::copyString(qualifiedName, attributeNameFormat);
+ XMLString::catString(qualifiedName, space);
+ XMLString::catString(qualifiedName, attributeName);
+
+ utf8.value = (void *)toUTF8(qualifiedName);
+ utf8.length = strlen((char *)utf8.value);
+
+ ret = addAttribute(this, &utf8, data);
+
+ delete qualifiedName;
+
+ if (!ret)
+ return ret;
+ }
+ }
+
+ return true;
+}
+
+static BaseRefVectorOf<XMLCh> *
+decomposeAttributeName(const gss_buffer_t attr)
+{
+ XMLCh *qualifiedAttr = new XMLCh[attr->length + 1];
+ XMLString::transcode((const char *)attr->value, qualifiedAttr, attr->length);
+
+ BaseRefVectorOf<XMLCh> *components = XMLString::tokenizeString(qualifiedAttr);
+
+ delete qualifiedAttr;
+
+ if (components->size() != 2) {
+ delete components;
+ components = NULL;
+ }
+
+ return components;
+}
+
+bool
+gss_eap_saml_attr_provider::setAttribute(int complete,
+ const gss_buffer_t attr,
+ const gss_buffer_t value)
+{
+ saml2::Assertion *assertion;
+ saml2::Attribute *attribute;
+ saml2::AttributeValue *attributeValue;
+ saml2::AttributeStatement *attributeStatement;
+
+ if (!getAssertion(NULL, &assertion, true))
+ return false;
+
+ if (assertion->getAttributeStatements().size() != 0) {
+ attributeStatement = assertion->getAttributeStatements().front();
+ } else {
+ attributeStatement = saml2::AttributeStatementBuilder::buildAttributeStatement();
+ assertion->getAttributeStatements().push_back(attributeStatement);
+ }
+
+ /* Check the attribute name consists of name format | whsp | name */
+ BaseRefVectorOf<XMLCh> *components = decomposeAttributeName(attr);
+ if (components == NULL)
+ return false;
+
+ attribute = saml2::AttributeBuilder::buildAttribute();
+ attribute->setNameFormat(components->elementAt(0));
+ attribute->setName(components->elementAt(1));
+
+ XMLCh *xmlValue = new XMLCh[value->length + 1];
+ XMLString::transcode((const char *)value->value, xmlValue, attr->length);
+
+ attributeValue = saml2::AttributeValueBuilder::buildAttributeValue();
+ attributeValue->setTextContent(xmlValue);
+
+ attribute->getAttributeValues().push_back(attributeValue);
+
+ assert(attributeStatement != NULL);
+ attributeStatement->getAttributes().push_back(attribute);
+
+ delete components;
+ delete xmlValue;
+
+ return true;
+}
+
+bool
+gss_eap_saml_attr_provider::deleteAttribute(const gss_buffer_t attr)
+{
+ saml2::Assertion *assertion;
+ bool ret = false;
+
+ if (!getAssertion(NULL, &assertion) ||
+ assertion->getAttributeStatements().size() == 0)
+ return false;
+
+ /* Check the attribute name consists of name format | whsp | name */
+ BaseRefVectorOf<XMLCh> *components = decomposeAttributeName(attr);
+ if (components == NULL)
+ return false;
+
+ /* For each attribute statement, look for an attribute match */
+ const vector<saml2::AttributeStatement *> &statements =
+ const_cast<const saml2::Assertion *>(assertion)->getAttributeStatements();
+
+ for (vector<saml2::AttributeStatement *>::const_iterator s = statements.begin();
+ s != statements.end();
+ ++s) {
+ const vector<saml2::Attribute *> &attrs =
+ const_cast<const saml2::AttributeStatement *>(*s)->getAttributes();
+ ssize_t index = -1, i = 0;
+
+ /* There's got to be an easier way to do this */
+ for (vector<saml2::Attribute *>::const_iterator a = attrs.begin();
+ a != attrs.end();
+ ++a) {
+ if (XMLString::equals((*a)->getNameFormat(), components->elementAt(0)) &&
+ XMLString::equals((*a)->getName(), components->elementAt(1))) {
+ index = i;
+ break;
+ }
+ ++i;
+ }
+ if (index != -1) {
+ (*s)->getAttributes().erase((*s)->getAttributes().begin() + index);
+ ret = true;
+ }
+ }
+
+ delete components;
+
+ return ret;
+}
+
+bool
+gss_eap_saml_attr_provider::getAttribute(const gss_buffer_t attr,
+ int *authenticated,
+ int *complete,
+ const saml2::Attribute **pAttribute) const
+{
+ saml2::Assertion *assertion;
+
+ if (authenticated != NULL)
+ *authenticated = false;
+ if (complete != NULL)
+ *complete = true;
+ *pAttribute = NULL;
+
+ if (!getAssertion(authenticated, &assertion) ||
+ assertion->getAttributeStatements().size() == 0)
+ return false;
+
+ /* Check the attribute name consists of name format | whsp | name */
+ BaseRefVectorOf<XMLCh> *components = decomposeAttributeName(attr);
+ if (components == NULL)
+ return false;
+
+ /* For each attribute statement, look for an attribute match */
+ const vector <saml2::AttributeStatement *> &statements =
+ const_cast<const saml2::Assertion *>(assertion)->getAttributeStatements();
+ const saml2::Attribute *ret = NULL;
+
+ for (vector<saml2::AttributeStatement *>::const_iterator s = statements.begin();
+ s != statements.end();
+ ++s) {
+ const vector<saml2::Attribute *> &attrs =
+ const_cast<const saml2::AttributeStatement*>(*s)->getAttributes();
+
+ for (vector<saml2::Attribute *>::const_iterator a = attrs.begin(); a != attrs.end(); ++a) {
+ if (XMLString::equals((*a)->getNameFormat(), components->elementAt(0)) &&
+ XMLString::equals((*a)->getName(), components->elementAt(1))) {
+ ret = *a;
+ break;
+ }
+ }
+
+ if (ret != NULL)
+ break;
+ }
+
+ delete components;
+
+ *pAttribute = ret;
+
+ return (ret != NULL);
+}
+
+bool
+gss_eap_saml_attr_provider::getAttribute(const gss_buffer_t attr,
+ int *authenticated,
+ int *complete,
+ gss_buffer_t value,
+ gss_buffer_t display_value,
+ int *more) const
+{
+ const saml2::Attribute *a;
+ const saml2::AttributeValue *av;
+ int nvalues, i = *more;
+
+ *more = 0;
+
+ if (!getAttribute(attr, authenticated, complete, &a))
+ return false;
+
+ nvalues = a->getAttributeValues().size();
+
+ if (i == -1)
+ i = 0;
+ else if (i >= nvalues)
+ return false;
+#ifdef __APPLE__
+ av = (const saml2::AttributeValue *)((void *)(a->getAttributeValues().at(i)));
+#else
+ av = dynamic_cast<const saml2::AttributeValue *>(a->getAttributeValues().at(i));
+#endif
+ if (av != NULL) {
+ if (value != NULL) {
+ value->value = toUTF8(av->getTextContent(), true);
+ value->length = strlen((char *)value->value);
+ }
+ if (display_value != NULL) {
+ display_value->value = toUTF8(av->getTextContent(), true);
+ display_value->length = strlen((char *)value->value);
+ }
+ }
+
+ if (nvalues > ++i)
+ *more = i;
+
+ return true;
+}
+
+gss_any_t
+gss_eap_saml_attr_provider::mapToAny(int authenticated,
+ gss_buffer_t type_id) const
+{
+ return (gss_any_t)NULL;
+}
+
+void
+gss_eap_saml_attr_provider::releaseAnyNameMapping(gss_buffer_t type_id,
+ gss_any_t input) const
+{
+}
+
+void
+gss_eap_saml_attr_provider::exportToBuffer(gss_buffer_t buffer) const
+{
+ buffer->length = 0;
+ buffer->value = NULL;
+}
+
+bool
+gss_eap_saml_attr_provider::initFromBuffer(const gss_eap_attr_ctx *ctx,
+ const gss_buffer_t buffer)
+{
+ return gss_eap_attr_provider::initFromBuffer(ctx, buffer);
+}
+
+bool
+gss_eap_saml_attr_provider::init(void)
+{
+ gss_eap_attr_ctx::registerProvider(ATTR_TYPE_SAML,
+ "urn:ietf:params:gss-eap:saml-attr",
+ gss_eap_saml_attr_provider::createAttrContext);
+ return true;
+}
+
+void
+gss_eap_saml_attr_provider::finalize(void)
+{
+ gss_eap_attr_ctx::unregisterProvider(ATTR_TYPE_SAML);
+}
+
+gss_eap_attr_provider *
+gss_eap_saml_attr_provider::createAttrContext(void)
+{
+ return new gss_eap_saml_attr_provider;
+}
+
+OM_uint32
+gssEapSamlAttrProvidersInit(OM_uint32 *minor)
+{
+ if (!gss_eap_saml_assertion_provider::init() ||
+ !gss_eap_saml_attr_provider::init()) {
+ *minor = GSSEAP_SAML_INIT_FAILURE;
+ return GSS_S_FAILURE;
+ }
+
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gssEapSamlAttrProvidersFinalize(OM_uint32 *minor)
+{
+ gss_eap_saml_attr_provider::finalize();
+ gss_eap_saml_assertion_provider::finalize();
+ return GSS_S_COMPLETE;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * SAML attribute provider.
+ */
+
+#ifndef _UTIL_SAML_H_
+#define _UTIL_SAML_H_ 1
+
+#ifdef __cplusplus
+
+namespace opensaml {
+ namespace saml2 {
+ class Attribute;
+ class Assertion;
+ class NameID;
+ };
+};
+
+struct gss_eap_saml_assertion_provider : gss_eap_attr_provider {
+public:
+ gss_eap_saml_assertion_provider(void);
+ ~gss_eap_saml_assertion_provider(void);
+
+ bool initFromExistingContext(const gss_eap_attr_ctx *source,
+ const gss_eap_attr_provider *ctx);
+ bool initFromGssContext(const gss_eap_attr_ctx *source,
+ const gss_cred_id_t cred,
+ const gss_ctx_id_t ctx);
+
+ bool getAttributeTypes(gss_eap_attr_enumeration_cb, void *data) const;
+ bool setAttribute(int complete,
+ const gss_buffer_t attr,
+ const gss_buffer_t value);
+ bool deleteAttribute(const gss_buffer_t value);
+ bool getAttribute(const gss_buffer_t attr,
+ int *authenticated,
+ int *complete,
+ gss_buffer_t value,
+ gss_buffer_t display_value,
+ int *more) const;
+ gss_any_t mapToAny(int authenticated,
+ gss_buffer_t type_id) const;
+ void releaseAnyNameMapping(gss_buffer_t type_id,
+ gss_any_t input) const;
+
+ void exportToBuffer(gss_buffer_t buffer) const;
+ bool initFromBuffer(const gss_eap_attr_ctx *ctx,
+ const gss_buffer_t buffer);
+
+ opensaml::saml2::Assertion *initAssertion(void);
+
+ opensaml::saml2::Assertion *getAssertion(void) const {
+ return m_assertion;
+ }
+ bool authenticated(void) const {
+ return m_authenticated;
+ }
+
+ time_t getExpiryTime(void) const;
+
+ static bool init(void);
+ static void finalize(void);
+
+ static gss_eap_attr_provider *createAttrContext(void);
+
+private:
+ static opensaml::saml2::Assertion *
+ parseAssertion(const gss_buffer_t buffer);
+
+ void setAssertion(const opensaml::saml2::Assertion *assertion,
+ bool authenticated = false);
+ void setAssertion(const gss_buffer_t buffer,
+ bool authenticated = false);
+
+ opensaml::saml2::Assertion *m_assertion;
+ bool m_authenticated;
+};
+
+struct gss_eap_saml_attr_provider : gss_eap_attr_provider {
+public:
+ gss_eap_saml_attr_provider(void) {}
+ ~gss_eap_saml_attr_provider(void) {}
+
+ bool getAttributeTypes(gss_eap_attr_enumeration_cb, void *data) const;
+ bool setAttribute(int complete,
+ const gss_buffer_t attr,
+ const gss_buffer_t value);
+ bool deleteAttribute(const gss_buffer_t value);
+ bool getAttribute(const gss_buffer_t attr,
+ int *authenticated,
+ int *complete,
+ gss_buffer_t value,
+ gss_buffer_t display_value,
+ int *more) const;
+ gss_any_t mapToAny(int authenticated,
+ gss_buffer_t type_id) const;
+ void releaseAnyNameMapping(gss_buffer_t type_id,
+ gss_any_t input) const;
+
+ void exportToBuffer(gss_buffer_t buffer) const;
+ bool initFromBuffer(const gss_eap_attr_ctx *ctx,
+ const gss_buffer_t buffer);
+
+ bool getAttribute(const gss_buffer_t attr,
+ int *authenticated,
+ int *complete,
+ const opensaml::saml2::Attribute **pAttribute) const;
+ bool getAssertion(int *authenticated,
+ opensaml::saml2::Assertion **pAssertion,
+ bool createIfAbsent = false) const;
+
+ static bool init(void);
+ static void finalize(void);
+
+ static gss_eap_attr_provider *createAttrContext(void);
+
+private:
+};
+
+extern "C" {
+#endif
+
+OM_uint32 gssEapSamlAttrProvidersInit(OM_uint32 *minor);
+OM_uint32 gssEapSamlAttrProvidersFinalize(OM_uint32 *minor);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _UTIL_SAML_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Copyright 2001-2009 Internet2
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Local attribute provider implementation.
+ */
+
+#include <shibsp/exceptions.h>
+#include <shibsp/attribute/SimpleAttribute.h>
+
+#include <shibresolver/resolver.h>
+
+#include <sstream>
+
+#include "gssapiP_eap.h"
+
+using namespace shibsp;
+using namespace shibresolver;
+using namespace opensaml::saml2md;
+using namespace opensaml;
+using namespace xmltooling;
+using namespace std;
+
+gss_eap_shib_attr_provider::gss_eap_shib_attr_provider(void)
+{
+ m_authenticated = false;
+}
+
+gss_eap_shib_attr_provider::~gss_eap_shib_attr_provider(void)
+{
+ for_each(m_attributes.begin(),
+ m_attributes.end(),
+ xmltooling::cleanup<Attribute>())
+ ;
+}
+
+bool
+gss_eap_shib_attr_provider::initFromExistingContext(const gss_eap_attr_ctx *manager,
+ const gss_eap_attr_provider *ctx)
+{
+ const gss_eap_shib_attr_provider *shib;
+
+ if (!gss_eap_attr_provider::initFromExistingContext(manager, ctx)) {
+ return false;
+ }
+
+ m_authenticated = false;
+
+ shib = static_cast<const gss_eap_shib_attr_provider *>(ctx);
+ if (shib != NULL) {
+ m_attributes = duplicateAttributes(shib->getAttributes());
+ m_authenticated = shib->authenticated();
+ }
+
+ return true;
+}
+
+bool
+addRadiusAttribute(const gss_eap_attr_provider *provider,
+ const gss_buffer_t attribute,
+ void *data)
+{
+ const gss_eap_shib_attr_provider *shib;
+ const gss_eap_radius_attr_provider *radius;
+ int authenticated, complete, more = -1;
+ vector <string> attributeIds(1);
+ SimpleAttribute *a;
+
+ radius = static_cast<const gss_eap_radius_attr_provider *>(provider);
+ shib = static_cast<const gss_eap_shib_attr_provider *>(data);
+
+ assert(radius != NULL && shib != NULL);
+
+ string attributeName =
+ gss_eap_attr_ctx::composeAttributeName(ATTR_TYPE_RADIUS, attribute);
+
+ attributeIds.push_back(attributeName);
+ a = new SimpleAttribute(attributeIds);
+ if (a == NULL)
+ return false;
+
+ while (more != 0) {
+ gss_buffer_desc value = GSS_C_EMPTY_BUFFER;
+ OM_uint32 minor;
+
+ if (!radius->getAttribute(attribute,
+ &authenticated,
+ &complete,
+ &value,
+ NULL,
+ &more))
+ return false;
+
+ string attributeValue((char *)value.value, value.length);
+ a->getValues().push_back(attributeValue);
+
+ gss_release_buffer(&minor, &value);
+ }
+
+ shib->getAttributes().push_back(a);
+
+ return true;
+}
+
+bool
+gss_eap_shib_attr_provider::initFromGssContext(const gss_eap_attr_ctx *manager,
+ const gss_cred_id_t gssCred,
+ const gss_ctx_id_t gssCtx)
+{
+ const gss_eap_saml_assertion_provider *saml;
+ const gss_eap_radius_attr_provider *radius;
+ gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
+ ShibbolethResolver *resolver;
+ OM_uint32 minor;
+
+ if (!gss_eap_attr_provider::initFromGssContext(manager, gssCred, gssCtx))
+ return false;
+
+ saml = static_cast<const gss_eap_saml_assertion_provider *>
+ (m_manager->getProvider(ATTR_TYPE_SAML_ASSERTION));
+ radius = static_cast<const gss_eap_radius_attr_provider *>
+ (m_manager->getProvider(ATTR_TYPE_RADIUS));
+
+ resolver = ShibbolethResolver::create();
+
+ if (gssCred != GSS_C_NO_CREDENTIAL &&
+ gssEapDisplayName(&minor, gssCred->name, &nameBuf, NULL) == GSS_S_COMPLETE)
+ resolver->setApplicationID((const char *)nameBuf.value);
+
+ m_authenticated = false;
+
+ if (radius != NULL) {
+ radius->getAttributeTypes(addRadiusAttribute, (void *)this);
+ m_authenticated = radius->authenticated();
+ }
+
+ if (saml != NULL && saml->getAssertion() != NULL) {
+ resolver->addToken(saml->getAssertion());
+ if (m_authenticated)
+ m_authenticated = saml->authenticated();
+ }
+
+ resolver->resolve();
+
+ m_attributes = resolver->getResolvedAttributes();
+ resolver->getResolvedAttributes().clear();
+
+ gss_release_buffer(&minor, &nameBuf);
+
+ delete resolver;
+
+ return true;
+}
+
+ssize_t
+gss_eap_shib_attr_provider::getAttributeIndex(const gss_buffer_t attr) const
+{
+ int i = 0;
+
+ for (vector<Attribute *>::const_iterator a = m_attributes.begin();
+ a != m_attributes.end();
+ ++a)
+ {
+ for (vector<string>::const_iterator s = (*a)->getAliases().begin();
+ s != (*a)->getAliases().end();
+ ++s) {
+ if (attr->length == (*s).length() &&
+ memcmp((*s).c_str(), attr->value, attr->length) == 0) {
+ return i;
+ }
+ }
+ }
+
+ return -1;
+}
+
+bool
+gss_eap_shib_attr_provider::setAttribute(int complete,
+ const gss_buffer_t attr,
+ const gss_buffer_t value)
+{
+ string attrStr((char *)attr->value, attr->length);
+ vector <string> ids(1, attrStr);
+ SimpleAttribute *a = new SimpleAttribute(ids);
+
+ if (value->length != 0) {
+ string valueStr((char *)value->value, value->length);
+
+ a->getValues().push_back(valueStr);
+ }
+
+ m_attributes.push_back(a);
+ m_authenticated = false;
+
+ return true;
+}
+
+bool
+gss_eap_shib_attr_provider::deleteAttribute(const gss_buffer_t attr)
+{
+ int i;
+
+ i = getAttributeIndex(attr);
+ if (i >= 0)
+ m_attributes.erase(m_attributes.begin() + i);
+
+ m_authenticated = false;
+
+ return true;
+}
+
+bool
+gss_eap_shib_attr_provider::getAttributeTypes(gss_eap_attr_enumeration_cb addAttribute,
+ void *data) const
+{
+ for (vector<Attribute*>::const_iterator a = m_attributes.begin();
+ a != m_attributes.end();
+ ++a)
+ {
+ gss_buffer_desc attribute;
+
+ attribute.value = (void *)((*a)->getId());
+ attribute.length = strlen((char *)attribute.value);
+
+ if (!addAttribute(this, &attribute, data))
+ return false;
+ }
+
+ return true;
+}
+
+const Attribute *
+gss_eap_shib_attr_provider::getAttribute(const gss_buffer_t attr) const
+{
+ const Attribute *ret = NULL;
+
+ for (vector<Attribute *>::const_iterator a = m_attributes.begin();
+ a != m_attributes.end();
+ ++a)
+ {
+ for (vector<string>::const_iterator s = (*a)->getAliases().begin();
+ s != (*a)->getAliases().end();
+ ++s) {
+ if (attr->length == (*s).length() &&
+ memcmp((*s).c_str(), attr->value, attr->length) == 0) {
+ ret = *a;
+ break;
+ }
+ }
+ if (ret != NULL)
+ break;
+ }
+
+ return ret;
+}
+
+bool
+gss_eap_shib_attr_provider::getAttribute(const gss_buffer_t attr,
+ int *authenticated,
+ int *complete,
+ gss_buffer_t value,
+ gss_buffer_t display_value,
+ int *more) const
+{
+ const Attribute *shibAttr = NULL;
+ gss_buffer_desc buf;
+ int nvalues, i = *more;
+
+ *more = 0;
+
+ shibAttr = getAttribute(attr);
+ if (shibAttr == NULL)
+ return false;
+
+ nvalues = shibAttr->valueCount();
+
+ if (i == -1)
+ i = 0;
+ else if (i >= nvalues)
+ return false;
+
+ buf.value = (void *)shibAttr->getString(*more);
+ buf.length = strlen((char *)buf.value);
+
+ if (buf.length != 0) {
+ if (value != NULL)
+ duplicateBuffer(buf, value);
+
+ if (display_value != NULL)
+ duplicateBuffer(buf, display_value);
+ }
+
+ if (authenticated != NULL)
+ *authenticated = m_authenticated;
+ if (complete != NULL)
+ *complete = false;
+
+ if (nvalues > ++i)
+ *more = i;
+
+ return true;
+}
+
+gss_any_t
+gss_eap_shib_attr_provider::mapToAny(int authenticated,
+ gss_buffer_t type_id) const
+{
+ gss_any_t output;
+
+ if (authenticated && !m_authenticated)
+ return (gss_any_t)NULL;
+
+ vector <Attribute *>v = duplicateAttributes(m_attributes);
+
+ output = (gss_any_t)new vector <Attribute *>(v);
+
+ return output;
+}
+
+void
+gss_eap_shib_attr_provider::releaseAnyNameMapping(gss_buffer_t type_id,
+ gss_any_t input) const
+{
+ vector <Attribute *> *v = ((vector <Attribute *> *)input);
+ delete v;
+}
+
+void
+gss_eap_shib_attr_provider::exportToBuffer(gss_buffer_t buffer) const
+{
+ DDF obj(NULL);
+ DDF attrs(NULL);
+
+ buffer->length = 0;
+ buffer->value = NULL;
+
+ obj.addmember("version").integer(1);
+ obj.addmember("authenticated").integer(m_authenticated);
+
+ attrs = obj.addmember("attributes").list();
+ for (vector<Attribute*>::const_iterator a = m_attributes.begin();
+ a != m_attributes.end(); ++a) {
+ DDF attr = (*a)->marshall();
+ attrs.add(attr);
+ }
+
+ ostringstream sink;
+ sink << attrs;
+ string str = sink.str();
+
+ duplicateBuffer(str, buffer);
+
+ attrs.destroy();
+}
+
+bool
+gss_eap_shib_attr_provider::initFromBuffer(const gss_eap_attr_ctx *ctx,
+ const gss_buffer_t buffer)
+{
+ if (!gss_eap_attr_provider::initFromBuffer(ctx, buffer))
+ return false;
+
+ if (buffer->length == 0)
+ return true;
+
+ assert(m_authenticated == false);
+ assert(m_attributes.size() == 0);
+
+ DDF obj(NULL);
+ string str((const char *)buffer->value, buffer->length);
+ istringstream source(str);
+
+ source >> obj;
+
+ if (obj["version"].integer() != 1)
+ return false;
+
+ m_authenticated = (obj["authenticated"].integer() != 0);
+
+ DDF attrs = obj["attributes"];
+ DDF attr = attrs.first();
+ while (!attr.isnull()) {
+ Attribute *attribute = Attribute::unmarshall(attr);
+ m_attributes.push_back(attribute);
+ attr = attrs.next();
+ }
+
+ attrs.destroy();
+
+ return true;
+}
+
+bool
+gss_eap_shib_attr_provider::init(void)
+{
+ if (!ShibbolethResolver::init())
+ return false;
+
+ gss_eap_attr_ctx::registerProvider(ATTR_TYPE_LOCAL,
+ NULL,
+ gss_eap_shib_attr_provider::createAttrContext);
+
+ return true;
+}
+
+void
+gss_eap_shib_attr_provider::finalize(void)
+{
+ gss_eap_attr_ctx::unregisterProvider(ATTR_TYPE_LOCAL);
+ ShibbolethResolver::term();
+}
+
+gss_eap_attr_provider *
+gss_eap_shib_attr_provider::createAttrContext(void)
+{
+ return new gss_eap_shib_attr_provider;
+}
+
+Attribute *
+gss_eap_shib_attr_provider::duplicateAttribute(const Attribute *src)
+{
+ DDF obj = src->marshall();
+ Attribute *attribute = Attribute::unmarshall(obj);
+ obj.destroy();
+
+ return attribute;
+}
+
+vector <Attribute *>
+gss_eap_shib_attr_provider::duplicateAttributes(const vector <Attribute *>src)
+{
+ vector <Attribute *> dst;
+
+ for (vector<Attribute *>::const_iterator a = src.begin();
+ a != src.end();
+ ++a)
+ dst.push_back(duplicateAttribute(*a));
+
+ return dst;
+}
+
+OM_uint32
+gssEapLocalAttrProviderInit(OM_uint32 *minor)
+{
+ if (!gss_eap_shib_attr_provider::init()) {
+ *minor = GSSEAP_SHIB_INIT_FAILURE;
+ return GSS_S_FAILURE;
+ }
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gssEapLocalAttrProviderFinalize(OM_uint32 *minor)
+{
+ gss_eap_shib_attr_provider::finalize();
+ return GSS_S_COMPLETE;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Local attribute provider.
+ */
+
+#ifndef _UTIL_SHIB_H_
+#define _UTIL_SHIB_H_ 1
+
+#ifdef __cplusplus
+
+#include <vector>
+
+namespace shibsp {
+ class Attribute;
+};
+
+namespace shibresolver {
+ class ShibbolethResolver;
+};
+
+struct gss_eap_shib_attr_provider : gss_eap_attr_provider {
+public:
+ gss_eap_shib_attr_provider(void);
+ ~gss_eap_shib_attr_provider(void);
+
+ bool initFromExistingContext(const gss_eap_attr_ctx *source,
+ const gss_eap_attr_provider *ctx);
+ bool initFromGssContext(const gss_eap_attr_ctx *source,
+ const gss_cred_id_t cred,
+ const gss_ctx_id_t ctx);
+
+ bool setAttribute(int complete,
+ const gss_buffer_t attr,
+ const gss_buffer_t value);
+ bool deleteAttribute(const gss_buffer_t value);
+ bool getAttributeTypes(gss_eap_attr_enumeration_cb, void *data) const;
+ bool getAttribute(const gss_buffer_t attr,
+ int *authenticated,
+ int *complete,
+ gss_buffer_t value,
+ gss_buffer_t display_value,
+ int *more) const;
+ gss_any_t mapToAny(int authenticated,
+ gss_buffer_t type_id) const;
+ void releaseAnyNameMapping(gss_buffer_t type_id,
+ gss_any_t input) const;
+
+ void exportToBuffer(gss_buffer_t buffer) const;
+ bool initFromBuffer(const gss_eap_attr_ctx *ctx,
+ const gss_buffer_t buffer);
+
+ static bool init(void);
+ static void finalize(void);
+
+ static gss_eap_attr_provider *createAttrContext(void);
+
+private:
+ static shibsp::Attribute *
+ duplicateAttribute(const shibsp::Attribute *src);
+ static std::vector <shibsp::Attribute *>
+ duplicateAttributes(const std::vector <shibsp::Attribute *>src);
+
+ ssize_t getAttributeIndex(const gss_buffer_t attr) const;
+ const shibsp::Attribute *getAttribute(const gss_buffer_t attr) const;
+
+ std::vector<shibsp::Attribute *> getAttributes(void) const {
+ return m_attributes;
+ }
+
+ bool authenticated(void) const { return m_authenticated; }
+
+ friend bool
+ addRadiusAttribute(const gss_eap_attr_provider *source,
+ const gss_buffer_t attribute,
+ void *data);
+
+ std::vector<shibsp::Attribute *> m_attributes;
+ int m_authenticated;
+};
+
+
+extern "C" {
+#endif
+
+OM_uint32 gssEapLocalAttrProviderInit(OM_uint32 *minor);
+OM_uint32 gssEapLocalAttrProviderFinalize(OM_uint32 *minor);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _UTIL_SHIB_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Utility routines for GSS tokens.
+ */
+
+#include "gssapiP_eap.h"
+
+/*
+ * $Id: util_token.c 23457 2009-12-08 00:04:48Z tlyu $
+ */
+
+/* XXXX this code currently makes the assumption that a mech oid will
+ never be longer than 127 bytes. This assumption is not inherent in
+ the interfaces, so the code can be fixed if the OSI namespace
+ balloons unexpectedly. */
+
+/*
+ * Each token looks like this:
+ * 0x60 tag for APPLICATION 0, SEQUENCE
+ * (constructed, definite-length)
+ * <length> possible multiple bytes, need to parse/generate
+ * 0x06 tag for OBJECT IDENTIFIER
+ * <moid_length> compile-time constant string (assume 1 byte)
+ * <moid_bytes> compile-time constant string
+ * <inner_bytes> the ANY containing the application token
+ * bytes 0,1 are the token type
+ * bytes 2,n are the token data
+ *
+ * Note that the token type field is a feature of RFC 1964 mechanisms and
+ * is not used by other GSSAPI mechanisms. As such, a token type of -1
+ * is interpreted to mean that no token type should be expected or
+ * generated.
+ *
+ * For the purposes of this abstraction, the token "header" consists of
+ * the sequence tag and length octets, the mech OID DER encoding, and the
+ * first two inner bytes, which indicate the token type. The token
+ * "body" consists of everything else.
+ */
+
+static size_t
+der_length_size(size_t length)
+{
+ if (length < (1<<7))
+ return 1;
+ else if (length < (1<<8))
+ return 2;
+#if INT_MAX == 0x7fff
+ else
+ return 3;
+#else
+ else if (length < (1<<16))
+ return 3;
+ else if (length < (1<<24))
+ return 4;
+ else
+ return 5;
+#endif
+}
+
+static void
+der_write_length(unsigned char **buf, size_t length)
+{
+ if (length < (1<<7)) {
+ *(*buf)++ = (unsigned char)length;
+ } else {
+ *(*buf)++ = (unsigned char)(der_length_size(length)+127);
+#if INT_MAX > 0x7fff
+ if (length >= (1<<24))
+ *(*buf)++ = (unsigned char)(length>>24);
+ if (length >= (1<<16))
+ *(*buf)++ = (unsigned char)((length>>16)&0xff);
+#endif
+ if (length >= (1<<8))
+ *(*buf)++ = (unsigned char)((length>>8)&0xff);
+ *(*buf)++ = (unsigned char)(length&0xff);
+ }
+}
+
+/* returns decoded length, or < 0 on failure. Advances buf and
+ decrements bufsize */
+
+static int
+der_read_length(unsigned char **buf, ssize_t *bufsize)
+{
+ unsigned char sf;
+ int ret;
+
+ if (*bufsize < 1)
+ return -1;
+
+ sf = *(*buf)++;
+ (*bufsize)--;
+ if (sf & 0x80) {
+ if ((sf &= 0x7f) > ((*bufsize)-1))
+ return -1;
+ if (sf > sizeof(int))
+ return -1;
+ ret = 0;
+ for (; sf; sf--) {
+ ret = (ret<<8) + (*(*buf)++);
+ (*bufsize)--;
+ }
+ } else {
+ ret = sf;
+ }
+
+ return ret;
+}
+
+/* returns the length of a token, given the mech oid and the body size */
+
+size_t
+tokenSize(const gss_OID_desc *mech, size_t body_size)
+{
+ /* set body_size to sequence contents size */
+ body_size += 4 + (size_t) mech->length; /* NEED overflow check */
+ return 1 + der_length_size(body_size) + body_size;
+}
+
+/* fills in a buffer with the token header. The buffer is assumed to
+ be the right size. buf is advanced past the token header */
+
+void
+makeTokenHeader(
+ const gss_OID_desc *mech,
+ size_t body_size,
+ unsigned char **buf,
+ enum gss_eap_token_type tok_type)
+{
+ *(*buf)++ = 0x60;
+ der_write_length(buf, (tok_type == -1) ?2:4 + mech->length + body_size);
+ *(*buf)++ = 0x06;
+ *(*buf)++ = (unsigned char)mech->length;
+ memcpy(*buf, mech->elements, mech->length);
+ *buf += mech->length;
+ assert(tok_type != TOK_TYPE_NONE);
+ *(*buf)++ = (unsigned char)((tok_type>>8) & 0xff);
+ *(*buf)++ = (unsigned char)(tok_type & 0xff);
+}
+
+/*
+ * Given a buffer containing a token, reads and verifies the token,
+ * leaving buf advanced past the token header, and setting body_size
+ * to the number of remaining bytes. Returns 0 on success,
+ * G_BAD_TOK_HEADER for a variety of errors, and G_WRONG_MECH if the
+ * mechanism in the token does not match the mech argument. buf and
+ * *body_size are left unmodified on error.
+ */
+
+OM_uint32
+verifyTokenHeader(OM_uint32 *minor,
+ gss_OID mech,
+ size_t *body_size,
+ unsigned char **buf_in,
+ size_t toksize_in,
+ enum gss_eap_token_type *ret_tok_type)
+{
+ unsigned char *buf = *buf_in;
+ ssize_t seqsize;
+ gss_OID_desc toid;
+ ssize_t toksize = (ssize_t)toksize_in;
+
+ *minor = GSSEAP_BAD_TOK_HEADER;
+
+ if (ret_tok_type != NULL)
+ *ret_tok_type = TOK_TYPE_NONE;
+
+ if ((toksize -= 1) < 0)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ if (*buf++ != 0x60)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ seqsize = der_read_length(&buf, &toksize);
+ if (seqsize < 0)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ if (seqsize != toksize)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ if ((toksize -= 1) < 0)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ if (*buf++ != 0x06)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ if ((toksize -= 1) < 0)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ toid.length = *buf++;
+
+ if ((toksize -= toid.length) < 0)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ toid.elements = buf;
+ buf += toid.length;
+
+ if (mech->elements == NULL) {
+ *mech = toid;
+ if (toid.length == 0)
+ return GSS_S_BAD_MECH;
+ } else if (!oidEqual(&toid, mech)) {
+ *minor = GSSEAP_WRONG_MECH;
+ return GSS_S_BAD_MECH;
+ }
+
+ if (ret_tok_type != NULL) {
+ if ((toksize -= 2) < 0)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ *ret_tok_type = load_uint16_be(buf);
+ buf += 2;
+ }
+
+ *buf_in = buf;
+ *body_size = toksize;
+
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Message protection services: verify a message integrity check.
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32
+gss_verify_mic(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ gss_buffer_t message_buffer,
+ gss_buffer_t message_token,
+ gss_qop_t *qop_state)
+{
+ OM_uint32 major;
+ gss_iov_buffer_desc iov[3];
+ int conf_state;
+
+ if (message_token->length < 16) {
+ *minor = GSSEAP_TOK_TRUNC;
+ return GSS_S_BAD_SIG;
+ }
+
+ *minor = 0;
+
+ iov[0].type = GSS_IOV_BUFFER_TYPE_DATA;
+ iov[0].buffer = *message_buffer;
+
+ iov[1].type = GSS_IOV_BUFFER_TYPE_HEADER;
+ iov[1].buffer.length = 16;
+ iov[1].buffer.value = message_token->value;
+
+ iov[2].type = GSS_IOV_BUFFER_TYPE_TRAILER;
+ iov[2].buffer.length = message_token->length - 16;
+ iov[2].buffer.value = (unsigned char *)message_token->value + 16;
+
+ GSSEAP_MUTEX_LOCK(&ctx->mutex);
+
+ major = gssEapUnwrapOrVerifyMIC(minor, ctx, &conf_state, qop_state,
+ iov, 3, TOK_TYPE_MIC);
+
+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
+
+ return major;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Message protection services: wrap.
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32
+gss_wrap(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ gss_buffer_t input_message_buffer,
+ int *conf_state,
+ gss_buffer_t output_message_buffer)
+{
+ OM_uint32 major;
+
+ if (ctx == GSS_C_NO_CONTEXT) {
+ *minor = EINVAL;
+ return GSS_S_NO_CONTEXT;
+ }
+
+ *minor = 0;
+
+ GSSEAP_MUTEX_LOCK(&ctx->mutex);
+
+ if (!CTX_IS_ESTABLISHED(ctx)) {
+ major = GSS_S_NO_CONTEXT;
+ *minor = GSSEAP_CONTEXT_INCOMPLETE;
+ goto cleanup;
+ }
+
+ major = gssEapWrap(minor, ctx, conf_req_flag, qop_req,
+ input_message_buffer,
+ conf_state, output_message_buffer);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+cleanup:
+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
+
+ return major;
+}
+
+OM_uint32
+gssEapWrap(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ gss_buffer_t input_message_buffer,
+ int *conf_state,
+ gss_buffer_t output_message_buffer)
+{
+ OM_uint32 major, tmpMinor;
+ gss_iov_buffer_desc iov[4];
+ unsigned char *p;
+ int i;
+
+ iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
+ iov[0].buffer.value = NULL;
+ iov[0].buffer.length = 0;
+
+ iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
+ iov[1].buffer = *input_message_buffer;
+
+ iov[2].type = GSS_IOV_BUFFER_TYPE_PADDING;
+ iov[2].buffer.value = NULL;
+ iov[2].buffer.length = 0;
+
+ iov[3].type = GSS_IOV_BUFFER_TYPE_TRAILER;
+ iov[3].buffer.value = NULL;
+ iov[3].buffer.length = 0;
+
+ major = gssEapWrapIovLength(minor, ctx, conf_req_flag, qop_req,
+ NULL, iov, 4);
+ if (GSS_ERROR(major)) {
+ return major;
+ }
+
+ for (i = 0, output_message_buffer->length = 0; i < 4; i++) {
+ output_message_buffer->length += iov[i].buffer.length;
+ }
+
+ output_message_buffer->value = GSSEAP_MALLOC(output_message_buffer->length);
+ if (output_message_buffer->value == NULL) {
+ *minor = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ for (i = 0, p = output_message_buffer->value; i < 4; i++) {
+ if (iov[i].type == GSS_IOV_BUFFER_TYPE_DATA) {
+ memcpy(p, input_message_buffer->value, input_message_buffer->length);
+ }
+ iov[i].buffer.value = p;
+ p += iov[i].buffer.length;
+ }
+
+ major = gssEapWrapOrGetMIC(minor, ctx, conf_req_flag, conf_state,
+ iov, 4, TOK_TYPE_WRAP);
+ if (GSS_ERROR(major)) {
+ gss_release_buffer(&tmpMinor, output_message_buffer);
+ }
+
+ return major;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Copyright 2008 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+/*
+ * Message protection services: wrap with scatter-gather API.
+ */
+
+#include "gssapiP_eap.h"
+
+unsigned char
+rfc4121Flags(gss_ctx_id_t ctx, int receiving)
+{
+ unsigned char flags;
+ int isAcceptor;
+
+ isAcceptor = !CTX_IS_INITIATOR(ctx);
+ if (receiving)
+ isAcceptor = !isAcceptor;
+
+ flags = 0;
+ if (isAcceptor)
+ flags |= TOK_FLAG_SENDER_IS_ACCEPTOR;
+
+ if ((ctx->flags & CTX_FLAG_KRB_REAUTH_GSS) &&
+ (ctx->gssFlags & GSS_C_MUTUAL_FLAG))
+ flags |= TOK_FLAG_ACCEPTOR_SUBKEY;
+
+ return flags;
+}
+
+OM_uint32
+gssEapWrapOrGetMIC(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ int conf_req_flag,
+ int *conf_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ enum gss_eap_token_type toktype)
+{
+ krb5_error_code code = 0;
+ gss_iov_buffer_t header;
+ gss_iov_buffer_t padding;
+ gss_iov_buffer_t trailer;
+ unsigned char flags;
+ unsigned char *outbuf = NULL;
+ unsigned char *tbuf = NULL;
+ int keyUsage;
+ size_t rrc = 0;
+ unsigned int gssHeaderLen, gssTrailerLen;
+ size_t dataLen, assocDataLen;
+ krb5_context krbContext;
+
+ if (ctx->encryptionType == ENCTYPE_NULL) {
+ *minor = GSSEAP_KEY_UNAVAILABLE;
+ return GSS_S_UNAVAILABLE;
+ }
+
+ GSSEAP_KRB_INIT(&krbContext);
+
+ flags = rfc4121Flags(ctx, FALSE);
+
+ if (toktype == TOK_TYPE_WRAP) {
+ keyUsage = CTX_IS_INITIATOR(ctx)
+ ? KEY_USAGE_INITIATOR_SEAL
+ : KEY_USAGE_ACCEPTOR_SEAL;
+ } else {
+ keyUsage = CTX_IS_INITIATOR(ctx)
+ ? KEY_USAGE_INITIATOR_SIGN
+ : KEY_USAGE_ACCEPTOR_SIGN;
+ }
+
+ gssEapIovMessageLength(iov, iov_count, &dataLen, &assocDataLen);
+
+ header = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
+ if (header == NULL) {
+ *minor = GSSEAP_MISSING_IOV;
+ return GSS_S_FAILURE;
+ }
+
+ padding = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
+ if (padding != NULL)
+ padding->buffer.length = 0;
+
+ trailer = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
+
+ if (toktype == TOK_TYPE_WRAP && conf_req_flag) {
+ unsigned int krbHeaderLen, krbTrailerLen, krbPadLen;
+ size_t ec = 0;
+ size_t confDataLen = dataLen - assocDataLen;
+
+ code = krb5_c_crypto_length(krbContext, ctx->encryptionType,
+ KRB5_CRYPTO_TYPE_HEADER, &krbHeaderLen);
+ if (code != 0)
+ goto cleanup;
+
+ code = krb5_c_padding_length(krbContext, ctx->encryptionType,
+ confDataLen + 16 /* E(Header) */,
+ &krbPadLen);
+ if (code != 0)
+ goto cleanup;
+
+ if (krbPadLen == 0 && (ctx->gssFlags & GSS_C_DCE_STYLE)) {
+ /* Windows rejects AEAD tokens with non-zero EC */
+ code = krb5_c_block_size(krbContext, ctx->encryptionType, &ec);
+ if (code != 0)
+ goto cleanup;
+ } else
+ ec = krbPadLen;
+
+ code = krb5_c_crypto_length(krbContext, ctx->encryptionType,
+ KRB5_CRYPTO_TYPE_TRAILER, &krbTrailerLen);
+ if (code != 0)
+ goto cleanup;
+
+ gssHeaderLen = 16 /* Header */ + krbHeaderLen;
+ gssTrailerLen = ec + 16 /* E(Header) */ + krbTrailerLen;
+
+ if (trailer == NULL) {
+ rrc = gssTrailerLen;
+ /* Workaround for Windows bug where it rotates by EC + RRC */
+ if (ctx->gssFlags & GSS_C_DCE_STYLE)
+ rrc -= ec;
+ gssHeaderLen += gssTrailerLen;
+ }
+
+ if (header->type & GSS_IOV_BUFFER_FLAG_ALLOCATE) {
+ code = gssEapAllocIov(header, (size_t)gssHeaderLen);
+ } else if (header->buffer.length < gssHeaderLen)
+ code = GSSEAP_WRONG_SIZE;
+ if (code != 0)
+ goto cleanup;
+ outbuf = (unsigned char *)header->buffer.value;
+ header->buffer.length = (size_t)gssHeaderLen;
+
+ if (trailer != NULL) {
+ if (trailer->type & GSS_IOV_BUFFER_FLAG_ALLOCATE)
+ code = gssEapAllocIov(trailer, (size_t)gssTrailerLen);
+ else if (trailer->buffer.length < gssTrailerLen)
+ code = GSSEAP_WRONG_SIZE;
+ if (code != 0)
+ goto cleanup;
+ trailer->buffer.length = (size_t)gssTrailerLen;
+ }
+
+ /* TOK_ID */
+ store_uint16_be((uint16_t)toktype, outbuf);
+ /* flags */
+ outbuf[2] = flags
+ | (conf_req_flag ? TOK_FLAG_WRAP_CONFIDENTIAL : 0);
+ /* filler */
+ outbuf[3] = 0xFF;
+ /* EC */
+ store_uint16_be(ec, outbuf + 4);
+ /* RRC */
+ store_uint16_be(0, outbuf + 6);
+ store_uint64_be(ctx->sendSeq, outbuf + 8);
+
+ /*
+ * EC | copy of header to be encrypted, located in
+ * (possibly rotated) trailer
+ */
+ if (trailer == NULL)
+ tbuf = (unsigned char *)header->buffer.value + 16; /* Header */
+ else
+ tbuf = (unsigned char *)trailer->buffer.value;
+
+ memset(tbuf, 0xFF, ec);
+ memcpy(tbuf + ec, header->buffer.value, 16);
+
+ code = gssEapEncrypt(krbContext,
+ ((ctx->gssFlags & GSS_C_DCE_STYLE) != 0),
+ ec, rrc, &ctx->rfc3961Key,
+ keyUsage, 0, iov, iov_count);
+ if (code != 0)
+ goto cleanup;
+
+ /* RRC */
+ store_uint16_be(rrc, outbuf + 6);
+
+ ctx->sendSeq++;
+ } else if (toktype == TOK_TYPE_WRAP && !conf_req_flag) {
+ wrap_with_checksum:
+
+ gssHeaderLen = 16;
+
+ code = krb5_c_crypto_length(krbContext, ctx->encryptionType,
+ KRB5_CRYPTO_TYPE_CHECKSUM,
+ &gssTrailerLen);
+ if (code != 0)
+ goto cleanup;
+
+ assert(gssTrailerLen <= 0xFFFF);
+
+ if (trailer == NULL) {
+ rrc = gssTrailerLen;
+ gssHeaderLen += gssTrailerLen;
+ }
+
+ if (header->type & GSS_IOV_BUFFER_FLAG_ALLOCATE)
+ code = gssEapAllocIov(header, (size_t)gssHeaderLen);
+ else if (header->buffer.length < gssHeaderLen)
+ code = GSSEAP_WRONG_SIZE;
+ if (code != 0)
+ goto cleanup;
+ outbuf = (unsigned char *)header->buffer.value;
+ header->buffer.length = (size_t)gssHeaderLen;
+
+ if (trailer != NULL) {
+ if (trailer->type & GSS_IOV_BUFFER_FLAG_ALLOCATE)
+ code = gssEapAllocIov(trailer, (size_t)gssTrailerLen);
+ else if (trailer->buffer.length < gssTrailerLen)
+ code = GSSEAP_WRONG_SIZE;
+ if (code != 0)
+ goto cleanup;
+ trailer->buffer.length = (size_t)gssTrailerLen;
+ }
+
+ /* TOK_ID */
+ store_uint16_be((uint16_t)toktype, outbuf);
+ /* flags */
+ outbuf[2] = flags;
+ /* filler */
+ outbuf[3] = 0xFF;
+ if (toktype == TOK_TYPE_WRAP) {
+ /* Use 0 for checksum calculation, substitute
+ * checksum length later.
+ */
+ /* EC */
+ store_uint16_be(0, outbuf + 4);
+ /* RRC */
+ store_uint16_be(0, outbuf + 6);
+ } else {
+ /* MIC and DEL store 0xFF in EC and RRC */
+ store_uint16_be(0xFFFF, outbuf + 4);
+ store_uint16_be(0xFFFF, outbuf + 6);
+ }
+ store_uint64_be(ctx->sendSeq, outbuf + 8);
+
+ code = gssEapSign(krbContext, ctx->checksumType,
+ rrc, &ctx->rfc3961Key, keyUsage,
+ iov, iov_count);
+ if (code != 0)
+ goto cleanup;
+
+ ctx->sendSeq++;
+
+ if (toktype == TOK_TYPE_WRAP) {
+ /* Fix up EC field */
+ store_uint16_be(gssTrailerLen, outbuf + 4);
+ /* Fix up RRC field */
+ store_uint16_be(rrc, outbuf + 6);
+ }
+ } else if (toktype == TOK_TYPE_MIC) {
+ trailer = NULL;
+ goto wrap_with_checksum;
+ } else if (toktype == TOK_TYPE_DELETE_CONTEXT) {
+ trailer = NULL;
+ goto wrap_with_checksum;
+ } else {
+ abort();
+ }
+
+ code = 0;
+
+cleanup:
+ if (code != 0)
+ gssEapReleaseIov(iov, iov_count);
+
+ *minor = code;
+
+ return (code == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
+}
+
+OM_uint32
+gss_wrap_iov(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ int *conf_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count)
+{
+ OM_uint32 major;
+
+ if (ctx == GSS_C_NO_CONTEXT) {
+ *minor = EINVAL;
+ return GSS_S_NO_CONTEXT;
+ }
+
+ if (qop_req != GSS_C_QOP_DEFAULT) {
+ *minor = GSSEAP_UNKNOWN_QOP;
+ return GSS_S_UNAVAILABLE;
+ }
+
+ *minor = 0;
+
+ GSSEAP_MUTEX_LOCK(&ctx->mutex);
+
+ if (!CTX_IS_ESTABLISHED(ctx)) {
+ major = GSS_S_NO_CONTEXT;
+ *minor = GSSEAP_CONTEXT_INCOMPLETE;
+ goto cleanup;
+ }
+
+ major = gssEapWrapOrGetMIC(minor, ctx, conf_req_flag, conf_state,
+ iov, iov_count, TOK_TYPE_WRAP);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+cleanup:
+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
+
+ return major;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Copyright 2008 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+/*
+ * Message protection services: determine protected message size.
+ */
+
+#include "gssapiP_eap.h"
+
+#define INIT_IOV_DATA(_iov) do { (_iov)->buffer.value = NULL; \
+ (_iov)->buffer.length = 0; } \
+ while (0)
+
+OM_uint32
+gssEapWrapIovLength(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ int *conf_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count)
+{
+ gss_iov_buffer_t header, trailer, padding;
+ size_t dataLength, assocDataLength;
+ size_t gssHeaderLen, gssPadLen, gssTrailerLen;
+ unsigned int krbHeaderLen = 0, krbTrailerLen = 0, krbPadLen = 0;
+ krb5_error_code code;
+ krb5_context krbContext;
+ int dce_style;
+ size_t ec;
+
+ if (qop_req != GSS_C_QOP_DEFAULT) {
+ *minor = GSSEAP_UNKNOWN_QOP;
+ return GSS_S_UNAVAILABLE;
+ }
+
+ if (ctx->encryptionType == ENCTYPE_NULL) {
+ *minor = GSSEAP_KEY_UNAVAILABLE;
+ return GSS_S_UNAVAILABLE;
+ }
+
+ GSSEAP_KRB_INIT(&krbContext);
+
+ header = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
+ if (header == NULL) {
+ *minor = GSSEAP_MISSING_IOV;
+ return GSS_S_FAILURE;
+ }
+ INIT_IOV_DATA(header);
+
+ trailer = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
+ if (trailer != NULL) {
+ INIT_IOV_DATA(trailer);
+ }
+
+ dce_style = ((ctx->gssFlags & GSS_C_DCE_STYLE) != 0);
+
+ /* For CFX, EC is used instead of padding, and is placed in header or trailer */
+ padding = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
+ if (padding != NULL) {
+ INIT_IOV_DATA(padding);
+ }
+
+ gssEapIovMessageLength(iov, iov_count, &dataLength, &assocDataLength);
+
+ if (conf_req_flag && gssEapIsIntegrityOnly(iov, iov_count))
+ conf_req_flag = FALSE;
+
+ gssHeaderLen = gssPadLen = gssTrailerLen = 0;
+
+ code = krb5_c_crypto_length(krbContext, ctx->encryptionType,
+ conf_req_flag ?
+ KRB5_CRYPTO_TYPE_TRAILER : KRB5_CRYPTO_TYPE_CHECKSUM,
+ &krbTrailerLen);
+ if (code != 0) {
+ *minor = code;
+ return GSS_S_FAILURE;
+ }
+
+ if (conf_req_flag) {
+ code = krb5_c_crypto_length(krbContext, ctx->encryptionType,
+ KRB5_CRYPTO_TYPE_HEADER, &krbHeaderLen);
+ if (code != 0) {
+ *minor = code;
+ return GSS_S_FAILURE;
+ }
+ }
+
+ gssHeaderLen = 16; /* Header */
+ if (conf_req_flag) {
+ gssHeaderLen += krbHeaderLen; /* Kerb-Header */
+ gssTrailerLen = 16 /* E(Header) */ + krbTrailerLen; /* Kerb-Trailer */
+
+ code = krb5_c_padding_length(krbContext, ctx->encryptionType,
+ dataLength - assocDataLength + 16 /* E(Header) */,
+ &krbPadLen);
+ if (code != 0) {
+ *minor = code;
+ return GSS_S_FAILURE;
+ }
+
+ if (krbPadLen == 0 && dce_style) {
+ /* Windows rejects AEAD tokens with non-zero EC */
+ code = krb5_c_block_size(krbContext, ctx->encryptionType, &ec);
+ if (code != 0) {
+ *minor = code;
+ return GSS_S_FAILURE;
+ }
+ } else
+ ec = krbPadLen;
+
+ gssTrailerLen += ec;
+ } else {
+ gssTrailerLen = krbTrailerLen; /* Kerb-Checksum */
+ }
+
+ dataLength += gssPadLen;
+
+ if (trailer == NULL)
+ gssHeaderLen += gssTrailerLen;
+ else
+ trailer->buffer.length = gssTrailerLen;
+
+ assert(gssPadLen == 0 || padding != NULL);
+
+ if (padding != NULL)
+ padding->buffer.length = gssPadLen;
+
+ header->buffer.length = gssHeaderLen;
+
+ if (conf_state != NULL)
+ *conf_state = conf_req_flag;
+
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gss_wrap_iov_length(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ int *conf_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count)
+{
+ OM_uint32 major;
+
+ if (ctx == GSS_C_NO_CONTEXT) {
+ *minor = EINVAL;
+ return GSS_S_NO_CONTEXT;
+ }
+
+ *minor = 0;
+
+ GSSEAP_MUTEX_LOCK(&ctx->mutex);
+
+ if (!CTX_IS_ESTABLISHED(ctx)) {
+ major = GSS_S_NO_CONTEXT;
+ *minor = GSSEAP_CONTEXT_INCOMPLETE;
+ goto cleanup;
+ }
+
+ major = gssEapWrapIovLength(minor, ctx, conf_req_flag, qop_req,
+ conf_state, iov, iov_count);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+cleanup:
+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
+
+ return major;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Message protection services: determine maximum input size.
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32
+gss_wrap_size_limit(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ OM_uint32 req_output_size,
+ OM_uint32 *max_input_size)
+{
+ gss_iov_buffer_desc iov[4];
+ OM_uint32 major, overhead;
+
+ if (ctx == GSS_C_NO_CONTEXT) {
+ *minor = EINVAL;
+ return GSS_S_NO_CONTEXT;
+ }
+
+ *minor = 0;
+
+ GSSEAP_MUTEX_LOCK(&ctx->mutex);
+
+ if (!CTX_IS_ESTABLISHED(ctx)) {
+ major = GSS_S_NO_CONTEXT;
+ *minor = GSSEAP_CONTEXT_INCOMPLETE;
+ goto cleanup;
+ }
+
+ iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
+ iov[0].buffer.value = NULL;
+ iov[0].buffer.length = 0;
+
+ iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
+ iov[1].buffer.length = req_output_size;
+ iov[1].buffer.value = NULL;
+
+ iov[2].type = GSS_IOV_BUFFER_TYPE_PADDING;
+ iov[2].buffer.value = NULL;
+ iov[2].buffer.length = 0;
+
+ iov[3].type = GSS_IOV_BUFFER_TYPE_TRAILER;
+ iov[3].buffer.value = NULL;
+ iov[3].buffer.length = 0;
+
+ major = gssEapWrapIovLength(minor, ctx, conf_req_flag, qop_req,
+ NULL, iov, 4);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ overhead = iov[0].buffer.length + iov[3].buffer.length;
+
+ if (iov[2].buffer.length == 0 && overhead < req_output_size)
+ *max_input_size = req_output_size - overhead;
+ else
+ *max_input_size = 0;
+
+cleanup:
+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
+
+ return major;
+}