Merge branch 'sam'
[freeradius.git] / src / main / acct.c
1 /*
2  * acct.c       Accounting routines.
3  *
4  * Version:     $Id$
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2000,2006  The FreeRADIUS server project
21  * Copyright 2000  Miquel van Smoorenburg <miquels@cistron.nl>
22  * Copyright 2000  Alan DeKok <aland@ox.org>
23  * Copyright 2000  Alan Curry <pacman@world.std.com>
24  */
25
26 #include <freeradius-devel/ident.h>
27 RCSID("$Id$")
28
29 #include <freeradius-devel/radiusd.h>
30 #include <freeradius-devel/modules.h>
31
32 #ifdef WITH_ACCOUNTING
33 /*
34  *      rad_accounting: call modules.
35  *
36  *      The return value of this function isn't actually used right now, so
37  *      it's not entirely clear if it is returning the right things. --Pac.
38  */
39 int rad_accounting(REQUEST *request)
40 {
41         int result = RLM_MODULE_OK;
42
43
44 #ifdef WITH_PROXY
45 #define WAS_PROXIED (request->proxy)
46 #else
47 #define WAS_PROXIED (0)
48 #endif
49
50         /*
51          *      Run the modules only once, before proxying.
52          */
53         if (!WAS_PROXIED) {
54                 VALUE_PAIR      *vp;
55                 int             acct_type = 0;
56
57                 result = module_preacct(request);
58                 switch (result) {
59                         /*
60                          *      The module has a number of OK return codes.
61                          */
62                         case RLM_MODULE_NOOP:
63                         case RLM_MODULE_OK:
64                         case RLM_MODULE_UPDATED:
65                                 break;
66                         /*
67                          *      The module handled the request, stop here.
68                          */
69                         case RLM_MODULE_HANDLED:
70                                 return result;
71                         /*
72                          *      The module failed, or said the request is
73                          *      invalid, therefore we stop here.
74                          */
75                         case RLM_MODULE_FAIL:
76                         case RLM_MODULE_INVALID:
77                         case RLM_MODULE_NOTFOUND:
78                         case RLM_MODULE_REJECT:
79                         case RLM_MODULE_USERLOCK:
80                         default:
81                                 return result;
82                 }
83
84                 /*
85                  *      Do the data storage before proxying. This is to ensure
86                  *      that we log the packet, even if the proxy never does.
87                  */
88                 vp = pairfind(request->config_items, PW_ACCT_TYPE, 0);
89                 if (vp) {
90                         acct_type = vp->vp_integer;
91                         DEBUG2("  Found Acct-Type %s",
92                                dict_valnamebyattr(PW_ACCT_TYPE, 0, acct_type));
93                 }
94                 result = module_accounting(acct_type, request);
95                 switch (result) {
96                         /*
97                          *      In case the accounting module returns FAIL,
98                          *      it's still useful to send the data to the
99                          *      proxy.
100                          */
101                         case RLM_MODULE_FAIL:
102                         case RLM_MODULE_NOOP:
103                         case RLM_MODULE_OK:
104                         case RLM_MODULE_UPDATED:
105                                 break;
106                         /*
107                          *      The module handled the request, don't reply.
108                          */
109                         case RLM_MODULE_HANDLED:
110                                 return result;
111                         /*
112                          *      Neither proxy, nor reply to invalid requests.
113                          */
114                         case RLM_MODULE_INVALID:
115                         case RLM_MODULE_NOTFOUND:
116                         case RLM_MODULE_REJECT:
117                         case RLM_MODULE_USERLOCK:
118                         default:
119                                 return result;
120                 }
121
122                 /*
123                  *      Maybe one of the preacct modules has decided
124                  *      that a proxy should be used.
125                  */
126                 if ((vp = pairfind(request->config_items, PW_PROXY_TO_REALM, 0))) {
127                         REALM *realm;
128
129                         /*
130                          *      Check whether Proxy-To-Realm is
131                          *      a LOCAL realm.
132                          */
133                         realm = realm_find2(vp->vp_strvalue);
134                         if (realm && !realm->acct_pool) {
135                                 DEBUG("rad_accounting: Cancelling proxy to realm %s, as it is a LOCAL realm.", realm->name);
136                                 pairdelete(&request->config_items, PW_PROXY_TO_REALM, 0);
137                         } else {
138                                 /*
139                                  *      Don't reply to the NAS now because
140                                  *      we have to send the proxied packet
141                                  *      before that.
142                                  */
143                                 return result;
144                         }
145                 }
146         }
147
148         /*
149          *      We get here IF we're not proxying, OR if we've
150          *      received the accounting reply from the end server,
151          *      THEN we can reply to the NAS.
152          *      If the accounting module returns NOOP, the data
153          *      storage did not succeed, so radiusd should not send
154          *      Accounting-Response.
155          */
156         switch (result) {
157                 /*
158                  *      Send back an ACK to the NAS.
159                  */
160                 case RLM_MODULE_OK:
161                 case RLM_MODULE_UPDATED:
162                         request->reply->code = PW_ACCOUNTING_RESPONSE;
163                         break;
164                 /*
165                  *      The module handled the request, don't reply.
166                  */
167                 case RLM_MODULE_HANDLED:
168                         break;
169                 /*
170                  *      Failed to log or to proxy the accounting data,
171                  *      therefore don't reply to the NAS.
172                  */
173                 case RLM_MODULE_FAIL:
174                 case RLM_MODULE_INVALID:
175                 case RLM_MODULE_NOOP:
176                 case RLM_MODULE_NOTFOUND:
177                 case RLM_MODULE_REJECT:
178                 case RLM_MODULE_USERLOCK:
179                 default:
180                         break;
181         }
182         return result;
183 }
184 #endif