########################################################################### # # BEHAVIOUR - Expression that defines the server's operating rules # # This is compiled at startup and ran for every request that comes in. # Upon entry, the REQUEST list of A/V pairs is already populated with # information from and about the request. Upon exit, the REPLY list is # used to build a response to send to the client. # # Other than the attributes / fixed fields you want to send, you need # to set the first instance of the attribute 'Secret' (see subdicts/dict. # internal) to the shared secret to be used for signing the response. # You also need to set the first instance of the RAD-Authenticator # attribute to the value that this attribute had in the original request; # i.e. copying the attribute from the REQUEST list to the REPLY list. # The same goes for the RAD-Identifier attribute and all instances of # the Proxy-State attribute. See RFC 2865 why. # # Then, when the expression completes (that is without being aborted), # the server will first build the packet only based on the attributes # on the REPLY list, so at first also putting in the original request # authenticator as the response authenticator. It will then sign the # packet using the shared secret provided on the reply list, putting the # signature over the original response authenticator, to create a valid # RADIUS response. # # See openradius-language.html for a list neatly showing all operators, # with contexts, precedence, association and auto-conversion properties. # # The 'and' and 'or' operators do short-circuit boolean evaluation as they do # in C, Perl and shell scripts - that's how conditional subexpressions # are implemented. # # This language has hardly any syntax, other than that a term may be # not be directly followed by another term. # ## # # This is a simpler example expression file that goes together with the # distributed 'configuration' file. It allows RADIUS clients to be listed # in an ASCII file .../raddb/legacy/clients, and uses the standard Unix # password database. # # (paths are dependent on what's specified in the configuration file). # # More specifically, this file provides the following rules: # # 1. look up the secret for the radius client by IP address, using the # Oldclients interface that uses the ascfile module to return # information from a flat file that lists the IP addresses and their # secrets next to each other, normally .../raddb/legacy/clients; # # 2. if not found, log the event using the Errorlogger interface that # uses the radlogger shell script module to log the message, normally # in /var/log/raderr.log and drops the request. Otherwise continue: # # 3. initialise the reply list by copying the Identifier, Authenticator # and all Proxy-State attributes from the request; # # 4. see if we're accounting. If so, verify the request authenticator # and put the result in Acct-Authentic, log the information using # the Acctlogger interface that uses the radlogger module. If that # didn't succeed, drop the request; otherwise, set RAD-Code to # Accounting-Response and halt the expression so that the client is # answered. But if we're authenticating: # # 5. set RAD-Code to Access-Reject and Reply-Message to something nasty, # so we can send a valid response that rejects users by simply # halting the expression at any point; # # 6. if a PAP password was supplied in the request, decrypt that # using the shared secret that was found for this client. # Otherwise we're already done. # # 7. log the request using the Stdlogger interface that uses the # radlogger shell script to log the username, password, CHAP # challenge and password, NAS IP and port, as per the send ACL # defined in the configuration file for the Stdlogger interface; # ########################################################################### # # Step 1 & 2: Look up client's secret by packet's source IP address; log # error and drop request if not found # Set the first 'str' instance to IP-Source (type conversion is # automatic), call Oldclients and evaluate the returned 'str' instance # as a boolean (false if nonexistant or empty). Oldclients(str=IP-Source), str or ( Errorlogger(str=Timestamp as "%c" . ": Request from unknown client " . IP-Source . " identified as NAS " . (NAS-Identifier or NAS-IP-Address) . " for user " . User-Name . " - ignored."), abort ), # Save returned string attribute in REP:Secret and delete the parameter # and the returned attributes. Note that the 'del' operator has the # REQUEST list as default for lowercase attributes because of rule c. Secret = str, del str, del REP:int, del REP:str, ########################################################################### # # Step 3: Initialise reply list RAD-Code = Access-Reject, RAD-Identifier = RAD-Identifier, RAD-Authenticator = "" . RAD-Authenticator, # we need a copy moveall Proxy-State, ########################################################################### # # Step 4: Handle accounting RAD-Code == Accounting-Request and ( # Verify request authenticator REQ:Acct-Authenticator = Mismatch, REQ:RAD-Authenticator pokedwith "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", REP:RAD-Authenticator == md5 (RAD-Packet . REP:Secret) and REQ:Acct-Authenticator := Verified, # Always log it; drop request if that fails Acctlogger(str = Timestamp as "%c", REQ:Record-Unique-Key = hex (NAS-IP-Address toraw . Timestamp toraw) . Acct-Session-Id), int or abort, del str, del REP:int, # Set response code and halt the expression acctresp ), ########################################################################### # # Step 5: Now we're authenticating, set defaults to reject when halted, # so we can do so at anytime # RAD-Code = Access-Reject, # Not needed anymore - already done Reply-Message = "I don't know you. Go away.\n", ########################################################################### # # Step 6: Decrypt PAP password. User-Password or reject, REQ:User-Password := (User-Password papdecrypt (REP:Secret . RAD-Authenticator) . "\x00") beforefirst "\x00", ########################################################################### # # Step 7: Log the request using the Stdlogger interface #Stdlogger(str=Timestamp as "%c"), #del str, del REP:int, ########################################################################### # # Step 9: Check unix password database; set some standard attrs. if OK. delall REP:int, # to be *very* sure Unixpasswd(str:=User-Name), int and ( RAD-Code := Access-Accept, Reply-Message := "Welcome, " . User-Name . ". You're coming in on NAS ". (NAS-Identifier or NAS-IP-Address) . " on port " . NAS-Port . ".\nStarting PPP; enjoy.\n", Service-Type = Framed, Framed-Protocol = PPP, accept ), reject