#
#	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: policy.txt,v 1.5 2007/12/29 05:01:45 aland Exp $
#
#  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"
		}
	}
}
