# Include EAP types. If you uncomment any here, also uncomment them from
# the EAP function body.

include eapfunctions.md5,
include eapfunctions.ttls,


# Main EAP body

function EAP (

  # Decode all concatenated EAP-Message attributes into the request list, using
  # the attribute space in which the dummy attribute 'EAP-Packet' is defined.

  all EAP-Message dictdecode EAP-Packet or (
    rep:Log-Line = rep:Log-Line = " - Could not decode EAP packet!",
    return (result = Access-Reject)
  ),
  #Ascdebug 0, del REP:int,

  # Initialize reply list (on which an EAP Request to the peer is built ;-)
  # EAP type specific functions will increment rep:Id wherever necessary.
  # This sets things up so that you can just exit with a Success or Failure.

  rep:Id = Id,

  # Handle Response/Identity. Here we initiate the EAP conversation by starting
  # our first preferred EAP type.

  Response-Identity exists and (
    rep:Log-Line := rep:Log-Line . " EAP: Identity " . Response-Identity,
    Response-Identity != User-Name and (
      rep:Log-Line := rep:Log-Line . " - does not match User-Name!"

      # We just warn. You could also fail here or perform a new user lookup,
      # eg. in a 'identities' space. 
    ),

    EAP-MD5
  )

  # Handle NAK and Expanded-NAK. 

  or (Response-Nak exists or Response-Exp-Nak exists) and (
    rep:Log-Line := rep:Log-Line . " EAP: Got NAK, client accepts types " . (hex (Response-Nak . Response-Exp-Nak)) asmac ", ",

    # Forget all state coming from previous types. You could also keep the
    # first NAK in the state DB to reject if the client appears to change its
    # mind regarding supported EAP types during negotiation, to prevent endless
    # loops with buggy clients.

    delall strval, delall ordval, 

    # Test for EAP types supported by client in order of our preference.

    0
    or (NAK-TTLS exists or NAK-Exp-TTLS exists) and (EAP-TTLS)
    or (NAK-MD5-Challenge exists or NAK-Exp-MD5-Challenge exists) and (EAP-MD5)

    # Always put this last; if an EAP type is requested that is undefined in
    # our dictionary, this is what we do.

    or (NAK-Unknown exists or NAK-Exp-Unknown exists) and (
      rep:Log-Line := rep:Log-Line . 
		      " - none of them supported here, rejecting.",
      rep:Failure = 1
    )
  )
  
  # Handle type-specific responses by branching to applicable EAP type

  or Response-MD5-Challenge exists and EAP-MD5
  or Response-TTLS exists and EAP-TTLS,

  # Encode reply list into EAP-Message (will be auto-split when encoding the
  # RADIUS packet) using space of dummy attribute 'EAP-Packet' as ground space

  rep:EAP-Message = dictencode rep:EAP-Packet,

  # We're done here. Set the result according to the EAP status. The top level
  # behaviour file will act upon it.

  rep:Success exists and return (result = Access-Accept),
  rep:Failure exists and return (result = Access-Reject),
  return (result = Access-Challenge)
)

# vim:softtabstop=2:sw=2

