ctx->gssFlags |= GSS_C_ANON_FLAG;
}
- major = gssEapImportName(minor, &nameBuf, GSS_C_NT_USER_NAME,
+ major = gssEapImportName(minor, &nameBuf,
+ (ctx->gssFlags & GSS_C_ANON_FLAG) ?
+ GSS_C_NT_ANONYMOUS : GSS_C_NT_USER_NAME,
&ctx->initiatorName);
if (GSS_ERROR(major))
return major;
gss_buffer_t outputToken)
{
OM_uint32 major;
- union {
- struct eap_hdr pdu;
- unsigned char data[5];
- } pkt;
+ struct wpabuf *reqData;
gss_buffer_desc pktBuffer;
if (inputToken != GSS_C_NO_BUFFER && inputToken->length != 0) {
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;
+ reqData = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, 0,
+ EAP_CODE_REQUEST, 0);
+ if (reqData == NULL) {
+ *minor = ENOMEM;
+ return GSS_S_FAILURE;
+ }
- pktBuffer.length = sizeof(pkt.data);
- pktBuffer.value = pkt.data;
+ pktBuffer.length = wpabuf_len(reqData);
+ pktBuffer.value = (void *)wpabuf_head(reqData);
major = duplicateBuffer(minor, &pktBuffer, outputToken);
if (GSS_ERROR(major))
ctx->state = GSSEAP_STATE_AUTHENTICATE;
+ wpabuf_free(reqData);
+
*minor = 0;
return GSS_S_CONTINUE_NEEDED;
}
/*
+ * Returns TRUE if the input token contains an EAP identity response.
+ */
+static int
+isIdentityResponseP(gss_buffer_t inputToken)
+{
+ struct wpabuf respData;
+
+ wpabuf_set(&respData, inputToken->value, inputToken->length);
+
+ return (eap_get_type(&respData) == EAP_TYPE_IDENTITY);
+}
+
+/*
+ * Save the asserted initiator identity from the EAP identity response.
+ */
+static OM_uint32
+importInitiatorIdentity(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ gss_buffer_t inputToken)
+{
+ OM_uint32 tmpMinor;
+ struct wpabuf respData;
+ const unsigned char *pos;
+ size_t len;
+ gss_buffer_desc nameBuf;
+
+ wpabuf_set(&respData, inputToken->value, inputToken->length);
+
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY,
+ &respData, &len);
+ if (pos == NULL) {
+ *minor = GSSEAP_PEER_BAD_MESSAGE;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ nameBuf.value = (void *)pos;
+ nameBuf.length = len;
+
+ gssEapReleaseName(&tmpMinor, &ctx->initiatorName);
+
+ return gssEapImportName(minor, &nameBuf, GSS_C_NT_USER_NAME,
+ &ctx->initiatorName);
+}
+
+/*
+ * Pass the asserted initiator identity to the authentication server.
+ */
+static OM_uint32
+setInitiatorIdentity(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ VALUE_PAIR **vps)
+{
+ OM_uint32 major, tmpMinor;
+ gss_buffer_desc nameBuf;
+
+ /*
+ * We should have got an EAP identity response, but if we didn't, then
+ * we will just avoid sending User-Name. Note that radsecproxy requires
+ * User-Name to be sent on every request (presumably so it can remain
+ * stateless).
+ */
+ if (ctx->initiatorName != GSS_C_NO_NAME) {
+ major = gssEapDisplayName(minor, ctx->initiatorName, &nameBuf, NULL);
+ if (GSS_ERROR(major))
+ return major;
+
+ major = gssEapRadiusAddAvp(minor, vps, PW_USER_NAME, 0, &nameBuf);
+ if (GSS_ERROR(major))
+ return major;
+
+ gss_release_buffer(&tmpMinor, &nameBuf);
+ }
+
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
+
+/*
* Pass the asserted acceptor identity to the authentication server.
*/
static OM_uint32
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;
+ if (isIdentityResponseP(inputToken)) {
+ major = importInitiatorIdentity(minor, ctx, inputToken);
+ if (GSS_ERROR(major))
+ return major;
}
rconn = ctx->acceptorCtx.radConn;
}
frreq = rs_packet_frpkt(req);
- if (sendAcceptorIdentity) {
- major = setAcceptorIdentity(minor, ctx, &frreq->vps);
- if (GSS_ERROR(major))
- goto cleanup;
- }
+ major = setInitiatorIdentity(minor, ctx, &frreq->vps);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ major = setAcceptorIdentity(minor, ctx, &frreq->vps);
+ if (GSS_ERROR(major))
+ goto cleanup;
major = gssEapRadiusAddAvp(minor, &frreq->vps,
PW_EAP_MESSAGE, 0, inputToken);
}
rs_request_add_reqpkt(request, req);
+ req = NULL;
if (rs_request_send(request, &resp) != 0) {
major = gssEapRadiusMapError(minor, rs_err_conn_pop(rconn));
major = GSS_S_CONTINUE_NEEDED;
cleanup:
- rs_request_destroy(request);
+ if (request != NULL)
+ rs_request_destroy(request);
+ if (req != NULL)
+ rs_packet_destroy(req);
return major;
}
output_token->length = 0;
output_token->value = NULL;
+ if (src_name != NULL)
+ *src_name = GSS_C_NO_NAME;
+
if (input_token == GSS_C_NO_BUFFER || input_token->length == 0) {
*minor = GSSEAP_TOK_TRUNC;
return GSS_S_DEFECTIVE_TOKEN;