import from HEAD:
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * Copyright 2000  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 static const char rcsid[] = "$Id$";
27
28 #include "autoconf.h"
29
30 #include <stdlib.h>
31
32 #include "radiusd.h"
33 #include "modules.h"
34
35 /*
36  *      rad_accounting: call modules.
37  *
38  *      The return value of this function isn't actually used right now, so
39  *      it's not entirely clear if it is returning the right things. --Pac.
40  */
41 int rad_accounting(REQUEST *request)
42 {
43         int result = RLM_MODULE_OK;
44
45         /*
46          *      Run the modules only once, before proxying.
47          */
48         if (!request->proxy) {
49                 char            *exec_program;
50                 int             exec_wait;
51                 VALUE_PAIR      *vp;
52                 int             rcode;
53                 int             acct_type = 0;
54
55                 result = module_preacct(request);
56                 switch (result) {
57                         /*
58                          *      The module has a number of OK return codes.
59                          */
60                         case RLM_MODULE_NOOP:
61                         case RLM_MODULE_OK:
62                         case RLM_MODULE_UPDATED:
63                                 break;
64                         /*
65                          *      The module handled the request, stop here.
66                          */
67                         case RLM_MODULE_HANDLED:
68                                 return result;
69                         /*
70                          *      The module failed, or said the request is
71                          *      invalid, therefore we stop here.
72                          */
73                         case RLM_MODULE_FAIL:
74                         case RLM_MODULE_INVALID:
75                         case RLM_MODULE_NOTFOUND:
76                         case RLM_MODULE_REJECT:
77                         case RLM_MODULE_USERLOCK:
78                         default:
79                                 return result;
80                 }
81
82                 /*
83                  *      Do the data storage before proxying. This is to ensure
84                  *      that we log the packet, even if the proxy never does.
85                  */
86                 vp = pairfind(request->config_items, PW_ACCT_TYPE);
87                 if (vp) {
88                         DEBUG2("  Found Acct-Type %s", vp->strvalue);
89                         acct_type = vp->lvalue;
90                 }
91                 result = module_accounting(acct_type, request);
92                 switch (result) {
93                         /*
94                          *      In case the accounting module returns FAIL,
95                          *      it's still useful to send the data to the
96                          *      proxy.
97                          */
98                         case RLM_MODULE_FAIL:
99                         case RLM_MODULE_NOOP:
100                         case RLM_MODULE_OK:
101                         case RLM_MODULE_UPDATED:
102                                 break;
103                         /*
104                          *      The module handled the request, don't reply.
105                          */
106                         case RLM_MODULE_HANDLED:
107                                 return result;
108                         /*
109                          *      Neither proxy, nor reply to invalid requests.
110                          */
111                         case RLM_MODULE_INVALID:
112                         case RLM_MODULE_NOTFOUND:
113                         case RLM_MODULE_REJECT:
114                         case RLM_MODULE_USERLOCK:
115                         default:
116                                 return result;
117                 }
118
119                 /*
120                  *      See if we need to execute a program.
121                  *      FIXME: somehow cache this info, and only execute the
122                  *      program when we receive an Accounting-START packet.
123                  *      Only at that time we know dynamic IP etc.
124                  */
125                 exec_program = NULL;
126                 exec_wait = 0;
127                 if ((vp = pairfind(request->reply->vps, PW_EXEC_PROGRAM)) != NULL) {
128                         exec_wait = 0;
129                         exec_program = strdup((char *)vp->strvalue);
130                         pairdelete(&request->reply->vps, PW_EXEC_PROGRAM);
131                 }
132
133                 if ((vp = pairfind(request->reply->vps, PW_EXEC_PROGRAM_WAIT)) != NULL) {
134                         free(exec_program);
135                         exec_wait = 1;
136                         exec_program = strdup((char *)vp->strvalue);
137                         pairdelete(&request->reply->vps, PW_EXEC_PROGRAM_WAIT);
138                 }
139
140                 /*
141                  *      If we want to exec a program, but wait for it,
142                  *      do it first before sending the reply, or
143                  *      proxying the packet.
144                  *
145                  *      If we're NOT waiting, then also do this now, but
146                  *      don't check the return code.
147                  */
148                 if (exec_program) {
149                         /*
150                          *      Wait for the answer.
151                          *      Don't look for a user message.
152                          *      Do look for returned VP's.
153                          */
154                         rcode = radius_exec_program(exec_program, request,
155                                                     exec_wait, NULL, 0,
156                                                     request->packet->vps, &vp);
157                         free(exec_program);
158
159                         /*
160                          *      Always add the value-pairs to the reply.
161                          *
162                          *      If we're not waiting, then the pairs
163                          *      will be empty, so this won't matter.
164                          */
165                         pairmove(&request->reply->vps, &vp);
166                         pairfree(&vp);
167
168                         if (exec_wait) {
169                                 if (rcode != 0) {
170                                         return result;
171                                 }
172                         }
173                 }
174
175                 /*
176                  *      Maybe one of the preacct modules has decided
177                  *      that a proxy should be used.
178                  */
179                 if ((vp = pairfind(request->config_items, PW_PROXY_TO_REALM))) {
180                         REALM *realm;
181
182                         /*
183                          *      Check whether Proxy-To-Realm is
184                          *      a LOCAL realm.
185                          */
186                         realm = realm_find(vp->strvalue, TRUE);
187                         if (realm != NULL &&
188                             realm->acct_ipaddr == htonl(INADDR_NONE)) {
189                                 DEBUG("rad_accounting: Cancelling proxy to realm %s, as it is a LOCAL realm.", realm->realm);
190                                 pairdelete(&request->config_items, PW_PROXY_TO_REALM);
191                         } else {
192                                 /*
193                                  *      Don't reply to the NAS now because
194                                  *      we have to send the proxied packet
195                                  *      before that.
196                                  */
197                                 return result;
198                         }
199                 }
200         }
201
202         /*
203          *      We get here IF we're not proxying, OR if we've
204          *      received the accounting reply from the end server,
205          *      THEN we can reply to the NAS.
206          *      If the accounting module returns NOOP, the data
207          *      storage did not succeed, so radiusd should not send
208          *      Accounting-Response.
209          */
210         switch (result) {
211                 /*
212                  *      Send back an ACK to the NAS.
213                  */
214                 case RLM_MODULE_OK:
215                 case RLM_MODULE_UPDATED:
216                         request->reply->code = PW_ACCOUNTING_RESPONSE;
217                         break;
218                 /*
219                  *      The module handled the request, don't reply.
220                  */
221                 case RLM_MODULE_HANDLED:
222                         break;
223                 /*
224                  *      Failed to log or to proxy the accounting data,
225                  *      therefore don't reply to the NAS.
226                  */
227                 case RLM_MODULE_FAIL:
228                 case RLM_MODULE_INVALID:
229                 case RLM_MODULE_NOOP:
230                 case RLM_MODULE_NOTFOUND:
231                 case RLM_MODULE_REJECT:
232                 case RLM_MODULE_USERLOCK:
233                 default:
234                         break;
235         }
236         return result;
237 }