Fixup more formatting in polcy.conf and add policy to remove Reply-Messages if the...
[freeradius.git] / raddb / policy.conf
1 # -*- text -*-
2 ##
3 ## policy.conf  -- FreeRADIUS server configuration file.
4 ##
5 ##      http://www.freeradius.org/
6 ##      $Id$
7 ##
8
9 #
10 #  Policies are virtual modules, similar to those defined in the
11 #  "instantate" section of radiusd.conf.
12 #
13 #  Defining a policy here means that it can be referenced in multiple
14 #  places as a *name*, rather than as a series of conditions to match,
15 #  and actions to take.
16 #
17 #  Policies are something like subroutines in a normal language, but
18 #  they cannot be called recursively. They MUST be defined in order.
19 #  If policy A calls policy B, then B MUST be defined before A.
20 #
21 policy {
22         #
23         #       Overload the default acct_unique module, it's not smart enough
24         #
25         acct_unique {
26                 #
27                 #  If we have a class attribute in the format 'auth_id:[0-9a-f]{32}' it'll have a local
28                 #  value (defined by insert_acct_class), this ensures uniquenes and suitability.
29                 #
30                 #  We could just use the Class attribute as Acct-Unique-Session-Id, but this may cause
31                 #  problems with NAS that carry Class values across between multiple linked sessions.
32                 #  So we rehash class with Acct-Session-ID to provide a truely unique session identifier.
33                 #
34                 #  Using a Class/Session-ID combination is more robust than using elements in the
35                 #  Accounting-Request, which may be subject to change, such as NAS-IP-Address,
36                 #  Client-IP-Address and NAS-Port-ID/NAS-Port.
37                 #
38                 #  This policy should ensure that session data is not affected if NAS IP addresses change,
39                 #  or the client roams to a different 'port' whilst maintaining its initial authentication
40                 #  session (Common in a wireless environment).
41                 #        
42                 if(Class =~ /auth_id:[0-9a-f]{32}/i) {
43                         update request {
44                                 Acct-Unique-Session-Id := "%{md5:%{Class}%{Acct-Session-ID}}"
45                         }
46                 }        
47                 #
48                 #  Not All devices respect RFC 2865 when dealing with the class attribute,
49                 #  so be prepared to use the older style of hashing scheme if a class attribute is not included 
50                 #
51                 else {
52                         update request {
53                                 Acct-Unique-Session-Id := "%{md5:%{User-Name}%{Acct-Session-ID}%{NAS-IP-Address}%{NAS-Port-ID:}%{NAS-Port}}" 
54                          }       
55                 }        
56         }        
57
58         #
59         #       Insert a (hopefully unique) value into class
60         #
61         insert_acct_class {
62                 update reply { 
63                         Class = "auth_id:%{md5:%t%{request:NAS-Identifier}%{NAS-Port-ID}%{NAS-Port}%{Calling-Station-ID}%{reply:User-Name}}"
64                 }
65         }
66
67         #
68         #       Forbid all EAP types.
69         #
70         forbid_eap {
71                 if (EAP-Message) {
72                         reject
73                 }
74         }
75         
76         #
77         #       Forbid all non-EAP types outside of an EAP tunnel.
78         #
79         permit_only_eap {
80                 if (!EAP-Message) {
81                         #  We MAY be inside of a TTLS tunnel.
82                         #  PEAP and EAP-FAST require EAP inside of
83                         #  the tunnel, so this check is OK.
84                         #  If so, then there MUST be an outer EAP message.
85                         if (!"%{outer.request:EAP-Message}") {
86                                 reject
87                         }
88                 }
89         }
90
91         #
92         #       Remove Reply-Message from response if were doing EAP
93         #
94         #  Be RFC 3579 2.6.5 compliant - EAP-Message and Reply-Message should
95         #  not be present in the same response.
96         #
97         remove_reply_message_if_eap {
98                 if(reply:EAP-Message && reply:Reply-Message) {
99                         update reply {
100                                 Reply-Message -= "%{reply:Reply-Message}"
101                         }
102                 }
103                 else {
104                         noop
105                 }
106         }
107
108         #
109         #          Split User-Name in NAI format (RFC 4282) into components
110         #
111         #  This policy writes the Username and Domain portions of the NAI into the 
112         #  Stripped-User-Name and Stripped-User-Domain attributes.
113         #
114         #  The regular expression to do this is not strictly compliant with the standard, 
115         #  but it is not possible to write a compliant regexp without perl style
116         #  regular expressions (or at least not a legible one).
117         #
118         split_username_nai {
119                         if(User-Name =~ /^([^@]*)(@([-[:alnum:]]+\\.[-[:alnum:].]+))?$/){
120                                 update request {
121                                         Stripped-User-Name := "%{1}"
122                                         Stripped-User-Domain = "%{3}"
123                                 }
124                         }
125                 else{
126                         noop
127                 }
128         }
129
130         #
131         #       Forbid all attempts to login via realms.
132         #
133         deny_realms {
134                 if (User-Name =~ /@|\\/) {
135                         reject
136                 }
137         }
138
139         #
140         #  If you want the server to pretend that it is dead,
141         #  then use the "do_not_respond" policy.
142         #
143         do_not_respond {
144                 update control {
145                         Response-Packet-Type := Do-Not-Respond
146                 }
147
148                 handled
149         }
150
151         #
152         #       Filter the username
153         #
154         #  Force some sanity on User-Name. This helps to avoid issues
155         #  issues where the back-end database is "forgiving" about
156         #  what constitutes a user name.
157         #
158         filter_username {
159                 # spaces at the start: reject
160                 if (User-Name =~ /^ /) {
161                         reject
162                 }
163
164                 # spaces at the end: reject
165                 if (User-Name =~ / $$/) {
166                         reject
167                 }
168
169                 # Mixed case: reject
170                 if (User-Name != "%{tolower:%{User-Name}}") {
171                         reject
172                 }
173         }
174
175
176         #       
177         #  The following policies are for the Chargeable-User-Identity
178         #  (CUI) configuration.
179         #
180         #  The policies below can be called as just 'cui' (not cui.authorize etc..)
181         #  from the various  config sections.   
182         #
183
184         #
185         #  The client indicates it can do CUI by sending a CUI attribute        
186         #  containing one zero byte
187         #
188         cui.authorize {
189                 update request {
190                         Chargeable-User-Identity:='\\000'
191                 }
192         }
193
194         #
195         #  Add a CUI attribute based on the User-Name, and a secret key
196         #  known only to this server.
197         #
198         cui.postauth {
199                 if (FreeRadius-Proxied-To == 127.0.0.1) {
200                         if (outer.request:Chargeable-User-Identity) {
201                                 update outer.reply {
202                                         Chargeable-User-Identity:="%{md5:%{config:cui_hash_key}%{User-Name}}"
203                                 }
204                         }
205                 }
206                 else {
207                         if (Chargeable-User-Identity) {
208                                 update reply {
209                                         Chargeable-User-Identity="%{md5:%{config:cui_hash_key}%{User-Name}}"
210                                 }
211                         }
212                 }
213         }
214
215
216         #
217         #  If we had stored a CUI for the User, add it to the request.
218         #
219         cui.accounting {
220                 #
221                 #  If the CUI isn't in the packet, see if we can find it
222                 #  in the DB.
223                 #
224                 if (!Chargeable-User-Identity) {
225                         update control {
226                                 Chargable-User-Identity := "%{cui: SELECT cui FROM cui WHERE clientipaddress = '%{Client-IP-Address}' AND callingstationid = '%{Calling-Station-Id}' AND username = '%{User-Name}'}"
227                         }
228                 }
229
230                 #
231                 #  If it exists now, then write out when we last saw
232                 #  this CUI.
233                 #
234                 if (Chargeable-User-Identity && (Chargeable-User-Identity != "")) {
235                         cui
236                 }
237         }
238
239         #
240         #  If there is a CUI attribute in the reply, add it to the DB.
241         #
242         cui_updatedb {
243                 if (reply:Chargeable-User-Identity) {
244                         cui
245                 }
246         }
247
248         #
249         #  Normalize the MAC Addresses in the Calling/Called-Station-Id
250         #
251         mac-addr-regexp = ([0-9a-f]{2})[^0-9a-f]?([0-9a-f]{2})[^0-9a-f]?([0-9a-f]{2})[^0-9a-f]?([0-9a-f]{2})[^0-9a-f]?([0-9a-f]{2})[^0-9a-f]?([0-9a-f]{2})
252         
253         #
254         #  Add "rewrite_called_station_id" in the "authorize" and "preacct" sections.
255         #
256         rewrite_called_station_id {
257                 if(Called-Station-Id =~ /^%{config:policy.mac-addr-regexp}(:(.+))?$/i) {
258                         update request {
259                                 Called-Station-Id := "%{tolower:%{1}-%{2}-%{3}-%{4}-%{5}-%{6}}"
260                         }
261
262                         # SSID component?
263                         if ("%{7}") {
264                                 update request {
265                                         Called-Station-SSID := "%{7}"
266                                 }
267                         }
268                         updated
269                 }
270                 else {
271                         noop
272                 }
273         }
274
275         #
276         #  Add "rewrite_calling_station_id" in the "authorize" and "preacct" sections.
277         #
278         rewrite_calling_station_id {
279                 if(Calling-Station-Id =~ /^%{config:policy.mac-addr-regexp}$/i) {
280                         update request {
281                                 Calling-Station-Id := "%{tolower:%{1}-%{2}-%{3}-%{4}-%{5}-%{6}}"
282                         }
283                         updated
284                 }
285                 else {
286                         noop
287                 }
288         }
289 }