# # Sample of a policy language for rlm_policy. # # This is NOT the "unlang" policy, and has NO RELATION to "unlang"! # The syntax is different, and the functionality is different. # # As of 2.0.0, the new configuration "un-language" is better # tested, has more features, and is better integrated into the # server than the rlm_policy module. rlm_policy is deprecated, # and will likely be removed in a future release. # # There is no documentation other than this file. # # The syntax is odd, but it sort of works. # # A number of sites are using it in production servers, # so it appears to be stable. However, we cannot answer # questions about it, because we use "unlang", instead of # this file. # # $Id$ # # Debugging statements # #debug print_tokens # as we're parsing this file debug print_policy # once the file has been parsed # Using this requires code edits to rlm_policy/evaluate.c #debug evaluate # print limited information during evaluation # # A named policy. # policy 3pm { if (Time-Of-Day < "15:00") { # # The general form of edits to the attribute lists: # # name s-operator { # Attribute-Name = Value # } # # name is: request, reply, control, proxy-request, proxy-reply # # s-operator is operator for section, not attributes: # # = append, using operators from attributes # .= append attributes, ignoring operators from attributes # ^= add to head of list # ^== add BEFORE matching attribute # ^. append # ^.= append BEFORE matching attribute # $= add AFTER (same as =) # $== add AFTER matching attribute # $. add after (same as .=) # $.= add after matching # # If the above explanation confuses you, don't ask. Try various # configurations to see what happens. The results are difficult # to explain, but easy to understand once you see them in action. # # The "matching attribute" text above refers to the syntax: # # name s-operator (match) { # Attribute-Name = Value # } # # Where "match" is something like: User-Name == "bob" # # This lets you insert/edit/update attributes by selected # position, which can be useful. # reply .= { # Use ARAP-Password for testing because it's an attribute # no one cares about. ARAP-Password = "< 15:00" } } } # # A named policy, executed during the "authorize" phase, # because it's named "authorize". # policy authorize { if (CHAP-Password) { if (!CHAP-Challenge) { print "Adding CHAP-Challenge = %{request:Packet-Authentication-Vector}\n" # # Append all attributes to the specified list. # The per-attribute operators MUST be '=' # request .= { CHAP-Challenge = "%{request:Packet-Authentication-Vector}" } } # # Use per-attribute operators to do override, replace, etc. # It's "control", not "check items", because "check items" # is a hold-over from the "users" file, and we no longer like that. # control = { Auth-Type := CHAP } } # # This could just as well be "%{ldap: query...}" =~ ... # # if ("%{User-Name}" =~ "^(b)") { # reply .= { # Arap-Password = "Hello, %{1}" # } # } # # Execute "3pm", as if it was in-line here. # # call 3pm } ###################################################################### # # The following entries are for example purposes only. # # Insert the attribute at the top of the list. # #reply ^= { # Attribute1 += "Value1" #} # Insert attribute1 before Attribute2 if found, otherwise it behaves # like ^= #reply ^== ( Attribute2 == "Value2" ) { # Attribute1 += "Value1" #} # ^. and ^.= have the same difference as .= and = # namely they append the attribute list instead of looking at the # attribute operators. # # Otherwise they are the same. # Motivation: # # Cisco NAS's will kick users who assign a VRF after assigning an IP # address. The VRF must come first. # # A sample policy to fix this is: # policy add_inter_vrf { # # If there's a matching lcp:..., # then add the vrf entry before it. # reply ^== ( reply:Cisco-Avpair =~ "lcp:interface-config") { Cisco-Avpair += "lcp:interface-config=ip vrf forwarding CHL-PRIVATE" } # # If there's no ip address thingy, # add ip unnumbered after the vrf stuff. # if (!reply:Cisco-Avpair =~ "lcp:interface-config=ip address.*") { reply $== (reply:Cisco-AVpair == "lcp:interface-config=ip vrf forwarding CHL-PRIVATE") { Cisco-Avpair += "lcp:interface-config=ip unnumbered l10" } } # # No IP address assigned through RADIUS, tell the Cisco # NAS to assign it from it's own private IP pool. # if (!reply:Framed-IP-Address =* "") { reply = { Cisco-Avpair += "ip:addr-pool=privatepool" } } }