!build-aux/compile
mech_eap.spec
mech_eap*tar*
+*.lo
+*#
-AC_PREREQ([2.61])
-AC_INIT([mech_eap], [0.1], [bugs@project-moonshot.org])
+/AC_PREREQ([2.61])
+AC_INIT([mech_eap], [0.9], [bugs@project-moonshot.org])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_AUX_DIR([build-aux])
#endif /* CONFIG_NATIVE_WINDOWS */
#ifdef _MSC_VER
+#ifndef __cplusplus
#define inline __inline
+#endif
#undef vsnprintf
#define vsnprintf _vsnprintf
%global _moonshot_krb5 %{!?_moonshot_krb5:krb5-devel}%{?_moonshot_krb5}
Name: moonshot-gss-eap
Version: @VERSION@
-Release: 4%{?dist}
+Release: 3%{?dist}
Summary: Moonshot GSS-API Mechanism
Group: Security Tools
BuildRequires: moonshot-ui-devel
BuildRequires: jansson-devel
Requires: moonshot-ui
-BuildRequires: libradsec-devel
-BuildRequires: shibboleth-devel >= 2.5
+BuildRequires: libradsec-devel >= 0.0.3
+BuildRequires: shibboleth-sp-devel >= 2.5
BuildRequires: libshibresolver-devel
%build
- export LDFLAGS='-L/usr/%{_lib}/freeradius -Wl,--rpath=/usr/%{_lib}/freeradius'
-%configure --with-libmoonshot=%{_prefix} --with-krb5=%{_prefix} --disable-reauth
+%configure --with-libmoonshot=%{_prefix} --with-krb5=%{_prefix} --enable-reauth LDFLAGs="${LDFLAGS} -L/opt/shibboleth/%{_lib} -Wl,--rpath=/opt/shibboleth/%{_lib}" CPPFLAGS="${CPPFLAGS} -I/opt/shibboleth/include"
make %{?_smp_mflags}
%{_libdir}/gss/mech_eap.so
%exclude %{_libdir}/gss/mech_eap.la
%{_includedir}/gssapi/*.h
-#%exclude %{_libdir}/krb5/plugins/authdata/*la
+%exclude %{_libdir}/krb5/plugins/authdata/*
#%{_libdir}/krb5/plugins/authdata/*.so
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 22 1 18}" \
+% gss-client -port 5555 -spnego -mech "{1 3 6 1 5 5 15 1 1 18}" \
-user <user>@<realm> -pass <pass> <host> host@<host> \
"Testing GSS EAP"
% gss-server -port 5555 -export host@<host>
* Add a mapping from the PAC RADIUS attribute to urn:mspac: in the file
/usr/local/etc/shibboleth/attribute-map.xml:
- <GSSAPIAttribute name="urn:ietf:params:gss-eap:radius-avp urn:x-radius:1679163525"
- id="urn:mspac:" binary="true"/>
+ <GSSAPIAttribute name="urn:ietf:params:gss:radius-attribute 26.25622.133"
+ id="urn:mspac:" binary="true"/>
FreeRADIUS
----------
For the client, the GSS EAP mechanism can be specified on the command line:
-smbclient --password samba --mechanism 1.3.6.1.4.1.5322.22.1.18 '\\host\share'".
+smbclient --password samba --mechanism 1.3.6.1.5.5.15.1.1.18 '\\host\share'".
There is no Moonshot SSPI implementation as yet, so it is not possible to test
with a Windows client.
+- draft-ietf-radext-radius-extensions
- integration with initiator-side EAP channel bindings
- investigate initiator-side credential locking
- always intern OIDs so they never need to be freed
acceptReadyEap(OM_uint32 *minor, gss_ctx_id_t ctx, gss_cred_id_t cred)
{
OM_uint32 major, tmpMinor;
- VALUE_PAIR *vp;
+ rs_const_avp *vp;
gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
/* Cache encryption type derived from selected mechanism OID */
major = gssEapRadiusGetRawAvp(minor, ctx->acceptorCtx.vps,
PW_USER_NAME, 0, &vp);
- if (major == GSS_S_COMPLETE && vp->length) {
- nameBuf.length = vp->length;
- nameBuf.value = vp->vp_strvalue;
+ if (major == GSS_S_COMPLETE && rs_avp_length(vp) != 0) {
+ rs_avp_octets_value_byref((rs_avp *)vp,
+ (unsigned char **)&nameBuf.value,
+ &nameBuf.length);
} else {
ctx->gssFlags |= GSS_C_ANON_FLAG;
}
return major;
major = gssEapRadiusGetRawAvp(minor, ctx->acceptorCtx.vps,
- PW_MS_MPPE_SEND_KEY, VENDORPEC_MS, &vp);
+ PW_MS_MPPE_SEND_KEY, VENDORPEC_MICROSOFT, &vp);
if (GSS_ERROR(major)) {
*minor = GSSEAP_KEY_UNAVAILABLE;
return GSS_S_UNAVAILABLE;
}
major = gssEapDeriveRfc3961Key(minor,
- vp->vp_octets,
- vp->length,
+ rs_avp_octets_value_const_ptr(vp),
+ rs_avp_length(vp),
ctx->encryptionType,
&ctx->rfc3961Key);
if (GSS_ERROR(major))
static OM_uint32
setInitiatorIdentity(OM_uint32 *minor,
gss_ctx_id_t ctx,
- VALUE_PAIR **vps)
+ struct rs_packet *req)
{
OM_uint32 major, tmpMinor;
gss_buffer_desc nameBuf;
if (GSS_ERROR(major))
return major;
- major = gssEapRadiusAddAvp(minor, vps, PW_USER_NAME, 0, &nameBuf);
+ major = gssEapRadiusAddAvp(minor, req, PW_USER_NAME, 0, &nameBuf);
if (GSS_ERROR(major))
return major;
static OM_uint32
setAcceptorIdentity(OM_uint32 *minor,
gss_ctx_id_t ctx,
- VALUE_PAIR **vps)
+ struct rs_packet *req)
{
OM_uint32 major;
gss_buffer_desc nameBuf;
/* Acceptor-Service-Name */
krbPrincComponentToGssBuffer(krbPrinc, 0, &nameBuf);
- major = gssEapRadiusAddAvp(minor, vps,
+ major = gssEapRadiusAddAvp(minor, req,
PW_GSS_ACCEPTOR_SERVICE_NAME,
- VENDORPEC_UKERNA,
+ 0,
&nameBuf);
if (GSS_ERROR(major))
return major;
/* Acceptor-Host-Name */
krbPrincComponentToGssBuffer(krbPrinc, 1, &nameBuf);
- major = gssEapRadiusAddAvp(minor, vps,
+ major = gssEapRadiusAddAvp(minor, req,
PW_GSS_ACCEPTOR_HOST_NAME,
- VENDORPEC_UKERNA,
+ 0,
&nameBuf);
if (GSS_ERROR(major))
return major;
if (*minor != 0)
return GSS_S_FAILURE;
- major = gssEapRadiusAddAvp(minor, vps,
- PW_GSS_ACCEPTOR_SERVICE_SPECIFIC,
- VENDORPEC_UKERNA,
+ major = gssEapRadiusAddAvp(minor, req,
+ PW_GSS_ACCEPTOR_SERVICE_SPECIFICS,
+ 0,
&nameBuf);
-
- if (GSS_ERROR(major)) {
- krbFreeUnparsedName(krbContext, &nameBuf);
+#ifdef HAVE_HEIMDAL_VERSION
+ krb5_xfree(ssi);
+#else
+ krb5_free_unparsed_name(krbContext, ssi);
+#endif
+ if (GSS_ERROR(major))
return major;
- }
- krbFreeUnparsedName(krbContext, &nameBuf);
}
krbPrincRealmToGssBuffer(krbPrinc, &nameBuf);
if (nameBuf.length != 0) {
/* Acceptor-Realm-Name */
- major = gssEapRadiusAddAvp(minor, vps,
+ major = gssEapRadiusAddAvp(minor, req,
PW_GSS_ACCEPTOR_REALM_NAME,
- VENDORPEC_UKERNA,
+ 0,
&nameBuf);
if (GSS_ERROR(major))
return major;
struct rs_connection *rconn;
struct rs_request *request = NULL;
struct rs_packet *req = NULL, *resp = NULL;
- struct radius_packet *frreq, *frresp;
+ int isAccessChallenge;
if (ctx->acceptorCtx.radContext == NULL) {
/* May be NULL from an imported partial context */
major = gssEapRadiusMapError(minor, rs_err_conn_pop(rconn));
goto cleanup;
}
- frreq = rs_packet_frpkt(req);
- major = setInitiatorIdentity(minor, ctx, &frreq->vps);
+ major = setInitiatorIdentity(minor, ctx, req);
if (GSS_ERROR(major))
goto cleanup;
- major = setAcceptorIdentity(minor, ctx, &frreq->vps);
+ major = setAcceptorIdentity(minor, ctx, req);
if (GSS_ERROR(major))
goto cleanup;
- major = gssEapRadiusAddAvp(minor, &frreq->vps,
+ major = gssEapRadiusAddAvp(minor, req,
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,
+ major = gssEapRadiusAddAvp(minor, req, PW_STATE, 0,
&ctx->acceptorCtx.state);
if (GSS_ERROR(major))
goto cleanup;
GSSEAP_ASSERT(resp != NULL);
- frresp = rs_packet_frpkt(resp);
- switch (frresp->code) {
+ isAccessChallenge = 0;
+
+ switch (rs_packet_code(resp)) {
case PW_ACCESS_CHALLENGE:
- case PW_AUTHENTICATION_ACK:
+ isAccessChallenge = 1;
+ break;
+ case PW_ACCESS_ACCEPT:
break;
- case PW_AUTHENTICATION_REJECT:
+ case PW_ACCESS_REJECT:
*minor = GSSEAP_RADIUS_AUTH_FAILURE;
major = GSS_S_DEFECTIVE_CREDENTIAL;
goto cleanup;
break;
}
- major = gssEapRadiusGetAvp(minor, frresp->vps, PW_EAP_MESSAGE, 0,
+ major = gssEapRadiusGetAvp(minor, resp, PW_EAP_MESSAGE, 0,
outputToken, TRUE);
- if (major == GSS_S_UNAVAILABLE && frresp->code == PW_ACCESS_CHALLENGE) {
+ if (major == GSS_S_UNAVAILABLE && isAccessChallenge) {
*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,
+ if (isAccessChallenge) {
+ major = gssEapRadiusGetAvp(minor, resp, 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_avp **vps;
+
+ rs_packet_avps(resp, &vps);
+
+ ctx->acceptorCtx.vps = *vps;
+ *vps = NULL;
major = acceptReadyEap(minor, ctx, cred);
if (GSS_ERROR(major))
gss_buffer_t outputToken GSSEAP_UNUSED,
OM_uint32 *smFlags GSSEAP_UNUSED)
{
- OM_uint32 major;
- gss_iov_buffer_desc iov[2];
+ krb5_error_code code;
+ krb5_context krbContext;
+ krb5_data data;
+ krb5_checksum cksum;
+ krb5_boolean valid = FALSE;
- iov[0].type = GSS_IOV_BUFFER_TYPE_DATA | GSS_IOV_BUFFER_FLAG_ALLOCATE;
- iov[0].buffer.length = 0;
- iov[0].buffer.value = NULL;
+ if (chanBindings == GSS_C_NO_CHANNEL_BINDINGS ||
+ chanBindings->application_data.length == 0)
+ return GSS_S_CONTINUE_NEEDED;
- iov[1].type = GSS_IOV_BUFFER_TYPE_STREAM | GSS_IOV_BUFFER_FLAG_ALLOCATED;
+ GSSEAP_KRB_INIT(&krbContext);
- /* XXX necessary because decrypted in place and we verify it later */
- major = duplicateBuffer(minor, inputToken, &iov[1].buffer);
- if (GSS_ERROR(major))
- return major;
+ KRB_DATA_INIT(&data);
- major = gssEapUnwrapOrVerifyMIC(minor, ctx, NULL, NULL,
- iov, 2, TOK_TYPE_WRAP);
- if (GSS_ERROR(major)) {
- gssEapReleaseIov(iov, 2);
- return major;
+ gssBufferToKrbData(&chanBindings->application_data, &data);
+
+ KRB_CHECKSUM_INIT(&cksum, ctx->checksumType, inputToken);
+
+ code = krb5_c_verify_checksum(krbContext, &ctx->rfc3961Key,
+ KEY_USAGE_GSSEAP_CHBIND_MIC,
+ &data, &cksum, &valid);
+ if (code != 0) {
+ *minor = code;
+ return GSS_S_FAILURE;
}
- if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS &&
- !bufferEqual(&iov[0].buffer, &chanBindings->application_data)) {
- major = GSS_S_BAD_BINDINGS;
+ if (valid == FALSE) {
*minor = GSSEAP_BINDINGS_MISMATCH;
- } else {
- major = GSS_S_CONTINUE_NEEDED;
- *minor = 0;
+ return GSS_S_BAD_BINDINGS;
}
- gssEapReleaseIov(iov, 2);
+ ctx->flags |= CTX_FLAG_CHANNEL_BINDINGS_VERIFIED;
- return major;
+ *minor = 0;
+ return GSS_S_CONTINUE_NEEDED;
}
static OM_uint32
gss_OID mech GSSEAP_UNUSED,
OM_uint32 reqFlags GSSEAP_UNUSED,
OM_uint32 timeReq GSSEAP_UNUSED,
- gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
+ gss_channel_bindings_t chanBindings,
gss_buffer_t inputToken,
gss_buffer_t outputToken GSSEAP_UNUSED,
OM_uint32 *smFlags GSSEAP_UNUSED)
{
OM_uint32 major;
+ /*
+ * The channel binding token is optional, however if the caller indicated
+ * bindings we must raise an error if it was absent.
+ *
+ * In the future, we might use a context option to allow the caller to
+ * indicate that missing bindings are acceptable.
+ */
+ if (chanBindings != NULL &&
+ chanBindings->application_data.length != 0 &&
+ (ctx->flags & CTX_FLAG_CHANNEL_BINDINGS_VERIFIED) == 0) {
+ *minor = GSSEAP_MISSING_BINDINGS;
+ return GSS_S_BAD_BINDINGS;
+ }
+
major = gssEapVerifyTokenMIC(minor, ctx, inputToken);
if (GSS_ERROR(major))
return major;
ITOK_TYPE_GSS_CHANNEL_BINDINGS,
ITOK_TYPE_NONE,
GSSEAP_STATE_INITIATOR_EXTS,
- SM_ITOK_FLAG_REQUIRED,
+ 0,
eapGssSmAcceptGssChannelBindings,
},
{
#endif
{
ITOK_TYPE_NONE,
+ ITOK_TYPE_ACCEPTOR_NAME_RESP,
+ GSSEAP_STATE_ACCEPTOR_EXTS,
+ 0,
+ eapGssSmAcceptAcceptorName
+ },
+ {
+ ITOK_TYPE_NONE,
ITOK_TYPE_ACCEPTOR_MIC,
GSSEAP_STATE_ACCEPTOR_EXTS,
0,
* credential handle.
*/
- /*
- * Calling gssEapInquireCred() forces the default acceptor credential name
- * to be resolved.
- */
- major = gssEapInquireCred(minor, cred, &ctx->acceptorName, NULL, NULL, NULL);
- if (GSS_ERROR(major))
- goto cleanup;
+ if (cred->name != GSS_C_NO_NAME) {
+ major = gssEapDuplicateName(minor, cred->name, &ctx->acceptorName);
+ if (GSS_ERROR(major))
+ goto cleanup;
+ }
major = gssEapSmStep(minor,
cred,
gss_name_t name2,
int *name_equal)
{
- return gssEapCompareName(minor, name1, name2, name_equal);
+ return gssEapCompareName(minor, name1, name2, 0, name_equal);
}
BEGIN-VENDOR UKERNA
-ATTRIBUTE GSS-Acceptor-Service-Name 128 string
-ATTRIBUTE GSS-Acceptor-Host-Name 129 string
-ATTRIBUTE GSS-Acceptor-Service-Specific 130 string
-ATTRIBUTE GSS-Acceptor-Realm-Name 131 string
-ATTRIBUTE SAML-AAA-Assertion 132 string
-ATTRIBUTE MS-Windows-Auth-Data 133 octets
-ATTRIBUTE MS-Windows-Group-Sid 134 string
+ATTRIBUTE GSS-Acceptor-Service-Name-VS 128 string
+ATTRIBUTE GSS-Acceptor-Host-Name-VS 129 string
+ATTRIBUTE GSS-Acceptor-Service-Specific-VS 130 string
+ATTRIBUTE GSS-Acceptor-Realm-Name-VS 131 string
+ATTRIBUTE SAML-AAA-Assertion 132 string
+ATTRIBUTE MS-Windows-Auth-Data 133 octets
+ATTRIBUTE MS-Windows-Group-Sid 134 string
ATTRIBUTE EAP-Channel-Binding-Message 135 octets
END-VENDOR UKERNA
key.length = KRB_KEY_LENGTH(&ctx->rfc3961Key);
key.value = KRB_KEY_DATA(&ctx->rfc3961Key);
+ /*
+ * As a shortcut, we omit the mechanism OID of the initiator name because
+ * we know it will match the context mechanism. The acceptor name mech OID
+ * is always included.
+ */
if (ctx->initiatorName != GSS_C_NO_NAME) {
major = gssEapExportNameInternal(minor, ctx->initiatorName,
&initiatorName,
if (ctx->acceptorName != GSS_C_NO_NAME) {
major = gssEapExportNameInternal(minor, ctx->acceptorName,
&acceptorName,
- EXPORT_NAME_FLAG_COMPOSITE);
+ EXPORT_NAME_FLAG_OID | EXPORT_NAME_FLAG_COMPOSITE);
if (GSS_ERROR(major))
goto cleanup;
}
#include <wpabuf.h>
#ifdef GSSEAP_ENABLE_ACCEPTOR
-/* FreeRADIUS headers */
-#ifdef __cplusplus
-extern "C" {
-#ifndef WIN32
-#define operator fr_operator
-#endif
-#endif
-#include <freeradius/libradius.h>
-#include <freeradius/radius.h>
-
-#undef pid_t
-
/* libradsec headers */
#include <radsec/radsec.h>
#include <radsec/request.h>
-#ifdef __cplusplus
-#ifndef WIN32
-#undef operator
+#include <radsec/radius.h>
#endif
-}
-#endif
-#endif /* GSSEAP_ENABLE_ACCEPTOR */
#include "gsseap_err.h"
#include "radsec_err.h"
#define CTX_FLAG_INITIATOR 0x00000001
#define CTX_FLAG_KRB_REAUTH 0x00000002
+#define CTX_FLAG_CHANNEL_BINDINGS_VERIFIED 0x00000004
#define CTX_IS_INITIATOR(ctx) (((ctx)->flags & CTX_FLAG_INITIATOR) != 0)
struct rs_connection *radConn;
char *radServer;
gss_buffer_desc state;
- VALUE_PAIR *vps;
+ rs_avp *vps;
};
#endif
#define KEY_USAGE_INITIATOR_SEAL 24
#define KEY_USAGE_INITIATOR_SIGN 25
+#define KEY_USAGE_GSSEAP_CHBIND_MIC 60
+#define KEY_USAGE_GSSEAP_ACCTOKEN_MIC 61
+#define KEY_USAGE_GSSEAP_INITOKEN_MIC 62
+
/* accept_sec_context.c */
OM_uint32
gssEapAcceptSecContext(OM_uint32 *minor,
#define IS_WIRE_ERROR(err) ((err) > GSSEAP_RESERVED && \
(err) <= GSSEAP_RADIUS_PROT_FAILURE)
-/* upper bound of RADIUS error range must be kept in sync with radsec.h */
+#ifdef GSSEAP_ENABLE_ACCEPTOR
#define IS_RADIUS_ERROR(err) ((err) >= ERROR_TABLE_BASE_rse && \
- (err) <= ERROR_TABLE_BASE_rse + 20)
+ (err) <= ERROR_TABLE_BASE_rse + RSE_MAX)
+#else
+#define IS_RADIUS_ERROR(err) (0)
+#endif
/* exchange_meta_data.c */
OM_uint32 GSSAPI_CALLCONV
gss_ctx_id_t ctx,
int prf_key,
const gss_buffer_t prf_in,
- ssize_t desired_output_len,
gss_buffer_t prf_out);
/* query_mechanism_info.c */
error_code GSSEAP_BAD_INITIATOR_NAME, "Initiator identity must be a valid name"
error_code GSSEAP_NO_HOSTNAME, "Could not determine local host name"
error_code GSSEAP_NO_ACCEPTOR_NAME, "Could not determine acceptor identity"
+error_code GSSEAP_WRONG_ACCEPTOR_NAME, "Acceptor identity different than expected"
error_code GSSEAP_BAD_ACCEPTOR_NAME, "Acceptor name is too long or has too many components"
error_code GSSEAP_BAD_NAME_TOKEN, "Name token is malformed or corrupt"
error_code GSSEAP_NO_LOCAL_MAPPING, "Unable to map name to a local identity"
# Extensions
#
error_code GSSEAP_BINDINGS_MISMATCH, "Channel bindings do not match"
+error_code GSSEAP_MISSING_BINDINGS, "Channel binding token missing"
error_code GSSEAP_NO_MECHGLUE_SYMBOL, "Could not find symbol in mechanism glue"
error_code GSSEAP_BAD_INVOCATION, "Bad mechanism invoke OID"
static OM_uint32
importName(OM_uint32 *minor,
+ gss_OID mech,
unsigned char **pBuf,
size_t *pRemain,
gss_name_t *pName)
{
- OM_uint32 major;
+ OM_uint32 major, tmpMinor, flags;
unsigned char *p = *pBuf;
size_t remain = *pRemain;
gss_buffer_desc tmp;
tmp.value = p + 4;
- major = gssEapImportNameInternal(minor, &tmp, pName,
- EXPORT_NAME_FLAG_COMPOSITE);
+ flags = EXPORT_NAME_FLAG_COMPOSITE;
+ if (mech == GSS_C_NO_OID)
+ flags |= EXPORT_NAME_FLAG_OID;
+
+ major = gssEapImportNameInternal(minor, &tmp, pName, flags);
if (GSS_ERROR(major))
return major;
+
+ if ((flags & EXPORT_NAME_FLAG_OID) == 0) {
+ major = gssEapCanonicalizeOid(minor, mech, 0, &(*pName)->mechanismUsed);
+ if (GSS_ERROR(major)) {
+ gssEapReleaseName(&tmpMinor, pName);
+ return major;
+ }
+ }
}
*pBuf += 4 + tmp.length;
if (GSS_ERROR(major))
return major;
- major = importName(minor, &p, &remain, &ctx->initiatorName);
+ /* Initiator name OID matches the context mechanism, so it's not encoded */
+ major = importName(minor, ctx->mechanismUsed, &p, &remain, &ctx->initiatorName);
if (GSS_ERROR(major))
return major;
- major = importName(minor, &p, &remain, &ctx->acceptorName);
+ major = importName(minor, GSS_C_NO_OID, &p, &remain, &ctx->acceptorName);
if (GSS_ERROR(major))
return major;
outputToken, NULL);
if (GSS_ERROR(major))
return major;
- } else if (inputToken != GSS_C_NO_BUFFER &&
- ctx->acceptorName == GSS_C_NO_NAME) {
- /* Accept target name hint from acceptor */
+ } else if (inputToken != GSS_C_NO_BUFFER) {
+ OM_uint32 tmpMinor;
+ gss_name_t nameHint;
+ int equal;
+
+ /* Accept target name hint from acceptor or verify acceptor */
major = gssEapImportName(minor, inputToken,
GSS_C_NT_USER_NAME,
ctx->mechanismUsed,
- &ctx->acceptorName);
+ &nameHint);
if (GSS_ERROR(major))
return major;
+
+ if (ctx->acceptorName != GSS_C_NO_NAME) {
+ /* verify name hint matched asserted acceptor name */
+ major = gssEapCompareName(minor,
+ nameHint,
+ ctx->acceptorName,
+ COMPARE_NAME_FLAG_IGNORE_EMPTY_REALMS,
+ &equal);
+ if (GSS_ERROR(major)) {
+ gssEapReleaseName(&tmpMinor, &nameHint);
+ return major;
+ }
+
+ gssEapReleaseName(&tmpMinor, &nameHint);
+
+ if (!equal) {
+ *minor = GSSEAP_WRONG_ACCEPTOR_NAME;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+ } else { /* acceptor name is no_name */
+ /* accept acceptor name hint */
+ ctx->acceptorName = nameHint;
+ nameHint = GSS_C_NO_NAME;
+ }
}
+
/*
* Currently, other parts of the code assume that the acceptor name
* is available, hence this check.
OM_uint32 *smFlags)
{
OM_uint32 major;
- gss_buffer_desc buffer = GSS_C_EMPTY_BUFFER;
+ krb5_error_code code;
+ krb5_context krbContext;
+ krb5_data data;
+ krb5_checksum cksum;
+ gss_buffer_desc cksumBuffer;
- if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS)
- buffer = chanBindings->application_data;
+ if (chanBindings == GSS_C_NO_CHANNEL_BINDINGS ||
+ chanBindings->application_data.length == 0)
+ return GSS_S_CONTINUE_NEEDED;
- major = gssEapWrap(minor, ctx, TRUE, GSS_C_QOP_DEFAULT,
- &buffer, NULL, outputToken);
- if (GSS_ERROR(major))
- return major;
+ GSSEAP_KRB_INIT(&krbContext);
+
+ KRB_DATA_INIT(&data);
+
+ gssBufferToKrbData(&chanBindings->application_data, &data);
- GSSEAP_ASSERT(outputToken->value != NULL);
+ code = krb5_c_make_checksum(krbContext, ctx->checksumType,
+ &ctx->rfc3961Key,
+ KEY_USAGE_GSSEAP_CHBIND_MIC,
+ &data, &cksum);
+ if (code != 0) {
+ *minor = code;
+ return GSS_S_FAILURE;
+ }
+
+ cksumBuffer.length = KRB_CHECKSUM_LENGTH(&cksum);
+ cksumBuffer.value = KRB_CHECKSUM_DATA(&cksum);
+
+ major = duplicateBuffer(minor, &cksumBuffer, outputToken);
+ if (GSS_ERROR(major)) {
+ krb5_free_checksum_contents(krbContext, &cksum);
+ return major;
+ }
*minor = 0;
*smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL;
+ krb5_free_checksum_contents(krbContext, &cksum);
+
return GSS_S_CONTINUE_NEEDED;
}
return GSS_S_CONTINUE_NEEDED;
}
-
+
#ifdef GSSEAP_ENABLE_REAUTH
static OM_uint32
eapGssSmInitReauthCreds(OM_uint32 *minor,
{
ITOK_TYPE_ACCEPTOR_NAME_RESP,
ITOK_TYPE_ACCEPTOR_NAME_REQ,
- GSSEAP_STATE_INITIAL | GSSEAP_STATE_AUTHENTICATE,
+ GSSEAP_STATE_INITIAL | GSSEAP_STATE_AUTHENTICATE |
+ GSSEAP_STATE_ACCEPTOR_EXTS,
0,
eapGssSmInitAcceptorName
},
ITOK_TYPE_NONE,
ITOK_TYPE_GSS_CHANNEL_BINDINGS,
GSSEAP_STATE_INITIATOR_EXTS,
- SM_ITOK_FLAG_REQUIRED,
+ 0,
eapGssSmInitGssChannelBindings
},
{
GSSEAP_MUTEX_LOCK(&ctx->mutex);
if (src_name != NULL) {
- major = gssEapDuplicateName(minor, ctx->initiatorName, src_name);
- if (GSS_ERROR(major))
- goto cleanup;
+ if (ctx->initiatorName != GSS_C_NO_NAME) {
+ major = gssEapDuplicateName(minor, ctx->initiatorName, src_name);
+ if (GSS_ERROR(major))
+ goto cleanup;
+ } else
+ *src_name = GSS_C_NO_NAME;
}
if (targ_name != NULL) {
- major = gssEapDuplicateName(minor, ctx->acceptorName, targ_name);
- if (GSS_ERROR(major))
- goto cleanup;
+ if (ctx->acceptorName != GSS_C_NO_NAME) {
+ major = gssEapDuplicateName(minor, ctx->acceptorName, targ_name);
+ if (GSS_ERROR(major))
+ goto cleanup;
+ } else
+ *targ_name = GSS_C_NO_NAME;
}
if (lifetime_rec != NULL) {
keySize = KRB_KEY_LENGTH(&ctx->rfc3961Key);
- major = gssEapPseudoRandom(minor, ctx, GSS_C_PRF_KEY_FULL, &salt,
- keySize, &key);
+ key.value = GSSEAP_MALLOC(keySize);
+ if (key.value == NULL) {
+ major = GSS_S_FAILURE;
+ *minor = ENOMEM;
+ goto cleanup;
+ }
+
+ key.length = keySize;
+
+ major = gssEapPseudoRandom(minor, ctx, GSS_C_PRF_KEY_FULL, &salt, &key);
if (GSS_ERROR(major))
goto cleanup;
# 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
+eap-aes128 1.3.6.1.5.5.15.1.1.17 mech_eap.so
+eap-aes256 1.3.6.1.5.5.15.1.1.18 mech_eap.so
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;
krb5_data t, ns;
unsigned char *p;
krb5_context krbContext;
-
- prf_out->length = 0;
- prf_out->value = NULL;
+ ssize_t desired_output_len = prf_out->length;
*minor = 0;
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);
GSSEAP_FREE(ns.data);
}
#ifdef HAVE_HEIMDAL_VERSION
- krb5_free_data_contents(krbContext, &t);
+ krb5_data_free(&t);
#else
if (t.data != NULL) {
memset(t.data, 0, t.length);
GSSEAP_MUTEX_LOCK(&ctx->mutex);
- if (CTX_IS_ESTABLISHED(ctx)) {
- major = gssEapPseudoRandom(minor, ctx, prf_key,
- prf_in, desired_output_len, prf_out);
- } else {
+ if (!CTX_IS_ESTABLISHED(ctx)) {
major = GSS_S_NO_CONTEXT;
*minor = GSSEAP_CONTEXT_INCOMPLETE;
+ goto cleanup;
+ }
+
+ prf_out->value = GSSEAP_MALLOC(desired_output_len);
+ if (prf_out->value == NULL) {
+ major = GSS_S_FAILURE;
+ *minor = ENOMEM;
+ goto cleanup;
}
+ prf_out->length = desired_output_len;
+
+ major = gssEapPseudoRandom(minor, ctx, prf_key,
+ prf_in, prf_out);
+
+cleanup:
GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
return major;
-dictionary = "/usr/local/etc/raddb/dictionary"
-
realm gss-eap {
type = "UDP"
timeout = 5
#include <krb5.h>
#ifdef WIN32
-#define inline __inline
+# ifndef __cplusplus
+# define inline __inline
+# endif
#define snprintf _snprintf
#endif
#define KRB_DATA_INIT(d) krb5_data_zero((d))
+#define KRB_CHECKSUM_TYPE(c) ((c)->cksumtype)
+#define KRB_CHECKSUM_LENGTH(c) ((c)->checksum.length)
+#define KRB_CHECKSUM_DATA(c) ((c)->checksum.data)
+
+#define KRB_CHECKSUM_INIT(cksum, type, d) do { \
+ (cksum)->cksumtype = (type); \
+ (cksum)->checksum.length = (d)->length; \
+ (cksum)->checksum.data = (d)->value; \
+ } while (0)
+
#else
#define KRB_TIME_FOREVER KRB5_INT32_MAX
(d)->data = NULL; \
} while (0)
+#define KRB_CHECKSUM_TYPE(c) ((c)->checksum_type)
+#define KRB_CHECKSUM_LENGTH(c) ((c)->length)
+#define KRB_CHECKSUM_DATA(c) ((c)->contents)
+
+#define KRB_CHECKSUM_INIT(cksum, type, d) do { \
+ (cksum)->checksum_type = (type); \
+ (cksum)->length = (d)->length; \
+ (cksum)->contents = (d)->value; \
+ } while (0)
+
#endif /* HAVE_HEIMDAL_VERSION */
#define KRB_KEY_INIT(key) do { \
gss_buffer_t output_name_buffer,
gss_OID *output_name_type);
+#define COMPARE_NAME_FLAG_IGNORE_EMPTY_REALMS 0x1
+
OM_uint32
gssEapCompareName(OM_uint32 *minor,
gss_name_t name1,
gss_name_t name2,
+ OM_uint32 flags,
int *name_equal);
/* util_oid.c */
};
static krb5_data radius_ad_attr = {
- KV5M_DATA, sizeof("urn:authdata-radius-avp") - 1, "urn:authdata-radius-avp" };
+ KV5M_DATA, sizeof("urn:authdata-aaa-radius") - 1, "urn:authdata-aaa-radius" };
static krb5_error_code
radius_ad_init(krb5_context kcontext GSSEAP_UNUSED,
int verifyMIC)
{
OM_uint32 major;
- gss_iov_buffer_desc *iov = NULL;
size_t i = 0, j;
enum gss_eap_token_type tokType;
OM_uint32 micTokType;
unsigned char wireTokType[2];
unsigned char *innerTokTypes = NULL, *innerTokLengths = NULL;
const struct gss_eap_token_buffer_set *tokens;
+ ssize_t checksumIndex = -1;
+
+ krb5_keyusage usage;
+ krb5_error_code code = 0;
+ krb5_context krbContext;
+ krb5_crypto_iov *kiov = NULL;
+#ifdef HAVE_HEIMDAL_VERSION
+ krb5_crypto krbCrypto = NULL;
+ krb5_cksumtype cksumType;
+#endif
+ size_t kiovCount;
+
+ GSSEAP_KRB_INIT(&krbContext);
tokens = verifyMIC ? ctx->inputTokens : ctx->outputTokens;
GSSEAP_ASSERT(tokens != NULL);
- iov = GSSEAP_CALLOC(2 + (3 * tokens->buffers.count) + 1, sizeof(*iov));
- if (iov == NULL) {
+#ifdef HAVE_HEIMDAL_VERSION
+ code = krb5_crypto_init(krbContext, &ctx->rfc3961Key, ETYPE_NULL, &krbCrypto);
+ if (code != 0)
+ goto cleanup;
+#endif
+
+ kiovCount = 2 + (3 * tokens->buffers.count) + 1;
+
+ if (verifyMIC) {
+ assert(tokens->buffers.count != 0);
+ kiovCount -= 3;
+ }
+
+ kiov = GSSEAP_CALLOC(kiovCount, sizeof(*kiov));
+ if (kiov == NULL) {
major = GSS_S_FAILURE;
*minor = ENOMEM;
goto cleanup;
/* Mechanism OID */
GSSEAP_ASSERT(ctx->mechanismUsed != GSS_C_NO_OID);
- iov[i].type = GSS_IOV_BUFFER_TYPE_DATA;
- iov[i].buffer.length = ctx->mechanismUsed->length;
- iov[i].buffer.value = ctx->mechanismUsed->elements;
+ kiov[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
+ kiov[i].data.length = ctx->mechanismUsed->length;
+ kiov[i].data.data = ctx->mechanismUsed->elements;
i++;
/* Token type */
if (CTX_IS_INITIATOR(ctx) ^ verifyMIC) {
tokType = TOK_TYPE_INITIATOR_CONTEXT;
micTokType = ITOK_TYPE_INITIATOR_MIC;
+ usage = KEY_USAGE_GSSEAP_INITOKEN_MIC;
} else {
tokType = TOK_TYPE_ACCEPTOR_CONTEXT;
micTokType = ITOK_TYPE_ACCEPTOR_MIC;
+ usage = KEY_USAGE_GSSEAP_ACCTOKEN_MIC;
}
store_uint16_be(tokType, wireTokType);
- iov[i].type = GSS_IOV_BUFFER_TYPE_DATA;
- iov[i].buffer.length = sizeof(wireTokType);
- iov[i].buffer.value = wireTokType;
+ kiov[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
+ kiov[i].data.length = sizeof(wireTokType);
+ kiov[i].data.data = (char *)wireTokType;
i++;
for (j = 0; j < tokens->buffers.count; j++) {
if (verifyMIC &&
- (tokens->types[j] & ITOK_TYPE_MASK) == micTokType)
- continue; /* will use this slot for trailer */
+ (tokens->types[j] & ITOK_TYPE_MASK) == micTokType) {
+ continue;
+ }
- iov[i].type = GSS_IOV_BUFFER_TYPE_DATA;
- iov[i].buffer.length = 4;
- iov[i].buffer.value = &innerTokTypes[j * 4];
+ kiov[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
+ kiov[i].data.length = 4;
+ kiov[i].data.data = (char *)&innerTokTypes[j * 4];
store_uint32_be(tokens->types[j] & ~(ITOK_FLAG_VERIFIED),
- iov[i].buffer.value);
+ kiov[i].data.data);
i++;
- iov[i].type = GSS_IOV_BUFFER_TYPE_DATA;
- iov[i].buffer.length = 4;
- iov[i].buffer.value = &innerTokLengths[j * 4];
+ kiov[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
+ kiov[i].data.length = 4;
+ kiov[i].data.data = (char *)&innerTokLengths[j * 4];
store_uint32_be(tokens->buffers.elements[j].length,
- iov[i].buffer.value);
+ kiov[i].data.data);
i++;
- iov[i].type = GSS_IOV_BUFFER_TYPE_DATA;
- iov[i].buffer = tokens->buffers.elements[j];
+ kiov[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
+ gssBufferToKrbData(&tokens->buffers.elements[j], &kiov[i].data);
i++;
}
+ kiov[i].flags = KRB5_CRYPTO_TYPE_CHECKSUM;
if (verifyMIC) {
- GSSEAP_ASSERT(tokenMIC->length >= 16);
+ gssBufferToKrbData(tokenMIC, &kiov[i].data);
+ } else {
+ size_t checksumSize;
- GSSEAP_ASSERT(i < 2 + (3 * tokens->buffers.count));
+ code = krb5_c_checksum_length(krbContext, ctx->checksumType,
+ &checksumSize);
+ if (code != 0)
+ goto cleanup;
- iov[i].type = GSS_IOV_BUFFER_TYPE_HEADER;
- iov[i].buffer = *tokenMIC;
- i++;
+ kiov[i].data.data = GSSEAP_MALLOC(checksumSize);
+ if (kiov[i].data.data == NULL) {
+ code = ENOMEM;
+ goto cleanup;
+ }
+ kiov[i].data.length = checksumSize;
+ checksumIndex = i;
+ }
+ i++;
+ GSSEAP_ASSERT(i == kiovCount);
- major = gssEapUnwrapOrVerifyMIC(minor, ctx, NULL, NULL,
- iov, i, TOK_TYPE_MIC);
+#ifdef HAVE_HEIMDAL_VERSION
+ cksumType = ctx->checksumType;
+
+ if (verifyMIC) {
+ code = krb5_verify_checksum_iov(krbContext, krbCrypto, usage,
+ kiov, i, &cksumType);
+ } else {
+ code = krb5_create_checksum_iov(krbContext, krbCrypto, usage,
+ kiov, i, &cksumType);
+ }
+#else
+ if (verifyMIC) {
+ krb5_boolean kvalid = FALSE;
+
+ code = krb5_c_verify_checksum_iov(krbContext, ctx->checksumType,
+ &ctx->rfc3961Key,
+ usage, kiov, i, &kvalid);
+ if (code == 0 && !kvalid) {
+ code = KRB5KRB_AP_ERR_BAD_INTEGRITY;
+ }
} else {
- iov[i++].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_FLAG_ALLOCATE;
- major = gssEapWrapOrGetMIC(minor, ctx, FALSE, NULL,
- iov, i, TOK_TYPE_MIC);
- if (!GSS_ERROR(major))
- *tokenMIC = iov[i - 1].buffer;
+ code = krb5_c_make_checksum_iov(krbContext, ctx->checksumType,
+ &ctx->rfc3961Key,
+ usage, kiov, i);
+ }
+#endif /* HAVE_HEIMDAL_VERSION */
+
+ if (code == 0 && !verifyMIC) {
+ krbDataToGssBuffer(&kiov[checksumIndex].data, tokenMIC);
+ checksumIndex = -1;
}
cleanup:
- if (iov != NULL)
- gssEapReleaseIov(iov, tokens->buffers.count);
+ if (checksumIndex != -1)
+ GSSEAP_FREE(kiov[checksumIndex].data.data);
+ if (kiov != NULL)
+ GSSEAP_FREE(kiov);
if (innerTokTypes != NULL)
GSSEAP_FREE(innerTokTypes);
if (innerTokLengths != NULL)
GSSEAP_FREE(innerTokLengths);
+#ifdef HAVE_HEIMDAL_VERSION
+ if (krbCrypto != NULL)
+ krb5_crypto_destroy(krbContext, krbCrypto);
+#endif
+
+ *minor = code;
+
+ switch (code) {
+ case KRB5KRB_AP_ERR_BAD_INTEGRITY:
+ major = GSS_S_BAD_SIG;
+ break;
+ case 0:
+ major = GSS_S_COMPLETE;
+ break;
+ default:
+ major = GSS_S_FAILURE;
+ break;
+ }
return major;
}
gss_ctx_id_t ctx,
const gss_buffer_t tokenMIC)
{
- if (tokenMIC->length < 16) {
- *minor = GSSEAP_TOK_TRUNC;
- return GSS_S_BAD_SIG;
- }
-
return gssEapMakeOrVerifyTokenMIC(minor, ctx, tokenMIC, TRUE);
}
gss_OID
gssEapPrimaryMechForCred(gss_cred_id_t cred)
{
- gss_OID nameMech = GSS_C_NO_OID;
+ gss_OID credMech = GSS_C_NO_OID;
- if (cred->mechanisms != GSS_C_NO_OID_SET &&
+ if (cred != GSS_C_NO_CREDENTIAL &&
+ cred->mechanisms != GSS_C_NO_OID_SET &&
cred->mechanisms->count == 1)
- nameMech = &cred->mechanisms->elements[0];
+ credMech = &cred->mechanisms->elements[0];
- return nameMech;
+ return credMech;
}
OM_uint32
isDefaultIdentity = TRUE;
} else {
major = gssEapCompareName(minor, cred->name,
- defaultIdentityName, &isDefaultIdentity);
+ defaultIdentityName, 0,
+ &isDefaultIdentity);
if (GSS_ERROR(major))
goto cleanup;
}
if (code != 0)
krb5_free_keyblock_contents(krbContext, &kd);
#ifdef HAVE_HEIMDAL_VERSION
- krb5_free_data_contents(krbContext, &t);
+ krb5_data_free(&t);
#else
if (t.data != NULL) {
memset(t.data, 0, t.length);
if (*minor != 0)
return GSS_S_FAILURE;
-#ifdef HAVE_HEIMDAL_VERSION
- *cksumtype = cksum.cksumtype;
-#else
- *cksumtype = cksum.checksum_type;
-#endif
+ *cksumtype = KRB_CHECKSUM_TYPE(&cksum);
krb5_free_checksum_contents(krbContext, &cksum);
#endif /* HAVE_KRB5INT_C_MANDATORY_CKSUMTYPE */
#include "gssapiP_eap.h"
/*
- * 1.3.6.1.4.1.5322(padl)
- * gssEap(22)
+ * Mechanism and name types are taken from 1.3.6.1.5.5(mechanisms)
+ * assigned at http://www.iana.org/assignments/smi-numbers
+ *
+ * abfab(15)
* mechanisms(1)
- * eap-aes128-cts-hmac-sha1-96(17)
- * eap-aes256-cts-hmac-sha1-96(18)
- * nameTypes(2)
+ * gss-eap-v1(1)
+ * eap-aes128-cts-hmac-sha1-96(17)
+ * eap-aes256-cts-hmac-sha1-96(18)
+ * nametypes(2)
+ * GSS_EAP_NT_EAP_NAME(1)
+ *
+ * Implementation-internal OIDs are taken from 1.3.6.1.4.1.5322(padl)
+ * gssEap(22)
* apiExtensions(3)
* inquireSecContextByOid(1)
* inquireCredByOid(2)
* canonicalized exported names.
*/
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" }
+ /* 1.3.6.1.5.5.15.1.1 */
+ { 8, "\x2B\x06\x01\x05\x05\x0f\x01\x01" },
+ /* 1.3.6.1.5.5.15.1.1.17 */
+ { 9, "\x2B\x06\x01\x05\x05\x0f\x01\x01\x11" },
+ /* 1.3.6.1.5.5.15.1.1.18 */
+ { 9, "\x2B\x06\x01\x05\x05\x0f\x01\x01\x12" },
};
gss_OID GSS_EAP_MECHANISM = &gssEapMechOids[0];
MoonshotError *error = NULL;
if (cred->name != GSS_C_NO_NAME) {
- major = gssEapExportName(minor, cred->name, &initiator);
+ major = gssEapDisplayName(minor, cred->name, &initiator, NULL);
if (GSS_ERROR(major))
goto cleanup;
}
if (targetName != GSS_C_NO_NAME) {
- major = gssEapExportName(minor, targetName, &target);
+ major = gssEapDisplayName(minor, targetName, &target, NULL);
if (GSS_ERROR(major))
goto cleanup;
}
#include "gssapiP_eap.h"
static gss_OID_desc gssEapNtEapName = {
- /* 1.3.6.1.4.1.5322.22.2.1 */
- 10, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x02\x01"
+ /* 1.3.6.1.5.5.15.2.1 */
+ 8, "\x2B\x06\x01\x05\x05\x0f\x02\x01"
};
gss_OID GSS_EAP_NT_EAP_NAME = &gssEapNtEapName;
GSS_C_NO_OID, dest_name);
}
+static int
+hasRealmP(gss_name_t name)
+{
+#ifdef HAVE_HEIMDAL_VERSION
+ if (KRB_PRINC_REALM(name->krbPrincipal) != NULL &&
+ KRB_PRINC_REALM(name->krbPrincipal)[0] != '\0')
+#else
+ if (KRB_PRINC_REALM(name->krbPrincipal)->length != 0)
+#endif
+ return TRUE;
+
+ return FALSE;
+}
+
OM_uint32
gssEapDisplayName(OM_uint32 *minor,
gss_name_t name,
* According to draft-ietf-abfab-gss-eap-01, when the realm is
* absent the trailing '@' is not included.
*/
-#ifdef HAVE_HEIMDAL_VERSION
- if (KRB_PRINC_REALM(name->krbPrincipal) == NULL ||
- KRB_PRINC_REALM(name->krbPrincipal)[0] == '\0')
-#else
- if (KRB_PRINC_REALM(name->krbPrincipal)->length == 0)
-#endif
+ if (!hasRealmP(name))
flags |= KRB5_PRINCIPAL_UNPARSE_NO_REALM;
*minor = krb5_unparse_name_flags(krbContext, name->krbPrincipal,
}
major = makeStringBuffer(minor, krbName, output_name_buffer);
- if (GSS_ERROR(major)) {
- krb5_free_unparsed_name(krbContext, krbName);
- return major;
- }
-
+#ifdef HAVE_HEIMDAL_VERSION
+ krb5_xfree(krbName);
+#else
krb5_free_unparsed_name(krbContext, krbName);
+#endif
+ if (GSS_ERROR(major))
+ return major;
if (output_name_buffer->length == 0) {
name_type = GSS_C_NT_ANONYMOUS;
gssEapCompareName(OM_uint32 *minor,
gss_name_t name1,
gss_name_t name2,
+ OM_uint32 flags,
int *name_equal)
{
krb5_context krbContext;
GSSEAP_KRB_INIT(&krbContext);
/* krbPrincipal is immutable, so lock not required */
- *name_equal = krb5_principal_compare(krbContext,
- name1->krbPrincipal,
- name2->krbPrincipal);
+ if ((flags & COMPARE_NAME_FLAG_IGNORE_EMPTY_REALMS) &&
+ (hasRealmP(name1) == FALSE || hasRealmP(name2) == FALSE)) {
+ *name_equal = krb5_principal_compare_any_realm(krbContext,
+ name1->krbPrincipal,
+ name2->krbPrincipal);
+ } else {
+ *name_equal = krb5_principal_compare(krbContext,
+ name1->krbPrincipal,
+ name2->krbPrincipal);
+ }
+ } else {
+ *name_equal = 0;
}
return GSS_S_COMPLETE;
*minor = GSSEAP_WRONG_SIZE;
return GSS_S_FAILURE;
}
- memcpy(*buf, vqueue, sizeof(queue));
+ if (vqueue != NULL)
+ memcpy(*buf, vqueue, sizeof(queue));
+ else
+ memset(*buf, 0, sizeof(queue));
*buf += sizeof(queue);
*lenremain -= sizeof(queue);
#ifdef GSSEAP_ENABLE_ACCEPTOR
-/* stuff that should be provided by libradsec/libfreeradius-radius */
-#define VENDORATTR(vendor, attr) (((vendor) << 16) | (attr))
+#define RS_MAP_ERROR(code) (ERROR_TABLE_BASE_rse + (code))
-#ifndef ATTRID
-#define ATTRID(attr) ((attr) & 0xFFFF)
-#endif
+static rs_avp *copyAvps(rs_const_avp *src);
-static gss_buffer_desc radiusUrnPrefix = {
- sizeof("urn:x-radius:") - 1,
- (void *)"urn:x-radius:"
-};
+static OM_uint32
+gssEapRadiusGetAvp(OM_uint32 *minor,
+ rs_avp *vps,
+ const gss_eap_attrid &attrid,
+ gss_buffer_t buffer,
+ int concat);
-static VALUE_PAIR *copyAvps(const VALUE_PAIR *src);
+static OM_uint32
+gssEapRadiusAddAvp(OM_uint32 *minor,
+ rs_avp **vps,
+ const gss_eap_attrid &attrid,
+ const gss_buffer_t buffer);
+
+static gss_eap_attrid
+avpToAttrId(rs_const_avp *vp)
+{
+ gss_eap_attrid attrid;
+
+ rs_avp_attrid(vp, &attrid.second, &attrid.first);
+
+ return attrid;
+}
gss_eap_radius_attr_provider::gss_eap_radius_attr_provider(void)
{
gss_eap_radius_attr_provider::~gss_eap_radius_attr_provider(void)
{
if (m_vps != NULL)
- pairfree(&m_vps);
+ rs_avp_free(&m_vps);
}
bool
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_vps = copyAvps(radius->getAvps());
m_authenticated = radius->m_authenticated;
return false;
/* We assume libradsec validated this for us */
- GSSEAP_ASSERT(pairfind(m_vps, PW_MESSAGE_AUTHENTICATOR) != NULL);
+ GSSEAP_ASSERT(rs_avp_find(m_vps, PW_MESSAGE_AUTHENTICATOR, 0) != NULL);
m_authenticated = true;
}
}
}
static bool
-alreadyAddedAttributeP(std::vector <std::string> &attrs, VALUE_PAIR *vp)
+alreadyAddedAttributeP(std::vector <gss_eap_attrid> &attrs,
+ gss_eap_attrid &attrid)
{
- for (std::vector<std::string>::const_iterator a = attrs.begin();
+ for (std::vector<gss_eap_attrid>::const_iterator a = attrs.begin();
a != attrs.end();
++a) {
- if (strcmp(vp->name, (*a).c_str()) == 0)
+ if (attrid.first == (*a).first &&
+ attrid.second == (*a).second)
return true;
}
}
static bool
-isSecretAttributeP(uint16_t attrid, uint16_t vendor)
+isSecretAttributeP(const gss_eap_attrid &attrid)
{
bool bSecretAttribute = false;
- switch (vendor) {
- case VENDORPEC_MS:
- switch (attrid) {
+ switch (attrid.first) {
+ case VENDORPEC_MICROSOFT:
+ switch (attrid.second) {
case PW_MS_MPPE_SEND_KEY:
case PW_MS_MPPE_RECV_KEY:
bSecretAttribute = true;
}
static bool
-isSecretAttributeP(uint32_t attribute)
+isSecretAttributeP(rs_const_avp *vp)
{
- return isSecretAttributeP(ATTRID(attribute), VENDOR(attribute));
+ return isSecretAttributeP(avpToAttrId(vp));
}
static bool
-isInternalAttributeP(uint16_t attrid, uint16_t vendor)
+isInternalAttributeP(const gss_eap_attrid &attrid)
{
bool bInternalAttribute = false;
/* should have been filtered */
- GSSEAP_ASSERT(!isSecretAttributeP(attrid, vendor));
+ GSSEAP_ASSERT(!isSecretAttributeP(attrid));
- switch (vendor) {
+ switch (attrid.first) {
case VENDORPEC_UKERNA:
- switch (attrid) {
+ switch (attrid.second) {
+ case PW_SAML_AAA_ASSERTION:
+ bInternalAttribute = true;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 0:
+ switch (attrid.second) {
case PW_GSS_ACCEPTOR_SERVICE_NAME:
case PW_GSS_ACCEPTOR_HOST_NAME:
- case PW_GSS_ACCEPTOR_SERVICE_SPECIFIC:
+ case PW_GSS_ACCEPTOR_SERVICE_SPECIFICS:
case PW_GSS_ACCEPTOR_REALM_NAME:
- case PW_SAML_AAA_ASSERTION:
bInternalAttribute = true;
break;
default:
}
static bool
-isInternalAttributeP(uint32_t attribute)
+isInternalAttributeP(rs_const_avp *vp)
{
- return isInternalAttributeP(ATTRID(attribute), VENDOR(attribute));
+ return isInternalAttributeP(avpToAttrId(vp));
}
static bool
-isFragmentedAttributeP(uint16_t attrid, uint16_t vendor)
+isFragmentedAttributeP(const gss_eap_attrid &attrid)
{
/* A bit of a hack for the PAC for now. Should be configurable. */
- return (vendor == VENDORPEC_UKERNA) &&
- !isInternalAttributeP(attrid, vendor);
-}
-
-static bool
-isFragmentedAttributeP(uint32_t attribute)
-{
- return isFragmentedAttributeP(ATTRID(attribute), VENDOR(attribute));
+ return (attrid.first == VENDORPEC_UKERNA) &&
+ !isInternalAttributeP(attrid);
}
/*
* Copy AVP list, same as paircopy except it filters out attributes
* containing keys.
*/
-static VALUE_PAIR *
-copyAvps(const VALUE_PAIR *src)
+static rs_avp *
+copyAvps(rs_const_avp *src)
{
- const VALUE_PAIR *vp;
- VALUE_PAIR *dst = NULL, **pDst = &dst;
+ rs_const_avp *vp;
+ rs_avp *dst = NULL;
- for (vp = src; vp != NULL; vp = vp->next) {
- VALUE_PAIR *vpcopy;
+ for (vp = src; vp != NULL; vp = rs_avp_next_const(vp)) {
+ rs_avp *vpcopy;
- if (isSecretAttributeP(vp->attribute))
+ if (isSecretAttributeP(vp))
continue;
- vpcopy = paircopyvp(vp);
+ vpcopy = rs_avp_dup(vp);
if (vpcopy == NULL) {
- pairfree(&dst);
+ rs_avp_free(&dst);
throw std::bad_alloc();
}
- *pDst = vpcopy;
- pDst = &vpcopy->next;
+
+ rs_avp_append(&dst, vpcopy);
}
return dst;
gss_eap_radius_attr_provider::getAttributeTypes(gss_eap_attr_enumeration_cb addAttribute,
void *data) const
{
- VALUE_PAIR *vp;
- std::vector <std::string> seen;
+ rs_avp *vp;
+ std::vector <gss_eap_attrid> seen;
- for (vp = m_vps; vp != NULL; vp = vp->next) {
- gss_buffer_desc attribute;
- char attrid[64];
+ for (vp = m_vps; vp != NULL; vp = rs_avp_next(vp)) {
+ gss_buffer_desc desc;
+ gss_eap_attrid attrid;
+ char buf[64];
/* Don't advertise attributes that are internal to the GSS-EAP mechanism */
- if (isInternalAttributeP(vp->attribute))
+ if (isInternalAttributeP(vp))
continue;
- if (alreadyAddedAttributeP(seen, vp))
+ rs_avp_attrid(vp, &attrid.second, &attrid.first);
+
+ if (alreadyAddedAttributeP(seen, attrid))
continue;
- snprintf(attrid, sizeof(attrid), "%s%d",
- (char *)radiusUrnPrefix.value, vp->attribute);
+ if (rs_attr_display_name(attrid.second, attrid.first,
+ buf, sizeof(buf), TRUE) != RSE_OK ||
+ strncmp(buf, "Attr-", 5) != 0)
+ continue;
- attribute.value = attrid;
- attribute.length = strlen(attrid);
+ desc.value = &buf[5];
+ desc.length = strlen((char *)desc.value);
- if (!addAttribute(m_manager, this, &attribute, data))
+ if (!addAttribute(m_manager, this, &desc, data))
return false;
- seen.push_back(std::string(vp->name));
+ seen.push_back(attrid);
}
return true;
}
-uint32_t
-getAttributeId(const gss_buffer_t attr)
+static bool
+getAttributeId(const gss_buffer_t desc,
+ gss_eap_attrid *attrid)
{
- OM_uint32 tmpMinor;
- gss_buffer_desc strAttr = GSS_C_EMPTY_BUFFER;
- DICT_ATTR *da;
- char *s;
- uint32_t attrid = 0;
+ char *strAttr, *s;
+ int canon, code;
- if (attr->length < radiusUrnPrefix.length ||
- memcmp(attr->value, radiusUrnPrefix.value, radiusUrnPrefix.length) != 0)
- return 0;
+ if (desc->length == 0)
+ return false;
+
+ canon = isdigit(*(char *)desc->value);
/* need to duplicate because attr may not be NUL terminated */
- duplicateBuffer(*attr, &strAttr);
- s = (char *)strAttr.value + radiusUrnPrefix.length;
+ strAttr = (char *)GSSEAP_MALLOC((canon ? 5 : 0) + desc->length + 1);
+ if (strAttr == NULL)
+ throw new std::bad_alloc();
- if (isdigit(*s)) {
- attrid = strtoul(s, NULL, 10);
- } else {
- da = dict_attrbyname(s);
- if (da != NULL)
- attrid = da->attr;
+ s = strAttr;
+
+ if (canon) {
+ memcpy(s, "Attr-", 5);
+ s += 5;
}
- gss_release_buffer(&tmpMinor, &strAttr);
+ memcpy(s, desc->value, desc->length);
+ s += desc->length;
+ *s = '\0';
- return attrid;
+ code = rs_attr_parse_name(strAttr, &attrid->second, &attrid->first);
+
+ GSSEAP_FREE(strAttr);
+
+ return (code == RSE_OK);
}
bool
gss_eap_radius_attr_provider::setAttribute(int complete GSSEAP_UNUSED,
- uint32_t attrid,
+ const gss_eap_attrid &attrid,
const gss_buffer_t value)
{
OM_uint32 major = GSS_S_UNAVAILABLE, minor;
!isInternalAttributeP(attrid)) {
deleteAttribute(attrid);
- major = gssEapRadiusAddAvp(&minor, &m_vps,
- ATTRID(attrid), VENDOR(attrid),
- value);
+ major = gssEapRadiusAddAvp(&minor, &m_vps, attrid, value);
}
return !GSS_ERROR(major);
const gss_buffer_t attr,
const gss_buffer_t value)
{
- uint32_t attrid = getAttributeId(attr);
+ gss_eap_attrid attrid;
- if (!attrid)
+ if (!getAttributeId(attr, &attrid))
return false;
return setAttribute(complete, attrid, value);
}
bool
-gss_eap_radius_attr_provider::deleteAttribute(uint32_t attrid)
+gss_eap_radius_attr_provider::deleteAttribute(const gss_eap_attrid &attrid)
{
- if (isSecretAttributeP(attrid) || isInternalAttributeP(attrid) ||
- pairfind(m_vps, attrid) == NULL)
+ if (isSecretAttributeP(attrid) ||
+ isInternalAttributeP(attrid) ||
+ rs_avp_find(m_vps, attrid.second, attrid.first) == NULL)
return false;
- pairdelete(&m_vps, attrid);
-
- return true;
+ return (rs_avp_delete(&m_vps, attrid.second, attrid.first) == RSE_OK);
}
bool
gss_eap_radius_attr_provider::deleteAttribute(const gss_buffer_t attr)
{
- uint32_t attrid = getAttributeId(attr);
+ gss_eap_attrid attrid;
- if (!attrid)
+ if (!getAttributeId(attr, &attrid))
return false;
return deleteAttribute(attrid);
gss_buffer_t display_value,
int *more) const
{
- uint32_t attrid;
+ gss_eap_attrid attrid;
- attrid = getAttributeId(attr);
- if (!attrid)
+ if (!getAttributeId(attr, &attrid))
return false;
- return getAttribute(attrid, authenticated, complete,
+ return getAttribute(attrid,
+ authenticated, complete,
value, display_value, more);
}
bool
-gss_eap_radius_attr_provider::getAttribute(uint32_t attrid,
+gss_eap_radius_attr_provider::getAttribute(const gss_eap_attrid &attrid,
int *authenticated,
int *complete,
gss_buffer_t value,
gss_buffer_t display_value,
int *more) const
{
- VALUE_PAIR *vp;
+ rs_const_avp *vp;
int i = *more, count = 0;
*more = 0;
if (i == -1)
i = 0;
- if (isSecretAttributeP(attrid) || isInternalAttributeP(attrid)) {
+ if (isSecretAttributeP(attrid) ||
+ isInternalAttributeP(attrid)) {
return false;
} else if (isFragmentedAttributeP(attrid)) {
return getFragmentedAttribute(attrid,
value);
}
- for (vp = pairfind(m_vps, attrid);
+ for (vp = rs_avp_find_const(m_vps, attrid.second, attrid.first);
vp != NULL;
- vp = pairfind(vp->next, attrid)) {
+ vp = rs_avp_find_const(rs_avp_next_const(vp), attrid.second, attrid.first)) {
if (count++ == i) {
- if (pairfind(vp->next, attrid) != NULL)
+ if (rs_avp_find_const(rs_avp_next_const(vp), attrid.second, attrid.first) != NULL)
*more = count;
break;
}
if (value != GSS_C_NO_BUFFER) {
gss_buffer_desc valueBuf;
- valueBuf.value = (void *)vp->vp_octets;
- valueBuf.length = vp->length;
+ rs_avp_octets_value_byref((rs_avp *)vp,
+ (unsigned char **)&valueBuf.value,
+ &valueBuf.length);
duplicateBuffer(valueBuf, value);
}
if (display_value != GSS_C_NO_BUFFER &&
- vp->type != PW_TYPE_OCTETS) {
- char displayString[MAX_STRING_LEN];
+ !rs_avp_is_octets(vp)) {
+ char displayString[RS_MAX_STRING_LEN];
gss_buffer_desc displayBuf;
- displayBuf.length = vp_prints_value(displayString,
- sizeof(displayString), vp, 0);
+ displayBuf.length = rs_avp_display_value(vp, displayString,
+ sizeof(displayString));
displayBuf.value = (void *)displayString;
duplicateBuffer(displayBuf, display_value);
}
bool
-gss_eap_radius_attr_provider::getFragmentedAttribute(uint16_t attribute,
- uint16_t vendor,
+gss_eap_radius_attr_provider::getFragmentedAttribute(const gss_eap_attrid &attrid,
int *authenticated,
int *complete,
gss_buffer_t value) const
{
OM_uint32 major, minor;
- major = gssEapRadiusGetAvp(&minor, m_vps, attribute, vendor, value, TRUE);
+ major = gssEapRadiusGetAvp(&minor, m_vps, attrid, value, TRUE);
if (authenticated != NULL)
*authenticated = m_authenticated;
return !GSS_ERROR(major);
}
-bool
-gss_eap_radius_attr_provider::getFragmentedAttribute(uint32_t attrid,
- int *authenticated,
- int *complete,
- gss_buffer_t value) const
-{
- return getFragmentedAttribute(ATTRID(attrid), VENDOR(attrid),
- authenticated, complete, value);
-}
-
-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 GSSEAP_UNUSED) const
gss_eap_radius_attr_provider::releaseAnyNameMapping(gss_buffer_t type_id GSSEAP_UNUSED,
gss_any_t input) const
{
- VALUE_PAIR *vp = (VALUE_PAIR *)input;
- pairfree(&vp);
+ rs_avp *vp = (rs_avp *)input;
+ rs_avp_free(&vp);
}
bool
return new gss_eap_radius_attr_provider;
}
-OM_uint32
+static OM_uint32
gssEapRadiusAddAvp(OM_uint32 *minor,
- VALUE_PAIR **vps,
- uint16_t attribute,
- uint16_t vendor,
+ rs_avp **vps,
+ const gss_eap_attrid &attrid,
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;
+ rs_avp *vp;
size_t n = remain;
/*
* There's an extra byte of padding; RADIUS AVPs can only
* be 253 octets.
*/
- if (n >= MAX_STRING_LEN)
- n = MAX_STRING_LEN - 1;
+ if (n >= RS_MAX_STRING_LEN)
+ n = RS_MAX_STRING_LEN - 1;
- vp = paircreate(attrid, PW_TYPE_OCTETS);
+ vp = rs_avp_alloc(attrid.second, attrid.first);
if (vp == NULL) {
*minor = ENOMEM;
return GSS_S_FAILURE;
}
- memcpy(vp->vp_octets, p, n);
- vp->length = n;
+ rs_avp_octets_set(vp, p, n);
- pairadd(vps, vp);
+ rs_avp_append(vps, vp);
p += n;
remain -= n;
}
OM_uint32
-gssEapRadiusGetRawAvp(OM_uint32 *minor,
- VALUE_PAIR *vps,
- uint16_t attribute,
- uint16_t vendor,
- VALUE_PAIR **vp)
+gssEapRadiusAddAvp(OM_uint32 *minor,
+ struct rs_packet *pkt,
+ unsigned int attribute,
+ unsigned int vendor,
+ const gss_buffer_t buffer)
{
- uint32_t attr = VENDORATTR(vendor, attribute);
+ gss_eap_attrid attrid(vendor, attribute);
+ int code;
+
+ code = rs_packet_append_avp(pkt, attrid.second, attrid.first,
+ buffer->value, buffer->length);
+ if (code != RSE_OK) {
+ *minor = RS_MAP_ERROR(code);
+ return GSS_S_FAILURE;
+ }
- *vp = pairfind(vps, attr);
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gssEapRadiusGetRawAvp(OM_uint32 *minor,
+ rs_const_avp *vps,
+ unsigned int attribute,
+ unsigned int vendor,
+ rs_const_avp **vp)
+{
+ *vp = rs_avp_find_const(vps, attribute, vendor);
if (*vp == NULL) {
*minor = GSSEAP_NO_SUCH_ATTR;
return GSS_S_UNAVAILABLE;
return GSS_S_COMPLETE;
}
-OM_uint32
+static OM_uint32
gssEapRadiusGetAvp(OM_uint32 *minor,
- VALUE_PAIR *vps,
- uint16_t attribute,
- uint16_t vendor,
+ rs_avp *vps,
+ const gss_eap_attrid &attrid,
gss_buffer_t buffer,
int concat)
{
- VALUE_PAIR *vp;
- unsigned char *p;
- uint32_t attr = VENDORATTR(vendor, attribute);
+ rs_const_avp *vp;
+ int err;
if (buffer != GSS_C_NO_BUFFER) {
buffer->length = 0;
buffer->value = NULL;
}
- vp = pairfind(vps, attr);
+ vp = rs_avp_find_const(vps, attrid.second, attrid.first);
if (vp == NULL) {
*minor = GSSEAP_NO_SUCH_ATTR;
return GSS_S_UNAVAILABLE;
}
if (buffer != GSS_C_NO_BUFFER) {
- do {
- buffer->length += vp->length;
- } while (concat && (vp = pairfind(vp->next, attr)) != NULL);
+ if (concat)
+ rs_avp_fragmented_value(vp, NULL, &buffer->length);
+ else
+ buffer->length = rs_avp_length(vp);
buffer->value = GSSEAP_MALLOC(buffer->length);
if (buffer->value == NULL) {
return GSS_S_FAILURE;
}
- p = (unsigned char *)buffer->value;
+ if (concat)
+ err = rs_avp_fragmented_value(vp, (unsigned char *)buffer->value, &buffer->length);
+ else
+ err = rs_avp_octets_value(vp, (unsigned char *)buffer->value, &buffer->length);
- for (vp = pairfind(vps, attr);
- concat && vp != NULL;
- vp = pairfind(vp->next, attr)) {
- memcpy(p, vp->vp_octets, vp->length);
- p += vp->length;
+ if (err != 0) {
+ *minor = RS_MAP_ERROR(err);
+ return GSS_S_FAILURE;
}
}
}
OM_uint32
+gssEapRadiusGetAvp(OM_uint32 *minor,
+ struct rs_packet *pkt,
+ unsigned int attribute,
+ unsigned int vendor,
+ gss_buffer_t buffer,
+ int concat)
+{
+ rs_avp **vps;
+ gss_eap_attrid attrid(vendor, attribute);
+
+ rs_packet_avps(pkt, &vps);
+
+ return gssEapRadiusGetAvp(minor, *vps, attrid, buffer, concat);
+}
+
+OM_uint32
gssEapRadiusFreeAvps(OM_uint32 *minor,
- VALUE_PAIR **vps)
+ rs_avp **vps)
{
- pairfree(vps);
+ rs_avp_free(vps);
*minor = 0;
return GSS_S_COMPLETE;
}
}
static JSONObject
-avpToJson(const VALUE_PAIR *vp)
+avpToJson(rs_const_avp *vp)
{
JSONObject obj;
+ gss_eap_attrid attrid;
- GSSEAP_ASSERT(vp->length <= MAX_STRING_LEN);
+ GSSEAP_ASSERT(rs_avp_length(vp) <= RS_MAX_STRING_LEN);
- switch (vp->type) {
- case PW_TYPE_INTEGER:
- case PW_TYPE_IPADDR:
- case PW_TYPE_DATE:
- obj.set("value", vp->lvalue);
+ switch (rs_avp_typeof(vp)) {
+ case RS_TYPE_INTEGER:
+ obj.set("value", rs_avp_integer_value(vp));
+ break;
+ case RS_TYPE_DATE:
+ obj.set("value", rs_avp_date_value(vp));
break;
- case PW_TYPE_STRING:
- obj.set("value", vp->vp_strvalue);
+ case RS_TYPE_STRING:
+ obj.set("value", rs_avp_string_value(vp));
break;
default: {
char *b64;
- if (base64Encode(vp->vp_octets, vp->length, &b64) < 0)
+ if (base64Encode(rs_avp_octets_value_const_ptr(vp),
+ rs_avp_length(vp), &b64) < 0)
throw std::bad_alloc();
obj.set("value", b64);
}
}
- obj.set("type", vp->attribute);
+ attrid = avpToAttrId(vp);
+
+ obj.set("type", attrid.second);
+ if (attrid.first != 0)
+ obj.set("vendor", attrid.first);
return obj;
}
static bool
-jsonToAvp(VALUE_PAIR **pVp, JSONObject &obj)
+jsonToAvp(rs_avp **pVp, JSONObject &obj)
{
- VALUE_PAIR *vp = NULL;
- DICT_ATTR *da;
- uint32_t attrid;
+ rs_avp *vp = NULL;
+ gss_eap_attrid attrid;
JSONObject type = obj["type"];
+ JSONObject vendor = obj["vendor"];
JSONObject value = obj["value"];
if (!type.isInteger())
goto fail;
+ attrid.second = type.integer();
- attrid = type.integer();
- da = dict_attrbyvalue(attrid);
- if (da != NULL) {
- vp = pairalloc(da);
+ if (!vendor.isNull()) {
+ if (!vendor.isInteger())
+ goto fail;
+ attrid.first = vendor.integer();
} else {
- int type = base64Valid(value.string()) ?
- PW_TYPE_OCTETS : PW_TYPE_STRING;
- vp = paircreate(attrid, type);
+ attrid.first = 0;
}
+
+ vp = rs_avp_alloc(attrid.second, attrid.first);
if (vp == NULL)
throw std::bad_alloc();
- switch (vp->type) {
- case PW_TYPE_INTEGER:
- case PW_TYPE_IPADDR:
- case PW_TYPE_DATE:
+ switch (rs_avp_typeof(vp)) {
+ case RS_TYPE_INTEGER:
+ case RS_TYPE_IPADDR:
+ case RS_TYPE_DATE:
if (!value.isInteger())
goto fail;
- vp->length = 4;
- vp->lvalue = value.integer();
+ if (rs_avp_integer_set(vp, value.integer()) != RSE_OK)
+ goto fail;
+
break;
- case PW_TYPE_STRING: {
+ case RS_TYPE_STRING: {
if (!value.isString())
goto fail;
- const char *str = value.string();
- size_t len = strlen(str);
-
- if (len >= MAX_STRING_LEN)
+ if (rs_avp_string_set(vp, value.string()) != RSE_OK)
goto fail;
- vp->length = len;
- memcpy(vp->vp_strvalue, str, len + 1);
break;
}
- case PW_TYPE_OCTETS:
+ case RS_TYPE_OCTETS:
default: {
+ unsigned char buf[RS_MAX_STRING_LEN];
+
if (!value.isString())
goto fail;
ssize_t len = strlen(str);
/* this optimization requires base64Decode only understand packed encoding */
- if (len >= BASE64_EXPAND(MAX_STRING_LEN))
+ if (len >= BASE64_EXPAND(RS_MAX_STRING_LEN))
goto fail;
- len = base64Decode(str, vp->vp_octets);
+ len = base64Decode(str, buf);
if (len < 0)
goto fail;
- vp->length = len;
+ if (rs_avp_octets_set(vp, buf, len) != RSE_OK)
+ goto fail;
+
break;
}
}
fail:
if (vp != NULL)
- pairbasicfree(vp);
+ rs_avp_free(&vp);
*pVp = NULL;
return false;
}
gss_eap_radius_attr_provider::initWithJsonObject(const gss_eap_attr_ctx *ctx,
JSONObject &obj)
{
- VALUE_PAIR **pNext = &m_vps;
-
if (!gss_eap_attr_provider::initWithJsonObject(ctx, obj))
return false;
for (size_t i = 0; i < nelems; i++) {
JSONObject attr = attrs[i];
- VALUE_PAIR *vp;
+ rs_avp *vp;
if (!jsonToAvp(&vp, attr))
return false;
- *pNext = vp;
- pNext = &vp->next;
+ rs_avp_append(&m_vps, vp);
}
m_authenticated = obj["authenticated"].integer() ? true : false;
const char *
gss_eap_radius_attr_provider::prefix(void) const
{
- return "urn:ietf:params:gss-eap:radius-avp";
+ return "urn:ietf:params:gss:radius-attribute";
}
JSONObject
{
JSONObject obj, attrs = JSONObject::array();
- for (VALUE_PAIR *vp = m_vps; vp != NULL; vp = vp->next) {
+ for (rs_avp *vp = m_vps; vp != NULL; vp = rs_avp_next(vp)) {
JSONObject attr = avpToJson(vp);
attrs.append(attr);
}
time_t
gss_eap_radius_attr_provider::getExpiryTime(void) const
{
- VALUE_PAIR *vp;
+ rs_const_avp *vp;
+ uint32_t value;
+
+ vp = rs_avp_find(m_vps, PW_SESSION_TIMEOUT, 0);
+ if (vp == NULL)
+ return 0;
- vp = pairfind(m_vps, PW_SESSION_TIMEOUT);
- if (vp == NULL || vp->lvalue == 0)
+ value = rs_avp_integer_value(vp);
+ if (value == 0)
return 0;
- return time(NULL) + vp->lvalue;
+ return time(NULL) + value;
}
OM_uint32
return GSS_S_COMPLETE;
}
- *minor = ERROR_TABLE_BASE_rse + code;
+ *minor = RS_MAP_ERROR(code);
gssEapSaveStatusInfo(*minor, "%s", rs_err_msg(err));
rs_err_free(err);
goto fail;
}
- if (rs_context_init_freeradius_dict(radContext, NULL) != 0) {
- err = rs_err_ctx_pop(radContext);
- goto fail;
- }
-
*pRadContext = radContext;
*minor = 0;
#ifdef __cplusplus
+typedef std::pair <unsigned int, unsigned int> gss_eap_attrid;
#ifdef GSSEAP_ENABLE_ACCEPTOR
+
struct gss_eap_radius_attr_provider : gss_eap_attr_provider {
public:
gss_eap_radius_attr_provider(void);
JSONObject &obj);
JSONObject jsonRepresentation(void) const;
- 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,
+ bool getAttribute(const gss_eap_attrid &attrid,
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_eap_attrid &attrid,
const gss_buffer_t value);
- bool deleteAttribute(uint32_t attribute);
+ bool deleteAttribute(const gss_eap_attrid &attrid);
- bool getFragmentedAttribute(uint16_t attribute,
- uint16_t vendor,
- int *authenticated,
- int *complete,
- gss_buffer_t value) const;
- bool getFragmentedAttribute(uint32_t attrid,
+ bool getFragmentedAttribute(const gss_eap_attrid &attrid,
int *authenticated,
int *complete,
gss_buffer_t value) const;
static gss_eap_attr_provider *createAttrContext(void);
private:
- const VALUE_PAIR *getAvps(void) const {
+ rs_const_avp *getAvps(void) const {
return m_vps;
}
- VALUE_PAIR *m_vps;
+ rs_avp *m_vps;
bool m_authenticated;
};
OM_uint32
gssEapRadiusAddAvp(OM_uint32 *minor,
- VALUE_PAIR **vp,
- uint16_t type,
- uint16_t vendor,
+ struct rs_packet *pkt,
+ unsigned int type,
+ unsigned int vendor,
const gss_buffer_t buffer);
OM_uint32
gssEapRadiusGetAvp(OM_uint32 *minor,
- VALUE_PAIR *vps,
- uint16_t type,
- uint16_t vendor,
+ struct rs_packet *pkt,
+ unsigned int type,
+ unsigned int 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);
+ rs_const_avp *vps,
+ unsigned int type,
+ unsigned int vendor,
+ rs_const_avp **vp);
OM_uint32
gssEapRadiusFreeAvps(OM_uint32 *minor,
- VALUE_PAIR **vps);
+ rs_avp **vps);
OM_uint32 gssEapRadiusAttrProviderInit(OM_uint32 *minor);
OM_uint32 gssEapRadiusAttrProviderFinalize(OM_uint32 *minor);
/* This really needs to be a function call on Windows */
#define RS_CONFIG_FILE SYSCONFDIR "/radsec.conf"
-#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 PW_MS_WINDOWS_AUTH_DATA 133
-
#ifdef __cplusplus
}
#endif
credBuf->length = 0;
credBuf->value = NULL;
+ if (ctx->acceptorName == GSS_C_NO_NAME) {
+ *minor = GSSEAP_NO_ACCEPTOR_NAME;
+ return GSS_S_UNAVAILABLE;
+ }
+
GSSEAP_KRB_INIT(&krbContext);
code = getAcceptorKey(krbContext, ctx, cred, &server, &acceptorKey);
#ifndef HAVE_HEIMDAL_VERSION
static gss_buffer_desc radiusAvpKrbAttr = {
- sizeof("urn:authdata-radius-avp") - 1, "urn:authdata-radius-avp"
+ sizeof("urn:authdata-aaa-radius") - 1, "urn:authdata-aaa-radius"
};
#endif
gss_buffer_desc value = GSS_C_EMPTY_BUFFER;
int authenticated, complete;
OM_uint32 minor;
+ gss_eap_attrid attrid(VENDORPEC_UKERNA, PW_SAML_AAA_ASSERTION);
GSSEAP_ASSERT(m_assertion == NULL);
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)) {
+ radius->getFragmentedAttribute(attrid, &authenticated, &complete, &value)) {
setAssertion(&value, authenticated);
gss_release_buffer(&minor, &value);
} else {
const char *
gss_eap_saml_assertion_provider::prefix(void) const
{
- return "urn:ietf:params:gss-eap:saml-aaa-assertion";
+ return "urn:ietf:params:gss:federated-saml-assertion";
}
bool
* 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
+ * urn:ietf:params:gss:federated-saml-attribute. 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
const char *
gss_eap_saml_attr_provider::prefix(void) const
{
- return "urn:ietf:params:gss-eap:saml-attr";
+ return "urn:ietf:params:gss:federated-saml-attribute";
}
bool
const gss_eap_radius_attr_provider *radius;
int authenticated, complete;
gss_buffer_desc value = GSS_C_EMPTY_BUFFER;
+ gss_eap_attrid attrid(VENDORPEC_UKERNA, PW_SAML_AAA_ASSERTION);
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)) {
+ radius->getFragmentedAttribute(attrid, &authenticated, &complete, &value)) {
string str((char *)value.value, value.length);
istringstream istream(str);
DOMDocument *doc = XMLToolingConfig::getConfig().getParser().parse(istream);