Convert Class to string before attempting to do a pattern match
[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("%{string:Class}" =~ /auth_id:([0-9a-f]{32})/i) {
43                         update request {
44                                 Acct-Unique-Session-Id := "%{md5:%{1}%{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 !* ANY
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                         # If any of the expansions result in a null string, the update
125                         # section may return something other than updated...
126                         updated
127                 }
128                 else{
129                         noop
130                 }
131         }
132
133         #
134         #       Forbid all attempts to login via realms.
135         #
136         deny_realms {
137                 if (User-Name =~ /@|\\/) {
138                         reject
139                 }
140         }
141
142         #
143         #  If you want the server to pretend that it is dead,
144         #  then use the "do_not_respond" policy.
145         #
146         do_not_respond {
147                 update control {
148                         Response-Packet-Type := Do-Not-Respond
149                 }
150
151                 handled
152         }
153
154         #
155         #       Filter the username
156         #
157         #  Force some sanity on User-Name. This helps to avoid issues
158         #  issues where the back-end database is "forgiving" about
159         #  what constitutes a user name.
160         #
161         filter_username {
162                 # spaces at the start: reject
163                 if (User-Name =~ /^ /) {
164                         reject
165                 }
166
167                 # spaces at the end: reject
168                 if (User-Name =~ / $$/) {
169                         reject
170                 }
171
172                 # Mixed case: reject
173                 if (User-Name != "%{tolower:%{User-Name}}") {
174                         reject
175                 }
176         }
177
178
179         #       
180         #  The following policies are for the Chargeable-User-Identity
181         #  (CUI) configuration.
182         #
183         #  The policies below can be called as just 'cui' (not cui.authorize etc..)
184         #  from the various  config sections.   
185         #
186
187         #
188         #  The client indicates it can do CUI by sending a CUI attribute        
189         #  containing one zero byte
190         #
191         cui.authorize {
192                 update request {
193                         Chargeable-User-Identity:='\\000'
194                 }
195         }
196
197         #
198         #  Add a CUI attribute based on the User-Name, and a secret key
199         #  known only to this server.
200         #
201         cui.post-auth {
202                 if (FreeRadius-Proxied-To == 127.0.0.1) {
203                         if (outer.request:Chargeable-User-Identity) {
204                                 update outer.reply {
205                                         Chargeable-User-Identity:="%{md5:%{config:cui_hash_key}%{User-Name}}"
206                                 }
207                         }
208                 }
209                 else {
210                         if (Chargeable-User-Identity) {
211                                 update reply {
212                                         Chargeable-User-Identity="%{md5:%{config:cui_hash_key}%{User-Name}}"
213                                 }
214                         }
215                 }
216         }
217
218
219         #
220         #  If we had stored a CUI for the User, add it to the request.
221         #
222         cui.accounting {
223                 #
224                 #  If the CUI isn't in the packet, see if we can find it
225                 #  in the DB.
226                 #
227                 if (!Chargeable-User-Identity) {
228                         update control {
229                                 Chargable-User-Identity := "%{cui: SELECT cui FROM cui WHERE clientipaddress = '%{Client-IP-Address}' AND callingstationid = '%{Calling-Station-Id}' AND username = '%{User-Name}'}"
230                         }
231                 }
232
233                 #
234                 #  If it exists now, then write out when we last saw
235                 #  this CUI.
236                 #
237                 if (Chargeable-User-Identity && (Chargeable-User-Identity != "")) {
238                         cui
239                 }
240         }
241
242         #
243         #  If there is a CUI attribute in the reply, add it to the DB.
244         #
245         cui_updatedb {
246                 if (reply:Chargeable-User-Identity) {
247                         cui
248                 }
249         }
250
251         #
252         #  Normalize the MAC Addresses in the Calling/Called-Station-Id
253         #
254         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})
255         
256         #
257         #  Add "rewrite_called_station_id" in the "authorize" and "preacct" sections.
258         #
259         rewrite_called_station_id {
260                 if(Called-Station-Id =~ /^%{config:policy.mac-addr-regexp}(:(.+))?$/i) {
261                         update request {
262                                 Called-Station-Id := "%{tolower:%{1}-%{2}-%{3}-%{4}-%{5}-%{6}}"
263                         }
264
265                         # SSID component?
266                         if ("%{7}") {
267                                 update request {
268                                         Called-Station-SSID := "%{7}"
269                                 }
270                         }
271                         updated
272                 }
273                 else {
274                         noop
275                 }
276         }
277
278         #
279         #  Add "rewrite_calling_station_id" in the "authorize" and "preacct" sections.
280         #
281         rewrite_calling_station_id {
282                 if(Calling-Station-Id =~ /^%{config:policy.mac-addr-regexp}$/i) {
283                         update request {
284                                 Calling-Station-Id := "%{tolower:%{1}-%{2}-%{3}-%{4}-%{5}-%{6}}"
285                         }
286                         updated
287                 }
288                 else {
289                         noop
290                 }
291         }
292 }